Index: org/apache/commons/httpclient/HttpMethodBase.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpMethodBase.java,v retrieving revision 1.194 diff -u -r1.194 HttpMethodBase.java --- org/apache/commons/httpclient/HttpMethodBase.java 11 Dec 2003 22:54:18 -0000 1.194 +++ org/apache/commons/httpclient/HttpMethodBase.java 12 Dec 2003 10:59:23 -0000 @@ -1715,8 +1715,19 @@ LOG.trace("enter HttpMethodBase.readResponseHeaders(HttpState," + "HttpConnection)"); + final int headerLineLimit = getParams(). + getIntParameter(HttpMethodParams.HTTP_HEADER_LINE_LIMIT, 4096); + final int headerLimit = getParams(). + getIntParameter(HttpMethodParams.HTTP_HEADER_LIMIT, 1000); + final int headerValueLimit = getParams(). + getIntParameter(HttpMethodParams.HTTP_HEADER_VALUE_LIMIT, 4096); + getResponseHeaderGroup().clear(); - Header[] headers = HttpParser.parseHeaders(conn.getResponseInputStream()); + Header[] headers = + HttpParser.parseHeaders( + conn.getResponseInputStream(), + headerLineLimit, headerLimit, headerValueLimit); + if (Wire.enabled()) { for (int i = 0; i < headers.length; i++) { Wire.input(headers[i].toExternalForm()); Index: org/apache/commons/httpclient/HttpParser.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpParser.java,v retrieving revision 1.8 diff -u -r1.8 HttpParser.java --- org/apache/commons/httpclient/HttpParser.java 15 Jul 2003 02:19:58 -0000 1.8 +++ org/apache/commons/httpclient/HttpParser.java 12 Dec 2003 10:59:23 -0000 @@ -76,6 +76,7 @@ * * @author Michael Becke * @author Oleg Kalnichevski + * @author Christian Kohlschuetter * * @since 2.0beta1 */ @@ -102,15 +103,36 @@ * @return a byte array from the stream */ public static byte[] readRawLine(InputStream inputStream) throws IOException { + return readRawLine(inputStream, Integer.MAX_VALUE); + } + + /** + * Return byte array from an (unchunked) input stream. + * Stop reading when "\n" terminator encountered + * or if the number of bytes read exceeds maxLen. + * + * @param inputStream the stream to read from + * @param the maximum number of bytes before "\n" + * + * @throws IOException if an I/O problem occurs + * @return a byte array from the stream + * @see #readRawLine(InputStream) + */ + public static byte[] readRawLine(InputStream inputStream, int maxLen) throws IOException { LOG.trace("enter HttpParser.readRawLine()"); ByteArrayOutputStream buf = new ByteArrayOutputStream(); int ch; + int n = 0; while ((ch = inputStream.read()) >= 0) { buf.write(ch); + n++; if (ch == '\n') { break; } + if(n > maxLen) { + throw new HttpException("Line too long (> "+maxLen+" bytes)"); + } } if (buf.size() == 0) { return null; @@ -129,10 +151,24 @@ * @throws IOException if an I/O problem occurs * @return a line from the stream */ - public static String readLine(InputStream inputStream) throws IOException { + return readLine(inputStream, Integer.MAX_VALUE); + } + + /** + * Read up to "\n" and up to maxLen bytes + * from an (unchunked) input stream. + * + * @param inputStream the stream to read from + * @param the maximum number of bytes before "\n" + * + * @throws IOException if an I/O problem occurs + * @return a line from the stream + * @see #readLine(InputStream) + */ + public static String readLine(InputStream inputStream, int maxLen) throws IOException { LOG.trace("enter HttpParser.readLine()"); - byte[] rawdata = readRawLine(inputStream); + byte[] rawdata = readRawLine(inputStream, maxLen); if (rawdata == null) { return null; } @@ -155,6 +191,12 @@ * Parses headers from the given stream. Headers with the same name are not * combined. * + * The maximum line length is 4096 bytes/8-bit-characters. + * The maximum number of headers is 1000. + * The maximum header value length is 4096 characters. + * + * A HttpException is thrown if at least one of these limits is exceeded. + * * @param is the stream to read headers from * * @return an array of headers in the order in which they were parsed @@ -163,13 +205,43 @@ * @throws HttpException if there is an error parsing a header value */ public static Header[] parseHeaders(InputStream is) throws IOException, HttpException { + return parseHeaders(is, 4096, 1000, 4096); + } + + /** + * Parses headers from the given stream. Headers with the same name are not + * combined, permitting a specific maximum line length, number of headers + * and header value length. + * + * A HttpException is thrown if at least one of the specified limits + * is exceeded. + * + * @param is the stream to read headers from + * @param maxLineLen Maximum line length (in bytes/8-bit characters) + * @param maxHeaders Maximum number of headers + * @param maxHeaderValueLength Maximum length of header values (in characters) + * + * @return an array of headers in the order in which they were parsed + * + * @throws IOException if an IO error occurs while reading from the stream + * @throws HttpException if there is an error parsing a header value + */ + public static Header[] parseHeaders( + InputStream is, + int maxLineLen, + int maxHeaders, + int maxHeaderValueLength) + throws IOException, HttpException { LOG.trace("enter HeaderParser.parseHeaders(HttpConnection, HeaderGroup)"); ArrayList headers = new ArrayList(); String name = null; StringBuffer value = null; for (; ;) { - String line = HttpParser.readLine(is); + if(headers.size() > maxHeaders) { + throw new HttpException("Too many headers (> "+maxHeaders+")"); + } + String line = HttpParser.readLine(is, maxLineLen); if ((line == null) || (line.length() < 1)) { break; } @@ -184,6 +256,9 @@ if (value != null) { value.append(' '); value.append(line.trim()); + if(value.length() > maxHeaderValueLength) { + throw new HttpException("Header value too long (> "+maxHeaderValueLength+")"); + } } } else { // make sure we save the previous name,value pair if present @@ -199,6 +274,9 @@ } name = line.substring(0, colon).trim(); value = new StringBuffer(line.substring(colon + 1).trim()); + if(value.length() > maxHeaderValueLength) { + throw new HttpException("Header value too long (> "+maxHeaderValueLength+")"); + } } } @@ -206,6 +284,9 @@ // make sure we save the last name,value pair if present if (name != null) { headers.add(new Header(name, value.toString())); + if(headers.size() > maxHeaders) { + throw new HttpException("Too many headers (> "+maxHeaders+")"); + } } return (Header[]) headers.toArray(new Header[headers.size()]); Index: org/apache/commons/httpclient/params/HttpMethodParams.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/params/HttpMethodParams.java,v retrieving revision 1.7 diff -u -r1.7 HttpMethodParams.java --- org/apache/commons/httpclient/params/HttpMethodParams.java 11 Dec 2003 22:54:19 -0000 1.7 +++ org/apache/commons/httpclient/params/HttpMethodParams.java 12 Dec 2003 10:59:23 -0000 @@ -242,6 +242,46 @@ * This parameter expects a value of type {@link Integer}. */ public static final String STATUS_LINE_GARBAGE_LIMIT = "http.protocol.status-line-garbage-limit"; + + /** + * Defines the maximum length (in bytes) of a line which is part of a HTTP header. + *

+ * If the HTTP Header is folded into several lines, this parameter controls + * the maximum length for every single line. + *

+ * This parameter should be set to a reasonable value (4096 by default). + * Set this to Integer.MAX_VALUE to allow any arbitrary header + * length. + *

+ * + * This parameter expects a value of type {@link Integer}. + */ + public static final String HTTP_HEADER_LINE_LIMIT = "http.protocol.header-line-limit"; + + /** + * Defines the maximum number of headers that will be parsed from a HTTP response. + *

+ * This parameter should be set to a reasonable value (1000 by default). + * Set this to Integer.MAX_VALUE to allow any arbitrary number + * of headers. + *

+ * + * This parameter expects a value of type {@link Integer}. + */ + public static final String HTTP_HEADER_LIMIT = "http.protocol.header-limit"; + + /** + * Defines the maximum length (in characters) of a header's value that will + * be parsed from a HTTP response. + *

+ * This parameter should be set to a reasonable value (4096 by default). + * Set this to Integer.MAX_VALUE to allow any arbitrary number + * of headers. + *

+ * + * This parameter expects a value of type {@link Integer}. + */ + public static final String HTTP_HEADER_VALUE_LIMIT = "http.protocol.header-value-limit"; /** * Creates a new collection of parameters with the collection returned