Source Code Cross Referenced for HttpParser.java in  » Sevlet-Container » jetty-modules » org » mortbay » jetty » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Sevlet Container » jetty modules » org.mortbay.jetty 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        // ========================================================================
002:        // Copyright 2004-2006 Mort Bay Consulting Pty. Ltd.
003:        // ------------------------------------------------------------------------
004:        // Licensed under the Apache License, Version 2.0 (the "License");
005:        // you may not use this file except in compliance with the License.
006:        // You may obtain a copy of the License at
007:        // http://www.apache.org/licenses/LICENSE-2.0
008:        // Unless required by applicable law or agreed to in writing, software
009:        // distributed under the License is distributed on an "AS IS" BASIS,
010:        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011:        // See the License for the specific language governing permissions and
012:        // limitations under the License.
013:        // ========================================================================
014:
015:        package org.mortbay.jetty;
016:
017:        import java.io.IOException;
018:        import java.io.InterruptedIOException;
019:
020:        import javax.servlet.ServletInputStream;
021:        import javax.servlet.http.HttpServletResponse;
022:
023:        import org.mortbay.io.Buffer;
024:        import org.mortbay.io.BufferUtil;
025:        import org.mortbay.io.Buffers;
026:        import org.mortbay.io.ByteArrayBuffer;
027:        import org.mortbay.io.EndPoint;
028:        import org.mortbay.io.View;
029:        import org.mortbay.io.BufferCache.CachedBuffer;
030:        import org.mortbay.log.Log;
031:
032:        /* ------------------------------------------------------------------------------- */
033:        /**
034:         * @author gregw
035:         */
036:        public class HttpParser implements  Parser {
037:            // States
038:            public static final int STATE_START = -11;
039:            public static final int STATE_FIELD0 = -10;
040:            public static final int STATE_SPACE1 = -9;
041:            public static final int STATE_FIELD1 = -8;
042:            public static final int STATE_SPACE2 = -7;
043:            public static final int STATE_END0 = -6;
044:            public static final int STATE_END1 = -5;
045:            public static final int STATE_FIELD2 = -4;
046:            public static final int STATE_HEADER = -3;
047:            public static final int STATE_HEADER_NAME = -2;
048:            public static final int STATE_HEADER_VALUE = -1;
049:            public static final int STATE_END = 0;
050:            public static final int STATE_EOF_CONTENT = 1;
051:            public static final int STATE_CONTENT = 2;
052:            public static final int STATE_CHUNKED_CONTENT = 3;
053:            public static final int STATE_CHUNK_SIZE = 4;
054:            public static final int STATE_CHUNK_PARAMS = 5;
055:            public static final int STATE_CHUNK = 6;
056:
057:            private Buffers _buffers; // source of buffers
058:            private EndPoint _endp;
059:            private Buffer _header; // Buffer for header data (and small _content)
060:            private Buffer _body; // Buffer for large content
061:            private Buffer _buffer; // The current buffer in use (either _header or _content)
062:            private View _contentView = new View(); // View of the content in the buffer for {@link Input}
063:            private int _headerBufferSize;
064:
065:            private int _contentBufferSize;
066:            private EventHandler _handler;
067:            private CachedBuffer _cached;
068:            private View _tok0; // Saved token: header name, request method or response version
069:            private View _tok1; // Saved token: header value, request URI or response code
070:            private String _multiLineValue;
071:            private boolean _response = false; // true if parsing a HTTP response
072:            /* ------------------------------------------------------------------------------- */
073:            protected int _state = STATE_START;
074:            protected byte _eol;
075:            protected int _length;
076:            protected long _contentLength;
077:            protected long _contentPosition;
078:            protected int _chunkLength;
079:            protected int _chunkPosition;
080:
081:            /* ------------------------------------------------------------------------------- */
082:            /**
083:             * Constructor.
084:             */
085:            public HttpParser(Buffer buffer, EventHandler handler) {
086:                this ._header = buffer;
087:                this ._buffer = buffer;
088:                this ._handler = handler;
089:
090:                if (buffer != null) {
091:                    _tok0 = new View(buffer);
092:                    _tok1 = new View(buffer);
093:                    _tok0.setPutIndex(_tok0.getIndex());
094:                    _tok1.setPutIndex(_tok1.getIndex());
095:                }
096:            }
097:
098:            /* ------------------------------------------------------------------------------- */
099:            /**
100:             * Constructor.
101:             * @param headerBufferSize size in bytes of header buffer  
102:             * @param contentBufferSize size in bytes of content buffer
103:             */
104:            public HttpParser(Buffers buffers, EndPoint endp,
105:                    EventHandler handler, int headerBufferSize,
106:                    int contentBufferSize) {
107:                _buffers = buffers;
108:                _endp = endp;
109:                _handler = handler;
110:                _headerBufferSize = headerBufferSize;
111:                _contentBufferSize = contentBufferSize;
112:            }
113:
114:            /* ------------------------------------------------------------------------------- */
115:            public long getContentLength() {
116:                return _contentLength;
117:            }
118:
119:            /* ------------------------------------------------------------------------------- */
120:            public int getState() {
121:                return _state;
122:            }
123:
124:            /* ------------------------------------------------------------------------------- */
125:            public boolean inContentState() {
126:                return _state > 0;
127:            }
128:
129:            /* ------------------------------------------------------------------------------- */
130:            public boolean inHeaderState() {
131:                return _state < 0;
132:            }
133:
134:            /* ------------------------------------------------------------------------------- */
135:            public boolean isChunking() {
136:                return _contentLength == HttpTokens.CHUNKED_CONTENT;
137:            }
138:
139:            /* ------------------------------------------------------------ */
140:            public boolean isIdle() {
141:                return isState(STATE_START);
142:            }
143:
144:            /* ------------------------------------------------------------ */
145:            public boolean isComplete() {
146:                return isState(STATE_END);
147:            }
148:
149:            /* ------------------------------------------------------------ */
150:            public boolean isMoreInBuffer() throws IOException {
151:                if (_header != null && _header.hasContent() || _body != null
152:                        && _body.hasContent())
153:                    return true;
154:
155:                return false;
156:            }
157:
158:            /* ------------------------------------------------------------------------------- */
159:            public boolean isState(int state) {
160:                return _state == state;
161:            }
162:
163:            /* ------------------------------------------------------------------------------- */
164:            /**
165:             * Parse until {@link #STATE_END END} state.
166:             * If the parser is already in the END state, then it is {@link #reset reset} and re-parsed.
167:             * @throws IllegalStateException If the buffers have already been partially parsed.
168:             */
169:            public void parse() throws IOException {
170:                if (_state == STATE_END)
171:                    reset(false);
172:                if (_state != STATE_START)
173:                    throw new IllegalStateException("!START");
174:
175:                // continue parsing
176:                while (_state != STATE_END)
177:                    parseNext();
178:            }
179:
180:            /* ------------------------------------------------------------------------------- */
181:            /**
182:             * Parse until END state.
183:             * This method will parse any remaining content in the current buffer. It does not care about the 
184:             * {@link #getState current state} of the parser.
185:             * @see #parse
186:             * @see #parseNext
187:             */
188:            public long parseAvailable() throws IOException {
189:                long len = parseNext();
190:                long total = len > 0 ? len : 0;
191:
192:                // continue parsing
193:                while (!isComplete() && _buffer != null && _buffer.length() > 0) {
194:                    len = parseNext();
195:                    if (len > 0)
196:                        total += len;
197:                }
198:                return total;
199:            }
200:
201:            /* ------------------------------------------------------------------------------- */
202:            /**
203:             * Parse until next Event.
204:             * @returns number of bytes filled from endpoint or -1 if fill never called.
205:             */
206:            public long parseNext() throws IOException {
207:                long total_filled = -1;
208:
209:                if (_buffer == null) {
210:                    if (_header == null) {
211:                        _header = _buffers.getBuffer(_headerBufferSize);
212:                    }
213:                    _buffer = _header;
214:                    _tok0 = new View(_header);
215:                    _tok1 = new View(_header);
216:                    _tok0.setPutIndex(_tok0.getIndex());
217:                    _tok1.setPutIndex(_tok1.getIndex());
218:                }
219:
220:                if (_state == STATE_END)
221:                    throw new IllegalStateException("STATE_END");
222:                if (_state == STATE_CONTENT
223:                        && _contentPosition == _contentLength) {
224:                    _state = STATE_END;
225:                    _handler.messageComplete(_contentPosition);
226:                    return total_filled;
227:                }
228:
229:                int length = _buffer.length();
230:
231:                // Fill buffer if we can
232:                if (length == 0) {
233:                    int filled = -1;
234:                    if (_body != null && _buffer != _body) {
235:                        _buffer = _body;
236:                        filled = _buffer.length();
237:                    }
238:
239:                    if (_buffer.markIndex() == 0
240:                            && _buffer.putIndex() == _buffer.capacity())
241:                        throw new IOException("FULL");
242:                    if (_endp != null && filled <= 0) {
243:                        // Compress buffer if handling _content buffer
244:                        // TODO check this is not moving data too much
245:                        if (_buffer == _body)
246:                            _buffer.compact();
247:
248:                        if (_buffer.space() == 0) {
249:                            throw new IOException("FULL");
250:                        }
251:
252:                        try {
253:                            if (total_filled < 0)
254:                                total_filled = 0;
255:                            filled = _endp.fill(_buffer);
256:                            if (filled > 0)
257:                                total_filled += filled;
258:                        } catch (IOException e) {
259:                            Log.debug(e);
260:                            reset(true);
261:                            throw (e instanceof  EofException) ? e
262:                                    : new EofException(e);
263:                        }
264:                    }
265:
266:                    if (filled < 0) {
267:                        if (_state == STATE_EOF_CONTENT) {
268:                            _state = STATE_END;
269:                            _handler.messageComplete(_contentPosition);
270:                            return total_filled;
271:                        }
272:                        reset(true);
273:                        throw new EofException();
274:                    }
275:                    length = _buffer.length();
276:                }
277:
278:                // EventHandler header
279:                byte ch;
280:                byte[] array = _buffer.array();
281:
282:                while (_state < STATE_END && length-- > 0) {
283:                    ch = _buffer.get();
284:
285:                    if (_eol == HttpTokens.CARRIAGE_RETURN
286:                            && ch == HttpTokens.LINE_FEED) {
287:                        _eol = HttpTokens.LINE_FEED;
288:                        continue;
289:                    }
290:                    _eol = 0;
291:                    switch (_state) {
292:                    case STATE_START:
293:                        _contentLength = HttpTokens.UNKNOWN_CONTENT;
294:                        _cached = null;
295:                        if (ch > HttpTokens.SPACE || ch < 0) {
296:                            _buffer.mark();
297:                            _state = STATE_FIELD0;
298:                        }
299:                        break;
300:
301:                    case STATE_FIELD0:
302:                        if (ch == HttpTokens.SPACE) {
303:                            _tok0.update(_buffer.markIndex(), _buffer
304:                                    .getIndex() - 1);
305:                            _state = STATE_SPACE1;
306:                            continue;
307:                        } else if (ch < HttpTokens.SPACE && ch >= 0) {
308:                            throw new HttpException(
309:                                    HttpServletResponse.SC_BAD_REQUEST);
310:                        }
311:                        break;
312:
313:                    case STATE_SPACE1:
314:                        if (ch > HttpTokens.SPACE || ch < 0) {
315:                            _buffer.mark();
316:                            _state = STATE_FIELD1;
317:                            _response = ch >= '1' && ch <= '5';
318:                        } else if (ch < HttpTokens.SPACE) {
319:                            throw new HttpException(
320:                                    HttpServletResponse.SC_BAD_REQUEST);
321:                        }
322:                        break;
323:
324:                    case STATE_FIELD1:
325:                        if (ch == HttpTokens.SPACE) {
326:                            _tok1.update(_buffer.markIndex(), _buffer
327:                                    .getIndex() - 1);
328:                            _state = STATE_SPACE2;
329:                            continue;
330:                        } else if (ch < HttpTokens.SPACE && ch >= 0) {
331:                            // HTTP/0.9
332:                            _handler.startRequest(HttpMethods.CACHE
333:                                    .lookup(_tok0), _buffer.sliceFromMark(),
334:                                    null);
335:                            _state = STATE_END;
336:                            _handler.headerComplete();
337:                            _handler.messageComplete(_contentPosition);
338:                            return total_filled;
339:                        }
340:                        break;
341:
342:                    case STATE_SPACE2:
343:                        if (ch > HttpTokens.SPACE || ch < 0) {
344:                            _buffer.mark();
345:                            _state = STATE_FIELD2;
346:                        } else if (ch < HttpTokens.SPACE) {
347:                            // HTTP/0.9
348:                            _handler.startRequest(HttpMethods.CACHE
349:                                    .lookup(_tok0), _tok1, null);
350:                            _state = STATE_END;
351:                            _handler.headerComplete();
352:                            _handler.messageComplete(_contentPosition);
353:                            return total_filled;
354:                        }
355:                        break;
356:
357:                    case STATE_FIELD2:
358:                        if (ch == HttpTokens.CARRIAGE_RETURN
359:                                || ch == HttpTokens.LINE_FEED) {
360:                            if (_response)
361:                                _handler.startResponse(HttpVersions.CACHE
362:                                        .lookup(_tok0),
363:                                        BufferUtil.toInt(_tok1), _buffer
364:                                                .sliceFromMark());
365:                            else
366:                                _handler.startRequest(HttpMethods.CACHE
367:                                        .lookup(_tok0), _tok1,
368:                                        HttpVersions.CACHE.lookup(_buffer
369:                                                .sliceFromMark()));
370:                            _eol = ch;
371:                            _state = STATE_HEADER;
372:                            _tok0.setPutIndex(_tok0.getIndex());
373:                            _tok1.setPutIndex(_tok1.getIndex());
374:                            _multiLineValue = null;
375:                            return total_filled;
376:                        }
377:                        break;
378:
379:                    case STATE_HEADER:
380:                        if (ch == HttpTokens.COLON || ch == HttpTokens.SPACE
381:                                || ch == HttpTokens.TAB) {
382:                            // header value without name - continuation?
383:                            _length = -1;
384:                            _state = STATE_HEADER_VALUE;
385:                        } else {
386:                            // handler last header if any
387:                            if (_cached != null || _tok0.length() > 0
388:                                    || _tok1.length() > 0
389:                                    || _multiLineValue != null) {
390:
391:                                Buffer header = _cached != null ? _cached
392:                                        : HttpHeaders.CACHE.lookup(_tok0);
393:                                _cached = null;
394:                                Buffer value = _multiLineValue == null ? (Buffer) _tok1
395:                                        : (Buffer) new ByteArrayBuffer(
396:                                                _multiLineValue);
397:
398:                                int ho = HttpHeaders.CACHE.getOrdinal(header);
399:                                if (ho >= 0) {
400:                                    int vo = -1;
401:
402:                                    switch (ho) {
403:                                    case HttpHeaders.CONTENT_LENGTH_ORDINAL:
404:                                        if (_contentLength != HttpTokens.CHUNKED_CONTENT) {
405:                                            _contentLength = BufferUtil
406:                                                    .toLong(value);
407:                                            if (_contentLength <= 0)
408:                                                _contentLength = HttpTokens.NO_CONTENT;
409:                                        }
410:                                        break;
411:
412:                                    case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
413:                                        value = HttpHeaderValues.CACHE
414:                                                .lookup(value);
415:                                        vo = HttpHeaderValues.CACHE
416:                                                .getOrdinal(value);
417:                                        if (HttpHeaderValues.CHUNKED_ORDINAL == vo)
418:                                            _contentLength = HttpTokens.CHUNKED_CONTENT;
419:                                        else {
420:                                            String c = value.toString();
421:                                            if (c
422:                                                    .endsWith(HttpHeaderValues.CHUNKED))
423:                                                _contentLength = HttpTokens.CHUNKED_CONTENT;
424:
425:                                            else if (c
426:                                                    .indexOf(HttpHeaderValues.CHUNKED) >= 0)
427:                                                throw new HttpException(400,
428:                                                        null);
429:                                        }
430:                                        break;
431:                                    }
432:                                }
433:
434:                                _handler.parsedHeader(header, value);
435:                                _tok0.setPutIndex(_tok0.getIndex());
436:                                _tok1.setPutIndex(_tok1.getIndex());
437:                                _multiLineValue = null;
438:                            }
439:
440:                            // now handle ch
441:                            if (ch == HttpTokens.CARRIAGE_RETURN
442:                                    || ch == HttpTokens.LINE_FEED) {
443:                                // End of header
444:
445:                                // work out the _content demarcation
446:                                if (_contentLength == HttpTokens.UNKNOWN_CONTENT)
447:                                    _contentLength = _response ? HttpTokens.EOF_CONTENT
448:                                            : HttpTokens.NO_CONTENT;
449:
450:                                _contentPosition = 0;
451:                                _eol = ch;
452:                                // We convert _contentLength to an int for this switch statement because
453:                                // we don't care about the amount of data available just whether there is some.
454:                                switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE
455:                                        : (int) _contentLength) {
456:                                case HttpTokens.EOF_CONTENT:
457:                                    _state = STATE_EOF_CONTENT;
458:                                    if (_body == null && _buffers != null)
459:                                        _body = _buffers
460:                                                .getBuffer(_contentBufferSize);
461:
462:                                    _handler.headerComplete(); // May recurse here !
463:                                    break;
464:
465:                                case HttpTokens.CHUNKED_CONTENT:
466:                                    _state = STATE_CHUNKED_CONTENT;
467:                                    if (_body == null && _buffers != null)
468:                                        _body = _buffers
469:                                                .getBuffer(_contentBufferSize);
470:                                    _handler.headerComplete(); // May recurse here !
471:                                    break;
472:
473:                                case HttpTokens.NO_CONTENT:
474:                                    _state = STATE_END;
475:                                    _handler.headerComplete();
476:                                    _handler.messageComplete(_contentPosition);
477:                                    break;
478:
479:                                default:
480:                                    _state = STATE_CONTENT;
481:
482:                                    if (_buffers != null
483:                                            && _body == null
484:                                            && _buffer == _header
485:                                            && _contentLength > (_header
486:                                                    .capacity() - _header
487:                                                    .getIndex()))
488:                                        _body = _buffers
489:                                                .getBuffer(_contentBufferSize);
490:                                    _handler.headerComplete(); // May recurse here !
491:                                    break;
492:                                }
493:                                return total_filled;
494:                            } else {
495:                                // New header
496:                                _length = 1;
497:                                _buffer.mark();
498:                                _state = STATE_HEADER_NAME;
499:
500:                                // try cached name!
501:                                if (array != null)
502:                                    _cached = HttpHeaders.CACHE.getBest(array,
503:                                            _buffer.markIndex(), length + 1);
504:                                if (_cached != null) {
505:                                    _length = _cached.length();
506:                                    _buffer.setGetIndex(_buffer.markIndex()
507:                                            + _length);
508:                                    length = _buffer.length();
509:                                }
510:                            }
511:                        }
512:                        break;
513:
514:                    case STATE_HEADER_NAME:
515:                        if (ch == HttpTokens.CARRIAGE_RETURN
516:                                || ch == HttpTokens.LINE_FEED) {
517:                            if (_length > 0)
518:                                _tok0.update(_buffer.markIndex(), _buffer
519:                                        .markIndex()
520:                                        + _length);
521:                            _eol = ch;
522:                            _state = STATE_HEADER;
523:                        } else if (ch == HttpTokens.COLON) {
524:                            if (_length > 0 && _cached == null)
525:                                _tok0.update(_buffer.markIndex(), _buffer
526:                                        .markIndex()
527:                                        + _length);
528:                            _length = -1;
529:                            _state = STATE_HEADER_VALUE;
530:                        } else if (ch != HttpTokens.SPACE
531:                                && ch != HttpTokens.TAB) {
532:                            // Drag the mark
533:                            if (_length == -1)
534:                                _buffer.mark();
535:                            _length = _buffer.getIndex() - _buffer.markIndex();
536:                        }
537:                        break;
538:
539:                    case STATE_HEADER_VALUE:
540:                        if (ch == HttpTokens.CARRIAGE_RETURN
541:                                || ch == HttpTokens.LINE_FEED) {
542:                            if (_length > 0) {
543:                                if (_tok1.length() == 0)
544:                                    _tok1.update(_buffer.markIndex(), _buffer
545:                                            .markIndex()
546:                                            + _length);
547:                                else {
548:                                    // Continuation line!
549:                                    if (_multiLineValue == null)
550:                                        _multiLineValue = _tok1.toString();
551:                                    _tok1.update(_buffer.markIndex(), _buffer
552:                                            .markIndex()
553:                                            + _length);
554:                                    _multiLineValue += " " + _tok1.toString();
555:                                }
556:                            }
557:                            _eol = ch;
558:                            _state = STATE_HEADER;
559:                        } else if (ch != HttpTokens.SPACE
560:                                && ch != HttpTokens.TAB) {
561:                            if (_length == -1)
562:                                _buffer.mark();
563:                            _length = _buffer.getIndex() - _buffer.markIndex();
564:                        }
565:                        break;
566:                    }
567:                } // end of HEADER states loop
568:
569:                // ==========================
570:
571:                // Handle _content
572:                length = _buffer.length();
573:                Buffer chunk;
574:                while (_state > STATE_END && length > 0) {
575:                    if (_eol == HttpTokens.CARRIAGE_RETURN
576:                            && _buffer.peek() == HttpTokens.LINE_FEED) {
577:                        _eol = _buffer.get();
578:                        length = _buffer.length();
579:                        continue;
580:                    }
581:                    _eol = 0;
582:                    switch (_state) {
583:                    case STATE_EOF_CONTENT:
584:                        chunk = _buffer.get(_buffer.length());
585:                        _contentPosition += chunk.length();
586:                        _contentView.update(chunk);
587:                        _handler.content(chunk);
588:                        // TODO adjust the _buffer to keep unconsumed content
589:                        return total_filled;
590:
591:                    case STATE_CONTENT: {
592:                        long remaining = _contentLength - _contentPosition;
593:                        if (remaining == 0) {
594:                            _state = STATE_END;
595:                            _handler.messageComplete(_contentPosition);
596:                            return total_filled;
597:                        } else if (length >= remaining) {
598:                            // We can cast reamining to an int as we know that it is smaller than
599:                            // or equal to length which is already an int. 
600:                            length = (int) remaining;
601:                            _state = STATE_END;
602:                        }
603:                        chunk = _buffer.get(length);
604:                        _contentPosition += chunk.length();
605:                        _contentView.update(chunk);
606:                        _handler.content(chunk);
607:                        // TODO adjust the _buffer to keep unconsumed content
608:                        return total_filled;
609:                    }
610:
611:                    case STATE_CHUNKED_CONTENT: {
612:                        ch = _buffer.peek();
613:                        if (ch == HttpTokens.CARRIAGE_RETURN
614:                                || ch == HttpTokens.LINE_FEED)
615:                            _eol = _buffer.get();
616:                        else if (ch <= HttpTokens.SPACE)
617:                            _buffer.get();
618:                        else {
619:                            _chunkLength = 0;
620:                            _chunkPosition = 0;
621:                            _state = STATE_CHUNK_SIZE;
622:                        }
623:                        break;
624:                    }
625:
626:                    case STATE_CHUNK_SIZE: {
627:                        ch = _buffer.get();
628:                        if (ch == HttpTokens.CARRIAGE_RETURN
629:                                || ch == HttpTokens.LINE_FEED) {
630:                            _eol = ch;
631:                            if (_chunkLength == 0) {
632:                                _state = STATE_END;
633:                                _handler.messageComplete(_contentPosition);
634:                                return total_filled;
635:                            } else
636:                                _state = STATE_CHUNK;
637:                        } else if (ch <= HttpTokens.SPACE
638:                                || ch == HttpTokens.SEMI_COLON)
639:                            _state = STATE_CHUNK_PARAMS;
640:                        else if (ch >= '0' && ch <= '9')
641:                            _chunkLength = _chunkLength * 16 + (ch - '0');
642:                        else if (ch >= 'a' && ch <= 'f')
643:                            _chunkLength = _chunkLength * 16 + (10 + ch - 'a');
644:                        else if (ch >= 'A' && ch <= 'F')
645:                            _chunkLength = _chunkLength * 16 + (10 + ch - 'A');
646:                        else
647:                            throw new IOException("bad chunk char: " + ch);
648:                        break;
649:                    }
650:
651:                    case STATE_CHUNK_PARAMS: {
652:                        ch = _buffer.get();
653:                        if (ch == HttpTokens.CARRIAGE_RETURN
654:                                || ch == HttpTokens.LINE_FEED) {
655:                            _eol = ch;
656:                            if (_chunkLength == 0) {
657:                                _state = STATE_END;
658:                                _handler.messageComplete(_contentPosition);
659:                                return total_filled;
660:                            } else
661:                                _state = STATE_CHUNK;
662:                        }
663:                        break;
664:                    }
665:
666:                    case STATE_CHUNK: {
667:                        int remaining = _chunkLength - _chunkPosition;
668:                        if (remaining == 0) {
669:                            _state = STATE_CHUNKED_CONTENT;
670:                            break;
671:                        } else if (length > remaining)
672:                            length = remaining;
673:                        chunk = _buffer.get(length);
674:                        _contentPosition += chunk.length();
675:                        _chunkPosition += chunk.length();
676:                        _contentView.update(chunk);
677:                        _handler.content(chunk);
678:                        // TODO adjust the _buffer to keep unconsumed content
679:                        return total_filled;
680:                    }
681:                    }
682:
683:                    length = _buffer.length();
684:                }
685:                return total_filled;
686:            }
687:
688:            /* ------------------------------------------------------------------------------- */
689:            public void reset(boolean returnBuffers) {
690:                synchronized (this ) // prevent dual reset.
691:                {
692:                    _state = STATE_START;
693:                    _contentLength = HttpTokens.UNKNOWN_CONTENT;
694:                    _contentPosition = 0;
695:                    _length = 0;
696:                    _response = false;
697:
698:                    if (_buffer != null && _buffer.length() > 0
699:                            && _eol == HttpTokens.CARRIAGE_RETURN
700:                            && _buffer.peek() == HttpTokens.LINE_FEED) {
701:                        _buffer.skip(1);
702:                        _eol = HttpTokens.LINE_FEED;
703:                    }
704:
705:                    if (_body != null) {
706:                        if (_body.hasContent()) {
707:                            _header.setMarkIndex(-1);
708:                            _header.compact();
709:                            // TODO if pipelined requests received after big input - maybe this is not good?.
710:                            _body.skip(_header.put(_body));
711:
712:                        }
713:
714:                        if (_body.length() == 0) {
715:                            if (_buffers != null && returnBuffers)
716:                                _buffers.returnBuffer(_body);
717:                            _body = null;
718:                        } else {
719:                            _body.setMarkIndex(-1);
720:                            _body.compact();
721:                        }
722:                    }
723:
724:                    if (_header != null) {
725:                        _header.setMarkIndex(-1);
726:                        if (!_header.hasContent() && _buffers != null
727:                                && returnBuffers) {
728:                            _buffers.returnBuffer(_header);
729:                            _header = null;
730:                            _buffer = null;
731:                        } else {
732:                            _header.compact();
733:                            _tok0.update(_header);
734:                            _tok0.update(0, 0);
735:                            _tok1.update(_header);
736:                            _tok1.update(0, 0);
737:                        }
738:                    }
739:
740:                    _buffer = _header;
741:                }
742:            }
743:
744:            /* ------------------------------------------------------------------------------- */
745:            public void setState(int state) {
746:                this ._state = state;
747:                _contentLength = HttpTokens.UNKNOWN_CONTENT;
748:            }
749:
750:            /* ------------------------------------------------------------------------------- */
751:            public String toString(Buffer buf) {
752:                return "state=" + _state + " length=" + _length + " buf="
753:                        + buf.hashCode();
754:            }
755:
756:            public Buffer getHeaderBuffer() {
757:                if (_header == null) {
758:                    _header = _buffers.getBuffer(_headerBufferSize);
759:                }
760:                return _header;
761:            }
762:
763:            /* ------------------------------------------------------------ */
764:            /* ------------------------------------------------------------ */
765:            /* ------------------------------------------------------------ */
766:            public static abstract class EventHandler {
767:                public abstract void content(Buffer ref) throws IOException;
768:
769:                public void headerComplete() throws IOException {
770:                }
771:
772:                public void messageComplete(long contextLength)
773:                        throws IOException {
774:                }
775:
776:                /**
777:                 * This is the method called by parser when a HTTP Header name and value is found
778:                 */
779:                public void parsedHeader(Buffer name, Buffer value)
780:                        throws IOException {
781:                }
782:
783:                /**
784:                 * This is the method called by parser when the HTTP request line is parsed
785:                 */
786:                public abstract void startRequest(Buffer method, Buffer url,
787:                        Buffer version) throws IOException;
788:
789:                /**
790:                 * This is the method called by parser when the HTTP request line is parsed
791:                 */
792:                public abstract void startResponse(Buffer version, int status,
793:                        Buffer reason) throws IOException;
794:            }
795:
796:            /* ------------------------------------------------------------ */
797:            /* ------------------------------------------------------------ */
798:            /* ------------------------------------------------------------ */
799:            public static class Input extends ServletInputStream {
800:                protected HttpParser _parser;
801:                protected EndPoint _endp;
802:                protected long _maxIdleTime;
803:                protected View _content;
804:
805:                /* ------------------------------------------------------------ */
806:                public Input(HttpParser parser, long maxIdleTime) {
807:                    _parser = parser;
808:                    _endp = parser._endp;
809:                    _maxIdleTime = maxIdleTime;
810:                    _content = _parser._contentView;
811:                }
812:
813:                /* ------------------------------------------------------------ */
814:                /*
815:                 * @see java.io.InputStream#read()
816:                 */
817:                public int read() throws IOException {
818:                    int c = -1;
819:                    if (blockForContent())
820:                        c = 0xff & _content.get();
821:                    return c;
822:                }
823:
824:                /* ------------------------------------------------------------ */
825:                /* 
826:                 * @see java.io.InputStream#read(byte[], int, int)
827:                 */
828:                public int read(byte[] b, int off, int len) throws IOException {
829:                    int l = -1;
830:                    if (blockForContent())
831:                        l = _content.get(b, off, len);
832:                    return l;
833:                }
834:
835:                /* ------------------------------------------------------------ */
836:                private boolean blockForContent() throws IOException {
837:                    if (_content.length() > 0)
838:                        return true;
839:                    if (_parser.isState(HttpParser.STATE_END))
840:                        return false;
841:
842:                    // Handle simple end points.
843:                    if (_endp == null)
844:                        _parser.parseNext();
845:
846:                    // Handle blocking end points
847:                    else if (_endp.isBlocking()) {
848:                        try {
849:                            long filled = _parser.parseNext();
850:
851:                            // parse until some progress is made (or IOException thrown for timeout)
852:                            while (_content.length() == 0 && filled != 0
853:                                    && !_parser.isState(HttpParser.STATE_END)) {
854:                                // Try to get more _parser._content
855:                                filled = _parser.parseNext();
856:                            }
857:                        } catch (IOException e) {
858:                            _endp.close();
859:                            throw e;
860:                        }
861:                    }
862:                    // Handle non-blocking end point
863:                    else {
864:                        _parser.parseNext();
865:
866:                        // parse until some progress is made (or IOException thrown for timeout)
867:                        while (_content.length() == 0
868:                                && !_parser.isState(HttpParser.STATE_END)) {
869:                            if (!_endp.blockReadable(_maxIdleTime)) {
870:                                _endp.close();
871:                                throw new EofException("timeout");
872:                            }
873:
874:                            // Try to get more _parser._content
875:                            _parser.parseNext();
876:                        }
877:                    }
878:
879:                    return _content.length() > 0;
880:                }
881:            }
882:
883:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.