comparison src/org/eclipse/jetty/http/HttpParser.java @ 980:bd26bd9320e2

simplify HttpParser
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 16 Oct 2016 21:01:26 -0600
parents c8cd3e96db5f
children 39154cfa58e4
comparison
equal deleted inserted replaced
979:c8cd3e96db5f 980:bd26bd9320e2
35 public final class HttpParser 35 public final class HttpParser
36 { 36 {
37 private static final Logger LOG = LoggerFactory.getLogger(HttpParser.class); 37 private static final Logger LOG = LoggerFactory.getLogger(HttpParser.class);
38 38
39 // States 39 // States
40 public static final int STATE_START=-14; 40 private static final int STATE_START=-14;
41 public static final int STATE_FIELD0=-13; 41 private static final int STATE_FIELD0=-13;
42 public static final int STATE_SPACE1=-12; 42 private static final int STATE_SPACE1=-12;
43 public static final int STATE_STATUS=-11; 43 private static final int STATE_STATUS=-11;
44 public static final int STATE_URI=-10; 44 private static final int STATE_URI=-10;
45 public static final int STATE_SPACE2=-9; 45 private static final int STATE_SPACE2=-9;
46 public static final int STATE_END0=-8; 46 private static final int STATE_END0=-8;
47 public static final int STATE_END1=-7; 47 private static final int STATE_END1=-7;
48 public static final int STATE_FIELD2=-6; 48 private static final int STATE_FIELD2=-6;
49 public static final int STATE_HEADER=-5; 49 private static final int STATE_HEADER=-5;
50 public static final int STATE_HEADER_NAME=-4; 50 private static final int STATE_HEADER_NAME=-4;
51 public static final int STATE_HEADER_IN_NAME=-3; 51 private static final int STATE_HEADER_IN_NAME=-3;
52 public static final int STATE_HEADER_VALUE=-2; 52 private static final int STATE_HEADER_VALUE=-2;
53 public static final int STATE_HEADER_IN_VALUE=-1; 53 private static final int STATE_HEADER_IN_VALUE=-1;
54 public static final int STATE_END=0; 54 private static final int STATE_END=0;
55 public static final int STATE_EOF_CONTENT=1; 55 private static final int STATE_EOF_CONTENT=1;
56 public static final int STATE_CONTENT=2; 56 private static final int STATE_CONTENT=2;
57 public static final int STATE_CHUNKED_CONTENT=3; 57 private static final int STATE_CHUNKED_CONTENT=3;
58 public static final int STATE_CHUNK_SIZE=4; 58 private static final int STATE_CHUNK_SIZE=4;
59 public static final int STATE_CHUNK_PARAMS=5; 59 private static final int STATE_CHUNK_PARAMS=5;
60 public static final int STATE_CHUNK=6; 60 private static final int STATE_CHUNK=6;
61 public static final int STATE_SEEKING_EOF=7; 61 private static final int STATE_SEEKING_EOF=7;
62 62
63 private final EventHandler _handler; 63 private final EventHandler _handler;
64 private final Buffers _buffers; // source of buffers 64 private final Buffers _buffers; // source of buffers
65 private final EndPoint _endp; 65 private final EndPoint _endp;
66 private Buffer _header; // Buffer for header data (and small _content) 66 private Buffer _header; // Buffer for header data (and small _content)
69 private CachedBuffer _cached; 69 private CachedBuffer _cached;
70 private final View.CaseInsensitive _tok0; // Saved token: header name, request method or response version 70 private final View.CaseInsensitive _tok0; // Saved token: header name, request method or response version
71 private final View.CaseInsensitive _tok1; // Saved token: header value, request URI or response code 71 private final View.CaseInsensitive _tok1; // Saved token: header value, request URI or response code
72 private String _multiLineValue; 72 private String _multiLineValue;
73 private int _responseStatus; // If >0 then we are parsing a response 73 private int _responseStatus; // If >0 then we are parsing a response
74 private boolean _forceContentBuffer;
75 private boolean _persistent; 74 private boolean _persistent;
76 75
77 /* ------------------------------------------------------------------------------- */ 76 protected final View _contentView = new View(); // View of the content in the buffer for {@link Input}
78 protected final View _contentView=new View(); // View of the content in the buffer for {@link Input} 77 protected int _state = STATE_START;
79 protected int _state=STATE_START;
80 protected byte _eol; 78 protected byte _eol;
81 protected int _length; 79 protected int _length;
82 protected long _contentLength; 80 protected long _contentLength;
83 protected long _contentPosition; 81 protected long _contentPosition;
84 protected int _chunkLength; 82 protected int _chunkLength;
85 protected int _chunkPosition; 83 protected int _chunkPosition;
86 private boolean _headResponse; 84 private boolean _headResponse;
87 85
88 /* ------------------------------------------------------------------------------- */
89 /**
90 * Constructor.
91 */
92 public HttpParser(Buffer buffer, EventHandler handler)
93 {
94 _endp=null;
95 _buffers=null;
96 _header=buffer;
97 _buffer=buffer;
98 _handler=handler;
99
100 _tok0=new View.CaseInsensitive(_header);
101 _tok1=new View.CaseInsensitive(_header);
102 }
103
104 /* ------------------------------------------------------------------------------- */
105 /**
106 * Constructor.
107 * @param buffers the buffers to use
108 * @param endp the endpoint
109 * @param handler the even handler
110 */
111 public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler) 86 public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler)
112 { 87 {
113 _buffers=buffers; 88 _buffers = buffers;
114 _endp=endp; 89 _endp = endp;
115 _handler=handler; 90 _handler = handler;
116 _tok0=new View.CaseInsensitive(); 91 _tok0 = new View.CaseInsensitive();
117 _tok1=new View.CaseInsensitive(); 92 _tok1 = new View.CaseInsensitive();
118 } 93 }
119 94
120 /* ------------------------------------------------------------------------------- */
121 public long getContentLength() 95 public long getContentLength()
122 { 96 {
123 return _contentLength; 97 return _contentLength;
124 } 98 }
125 99
126 /* ------------------------------------------------------------ */
127 public long getContentRead() 100 public long getContentRead()
128 { 101 {
129 return _contentPosition; 102 return _contentPosition;
130 } 103 }
131 104
133 /** Set if a HEAD response is expected 106 /** Set if a HEAD response is expected
134 * @param head 107 * @param head
135 */ 108 */
136 public void setHeadResponse(boolean head) 109 public void setHeadResponse(boolean head)
137 { 110 {
138 _headResponse=head; 111 _headResponse = head;
139 } 112 }
140 113
141 /* ------------------------------------------------------------------------------- */
142 public int getState()
143 {
144 return _state;
145 }
146
147 /* ------------------------------------------------------------------------------- */
148 public boolean inContentState()
149 {
150 return _state > 0;
151 }
152
153 /* ------------------------------------------------------------------------------- */
154 public boolean inHeaderState()
155 {
156 return _state < 0;
157 }
158
159 /* ------------------------------------------------------------------------------- */
160 public boolean isChunking() 114 public boolean isChunking()
161 { 115 {
162 return _contentLength==HttpTokens.CHUNKED_CONTENT; 116 return _contentLength==HttpTokens.CHUNKED_CONTENT;
163 } 117 }
164 118
165 /* ------------------------------------------------------------ */
166 public boolean isIdle() 119 public boolean isIdle()
167 { 120 {
168 return isState(STATE_START); 121 return _state==STATE_START;
169 } 122 }
170 123
171 /* ------------------------------------------------------------ */
172 public boolean isComplete() 124 public boolean isComplete()
173 { 125 {
174 return isState(STATE_END); 126 return _state==STATE_END;
175 } 127 }
176 128
177 /* ------------------------------------------------------------ */
178 public boolean isMoreInBuffer()
179 throws IOException
180 {
181 return ( _header!=null && _header.hasContent() ||
182 _body!=null && _body.hasContent());
183 }
184
185 /* ------------------------------------------------------------------------------- */
186 public boolean isState(int state)
187 {
188 return _state == state;
189 }
190
191 /* ------------------------------------------------------------------------------- */
192 public boolean isPersistent() 129 public boolean isPersistent()
193 { 130 {
194 return _persistent; 131 return _persistent;
195 } 132 }
196 133
197 /* ------------------------------------------------------------------------------- */
198 public void setPersistent(boolean persistent) 134 public void setPersistent(boolean persistent)
199 { 135 {
200 _persistent = persistent; 136 _persistent = persistent;
201 if (!_persistent &&(_state==STATE_END || _state==STATE_START)) 137 if (!_persistent &&(_state==STATE_END || _state==STATE_START))
202 _state=STATE_SEEKING_EOF; 138 _state=STATE_SEEKING_EOF;
203 }
204
205 /* ------------------------------------------------------------------------------- */
206 /**
207 * Parse until {@link #STATE_END END} state.
208 * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed.
209 * @throws IllegalStateException If the buffers have already been partially parsed.
210 */
211 public void parse() throws IOException
212 {
213 if (_state==STATE_END)
214 reset();
215 if (_state!=STATE_START)
216 throw new IllegalStateException("!START");
217
218 // continue parsing
219 while (_state != STATE_END)
220 if (parseNext()<0)
221 return;
222 } 139 }
223 140
224 /* ------------------------------------------------------------------------------- */ 141 /* ------------------------------------------------------------------------------- */
225 /** 142 /**
226 * Parse until END state. 143 * Parse until END state.
245 /* ------------------------------------------------------------------------------- */ 162 /* ------------------------------------------------------------------------------- */
246 /** 163 /**
247 * Parse until next Event. 164 * Parse until next Event.
248 * @return an indication of progress <0 EOF, 0 no progress, >0 progress. 165 * @return an indication of progress <0 EOF, 0 no progress, >0 progress.
249 */ 166 */
250 public int parseNext() throws IOException 167 private int parseNext() throws IOException
251 { 168 {
252 try 169 try
253 { 170 {
254 int progress=0; 171 int progress=0;
255 172
416 _responseStatus=_responseStatus*10+(ch-'0'); 333 _responseStatus=_responseStatus*10+(ch-'0');
417 continue; 334 continue;
418 } 335 }
419 else if (ch < HttpTokens.SPACE && ch>=0) 336 else if (ch < HttpTokens.SPACE && ch>=0)
420 { 337 {
421 _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
422 _eol=ch; 338 _eol=ch;
423 _state=STATE_HEADER; 339 _state=STATE_HEADER;
424 _tok0.setPutIndex(_tok0.getIndex()); 340 _tok0.setPutIndex(_tok0.getIndex());
425 _tok1.setPutIndex(_tok1.getIndex()); 341 _tok1.setPutIndex(_tok1.getIndex());
426 _multiLineValue=null; 342 _multiLineValue=null;
458 } 374 }
459 else if (ch < HttpTokens.SPACE) 375 else if (ch < HttpTokens.SPACE)
460 { 376 {
461 if (_responseStatus>0) 377 if (_responseStatus>0)
462 { 378 {
463 _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
464 _eol=ch; 379 _eol=ch;
465 _state=STATE_HEADER; 380 _state=STATE_HEADER;
466 _tok0.setPutIndex(_tok0.getIndex()); 381 _tok0.setPutIndex(_tok0.getIndex());
467 _tok1.setPutIndex(_tok1.getIndex()); 382 _tok1.setPutIndex(_tok1.getIndex());
468 _multiLineValue=null; 383 _multiLineValue=null;
483 case STATE_FIELD2: 398 case STATE_FIELD2:
484 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) 399 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
485 { 400 {
486 Buffer version; 401 Buffer version;
487 if (_responseStatus>0) 402 if (_responseStatus>0)
488 _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark()); 403 // _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark());
404 version = HttpVersions.CACHE.lookup(_tok0);
489 else 405 else
490 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark())); 406 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark()));
491 _eol=ch; 407 _eol=ch;
492 _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL; 408 _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL;
493 _state=STATE_HEADER; 409 _state=STATE_HEADER;
998 914
999 /* ------------------------------------------------------------------------------- */ 915 /* ------------------------------------------------------------------------------- */
1000 /** fill the buffers from the endpoint 916 /** fill the buffers from the endpoint
1001 * 917 *
1002 */ 918 */
1003 protected int fill() throws IOException 919 private int fill() throws IOException
1004 { 920 {
1005 // Do we have a buffer? 921 // Do we have a buffer?
1006 if (_buffer==null) 922 if (_buffer==null)
1007 _buffer=getHeaderBuffer(); 923 _buffer=getHeaderBuffer();
1008 924
1012 _buffer=_body; 928 _buffer=_body;
1013 return _buffer.length(); 929 return _buffer.length();
1014 } 930 }
1015 931
1016 // Shall we switch to a body buffer? 932 // Shall we switch to a body buffer?
1017 if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null)) 933 if (_buffer==_header && _state>STATE_END && _header.length()==0 && ((_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null))
1018 { 934 {
1019 if (_body==null) 935 if (_body==null)
1020 _body=_buffers.getBuffer(); 936 _body=_buffers.getBuffer();
1021 _buffer=_body; 937 _buffer=_body;
1022 } 938 }
1023 939
1024 // Do we have somewhere to fill from? 940 // Shall we compact the body?
1025 if (_endp != null ) 941 if (_buffer==_body || _state>STATE_END)
1026 { 942 {
1027 // Shall we compact the body? 943 _buffer.compact();
1028 if (_buffer==_body || _state>STATE_END) 944 }
1029 { 945
1030 _buffer.compact(); 946 // Are we full?
1031 } 947 if (_buffer.space() == 0)
1032 948 {
1033 // Are we full? 949 LOG.warn("HttpParser Full for {} ",_endp);
1034 if (_buffer.space() == 0) 950 _buffer.clear();
1035 { 951 throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large: "+(_buffer==_body?"body":"head"));
1036 LOG.warn("HttpParser Full for {} ",_endp); 952 }
1037 _buffer.clear(); 953
1038 throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large: "+(_buffer==_body?"body":"head")); 954 try
1039 } 955 {
1040 956 int filled = _endp.fill(_buffer);
1041 try 957 return filled;
1042 { 958 }
1043 int filled = _endp.fill(_buffer); 959 catch(IOException e)
1044 return filled; 960 {
1045 } 961 LOG.debug("",e);
1046 catch(IOException e) 962 throw (e instanceof EofException) ? e:new EofException(e);
1047 { 963 }
1048 LOG.debug("",e); 964 }
1049 throw (e instanceof EofException) ? e:new EofException(e); 965
1050 }
1051 }
1052
1053 return -1;
1054 }
1055
1056 /* ------------------------------------------------------------------------------- */
1057 public void reset() 966 public void reset()
1058 { 967 {
1059 // reset state 968 // reset state
1060 _contentView.setGetIndex(_contentView.putIndex()); 969 _contentView.setGetIndex(_contentView.putIndex());
1061 _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF); 970 _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF);
1098 _buffer=_header; 1007 _buffer=_header;
1099 returnBuffers(); 1008 returnBuffers();
1100 } 1009 }
1101 1010
1102 1011
1103 /* ------------------------------------------------------------------------------- */
1104 public void returnBuffers() 1012 public void returnBuffers()
1105 { 1013 {
1106 if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null) 1014 if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null)
1107 { 1015 {
1108 if (_buffer==_body) 1016 if (_buffer==_body)
1119 _buffers.returnBuffer(_header); 1027 _buffers.returnBuffer(_header);
1120 _header=null; 1028 _header=null;
1121 } 1029 }
1122 } 1030 }
1123 1031
1124 /* ------------------------------------------------------------------------------- */
1125 public void setState(int state)
1126 {
1127 this._state=state;
1128 _contentLength=HttpTokens.UNKNOWN_CONTENT;
1129 }
1130
1131 /* ------------------------------------------------------------------------------- */
1132 public String toString(Buffer buf)
1133 {
1134 return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode();
1135 }
1136
1137 /* ------------------------------------------------------------------------------- */
1138 @Override 1032 @Override
1139 public String toString() 1033 public String toString()
1140 { 1034 {
1141 return String.format("%s{s=%d,l=%d,c=%d}", 1035 return String.format("%s{s=%d,l=%d,c=%d}",
1142 getClass().getSimpleName(), 1036 getClass().getSimpleName(),
1143 _state, 1037 _state,
1144 _length, 1038 _length,
1145 _contentLength); 1039 _contentLength);
1146 } 1040 }
1147 1041
1148 /* ------------------------------------------------------------ */
1149 public Buffer getHeaderBuffer() 1042 public Buffer getHeaderBuffer()
1150 { 1043 {
1151 if (_header == null) 1044 if (_header == null)
1152 { 1045 {
1153 _header=_buffers.getHeader(); 1046 _header = _buffers.getHeader();
1154 _tok0.update(_header); 1047 _tok0.update(_header);
1155 _tok1.update(_header); 1048 _tok1.update(_header);
1156 } 1049 }
1157 return _header; 1050 return _header;
1158 } 1051 }
1159 1052
1160 /* ------------------------------------------------------------ */
1161 public Buffer getBodyBuffer()
1162 {
1163 return _body;
1164 }
1165
1166 /* ------------------------------------------------------------ */
1167 /**
1168 * @param force True if a new buffer will be forced to be used for content and the header buffer will not be used.
1169 */
1170 public void setForceContentBuffer(boolean force)
1171 {
1172 _forceContentBuffer=force;
1173 }
1174
1175 /* ------------------------------------------------------------ */
1176 public Buffer blockForContent(long maxIdleTime) throws IOException 1053 public Buffer blockForContent(long maxIdleTime) throws IOException
1177 { 1054 {
1178 if (_contentView.length()>0) 1055 if (_contentView.length()>0)
1179 return _contentView; 1056 return _contentView;
1180 1057
1181 if (getState() <= STATE_END || isState(STATE_SEEKING_EOF)) 1058 if (_state <= STATE_END || _state==STATE_SEEKING_EOF)
1182 return null; 1059 return null;
1183 1060
1184 try 1061 try
1185 { 1062 {
1186 parseNext(); 1063 parseNext();
1187 1064
1188 // parse until some progress is made (or IOException thrown for timeout) 1065 // parse until some progress is made (or IOException thrown for timeout)
1189 while(_contentView.length() == 0 && !(isState(HttpParser.STATE_END)||isState(HttpParser.STATE_SEEKING_EOF)) && _endp!=null && _endp.isOpen()) 1066 while(_contentView.length() == 0 && !(_state==STATE_END||_state==STATE_SEEKING_EOF) && _endp.isOpen())
1190 { 1067 {
1191 if (!_endp.isBlocking()) 1068 if (!_endp.isBlocking())
1192 { 1069 {
1193 if (parseNext()>0) 1070 if (parseNext()>0)
1194 continue; 1071 continue;
1229 1106
1230 parseNext(); 1107 parseNext();
1231 return _contentView==null?0:_contentView.length(); 1108 return _contentView==null?0:_contentView.length();
1232 } 1109 }
1233 1110
1234 /* ------------------------------------------------------------ */ 1111
1235 /* ------------------------------------------------------------ */ 1112 public interface EventHandler
1236 /* ------------------------------------------------------------ */
1237 public static abstract class EventHandler
1238 { 1113 {
1239 public abstract void content(Buffer ref) throws IOException; 1114 public abstract void content(Buffer ref) throws IOException;
1240 1115
1241 public void headerComplete() throws IOException 1116 public void headerComplete() throws IOException;
1242 { 1117
1243 } 1118 public void messageComplete(long contentLength) throws IOException;
1244
1245 public void messageComplete(long contentLength) throws IOException
1246 {
1247 }
1248 1119
1249 /** 1120 /**
1250 * This is the method called by parser when a HTTP Header name and value is found 1121 * This is the method called by parser when a HTTP Header name and value is found
1251 */ 1122 */
1252 public void parsedHeader(Buffer name, Buffer value) throws IOException 1123 public void parsedHeader(Buffer name, Buffer value) throws IOException;
1253 {
1254 }
1255 1124
1256 /** 1125 /**
1257 * This is the method called by parser when the HTTP request line is parsed 1126 * This is the method called by parser when the HTTP request line is parsed
1258 */ 1127 */
1259 public abstract void startRequest(Buffer method, Buffer url, Buffer version) 1128 public abstract void startRequest(Buffer method, Buffer url, Buffer version)
1260 throws IOException; 1129 throws IOException;
1261 1130
1262 /** 1131 public void earlyEOF();
1263 * This is the method called by parser when the HTTP request line is parsed
1264 */
1265 public abstract void startResponse(Buffer version, int status, Buffer reason)
1266 throws IOException;
1267
1268 public void earlyEOF()
1269 {}
1270 } 1132 }
1271 1133
1272 1134
1273 1135
1274 1136