1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */

17 package org.apache.coyote.http11;
18
19 import java.io.EOFException;
20 import java.io.IOException;
21 import java.nio.ByteBuffer;
22 import java.nio.charset.StandardCharsets;
23 import java.util.Arrays;
24
25 import org.apache.coyote.CloseNowException;
26 import org.apache.coyote.InputBuffer;
27 import org.apache.coyote.Request;
28 import org.apache.juli.logging.Log;
29 import org.apache.juli.logging.LogFactory;
30 import org.apache.tomcat.util.buf.MessageBytes;
31 import org.apache.tomcat.util.http.HeaderUtil;
32 import org.apache.tomcat.util.http.MimeHeaders;
33 import org.apache.tomcat.util.http.parser.HttpParser;
34 import org.apache.tomcat.util.net.ApplicationBufferHandler;
35 import org.apache.tomcat.util.net.SocketWrapperBase;
36 import org.apache.tomcat.util.res.StringManager;
37
38 /**
39  * InputBuffer for HTTP that provides request header parsing as well as transfer
40  * encoding.
41  */

42 public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler {
43
44     // -------------------------------------------------------------- Constants
45
46     private static final Log log = LogFactory.getLog(Http11InputBuffer.class);
47
48     /**
49      * The string manager for this package.
50      */

51     private static final StringManager sm = StringManager.getManager(Http11InputBuffer.class);
52
53
54     private static final byte[] CLIENT_PREFACE_START =
55             "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1);
56
57     /**
58      * Associated Coyote request.
59      */

60     private final Request request;
61
62
63     /**
64      * Headers of the associated request.
65      */

66     private final MimeHeaders headers;
67
68
69     private final boolean rejectIllegalHeader;
70
71     /**
72      * State.
73      */

74     private boolean parsingHeader;
75
76
77     /**
78      * Swallow input ? (in the case of an expectation)
79      */

80     private boolean swallowInput;
81
82
83     /**
84      * The read buffer.
85      */

86     private ByteBuffer byteBuffer;
87
88
89     /**
90      * Pos of the end of the header in the buffer, which is also the
91      * start of the body.
92      */

93     private int end;
94
95
96     /**
97      * Wrapper that provides access to the underlying socket.
98      */

99     private SocketWrapperBase<?> wrapper;
100
101
102     /**
103      * Underlying input buffer.
104      */

105     private InputBuffer inputStreamInputBuffer;
106
107
108     /**
109      * Filter library.
110      * Note: Filter[Constants.CHUNKED_FILTER] is always the "chunked" filter.
111      */

112     private InputFilter[] filterLibrary;
113
114
115     /**
116      * Active filters (in order).
117      */

118     private InputFilter[] activeFilters;
119
120
121     /**
122      * Index of the last active filter.
123      */

124     private int lastActiveFilter;
125
126
127     /**
128      * Parsing state - used for non blocking parsing so that
129      * when more data arrives, we can pick up where we left off.
130      */

131     private byte prevChr = 0;
132     private byte chr = 0;
133     private boolean parsingRequestLine;
134     private int parsingRequestLinePhase = 0;
135     private boolean parsingRequestLineEol = false;
136     private int parsingRequestLineStart = 0;
137     private int parsingRequestLineQPos = -1;
138     private HeaderParsePosition headerParsePos;
139     private final HeaderParseData headerData = new HeaderParseData();
140     private final HttpParser httpParser;
141
142     /**
143      * Maximum allowed size of the HTTP request line plus headers plus any
144      * leading blank lines.
145      */

146     private final int headerBufferSize;
147
148     /**
149      * Known size of the NioChannel read buffer.
150      */

151     private int socketReadBufferSize;
152
153
154     // ----------------------------------------------------------- Constructors
155
156     public Http11InputBuffer(Request request, int headerBufferSize,
157             boolean rejectIllegalHeader, HttpParser httpParser) {
158
159         this.request = request;
160         headers = request.getMimeHeaders();
161
162         this.headerBufferSize = headerBufferSize;
163         this.rejectIllegalHeader = rejectIllegalHeader;
164         this.httpParser = httpParser;
165
166         filterLibrary = new InputFilter[0];
167         activeFilters = new InputFilter[0];
168         lastActiveFilter = -1;
169
170         parsingHeader = true;
171         parsingRequestLine = true;
172         parsingRequestLinePhase = 0;
173         parsingRequestLineEol = false;
174         parsingRequestLineStart = 0;
175         parsingRequestLineQPos = -1;
176         headerParsePos = HeaderParsePosition.HEADER_START;
177         swallowInput = true;
178
179         inputStreamInputBuffer = new SocketInputBuffer();
180     }
181
182
183     // ------------------------------------------------------------- Properties
184
185     /**
186      * Add an input filter to the filter library.
187      *
188      * @throws NullPointerException if the supplied filter is null
189      */

190     void addFilter(InputFilter filter) {
191
192         if (filter == null) {
193             throw new NullPointerException(sm.getString("iib.filter.npe"));
194         }
195
196         InputFilter[] newFilterLibrary = Arrays.copyOf(filterLibrary, filterLibrary.length + 1);
197         newFilterLibrary[filterLibrary.length] = filter;
198         filterLibrary = newFilterLibrary;
199
200         activeFilters = new InputFilter[filterLibrary.length];
201     }
202
203
204     /**
205      * Get filters.
206      */

207     InputFilter[] getFilters() {
208         return filterLibrary;
209     }
210
211
212     /**
213      * Add an input filter to the filter library.
214      */

215     void addActiveFilter(InputFilter filter) {
216
217         if (lastActiveFilter == -1) {
218             filter.setBuffer(inputStreamInputBuffer);
219         } else {
220             for (int i = 0; i <= lastActiveFilter; i++) {
221                 if (activeFilters[i] == filter)
222                     return;
223             }
224             filter.setBuffer(activeFilters[lastActiveFilter]);
225         }
226
227         activeFilters[++lastActiveFilter] = filter;
228
229         filter.setRequest(request);
230     }
231
232
233     /**
234      * Set the swallow input flag.
235      */

236     void setSwallowInput(boolean swallowInput) {
237         this.swallowInput = swallowInput;
238     }
239
240
241     // ---------------------------------------------------- InputBuffer Methods
242
243     @Override
244     public int doRead(ApplicationBufferHandler handler) throws IOException {
245
246         if (lastActiveFilter == -1)
247             return inputStreamInputBuffer.doRead(handler);
248         else
249             return activeFilters[lastActiveFilter].doRead(handler);
250
251     }
252
253
254     // ------------------------------------------------------- Protected Methods
255
256     /**
257      * Recycle the input buffer. This should be called when closing the
258      * connection.
259      */

260     void recycle() {
261         wrapper = null;
262         request.recycle();
263
264         for (int i = 0; i <= lastActiveFilter; i++) {
265             activeFilters[i].recycle();
266         }
267
268         byteBuffer.limit(0).position(0);
269         lastActiveFilter = -1;
270         parsingHeader = true;
271         swallowInput = true;
272
273         chr = 0;
274         prevChr = 0;
275         headerParsePos = HeaderParsePosition.HEADER_START;
276         parsingRequestLine = true;
277         parsingRequestLinePhase = 0;
278         parsingRequestLineEol = false;
279         parsingRequestLineStart = 0;
280         parsingRequestLineQPos = -1;
281         headerData.recycle();
282     }
283
284
285     /**
286      * End processing of current HTTP request.
287      * Note: All bytes of the current request should have been already
288      * consumed. This method only resets all the pointers so that we are ready
289      * to parse the next HTTP request.
290      */

291     void nextRequest() {
292         request.recycle();
293
294         if (byteBuffer.position() > 0) {
295             if (byteBuffer.remaining() > 0) {
296                 // Copy leftover bytes to the beginning of the buffer
297                 byteBuffer.compact();
298                 byteBuffer.flip();
299             } else {
300                 // Reset position and limit to 0
301                 byteBuffer.position(0).limit(0);
302             }
303         }
304
305         // Recycle filters
306         for (int i = 0; i <= lastActiveFilter; i++) {
307             activeFilters[i].recycle();
308         }
309
310         // Reset pointers
311         lastActiveFilter = -1;
312         parsingHeader = true;
313         swallowInput = true;
314
315         headerParsePos = HeaderParsePosition.HEADER_START;
316         parsingRequestLine = true;
317         parsingRequestLinePhase = 0;
318         parsingRequestLineEol = false;
319         parsingRequestLineStart = 0;
320         parsingRequestLineQPos = -1;
321         headerData.recycle();
322     }
323
324
325     /**
326      * Read the request line. This function is meant to be used during the
327      * HTTP request header parsing. Do NOT attempt to read the request body
328      * using it.
329      *
330      * @throws IOException If an exception occurs during the underlying socket
331      * read operations, or if the given buffer is not big enough to accommodate
332      * the whole line.
333      *
334      * @return true if data is properly fed; false if no data is available
335      * immediately and thread should be freed
336      */

337     boolean parseRequestLine(boolean keptAlive, int connectionTimeout, int keepAliveTimeout)
338             throws IOException {
339
340         // check state
341         if (!parsingRequestLine) {
342             return true;
343         }
344         //
345         // Skipping blank lines
346         //
347         if (parsingRequestLinePhase < 2) {
348             do {
349                 // Read new bytes if needed
350                 if (byteBuffer.position() >= byteBuffer.limit()) {
351                     if (keptAlive) {
352                         // Haven't read any request data yet so use the keep-alive
353                         // timeout.
354                         wrapper.setReadTimeout(keepAliveTimeout);
355                     }
356                     if (!fill(false)) {
357                         // A read is pending, so no longer in initial state
358                         parsingRequestLinePhase = 1;
359                         return false;
360                     }
361                     // At least one byte of the request has been received.
362                     // Switch to the socket timeout.
363                     wrapper.setReadTimeout(connectionTimeout);
364                 }
365                 if (!keptAlive && byteBuffer.position() == 0 && byteBuffer.limit() >= CLIENT_PREFACE_START.length - 1) {
366                     boolean prefaceMatch = true;
367                     for (int i = 0; i < CLIENT_PREFACE_START.length && prefaceMatch; i++) {
368                         if (CLIENT_PREFACE_START[i] != byteBuffer.get(i)) {
369                             prefaceMatch = false;
370                         }
371                     }
372                     if (prefaceMatch) {
373                         // HTTP/2 preface matched
374                         parsingRequestLinePhase = -1;
375                         return false;
376                     }
377                 }
378                 // Set the start time once we start reading data (even if it is
379                 // just skipping blank lines)
380                 if (request.getStartTime() < 0) {
381                     request.setStartTime(System.currentTimeMillis());
382                 }
383                 chr = byteBuffer.get();
384             } while ((chr == Constants.CR) || (chr == Constants.LF));
385             byteBuffer.position(byteBuffer.position() - 1);
386
387             parsingRequestLineStart = byteBuffer.position();
388             parsingRequestLinePhase = 2;
389             if (log.isDebugEnabled()) {
390                 log.debug("Received ["
391                         + new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining(), StandardCharsets.ISO_8859_1) + "]");
392             }
393         }
394         if (parsingRequestLinePhase == 2) {
395             //
396             // Reading the method name
397             // Method name is a token
398             //
399             boolean space = false;
400             while (!space) {
401                 // Read new bytes if needed
402                 if (byteBuffer.position() >= byteBuffer.limit()) {
403                     if (!fill(false)) // request line parsing
404                         return false;
405                 }
406                 // Spec says method name is a token followed by a single SP but
407                 // also be tolerant of multiple SP and/or HT.
408                 int pos = byteBuffer.position();
409                 chr = byteBuffer.get();
410                 if (chr == Constants.SP || chr == Constants.HT) {
411                     space = true;
412                     request.method().setBytes(byteBuffer.array(), parsingRequestLineStart,
413                             pos - parsingRequestLineStart);
414                 } else if (!HttpParser.isToken(chr)) {
415                     byteBuffer.position(byteBuffer.position() - 1);
416                     // Avoid unknown protocol triggering an additional error
417                     request.protocol().setString(Constants.HTTP_11);
418                     throw new IllegalArgumentException(sm.getString("iib.invalidmethod"));
419                 }
420             }
421             parsingRequestLinePhase = 3;
422         }
423         if (parsingRequestLinePhase == 3) {
424             // Spec says single SP but also be tolerant of multiple SP and/or HT
425             boolean space = true;
426             while (space) {
427                 // Read new bytes if needed
428                 if (byteBuffer.position() >= byteBuffer.limit()) {
429                     if (!fill(false)) // request line parsing
430                         return false;
431                 }
432                 chr = byteBuffer.get();
433                 if (!(chr == Constants.SP || chr == Constants.HT)) {
434                     space = false;
435                     byteBuffer.position(byteBuffer.position() - 1);
436                 }
437             }
438             parsingRequestLineStart = byteBuffer.position();
439             parsingRequestLinePhase = 4;
440         }
441         if (parsingRequestLinePhase == 4) {
442             // Mark the current buffer position
443
444             int end = 0;
445             //
446             // Reading the URI
447             //
448             boolean space = false;
449             while (!space) {
450                 // Read new bytes if needed
451                 if (byteBuffer.position() >= byteBuffer.limit()) {
452                     if (!fill(false)) // request line parsing
453                         return false;
454                 }
455                 int pos = byteBuffer.position();
456                 prevChr = chr;
457                 chr = byteBuffer.get();
458                 if (prevChr == Constants.CR && chr != Constants.LF) {
459                     // CR not followed by LF so not an HTTP/0.9 request and
460                     // therefore invalid. Trigger error handling.
461                     // Avoid unknown protocol triggering an additional error
462                     request.protocol().setString(Constants.HTTP_11);
463                     throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget"));
464                 }
465                 if (chr == Constants.SP || chr == Constants.HT) {
466                     space = true;
467                     end = pos;
468                 } else if (chr == Constants.CR) {
469                     // HTTP/0.9 style request. CR is optional. LF is not.
470                 } else if (chr == Constants.LF) {
471                     // HTTP/0.9 style request
472                     // Stop this processing loop
473                     space = true;
474                     // Skip the protocol processing
475                     parsingRequestLinePhase = 6;
476                     parsingRequestLineEol = true;
477                     if (prevChr == Constants.CR) {
478                         end = pos - 1;
479                     } else {
480                         end = pos;
481                     }
482                 } else if (chr == Constants.QUESTION && parsingRequestLineQPos == -1) {
483                     parsingRequestLineQPos = pos;
484                 } else if (parsingRequestLineQPos != -1 && !httpParser.isQueryRelaxed(chr)) {
485                     // Avoid unknown protocol triggering an additional error
486                     request.protocol().setString(Constants.HTTP_11);
487                     // %nn decoding will be checked at the point of decoding
488                     throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget"));
489                 } else if (httpParser.isNotRequestTargetRelaxed(chr)) {
490                     // Avoid unknown protocol triggering an additional error
491                     request.protocol().setString(Constants.HTTP_11);
492                     // This is a general check that aims to catch problems early
493                     // Detailed checking of each part of the request target will
494                     // happen in Http11Processor#prepareRequest()
495                     throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget"));
496                 }
497             }
498             if (parsingRequestLineQPos >= 0) {
499                 request.queryString().setBytes(byteBuffer.array(), parsingRequestLineQPos + 1,
500                         end - parsingRequestLineQPos - 1);
501                 request.requestURI().setBytes(byteBuffer.array(), parsingRequestLineStart,
502                         parsingRequestLineQPos - parsingRequestLineStart);
503             } else {
504                 request.requestURI().setBytes(byteBuffer.array(), parsingRequestLineStart,
505                         end - parsingRequestLineStart);
506             }
507             if (!parsingRequestLineEol) {
508                 parsingRequestLinePhase = 5;
509             }
510         }
511         if (parsingRequestLinePhase == 5) {
512             // Spec says single SP but also be tolerant of multiple and/or HT
513             boolean space = true;
514             while (space) {
515                 // Read new bytes if needed
516                 if (byteBuffer.position() >= byteBuffer.limit()) {
517                     if (!fill(false)) // request line parsing
518                         return false;
519                 }
520                 byte chr = byteBuffer.get();
521                 if (!(chr == Constants.SP || chr == Constants.HT)) {
522                     space = false;
523                     byteBuffer.position(byteBuffer.position() - 1);
524                 }
525             }
526             parsingRequestLineStart = byteBuffer.position();
527             parsingRequestLinePhase = 6;
528
529             // Mark the current buffer position
530             end = 0;
531         }
532         if (parsingRequestLinePhase == 6) {
533             //
534             // Reading the protocol
535             // Protocol is always "HTTP/" DIGIT "." DIGIT
536             //
537             while (!parsingRequestLineEol) {
538                 // Read new bytes if needed
539                 if (byteBuffer.position() >= byteBuffer.limit()) {
540                     if (!fill(false)) // request line parsing
541                         return false;
542                 }
543
544                 int pos = byteBuffer.position();
545                 prevChr = chr;
546                 chr = byteBuffer.get();
547                 if (chr == Constants.CR) {
548                     // Possible end of request line. Need LF next.
549                 } else if (prevChr == Constants.CR && chr == Constants.LF) {
550                     end = pos - 1;
551                     parsingRequestLineEol = true;
552                 } else if (!HttpParser.isHttpProtocol(chr)) {
553                     throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol"));
554                 }
555             }
556
557             if ((end - parsingRequestLineStart) > 0) {
558                 request.protocol().setBytes(byteBuffer.array(), parsingRequestLineStart,
559                         end - parsingRequestLineStart);
560             } else {
561                 request.protocol().setString("");
562             }
563             parsingRequestLine = false;
564             parsingRequestLinePhase = 0;
565             parsingRequestLineEol = false;
566             parsingRequestLineStart = 0;
567             return true;
568         }
569         throw new IllegalStateException(sm.getString("iib.invalidPhase", Integer.valueOf(parsingRequestLinePhase)));
570     }
571
572
573     /**
574      * Parse the HTTP headers.
575      */

576     boolean parseHeaders() throws IOException {
577         if (!parsingHeader) {
578             throw new IllegalStateException(sm.getString("iib.parseheaders.ise.error"));
579         }
580
581         HeaderParseStatus status = HeaderParseStatus.HAVE_MORE_HEADERS;
582
583         do {
584             status = parseHeader();
585             // Checking that
586             // (1) Headers plus request line size does not exceed its limit
587             // (2) There are enough bytes to avoid expanding the buffer when
588             // reading body
589             // Technically, (2) is technical limitation, (1) is logical
590             // limitation to enforce the meaning of headerBufferSize
591             // From the way how buf is allocated and how blank lines are being
592             // read, it should be enough to check (1) only.
593             if (byteBuffer.position() > headerBufferSize || byteBuffer.capacity() - byteBuffer.position() < socketReadBufferSize) {
594                 throw new IllegalArgumentException(sm.getString("iib.requestheadertoolarge.error"));
595             }
596         } while (status == HeaderParseStatus.HAVE_MORE_HEADERS);
597         if (status == HeaderParseStatus.DONE) {
598             parsingHeader = false;
599             end = byteBuffer.position();
600             return true;
601         } else {
602             return false;
603         }
604     }
605
606
607     int getParsingRequestLinePhase() {
608         return parsingRequestLinePhase;
609     }
610
611
612     /**
613      * End request (consumes leftover bytes).
614      *
615      * @throws IOException an underlying I/O error occurred
616      */

617     void endRequest() throws IOException {
618
619         if (swallowInput && (lastActiveFilter != -1)) {
620             int extraBytes = (int) activeFilters[lastActiveFilter].end();
621             byteBuffer.position(byteBuffer.position() - extraBytes);
622         }
623     }
624
625
626     /**
627      * Available bytes in the buffers (note that due to encoding, this may not
628      * correspond).
629      */

630     int available(boolean read) {
631         int available = byteBuffer.remaining();
632         if ((available == 0) && (lastActiveFilter >= 0)) {
633             for (int i = 0; (available == 0) && (i <= lastActiveFilter); i++) {
634                 available = activeFilters[i].available();
635             }
636         }
637         if (available > 0 || !read) {
638             return available;
639         }
640
641         try {
642             if (wrapper.hasDataToRead()) {
643                 fill(false);
644                 available = byteBuffer.remaining();
645             }
646         } catch (IOException ioe) {
647             if (log.isDebugEnabled()) {
648                 log.debug(sm.getString("iib.available.readFail"), ioe);
649             }
650             // Not ideal. This will indicate that data is available which should
651             // trigger a read which in turn will trigger another IOException and
652             // that one can be thrown.
653             available = 1;
654         }
655         return available;
656     }
657
658
659     /**
660      * Has all of the request body been read? There are subtle differences
661      * between this and available() &gt; 0 primarily because of having to handle
662      * faking non-blocking reads with the blocking IO connector.
663      */

664     boolean isFinished() {
665         if (byteBuffer.limit() > byteBuffer.position()) {
666             // Data to read in the buffer so not finished
667             return false;
668         }
669
670         /*
671          * Don't use fill(false) here because in the following circumstances
672          * BIO will block - possibly indefinitely
673          * - client is using keep-alive and connection is still open
674          * - client has sent the complete request
675          * - client has not sent any of the next request (i.e. no pipelining)
676          * - application has read the complete request
677          */

678
679         // Check the InputFilters
680
681         if (lastActiveFilter >= 0) {
682             return activeFilters[lastActiveFilter].isFinished();
683         } else {
684             // No filters. Assume request is not finished. EOF will signal end of
685             // request.
686             return false;
687         }
688     }
689
690     ByteBuffer getLeftover() {
691         int available = byteBuffer.remaining();
692         if (available > 0) {
693             return ByteBuffer.wrap(byteBuffer.array(), byteBuffer.position(), available);
694         } else {
695             return null;
696         }
697     }
698
699
700     boolean isChunking() {
701         for (int i = 0; i < lastActiveFilter; i++) {
702             if (activeFilters[i] == filterLibrary[Constants.CHUNKED_FILTER]) {
703                 return true;
704             }
705         }
706         return false;
707     }
708
709
710     void init(SocketWrapperBase<?> socketWrapper) {
711
712         wrapper = socketWrapper;
713         wrapper.setAppReadBufHandler(this);
714
715         int bufLength = headerBufferSize +
716                 wrapper.getSocketBufferHandler().getReadBuffer().capacity();
717         if (byteBuffer == null || byteBuffer.capacity() < bufLength) {
718             byteBuffer = ByteBuffer.allocate(bufLength);
719             byteBuffer.position(0).limit(0);
720         }
721     }
722
723
724
725     // --------------------------------------------------------- Private Methods
726
727     /**
728      * Attempts to read some data into the input buffer.
729      *
730      * @return <code>true</code> if more data was added to the input buffer
731      *         otherwise <code>false</code>
732      */

733     private boolean fill(boolean block) throws IOException {
734
735         if (parsingHeader) {
736             if (byteBuffer.limit() >= headerBufferSize) {
737                 if (parsingRequestLine) {
738                     // Avoid unknown protocol triggering an additional error
739                     request.protocol().setString(Constants.HTTP_11);
740                 }
741                 throw new IllegalArgumentException(sm.getString("iib.requestheadertoolarge.error"));
742             }
743         } else {
744             byteBuffer.limit(end).position(end);
745         }
746
747         byteBuffer.mark();
748         if (byteBuffer.position() < byteBuffer.limit()) {
749             byteBuffer.position(byteBuffer.limit());
750         }
751         byteBuffer.limit(byteBuffer.capacity());
752         SocketWrapperBase<?> socketWrapper = this.wrapper;
753         int nRead = -1;
754         if (socketWrapper != null) {
755             nRead = socketWrapper.read(block, byteBuffer);
756         } else {
757             throw new CloseNowException(sm.getString("iib.eof.error"));
758         }
759         byteBuffer.limit(byteBuffer.position()).reset();
760         if (nRead > 0) {
761             return true;
762         } else if (nRead == -1) {
763             throw new EOFException(sm.getString("iib.eof.error"));
764         } else {
765             return false;
766         }
767
768     }
769
770
771     /**
772      * Parse an HTTP header.
773      *
774      * @return false after reading a blank line (which indicates that the
775      * HTTP header parsing is done
776      */

777     private HeaderParseStatus parseHeader() throws IOException {
778
779         while (headerParsePos == HeaderParsePosition.HEADER_START) {
780
781             // Read new bytes if needed
782             if (byteBuffer.position() >= byteBuffer.limit()) {
783                 if (!fill(false)) {// parse header
784                     headerParsePos = HeaderParsePosition.HEADER_START;
785                     return HeaderParseStatus.NEED_MORE_DATA;
786                 }
787             }
788
789             prevChr = chr;
790             chr = byteBuffer.get();
791
792             if (chr == Constants.CR && prevChr != Constants.CR) {
793                 // Possible start of CRLF - process the next byte.
794             } else if (prevChr == Constants.CR && chr == Constants.LF) {
795                 return HeaderParseStatus.DONE;
796             } else {
797                 if (prevChr == Constants.CR) {
798                     // Must have read two bytes (first was CR, second was not LF)
799                     byteBuffer.position(byteBuffer.position() - 2);
800                 } else {
801                     // Must have only read one byte
802                     byteBuffer.position(byteBuffer.position() - 1);
803                 }
804                 break;
805             }
806         }
807
808         if (headerParsePos == HeaderParsePosition.HEADER_START) {
809             // Mark the current buffer position
810             headerData.start = byteBuffer.position();
811             headerData.lineStart = headerData.start;
812             headerParsePos = HeaderParsePosition.HEADER_NAME;
813         }
814
815         //
816         // Reading the header name
817         // Header name is always US-ASCII
818         //
819
820         while (headerParsePos == HeaderParsePosition.HEADER_NAME) {
821
822             // Read new bytes if needed
823             if (byteBuffer.position() >= byteBuffer.limit()) {
824                 if (!fill(false)) { // parse header
825                     return HeaderParseStatus.NEED_MORE_DATA;
826                 }
827             }
828
829             int pos = byteBuffer.position();
830             chr = byteBuffer.get();
831             if (chr == Constants.COLON) {
832                 headerParsePos = HeaderParsePosition.HEADER_VALUE_START;
833                 headerData.headerValue = headers.addValue(byteBuffer.array(), headerData.start,
834                         pos - headerData.start);
835                 pos = byteBuffer.position();
836                 // Mark the current buffer position
837                 headerData.start = pos;
838                 headerData.realPos = pos;
839                 headerData.lastSignificantChar = pos;
840                 break;
841             } else if (!HttpParser.isToken(chr)) {
842                 // Non-token characters are illegal in header names
843                 // Parsing continues so the error can be reported in context
844                 headerData.lastSignificantChar = pos;
845                 byteBuffer.position(byteBuffer.position() - 1);
846                 // skipLine() will handle the error
847                 return skipLine();
848             }
849
850             // chr is next byte of header name. Convert to lowercase.
851             if ((chr >= Constants.A) && (chr <= Constants.Z)) {
852                 byteBuffer.put(pos, (byte) (chr - Constants.LC_OFFSET));
853             }
854         }
855
856         // Skip the line and ignore the header
857         if (headerParsePos == HeaderParsePosition.HEADER_SKIPLINE) {
858             return skipLine();
859         }
860
861         //
862         // Reading the header value (which can be spanned over multiple lines)
863         //
864
865         while (headerParsePos == HeaderParsePosition.HEADER_VALUE_START ||
866                headerParsePos == HeaderParsePosition.HEADER_VALUE ||
867                headerParsePos == HeaderParsePosition.HEADER_MULTI_LINE) {
868
869             if (headerParsePos == HeaderParsePosition.HEADER_VALUE_START) {
870                 // Skipping spaces
871                 while (true) {
872                     // Read new bytes if needed
873                     if (byteBuffer.position() >= byteBuffer.limit()) {
874                         if (!fill(false)) {// parse header
875                             // HEADER_VALUE_START
876                             return HeaderParseStatus.NEED_MORE_DATA;
877                         }
878                     }
879
880                     chr = byteBuffer.get();
881                     if (!(chr == Constants.SP || chr == Constants.HT)) {
882                         headerParsePos = HeaderParsePosition.HEADER_VALUE;
883                         byteBuffer.position(byteBuffer.position() - 1);
884                         break;
885                     }
886                 }
887             }
888             if (headerParsePos == HeaderParsePosition.HEADER_VALUE) {
889
890                 // Reading bytes until the end of the line
891                 boolean eol = false;
892                 while (!eol) {
893
894                     // Read new bytes if needed
895                     if (byteBuffer.position() >= byteBuffer.limit()) {
896                         if (!fill(false)) {// parse header
897                             // HEADER_VALUE
898                             return HeaderParseStatus.NEED_MORE_DATA;
899                         }
900                     }
901
902                     prevChr = chr;
903                     chr = byteBuffer.get();
904                     if (chr == Constants.CR) {
905                         // Possible start of CRLF - process the next byte.
906                     } else if (prevChr == Constants.CR && chr == Constants.LF) {
907                         eol = true;
908                     } else if (prevChr == Constants.CR) {
909                         // Invalid value
910                         // Delete the header (it will be the most recent one)
911                         headers.removeHeader(headers.size() - 1);
912                         return skipLine();
913                     } else if (chr != Constants.HT && HttpParser.isControl(chr)) {
914                         // Invalid value
915                         // Delete the header (it will be the most recent one)
916                         headers.removeHeader(headers.size() - 1);
917                         return skipLine();
918                     } else if (chr == Constants.SP || chr == Constants.HT) {
919                         byteBuffer.put(headerData.realPos, chr);
920                         headerData.realPos++;
921                     } else {
922                         byteBuffer.put(headerData.realPos, chr);
923                         headerData.realPos++;
924                         headerData.lastSignificantChar = headerData.realPos;
925                     }
926                 }
927
928                 // Ignore whitespaces at the end of the line
929                 headerData.realPos = headerData.lastSignificantChar;
930
931                 // Checking the first character of the new line. If the character
932                 // is a LWS, then it's a multiline header
933                 headerParsePos = HeaderParsePosition.HEADER_MULTI_LINE;
934             }
935             // Read new bytes if needed
936             if (byteBuffer.position() >= byteBuffer.limit()) {
937                 if (!fill(false)) {// parse header
938                     // HEADER_MULTI_LINE
939                     return HeaderParseStatus.NEED_MORE_DATA;
940                 }
941             }
942
943             byte peek = byteBuffer.get(byteBuffer.position());
944             if (headerParsePos == HeaderParsePosition.HEADER_MULTI_LINE) {
945                 if ((peek != Constants.SP) && (peek != Constants.HT)) {
946                     headerParsePos = HeaderParsePosition.HEADER_START;
947                     break;
948                 } else {
949                     // Copying one extra space in the buffer (since there must
950                     // be at least one space inserted between the lines)
951                     byteBuffer.put(headerData.realPos, peek);
952                     headerData.realPos++;
953                     headerParsePos = HeaderParsePosition.HEADER_VALUE_START;
954                 }
955             }
956         }
957         // Set the header value
958         headerData.headerValue.setBytes(byteBuffer.array(), headerData.start,
959                 headerData.lastSignificantChar - headerData.start);
960         headerData.recycle();
961         return HeaderParseStatus.HAVE_MORE_HEADERS;
962     }
963
964
965     private HeaderParseStatus skipLine() throws IOException {
966         headerParsePos = HeaderParsePosition.HEADER_SKIPLINE;
967         boolean eol = false;
968
969         // Reading bytes until the end of the line
970         while (!eol) {
971
972             // Read new bytes if needed
973             if (byteBuffer.position() >= byteBuffer.limit()) {
974                 if (!fill(false)) {
975                     return HeaderParseStatus.NEED_MORE_DATA;
976                 }
977             }
978
979             int pos = byteBuffer.position();
980             prevChr = chr;
981             chr = byteBuffer.get();
982             if (chr == Constants.CR) {
983                 // Skip
984             } else if (prevChr == Constants.CR && chr == Constants.LF) {
985                 eol = true;
986             } else {
987                 headerData.lastSignificantChar = pos;
988             }
989         }
990         if (rejectIllegalHeader || log.isDebugEnabled()) {
991             String message = sm.getString("iib.invalidheader",
992                     HeaderUtil.toPrintableString(byteBuffer.array(), headerData.lineStart,
993                             headerData.lastSignificantChar - headerData.lineStart + 1));
994             if (rejectIllegalHeader) {
995                 throw new IllegalArgumentException(message);
996             }
997             log.debug(message);
998         }
999
1000         headerParsePos = HeaderParsePosition.HEADER_START;
1001         return HeaderParseStatus.HAVE_MORE_HEADERS;
1002     }
1003
1004
1005     // ----------------------------------------------------------- Inner classes
1006
1007     private enum HeaderParseStatus {
1008         DONE, HAVE_MORE_HEADERS, NEED_MORE_DATA
1009     }
1010
1011
1012     private enum HeaderParsePosition {
1013         /**
1014          * Start of a new header. A CRLF here means that there are no more
1015          * headers. Any other character starts a header name.
1016          */

1017         HEADER_START,
1018         /**
1019          * Reading a header name. All characters of header are HTTP_TOKEN_CHAR.
1020          * Header name is followed by ':'. No whitespace is allowed.<br>
1021          * Any non-HTTP_TOKEN_CHAR (this includes any whitespace) encountered
1022          * before ':' will result in the whole line being ignored.
1023          */

1024         HEADER_NAME,
1025         /**
1026          * Skipping whitespace before text of header value starts, either on the
1027          * first line of header value (just after ':') or on subsequent lines
1028          * when it is known that subsequent line starts with SP or HT.
1029          */

1030         HEADER_VALUE_START,
1031         /**
1032          * Reading the header value. We are inside the value. Either on the
1033          * first line or on any subsequent line. We come into this state from
1034          * HEADER_VALUE_START after the first non-SP/non-HT byte is encountered
1035          * on the line.
1036          */

1037         HEADER_VALUE,
1038         /**
1039          * Before reading a new line of a header. Once the next byte is peeked,
1040          * the state changes without advancing our position. The state becomes
1041          * either HEADER_VALUE_START (if that first byte is SP or HT), or
1042          * HEADER_START (otherwise).
1043          */

1044         HEADER_MULTI_LINE,
1045         /**
1046          * Reading all bytes until the next CRLF. The line is being ignored.
1047          */

1048         HEADER_SKIPLINE
1049     }
1050
1051
1052     private static class HeaderParseData {
1053         /**
1054          * The first character of the header line.
1055          */

1056         int lineStart = 0;
1057         /**
1058          * When parsing header name: first character of the header.<br>
1059          * When skipping broken header line: first character of the header.<br>
1060          * When parsing header value: first character after ':'.
1061          */

1062         int start = 0;
1063         /**
1064          * When parsing header name: not used (stays as 0).<br>
1065          * When skipping broken header line: not used (stays as 0).<br>
1066          * When parsing header value: starts as the first character after ':'.
1067          * Then is increased as far as more bytes of the header are harvested.
1068          * Bytes from buf[pos] are copied to buf[realPos]. Thus the string from
1069          * [start] to [realPos-1] is the prepared value of the header, with
1070          * whitespaces removed as needed.<br>
1071          */

1072         int realPos = 0;
1073         /**
1074          * When parsing header name: not used (stays as 0).<br>
1075          * When skipping broken header line: last non-CR/non-LF character.<br>
1076          * When parsing header value: position after the last not-LWS character.<br>
1077          */

1078         int lastSignificantChar = 0;
1079         /**
1080          * MB that will store the value of the header. It is null while parsing
1081          * header name and is created after the name has been parsed.
1082          */

1083         MessageBytes headerValue = null;
1084         public void recycle() {
1085             lineStart = 0;
1086             start = 0;
1087             realPos = 0;
1088             lastSignificantChar = 0;
1089             headerValue = null;
1090         }
1091     }
1092
1093
1094     // ------------------------------------- InputStreamInputBuffer Inner Class
1095
1096     /**
1097      * This class is an input buffer which will read its data from an input
1098      * stream.
1099      */

1100     private class SocketInputBuffer implements InputBuffer {
1101
1102         @Override
1103         public int doRead(ApplicationBufferHandler handler) throws IOException {
1104
1105             if (byteBuffer.position() >= byteBuffer.limit()) {
1106                 // The application is reading the HTTP request body which is
1107                 // always a blocking operation.
1108                 if (!fill(true))
1109                     return -1;
1110             }
1111
1112             int length = byteBuffer.remaining();
1113             handler.setByteBuffer(byteBuffer.duplicate());
1114             byteBuffer.position(byteBuffer.limit());
1115
1116             return length;
1117         }
1118     }
1119
1120
1121     @Override
1122     public void setByteBuffer(ByteBuffer buffer) {
1123         byteBuffer = buffer;
1124     }
1125
1126
1127     @Override
1128     public ByteBuffer getByteBuffer() {
1129         return byteBuffer;
1130     }
1131
1132
1133     @Override
1134     public void expand(int size) {
1135         if (byteBuffer.capacity() >= size) {
1136             byteBuffer.limit(size);
1137         }
1138         ByteBuffer temp = ByteBuffer.allocate(size);
1139         temp.put(byteBuffer);
1140         byteBuffer = temp;
1141         byteBuffer.mark();
1142         temp = null;
1143     }
1144 }
1145