1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestBadContentLength.java,v 1.6 2004/02/27 19:01:33 olegk Exp $
3    * $Revision: 1.6 $
4    * $Date: 2004/02/27 19:01:33 $
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   * [Additional notices, if required by prior licensing conditions]
28   *
29   */
30  package org.apache.commons.httpclient;
31  
32  import java.io.IOException;
33  import java.io.InputStream;
34  
35  import junit.framework.Test;
36  import junit.framework.TestSuite;
37  
38  import org.apache.commons.httpclient.methods.GetMethod;
39  import org.apache.commons.httpclient.server.HttpRequestHandler;
40  import org.apache.commons.httpclient.server.RequestLine;
41  import org.apache.commons.httpclient.server.ResponseWriter;
42  import org.apache.commons.httpclient.server.SimpleHttpServer;
43  import org.apache.commons.httpclient.server.SimpleHttpServerConnection;
44  import org.apache.commons.httpclient.server.SimpleRequest;
45  
46  /***
47   * Tests HttpClient's behaviour when receiving more response data than expected.
48   * <p>
49   * A very simple HTTP Server will be setup on a free port during testing, which
50   * returns an incorrect response Content-Length, sending surplus response data,
51   * which may contain malicious/fake response headers.
52   * </p> 
53   * 
54   * @author Christian Kohlschuetter
55   * @version $Id: TestBadContentLength.java,v 1.6 2004/02/27 19:01:33 olegk Exp $
56   */
57  public class TestBadContentLength extends TestNoHost {
58      private HttpClient client = null;
59      private SimpleHttpServer server = null;
60  
61      // ------------------------------------------------------------ Constructor
62      public TestBadContentLength(String testName) {
63          super(testName);
64      }
65  
66      // ------------------------------------------------------------------- Main
67      public static void main(String args[]) {
68          String[] testCaseName = { TestBadContentLength.class.getName()};
69          junit.textui.TestRunner.main(testCaseName);
70      }
71  
72      // ------------------------------------------------------- TestCase Methods
73  
74      public static Test suite() {
75          return new TestSuite(TestBadContentLength.class);
76      }
77  
78      // ----------------------------------------------------------- Test Methods
79  
80      public void setUp() throws IOException {
81          client = new HttpClient();
82          server = new SimpleHttpServer(); // use arbitrary port
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.recycle();
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.recycle();
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.connectionKeepAlive();
199                 }
200             }
201             return true;
202         }
203     }
204 
205 }