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