1   /*
2    * $HeadURL: http://svn.apache.org/repos/asf/jakarta/commons/proper/httpclient/trunk/src/test/org/apache/commons/httpclient/TestBadContentLength.java $
3    * $Revision: 201862 $
4    * $Date: 2005-06-26 11:03:07 -0400 (Sun, 26 Jun 2005) $
5    * ====================================================================
6    *
7    *  Copyright 1999-2004 The Apache Software Foundation
8    *
9    *  Licensed under the Apache License, Version 2.0 (the "License");
10   *  you may not use this file except in compliance with the License.
11   *  You may obtain a copy of the License at
12   *
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   *
15   *  Unless required by applicable law or agreed to in writing, software
16   *  distributed under the License is distributed on an "AS IS" BASIS,
17   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   *  See the License for the specific language governing permissions and
19   *  limitations under the License.
20   * ====================================================================
21   *
22   * This software consists of voluntary contributions made by many
23   * individuals on behalf of the Apache Software Foundation.  For more
24   * information on the Apache Software Foundation, please see
25   * <http://www.apache.org/>.
26   *
27   */
28  package org.apache.commons.httpclient;
29  
30  import java.io.IOException;
31  import java.io.InputStream;
32  
33  import junit.framework.Test;
34  import junit.framework.TestCase;
35  import junit.framework.TestSuite;
36  
37  import org.apache.commons.httpclient.methods.GetMethod;
38  import org.apache.commons.httpclient.server.HttpRequestHandler;
39  import org.apache.commons.httpclient.server.RequestLine;
40  import org.apache.commons.httpclient.server.ResponseWriter;
41  import org.apache.commons.httpclient.server.SimpleHttpServer;
42  import org.apache.commons.httpclient.server.SimpleHttpServerConnection;
43  import org.apache.commons.httpclient.server.SimpleRequest;
44  
45  /***
46   * Tests HttpClient's behaviour when receiving more response data than expected.
47   * <p>
48   * A very simple HTTP Server will be setup on a free port during testing, which
49   * returns an incorrect response Content-Length, sending surplus response data,
50   * which may contain malicious/fake response headers.
51   * </p> 
52   * 
53   * @author Christian Kohlschuetter
54   * @version $Id: TestBadContentLength.java 201862 2005-06-26 15:03:07Z olegk $
55   */
56  public class TestBadContentLength extends TestCase {
57      private HttpClient client = null;
58      private SimpleHttpServer server = null;
59  
60      // ------------------------------------------------------------ Constructor
61      public TestBadContentLength(String testName) {
62          super(testName);
63      }
64  
65      // ------------------------------------------------------------------- Main
66      public static void main(String args[]) {
67          String[] testCaseName = { TestBadContentLength.class.getName()};
68          junit.textui.TestRunner.main(testCaseName);
69      }
70  
71      // ------------------------------------------------------- TestCase Methods
72  
73      public static Test suite() {
74          return new TestSuite(TestBadContentLength.class);
75      }
76  
77      // ----------------------------------------------------------- Test Methods
78  
79      public void setUp() throws IOException {
80          client = new HttpClient();
81          server = new SimpleHttpServer(); // use arbitrary port
82          server.setTestname(getName());
83          server.setRequestHandler(new MyHttpRequestHandler());
84      }
85  
86      public void tearDown() throws IOException {
87          client = null;
88  
89          server.destroy();
90      }
91  
92      /***
93       * HttpClient connects to the test server and performs two subsequent
94       * requests to the same URI in <u>lenient</u> mode.
95       * 
96       * Expected behavior:
97       * For both requests, status code 200 and a response body of "12345"
98       * should be returned.
99       *
100      * @throws IOException
101      */
102     public void test1Lenient() throws IOException {
103     	client.getParams().makeLenient();
104     	
105         GetMethod m =
106             new GetMethod("http://localhost:" + server.getLocalPort() + "/");
107 
108         client.executeMethod(m);
109         assertEquals(200, m.getStatusCode());
110         assertEquals("12345", m.getResponseBodyAsString());
111 
112         m = new GetMethod("http://localhost:" + server.getLocalPort() + "/");
113 
114         client.executeMethod(m);
115         assertEquals(200, m.getStatusCode());
116         assertEquals("12345", m.getResponseBodyAsString());
117         m.releaseConnection();
118     }
119 
120     /***
121      * HttpClient connects to the test server and performs two subsequent
122      * requests to the same URI in <u>strict</u> mode.
123      * <p>
124      * The first response body will be read with getResponseBodyAsString(),
125      * which returns null if an error occured.
126      * </p>
127      * <p>
128      * The second response body will be read using an InputStream, which
129      * throws an IOException if something went wrong.
130      * </p>
131      * Expected behavior:
132      * For both requests, status code 200 should be returned.<br />
133      * For request 1, a <code>null</code> response body should be returned.<br />
134      * For request 2, a {@link ProtocolException} is expected.
135      *
136      * @throws IOException
137      */
138     public void test1Strict() throws IOException {
139         client.getParams().makeStrict();
140 
141         GetMethod m =
142             new GetMethod("http://localhost:" + server.getLocalPort() + "/");
143 
144         client.executeMethod(m);
145         assertEquals(200, m.getStatusCode());
146         assertEquals("12345", m.getResponseBodyAsString());
147 
148         m = new GetMethod("http://localhost:" + server.getLocalPort() + "/");
149 
150         client.executeMethod(m);
151         assertEquals(200, m.getStatusCode());
152 
153         InputStream in = m.getResponseBodyAsStream();
154         while (in.read() != -1) {
155         }
156 
157         m.releaseConnection();
158     }
159 
160     public void enableThisTestForDebuggingOnly()
161         throws InterruptedException {
162         while (server.isRunning()) {
163             Thread.sleep(100);
164         }
165     }
166 
167     private class MyHttpRequestHandler implements HttpRequestHandler {
168         private int requestNo = 0;
169 
170         public boolean processRequest(
171             final SimpleHttpServerConnection conn,
172             final SimpleRequest request) throws IOException
173         {
174         	RequestLine requestLine = request.getRequestLine();
175         	ResponseWriter out = conn.getWriter();
176             if ("GET".equals(requestLine.getMethod())
177                 && "/".equals(requestLine.getUri())) {
178 
179                 requestNo++;
180 
181                 out.println("HTTP/1.1 200 OK");
182                 out.println("Content-Type: text/html");
183                 out.println("Content-Length: 5");
184                 out.println("Connection: keep-alive");
185                 out.println();
186                 out.println("12345"); // send exactly 5 bytes
187 
188                 // and some more garbage!
189                 out.println("AND SOME MORE\r\nGARBAGE!");
190                 out.println("HTTP/1.0 404 Not Found");
191                 out.println("Content-Type: text/plain");
192                 out.println("");
193                 out.println("THIS-IS-A-FAKE-RESPONSE!");
194 
195                 out.flush();
196                 // process max. 2 subsequents requests per connection
197                 if (requestNo < 2) {
198                     conn.setKeepAlive(true);
199                 }
200             }
201             return true;
202         }
203     }
204 
205 }