You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2007/06/13 21:50:24 UTC

svn commit: r547010 - in /jakarta/httpcomponents/httpcore/trunk: ./ module-nio/src/main/java/org/apache/http/impl/nio/ module-nio/src/main/java/org/apache/http/impl/nio/codecs/ module-nio/src/test/java/org/apache/http/impl/nio/codecs/

Author: olegk
Date: Wed Jun 13 12:50:22 2007
New Revision: 547010

URL: http://svn.apache.org/viewvc?view=rev&rev=547010
Log:
HTTPCORE-81: Maximum line length and maximum header counts parameters are now correctly enforced in both base and NIO modules

Contributed by Steffen Pingel <spingel at limewire.com>
Reviewed by Oleg Kalnichevski

Modified:
    jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpMessageParser.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpRequestParser.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpResponseParser.java
    jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/codecs/TestHttpMessageParser.java

Modified: jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt?view=diff&rev=547010&r1=547009&r2=547010
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt (original)
+++ jakarta/httpcomponents/httpcore/trunk/RELEASE_NOTES.txt Wed Jun 13 12:50:22 2007
@@ -1,5 +1,9 @@
 Changes since 4.0 Alpha 4
 
+* [HTTPCORE-81]: Maximum line length and maximum header counts parameters are now 
+  correctly enforced in both base and NIO modules.
+  Contributed by Steffen Pingel <spingel at limewire.com>
+
 * Added HTTP client handler implementation that allocates fixed size content 
   buffers upon initialization and is capable of throttling the rate of I/O events 
   in order to make sure those content buffers do not get overflown.

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java?view=diff&rev=547010&r1=547009&r2=547010
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpClientConnection.java Wed Jun 13 12:50:22 2007
@@ -50,6 +50,7 @@
 import org.apache.http.nio.reactor.EventMask;
 import org.apache.http.nio.reactor.IOSession;
 import org.apache.http.nio.util.ByteBufferAllocator;
+import org.apache.http.params.HttpConnectionParams;
 import org.apache.http.params.HttpParams;
 
 public class DefaultNHttpClientConnection 
@@ -66,7 +67,11 @@
         if (responseFactory == null) {
             throw new IllegalArgumentException("Response factory may not be null");
         }
-        this.responseParser = new HttpResponseParser(this.inbuf, responseFactory);
+        this.responseParser = new HttpResponseParser(
+                this.inbuf,
+                params.getIntParameter(HttpConnectionParams.MAX_LINE_LENGTH, -1),
+                params.getIntParameter(HttpConnectionParams.MAX_HEADER_COUNT, -1),
+                responseFactory);
         this.hasBufferedInput = false;
         this.hasBufferedOutput = false;
         this.session.setBufferStatus(this);

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java?view=diff&rev=547010&r1=547009&r2=547010
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/DefaultNHttpServerConnection.java Wed Jun 13 12:50:22 2007
@@ -50,6 +50,7 @@
 import org.apache.http.nio.reactor.EventMask;
 import org.apache.http.nio.reactor.IOSession;
 import org.apache.http.nio.util.ByteBufferAllocator;
+import org.apache.http.params.HttpConnectionParams;
 import org.apache.http.params.HttpParams;
 
 public class DefaultNHttpServerConnection 
@@ -66,7 +67,11 @@
         if (requestFactory == null) {
             throw new IllegalArgumentException("Request factory may not be null");
         }
-        this.requestParser = new HttpRequestParser(this.inbuf, requestFactory);
+        this.requestParser = new HttpRequestParser(
+                this.inbuf,
+                params.getIntParameter(HttpConnectionParams.MAX_LINE_LENGTH, -1),
+                params.getIntParameter(HttpConnectionParams.MAX_HEADER_COUNT, -1),
+                requestFactory);
     }
 
     public void resetInput() {

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpMessageParser.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpMessageParser.java?view=diff&rev=547010&r1=547009&r2=547010
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpMessageParser.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpMessageParser.java Wed Jun 13 12:50:22 2007
@@ -58,7 +58,10 @@
     private CharArrayBuffer lineBuf;
     private final List headerBufs;
 
-    public HttpMessageParser(final SessionInputBuffer buffer) {
+    private int maxLineLen;
+    private int maxHeaderCount;
+
+    public HttpMessageParser(final SessionInputBuffer buffer, int maxLineLen, int maxHeaderCount) {
         super();
         if (buffer == null) {
             throw new IllegalArgumentException("Session input buffer may not be null");
@@ -67,6 +70,8 @@
         this.state = READ_HEAD_LINE;
         this.endOfStream = false;
         this.headerBufs = new ArrayList();        
+        this.maxLineLen = maxLineLen;
+        this.maxHeaderCount = maxHeaderCount;
     }
     
     public void reset() {
@@ -91,7 +96,7 @@
         this.message = createMessage(this.lineBuf);
     }
     
-    private void parseHeader() {
+    private void parseHeader() throws IOException {
         CharArrayBuffer current = this.lineBuf;
         int count = this.headerBufs.size();
         if ((this.lineBuf.charAt(0) == ' ' || this.lineBuf.charAt(0) == '\t') && count > 0) {
@@ -105,6 +110,9 @@
                 }
                 i++;
             }
+            if (this.maxLineLen > 0 && previous.length() + 1 + current.length() - i > this.maxLineLen) {
+                throw new IOException("Maximum line length limit exceeded");
+            }
             previous.append(' ');
             previous.append(current, i, current.length() - i);
         } else {
@@ -120,9 +128,14 @@
             } else {
                 this.lineBuf.clear();
             }
-            if (!this.buffer.readLine(this.lineBuf, this.endOfStream)) {
+            boolean lineComplete = this.buffer.readLine(this.lineBuf, this.endOfStream);
+            if (this.maxLineLen > 0 && this.lineBuf.length() > this.maxLineLen) {
+                throw new IOException("Maximum line length limit exceeded");
+            }
+            if (!lineComplete) {
                 break;
             }
+
             switch (this.state) {
             case READ_HEAD_LINE:
                 parseHeadLine();
@@ -130,6 +143,10 @@
                 break;
             case READ_HEADERS:
                 if (this.lineBuf.length() > 0) {
+                    if (this.maxHeaderCount > 0 && headerBufs.size() >= this.maxHeaderCount) {
+                        throw new IOException("Maximum header count exceeded");
+                    }
+                    
                     parseHeader();
                 } else {
                     this.state = COMPLETED;

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpRequestParser.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpRequestParser.java?view=diff&rev=547010&r1=547009&r2=547010
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpRequestParser.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpRequestParser.java Wed Jun 13 12:50:22 2007
@@ -45,12 +45,20 @@
     
     public HttpRequestParser(
             final SessionInputBuffer buffer,
+            int maxLineLen, 
+            int maxHeaderCount,
             final HttpRequestFactory requestFactory) {
-        super(buffer);
+        super(buffer, maxLineLen, maxHeaderCount);
         if (requestFactory == null) {
             throw new IllegalArgumentException("Request factory may not be null");
         }
         this.requestFactory = requestFactory;
+    }
+
+    public HttpRequestParser(
+            final SessionInputBuffer buffer,
+            final HttpRequestFactory requestFactory) {
+        this(buffer, -1, -1, requestFactory);
     }
 
     protected HttpMessage createMessage(final CharArrayBuffer buffer) 

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpResponseParser.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpResponseParser.java?view=diff&rev=547010&r1=547009&r2=547010
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpResponseParser.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/impl/nio/codecs/HttpResponseParser.java Wed Jun 13 12:50:22 2007
@@ -45,12 +45,20 @@
     
     public HttpResponseParser(
             final SessionInputBuffer buffer,
+            int maxLineLen, 
+            int maxHeaderCount,
             final HttpResponseFactory responseFactory) {
-        super(buffer);
+        super(buffer, maxLineLen, maxHeaderCount);
         if (responseFactory == null) {
             throw new IllegalArgumentException("Response factory may not be null");
         }
         this.responseFactory = responseFactory;
+    }
+
+    public HttpResponseParser(
+            final SessionInputBuffer buffer,
+            final HttpResponseFactory responseFactory) {
+        this(buffer, -1, -1, responseFactory);
     }
 
     protected HttpMessage createMessage(final CharArrayBuffer buffer) 

Modified: jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/codecs/TestHttpMessageParser.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/codecs/TestHttpMessageParser.java?view=diff&rev=547010&r1=547009&r2=547010
==============================================================================
--- jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/codecs/TestHttpMessageParser.java (original)
+++ jakarta/httpcomponents/httpcore/trunk/module-nio/src/test/java/org/apache/http/impl/nio/codecs/TestHttpMessageParser.java Wed Jun 13 12:50:22 2007
@@ -31,6 +31,7 @@
 package org.apache.http.impl.nio.codecs;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
@@ -46,8 +47,6 @@
 import org.apache.http.HttpVersion;
 import org.apache.http.impl.DefaultHttpRequestFactory;
 import org.apache.http.impl.DefaultHttpResponseFactory;
-import org.apache.http.impl.nio.codecs.HttpMessageParser;
-import org.apache.http.impl.nio.codecs.HttpRequestParser;
 import org.apache.http.impl.nio.reactor.SessionInputBuffer;
 
 /**
@@ -320,6 +319,75 @@
             fail("IllegalArgumentException should have been thrown");
         } catch (IllegalArgumentException ex) {
             // ignore
+        }
+    }
+
+    public void testLineLimitForStatus() throws Exception {
+        SessionInputBuffer inbuf = new SessionInputBuffer(1024, 128); 
+        HttpRequestFactory requestFactory = new DefaultHttpRequestFactory();
+        HttpRequestParser requestParser = new HttpRequestParser(inbuf, 0, -1, requestFactory);
+
+        requestParser.fillBuffer(newChannel("GET /whatever HTTP/1.0\r\nHeader: one\r\n\r\n"));
+        requestParser.parse();
+        requestParser.reset();
+
+        requestParser = new HttpRequestParser(inbuf, 15, -1, requestFactory);
+        try {
+            requestParser.fillBuffer(newChannel("GET /loooooooooooooooong HTTP/1.0\r\nHeader: one\r\n\r\n"));
+            requestParser.parse();
+            fail("IOException should have been thrown");
+        } catch (IOException expected) {
+        }
+    }
+
+    public void testLineLimitForHeader() throws Exception {
+        SessionInputBuffer inbuf = new SessionInputBuffer(1024, 128); 
+        HttpRequestFactory requestFactory = new DefaultHttpRequestFactory();
+        HttpRequestParser requestParser = new HttpRequestParser(inbuf, 0, -1, requestFactory);
+
+        requestParser.fillBuffer(newChannel("GET /whatever HTTP/1.0\r\nHeader: one\r\n\r\n"));
+        requestParser.parse();
+        requestParser.reset();
+
+        requestParser = new HttpRequestParser(inbuf, 15, -1, requestFactory);
+        requestParser.fillBuffer(newChannel("GET / HTTP/1.0\r\nHeader: 9012345\r\n\r\n"));
+        requestParser.parse();
+        requestParser.reset();
+        try {
+            requestParser.fillBuffer(newChannel("GET / HTTP/1.0\r\nHeader: 90123456\r\n\r\n"));
+            requestParser.parse();
+            fail("IOException should have been thrown");
+        } catch (IOException expected) {
+        }
+    }
+
+    public void testLineLimitForFoldedHeader() throws Exception {
+        SessionInputBuffer inbuf = new SessionInputBuffer(1024, 128); 
+        HttpRequestFactory requestFactory = new DefaultHttpRequestFactory();
+        HttpRequestParser requestParser = new HttpRequestParser(inbuf, 15, 2, requestFactory);
+
+        try {
+            requestParser.fillBuffer(newChannel("GET / HTTP/1.0\r\nHeader: 9012345\r\n 23456789012345\r\n 23456789012345\r\n 23456789012345\r\n\r\n"));
+            requestParser.parse();
+            fail("IOException should have been thrown");
+        } catch (IOException expected) {
+        }
+    }
+
+    public void testMaxHeaderCount() throws Exception {
+        SessionInputBuffer inbuf = new SessionInputBuffer(1024, 128); 
+        HttpRequestFactory requestFactory = new DefaultHttpRequestFactory();
+        HttpRequestParser requestParser = new HttpRequestParser(inbuf, -1, 2, requestFactory);
+
+        requestParser.fillBuffer(newChannel("GET /whatever HTTP/1.0\r\nHeader: one\r\nHeader: two\r\n\r\n"));
+        requestParser.parse();
+        requestParser.reset();
+
+        try {
+            requestParser.fillBuffer(newChannel("GET /whatever HTTP/1.0\r\nHeader: one\r\nHeader: two\r\nHeader: three\r\n\r\n"));
+            requestParser.parse();
+            fail("IOException should have been thrown");
+        } catch (IOException expected) {
         }
     }