1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.http2.server;
20
21 import java.io.IOException;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.concurrent.TimeoutException;
25
26 import org.eclipse.jetty.http2.ErrorCode;
27 import org.eclipse.jetty.http2.HTTP2Cipher;
28 import org.eclipse.jetty.http2.IStream;
29 import org.eclipse.jetty.http2.api.Session;
30 import org.eclipse.jetty.http2.api.Stream;
31 import org.eclipse.jetty.http2.api.server.ServerSessionListener;
32 import org.eclipse.jetty.http2.frames.DataFrame;
33 import org.eclipse.jetty.http2.frames.GoAwayFrame;
34 import org.eclipse.jetty.http2.frames.HeadersFrame;
35 import org.eclipse.jetty.http2.frames.PushPromiseFrame;
36 import org.eclipse.jetty.http2.frames.ResetFrame;
37 import org.eclipse.jetty.http2.frames.SettingsFrame;
38 import org.eclipse.jetty.io.EndPoint;
39 import org.eclipse.jetty.server.Connector;
40 import org.eclipse.jetty.server.HttpConfiguration;
41 import org.eclipse.jetty.server.NegotiatingServerConnection.CipherDiscriminator;
42 import org.eclipse.jetty.util.Callback;
43 import org.eclipse.jetty.util.annotation.Name;
44 import org.eclipse.jetty.util.log.Log;
45 import org.eclipse.jetty.util.log.Logger;
46
47 public class HTTP2ServerConnectionFactory extends AbstractHTTP2ServerConnectionFactory implements CipherDiscriminator
48 {
49 private static final Logger LOG = Log.getLogger(HTTP2ServerConnectionFactory.class);
50
51 public HTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration)
52 {
53 super(httpConfiguration);
54 }
55
56 protected HTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration,String... protocols)
57 {
58 super(httpConfiguration,protocols);
59 }
60
61 @Override
62 protected ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint)
63 {
64 return new HTTPServerSessionListener(connector, endPoint);
65 }
66
67 @Override
68 public boolean isAcceptable(String protocol, String tlsProtocol, String tlsCipher)
69 {
70
71
72 boolean acceptable = "h2-14".equals(protocol) || !(HTTP2Cipher.isBlackListProtocol(tlsProtocol) && HTTP2Cipher.isBlackListCipher(tlsCipher));
73 if (LOG.isDebugEnabled())
74 LOG.debug("proto={} tls={} cipher={} 9.2.2-acceptable={}",protocol,tlsProtocol,tlsCipher,acceptable);
75 return acceptable;
76 }
77
78 protected class HTTPServerSessionListener extends ServerSessionListener.Adapter implements Stream.Listener
79 {
80 private final Connector connector;
81 private final EndPoint endPoint;
82
83 public HTTPServerSessionListener(Connector connector, EndPoint endPoint)
84 {
85 this.connector = connector;
86 this.endPoint = endPoint;
87 }
88
89 protected HTTP2ServerConnection getConnection()
90 {
91 return (HTTP2ServerConnection)endPoint.getConnection();
92 }
93
94 @Override
95 public Map<Integer, Integer> onPreface(Session session)
96 {
97 Map<Integer, Integer> settings = new HashMap<>();
98 settings.put(SettingsFrame.HEADER_TABLE_SIZE, getMaxDynamicTableSize());
99 settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, getInitialStreamRecvWindow());
100 int maxConcurrentStreams = getMaxConcurrentStreams();
101 if (maxConcurrentStreams >= 0)
102 settings.put(SettingsFrame.MAX_CONCURRENT_STREAMS, maxConcurrentStreams);
103 settings.put(SettingsFrame.MAX_HEADER_LIST_SIZE, getHttpConfiguration().getRequestHeaderSize());
104 return settings;
105 }
106
107 @Override
108 public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
109 {
110 getConnection().onNewStream(connector, (IStream)stream, frame);
111 return this;
112 }
113
114 @Override
115 public boolean onIdleTimeout(Session session)
116 {
117 boolean close = super.onIdleTimeout(session);
118 if (!close)
119 return false;
120
121 long idleTimeout = getConnection().getEndPoint().getIdleTimeout();
122 return getConnection().onSessionTimeout(new TimeoutException("Session idle timeout " + idleTimeout + " ms"));
123 }
124
125 @Override
126 public void onClose(Session session, GoAwayFrame frame)
127 {
128 ErrorCode error = ErrorCode.from(frame.getError());
129 if (error == null)
130 error = ErrorCode.STREAM_CLOSED_ERROR;
131 String reason = frame.tryConvertPayload();
132 if (reason != null && !reason.isEmpty())
133 reason = " (" + reason + ")";
134 getConnection().onSessionFailure(new IOException("HTTP/2 " + error + reason));
135 }
136
137 @Override
138 public void onFailure(Session session, Throwable failure)
139 {
140 getConnection().onSessionFailure(failure);
141 }
142
143 @Override
144 public void onHeaders(Stream stream, HeadersFrame frame)
145 {
146
147 close(stream, "response_headers");
148 }
149
150 @Override
151 public Stream.Listener onPush(Stream stream, PushPromiseFrame frame)
152 {
153
154 close(stream, "push_promise");
155 return null;
156 }
157
158 @Override
159 public void onData(Stream stream, DataFrame frame, Callback callback)
160 {
161 getConnection().onData((IStream)stream, frame, callback);
162 }
163
164 @Override
165 public void onReset(Stream stream, ResetFrame frame)
166 {
167 ErrorCode error = ErrorCode.from(frame.getError());
168 if (error == null)
169 error = ErrorCode.CANCEL_STREAM_ERROR;
170 getConnection().onStreamFailure((IStream)stream, new IOException("HTTP/2 " + error));
171 }
172
173 @Override
174 public boolean onIdleTimeout(Stream stream, Throwable x)
175 {
176 return getConnection().onStreamTimeout((IStream)stream, x);
177 }
178
179 private void close(Stream stream, String reason)
180 {
181 stream.getSession().close(ErrorCode.PROTOCOL_ERROR.code, reason, Callback.NOOP);
182 }
183 }
184 }