1 //
2 // ========================================================================
3 // Copyright (c) 1995-2014 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.http;
20
21 import java.nio.ByteBuffer;
22 import java.nio.charset.StandardCharsets;
23
24 import org.eclipse.jetty.http.HttpTokens.EndOfContent;
25 import org.eclipse.jetty.util.ArrayTernaryTrie;
26 import org.eclipse.jetty.util.ArrayTrie;
27 import org.eclipse.jetty.util.BufferUtil;
28 import org.eclipse.jetty.util.StringUtil;
29 import org.eclipse.jetty.util.Trie;
30 import org.eclipse.jetty.util.TypeUtil;
31 import org.eclipse.jetty.util.log.Log;
32 import org.eclipse.jetty.util.log.Logger;
33
34
35 /* ------------------------------------------------------------ */
36 /** A Parser for HTTP 0.9, 1.0 and 1.1
37 * <p>
38 * This parser parses HTTP client and server messages from buffers
39 * passed in the {@link #parseNext(ByteBuffer)} method. The parsed
40 * elements of the HTTP message are passed as event calls to the
41 * {@link HttpHandler} instance the parser is constructed with.
42 * If the passed handler is a {@link RequestHandler} then server side
43 * parsing is performed and if it is a {@link ResponseHandler}, then
44 * client side parsing is done.
45 * </p>
46 * <p>
47 * The contract of the {@link HttpHandler} API is that if a call returns
48 * true then the call to {@link #parseNext(ByteBuffer)} will return as
49 * soon as possible also with a true response. Typically this indicates
50 * that the parsing has reached a stage where the caller should process
51 * the events accumulated by the handler. It is the preferred calling
52 * style that handling such as calling a servlet to process a request,
53 * should be done after a true return from {@link #parseNext(ByteBuffer)}
54 * rather than from within the scope of a call like
55 * {@link RequestHandler#messageComplete()}
56 * </p>
57 * <p>
58 * For performance, the parse is heavily dependent on the
59 * {@link Trie#getBest(ByteBuffer, int, int)} method to look ahead in a
60 * single pass for both the structure ( : and CRLF ) and semantic (which
61 * header and value) of a header. Specifically the static {@link HttpHeader#CACHE}
62 * is used to lookup common combinations of headers and values
63 * (eg. "Connection: close"), or just header names (eg. "Connection:" ).
64 * For headers who's value is not known statically (eg. Host, COOKIE) then a
65 * per parser dynamic Trie of {@link HttpFields} from previous parsed messages
66 * is used to help the parsing of subsequent messages.
67 * </p>
68 * <p>
69 * If the system property "org.eclipse.jetty.http.HttpParser.STRICT" is set to true,
70 * then the parser will strictly pass on the exact strings received for methods and header
71 * fields. Otherwise a fast case insensitive string lookup is used that may alter the
72 * case of the method and/or headers
73 * </p>
74 */
75 public class HttpParser
76 {
77 public static final Logger LOG = Log.getLogger(HttpParser.class);
78 public final static boolean __STRICT=Boolean.getBoolean("org.eclipse.jetty.http.HttpParser.STRICT");
79 public final static int INITIAL_URI_LENGTH=256;
80
81 /**
82 * Cache of common {@link HttpField}s including: <UL>
83 * <LI>Common static combinations such as:<UL>
84 * <li>Connection: close
85 * <li>Accept-Encoding: gzip
86 * <li>Content-Length: 0
87 * </ul>
88 * <li>Combinations of Content-Type header for common mime types by common charsets
89 * <li>Most common headers with null values so that a lookup will at least
90 * determine the header name even if the name:value combination is not cached
91 * </ul>
92 */
93 public final static Trie<HttpField> CACHE = new ArrayTrie<>(2048);
94
95 // States
96 public enum State
97 {
98 START,
99 METHOD,
100 RESPONSE_VERSION,
101 SPACE1,
102 STATUS,
103 URI,
104 SPACE2,
105 REQUEST_VERSION,
106 REASON,
107 PROXY,
108 HEADER,
109 HEADER_IN_NAME,
110 HEADER_VALUE,
111 HEADER_IN_VALUE,
112 CONTENT,
113 EOF_CONTENT,
114 CHUNKED_CONTENT,
115 CHUNK_SIZE,
116 CHUNK_PARAMS,
117 CHUNK,
118 END,
119 CLOSED
120 }
121
122 private final boolean DEBUG=LOG.isDebugEnabled(); // Cache debug to help branch prediction
123 private final HttpHandler<ByteBuffer> _handler;
124 private final RequestHandler<ByteBuffer> _requestHandler;
125 private final ResponseHandler<ByteBuffer> _responseHandler;
126 private final int _maxHeaderBytes;
127 private final boolean _strict;
128 private HttpField _field;
129 private HttpHeader _header;
130 private String _headerString;
131 private HttpHeaderValue _value;
132 private String _valueString;
133 private int _responseStatus;
134 private int _headerBytes;
135 private boolean _host;
136
137 /* ------------------------------------------------------------------------------- */
138 private volatile State _state=State.START;
139 private volatile boolean _eof;
140 private volatile boolean _closed;
141 private HttpMethod _method;
142 private String _methodString;
143 private HttpVersion _version;
144 private ByteBuffer _uri=ByteBuffer.allocate(INITIAL_URI_LENGTH); // Tune?
145 private EndOfContent _endOfContent;
146 private long _contentLength;
147 private long _contentPosition;
148 private int _chunkLength;
149 private int _chunkPosition;
150 private boolean _headResponse;
151 private boolean _cr;
152 private ByteBuffer _contentChunk;
153 private Trie<HttpField> _connectionFields;
154
155 private int _length;
156 private final StringBuilder _string=new StringBuilder();
157
158 static
159 {
160 CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE));
161 CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE));
162 CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.UPGRADE));
163 CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip"));
164 CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate"));
165 CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip,deflate,sdch"));
166 CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-US,en;q=0.5"));
167 CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-GB,en-US;q=0.8,en;q=0.6"));
168 CACHE.put(new HttpField(HttpHeader.ACCEPT_CHARSET,"ISO-8859-1,utf-8;q=0.7,*;q=0.3"));
169 CACHE.put(new HttpField(HttpHeader.ACCEPT,"*/*"));
170 CACHE.put(new HttpField(HttpHeader.ACCEPT,"image/png,image/*;q=0.8,*/*;q=0.5"));
171 CACHE.put(new HttpField(HttpHeader.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
172 CACHE.put(new HttpField(HttpHeader.PRAGMA,"no-cache"));
173 CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"private, no-cache, no-cache=Set-Cookie, proxy-revalidate"));
174 CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"no-cache"));
175 CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH,"0"));
176 CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"gzip"));
177 CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"deflate"));
178 CACHE.put(new HttpField(HttpHeader.TRANSFER_ENCODING,"chunked"));
179 CACHE.put(new HttpField(HttpHeader.EXPIRES,"Fri, 01 Jan 1990 00:00:00 GMT"));
180
181 // Add common Content types as fields
182 for (String type : new String[]{"text/plain","text/html","text/xml","text/json","application/json","application/x-www-form-urlencoded"})
183 {
184 HttpField field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type);
185 CACHE.put(field);
186
187 for (String charset : new String[]{"UTF-8","ISO-8859-1"})
188 {
189 CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+";charset="+charset));
190 CACHE.put(new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,type+"; charset="+charset));
191 }
192 }
193
194 // Add headers with null values so HttpParser can avoid looking up name again for unknown values
195 for (HttpHeader h:HttpHeader.values())
196 if (!CACHE.put(new HttpField(h,(String)null)))
197 throw new IllegalStateException("CACHE FULL");
198 // Add some more common headers
199 CACHE.put(new HttpField(HttpHeader.REFERER,(String)null));
200 CACHE.put(new HttpField(HttpHeader.IF_MODIFIED_SINCE,(String)null));
201 CACHE.put(new HttpField(HttpHeader.IF_NONE_MATCH,(String)null));
202 CACHE.put(new HttpField(HttpHeader.AUTHORIZATION,(String)null));
203 CACHE.put(new HttpField(HttpHeader.COOKIE,(String)null));
204 }
205
206 /* ------------------------------------------------------------------------------- */
207 public HttpParser(RequestHandler<ByteBuffer> handler)
208 {
209 this(handler,-1,__STRICT);
210 }
211
212 /* ------------------------------------------------------------------------------- */
213 public HttpParser(ResponseHandler<ByteBuffer> handler)
214 {
215 this(handler,-1,__STRICT);
216 }
217
218 /* ------------------------------------------------------------------------------- */
219 public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes)
220 {
221 this(handler,maxHeaderBytes,__STRICT);
222 }
223
224 /* ------------------------------------------------------------------------------- */
225 public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes)
226 {
227 this(handler,maxHeaderBytes,__STRICT);
228 }
229
230 /* ------------------------------------------------------------------------------- */
231 public HttpParser(RequestHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
232 {
233 _handler=handler;
234 _requestHandler=handler;
235 _responseHandler=null;
236 _maxHeaderBytes=maxHeaderBytes;
237 _strict=strict;
238 }
239
240 /* ------------------------------------------------------------------------------- */
241 public HttpParser(ResponseHandler<ByteBuffer> handler,int maxHeaderBytes,boolean strict)
242 {
243 _handler=handler;
244 _requestHandler=null;
245 _responseHandler=handler;
246 _maxHeaderBytes=maxHeaderBytes;
247 _strict=strict;
248 }
249
250 /* ------------------------------------------------------------------------------- */
251 public long getContentLength()
252 {
253 return _contentLength;
254 }
255
256 /* ------------------------------------------------------------ */
257 public long getContentRead()
258 {
259 return _contentPosition;
260 }
261
262 /* ------------------------------------------------------------ */
263 /** Set if a HEAD response is expected
264 * @param head
265 */
266 public void setHeadResponse(boolean head)
267 {
268 _headResponse=head;
269 }
270
271 /* ------------------------------------------------------------------------------- */
272 protected void setResponseStatus(int status)
273 {
274 _responseStatus=status;
275 }
276
277 /* ------------------------------------------------------------------------------- */
278 public State getState()
279 {
280 return _state;
281 }
282
283 /* ------------------------------------------------------------------------------- */
284 public boolean inContentState()
285 {
286 return _state.ordinal()>=State.CONTENT.ordinal() && _state.ordinal()<State.END.ordinal();
287 }
288
289 /* ------------------------------------------------------------------------------- */
290 public boolean inHeaderState()
291 {
292 return _state.ordinal() < State.CONTENT.ordinal();
293 }
294
295 /* ------------------------------------------------------------------------------- */
296 public boolean isChunking()
297 {
298 return _endOfContent==EndOfContent.CHUNKED_CONTENT;
299 }
300
301 /* ------------------------------------------------------------ */
302 public boolean isStart()
303 {
304 return isState(State.START);
305 }
306
307 /* ------------------------------------------------------------ */
308 public boolean isClosed()
309 {
310 return isState(State.CLOSED);
311 }
312
313 /* ------------------------------------------------------------ */
314 public boolean isIdle()
315 {
316 return isState(State.START)||isState(State.END)||isState(State.CLOSED);
317 }
318
319 /* ------------------------------------------------------------ */
320 public boolean isComplete()
321 {
322 return isState(State.END)||isState(State.CLOSED);
323 }
324
325 /* ------------------------------------------------------------------------------- */
326 public boolean isState(State state)
327 {
328 return _state == state;
329 }
330
331 /* ------------------------------------------------------------------------------- */
332 private static class BadMessage extends Error
333 {
334 private static final long serialVersionUID = 1L;
335 private final int _code;
336 private final String _message;
337
338 BadMessage()
339 {
340 this(400,null);
341 }
342
343 BadMessage(int code)
344 {
345 this(code,null);
346 }
347
348 BadMessage(String message)
349 {
350 this(400,message);
351 }
352
353 BadMessage(int code,String message)
354 {
355 _code=code;
356 _message=message;
357 }
358
359 }
360
361 /* ------------------------------------------------------------------------------- */
362 private byte next(ByteBuffer buffer)
363 {
364 byte ch = buffer.get();
365
366 if (_cr)
367 {
368 if (ch!=HttpTokens.LINE_FEED)
369 throw new BadMessage("Bad EOL");
370 _cr=false;
371 return ch;
372 }
373
374 if (ch>=0 && ch<HttpTokens.SPACE)
375 {
376 if (ch==HttpTokens.CARRIAGE_RETURN)
377 {
378 if (buffer.hasRemaining())
379 {
380 if(_maxHeaderBytes>0 && _state.ordinal()<State.END.ordinal())
381 _headerBytes++;
382 ch=buffer.get();
383 if (ch!=HttpTokens.LINE_FEED)
384 throw new BadMessage("Bad EOL");
385 }
386 else
387 {
388 _cr=true;
389 // Can return 0 here to indicate the need for more characters,
390 // because a real 0 in the buffer would cause a BadMessage below
391 return 0;
392 }
393 }
394 // Only LF or TAB acceptable special characters
395 else if (!(ch==HttpTokens.LINE_FEED || ch==HttpTokens.TAB))
396 throw new BadMessage("Illegal character");
397 }
398
399 return ch;
400 }
401
402 /* ------------------------------------------------------------------------------- */
403 /* Quick lookahead for the start state looking for a request method or a HTTP version,
404 * otherwise skip white space until something else to parse.
405 */
406 private boolean quickStart(ByteBuffer buffer)
407 {
408 if (_requestHandler!=null)
409 {
410 _method = HttpMethod.lookAheadGet(buffer);
411 if (_method!=null)
412 {
413 _methodString = _method.asString();
414 buffer.position(buffer.position()+_methodString.length()+1);
415
416 setState(State.SPACE1);
417 return false;
418 }
419 }
420 else if (_responseHandler!=null)
421 {
422 _version = HttpVersion.lookAheadGet(buffer);
423 if (_version!=null)
424 {
425 buffer.position(buffer.position()+_version.asString().length()+1);
426 setState(State.SPACE1);
427 return false;
428 }
429 }
430
431 // Quick start look
432 while (_state==State.START && buffer.hasRemaining())
433 {
434 int ch=next(buffer);
435
436 if (ch > HttpTokens.SPACE)
437 {
438 _string.setLength(0);
439 _string.append((char)ch);
440 setState(_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION);
441 return false;
442 }
443 else if (ch==0)
444 break;
445 else if (ch<0)
446 throw new BadMessage();
447
448 // count this white space as a header byte to avoid DOS
449 if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
450 {
451 LOG.warn("padding is too large >"+_maxHeaderBytes);
452 throw new BadMessage(HttpStatus.BAD_REQUEST_400);
453 }
454 }
455 return false;
456 }
457
458 /* ------------------------------------------------------------------------------- */
459 private void setString(String s)
460 {
461 _string.setLength(0);
462 _string.append(s);
463 _length=s.length();
464 }
465
466 /* ------------------------------------------------------------------------------- */
467 private String takeString()
468 {
469 _string.setLength(_length);
470 String s =_string.toString();
471 _string.setLength(0);
472 _length=-1;
473 return s;
474 }
475
476 /* ------------------------------------------------------------------------------- */
477 /* Parse a request or response line
478 */
479 private boolean parseLine(ByteBuffer buffer)
480 {
481 boolean handle=false;
482
483 // Process headers
484 while (_state.ordinal()<State.HEADER.ordinal() && buffer.hasRemaining() && !handle)
485 {
486 // process each character
487 byte ch=next(buffer);
488 if (ch==0)
489 break;
490
491 if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
492 {
493 if (_state==State.URI)
494 {
495 LOG.warn("URI is too large >"+_maxHeaderBytes);
496 throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
497 }
498 else
499 {
500 if (_requestHandler!=null)
501 LOG.warn("request is too large >"+_maxHeaderBytes);
502 else
503 LOG.warn("response is too large >"+_maxHeaderBytes);
504 throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
505 }
506 }
507
508 switch (_state)
509 {
510 case METHOD:
511 if (ch == HttpTokens.SPACE)
512 {
513 _length=_string.length();
514 _methodString=takeString();
515 HttpMethod method=HttpMethod.CACHE.get(_methodString);
516 if (method!=null && !_strict)
517 _methodString=method.asString();
518 setState(State.SPACE1);
519 }
520 else if (ch < HttpTokens.SPACE)
521 throw new BadMessage(ch<0?"Illegal character":"No URI");
522 else
523 _string.append((char)ch);
524 break;
525
526 case RESPONSE_VERSION:
527 if (ch == HttpTokens.SPACE)
528 {
529 _length=_string.length();
530 String version=takeString();
531 _version=HttpVersion.CACHE.get(version);
532 if (_version==null)
533 throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version");
534 setState(State.SPACE1);
535 }
536 else if (ch < HttpTokens.SPACE)
537 throw new BadMessage(ch<0?"Illegal character":"No Status");
538 else
539 _string.append((char)ch);
540 break;
541
542 case SPACE1:
543 if (ch > HttpTokens.SPACE || ch<0)
544 {
545 if (_responseHandler!=null)
546 {
547 setState(State.STATUS);
548 setResponseStatus(ch-'0');
549 }
550 else
551 {
552 _uri.clear();
553 setState(State.URI);
554 // quick scan for space or EoBuffer
555 if (buffer.hasArray())
556 {
557 byte[] array=buffer.array();
558 int p=buffer.arrayOffset()+buffer.position();
559 int l=buffer.arrayOffset()+buffer.limit();
560 int i=p;
561 while (i<l && array[i]>HttpTokens.SPACE)
562 i++;
563
564 int len=i-p;
565 _headerBytes+=len;
566
567 if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
568 {
569 LOG.warn("URI is too large >"+_maxHeaderBytes);
570 throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
571 }
572 if (_uri.remaining()<=len)
573 {
574 ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()+2*len);
575 _uri.flip();
576 uri.put(_uri);
577 _uri=uri;
578 }
579 _uri.put(array,p-1,len+1);
580 buffer.position(i-buffer.arrayOffset());
581 }
582 else
583 _uri.put(ch);
584 }
585 }
586 else if (ch < HttpTokens.SPACE)
587 {
588 throw new BadMessage(HttpStatus.BAD_REQUEST_400,_requestHandler!=null?"No URI":"No Status");
589 }
590 break;
591
592 case STATUS:
593 if (ch == HttpTokens.SPACE)
594 {
595 setState(State.SPACE2);
596 }
597 else if (ch>='0' && ch<='9')
598 {
599 _responseStatus=_responseStatus*10+(ch-'0');
600 }
601 else if (ch < HttpTokens.SPACE && ch>=0)
602 {
603 handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle;
604 setState(State.HEADER);
605 }
606 else
607 {
608 throw new BadMessage();
609 }
610 break;
611
612 case URI:
613 if (ch == HttpTokens.SPACE)
614 {
615 setState(State.SPACE2);
616 }
617 else if (ch < HttpTokens.SPACE && ch>=0)
618 {
619 // HTTP/0.9
620 _uri.flip();
621 handle=_requestHandler.startRequest(_method,_methodString,_uri,null)||handle;
622 setState(State.END);
623 BufferUtil.clear(buffer);
624 handle=_handler.headerComplete()||handle;
625 handle=_handler.messageComplete()||handle;
626 }
627 else
628 {
629 if (!_uri.hasRemaining())
630 {
631 ByteBuffer uri = ByteBuffer.allocate(_uri.capacity()*2);
632 _uri.flip();
633 uri.put(_uri);
634 _uri=uri;
635 }
636 _uri.put(ch);
637 }
638 break;
639
640 case SPACE2:
641 if (ch > HttpTokens.SPACE)
642 {
643 _string.setLength(0);
644 _string.append((char)ch);
645 if (_responseHandler!=null)
646 {
647 _length=1;
648 setState(State.REASON);
649 }
650 else
651 {
652 setState(State.REQUEST_VERSION);
653
654 // try quick look ahead for HTTP Version
655 HttpVersion version;
656 if (buffer.position()>0 && buffer.hasArray())
657 version=HttpVersion.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit());
658 else
659 version=HttpVersion.CACHE.getBest(buffer,0,buffer.remaining());
660 if (version==null)
661 {
662 if (_method==HttpMethod.PROXY)
663 {
664 if (!(_requestHandler instanceof ProxyHandler))
665 throw new BadMessage();
666
667 _uri.flip();
668 String protocol=BufferUtil.toString(_uri);
669 // This is the proxy protocol, so we can assume entire first line is in buffer else 400
670 buffer.position(buffer.position()-1);
671 String sAddr = getProxyField(buffer);
672 String dAddr = getProxyField(buffer);
673 int sPort = BufferUtil.takeInt(buffer);
674 next(buffer);
675 int dPort = BufferUtil.takeInt(buffer);
676 next(buffer);
677 _state=State.START;
678 ((ProxyHandler)_requestHandler).proxied(protocol,sAddr,dAddr,sPort,dPort);
679 return false;
680 }
681 }
682 else
683 {
684 int pos = buffer.position()+version.asString().length()-1;
685 if (pos<buffer.limit())
686 {
687 byte n=buffer.get(pos);
688 if (n==HttpTokens.CARRIAGE_RETURN)
689 {
690 _cr=true;
691 _version=version;
692 _string.setLength(0);
693 buffer.position(pos+1);
694 }
695 else if (n==HttpTokens.LINE_FEED)
696 {
697 _version=version;
698 _string.setLength(0);
699 buffer.position(pos);
700 }
701 }
702 }
703 }
704 }
705 else if (ch == HttpTokens.LINE_FEED)
706 {
707 if (_responseHandler!=null)
708 {
709 handle=_responseHandler.startResponse(_version, _responseStatus, null)||handle;
710 setState(State.HEADER);
711 }
712 else
713 {
714 // HTTP/0.9
715 _uri.flip();
716 handle=_requestHandler.startRequest(_method,_methodString,_uri, null)||handle;
717 setState(State.END);
718 BufferUtil.clear(buffer);
719 handle=_handler.headerComplete()||handle;
720 handle=_handler.messageComplete()||handle;
721 }
722 }
723 else if (ch<0)
724 throw new BadMessage();
725 break;
726
727 case REQUEST_VERSION:
728 if (ch == HttpTokens.LINE_FEED)
729 {
730 if (_version==null)
731 {
732 _length=_string.length();
733 _version=HttpVersion.CACHE.get(takeString());
734 }
735 if (_version==null)
736 throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Unknown Version");
737
738 // Should we try to cache header fields?
739 if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
740 {
741 int header_cache = _handler.getHeaderCacheSize();
742 _connectionFields=new ArrayTernaryTrie<>(header_cache);
743 }
744
745 setState(State.HEADER);
746 _uri.flip();
747 handle=_requestHandler.startRequest(_method,_methodString,_uri, _version)||handle;
748 continue;
749 }
750 else if (ch>=HttpTokens.SPACE)
751 _string.append((char)ch);
752 else
753 throw new BadMessage();
754
755 break;
756
757 case REASON:
758 if (ch == HttpTokens.LINE_FEED)
759 {
760 String reason=takeString();
761
762 setState(State.HEADER);
763 handle=_responseHandler.startResponse(_version, _responseStatus, reason)||handle;
764 continue;
765 }
766 else if (ch>=HttpTokens.SPACE)
767 {
768 _string.append((char)ch);
769 if (ch!=' '&&ch!='\t')
770 _length=_string.length();
771 }
772 else
773 throw new BadMessage();
774 break;
775
776 default:
777 throw new IllegalStateException(_state.toString());
778
779 }
780 }
781
782 return handle;
783 }
784
785 private boolean handleKnownHeaders(ByteBuffer buffer)
786 {
787 boolean add_to_connection_trie=false;
788 switch (_header)
789 {
790 case CONTENT_LENGTH:
791 if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
792 {
793 try
794 {
795 _contentLength=Long.parseLong(_valueString);
796 }
797 catch(NumberFormatException e)
798 {
799 LOG.ignore(e);
800 throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
801 }
802 if (_contentLength <= 0)
803 _endOfContent=EndOfContent.NO_CONTENT;
804 else
805 _endOfContent=EndOfContent.CONTENT_LENGTH;
806 }
807 break;
808
809 case TRANSFER_ENCODING:
810 if (_value==HttpHeaderValue.CHUNKED)
811 _endOfContent=EndOfContent.CHUNKED_CONTENT;
812 else
813 {
814 if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString()))
815 _endOfContent=EndOfContent.CHUNKED_CONTENT;
816 else if (_valueString.contains(HttpHeaderValue.CHUNKED.toString()))
817 {
818 throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad chunking");
819 }
820 }
821 break;
822
823 case HOST:
824 add_to_connection_trie=_connectionFields!=null && _field==null;
825 _host=true;
826 String host=_valueString;
827 int port=0;
828 if (host==null || host.length()==0)
829 {
830 throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header");
831 }
832
833 int len=host.length();
834 loop: for (int i = len; i-- > 0;)
835 {
836 char c2 = (char)(0xff & host.charAt(i));
837 switch (c2)
838 {
839 case ']':
840 break loop;
841
842 case ':':
843 try
844 {
845 len=i;
846 port = StringUtil.toInt(host.substring(i+1));
847 }
848 catch (NumberFormatException e)
849 {
850 if (DEBUG)
851 LOG.debug(e);
852 throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad Host header");
853 }
854 break loop;
855 }
856 }
857 if (host.charAt(0)=='[')
858 {
859 if (host.charAt(len-1)!=']')
860 {
861 throw new BadMessage(HttpStatus.BAD_REQUEST_400,"Bad IPv6 Host header");
862 }
863 host = host.substring(0,len);
864 }
865 else if (len!=host.length())
866 host = host.substring(0,len);
867
868 if (_requestHandler!=null)
869 _requestHandler.parsedHostHeader(host,port);
870
871 break;
872
873 case CONNECTION:
874 // Don't cache if not persistent
875 if (_valueString!=null && _valueString.contains("close"))
876 {
877 _closed=true;
878 _connectionFields=null;
879 }
880 break;
881
882 case AUTHORIZATION:
883 case ACCEPT:
884 case ACCEPT_CHARSET:
885 case ACCEPT_ENCODING:
886 case ACCEPT_LANGUAGE:
887 case COOKIE:
888 case CACHE_CONTROL:
889 case USER_AGENT:
890 add_to_connection_trie=_connectionFields!=null && _field==null;
891 break;
892
893 default: break;
894 }
895
896 if (add_to_connection_trie && !_connectionFields.isFull() && _header!=null && _valueString!=null)
897 {
898 _field=new HttpField(_header,_valueString);
899 _connectionFields.put(_field);
900 }
901
902 return false;
903 }
904
905
906 /* ------------------------------------------------------------------------------- */
907 /*
908 * Parse the message headers and return true if the handler has signaled for a return
909 */
910 protected boolean parseHeaders(ByteBuffer buffer)
911 {
912 boolean handle=false;
913
914 // Process headers
915 while (_state.ordinal()<State.CONTENT.ordinal() && buffer.hasRemaining() && !handle)
916 {
917 // process each character
918 byte ch=next(buffer);
919 if (ch==0)
920 break;
921
922 if (_maxHeaderBytes>0 && ++_headerBytes>_maxHeaderBytes)
923 {
924 LOG.warn("Header is too large >"+_maxHeaderBytes);
925 throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
926 }
927
928 switch (_state)
929 {
930 case HEADER:
931 switch(ch)
932 {
933 case HttpTokens.COLON:
934 case HttpTokens.SPACE:
935 case HttpTokens.TAB:
936 {
937 // header value without name - continuation?
938 if (_valueString==null)
939 {
940 _string.setLength(0);
941 _length=0;
942 }
943 else
944 {
945 setString(_valueString);
946 _string.append(' ');
947 _length++;
948 _valueString=null;
949 }
950 setState(State.HEADER_VALUE);
951 break;
952 }
953
954 default:
955 {
956 // handler last header if any. Delayed to here just in case there was a continuation line (above)
957 if (_headerString!=null || _valueString!=null)
958 {
959 // Handle known headers
960 if (_header!=null && handleKnownHeaders(buffer))
961 {
962 _headerString=_valueString=null;
963 _header=null;
964 _value=null;
965 _field=null;
966 return true;
967 }
968 handle=_handler.parsedHeader(_field!=null?_field:new HttpField(_header,_headerString,_valueString))||handle;
969 }
970 _headerString=_valueString=null;
971 _header=null;
972 _value=null;
973 _field=null;
974
975 // now handle the ch
976 if (ch == HttpTokens.LINE_FEED)
977 {
978 _contentPosition=0;
979
980 // End of headers!
981
982 // Was there a required host header?
983 if (!_host && _version!=HttpVersion.HTTP_1_0 && _requestHandler!=null)
984 {
985 throw new BadMessage(HttpStatus.BAD_REQUEST_400,"No Host");
986 }
987
988 // is it a response that cannot have a body?
989 if (_responseHandler !=null && // response
990 (_responseStatus == 304 || // not-modified response
991 _responseStatus == 204 || // no-content response
992 _responseStatus < 200)) // 1xx response
993 _endOfContent=EndOfContent.NO_CONTENT; // ignore any other headers set
994
995 // else if we don't know framing
996 else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
997 {
998 if (_responseStatus == 0 // request
999 || _responseStatus == 304 // not-modified response
1000 || _responseStatus == 204 // no-content response
1001 || _responseStatus < 200) // 1xx response
1002 _endOfContent=EndOfContent.NO_CONTENT;
1003 else
1004 _endOfContent=EndOfContent.EOF_CONTENT;
1005 }
1006
1007 // How is the message ended?
1008 switch (_endOfContent)
1009 {
1010 case EOF_CONTENT:
1011 setState(State.EOF_CONTENT);
1012 handle=_handler.headerComplete()||handle;
1013 break;
1014
1015 case CHUNKED_CONTENT:
1016 setState(State.CHUNKED_CONTENT);
1017 handle=_handler.headerComplete()||handle;
1018 break;
1019
1020 case NO_CONTENT:
1021 handle=_handler.headerComplete()||handle;
1022 setState(State.END);
1023 handle=_handler.messageComplete()||handle;
1024 break;
1025
1026 default:
1027 setState(State.CONTENT);
1028 handle=_handler.headerComplete()||handle;
1029 break;
1030 }
1031 }
1032 else if (ch<=HttpTokens.SPACE)
1033 throw new BadMessage();
1034 else
1035 {
1036 if (buffer.hasRemaining())
1037 {
1038 // Try a look ahead for the known header name and value.
1039 HttpField field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining());
1040 if (field==null)
1041 field=CACHE.getBest(buffer,-1,buffer.remaining());
1042
1043 if (field!=null)
1044 {
1045 final String n;
1046 final String v;
1047
1048 if (_strict)
1049 {
1050 // Have to get the fields exactly from the buffer to match case
1051 String fn=field.getName();
1052 String fv=field.getValue();
1053 n=BufferUtil.toString(buffer,buffer.position()-1,fn.length(),StandardCharsets.US_ASCII);
1054 if (fv==null)
1055 v=null;
1056 else
1057 {
1058 v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1);
1059 field=new HttpField(field.getHeader(),n,v);
1060 }
1061 }
1062 else
1063 {
1064 n=field.getName();
1065 v=field.getValue();
1066 }
1067
1068 _header=field.getHeader();
1069 _headerString=n;
1070
1071 if (v==null)
1072 {
1073 // Header only
1074 setState(State.HEADER_VALUE);
1075 _string.setLength(0);
1076 _length=0;
1077 buffer.position(buffer.position()+n.length()+1);
1078 break;
1079 }
1080 else
1081 {
1082 // Header and value
1083 int pos=buffer.position()+n.length()+v.length()+1;
1084 byte b=buffer.get(pos);
1085
1086 if (b==HttpTokens.CARRIAGE_RETURN || b==HttpTokens.LINE_FEED)
1087 {
1088 _field=field;
1089 _valueString=v;
1090 setState(State.HEADER_IN_VALUE);
1091
1092 if (b==HttpTokens.CARRIAGE_RETURN)
1093 {
1094 _cr=true;
1095 buffer.position(pos+1);
1096 }
1097 else
1098 buffer.position(pos);
1099 break;
1100 }
1101 else
1102 {
1103 setState(State.HEADER_IN_VALUE);
1104 setString(v);
1105 buffer.position(pos);
1106 break;
1107 }
1108 }
1109 }
1110 }
1111
1112 // New header
1113 setState(State.HEADER_IN_NAME);
1114 _string.setLength(0);
1115 _string.append((char)ch);
1116 _length=1;
1117 }
1118 }
1119 }
1120 break;
1121
1122 case HEADER_IN_NAME:
1123 if (ch==HttpTokens.COLON || ch==HttpTokens.LINE_FEED)
1124 {
1125 if (_headerString==null)
1126 {
1127 _headerString=takeString();
1128 _header=HttpHeader.CACHE.get(_headerString);
1129 }
1130 _length=-1;
1131
1132 setState(ch==HttpTokens.LINE_FEED?State.HEADER:State.HEADER_VALUE);
1133 break;
1134 }
1135
1136 if (ch>=HttpTokens.SPACE || ch==HttpTokens.TAB)
1137 {
1138 if (_header!=null)
1139 {
1140 setString(_header.asString());
1141 _header=null;
1142 _headerString=null;
1143 }
1144
1145 _string.append((char)ch);
1146 if (ch>HttpTokens.SPACE)
1147 _length=_string.length();
1148 break;
1149 }
1150
1151 throw new BadMessage("Illegal character");
1152
1153 case HEADER_VALUE:
1154 if (ch>HttpTokens.SPACE || ch<0)
1155 {
1156 _string.append((char)(0xff&ch));
1157 _length=_string.length();
1158 setState(State.HEADER_IN_VALUE);
1159 break;
1160 }
1161
1162 if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB)
1163 break;
1164
1165 if (ch==HttpTokens.LINE_FEED)
1166 {
1167 if (_length > 0)
1168 {
1169 _value=null;
1170 _valueString=(_valueString==null)?takeString():(_valueString+" "+takeString());
1171 }
1172 setState(State.HEADER);
1173 break;
1174 }
1175
1176 throw new BadMessage("Illegal character");
1177
1178 case HEADER_IN_VALUE:
1179 if (ch>=HttpTokens.SPACE || ch<0 || ch==HttpTokens.TAB)
1180 {
1181 if (_valueString!=null)
1182 {
1183 setString(_valueString);
1184 _valueString=null;
1185 _field=null;
1186 }
1187 _string.append((char)(0xff&ch));
1188 if (ch>HttpTokens.SPACE || ch<0)
1189 _length=_string.length();
1190 break;
1191 }
1192
1193 if (ch==HttpTokens.LINE_FEED)
1194 {
1195 if (_length > 0)
1196 {
1197 _value=null;
1198 _valueString=takeString();
1199 _length=-1;
1200 }
1201 setState(State.HEADER);
1202 break;
1203 }
1204 throw new BadMessage("Illegal character");
1205
1206 default:
1207 throw new IllegalStateException(_state.toString());
1208
1209 }
1210 }
1211
1212 return handle;
1213 }
1214
1215 /* ------------------------------------------------------------------------------- */
1216 /**
1217 * Parse until next Event.
1218 * @return True if an {@link RequestHandler} method was called and it returned true;
1219 */
1220 public boolean parseNext(ByteBuffer buffer)
1221 {
1222 if (DEBUG)
1223 LOG.debug("parseNext s={} {}",_state,BufferUtil.toDetailString(buffer));
1224 try
1225 {
1226 // Start a request/response
1227 if (_state==State.START)
1228 {
1229 _version=null;
1230 _method=null;
1231 _methodString=null;
1232 _endOfContent=EndOfContent.UNKNOWN_CONTENT;
1233 _header=null;
1234 if (quickStart(buffer))
1235 return true;
1236 }
1237
1238 // Request/response line
1239 if (_state.ordinal()>= State.START.ordinal() && _state.ordinal()<State.HEADER.ordinal())
1240 {
1241 if (parseLine(buffer))
1242 return true;
1243 }
1244
1245 // parse headers
1246 if (_state.ordinal()>= State.HEADER.ordinal() && _state.ordinal()<State.CONTENT.ordinal())
1247 {
1248 if (parseHeaders(buffer))
1249 return true;
1250 }
1251
1252 // parse content
1253 if (_state.ordinal()>= State.CONTENT.ordinal() && _state.ordinal()<State.END.ordinal())
1254 {
1255 // Handle HEAD response
1256 if (_responseStatus>0 && _headResponse)
1257 {
1258 setState(State.END);
1259 if (_handler.messageComplete())
1260 return true;
1261 }
1262 else
1263 {
1264 if (parseContent(buffer))
1265 return true;
1266 }
1267 }
1268
1269 // handle end states
1270 if (_state==State.END)
1271 {
1272 // eat white space
1273 while (buffer.remaining()>0 && buffer.get(buffer.position())<=HttpTokens.SPACE)
1274 buffer.get();
1275 }
1276 else if (_state==State.CLOSED)
1277 {
1278 if (BufferUtil.hasContent(buffer))
1279 {
1280 // Just ignore data when closed
1281 _headerBytes+=buffer.remaining();
1282 BufferUtil.clear(buffer);
1283 if (_headerBytes>_maxHeaderBytes)
1284 {
1285 // Don't want to waste time reading data of a closed request
1286 throw new IllegalStateException("too much data after closed");
1287 }
1288 }
1289 }
1290
1291 // Handle EOF
1292 if (_eof && !buffer.hasRemaining())
1293 {
1294 switch(_state)
1295 {
1296 case CLOSED:
1297 break;
1298
1299 case START:
1300 setState(State.CLOSED);
1301 _handler.earlyEOF();
1302 break;
1303
1304 case END:
1305 setState(State.CLOSED);
1306 break;
1307
1308 case EOF_CONTENT:
1309 setState(State.CLOSED);
1310 return _handler.messageComplete();
1311
1312 case CONTENT:
1313 case CHUNKED_CONTENT:
1314 case CHUNK_SIZE:
1315 case CHUNK_PARAMS:
1316 case CHUNK:
1317 setState(State.CLOSED);
1318 _handler.earlyEOF();
1319 break;
1320
1321 default:
1322 if (DEBUG)
1323 LOG.debug("{} EOF in {}",this,_state);
1324 setState(State.CLOSED);
1325 _handler.badMessage(400,null);
1326 break;
1327 }
1328 }
1329
1330 return false;
1331 }
1332 catch(BadMessage e)
1333 {
1334 BufferUtil.clear(buffer);
1335
1336 LOG.warn("badMessage: "+e._code+(e._message!=null?" "+e._message:"")+" for "+_handler);
1337 if (DEBUG)
1338 LOG.debug(e);
1339 setState(State.CLOSED);
1340 _handler.badMessage(e._code, e._message);
1341 return false;
1342 }
1343 catch(Exception e)
1344 {
1345 BufferUtil.clear(buffer);
1346
1347 LOG.warn("badMessage: "+e.toString()+" for "+_handler);
1348 if (DEBUG)
1349 LOG.debug(e);
1350
1351 if (_state.ordinal()<=State.END.ordinal())
1352 {
1353 setState(State.CLOSED);
1354 _handler.badMessage(400,null);
1355 }
1356 else
1357 {
1358 _handler.earlyEOF();
1359 setState(State.CLOSED);
1360 }
1361
1362 return false;
1363 }
1364 }
1365
1366 protected boolean parseContent(ByteBuffer buffer)
1367 {
1368 int remaining=buffer.remaining();
1369 if (remaining==0 && _state==State.CONTENT)
1370 {
1371 long content=_contentLength - _contentPosition;
1372 if (content == 0)
1373 {
1374 setState(State.END);
1375 if (_handler.messageComplete())
1376 return true;
1377 }
1378 }
1379
1380 // Handle _content
1381 byte ch;
1382 while (_state.ordinal() < State.END.ordinal() && remaining>0)
1383 {
1384 switch (_state)
1385 {
1386 case EOF_CONTENT:
1387 _contentChunk=buffer.asReadOnlyBuffer();
1388 _contentPosition += remaining;
1389 buffer.position(buffer.position()+remaining);
1390 if (_handler.content(_contentChunk))
1391 return true;
1392 break;
1393
1394 case CONTENT:
1395 {
1396 long content=_contentLength - _contentPosition;
1397 if (content == 0)
1398 {
1399 setState(State.END);
1400 if (_handler.messageComplete())
1401 return true;
1402 }
1403 else
1404 {
1405 _contentChunk=buffer.asReadOnlyBuffer();
1406
1407 // limit content by expected size
1408 if (remaining > content)
1409 {
1410 // We can cast remaining to an int as we know that it is smaller than
1411 // or equal to length which is already an int.
1412 _contentChunk.limit(_contentChunk.position()+(int)content);
1413 }
1414
1415 _contentPosition += _contentChunk.remaining();
1416 buffer.position(buffer.position()+_contentChunk.remaining());
1417
1418 if (_handler.content(_contentChunk))
1419 return true;
1420
1421 if(_contentPosition == _contentLength)
1422 {
1423 setState(State.END);
1424 if (_handler.messageComplete())
1425 return true;
1426 }
1427 }
1428 break;
1429 }
1430
1431 case CHUNKED_CONTENT:
1432 {
1433 ch=next(buffer);
1434 if (ch>HttpTokens.SPACE)
1435 {
1436 _chunkLength=TypeUtil.convertHexDigit(ch);
1437 _chunkPosition=0;
1438 setState(State.CHUNK_SIZE);
1439 }
1440
1441 break;
1442 }
1443
1444 case CHUNK_SIZE:
1445 {
1446 ch=next(buffer);
1447 if (ch==0)
1448 break;
1449 if (ch == HttpTokens.LINE_FEED)
1450 {
1451 if (_chunkLength == 0)
1452 {
1453 setState(State.END);
1454 if (_handler.messageComplete())
1455 return true;
1456 }
1457 else
1458 setState(State.CHUNK);
1459 }
1460 else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
1461 setState(State.CHUNK_PARAMS);
1462 else
1463 _chunkLength=_chunkLength * 16 + TypeUtil.convertHexDigit(ch);
1464 break;
1465 }
1466
1467 case CHUNK_PARAMS:
1468 {
1469 ch=next(buffer);
1470 if (ch == HttpTokens.LINE_FEED)
1471 {
1472 if (_chunkLength == 0)
1473 {
1474 setState(State.END);
1475 if (_handler.messageComplete())
1476 return true;
1477 }
1478 else
1479 setState(State.CHUNK);
1480 }
1481 break;
1482 }
1483
1484 case CHUNK:
1485 {
1486 int chunk=_chunkLength - _chunkPosition;
1487 if (chunk == 0)
1488 {
1489 setState(State.CHUNKED_CONTENT);
1490 }
1491 else
1492 {
1493 _contentChunk=buffer.asReadOnlyBuffer();
1494
1495 if (remaining > chunk)
1496 _contentChunk.limit(_contentChunk.position()+chunk);
1497 chunk=_contentChunk.remaining();
1498
1499 _contentPosition += chunk;
1500 _chunkPosition += chunk;
1501 buffer.position(buffer.position()+chunk);
1502 if (_handler.content(_contentChunk))
1503 return true;
1504 }
1505 break;
1506 }
1507
1508 case CLOSED:
1509 {
1510 BufferUtil.clear(buffer);
1511 return false;
1512 }
1513
1514 default:
1515 break;
1516
1517 }
1518
1519 remaining=buffer.remaining();
1520 }
1521 return false;
1522 }
1523
1524 /* ------------------------------------------------------------------------------- */
1525 public boolean isAtEOF()
1526
1527 {
1528 return _eof;
1529 }
1530
1531 /* ------------------------------------------------------------------------------- */
1532 public void atEOF()
1533
1534 {
1535 if (DEBUG)
1536 LOG.debug("atEOF {}", this);
1537 _eof=true;
1538 }
1539
1540 /* ------------------------------------------------------------------------------- */
1541 public void close()
1542 {
1543 if (DEBUG)
1544 LOG.debug("close {}", this);
1545 setState(State.CLOSED);
1546 }
1547
1548 /* ------------------------------------------------------------------------------- */
1549 public void reset()
1550 {
1551 if (DEBUG)
1552 LOG.debug("reset {}", this);
1553 // reset state
1554 if (_state==State.CLOSED)
1555 return;
1556 if (_closed)
1557 {
1558 setState(State.CLOSED);
1559 return;
1560 }
1561
1562 setState(State.START);
1563 _endOfContent=EndOfContent.UNKNOWN_CONTENT;
1564 _contentLength=-1;
1565 _contentPosition=0;
1566 _responseStatus=0;
1567 _contentChunk=null;
1568 _headerBytes=0;
1569 _host=false;
1570 }
1571
1572 /* ------------------------------------------------------------------------------- */
1573 protected void setState(State state)
1574 {
1575 if (DEBUG)
1576 LOG.debug("{} --> {}",_state,state);
1577 _state=state;
1578 }
1579
1580 /* ------------------------------------------------------------------------------- */
1581 @Override
1582 public String toString()
1583 {
1584 return String.format("%s{s=%s,%d of %d}",
1585 getClass().getSimpleName(),
1586 _state,
1587 _contentPosition,
1588 _contentLength);
1589 }
1590
1591 /* ------------------------------------------------------------ */
1592 /* ------------------------------------------------------------ */
1593 /* ------------------------------------------------------------ */
1594 /* Event Handler interface
1595 * These methods return true if the caller should process the events
1596 * so far received (eg return from parseNext and call HttpChannel.handle).
1597 * If multiple callbacks are called in sequence (eg
1598 * headerComplete then messageComplete) from the same point in the parsing
1599 * then it is sufficient for the caller to process the events only once.
1600 */
1601 public interface HttpHandler<T>
1602 {
1603 public boolean content(T item);
1604
1605 public boolean headerComplete();
1606
1607 public boolean messageComplete();
1608
1609 /**
1610 * This is the method called by parser when a HTTP Header name and value is found
1611 * @param field The field parsed
1612 * @return True if the parser should return to its caller
1613 */
1614 public boolean parsedHeader(HttpField field);
1615
1616 /* ------------------------------------------------------------ */
1617 /** Called to signal that an EOF was received unexpectedly
1618 * during the parsing of a HTTP message
1619 */
1620 public void earlyEOF();
1621
1622 /* ------------------------------------------------------------ */
1623 /** Called to signal that a bad HTTP message has been received.
1624 * @param status The bad status to send
1625 * @param reason The textual reason for badness
1626 */
1627 public void badMessage(int status, String reason);
1628
1629 /* ------------------------------------------------------------ */
1630 /** @return the size in bytes of the per parser header cache
1631 */
1632 public int getHeaderCacheSize();
1633 }
1634
1635 public interface ProxyHandler
1636 {
1637 void proxied(String protocol, String sAddr, String dAddr, int sPort, int dPort);
1638 }
1639
1640 public interface RequestHandler<T> extends HttpHandler<T>
1641 {
1642 /**
1643 * This is the method called by parser when the HTTP request line is parsed
1644 * @param method The method as enum if of a known type
1645 * @param methodString The method as a string
1646 * @param uri The raw bytes of the URI. These are copied into a ByteBuffer that will not be changed until this parser is reset and reused.
1647 * @param version
1648 * @return true if handling parsing should return.
1649 */
1650 public abstract boolean startRequest(HttpMethod method, String methodString, ByteBuffer uri, HttpVersion version);
1651
1652 /**
1653 * This is the method called by the parser after it has parsed the host header (and checked it's format). This is
1654 * called after the {@link HttpHandler#parsedHeader(HttpField)} methods and before
1655 * HttpHandler#headerComplete();
1656 */
1657 public abstract boolean parsedHostHeader(String host,int port);
1658 }
1659
1660 public interface ResponseHandler<T> extends HttpHandler<T>
1661 {
1662 /**
1663 * This is the method called by parser when the HTTP request line is parsed
1664 */
1665 public abstract boolean startResponse(HttpVersion version, int status, String reason);
1666 }
1667
1668 public Trie<HttpField> getFieldCache()
1669 {
1670 return _connectionFields;
1671 }
1672
1673 private String getProxyField(ByteBuffer buffer)
1674 {
1675 _string.setLength(0);
1676 _length=0;
1677
1678 while (buffer.hasRemaining())
1679 {
1680 // process each character
1681 byte ch=next(buffer);
1682 if (ch<=' ')
1683 return _string.toString();
1684 _string.append((char)ch);
1685 }
1686 throw new BadMessage();
1687 }
1688 }