/*
* ====================================================================
* 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
*
* {@link #readLine(CharArrayBuffer)} and {@link #readLine()} methods of this * class treat a lone LF as valid line delimiters in addition to CR-LF required * by the HTTP specification. * *
* The following parameters can be used to customize the behavior of this * class: *
-1 is returned. This method blocks until input
* data is available, end of file is detected, or an exception is thrown.
*
* This method treats a lone LF as a valid line delimiters in addition
* to CR-LF required by the HTTP specification.
*
* @param charbuffer the line buffer.
* @return one line of characters
* @exception IOException if an I/O error occurs.
*/
public int readLine(final CharArrayBuffer charbuffer) throws IOException {
if (charbuffer == null) {
throw new IllegalArgumentException("Char array buffer may not be null");
}
int noRead = 0;
boolean retry = true;
while (retry) {
// attempt to find end of line (LF)
int i = locateLF();
if (i != -1) {
// end of line found.
if (this.linebuffer.isEmpty()) {
// the entire line is preset in the read buffer
return lineFromReadBuffer(charbuffer, i);
}
retry = false;
int len = i + 1 - this.bufferpos;
this.linebuffer.append(this.buffer, this.bufferpos, len);
this.bufferpos = i + 1;
} else {
// end of line not found
if (hasBufferedData()) {
int len = this.bufferlen - this.bufferpos;
this.linebuffer.append(this.buffer, this.bufferpos, len);
this.bufferpos = this.bufferlen;
}
noRead = fillBuffer();
if (noRead == -1) {
retry = false;
}
}
if (this.maxLineLen > 0 && this.linebuffer.length() >= this.maxLineLen) {
throw new IOException("Maximum line length limit exceeded");
}
}
if (noRead == -1 && this.linebuffer.isEmpty()) {
// indicate the end of stream
return -1;
}
return lineFromLineBuffer(charbuffer);
}
/**
* Reads a complete line of characters up to a line delimiter from this
* session buffer. The line delimiter itself is discarded. If no char is
* available because the end of the stream has been reached,
* null is returned. This method blocks until input data is
* available, end of file is detected, or an exception is thrown.
*
* This method treats a lone LF as a valid line delimiters in addition * to CR-LF required by the HTTP specification. * * @return HTTP line as a string * @exception IOException if an I/O error occurs. */ private int lineFromLineBuffer(final CharArrayBuffer charbuffer) throws IOException { // discard LF if found int l = this.linebuffer.length(); if (l > 0) { if (this.linebuffer.byteAt(l - 1) == HTTP.LF) { l--; this.linebuffer.setLength(l); } // discard CR if found if (l > 0) { if (this.linebuffer.byteAt(l - 1) == HTTP.CR) { l--; this.linebuffer.setLength(l); } } } l = this.linebuffer.length(); if (this.ascii) { charbuffer.append(this.linebuffer, 0, l); } else { // This is VERY memory inefficient, BUT since non-ASCII charsets are // NOT meant to be used anyway, there's no point optimizing it String s = new String(this.linebuffer.buffer(), 0, l, this.charset); l = s.length(); charbuffer.append(s); } this.linebuffer.clear(); return l; } private int lineFromReadBuffer(final CharArrayBuffer charbuffer, int pos) throws IOException { int off = this.bufferpos; int len; this.bufferpos = pos + 1; if (pos > 0 && this.buffer[pos - 1] == HTTP.CR) { // skip CR if found pos--; } len = pos - off; if (this.ascii) { charbuffer.append(this.buffer, off, len); } else { // This is VERY memory inefficient, BUT since non-ASCII charsets are // NOT meant to be used anyway, there's no point optimizing it String s = new String(this.buffer, off, len, this.charset); charbuffer.append(s); len = s.length(); } return len; } public String readLine() throws IOException { CharArrayBuffer charbuffer = new CharArrayBuffer(64); int l = readLine(charbuffer); if (l != -1) { return charbuffer.toString(); } else { return null; } } public HttpTransportMetrics getMetrics() { return this.metrics; } }