Index: module-main/src/test/java/org/apache/http/impl/io/TestMessageParser.java =================================================================== --- module-main/src/test/java/org/apache/http/impl/io/TestMessageParser.java (revision 568813) +++ module-main/src/test/java/org/apache/http/impl/io/TestMessageParser.java (working copy) @@ -67,7 +67,7 @@ public void testInvalidInput() throws Exception { try { - AbstractMessageParser.parseHeaders(null); + AbstractMessageParser.parseHeaders(null, -1, -1); fail("IllegalArgumentException should have been thrown"); } catch (IllegalArgumentException ex) { // expected @@ -90,7 +90,7 @@ " \r\n" + "\r\n"; SessionInputBuffer receiver = new SessionInputBufferMockup(s, "US-ASCII"); - Header[] headers = AbstractMessageParser.parseHeaders(receiver); + Header[] headers = AbstractMessageParser.parseHeaders(receiver,-1,-1); assertNotNull(headers); assertEquals(3, headers.length); assertEquals("header1", headers[0].getName()); @@ -113,7 +113,7 @@ "header1 : stuff; param1 = value1; param2 = \"value 2\" \r\n" + "\r\n"; SessionInputBuffer receiver = new SessionInputBufferMockup(s, "US-ASCII"); - Header[] headers = AbstractMessageParser.parseHeaders(receiver); + Header[] headers = AbstractMessageParser.parseHeaders(receiver,-1,-1); assertNotNull(headers); assertEquals(1, headers.length); assertEquals("header1 : stuff; param1 = value1; param2 = \"value 2\" ", headers[0].toString()); @@ -137,7 +137,7 @@ "\r\n"; SessionInputBuffer receiver = new SessionInputBufferMockup(s, "US-ASCII"); try { - AbstractMessageParser.parseHeaders(receiver); + AbstractMessageParser.parseHeaders(receiver, -1, -1); fail("ProtocolException should have been thrown"); } catch (ProtocolException ex) { // expected @@ -147,7 +147,7 @@ "\r\n"; receiver = new SessionInputBufferMockup(s, "US-ASCII"); try { - AbstractMessageParser.parseHeaders(receiver); + AbstractMessageParser.parseHeaders(receiver, -1, -1); fail("ProtocolException should have been thrown"); } catch (ProtocolException ex) { // expected @@ -159,7 +159,7 @@ " header1: stuff\r\n" + "header2 : stuff \r\n"; SessionInputBuffer receiver = new SessionInputBufferMockup(s, "US-ASCII"); - Header[] headers = AbstractMessageParser.parseHeaders(receiver); + Header[] headers = AbstractMessageParser.parseHeaders(receiver,-1,-1); assertNotNull(headers); assertEquals(2, headers.length); assertEquals("header1", headers[0].getName()); @@ -171,7 +171,7 @@ public void testEmptyDataStream() throws Exception { String s = ""; SessionInputBuffer receiver = new SessionInputBufferMockup(s, "US-ASCII"); - Header[] headers = AbstractMessageParser.parseHeaders(receiver); + Header[] headers = AbstractMessageParser.parseHeaders(receiver,-1,-1); assertNotNull(headers); assertEquals(0, headers.length); } @@ -185,8 +185,8 @@ SessionInputBuffer receiver = new SessionInputBufferMockup(s, "US-ASCII"); try { AbstractMessageParser.parseHeaders(receiver, 2, -1); - fail("IOException should have been thrown"); - } catch (IOException ex) { + fail("exception should have been thrown"); + } catch (ProtocolException ex) { // expected } } @@ -200,8 +200,8 @@ SessionInputBuffer receiver = new SessionInputBufferMockup(s, "US-ASCII"); try { AbstractMessageParser.parseHeaders(receiver, 2, 15); - fail("IOException should have been thrown"); - } catch (IOException ex) { + fail("exception should have been thrown"); + } catch (ProtocolException ex) { // expected } } Index: module-main/src/main/java/org/apache/http/message/LineParser.java =================================================================== --- module-main/src/main/java/org/apache/http/message/LineParser.java (revision 568813) +++ module-main/src/main/java/org/apache/http/message/LineParser.java (working copy) @@ -127,4 +127,15 @@ ; + /** + * Creates a stateful header section parser. + * The returned parser will call back to {@link #parseHeader} + * in this parser for parsing the header lines. + * It still has to be initialized before use. + * + * @return a new parser for header sections + */ + HeaderSectionParser createHeaderSectionParser() + ; + } Index: module-main/src/main/java/org/apache/http/message/BasicLineParser.java =================================================================== --- module-main/src/main/java/org/apache/http/message/BasicLineParser.java (revision 568813) +++ module-main/src/main/java/org/apache/http/message/BasicLineParser.java (working copy) @@ -421,4 +421,11 @@ } + + // non-javadoc, see interface LineParser + public HeaderSectionParser createHeaderSectionParser() { + return new BasicHeaderSectionParser(this); + } + + } // class BasicLineParser Index: module-main/src/main/java/org/apache/http/message/HeaderSectionParser.java =================================================================== --- module-main/src/main/java/org/apache/http/message/HeaderSectionParser.java (revision 0) +++ module-main/src/main/java/org/apache/http/message/HeaderSectionParser.java (revision 0) @@ -0,0 +1,173 @@ +/* + * $HeadURL$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.message; + + +import org.apache.http.ProtocolException; //@@@ ParseException +import org.apache.http.Header; +import org.apache.http.HttpMessage; +import org.apache.http.params.HttpParams; +import org.apache.http.util.CharArrayBuffer; + + + +/** + * Interface for parsing a section of headers in an HTTP message. + * A header section is found in the head section of every HTTP message. + * Some messages may additionally have so-called footers, which form + * also a header section, except it's not in the head of the message. + * The lines to parse are passed in memory, the parser does not depend + * on any specific IO mechanism. + *
+ * In order to process header continuation lines, a header section parser + * needs either one line of look-ahead or has to be stateful. + * This interface is for a stateful parser. Instances are expected + * to be re-usable, but not thread-safe. + * Instances of this interface are expected to be stateless and thread-safe. + * + * @author Roland Weber + * + * + * + * @version $Revision$ $Date$ + * + * @since 4.0 + */ +public interface HeaderSectionParser { + + /** + * Initializes this parser. + * A parser is re-usable, each call to this method will re-set + * it to a defined state. Implementations must not assume that + * the previous parse run is complete when the parser is re-set. + * Parse runs can be cancelled at any time. + * + * @param maxHeaderCount the maximum number of headers to parse, + * or negative to disable this limit + * @param maxLineLength the maximum length of a header line + * after concatenation of continuation lines, + * or negative to disable this limit + * @param params additional implementation-specific parameters, + * or null + */ + void init(int maxHeaderCount, int maxLineLength, HttpParams params) + ; + + + /** + * Checks whether a parse run is complete. + * A parse run starts with a call to {@link #init} and is complete + * when the parser has detected the end of the header section. + * The latter happens in a call to {@link #parseLine parseLine}. + * Once the parse run is complete, the result can be obtained from + * {@link #getHeaders getHeaders}. + * A parse run can also be completed prematurely by calling + * {@link #complete}. + * + * @return true if the current parse run is complete, + * false otherwise + */ + boolean isComplete() + ; + + + /** + * Parses an input line of a header section. + * The parser may need to keep the argument buffer for further + * processing. In that case, this method returns null + * and the caller MUST NOT re-use or modify the buffer afterwards. + * If the parser does not need the buffer anymore, a reference to + * the buffer is returned. This can be used as follows: + *
+     *     buffer = headerSectionParser.parseLine(buffer);
+     *     if (buffer == null)
+     *         ...; // need to create a new buffer
+     * 
+ * + * @param buffer the buffer holding the line to parse + * + * @return null if the parser takes control of the argument + * buffer, keeping it for further use. In that case, the caller + * MUST NOT alter the buffer afterwards, ever. + * buffer indicates that the parser will not need + * the buffer content anymore. + * + * @throws ProtocolException in case of a parse error + */ + CharArrayBuffer parseLine(CharArrayBuffer buffer) + throws ProtocolException + ; + + + /** + * Completes a parse run explicitly. + * If the parse run was already complete, this method does nothing. + * Otherwise, the parser behaves as if the end of the header section + * had been detected. + * + * @throws ProtocolException in case of a parse error + */ + void complete() + throws ProtocolException + ; + + + /** + * Obtains the headers collected during the parse run. + * Once a parse run is {@link #isComplete complete}, this method will + * return all headers found in the parsed section. + * At any other time, the behavior is undefined. + * + * @return the headers collected during the parse run, + * never null + * + * @throws ProtocolException in case of a parse error + */ + Header[] getHeaders() + throws ProtocolException + ; + + + /** + * Adds the headers collected during the parse run to a message. + * This avoids creating the array returned by {@link #getHeaders}. + * This method must only be called when a parse run is + * {@link #isComplete complete}. + * + * @param message the message to which to append the headers + * + * @throws ProtocolException in case of a parse error + */ + void addHeadersTo(HttpMessage message) + throws ProtocolException + ; +} Property changes on: module-main/src/main/java/org/apache/http/message/HeaderSectionParser.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Date Author Id Revision HeadURL Name: svn:eol-style + native Index: module-main/src/main/java/org/apache/http/message/BasicHeaderSectionParser.java =================================================================== --- module-main/src/main/java/org/apache/http/message/BasicHeaderSectionParser.java (revision 0) +++ module-main/src/main/java/org/apache/http/message/BasicHeaderSectionParser.java (revision 0) @@ -0,0 +1,347 @@ +/* + * $HeadURL$ + * $Revision$ + * $Date$ + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.message; + + +import java.util.List; +import java.util.ArrayList; + +import org.apache.http.ProtocolException; //@@@ replace by ParseException +import org.apache.http.Header; +import org.apache.http.HttpMessage; +import org.apache.http.ParseException; +import org.apache.http.params.HttpParams; +import org.apache.http.util.CharArrayBuffer; + + + +/** + * Interface for parsing a section of headers in an HTTP message. + * A header section is found in the head section of every HTTP message. + * Some messages may additionally have so-called footers, which form + * also a header section, except it's not in the head of the message. + * The lines to parse are passed in memory, the parser does not depend + * on any specific IO mechanism. + *
+ * In order to process header continuation lines, a header section parser + * needs either one line of look-ahead or has to be stateful. + * This interface is for a stateful parser. Instances are expected + * to be re-usable, but not thread-safe. + * Instances of this interface are expected to be stateless and thread-safe. + * + * + * + * @version $Revision$ $Date$ + * + * @since 4.0 + */ +public class BasicHeaderSectionParser implements HeaderSectionParser { + + public final static int STATE_INVALID = 0; + public final static int STATE_PARSING = 1; + public final static int STATE_COMPLETE = 2; + + + /** The line parser to use for the headers, never null. */ + protected LineParser lineParser; + + /** The current state of this parser. */ + protected int parseState; + + + /** The maximum number of headers. */ + protected int maxHeaderCount; + + /** The maximum length of a header line, including continuations. */ + protected int maxLineLength; + + + /** + * The list of headers in the current parse run. + * Filled by {@link #storeCurrentHeader}, + * accessed by {@link #getHeaders} and {@link #addHeadersTo}. + * Holds {@link Header} objects. + */ + protected List collectedHeaders; + + /** The header currently being parsed. */ + protected CharArrayBuffer currentHeader; + + /** A line counter, for improved error reporting. */ + protected int lineCounter; + + + + /** + * Instantiates a new header section parser. + * + * @param linep the line parser to use for the headers, or + * null for the default + */ + public BasicHeaderSectionParser(LineParser linep) { + + lineParser = (linep != null) ? linep : BasicLineParser.DEFAULT; + parseState = STATE_INVALID; // until initialized + lineCounter = -1; + } + + + + + // non-javadoc, see interface HeaderSectionParser + public void init(int maxCount, int maxLength, HttpParams params) { + + // params are allowed to be null here + + maxLineLength = maxLength; + maxHeaderCount = maxCount; + + if (collectedHeaders == null) + collectedHeaders = new ArrayList(); // default size from params? + else + collectedHeaders.clear(); // reduce capacity if too large? + + currentHeader = null; + lineCounter = 0; + + // init/reset complete + parseState = STATE_PARSING; + } + + + // non-javadoc, see interface HeaderSectionParser + public boolean isComplete() { + return (parseState == STATE_COMPLETE); + } + + + // non-javadoc, see interface HeaderSectionParser + public CharArrayBuffer parseLine(CharArrayBuffer buffer) + throws ProtocolException { + + if (buffer == null) { + throw new IllegalArgumentException + ("Buffer to parse must not be null."); + } + if (parseState != STATE_PARSING) { + throw new IllegalStateException + ("Not parsing at line " + + lineCounter + ", state " + parseState); + } + + // We count the lines before they are parsed. Line numbers in + // exception messages are therefore 1-based, starting at the header + // section. For message heads, that corresponds to a 0-based count + // from the request or status line. For footers... who cares? ;-) + // Counting the line now makes sure that the count is updated + // in case of a parse error. Note that the caller may continue + // to parse a header section even if some lines cause errors. + lineCounter++; + + boolean keepbuffer = false; + if (isContinuationLine(buffer)) { + keepbuffer = handleContinuationLine(buffer); + + } else { // we have a new header, or an empty line + + storeCurrentHeader(); + + if (buffer.length() > 0) { + // new header, check the count + if ((maxHeaderCount >= 0) && + (collectedHeaders.size() >= maxHeaderCount)) { + throw new ProtocolException + ("Maximum header count exceeded at line " + + lineCounter + "."); + } + // wait for possible continuation lines + currentHeader = buffer; + keepbuffer = true; + } else { + // empty line marks end of headers + parseState = STATE_COMPLETE; + } + } + + return keepbuffer ? null : buffer; + + } // parseLine + + + // non-javadoc, see interface HeaderSectionParser + public void complete() + throws ProtocolException { + + switch (parseState) { + + case STATE_PARSING: + storeCurrentHeader(); + parseState = STATE_COMPLETE; + break; + + case STATE_COMPLETE: + break; + // do nothing + + default: + throw new IllegalStateException + ("Parsing not in progress at line " + + lineCounter + ", state " + parseState + "."); + } + } + + + /** + * Checks whether the given buffer holds a header continuation line. + * + * @param buffer the buffer to check + * + * @return true if the buffer holds a continuation line, + * false otherwise + */ + protected boolean isContinuationLine(CharArrayBuffer buffer) { + + // should we allow for a malformed first header anyway? + // there is a test case, so the code needs be remain here for now + return (currentHeader != null) && + isContinuationLineLead(buffer.charAt(0)); + } + + + /** + * Checks whether the given character is a continuation line indicator. + * The default implementation accepts space and tab characters. + * + * @param c the character to check + * + * @return true if the argument is a header continuation line + * indicator, false otherwise + */ + protected boolean isContinuationLineLead(char c) { + return (c == ' ' || c == '\t'); + } + + + /** + * Called to append a continuation line to the current header. + * The default implementation skips leading whitespace, then + * joins the rest of the line to {@link #currentHeader}. + * + * @param buffer the buffer holding the continuation line + * + * @return true if the argument buffer needs to be kept + * unmodified, false if it is no longer needed + */ + protected boolean handleContinuationLine(CharArrayBuffer buffer) + throws ProtocolException { + + if (currentHeader == null) { + throw new ProtocolException + ("No header to continue at line " + lineCounter + "."); + } + + int i; + for (i=0; + (i= 0 && + (currentHeader.length() + 1 + buffer.length() - i + > maxLineLength) + ) { + throw new ProtocolException + ("Maximum line length exceeded at header line " + + lineCounter + "."); + } + + currentHeader.append(' '); + currentHeader.append(buffer, i, buffer.length() - i); + + return false; // don't need that buffer anymore + } + + + /** + * Called to store {@link #currentHeader} into {@link #collectedHeaders}. + * This method is called once while {@link #currentHeader} is still + * null. In that case, it does nothing. + */ + protected void storeCurrentHeader() + throws ProtocolException { + + if (currentHeader == null) + return; + + Header h; + try { + h = lineParser.parseHeader(currentHeader); + } catch (ParseException ex) { + throw new ProtocolException(ex.getMessage()); // line number? + } + + collectedHeaders.add(h); + } + + + // non-javadoc, see interface HeaderSectionParser + public Header[] getHeaders() throws ProtocolException { + + if (parseState != STATE_COMPLETE) { + throw new IllegalStateException + ("Parsing not complete at line " + + lineCounter + ", state " + parseState + "."); + } + + return (Header[]) + collectedHeaders.toArray(new Header[collectedHeaders.size()]); + } + + + // non-javadoc, see interface HeaderSectionParser + public void addHeadersTo(HttpMessage message) + throws ProtocolException { + + if (parseState != STATE_COMPLETE) { + throw new IllegalStateException + ("Parsing not complete at line " + + lineCounter + ", state " + parseState + "."); + } + + for (int i = 0; i < collectedHeaders.size(); i++) { // iterator? + message.addHeader((Header)collectedHeaders.get(i)); + } + } + + +} // class BasicHeaderSectionParser Property changes on: module-main/src/main/java/org/apache/http/message/BasicHeaderSectionParser.java ___________________________________________________________________ Name: svn:mime-type + text/plain Name: svn:keywords + Date Author Id Revision HeadURL Name: svn:eol-style + native Index: module-main/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java =================================================================== --- module-main/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java (revision 568813) +++ module-main/src/main/java/org/apache/http/impl/io/ChunkedInputStream.java (working copy) @@ -239,7 +239,7 @@ */ private void parseTrailerHeaders() throws IOException { try { - this.footers = AbstractMessageParser.parseHeaders(in); + this.footers = AbstractMessageParser.parseHeaders(in, -1, -1); } catch (HttpException e) { IOException ioe = new MalformedChunkCodingException("Invalid footer: " + e.getMessage()); Index: module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java =================================================================== --- module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java (revision 568813) +++ module-main/src/main/java/org/apache/http/impl/io/AbstractMessageParser.java (working copy) @@ -41,6 +41,7 @@ import org.apache.http.io.HttpMessageParser; import org.apache.http.io.SessionInputBuffer; import org.apache.http.message.LineParser; +import org.apache.http.message.HeaderSectionParser; import org.apache.http.message.BasicLineParser; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; @@ -77,116 +78,72 @@ this.maxLineLen = params.getIntParameter( HttpConnectionParams.MAX_LINE_LENGTH, -1); this.lineParser = (parser != null) ? parser : BasicLineParser.DEFAULT; + //@@@ remember params to initialize header section parser? } - /** - * Parses HTTP headers from the data receiver stream according to the generic - * format as given in Section 3.1 of RFC 822, RFC-2616 Section 4 and 19.3. - * - * @param inbuffer Session input buffer - * @param maxHeaderCount maximum number of headers allowed. If the number - * of headers received from the data stream exceeds maxCount value, an - * IOException will be thrown. Setting this parameter to a negative value - * or zero will disable the check. - * @param maxLineLen maximum number of characters for a header line, - * including the continuation lines - * @return array of HTTP headers - * - * @throws HttpException - * @throws IOException - */ + + //@@@ currently needed for parsing footers in ChunkedInputStream public static Header[] parseHeaders( final SessionInputBuffer inbuffer, int maxHeaderCount, - int maxLineLen, - LineParser parser) + int maxLineLen) throws HttpException, IOException { if (inbuffer == null) { - throw new IllegalArgumentException("Session input buffer may not be null"); + throw new IllegalArgumentException + ("Session input buffer may not be null"); } - if (parser == null) - parser = BasicLineParser.DEFAULT; - ArrayList headerLines = new ArrayList(); + HeaderSectionParser hsp = + BasicLineParser.DEFAULT.createHeaderSectionParser(); + hsp.init(maxHeaderCount, maxLineLen, null); - CharArrayBuffer current = null; - CharArrayBuffer previous = null; - for (;;) { - if (current == null) { - current = new CharArrayBuffer(64); + CharArrayBuffer buffer = null; + boolean done = false; + while (!done) { + if (buffer == null) { + buffer = new CharArrayBuffer(64); } else { - current.clear(); + buffer.clear(); } - int l = inbuffer.readLine(current); - if (l == -1 || current.length() < 1) { - break; - } - // Parse the header name and value - // Check for folded headers first - // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2 - // discussion on folded headers - if ((current.charAt(0) == ' ' || current.charAt(0) == '\t') && previous != null) { - // we have continuation folded header - // so append value - int i = 0; - while (i < current.length()) { - char ch = current.charAt(i); - if (ch != ' ' && ch != '\t') { - break; - } - i++; - } - if (maxLineLen > 0 - && previous.length() + 1 + current.length() - i > maxLineLen) { - throw new IOException("Maximum line length limit exceeded"); - } - previous.append(' '); - previous.append(current, i, current.length() - i); + int l = inbuffer.readLine(buffer); + if (l < 0) { + hsp.complete(); // premature end of header section } else { - headerLines.add(current); - previous = current; - current = null; + buffer = hsp.parseLine(buffer); } - if (maxHeaderCount > 0 && headerLines.size() >= maxHeaderCount) { - throw new IOException("Maximum header count exceeded"); - } + done = hsp.isComplete(); } - Header[] headers = new Header[headerLines.size()]; - for (int i = 0; i < headerLines.size(); i++) { - CharArrayBuffer buffer = (CharArrayBuffer) headerLines.get(i); - try { - headers[i] = parser.parseHeader(buffer); - } catch (IllegalArgumentException ex) { - throw new ProtocolException(ex.getMessage()); - } - } - return headers; + return hsp.getHeaders(); } - public static Header[] parseHeaders( - final SessionInputBuffer inbuffer, - int maxHeaderCount, - int maxLineLen) throws HttpException, IOException { - return parseHeaders(inbuffer, maxHeaderCount, maxLineLen, null); - } - - public static Header[] parseHeaders(final SessionInputBuffer inbuffer) - throws HttpException, IOException { - return parseHeaders(inbuffer, -1, -1, null); - } - protected abstract HttpMessage parseHead(SessionInputBuffer sessionBuffer) throws IOException, HttpException; public HttpMessage parse() throws IOException, HttpException { HttpMessage message = parseHead(this.sessionBuffer); - Header[] headers = AbstractMessageParser.parseHeaders( - this.sessionBuffer, - this.maxHeaderCount, - this.maxLineLen, - this.lineParser); - message.setHeaders(headers); + + HeaderSectionParser hsp = lineParser.createHeaderSectionParser(); + hsp.init(maxHeaderCount, maxLineLen, null); + + CharArrayBuffer buffer = null; + boolean done = false; + while (!done) { + if (buffer == null) { + buffer = new CharArrayBuffer(64); + } else { + buffer.clear(); + } + int l = this.sessionBuffer.readLine(buffer); + if (l < 0) { + hsp.complete(); // premature end of header section + } else { + buffer = hsp.parseLine(buffer); + } + done = hsp.isComplete(); + } + hsp.addHeadersTo(message); + return message; }