Index: TestBadResponseHeader.java =================================================================== RCS file: TestBadResponseHeader.java diff -N TestBadResponseHeader.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ TestBadResponseHeader.java 12 Dec 2003 10:59:42 -0000 @@ -0,0 +1,294 @@ +package org.apache.commons.httpclient; + +import java.io.IOException; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.server.HttpRequestHandler; +import org.apache.commons.httpclient.server.RequestLine; +import org.apache.commons.httpclient.server.ResponseWriter; +import org.apache.commons.httpclient.server.SimpleHttpServer; +import org.apache.commons.httpclient.server.SimpleHttpServerConnection; +import org.apache.commons.httpclient.util.TimeoutController; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Tests HttpClient's behaviour when receiving bad response headers. + *
+ * A very simple HTTP Server will be setup on a free local port during testing, which + * returns bad/malicious response headers. + *
+ * + * @author Christian Kohlschuetter + * @version $Id$ + */ +public class TestBadResponseHeader extends TestNoHost { + private static final Log LOG = LogFactory.getLog(SimpleHttpServer.class); + + private HttpClient client = null; + private SimpleHttpServer server = null; + + // ------------------------------------------------------------ Constructor + public TestBadResponseHeader(String testName) { + super(testName); + } + + // ------------------------------------------------------------------- Main + public static void main(String args[]) { + String[] testCaseName = { TestBadResponseHeader.class.getName()}; + junit.textui.TestRunner.main(testCaseName); + } + + // ------------------------------------------------------- TestCase Methods + + public static Test suite() { + return new TestSuite(TestBadResponseHeader.class); + } + + // ----------------------------------------------------------- Test Methods + + public void setUp() throws IOException { + /* + * uncomment to enable wire log + */ + + System.setProperty( + "org.apache.commons.logging.Log", + "org.apache.commons.logging.impl.SimpleLog"); + System.setProperty( + "org.apache.commons.logging.simplelog.showdatetime", + "true"); + System.setProperty( + "org.apache.commons.logging.simplelog.log.httpclient.wire", + "debug"); + System.setProperty( + "org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient", + "debug"); + + client = new HttpClient(); + + server = new SimpleHttpServer(); // use arbitrary port + server.setRequestHandler(new MyHttpRequestHandler()); + } + + public void tearDown() throws IOException { + client = null; + + server.destroy(); + } + + /** + * HttpClient connects to the test server and performs a + * request. + * + * The server responds to the request and sends a HTTP/1.0 200 OK + * followed by a Header with infinite number of data. + * + * Expected behavior: + * HTTPClient should detect that the header line is too long and + * throw a HttpException. + * + * @throws IOException + */ + public void testLongHeaderLine() throws IOException { + client.getParams().makeLenient(); + + final long waitMax = 3 * 1000; // [ms] + FetchJob fj = + new FetchJob( + client, + "http://" + + server.getLocalAddress() + + ":" + + server.getLocalPort() + + "/long_line"); + + try { + TimeoutController.execute(fj, waitMax); + } catch (TimeoutController.TimeoutException e) { + throw new IOTimeoutException("FetchJob timeout", e); + } + + Throwable t = fj.getThrowable(); + if (t != null) { + if (t instanceof HttpException) { + LOG.info("Received expected HttpException", t); + return; + } + fail("Unexpected error in testPort/FetchJob: " + t.toString()); + } else { + fail("Did not receive expected HttpException"); + } + } + + /** + * HttpClient connects to the test server and performs a + * request. + * + * The server responds to the request and sends a HTTP/1.0 200 OK + * followed by an infinite number of Headers. + * + * Expected behavior: + * HTTPClient should detect that too many headers were received and + * throw a HttpException. + * + * @throws IOException + */ + public void testInfiniteHeaderLines() throws IOException { + client.getParams().makeLenient(); + + final long waitMax = 3 * 1000; // [ms] + FetchJob fj = + new FetchJob( + client, + "http://" + + server.getLocalAddress() + + ":" + + server.getLocalPort() + + "/infinite_lines"); + + try { + TimeoutController.execute(fj, waitMax); + } catch (TimeoutController.TimeoutException e) { + throw new IOTimeoutException("FetchJob timeout", e); + } + + Throwable t = fj.getThrowable(); + if (t != null) { + if (t instanceof HttpException) { + LOG.info("Received expected HttpException", t); + return; + } + fail("Unexpected error in testPort/FetchJob: " + t.toString()); + } else { + fail("Did not receive expected HttpException"); + } + } + + /** + * HttpClient connects to the test server and performs a + * request. + * + * The server responds to the request and sends a HTTP/1.0 200 OK + * followed by a Header with infinite number of folded lines. + * + * Expected behavior: + * HTTPClient should detect that the Header is too long and + * throw a HttpException. + * + * @throws IOException + */ + public void testInfinitelyFoldedHeaderLine() throws IOException { + client.getParams().makeLenient(); + + final long waitMax = 3 * 1000; // [ms] + FetchJob fj = + new FetchJob( + client, + "http://" + + server.getLocalAddress() + + ":" + + server.getLocalPort() + + "/infinitely_folded_header"); + + try { + TimeoutController.execute(fj, waitMax); + } catch (TimeoutController.TimeoutException e) { + throw new IOTimeoutException("FetchJob timeout", e); + } + + Throwable t = fj.getThrowable(); + if (t != null) { + if (t instanceof HttpException) { + LOG.info("Received expected HttpException", t); + return; + } + fail("Unexpected error in testPort/FetchJob: " + t.toString()); + } else { + fail("Did not receive expected HttpException"); + } + } + + /* + public void testForDebuggingOnly() + throws InterruptedException { + while (server.isRunning()) { + Thread.sleep(100); + } + } + */ + + private class MyHttpRequestHandler implements HttpRequestHandler { + public boolean processRequest(SimpleHttpServerConnection conn) + throws IOException { + RequestLine requestLine = conn.getRequestLine(); + ResponseWriter out = conn.getWriter(); + if ("GET".equals(requestLine.getMethod())) { + + if ("/long_line".equals(requestLine.getUri())) { + out.println("HTTP/1.1 200 OK"); + out.println("Content-Type: text/html"); + out.print("Nonsense: "); + while (true) { + out.print("12345"); + out.flush(); + } + } else if ("/infinite_lines".equals(requestLine.getUri())) { + out.println("HTTP/1.1 200 OK"); + out.println("Content-Type: text/html"); + while (true) { + out.println("Nonsense: 12345"); + out.flush(); + } + } else if ("/infinitely_folded_header".equals(requestLine.getUri())) { + out.println("HTTP/1.1 200 OK"); + out.println("Content-Type: text/html"); + out.print("Nonsense: "); + while (true) { + for(int i=0;i<8;i++) { + out.print("0123456789"); + } + out.println(); + out.flush(); + out.print(" "); + } + } + } + + return false; + } + } + + private class FetchJob implements Runnable { + private Throwable throwable = null; + private HttpClient client; + private String uri; + + public FetchJob(HttpClient client, String uri) { + this.client = client; + this.uri = uri; + } + + public Throwable getThrowable() { + return throwable; + } + + public void run() { + GetMethod method = null; + try { + method = new GetMethod(uri); + client.executeMethod(method); + } catch (Throwable t) { + throwable = t; + } finally { + if (method != null) { + method.releaseConnection(); + } + } + } + } + +}