View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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.FlowControlStrategy;
27  import org.eclipse.jetty.http2.HTTP2Connection;
28  import org.eclipse.jetty.http2.ISession;
29  import org.eclipse.jetty.http2.api.Session;
30  import org.eclipse.jetty.http2.frames.PrefaceFrame;
31  import org.eclipse.jetty.http2.frames.SettingsFrame;
32  import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
33  import org.eclipse.jetty.http2.generator.Generator;
34  import org.eclipse.jetty.http2.parser.Parser;
35  import org.eclipse.jetty.io.ByteBufferPool;
36  import org.eclipse.jetty.io.ClientConnectionFactory;
37  import org.eclipse.jetty.io.Connection;
38  import org.eclipse.jetty.io.EndPoint;
39  import org.eclipse.jetty.util.Callback;
40  import org.eclipse.jetty.util.Promise;
41  import org.eclipse.jetty.util.component.LifeCycle;
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 final Connection.Listener connectionListener = new ConnectionListener();
54      private int initialSessionRecvWindow = FlowControlStrategy.DEFAULT_WINDOW_SIZE;
55  
56      @Override
57      public Connection newConnection(EndPoint endPoint, Map<String, Object> context) throws IOException
58      {
59          HTTP2Client client = (HTTP2Client)context.get(CLIENT_CONTEXT_KEY);
60          ByteBufferPool byteBufferPool = (ByteBufferPool)context.get(BYTE_BUFFER_POOL_CONTEXT_KEY);
61          Executor executor = (Executor)context.get(EXECUTOR_CONTEXT_KEY);
62          Scheduler scheduler = (Scheduler)context.get(SCHEDULER_CONTEXT_KEY);
63          Session.Listener listener = (Session.Listener)context.get(SESSION_LISTENER_CONTEXT_KEY);
64          @SuppressWarnings("unchecked")
65          Promise<Session> promise = (Promise<Session>)context.get(SESSION_PROMISE_CONTEXT_KEY);
66  
67          Generator generator = new Generator(byteBufferPool);
68          FlowControlStrategy flowControl = newFlowControlStrategy();
69          if (flowControl == null)
70              flowControl = client.getFlowControlStrategyFactory().newFlowControlStrategy();
71          HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
72          Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
73          HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint, parser, session, client.getInputBufferSize(), promise, listener);
74          connection.addListener(connectionListener);
75          return connection;
76      }
77  
78      /**
79       * @deprecated use {@link HTTP2Client#setFlowControlStrategyFactory(FlowControlStrategy.Factory)} instead
80       */
81      @Deprecated
82      protected FlowControlStrategy newFlowControlStrategy()
83      {
84          return null;
85      }
86  
87      /**
88       * @deprecated use {@link HTTP2Client#getInitialSessionRecvWindow()} instead
89       */
90      @Deprecated
91      public int getInitialSessionRecvWindow()
92      {
93          return initialSessionRecvWindow;
94      }
95  
96      /**
97       * @deprecated use {@link HTTP2Client#setInitialSessionRecvWindow(int)} instead
98       */
99      @Deprecated
100     public void setInitialSessionRecvWindow(int initialSessionRecvWindow)
101     {
102         this.initialSessionRecvWindow = initialSessionRecvWindow;
103     }
104 
105     private class HTTP2ClientConnection extends HTTP2Connection implements Callback
106     {
107         private final HTTP2Client client;
108         private final Promise<Session> promise;
109         private final Session.Listener listener;
110 
111         public HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise<Session> promise, Session.Listener listener)
112         {
113             super(byteBufferPool, executor, endpoint, parser, session, bufferSize);
114             this.client = client;
115             this.promise = promise;
116             this.listener = listener;
117         }
118 
119         @Override
120         public void onOpen()
121         {
122             Map<Integer, Integer> settings = listener.onPreface(getSession());
123             if (settings == null)
124                 settings = Collections.emptyMap();
125 
126             PrefaceFrame prefaceFrame = new PrefaceFrame();
127             SettingsFrame settingsFrame = new SettingsFrame(settings, false);
128 
129             ISession session = getSession();
130 
131             int sessionRecv = client.getInitialSessionRecvWindow();
132             if (sessionRecv == FlowControlStrategy.DEFAULT_WINDOW_SIZE)
133                 sessionRecv = initialSessionRecvWindow;
134 
135             int windowDelta = sessionRecv - FlowControlStrategy.DEFAULT_WINDOW_SIZE;
136             if (windowDelta > 0)
137             {
138                 session.updateRecvWindow(windowDelta);
139                 session.frames(null, this, prefaceFrame, settingsFrame, new WindowUpdateFrame(0, windowDelta));
140             }
141             else
142             {
143                 session.frames(null, this, prefaceFrame, settingsFrame);
144             }
145             // Only start reading from server after we have sent the client preface,
146             // otherwise we risk to read the server preface (a SETTINGS frame) and
147             // reply to that before we have the chance to send the client preface.
148             super.onOpen();
149         }
150 
151         @Override
152         public void succeeded()
153         {
154             promise.succeeded(getSession());
155         }
156 
157         @Override
158         public void failed(Throwable x)
159         {
160             close();
161             promise.failed(x);
162         }
163     }
164 
165     private class ConnectionListener implements Connection.Listener
166     {
167         @Override
168         public void onOpened(Connection connection)
169         {
170             HTTP2ClientConnection http2Connection = (HTTP2ClientConnection)connection;
171             http2Connection.client.addManaged((LifeCycle)http2Connection.getSession());
172         }
173 
174         @Override
175         public void onClosed(Connection connection)
176         {
177             HTTP2ClientConnection http2Connection = (HTTP2ClientConnection)connection;
178             http2Connection.client.removeBean(http2Connection.getSession());
179         }
180     }
181 }