comparison src/org/eclipse/jetty/http/HttpParser.java @ 873:220ad4853cda

remove StreamEndPoint
author Franklin Schmidt <fschmidt@gmail.com>
date Mon, 03 Oct 2016 20:03:50 -0600
parents 8e9db0bbf4f9
children c8cd3e96db5f
comparison
equal deleted inserted replaced
872:1c0b6841cd32 873:220ad4853cda
26 import org.eclipse.jetty.io.Buffers; 26 import org.eclipse.jetty.io.Buffers;
27 import org.eclipse.jetty.io.ByteArrayBuffer; 27 import org.eclipse.jetty.io.ByteArrayBuffer;
28 import org.eclipse.jetty.io.EndPoint; 28 import org.eclipse.jetty.io.EndPoint;
29 import org.eclipse.jetty.io.EofException; 29 import org.eclipse.jetty.io.EofException;
30 import org.eclipse.jetty.io.View; 30 import org.eclipse.jetty.io.View;
31 import org.eclipse.jetty.io.bio.StreamEndPoint;
32 import org.eclipse.jetty.util.StringUtil; 31 import org.eclipse.jetty.util.StringUtil;
33 import org.slf4j.Logger; 32 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory; 33 import org.slf4j.LoggerFactory;
35 34
36 public class HttpParser implements Parser 35 public class HttpParser implements Parser
37 { 36 {
38 private static final Logger LOG = LoggerFactory.getLogger(HttpParser.class); 37 private static final Logger LOG = LoggerFactory.getLogger(HttpParser.class);
39 38
40 // States 39 // States
41 public static final int STATE_START=-14; 40 public static final int STATE_START=-14;
42 public static final int STATE_FIELD0=-13; 41 public static final int STATE_FIELD0=-13;
43 public static final int STATE_SPACE1=-12; 42 public static final int STATE_SPACE1=-12;
44 public static final int STATE_STATUS=-11; 43 public static final int STATE_STATUS=-11;
45 public static final int STATE_URI=-10; 44 public static final int STATE_URI=-10;
46 public static final int STATE_SPACE2=-9; 45 public static final int STATE_SPACE2=-9;
47 public static final int STATE_END0=-8; 46 public static final int STATE_END0=-8;
48 public static final int STATE_END1=-7; 47 public static final int STATE_END1=-7;
49 public static final int STATE_FIELD2=-6; 48 public static final int STATE_FIELD2=-6;
50 public static final int STATE_HEADER=-5; 49 public static final int STATE_HEADER=-5;
51 public static final int STATE_HEADER_NAME=-4; 50 public static final int STATE_HEADER_NAME=-4;
52 public static final int STATE_HEADER_IN_NAME=-3; 51 public static final int STATE_HEADER_IN_NAME=-3;
53 public static final int STATE_HEADER_VALUE=-2; 52 public static final int STATE_HEADER_VALUE=-2;
54 public static final int STATE_HEADER_IN_VALUE=-1; 53 public static final int STATE_HEADER_IN_VALUE=-1;
55 public static final int STATE_END=0; 54 public static final int STATE_END=0;
56 public static final int STATE_EOF_CONTENT=1; 55 public static final int STATE_EOF_CONTENT=1;
57 public static final int STATE_CONTENT=2; 56 public static final int STATE_CONTENT=2;
58 public static final int STATE_CHUNKED_CONTENT=3; 57 public static final int STATE_CHUNKED_CONTENT=3;
59 public static final int STATE_CHUNK_SIZE=4; 58 public static final int STATE_CHUNK_SIZE=4;
60 public static final int STATE_CHUNK_PARAMS=5; 59 public static final int STATE_CHUNK_PARAMS=5;
61 public static final int STATE_CHUNK=6; 60 public static final int STATE_CHUNK=6;
62 public static final int STATE_SEEKING_EOF=7; 61 public static final int STATE_SEEKING_EOF=7;
63 62
64 private final EventHandler _handler; 63 private final EventHandler _handler;
65 private final Buffers _buffers; // source of buffers 64 private final Buffers _buffers; // source of buffers
66 private final EndPoint _endp; 65 private final EndPoint _endp;
67 private Buffer _header; // Buffer for header data (and small _content) 66 private Buffer _header; // Buffer for header data (and small _content)
68 private Buffer _body; // Buffer for large content 67 private Buffer _body; // Buffer for large content
69 private Buffer _buffer; // The current buffer in use (either _header or _content) 68 private Buffer _buffer; // The current buffer in use (either _header or _content)
70 private CachedBuffer _cached; 69 private CachedBuffer _cached;
71 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
72 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
73 private String _multiLineValue; 72 private String _multiLineValue;
74 private int _responseStatus; // If >0 then we are parsing a response 73 private int _responseStatus; // If >0 then we are parsing a response
75 private boolean _forceContentBuffer; 74 private boolean _forceContentBuffer;
76 private boolean _persistent; 75 private boolean _persistent;
77 76
78 /* ------------------------------------------------------------------------------- */ 77 /* ------------------------------------------------------------------------------- */
79 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}
80 protected int _state=STATE_START; 79 protected int _state=STATE_START;
81 protected byte _eol; 80 protected byte _eol;
82 protected int _length; 81 protected int _length;
83 protected long _contentLength; 82 protected long _contentLength;
84 protected long _contentPosition; 83 protected long _contentPosition;
85 protected int _chunkLength; 84 protected int _chunkLength;
86 protected int _chunkPosition; 85 protected int _chunkPosition;
87 private boolean _headResponse; 86 private boolean _headResponse;
88 87
89 /* ------------------------------------------------------------------------------- */ 88 /* ------------------------------------------------------------------------------- */
90 /** 89 /**
91 * Constructor. 90 * Constructor.
92 */ 91 */
93 public HttpParser(Buffer buffer, EventHandler handler) 92 public HttpParser(Buffer buffer, EventHandler handler)
94 { 93 {
95 _endp=null; 94 _endp=null;
96 _buffers=null; 95 _buffers=null;
97 _header=buffer; 96 _header=buffer;
98 _buffer=buffer; 97 _buffer=buffer;
99 _handler=handler; 98 _handler=handler;
100 99
101 _tok0=new View.CaseInsensitive(_header); 100 _tok0=new View.CaseInsensitive(_header);
102 _tok1=new View.CaseInsensitive(_header); 101 _tok1=new View.CaseInsensitive(_header);
103 } 102 }
104 103
105 /* ------------------------------------------------------------------------------- */ 104 /* ------------------------------------------------------------------------------- */
106 /** 105 /**
107 * Constructor. 106 * Constructor.
108 * @param buffers the buffers to use 107 * @param buffers the buffers to use
109 * @param endp the endpoint 108 * @param endp the endpoint
110 * @param handler the even handler 109 * @param handler the even handler
111 */ 110 */
112 public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler) 111 public HttpParser(Buffers buffers, EndPoint endp, EventHandler handler)
113 { 112 {
114 _buffers=buffers; 113 _buffers=buffers;
115 _endp=endp; 114 _endp=endp;
116 _handler=handler; 115 _handler=handler;
117 _tok0=new View.CaseInsensitive(); 116 _tok0=new View.CaseInsensitive();
118 _tok1=new View.CaseInsensitive(); 117 _tok1=new View.CaseInsensitive();
119 } 118 }
120 119
121 /* ------------------------------------------------------------------------------- */ 120 /* ------------------------------------------------------------------------------- */
122 public long getContentLength() 121 public long getContentLength()
123 { 122 {
124 return _contentLength; 123 return _contentLength;
125 } 124 }
126 125
127 /* ------------------------------------------------------------ */ 126 /* ------------------------------------------------------------ */
128 public long getContentRead() 127 public long getContentRead()
129 { 128 {
130 return _contentPosition; 129 return _contentPosition;
131 } 130 }
132 131
133 /* ------------------------------------------------------------ */ 132 /* ------------------------------------------------------------ */
134 /** Set if a HEAD response is expected 133 /** Set if a HEAD response is expected
135 * @param head 134 * @param head
136 */ 135 */
137 public void setHeadResponse(boolean head) 136 public void setHeadResponse(boolean head)
138 { 137 {
139 _headResponse=head; 138 _headResponse=head;
140 } 139 }
141 140
142 /* ------------------------------------------------------------------------------- */ 141 /* ------------------------------------------------------------------------------- */
143 public int getState() 142 public int getState()
144 { 143 {
145 return _state; 144 return _state;
146 } 145 }
147 146
148 /* ------------------------------------------------------------------------------- */ 147 /* ------------------------------------------------------------------------------- */
149 public boolean inContentState() 148 public boolean inContentState()
150 { 149 {
151 return _state > 0; 150 return _state > 0;
152 } 151 }
153 152
154 /* ------------------------------------------------------------------------------- */ 153 /* ------------------------------------------------------------------------------- */
155 public boolean inHeaderState() 154 public boolean inHeaderState()
156 { 155 {
157 return _state < 0; 156 return _state < 0;
158 } 157 }
159 158
160 /* ------------------------------------------------------------------------------- */ 159 /* ------------------------------------------------------------------------------- */
161 public boolean isChunking() 160 public boolean isChunking()
162 { 161 {
163 return _contentLength==HttpTokens.CHUNKED_CONTENT; 162 return _contentLength==HttpTokens.CHUNKED_CONTENT;
164 } 163 }
165 164
166 /* ------------------------------------------------------------ */ 165 /* ------------------------------------------------------------ */
167 public boolean isIdle() 166 public boolean isIdle()
168 { 167 {
169 return isState(STATE_START); 168 return isState(STATE_START);
170 } 169 }
171 170
172 /* ------------------------------------------------------------ */ 171 /* ------------------------------------------------------------ */
173 public boolean isComplete() 172 public boolean isComplete()
174 { 173 {
175 return isState(STATE_END); 174 return isState(STATE_END);
176 } 175 }
177 176
178 /* ------------------------------------------------------------ */ 177 /* ------------------------------------------------------------ */
179 public boolean isMoreInBuffer() 178 public boolean isMoreInBuffer()
180 throws IOException 179 throws IOException
181 { 180 {
182 return ( _header!=null && _header.hasContent() || 181 return ( _header!=null && _header.hasContent() ||
183 _body!=null && _body.hasContent()); 182 _body!=null && _body.hasContent());
184 } 183 }
185 184
186 /* ------------------------------------------------------------------------------- */ 185 /* ------------------------------------------------------------------------------- */
187 public boolean isState(int state) 186 public boolean isState(int state)
188 { 187 {
189 return _state == state; 188 return _state == state;
190 } 189 }
191 190
192 /* ------------------------------------------------------------------------------- */ 191 /* ------------------------------------------------------------------------------- */
193 public boolean isPersistent() 192 public boolean isPersistent()
194 { 193 {
195 return _persistent; 194 return _persistent;
196 } 195 }
197 196
198 /* ------------------------------------------------------------------------------- */ 197 /* ------------------------------------------------------------------------------- */
199 public void setPersistent(boolean persistent) 198 public void setPersistent(boolean persistent)
200 { 199 {
201 _persistent = persistent; 200 _persistent = persistent;
202 if (!_persistent &&(_state==STATE_END || _state==STATE_START)) 201 if (!_persistent &&(_state==STATE_END || _state==STATE_START))
203 _state=STATE_SEEKING_EOF; 202 _state=STATE_SEEKING_EOF;
204 } 203 }
205 204
206 /* ------------------------------------------------------------------------------- */ 205 /* ------------------------------------------------------------------------------- */
207 /** 206 /**
208 * Parse until {@link #STATE_END END} state. 207 * Parse until {@link #STATE_END END} state.
209 * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed. 208 * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed.
210 * @throws IllegalStateException If the buffers have already been partially parsed. 209 * @throws IllegalStateException If the buffers have already been partially parsed.
211 */ 210 */
212 public void parse() throws IOException 211 public void parse() throws IOException
213 { 212 {
214 if (_state==STATE_END) 213 if (_state==STATE_END)
215 reset(); 214 reset();
216 if (_state!=STATE_START) 215 if (_state!=STATE_START)
217 throw new IllegalStateException("!START"); 216 throw new IllegalStateException("!START");
218 217
219 // continue parsing 218 // continue parsing
220 while (_state != STATE_END) 219 while (_state != STATE_END)
221 if (parseNext()<0) 220 if (parseNext()<0)
222 return; 221 return;
223 } 222 }
224 223
225 /* ------------------------------------------------------------------------------- */ 224 /* ------------------------------------------------------------------------------- */
226 /** 225 /**
227 * Parse until END state. 226 * Parse until END state.
228 * This method will parse any remaining content in the current buffer as long as there is 227 * This method will parse any remaining content in the current buffer as long as there is
229 * no unconsumed content. It does not care about the {@link #getState current state} of the parser. 228 * no unconsumed content. It does not care about the {@link #getState current state} of the parser.
230 * @see #parse 229 * @see #parse
231 * @see #parseNext 230 * @see #parseNext
232 */ 231 */
233 public boolean parseAvailable() throws IOException 232 public boolean parseAvailable() throws IOException
234 { 233 {
235 boolean progress=parseNext()>0; 234 boolean progress=parseNext()>0;
236 235
237 // continue parsing 236 // continue parsing
238 while (!isComplete() && _buffer!=null && _buffer.length()>0 && !_contentView.hasContent()) 237 while (!isComplete() && _buffer!=null && _buffer.length()>0 && !_contentView.hasContent())
239 { 238 {
240 progress |= parseNext()>0; 239 progress |= parseNext()>0;
241 } 240 }
242 return progress; 241 return progress;
243 } 242 }
244 243
245 244
246 /* ------------------------------------------------------------------------------- */ 245 /* ------------------------------------------------------------------------------- */
247 /** 246 /**
248 * Parse until next Event. 247 * Parse until next Event.
249 * @return an indication of progress <0 EOF, 0 no progress, >0 progress. 248 * @return an indication of progress <0 EOF, 0 no progress, >0 progress.
250 */ 249 */
251 public int parseNext() throws IOException 250 public int parseNext() throws IOException
252 { 251 {
253 try 252 try
254 { 253 {
255 int progress=0; 254 int progress=0;
256 255
257 if (_state == STATE_END) 256 if (_state == STATE_END)
258 return 0; 257 return 0;
259 258
260 if (_buffer==null) 259 if (_buffer==null)
261 _buffer=getHeaderBuffer(); 260 _buffer=getHeaderBuffer();
262 261
263 262
264 if (_state == STATE_CONTENT && _contentPosition == _contentLength) 263 if (_state == STATE_CONTENT && _contentPosition == _contentLength)
265 { 264 {
266 _state=STATE_END; 265 _state=STATE_END;
267 _handler.messageComplete(_contentPosition); 266 _handler.messageComplete(_contentPosition);
268 return 1; 267 return 1;
269 } 268 }
270 269
271 int length=_buffer.length(); 270 int length=_buffer.length();
272 271
273 // Fill buffer if we can 272 // Fill buffer if we can
274 if (length == 0) 273 if (length == 0)
275 { 274 {
276 int filled=-1; 275 int filled=-1;
277 IOException ex=null; 276 IOException ex=null;
278 try 277 try
279 { 278 {
280 filled=fill(); 279 filled=fill();
281 LOG.debug("filled {}/{}",filled,_buffer.length()); 280 LOG.debug("filled {}/{}",filled,_buffer.length());
282 } 281 }
283 catch(IOException e) 282 catch(IOException e)
284 { 283 {
285 LOG.debug(this.toString(),e); 284 LOG.debug(this.toString(),e);
286 ex=e; 285 ex=e;
287 } 286 }
288 287
289 if (filled > 0 ) 288 if (filled > 0 )
290 progress++; 289 progress++;
291 else if (filled < 0 ) 290 else if (filled < 0 )
292 { 291 {
293 _persistent=false; 292 _persistent=false;
294 293
295 // do we have content to deliver? 294 // do we have content to deliver?
296 if (_state>STATE_END) 295 if (_state>STATE_END)
297 { 296 {
298 if (_buffer.length()>0 && !_headResponse) 297 if (_buffer.length()>0 && !_headResponse)
299 { 298 {
300 Buffer chunk=_buffer.get(_buffer.length()); 299 Buffer chunk=_buffer.get(_buffer.length());
301 _contentPosition += chunk.length(); 300 _contentPosition += chunk.length();
302 _contentView.update(chunk); 301 _contentView.update(chunk);
303 _handler.content(chunk); // May recurse here 302 _handler.content(chunk); // May recurse here
304 } 303 }
305 } 304 }
306 305
307 // was this unexpected? 306 // was this unexpected?
308 switch(_state) 307 switch(_state)
309 { 308 {
310 case STATE_END: 309 case STATE_END:
311 case STATE_SEEKING_EOF: 310 case STATE_SEEKING_EOF:
312 _state=STATE_END; 311 _state=STATE_END;
313 break; 312 break;
314 313
315 case STATE_EOF_CONTENT: 314 case STATE_EOF_CONTENT:
316 _state=STATE_END; 315 _state=STATE_END;
317 _handler.messageComplete(_contentPosition); 316 _handler.messageComplete(_contentPosition);
318 break; 317 break;
319 318
320 default: 319 default:
321 _state=STATE_END; 320 _state=STATE_END;
322 if (!_headResponse) 321 if (!_headResponse)
323 _handler.earlyEOF(); 322 _handler.earlyEOF();
324 _handler.messageComplete(_contentPosition); 323 _handler.messageComplete(_contentPosition);
325 } 324 }
326 325
327 if (ex!=null) 326 if (ex!=null)
328 throw ex; 327 throw ex;
329 328
330 if (!isComplete() && !isIdle()) 329 if (!isComplete() && !isIdle())
331 throw new EofException(); 330 throw new EofException();
332 331
333 return -1; 332 return -1;
334 } 333 }
335 length=_buffer.length(); 334 length=_buffer.length();
336 } 335 }
337 336
338 337
339 // Handle header states 338 // Handle header states
340 byte ch; 339 byte ch;
341 byte[] array=_buffer.array(); 340 byte[] array=_buffer.array();
342 int last=_state; 341 int last=_state;
343 while (_state<STATE_END && length-->0) 342 while (_state<STATE_END && length-->0)
344 { 343 {
345 if (last!=_state) 344 if (last!=_state)
346 { 345 {
347 progress++; 346 progress++;
348 last=_state; 347 last=_state;
349 } 348 }
350 349
351 ch=_buffer.get(); 350 ch=_buffer.get();
352 351
353 if (_eol == HttpTokens.CARRIAGE_RETURN) 352 if (_eol == HttpTokens.CARRIAGE_RETURN)
354 { 353 {
355 if (ch == HttpTokens.LINE_FEED) 354 if (ch == HttpTokens.LINE_FEED)
356 { 355 {
357 _eol=HttpTokens.LINE_FEED; 356 _eol=HttpTokens.LINE_FEED;
358 continue; 357 continue;
359 } 358 }
360 throw new HttpException(HttpStatus.BAD_REQUEST_400); 359 throw new HttpException(HttpStatus.BAD_REQUEST_400);
361 } 360 }
362 _eol=0; 361 _eol=0;
363 362
364 switch (_state) 363 switch (_state)
365 { 364 {
366 case STATE_START: 365 case STATE_START:
367 _contentLength=HttpTokens.UNKNOWN_CONTENT; 366 _contentLength=HttpTokens.UNKNOWN_CONTENT;
368 _cached=null; 367 _cached=null;
369 if (ch > HttpTokens.SPACE || ch<0) 368 if (ch > HttpTokens.SPACE || ch<0)
370 { 369 {
371 _buffer.mark(); 370 _buffer.mark();
372 _state=STATE_FIELD0; 371 _state=STATE_FIELD0;
373 } 372 }
374 break; 373 break;
375 374
376 case STATE_FIELD0: 375 case STATE_FIELD0:
377 if (ch == HttpTokens.SPACE) 376 if (ch == HttpTokens.SPACE)
378 { 377 {
379 _tok0.update(_buffer.markIndex(), _buffer.getIndex() - 1); 378 _tok0.update(_buffer.markIndex(), _buffer.getIndex() - 1);
380 _responseStatus=HttpVersions.CACHE.get(_tok0)==null?-1:0; 379 _responseStatus=HttpVersions.CACHE.get(_tok0)==null?-1:0;
381 _state=STATE_SPACE1; 380 _state=STATE_SPACE1;
382 continue; 381 continue;
383 } 382 }
384 else if (ch < HttpTokens.SPACE && ch>=0) 383 else if (ch < HttpTokens.SPACE && ch>=0)
385 { 384 {
386 throw new HttpException(HttpStatus.BAD_REQUEST_400); 385 throw new HttpException(HttpStatus.BAD_REQUEST_400);
387 } 386 }
388 break; 387 break;
389 388
390 case STATE_SPACE1: 389 case STATE_SPACE1:
391 if (ch > HttpTokens.SPACE || ch<0) 390 if (ch > HttpTokens.SPACE || ch<0)
392 { 391 {
393 _buffer.mark(); 392 _buffer.mark();
394 if (_responseStatus>=0) 393 if (_responseStatus>=0)
395 { 394 {
396 _state=STATE_STATUS; 395 _state=STATE_STATUS;
397 _responseStatus=ch-'0'; 396 _responseStatus=ch-'0';
398 } 397 }
399 else 398 else
400 _state=STATE_URI; 399 _state=STATE_URI;
401 } 400 }
402 else if (ch < HttpTokens.SPACE) 401 else if (ch < HttpTokens.SPACE)
403 { 402 {
404 throw new HttpException(HttpStatus.BAD_REQUEST_400); 403 throw new HttpException(HttpStatus.BAD_REQUEST_400);
405 } 404 }
406 break; 405 break;
407 406
408 case STATE_STATUS: 407 case STATE_STATUS:
409 if (ch == HttpTokens.SPACE) 408 if (ch == HttpTokens.SPACE)
410 { 409 {
411 _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1); 410 _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1);
412 _state=STATE_SPACE2; 411 _state=STATE_SPACE2;
413 continue; 412 continue;
414 } 413 }
415 else if (ch>='0' && ch<='9') 414 else if (ch>='0' && ch<='9')
416 { 415 {
417 _responseStatus=_responseStatus*10+(ch-'0'); 416 _responseStatus=_responseStatus*10+(ch-'0');
418 continue; 417 continue;
419 } 418 }
420 else if (ch < HttpTokens.SPACE && ch>=0) 419 else if (ch < HttpTokens.SPACE && ch>=0)
421 { 420 {
422 _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null); 421 _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
423 _eol=ch; 422 _eol=ch;
424 _state=STATE_HEADER; 423 _state=STATE_HEADER;
425 _tok0.setPutIndex(_tok0.getIndex()); 424 _tok0.setPutIndex(_tok0.getIndex());
426 _tok1.setPutIndex(_tok1.getIndex()); 425 _tok1.setPutIndex(_tok1.getIndex());
427 _multiLineValue=null; 426 _multiLineValue=null;
428 continue; 427 continue;
429 } 428 }
430 // not a digit, so must be a URI 429 // not a digit, so must be a URI
431 _state=STATE_URI; 430 _state=STATE_URI;
432 _responseStatus=-1; 431 _responseStatus=-1;
433 break; 432 break;
434 433
435 case STATE_URI: 434 case STATE_URI:
436 if (ch == HttpTokens.SPACE) 435 if (ch == HttpTokens.SPACE)
437 { 436 {
438 _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1); 437 _tok1.update(_buffer.markIndex(), _buffer.getIndex() - 1);
439 _state=STATE_SPACE2; 438 _state=STATE_SPACE2;
440 continue; 439 continue;
441 } 440 }
442 else if (ch < HttpTokens.SPACE && ch>=0) 441 else if (ch < HttpTokens.SPACE && ch>=0)
443 { 442 {
444 // HTTP/0.9 443 // HTTP/0.9
445 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer.sliceFromMark(), null); 444 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer.sliceFromMark(), null);
446 _persistent=false; 445 _persistent=false;
447 _state=STATE_SEEKING_EOF; 446 _state=STATE_SEEKING_EOF;
448 _handler.headerComplete(); 447 _handler.headerComplete();
449 _handler.messageComplete(_contentPosition); 448 _handler.messageComplete(_contentPosition);
450 return 1; 449 return 1;
451 } 450 }
452 break; 451 break;
453 452
454 case STATE_SPACE2: 453 case STATE_SPACE2:
455 if (ch > HttpTokens.SPACE || ch<0) 454 if (ch > HttpTokens.SPACE || ch<0)
456 { 455 {
457 _buffer.mark(); 456 _buffer.mark();
458 _state=STATE_FIELD2; 457 _state=STATE_FIELD2;
459 } 458 }
460 else if (ch < HttpTokens.SPACE) 459 else if (ch < HttpTokens.SPACE)
461 { 460 {
462 if (_responseStatus>0) 461 if (_responseStatus>0)
463 { 462 {
464 _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null); 463 _handler.startResponse(HttpMethods.CACHE.lookup(_tok0), _responseStatus, null);
465 _eol=ch; 464 _eol=ch;
466 _state=STATE_HEADER; 465 _state=STATE_HEADER;
467 _tok0.setPutIndex(_tok0.getIndex()); 466 _tok0.setPutIndex(_tok0.getIndex());
468 _tok1.setPutIndex(_tok1.getIndex()); 467 _tok1.setPutIndex(_tok1.getIndex());
469 _multiLineValue=null; 468 _multiLineValue=null;
470 } 469 }
471 else 470 else
472 { 471 {
473 // HTTP/0.9 472 // HTTP/0.9
474 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, null); 473 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, null);
475 _persistent=false; 474 _persistent=false;
476 _state=STATE_SEEKING_EOF; 475 _state=STATE_SEEKING_EOF;
477 _handler.headerComplete(); 476 _handler.headerComplete();
478 _handler.messageComplete(_contentPosition); 477 _handler.messageComplete(_contentPosition);
479 return 1; 478 return 1;
480 } 479 }
481 } 480 }
482 break; 481 break;
483 482
484 case STATE_FIELD2: 483 case STATE_FIELD2:
485 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) 484 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
486 { 485 {
487 Buffer version; 486 Buffer version;
488 if (_responseStatus>0) 487 if (_responseStatus>0)
489 _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark()); 488 _handler.startResponse(version=HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark());
490 else 489 else
491 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark())); 490 _handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, version=HttpVersions.CACHE.lookup(_buffer.sliceFromMark()));
492 _eol=ch; 491 _eol=ch;
493 _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL; 492 _persistent=HttpVersions.CACHE.getOrdinal(version)>=HttpVersions.HTTP_1_1_ORDINAL;
494 _state=STATE_HEADER; 493 _state=STATE_HEADER;
495 _tok0.setPutIndex(_tok0.getIndex()); 494 _tok0.setPutIndex(_tok0.getIndex());
496 _tok1.setPutIndex(_tok1.getIndex()); 495 _tok1.setPutIndex(_tok1.getIndex());
497 _multiLineValue=null; 496 _multiLineValue=null;
498 continue; 497 continue;
499 } 498 }
500 break; 499 break;
501 500
502 case STATE_HEADER: 501 case STATE_HEADER:
503 switch(ch) 502 switch(ch)
504 { 503 {
505 case HttpTokens.COLON: 504 case HttpTokens.COLON:
506 case HttpTokens.SPACE: 505 case HttpTokens.SPACE:
507 case HttpTokens.TAB: 506 case HttpTokens.TAB:
508 { 507 {
509 // header value without name - continuation? 508 // header value without name - continuation?
510 _length=-1; 509 _length=-1;
511 _state=STATE_HEADER_VALUE; 510 _state=STATE_HEADER_VALUE;
512 break; 511 break;
513 } 512 }
514 513
515 default: 514 default:
516 { 515 {
517 // handler last header if any 516 // handler last header if any
518 if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null) 517 if (_cached!=null || _tok0.length() > 0 || _tok1.length() > 0 || _multiLineValue != null)
519 { 518 {
520 Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0); 519 Buffer header=_cached!=null?_cached:HttpHeaders.CACHE.lookup(_tok0);
521 _cached=null; 520 _cached=null;
522 Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue); 521 Buffer value=_multiLineValue == null ? _tok1 : new ByteArrayBuffer(_multiLineValue);
523 522
524 int ho=HttpHeaders.CACHE.getOrdinal(header); 523 int ho=HttpHeaders.CACHE.getOrdinal(header);
525 if (ho >= 0) 524 if (ho >= 0)
526 { 525 {
527 int vo; 526 int vo;
528 527
529 switch (ho) 528 switch (ho)
530 { 529 {
531 case HttpHeaders.CONTENT_LENGTH_ORDINAL: 530 case HttpHeaders.CONTENT_LENGTH_ORDINAL:
532 if (_contentLength != HttpTokens.CHUNKED_CONTENT ) 531 if (_contentLength != HttpTokens.CHUNKED_CONTENT )
533 { 532 {
534 try 533 try
535 { 534 {
536 _contentLength=BufferUtil.toLong(value); 535 _contentLength=BufferUtil.toLong(value);
537 } 536 }
538 catch(NumberFormatException e) 537 catch(NumberFormatException e)
539 { 538 {
540 LOG.trace("",e); 539 LOG.trace("",e);
541 throw new HttpException(HttpStatus.BAD_REQUEST_400); 540 throw new HttpException(HttpStatus.BAD_REQUEST_400);
542 } 541 }
543 if (_contentLength <= 0) 542 if (_contentLength <= 0)
544 _contentLength=HttpTokens.NO_CONTENT; 543 _contentLength=HttpTokens.NO_CONTENT;
545 } 544 }
546 break; 545 break;
547 546
548 case HttpHeaders.TRANSFER_ENCODING_ORDINAL: 547 case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
549 value=HttpHeaderValues.CACHE.lookup(value); 548 value=HttpHeaderValues.CACHE.lookup(value);
550 vo=HttpHeaderValues.CACHE.getOrdinal(value); 549 vo=HttpHeaderValues.CACHE.getOrdinal(value);
551 if (HttpHeaderValues.CHUNKED_ORDINAL == vo) 550 if (HttpHeaderValues.CHUNKED_ORDINAL == vo)
552 _contentLength=HttpTokens.CHUNKED_CONTENT; 551 _contentLength=HttpTokens.CHUNKED_CONTENT;
553 else 552 else
554 { 553 {
555 String c=value.toString(StringUtil.__ISO_8859_1); 554 String c=value.toString(StringUtil.__ISO_8859_1);
556 if (c.endsWith(HttpHeaderValues.CHUNKED)) 555 if (c.endsWith(HttpHeaderValues.CHUNKED))
557 _contentLength=HttpTokens.CHUNKED_CONTENT; 556 _contentLength=HttpTokens.CHUNKED_CONTENT;
558 557
559 else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0) 558 else if (c.indexOf(HttpHeaderValues.CHUNKED) >= 0)
560 throw new HttpException(400,null); 559 throw new HttpException(400,null);
561 } 560 }
562 break; 561 break;
563 562
564 case HttpHeaders.CONNECTION_ORDINAL: 563 case HttpHeaders.CONNECTION_ORDINAL:
565 switch(HttpHeaderValues.CACHE.getOrdinal(value)) 564 switch(HttpHeaderValues.CACHE.getOrdinal(value))
566 { 565 {
567 case HttpHeaderValues.CLOSE_ORDINAL: 566 case HttpHeaderValues.CLOSE_ORDINAL:
568 _persistent=false; 567 _persistent=false;
569 break; 568 break;
570 569
571 case HttpHeaderValues.KEEP_ALIVE_ORDINAL: 570 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
572 _persistent=true; 571 _persistent=true;
573 break; 572 break;
574 573
575 case -1: // No match, may be multi valued 574 case -1: // No match, may be multi valued
576 { 575 {
577 for (String v : value.toString().split(",")) 576 for (String v : value.toString().split(","))
578 { 577 {
579 switch(HttpHeaderValues.CACHE.getOrdinal(v.trim())) 578 switch(HttpHeaderValues.CACHE.getOrdinal(v.trim()))
580 { 579 {
581 case HttpHeaderValues.CLOSE_ORDINAL: 580 case HttpHeaderValues.CLOSE_ORDINAL:
582 _persistent=false; 581 _persistent=false;
583 break; 582 break;
584 583
585 case HttpHeaderValues.KEEP_ALIVE_ORDINAL: 584 case HttpHeaderValues.KEEP_ALIVE_ORDINAL:
586 _persistent=true; 585 _persistent=true;
587 break; 586 break;
588 } 587 }
589 } 588 }
590 break; 589 break;
591 } 590 }
592 } 591 }
593 } 592 }
594 } 593 }
595 594
596 _handler.parsedHeader(header, value); 595 _handler.parsedHeader(header, value);
597 _tok0.setPutIndex(_tok0.getIndex()); 596 _tok0.setPutIndex(_tok0.getIndex());
598 _tok1.setPutIndex(_tok1.getIndex()); 597 _tok1.setPutIndex(_tok1.getIndex());
599 _multiLineValue=null; 598 _multiLineValue=null;
600 } 599 }
601 _buffer.setMarkIndex(-1); 600 _buffer.setMarkIndex(-1);
602 601
603 // now handle ch 602 // now handle ch
604 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) 603 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
605 { 604 {
606 // is it a response that cannot have a body? 605 // is it a response that cannot have a body?
607 if (_responseStatus > 0 && // response 606 if (_responseStatus > 0 && // response
608 (_responseStatus == 304 || // not-modified response 607 (_responseStatus == 304 || // not-modified response
609 _responseStatus == 204 || // no-content response 608 _responseStatus == 204 || // no-content response
610 _responseStatus < 200)) // 1xx response 609 _responseStatus < 200)) // 1xx response
611 _contentLength=HttpTokens.NO_CONTENT; // ignore any other headers set 610 _contentLength=HttpTokens.NO_CONTENT; // ignore any other headers set
612 // else if we don't know framing 611 // else if we don't know framing
613 else if (_contentLength == HttpTokens.UNKNOWN_CONTENT) 612 else if (_contentLength == HttpTokens.UNKNOWN_CONTENT)
614 { 613 {
615 if (_responseStatus == 0 // request 614 if (_responseStatus == 0 // request
616 || _responseStatus == 304 // not-modified response 615 || _responseStatus == 304 // not-modified response
617 || _responseStatus == 204 // no-content response 616 || _responseStatus == 204 // no-content response
618 || _responseStatus < 200) // 1xx response 617 || _responseStatus < 200) // 1xx response
619 _contentLength=HttpTokens.NO_CONTENT; 618 _contentLength=HttpTokens.NO_CONTENT;
620 else 619 else
621 _contentLength=HttpTokens.EOF_CONTENT; 620 _contentLength=HttpTokens.EOF_CONTENT;
622 } 621 }
623 622
624 _contentPosition=0; 623 _contentPosition=0;
625 _eol=ch; 624 _eol=ch;
626 if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) 625 if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
627 _eol=_buffer.get(); 626 _eol=_buffer.get();
628 627
629 // We convert _contentLength to an int for this switch statement because 628 // We convert _contentLength to an int for this switch statement because
630 // we don't care about the amount of data available just whether there is some. 629 // we don't care about the amount of data available just whether there is some.
631 switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength) 630 switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
632 { 631 {
633 case HttpTokens.EOF_CONTENT: 632 case HttpTokens.EOF_CONTENT:
634 _state=STATE_EOF_CONTENT; 633 _state=STATE_EOF_CONTENT;
635 _handler.headerComplete(); // May recurse here ! 634 _handler.headerComplete(); // May recurse here !
636 break; 635 break;
637 636
638 case HttpTokens.CHUNKED_CONTENT: 637 case HttpTokens.CHUNKED_CONTENT:
639 _state=STATE_CHUNKED_CONTENT; 638 _state=STATE_CHUNKED_CONTENT;
640 _handler.headerComplete(); // May recurse here ! 639 _handler.headerComplete(); // May recurse here !
641 break; 640 break;
642 641
643 case HttpTokens.NO_CONTENT: 642 case HttpTokens.NO_CONTENT:
644 _handler.headerComplete(); 643 _handler.headerComplete();
645 _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF; 644 _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
646 _handler.messageComplete(_contentPosition); 645 _handler.messageComplete(_contentPosition);
647 return 1; 646 return 1;
648 647
649 default: 648 default:
650 _state=STATE_CONTENT; 649 _state=STATE_CONTENT;
651 _handler.headerComplete(); // May recurse here ! 650 _handler.headerComplete(); // May recurse here !
652 break; 651 break;
653 } 652 }
654 return 1; 653 return 1;
655 } 654 }
656 else 655 else
657 { 656 {
658 // New header 657 // New header
659 _length=1; 658 _length=1;
660 _buffer.mark(); 659 _buffer.mark();
661 _state=STATE_HEADER_NAME; 660 _state=STATE_HEADER_NAME;
662 661
663 // try cached name! 662 // try cached name!
664 if (array!=null) 663 if (array!=null)
665 { 664 {
666 _cached=HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1); 665 _cached=HttpHeaders.CACHE.getBest(array, _buffer.markIndex(), length+1);
667 666
668 if (_cached!=null) 667 if (_cached!=null)
669 { 668 {
670 _length=_cached.length(); 669 _length=_cached.length();
671 _buffer.setGetIndex(_buffer.markIndex()+_length); 670 _buffer.setGetIndex(_buffer.markIndex()+_length);
672 length=_buffer.length(); 671 length=_buffer.length();
673 } 672 }
674 } 673 }
675 } 674 }
676 } 675 }
677 } 676 }
678 677
679 break; 678 break;
680 679
681 case STATE_HEADER_NAME: 680 case STATE_HEADER_NAME:
682 switch(ch) 681 switch(ch)
683 { 682 {
684 case HttpTokens.CARRIAGE_RETURN: 683 case HttpTokens.CARRIAGE_RETURN:
685 case HttpTokens.LINE_FEED: 684 case HttpTokens.LINE_FEED:
686 if (_length > 0) 685 if (_length > 0)
687 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); 686 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
688 _eol=ch; 687 _eol=ch;
689 _state=STATE_HEADER; 688 _state=STATE_HEADER;
690 break; 689 break;
691 case HttpTokens.COLON: 690 case HttpTokens.COLON:
692 if (_length > 0 && _cached==null) 691 if (_length > 0 && _cached==null)
693 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); 692 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
694 _length=-1; 693 _length=-1;
695 _state=STATE_HEADER_VALUE; 694 _state=STATE_HEADER_VALUE;
696 break; 695 break;
697 case HttpTokens.SPACE: 696 case HttpTokens.SPACE:
698 case HttpTokens.TAB: 697 case HttpTokens.TAB:
699 break; 698 break;
700 default: 699 default:
701 { 700 {
702 _cached=null; 701 _cached=null;
703 if (_length == -1) 702 if (_length == -1)
704 _buffer.mark(); 703 _buffer.mark();
705 _length=_buffer.getIndex() - _buffer.markIndex(); 704 _length=_buffer.getIndex() - _buffer.markIndex();
706 _state=STATE_HEADER_IN_NAME; 705 _state=STATE_HEADER_IN_NAME;
707 } 706 }
708 } 707 }
709 708
710 break; 709 break;
711 710
712 case STATE_HEADER_IN_NAME: 711 case STATE_HEADER_IN_NAME:
713 switch(ch) 712 switch(ch)
714 { 713 {
715 case HttpTokens.CARRIAGE_RETURN: 714 case HttpTokens.CARRIAGE_RETURN:
716 case HttpTokens.LINE_FEED: 715 case HttpTokens.LINE_FEED:
717 if (_length > 0) 716 if (_length > 0)
718 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); 717 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
719 _eol=ch; 718 _eol=ch;
720 _state=STATE_HEADER; 719 _state=STATE_HEADER;
721 break; 720 break;
722 case HttpTokens.COLON: 721 case HttpTokens.COLON:
723 if (_length > 0 && _cached==null) 722 if (_length > 0 && _cached==null)
724 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length); 723 _tok0.update(_buffer.markIndex(), _buffer.markIndex() + _length);
725 _length=-1; 724 _length=-1;
726 _state=STATE_HEADER_VALUE; 725 _state=STATE_HEADER_VALUE;
727 break; 726 break;
728 case HttpTokens.SPACE: 727 case HttpTokens.SPACE:
729 case HttpTokens.TAB: 728 case HttpTokens.TAB:
730 _state=STATE_HEADER_NAME; 729 _state=STATE_HEADER_NAME;
731 break; 730 break;
732 default: 731 default:
733 { 732 {
734 _cached=null; 733 _cached=null;
735 _length++; 734 _length++;
736 } 735 }
737 } 736 }
738 break; 737 break;
739 738
740 case STATE_HEADER_VALUE: 739 case STATE_HEADER_VALUE:
741 switch(ch) 740 switch(ch)
742 { 741 {
743 case HttpTokens.CARRIAGE_RETURN: 742 case HttpTokens.CARRIAGE_RETURN:
744 case HttpTokens.LINE_FEED: 743 case HttpTokens.LINE_FEED:
745 if (_length > 0) 744 if (_length > 0)
746 { 745 {
747 if (_tok1.length() == 0) 746 if (_tok1.length() == 0)
748 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); 747 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
749 else 748 else
750 { 749 {
751 // Continuation line! 750 // Continuation line!
752 if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1); 751 if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1);
753 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); 752 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
754 _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1); 753 _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1);
755 } 754 }
756 } 755 }
757 _eol=ch; 756 _eol=ch;
758 _state=STATE_HEADER; 757 _state=STATE_HEADER;
759 break; 758 break;
760 case HttpTokens.SPACE: 759 case HttpTokens.SPACE:
761 case HttpTokens.TAB: 760 case HttpTokens.TAB:
762 break; 761 break;
763 default: 762 default:
764 { 763 {
765 if (_length == -1) 764 if (_length == -1)
766 _buffer.mark(); 765 _buffer.mark();
767 _length=_buffer.getIndex() - _buffer.markIndex(); 766 _length=_buffer.getIndex() - _buffer.markIndex();
768 _state=STATE_HEADER_IN_VALUE; 767 _state=STATE_HEADER_IN_VALUE;
769 } 768 }
770 } 769 }
771 break; 770 break;
772 771
773 case STATE_HEADER_IN_VALUE: 772 case STATE_HEADER_IN_VALUE:
774 switch(ch) 773 switch(ch)
775 { 774 {
776 case HttpTokens.CARRIAGE_RETURN: 775 case HttpTokens.CARRIAGE_RETURN:
777 case HttpTokens.LINE_FEED: 776 case HttpTokens.LINE_FEED:
778 if (_length > 0) 777 if (_length > 0)
779 { 778 {
780 if (_tok1.length() == 0) 779 if (_tok1.length() == 0)
781 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); 780 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
782 else 781 else
783 { 782 {
784 // Continuation line! 783 // Continuation line!
785 if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1); 784 if (_multiLineValue == null) _multiLineValue=_tok1.toString(StringUtil.__ISO_8859_1);
786 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length); 785 _tok1.update(_buffer.markIndex(), _buffer.markIndex() + _length);
787 _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1); 786 _multiLineValue += " " + _tok1.toString(StringUtil.__ISO_8859_1);
788 } 787 }
789 } 788 }
790 _eol=ch; 789 _eol=ch;
791 _state=STATE_HEADER; 790 _state=STATE_HEADER;
792 break; 791 break;
793 case HttpTokens.SPACE: 792 case HttpTokens.SPACE:
794 case HttpTokens.TAB: 793 case HttpTokens.TAB:
795 _state=STATE_HEADER_VALUE; 794 _state=STATE_HEADER_VALUE;
796 break; 795 break;
797 default: 796 default:
798 _length++; 797 _length++;
799 } 798 }
800 break; 799 break;
801 } 800 }
802 } // end of HEADER states loop 801 } // end of HEADER states loop
803 802
804 // ========================== 803 // ==========================
805 804
806 // Handle HEAD response 805 // Handle HEAD response
807 if (_responseStatus>0 && _headResponse) 806 if (_responseStatus>0 && _headResponse)
808 { 807 {
809 _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF; 808 _state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
810 _handler.messageComplete(_contentLength); 809 _handler.messageComplete(_contentLength);
811 } 810 }
812 811
813 812
814 // ========================== 813 // ==========================
815 814
816 // Handle _content 815 // Handle _content
817 length=_buffer.length(); 816 length=_buffer.length();
818 Buffer chunk; 817 Buffer chunk;
819 last=_state; 818 last=_state;
820 while (_state > STATE_END && length > 0) 819 while (_state > STATE_END && length > 0)
821 { 820 {
822 if (last!=_state) 821 if (last!=_state)
823 { 822 {
824 progress++; 823 progress++;
825 last=_state; 824 last=_state;
826 } 825 }
827 826
828 if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED) 827 if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer.peek() == HttpTokens.LINE_FEED)
829 { 828 {
830 _eol=_buffer.get(); 829 _eol=_buffer.get();
831 length=_buffer.length(); 830 length=_buffer.length();
832 continue; 831 continue;
833 } 832 }
834 _eol=0; 833 _eol=0;
835 switch (_state) 834 switch (_state)
836 { 835 {
837 case STATE_EOF_CONTENT: 836 case STATE_EOF_CONTENT:
838 chunk=_buffer.get(_buffer.length()); 837 chunk=_buffer.get(_buffer.length());
839 _contentPosition += chunk.length(); 838 _contentPosition += chunk.length();
840 _contentView.update(chunk); 839 _contentView.update(chunk);
841 _handler.content(chunk); // May recurse here 840 _handler.content(chunk); // May recurse here
842 // TODO adjust the _buffer to keep unconsumed content 841 // TODO adjust the _buffer to keep unconsumed content
843 return 1; 842 return 1;
844 843
845 case STATE_CONTENT: 844 case STATE_CONTENT:
846 { 845 {
847 long remaining=_contentLength - _contentPosition; 846 long remaining=_contentLength - _contentPosition;
848 if (remaining == 0) 847 if (remaining == 0)
849 { 848 {
850 _state=_persistent?STATE_END:STATE_SEEKING_EOF; 849 _state=_persistent?STATE_END:STATE_SEEKING_EOF;
851 _handler.messageComplete(_contentPosition); 850 _handler.messageComplete(_contentPosition);
852 return 1; 851 return 1;
853 } 852 }
854 853
855 if (length > remaining) 854 if (length > remaining)
856 { 855 {
857 // We can cast reamining to an int as we know that it is smaller than 856 // We can cast reamining to an int as we know that it is smaller than
858 // or equal to length which is already an int. 857 // or equal to length which is already an int.
859 length=(int)remaining; 858 length=(int)remaining;
860 } 859 }
861 860
862 chunk=_buffer.get(length); 861 chunk=_buffer.get(length);
863 _contentPosition += chunk.length(); 862 _contentPosition += chunk.length();
864 _contentView.update(chunk); 863 _contentView.update(chunk);
865 _handler.content(chunk); // May recurse here 864 _handler.content(chunk); // May recurse here
866 865
867 if(_contentPosition == _contentLength) 866 if(_contentPosition == _contentLength)
868 { 867 {
869 _state=_persistent?STATE_END:STATE_SEEKING_EOF; 868 _state=_persistent?STATE_END:STATE_SEEKING_EOF;
870 _handler.messageComplete(_contentPosition); 869 _handler.messageComplete(_contentPosition);
871 } 870 }
872 // TODO adjust the _buffer to keep unconsumed content 871 // TODO adjust the _buffer to keep unconsumed content
873 return 1; 872 return 1;
874 } 873 }
875 874
876 case STATE_CHUNKED_CONTENT: 875 case STATE_CHUNKED_CONTENT:
877 { 876 {
878 ch=_buffer.peek(); 877 ch=_buffer.peek();
879 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) 878 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
880 _eol=_buffer.get(); 879 _eol=_buffer.get();
881 else if (ch <= HttpTokens.SPACE) 880 else if (ch <= HttpTokens.SPACE)
882 _buffer.get(); 881 _buffer.get();
883 else 882 else
884 { 883 {
885 _chunkLength=0; 884 _chunkLength=0;
886 _chunkPosition=0; 885 _chunkPosition=0;
887 _state=STATE_CHUNK_SIZE; 886 _state=STATE_CHUNK_SIZE;
888 } 887 }
889 break; 888 break;
890 } 889 }
891 890
892 case STATE_CHUNK_SIZE: 891 case STATE_CHUNK_SIZE:
893 { 892 {
894 ch=_buffer.get(); 893 ch=_buffer.get();
895 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) 894 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
896 { 895 {
897 _eol=ch; 896 _eol=ch;
898 897
899 if (_chunkLength == 0) 898 if (_chunkLength == 0)
900 { 899 {
901 if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) 900 if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
902 _eol=_buffer.get(); 901 _eol=_buffer.get();
903 _state=_persistent?STATE_END:STATE_SEEKING_EOF; 902 _state=_persistent?STATE_END:STATE_SEEKING_EOF;
904 _handler.messageComplete(_contentPosition); 903 _handler.messageComplete(_contentPosition);
905 return 1; 904 return 1;
906 } 905 }
907 else 906 else
908 _state=STATE_CHUNK; 907 _state=STATE_CHUNK;
909 } 908 }
910 else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON) 909 else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
911 _state=STATE_CHUNK_PARAMS; 910 _state=STATE_CHUNK_PARAMS;
912 else if (ch >= '0' && ch <= '9') 911 else if (ch >= '0' && ch <= '9')
913 _chunkLength=_chunkLength * 16 + (ch - '0'); 912 _chunkLength=_chunkLength * 16 + (ch - '0');
914 else if (ch >= 'a' && ch <= 'f') 913 else if (ch >= 'a' && ch <= 'f')
915 _chunkLength=_chunkLength * 16 + (10 + ch - 'a'); 914 _chunkLength=_chunkLength * 16 + (10 + ch - 'a');
916 else if (ch >= 'A' && ch <= 'F') 915 else if (ch >= 'A' && ch <= 'F')
917 _chunkLength=_chunkLength * 16 + (10 + ch - 'A'); 916 _chunkLength=_chunkLength * 16 + (10 + ch - 'A');
918 else 917 else
919 throw new IOException("bad chunk char: " + ch); 918 throw new IOException("bad chunk char: " + ch);
920 break; 919 break;
921 } 920 }
922 921
923 case STATE_CHUNK_PARAMS: 922 case STATE_CHUNK_PARAMS:
924 { 923 {
925 ch=_buffer.get(); 924 ch=_buffer.get();
926 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED) 925 if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
927 { 926 {
928 _eol=ch; 927 _eol=ch;
929 if (_chunkLength == 0) 928 if (_chunkLength == 0)
930 { 929 {
931 if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED) 930 if (_eol==HttpTokens.CARRIAGE_RETURN && _buffer.hasContent() && _buffer.peek()==HttpTokens.LINE_FEED)
932 _eol=_buffer.get(); 931 _eol=_buffer.get();
933 _state=_persistent?STATE_END:STATE_SEEKING_EOF; 932 _state=_persistent?STATE_END:STATE_SEEKING_EOF;
934 _handler.messageComplete(_contentPosition); 933 _handler.messageComplete(_contentPosition);
935 return 1; 934 return 1;
936 } 935 }
937 else 936 else
938 _state=STATE_CHUNK; 937 _state=STATE_CHUNK;
939 } 938 }
940 break; 939 break;
941 } 940 }
942 941
943 case STATE_CHUNK: 942 case STATE_CHUNK:
944 { 943 {
945 int remaining=_chunkLength - _chunkPosition; 944 int remaining=_chunkLength - _chunkPosition;
946 if (remaining == 0) 945 if (remaining == 0)
947 { 946 {
948 _state=STATE_CHUNKED_CONTENT; 947 _state=STATE_CHUNKED_CONTENT;
949 break; 948 break;
950 } 949 }
951 else if (length > remaining) 950 else if (length > remaining)
952 length=remaining; 951 length=remaining;
953 chunk=_buffer.get(length); 952 chunk=_buffer.get(length);
954 _contentPosition += chunk.length(); 953 _contentPosition += chunk.length();
955 _chunkPosition += chunk.length(); 954 _chunkPosition += chunk.length();
956 _contentView.update(chunk); 955 _contentView.update(chunk);
957 _handler.content(chunk); // May recurse here 956 _handler.content(chunk); // May recurse here
958 // TODO adjust the _buffer to keep unconsumed content 957 // TODO adjust the _buffer to keep unconsumed content
959 return 1; 958 return 1;
960 } 959 }
961 960
962 case STATE_SEEKING_EOF: 961 case STATE_SEEKING_EOF:
963 { 962 {
964 // Close if there is more data than CRLF 963 // Close if there is more data than CRLF
965 if (_buffer.length()>2) 964 if (_buffer.length()>2)
966 { 965 {
967 _state=STATE_END; 966 _state=STATE_END;
968 _endp.close(); 967 _endp.close();
969 } 968 }
970 else 969 else
971 { 970 {
972 // or if the data is not white space 971 // or if the data is not white space
973 while (_buffer.length()>0) 972 while (_buffer.length()>0)
974 if (!Character.isWhitespace(_buffer.get())) 973 if (!Character.isWhitespace(_buffer.get()))
975 { 974 {
976 _state=STATE_END; 975 _state=STATE_END;
977 _endp.close(); 976 _endp.close();
978 _buffer.clear(); 977 _buffer.clear();
979 } 978 }
980 } 979 }
981 980
982 _buffer.clear(); 981 _buffer.clear();
983 break; 982 break;
984 } 983 }
985 } 984 }
986 985
987 length=_buffer.length(); 986 length=_buffer.length();
988 } 987 }
989 988
990 return progress; 989 return progress;
991 } 990 }
992 catch(HttpException e) 991 catch(HttpException e)
993 { 992 {
994 _persistent=false; 993 _persistent=false;
995 _state=STATE_SEEKING_EOF; 994 _state=STATE_SEEKING_EOF;
996 throw e; 995 throw e;
997 } 996 }
998 } 997 }
999 998
1000 /* ------------------------------------------------------------------------------- */ 999 /* ------------------------------------------------------------------------------- */
1001 /** fill the buffers from the endpoint 1000 /** fill the buffers from the endpoint
1002 * 1001 *
1003 */ 1002 */
1004 protected int fill() throws IOException 1003 protected int fill() throws IOException
1005 { 1004 {
1006 // Do we have a buffer? 1005 // Do we have a buffer?
1007 if (_buffer==null) 1006 if (_buffer==null)
1008 _buffer=getHeaderBuffer(); 1007 _buffer=getHeaderBuffer();
1009 1008
1010 // Is there unconsumed content in body buffer 1009 // Is there unconsumed content in body buffer
1011 if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent()) 1010 if (_state>STATE_END && _buffer==_header && _header!=null && !_header.hasContent() && _body!=null && _body.hasContent())
1012 { 1011 {
1013 _buffer=_body; 1012 _buffer=_body;
1014 return _buffer.length(); 1013 return _buffer.length();
1015 } 1014 }
1016 1015
1017 // Shall we switch to a body buffer? 1016 // Shall we switch to a body buffer?
1018 if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null)) 1017 if (_buffer==_header && _state>STATE_END && _header.length()==0 && (_forceContentBuffer || (_contentLength-_contentPosition)>_header.capacity()) && (_body!=null||_buffers!=null))
1019 { 1018 {
1020 if (_body==null) 1019 if (_body==null)
1021 _body=_buffers.getBuffer(); 1020 _body=_buffers.getBuffer();
1022 _buffer=_body; 1021 _buffer=_body;
1023 } 1022 }
1024 1023
1025 // Do we have somewhere to fill from? 1024 // Do we have somewhere to fill from?
1026 if (_endp != null ) 1025 if (_endp != null )
1027 { 1026 {
1028 // Shall we compact the body? 1027 // Shall we compact the body?
1029 if (_buffer==_body || _state>STATE_END) 1028 if (_buffer==_body || _state>STATE_END)
1030 { 1029 {
1031 _buffer.compact(); 1030 _buffer.compact();
1032 } 1031 }
1033 1032
1034 // Are we full? 1033 // Are we full?
1035 if (_buffer.space() == 0) 1034 if (_buffer.space() == 0)
1036 { 1035 {
1037 LOG.warn("HttpParser Full for {} ",_endp); 1036 LOG.warn("HttpParser Full for {} ",_endp);
1038 _buffer.clear(); 1037 _buffer.clear();
1039 throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large: "+(_buffer==_body?"body":"head")); 1038 throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "Request Entity Too Large: "+(_buffer==_body?"body":"head"));
1040 } 1039 }
1041 1040
1042 try 1041 try
1043 { 1042 {
1044 int filled = _endp.fill(_buffer); 1043 int filled = _endp.fill(_buffer);
1045 return filled; 1044 return filled;
1046 } 1045 }
1047 catch(IOException e) 1046 catch(IOException e)
1048 { 1047 {
1049 LOG.debug("",e); 1048 LOG.debug("",e);
1050 throw (e instanceof EofException) ? e:new EofException(e); 1049 throw (e instanceof EofException) ? e:new EofException(e);
1051 } 1050 }
1052 } 1051 }
1053 1052
1054 return -1; 1053 return -1;
1055 } 1054 }
1056 1055
1057 /* ------------------------------------------------------------------------------- */ 1056 /* ------------------------------------------------------------------------------- */
1058 public void reset() 1057 public void reset()
1059 { 1058 {
1060 // reset state 1059 // reset state
1061 _contentView.setGetIndex(_contentView.putIndex()); 1060 _contentView.setGetIndex(_contentView.putIndex());
1062 _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF); 1061 _state=_persistent?STATE_START:(_endp.isInputShutdown()?STATE_END:STATE_SEEKING_EOF);
1063 _contentLength=HttpTokens.UNKNOWN_CONTENT; 1062 _contentLength=HttpTokens.UNKNOWN_CONTENT;
1064 _contentPosition=0; 1063 _contentPosition=0;
1065 _length=0; 1064 _length=0;
1066 _responseStatus=0; 1065 _responseStatus=0;
1067 1066
1068 // Consume LF if CRLF 1067 // Consume LF if CRLF
1069 if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer!=null && _buffer.hasContent() && _buffer.peek() == HttpTokens.LINE_FEED) 1068 if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer!=null && _buffer.hasContent() && _buffer.peek() == HttpTokens.LINE_FEED)
1070 _eol=_buffer.get(); 1069 _eol=_buffer.get();
1071 1070
1072 if (_body!=null && _body.hasContent()) 1071 if (_body!=null && _body.hasContent())
1073 { 1072 {
1074 // There is content in the body after the end of the request. 1073 // There is content in the body after the end of the request.
1075 // This is probably a pipelined header of the next request, so we need to 1074 // This is probably a pipelined header of the next request, so we need to
1076 // copy it to the header buffer. 1075 // copy it to the header buffer.
1077 if (_header==null) 1076 if (_header==null)
1078 getHeaderBuffer(); 1077 getHeaderBuffer();
1079 else 1078 else
1080 { 1079 {
1081 _header.setMarkIndex(-1); 1080 _header.setMarkIndex(-1);
1082 _header.compact(); 1081 _header.compact();
1083 } 1082 }
1084 int take=_header.space(); 1083 int take=_header.space();
1085 if (take>_body.length()) 1084 if (take>_body.length())
1086 take=_body.length(); 1085 take=_body.length();
1087 _body.peek(_body.getIndex(),take); 1086 _body.peek(_body.getIndex(),take);
1088 _body.skip(_header.put(_body.peek(_body.getIndex(),take))); 1087 _body.skip(_header.put(_body.peek(_body.getIndex(),take)));
1089 } 1088 }
1090 1089
1091 if (_header!=null) 1090 if (_header!=null)
1092 { 1091 {
1093 _header.setMarkIndex(-1); 1092 _header.setMarkIndex(-1);
1094 _header.compact(); 1093 _header.compact();
1095 } 1094 }
1096 if (_body!=null) 1095 if (_body!=null)
1097 _body.setMarkIndex(-1); 1096 _body.setMarkIndex(-1);
1098 1097
1099 _buffer=_header; 1098 _buffer=_header;
1100 returnBuffers(); 1099 returnBuffers();
1101 } 1100 }
1102 1101
1103 1102
1104 /* ------------------------------------------------------------------------------- */ 1103 /* ------------------------------------------------------------------------------- */
1105 public void returnBuffers() 1104 public void returnBuffers()
1106 { 1105 {
1107 if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null) 1106 if (_body!=null && !_body.hasContent() && _body.markIndex()==-1 && _buffers!=null)
1108 { 1107 {
1109 if (_buffer==_body) 1108 if (_buffer==_body)
1110 _buffer=_header; 1109 _buffer=_header;
1111 if (_buffers!=null) 1110 if (_buffers!=null)
1112 _buffers.returnBuffer(_body); 1111 _buffers.returnBuffer(_body);
1113 _body=null; 1112 _body=null;
1114 } 1113 }
1115 1114
1116 if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null) 1115 if (_header!=null && !_header.hasContent() && _header.markIndex()==-1 && _buffers!=null)
1117 { 1116 {
1118 if (_buffer==_header) 1117 if (_buffer==_header)
1119 _buffer=null; 1118 _buffer=null;
1120 _buffers.returnBuffer(_header); 1119 _buffers.returnBuffer(_header);
1121 _header=null; 1120 _header=null;
1122 } 1121 }
1123 } 1122 }
1124 1123
1125 /* ------------------------------------------------------------------------------- */ 1124 /* ------------------------------------------------------------------------------- */
1126 public void setState(int state) 1125 public void setState(int state)
1127 { 1126 {
1128 this._state=state; 1127 this._state=state;
1129 _contentLength=HttpTokens.UNKNOWN_CONTENT; 1128 _contentLength=HttpTokens.UNKNOWN_CONTENT;
1130 } 1129 }
1131 1130
1132 /* ------------------------------------------------------------------------------- */ 1131 /* ------------------------------------------------------------------------------- */
1133 public String toString(Buffer buf) 1132 public String toString(Buffer buf)
1134 { 1133 {
1135 return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode(); 1134 return "state=" + _state + " length=" + _length + " buf=" + buf.hashCode();
1136 } 1135 }
1137 1136
1138 /* ------------------------------------------------------------------------------- */ 1137 /* ------------------------------------------------------------------------------- */
1139 @Override 1138 @Override
1140 public String toString() 1139 public String toString()
1141 { 1140 {
1142 return String.format("%s{s=%d,l=%d,c=%d}", 1141 return String.format("%s{s=%d,l=%d,c=%d}",
1143 getClass().getSimpleName(), 1142 getClass().getSimpleName(),
1144 _state, 1143 _state,
1145 _length, 1144 _length,
1146 _contentLength); 1145 _contentLength);
1147 } 1146 }
1148 1147
1149 /* ------------------------------------------------------------ */ 1148 /* ------------------------------------------------------------ */
1150 public Buffer getHeaderBuffer() 1149 public Buffer getHeaderBuffer()
1151 { 1150 {
1152 if (_header == null) 1151 if (_header == null)
1153 { 1152 {
1154 _header=_buffers.getHeader(); 1153 _header=_buffers.getHeader();
1155 _tok0.update(_header); 1154 _tok0.update(_header);
1156 _tok1.update(_header); 1155 _tok1.update(_header);
1157 } 1156 }
1158 return _header; 1157 return _header;
1159 } 1158 }
1160 1159
1161 /* ------------------------------------------------------------ */ 1160 /* ------------------------------------------------------------ */
1162 public Buffer getBodyBuffer() 1161 public Buffer getBodyBuffer()
1163 { 1162 {
1164 return _body; 1163 return _body;
1165 } 1164 }
1166 1165
1167 /* ------------------------------------------------------------ */ 1166 /* ------------------------------------------------------------ */
1168 /** 1167 /**
1169 * @param force True if a new buffer will be forced to be used for content and the header buffer will not be used. 1168 * @param force True if a new buffer will be forced to be used for content and the header buffer will not be used.
1170 */ 1169 */
1171 public void setForceContentBuffer(boolean force) 1170 public void setForceContentBuffer(boolean force)
1172 { 1171 {
1173 _forceContentBuffer=force; 1172 _forceContentBuffer=force;
1174 } 1173 }
1175 1174
1176 /* ------------------------------------------------------------ */ 1175 /* ------------------------------------------------------------ */
1177 public Buffer blockForContent(long maxIdleTime) throws IOException 1176 public Buffer blockForContent(long maxIdleTime) throws IOException
1178 { 1177 {
1179 if (_contentView.length()>0) 1178 if (_contentView.length()>0)
1180 return _contentView; 1179 return _contentView;
1181 1180
1182 if (getState() <= STATE_END || isState(STATE_SEEKING_EOF)) 1181 if (getState() <= STATE_END || isState(STATE_SEEKING_EOF))
1183 return null; 1182 return null;
1184 1183
1185 try 1184 try
1186 { 1185 {
1187 parseNext(); 1186 parseNext();
1188 1187
1189 // parse until some progress is made (or IOException thrown for timeout) 1188 // parse until some progress is made (or IOException thrown for timeout)
1190 while(_contentView.length() == 0 && !(isState(HttpParser.STATE_END)||isState(HttpParser.STATE_SEEKING_EOF)) && _endp!=null && _endp.isOpen()) 1189 while(_contentView.length() == 0 && !(isState(HttpParser.STATE_END)||isState(HttpParser.STATE_SEEKING_EOF)) && _endp!=null && _endp.isOpen())
1191 { 1190 {
1192 if (!_endp.isBlocking()) 1191 if (!_endp.isBlocking())
1193 { 1192 {
1194 if (parseNext()>0) 1193 if (parseNext()>0)
1195 continue; 1194 continue;
1196 1195
1197 if (!_endp.blockReadable(maxIdleTime)) 1196 if (!_endp.blockReadable(maxIdleTime))
1198 { 1197 {
1199 _endp.close(); 1198 _endp.close();
1200 throw new EofException("timeout"); 1199 throw new EofException("timeout");
1201 } 1200 }
1202 } 1201 }
1203 1202
1204 parseNext(); 1203 parseNext();
1205 } 1204 }
1206 } 1205 }
1207 catch(IOException e) 1206 catch(IOException e)
1208 { 1207 {
1209 // TODO is this needed? 1208 // TODO is this needed?
1210 _endp.close(); 1209 _endp.close();
1211 throw e; 1210 throw e;
1212 } 1211 }
1213 1212
1214 return _contentView.length()>0?_contentView:null; 1213 return _contentView.length()>0?_contentView:null;
1215 } 1214 }
1216 1215
1217 /* ------------------------------------------------------------ */ 1216 /* ------------------------------------------------------------ */
1218 /* (non-Javadoc) 1217 /* (non-Javadoc)
1219 * @see java.io.InputStream#available() 1218 * @see java.io.InputStream#available()
1220 */ 1219 */
1221 public int available() throws IOException 1220 public int available() throws IOException
1222 { 1221 {
1223 if (_contentView!=null && _contentView.length()>0) 1222 if (_contentView!=null && _contentView.length()>0)
1224 return _contentView.length(); 1223 return _contentView.length();
1225 1224
1226 if (_endp.isBlocking()) 1225 if (_endp.isBlocking())
1227 { 1226 {
1228 if (_state>0 && _endp instanceof StreamEndPoint) 1227 return 0;
1229 return ((StreamEndPoint)_endp).getInputStream().available()>0?1:0; 1228 }
1230 1229
1231 return 0; 1230 parseNext();
1232 } 1231 return _contentView==null?0:_contentView.length();
1233 1232 }
1234 parseNext(); 1233
1235 return _contentView==null?0:_contentView.length(); 1234 /* ------------------------------------------------------------ */
1236 } 1235 /* ------------------------------------------------------------ */
1237 1236 /* ------------------------------------------------------------ */
1238 /* ------------------------------------------------------------ */ 1237 public static abstract class EventHandler
1239 /* ------------------------------------------------------------ */ 1238 {
1240 /* ------------------------------------------------------------ */ 1239 public abstract void content(Buffer ref) throws IOException;
1241 public static abstract class EventHandler 1240
1242 { 1241 public void headerComplete() throws IOException
1243 public abstract void content(Buffer ref) throws IOException; 1242 {
1244 1243 }
1245 public void headerComplete() throws IOException 1244
1246 { 1245 public void messageComplete(long contentLength) throws IOException
1247 } 1246 {
1248 1247 }
1249 public void messageComplete(long contentLength) throws IOException 1248
1250 { 1249 /**
1251 } 1250 * This is the method called by parser when a HTTP Header name and value is found
1252 1251 */
1253 /** 1252 public void parsedHeader(Buffer name, Buffer value) throws IOException
1254 * This is the method called by parser when a HTTP Header name and value is found 1253 {
1255 */ 1254 }
1256 public void parsedHeader(Buffer name, Buffer value) throws IOException 1255
1257 { 1256 /**
1258 } 1257 * This is the method called by parser when the HTTP request line is parsed
1259 1258 */
1260 /** 1259 public abstract void startRequest(Buffer method, Buffer url, Buffer version)
1261 * This is the method called by parser when the HTTP request line is parsed 1260 throws IOException;
1262 */ 1261
1263 public abstract void startRequest(Buffer method, Buffer url, Buffer version) 1262 /**
1264 throws IOException; 1263 * This is the method called by parser when the HTTP request line is parsed
1265 1264 */
1266 /** 1265 public abstract void startResponse(Buffer version, int status, Buffer reason)
1267 * This is the method called by parser when the HTTP request line is parsed 1266 throws IOException;
1268 */ 1267
1269 public abstract void startResponse(Buffer version, int status, Buffer reason) 1268 public void earlyEOF()
1270 throws IOException; 1269 {}
1271 1270 }
1272 public void earlyEOF()
1273 {}
1274 }
1275 1271
1276 1272
1277 1273
1278 1274
1279 } 1275 }