1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 }