1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.eclipse.jetty.server;
21
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24
25 import org.eclipse.jetty.http.BadMessageException;
26 import org.eclipse.jetty.http.HostPortHttpField;
27 import org.eclipse.jetty.http.HttpField;
28 import org.eclipse.jetty.http.HttpFields;
29 import org.eclipse.jetty.http.HttpGenerator;
30 import org.eclipse.jetty.http.HttpHeader;
31 import org.eclipse.jetty.http.HttpHeaderValue;
32 import org.eclipse.jetty.http.HttpMethod;
33 import org.eclipse.jetty.http.HttpParser;
34 import org.eclipse.jetty.http.HttpStatus;
35 import org.eclipse.jetty.http.HttpURI;
36 import org.eclipse.jetty.http.HttpVersion;
37 import org.eclipse.jetty.http.MetaData;
38 import org.eclipse.jetty.io.Connection;
39 import org.eclipse.jetty.io.EndPoint;
40 import org.eclipse.jetty.util.log.Log;
41 import org.eclipse.jetty.util.log.Logger;
42
43
44
45
46 class HttpChannelOverHttp extends HttpChannel implements HttpParser.RequestHandler
47 {
48 private static final Logger LOG = Log.getLogger(HttpChannelOverHttp.class);
49 private final static HttpField PREAMBLE_UPGRADE_H2C = new HttpField(HttpHeader.UPGRADE,"h2c");
50
51 private final HttpFields _fields = new HttpFields();
52 private final MetaData.Request _metadata = new MetaData.Request(_fields);
53 private final HttpConnection _httpConnection;
54 private HttpField _connection;
55 private HttpField _upgrade = null;
56 private boolean _delayedForContent;
57 private boolean _unknownExpectation = false;
58 private boolean _expect100Continue = false;
59 private boolean _expect102Processing = false;
60
61
62 public HttpChannelOverHttp(HttpConnection httpConnection, Connector connector, HttpConfiguration config, EndPoint endPoint, HttpTransport transport)
63 {
64 super(connector,config,endPoint,transport);
65 _httpConnection = httpConnection;
66 _metadata.setURI(new HttpURI());
67 }
68
69 @Override
70 protected HttpInput newHttpInput(HttpChannelState state)
71 {
72 return new HttpInputOverHTTP(state);
73 }
74
75 @Override
76 public void recycle()
77 {
78 super.recycle();
79 _unknownExpectation = false;
80 _expect100Continue = false;
81 _expect102Processing = false;
82 _metadata.recycle();
83 _connection=null;
84 _fields.clear();
85 _upgrade=null;
86 }
87
88 @Override
89 public boolean isExpecting100Continue()
90 {
91 return _expect100Continue;
92 }
93
94 @Override
95 public boolean isExpecting102Processing()
96 {
97 return _expect102Processing;
98 }
99
100 @Override
101 public boolean startRequest(String method, String uri, HttpVersion version)
102 {
103 _metadata.setMethod(method);
104 if (HttpMethod.CONNECT.is(method))
105 _metadata.getURI().parseConnect(uri);
106 else
107 _metadata.getURI().parse(uri);
108 _metadata.setHttpVersion(version);
109 _unknownExpectation = false;
110 _expect100Continue = false;
111 _expect102Processing = false;
112 return false;
113 }
114
115 @Override
116 public void parsedHeader(HttpField field)
117 {
118 HttpHeader header=field.getHeader();
119 String value=field.getValue();
120 if (header!=null)
121 {
122 switch(header)
123 {
124 case CONNECTION:
125 _connection=field;
126 break;
127
128 case HOST:
129 if (!_metadata.getURI().isAbsolute() && field instanceof HostPortHttpField)
130 {
131 HostPortHttpField hp = (HostPortHttpField)field;
132 _metadata.getURI().setAuthority(hp.getHost(),hp.getPort());
133 }
134 break;
135
136 case EXPECT:
137 {
138 if (_metadata.getVersion()==HttpVersion.HTTP_1_1)
139 {
140 HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value);
141 switch (expect == null ? HttpHeaderValue.UNKNOWN : expect)
142 {
143 case CONTINUE:
144 _expect100Continue = true;
145 break;
146
147 case PROCESSING:
148 _expect102Processing = true;
149 break;
150
151 default:
152 String[] values = field.getValues();
153 for (int i = 0; values != null && i < values.length; i++)
154 {
155 expect = HttpHeaderValue.CACHE.get(values[i].trim());
156 if (expect == null)
157 _unknownExpectation = true;
158 else
159 {
160 switch (expect)
161 {
162 case CONTINUE:
163 _expect100Continue = true;
164 break;
165 case PROCESSING:
166 _expect102Processing = true;
167 break;
168 default:
169 _unknownExpectation = true;
170 }
171 }
172 }
173 }
174 }
175 break;
176 }
177
178 case UPGRADE:
179 _upgrade=field;
180 break;
181
182 default:
183 break;
184 }
185 }
186 _fields.add(field);
187 }
188
189
190
191
192
193
194
195
196 @Override
197 public void continue100(int available) throws IOException
198 {
199
200
201 if (isExpecting100Continue())
202 {
203 _expect100Continue = false;
204
205
206 if (available == 0)
207 {
208 if (getResponse().isCommitted())
209 throw new IOException("Committed before 100 Continues");
210
211 boolean committed = sendResponse(HttpGenerator.CONTINUE_100_INFO, null, false);
212 if (!committed)
213 throw new IOException("Concurrent commit while trying to send 100-Continue");
214 }
215 }
216 }
217
218 @Override
219 public void earlyEOF()
220 {
221
222 if (_metadata.getMethod()==null)
223 _httpConnection.close();
224 else
225 onEarlyEOF();
226 }
227
228 @Override
229 public boolean content(ByteBuffer content)
230 {
231 HttpInput.Content c = _httpConnection.newContent(content);
232 boolean handle = onContent(c) || _delayedForContent;
233 _delayedForContent=false;
234 return handle;
235 }
236
237 public void asyncReadFillInterested()
238 {
239 _httpConnection.asyncReadFillInterested();
240 }
241
242 @Override
243 public void badMessage(int status, String reason)
244 {
245 _httpConnection.getGenerator().setPersistent(false);
246 try
247 {
248
249 onRequest(_metadata);
250 }
251 catch (Exception e)
252 {
253 LOG.ignore(e);
254 }
255
256 onBadMessage(status,reason);
257 }
258
259 @Override
260 public boolean headerComplete()
261 {
262 boolean persistent;
263
264 switch (_metadata.getVersion())
265 {
266 case HTTP_1_0:
267 {
268 if (getHttpConfiguration().isPersistentConnectionsEnabled())
269 {
270 if (_connection!=null)
271 {
272 if (_connection.contains(HttpHeaderValue.KEEP_ALIVE.asString()))
273 persistent=true;
274 else
275 persistent=_fields.contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString());
276 }
277 else
278 persistent=false;
279 }
280 else
281 persistent=false;
282
283 if (!persistent)
284 persistent = HttpMethod.CONNECT.is(_metadata.getMethod());
285 if (persistent)
286 getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE);
287
288 break;
289 }
290
291 case HTTP_1_1:
292 {
293 if (_unknownExpectation)
294 {
295 badMessage(HttpStatus.EXPECTATION_FAILED_417,null);
296 return false;
297 }
298
299 if (getHttpConfiguration().isPersistentConnectionsEnabled())
300 {
301 if (_connection!=null)
302 {
303 if (_connection.contains(HttpHeaderValue.CLOSE.asString()))
304 persistent=false;
305 else
306 persistent=!_fields.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString());
307 }
308 else
309 persistent=true;
310 }
311 else
312 persistent=false;
313
314 if (!persistent)
315 persistent = HttpMethod.CONNECT.is(_metadata.getMethod());
316 if (!persistent)
317 getResponse().getHttpFields().add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE);
318
319 if (_upgrade!=null && upgrade())
320 return true;
321
322 break;
323 }
324
325 case HTTP_2:
326 {
327
328 _upgrade=PREAMBLE_UPGRADE_H2C;
329
330 if (HttpMethod.PRI.is(_metadata.getMethod()) &&
331 "*".equals(_metadata.getURI().toString()) &&
332 _fields.size()==0 &&
333 upgrade())
334 return false;
335
336 badMessage(HttpStatus.UPGRADE_REQUIRED_426,null);
337 return false;
338 }
339
340 default:
341 {
342 throw new IllegalStateException();
343 }
344 }
345
346 if (!persistent)
347 _httpConnection.getGenerator().setPersistent(false);
348
349 onRequest(_metadata);
350
351
352
353 _delayedForContent = (getHttpConfiguration().isDelayDispatchUntilContent() && _httpConnection.getParser().getContentLength()>0 && !isExpecting100Continue() && !isCommitted() && _httpConnection.isRequestBufferEmpty());
354
355 return !_delayedForContent;
356 }
357
358
359
360
361
362
363
364
365
366
367
368 private boolean upgrade() throws BadMessageException
369 {
370 if (LOG.isDebugEnabled())
371 LOG.debug("upgrade {} {}",this,_upgrade);
372
373 if (_upgrade!=PREAMBLE_UPGRADE_H2C && (_connection==null || !_connection.getValue().contains("Upgrade")))
374 throw new BadMessageException(HttpStatus.BAD_REQUEST_400);
375
376
377 ConnectionFactory.Upgrading factory=null;
378 for (ConnectionFactory f : getConnector().getConnectionFactories())
379 {
380 if (f instanceof ConnectionFactory.Upgrading)
381 {
382 if (f.getProtocols().contains(_upgrade.getValue()))
383 {
384 factory=(ConnectionFactory.Upgrading)f;
385 break;
386 }
387 }
388 }
389
390 if (factory==null)
391 {
392 if (LOG.isDebugEnabled())
393 LOG.debug("No factory for {} in {}",_upgrade,getConnector());
394 return false;
395 }
396
397
398 HttpFields response101 = new HttpFields();
399 Connection upgrade_connection = factory.upgradeConnection(getConnector(),getEndPoint(),_metadata,response101);
400 if (upgrade_connection==null)
401 {
402 if (LOG.isDebugEnabled())
403 LOG.debug("Upgrade ignored for {} by {}",_upgrade,factory);
404 return false;
405 }
406
407
408 try
409 {
410 if (_upgrade!=PREAMBLE_UPGRADE_H2C)
411 sendResponse(new MetaData.Response(HttpVersion.HTTP_1_1,HttpStatus.SWITCHING_PROTOCOLS_101,response101,0),null,true);
412 }
413 catch(IOException e)
414 {
415 throw new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500,null,e);
416 }
417
418 if (LOG.isDebugEnabled())
419 LOG.debug("Upgrade from {} to {}", getEndPoint().getConnection(),upgrade_connection);
420 getRequest().setAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE,upgrade_connection);
421 getResponse().setStatus(101);
422 getHttpTransport().onCompleted();
423 return true;
424 }
425
426 @Override
427 protected void handleException(Throwable x)
428 {
429 _httpConnection.getGenerator().setPersistent(false);
430 super.handleException(x);
431 }
432
433 @Override
434 public void abort(Throwable failure)
435 {
436 super.abort(failure);
437 _httpConnection.getGenerator().setPersistent(false);
438 }
439
440 @Override
441 public boolean messageComplete()
442 {
443 return onRequestComplete();
444 }
445
446 @Override
447 public int getHeaderCacheSize()
448 {
449 return getHttpConfiguration().getHeaderCacheSize();
450 }
451 }