View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.http2.client;
20  
21  import java.io.IOException;
22  import java.util.Collections;
23  import java.util.Map;
24  import java.util.concurrent.Executor;
25  
26  import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
27  import org.eclipse.jetty.http2.FlowControlStrategy;
28  import org.eclipse.jetty.http2.HTTP2Connection;
29  import org.eclipse.jetty.http2.ISession;
30  import org.eclipse.jetty.http2.api.Session;
31  import org.eclipse.jetty.http2.frames.PrefaceFrame;
32  import org.eclipse.jetty.http2.frames.SettingsFrame;
33  import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
34  import org.eclipse.jetty.http2.generator.Generator;
35  import org.eclipse.jetty.http2.parser.Parser;
36  import org.eclipse.jetty.io.ByteBufferPool;
37  import org.eclipse.jetty.io.ClientConnectionFactory;
38  import org.eclipse.jetty.io.Connection;
39  import org.eclipse.jetty.io.EndPoint;
40  import org.eclipse.jetty.util.Callback;
41  import org.eclipse.jetty.util.Promise;
42  import org.eclipse.jetty.util.thread.Scheduler;
43  
44  public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
45  {
46      public static final String CLIENT_CONTEXT_KEY = "http2.client";
47      public static final String BYTE_BUFFER_POOL_CONTEXT_KEY = "http2.client.byteBufferPool";
48      public static final String EXECUTOR_CONTEXT_KEY = "http2.client.executor";
49      public static final String SCHEDULER_CONTEXT_KEY = "http2.client.scheduler";
50      public static final String SESSION_LISTENER_CONTEXT_KEY = "http2.client.sessionListener";
51      public static final String SESSION_PROMISE_CONTEXT_KEY = "http2.client.sessionPromise";
52  
53      private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
54  
55      @Override
56      public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
57      {
58          HTTP2Client client = (HTTP2Client)context.get(CLIENT_CONTEXT_KEY);
59          ByteBufferPool byteBufferPool = (ByteBufferPool)context.get(BYTE_BUFFER_POOL_CONTEXT_KEY);
60          Executor executor = (Executor)context.get(EXECUTOR_CONTEXT_KEY);
61          Scheduler scheduler = (Scheduler)context.get(SCHEDULER_CONTEXT_KEY);
62          Session.Listener listener = (Session.Listener)context.get(SESSION_LISTENER_CONTEXT_KEY);
63          @SuppressWarnings("unchecked")
64          Promise<Session> promise = (Promise<Session>)context.get(SESSION_PROMISE_CONTEXT_KEY);
65  
66          Generator generator = new Generator(byteBufferPool);
67          FlowControlStrategy flowControl = newFlowControlStrategy();
68          HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
69          Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
70          return new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, 8192, promise, listener);
71      }
72  
73      protected FlowControlStrategy newFlowControlStrategy()
74      {
75          return new BufferingFlowControlStrategy(0.5F);
76      }
77  
78      public int getInitialSessionRecvWindow()
79      {
80          return initialSessionRecvWindow;
81      }
82  
83      public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
84      {
85          this.initialSessionRecvWindow = initialSessionRecvWindow;
86      }
87  
88      private class HTTP2ClientConnection extends HTTP2Connection implements Callback
89      {
90          private final HTTP2Client client;
91          private final Promise<Session> promise;
92          private final Session.Listener listener;
93  
94          public HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise<Session> promise, Session.Listener listener)
95          {
96              super(byteBufferPool, executor, endpoint, parser, session, bufferSize);
97              this.client = client;
98              this.promise = promise;
99              this.listener = listener;
100         }
101 
102         @Override
103         public void onOpen()
104         {
105             super.onOpen();
106             Map<Integer, Integer> settings = listener.onPreface(getSession());
107             if (settings == null)
108                 settings = Collections.emptyMap();
109 
110             PrefaceFrame prefaceFrame = new PrefaceFrame();
111             SettingsFrame settingsFrame = new SettingsFrame(settings, false);
112             ISession session = getSession();
113             int windowDelta = getInitialSessionRecvWindow() - FlowControlStrategy.DEFAULT_WINDOW_SIZE;
114             if (windowDelta > 0)
115             {
116                 session.updateRecvWindow(windowDelta);
117                 session.frames(null, this, prefaceFrame, settingsFrame, new WindowUpdateFrame(0, windowDelta));
118             }
119             else
120             {
121                 session.frames(null, this, prefaceFrame, settingsFrame);
122             }
123         }
124 
125         @Override
126         public void onClose()
127         {
128             super.onClose();
129             client.removeSession(getSession());
130         }
131 
132         @Override
133         public void succeeded()
134         {
135             client.addSession(getSession());
136             promise.succeeded(getSession());
137         }
138 
139         @Override
140         public void failed(Throwable x)
141         {
142             close();
143             promise.failed(x);
144         }
145     }
146 }