    1   /*
    2    * ====================================================================
    3    *
    4    *  Licensed to the Apache Software Foundation (ASF) under one or more
    5    *  contributor license agreements.  See the NOTICE file distributed with
    6    *  this work for additional information regarding copyright ownership.
    7    *  The ASF licenses this file to You under the Apache License, Version 2.0
    8    *  (the "License"); you may not use this file except in compliance with
    9    *  the License.  You may obtain a copy of the License at
    10   *
    11   *      http://www.apache.org/licenses/LICENSE-2.0
    12   *
    13   *  Unless required by applicable law or agreed to in writing, software
    14   *  distributed under the License is distributed on an "AS IS" BASIS,
    15   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16   *  See the License for the specific language governing permissions and
    17   *  limitations under the License.
    18   * ====================================================================
    19   *
    20   * This software consists of voluntary contributions made by many
    21   * individuals on behalf of the Apache Software Foundation.  For more
    22   * information on the Apache Software Foundation, please see
    23   * <http://www.apache.org/>.
    24   *
    25   * [Additional notices, if required by prior licensing conditions]
    26   *
    27   */
    28  package org.apache.commons.httpclient;
    29
    30  import java.io.IOException;
    31
    32  import junit.framework.*;
    33  import org.apache.commons.httpclient.methods.*;
    34  import org.apache.commons.httpclient.params.HttpMethodParams;
    35  import org.apache.commons.httpclient.server.HttpRequestHandler;
    36  import org.apache.commons.httpclient.server.ResponseWriter;
    37  import org.apache.commons.httpclient.server.SimpleHttpServerConnection;
    38  import org.apache.commons.httpclient.server.SimpleRequest;
    39
    40  /**
    41   * Tests handling of non-compliant responses.
    42   *
    43   * @author Oleg Kalnichevski
    44   * @author Jeff Dever
    45   */
    46  public class TestNoncompliant extends HttpClientTestBase {
    47
    48      public TestNoncompliant(String s) throws IOException {
    49          super(s);
    50      }
    51
    52      public static Test suite() {
    53          TestSuite suite = new TestSuite(TestNoncompliant.class);
    54          return suite;
    55      }
    56
    57      /**
    58       * Tests if client is able to recover gracefully when HTTP server or
    59       * proxy fails to send 100 status code when expected. The client should
    60       * resume sending the request body after a defined timeout without having
    61       * received "continue" code.
    62       */
    63      public void testNoncompliantPostMethodString() throws Exception {
    64          this.server.setRequestHandler(new HttpRequestHandler() {
    65              public boolean processRequest(SimpleHttpServerConnection conn,
    66                      SimpleRequest request) throws IOException {
    67                  ResponseWriter out = conn.getWriter();
    68                  out.println("HTTP/1.1 200 OK");
    69                  out.println("Connection: close");
    70                  out.println("Content-Length: 0");
    71                  out.println();
    72                  out.flush();
    73                  return true;
    74              }
    75          });
    76
    77          PostMethod method = new PostMethod("/");
    78          method.getParams().setBooleanParameter(
    79                  HttpMethodParams.USE_EXPECT_CONTINUE, true);
    80          method.setRequestEntity(new StringRequestEntity(
    81                  "This is data to be sent in the body of an HTTP POST.", null, null));
    82          client.executeMethod(method);
    83          assertEquals(200, method.getStatusCode());
    84      }
    85
    86      /**
    87       * Tests that a response status line containing \r and \n is handled.
    88       */
    89      public void testNoncompliantStatusLine() {
    90          this.server.setRequestHandler(new HttpRequestHandler() {
    91              public boolean processRequest(SimpleHttpServerConnection conn,
    92                      SimpleRequest request) throws IOException {
    93                  ResponseWriter out = conn.getWriter();
    94                  out.println("HTTP/1.1 444 This status message contains\n"
    95                          + " a newline and a\r"
    96                          + " carrage return but that should be OK.");
    97                  out.println("Connection: close");
    98                  out.println("Content-Length: 0");
    99                  out.println();
    100                 out.flush();
    101                 return true;
    102             }
    103         });
    104         GetMethod method = new GetMethod("/");
    105         try {
    106             client.executeMethod(method);
    107         } catch (Exception e) {
    108             e.printStackTrace();
    109             fail("Unexpected exception: " + e.toString());
    110         }
    111         assertEquals(444, method.getStatusCode());
    112     }
    113
    114     /**
    115      * Test if a response to HEAD method from non-compliant server that contains
    116      * an unexpected body content can be correctly redirected
    117      */
    118     public void testNoncompliantHeadWithResponseBody() throws Exception {
    119         final String body = "Test body";
    120         this.server.setRequestHandler(new HttpRequestHandler() {
    121             public boolean processRequest(SimpleHttpServerConnection conn,
    122                     SimpleRequest request) throws IOException {
    123                 ResponseWriter out = conn.getWriter();
    124                 out.println("HTTP/1.1 200 OK");
    125                 out.println("Connection: close");
    126                 out.println("Content-Length: " + body.length());
    127                 out.println();
    128                 out.print(body);
    129                 out.flush();
    130                 return true;
    131             }
    132         });
    133         HeadMethod method = new HeadMethod("/");
    134         method.getParams().setIntParameter(
    135                 HttpMethodParams.HEAD_BODY_CHECK_TIMEOUT, 50);
    136         client.executeMethod(method);
    137         assertEquals(200, method.getStatusCode());
    138         method.releaseConnection();
    139     }
    140
    141     /**
    142      * Test if a response to HEAD method from non-compliant server causes an
    143      * HttpException to be thrown
    144      */
    145     public void testNoncompliantHeadStrictMode() throws Exception {
    146         final String body = "Test body";
    147         this.server.setRequestHandler(new HttpRequestHandler() {
    148             public boolean processRequest(SimpleHttpServerConnection conn,
    149                     SimpleRequest request) throws IOException {
    150                 ResponseWriter out = conn.getWriter();
    151                 out.println("HTTP/1.1 200 OK");
    152                 out.println("Connection: close");
    153                 out.println("Content-Length: " + body.length());
    154                 out.println();
    155                 out.print(body);
    156                 out.flush();
    157                 return true;
    158             }
    159         });
    160         client.getParams().setBooleanParameter(
    161                 HttpMethodParams.REJECT_HEAD_BODY, true);
    162         HeadMethod method = new NoncompliantHeadMethod("/");
    163         method.getParams().setIntParameter(
    164                 HttpMethodParams.HEAD_BODY_CHECK_TIMEOUT, 50);
    165         try {
    166             client.executeMethod(method);
    167             fail("HttpException should have been thrown");
    168         } catch (HttpException e) {
    169             // Expected
    170         }
    171         method.releaseConnection();
    172     }
    173
    174     /**
    175      * Tests if client is able to handle gracefully malformed responses
    176      * that may not include response body.
    177      */
    178     public void testMalformed304Response() throws Exception {
    179         this.server.setRequestHandler(new HttpRequestHandler() {
    180             public boolean processRequest(SimpleHttpServerConnection conn,
    181                     SimpleRequest request) throws IOException {
    182                 conn.setSocketTimeout(20000);
    183                 ResponseWriter out = conn.getWriter();
    184                 out.println("HTTP/1.1 304 OK");
    185                 out.println("Connection: keep-alive");
    186                 out.println("Content-Length: 100");
    187                 out.println();
    188                 out.flush();
    189                 conn.setKeepAlive(true);
    190                 return true;
    191             }
    192         });
    193
    194         GetMethod method = new GetMethod("/");
    195         method.getParams().setSoTimeout(1000);
    196         client.executeMethod(method);
    197         assertEquals(HttpStatus.SC_NOT_MODIFIED, method.getStatusCode());
    198         method.getResponseBody();
    199     }
    200
    201     public void testMalformed204Response() throws Exception {
    202         this.server.setRequestHandler(new HttpRequestHandler() {
    203             public boolean processRequest(SimpleHttpServerConnection conn,
    204                     SimpleRequest request) throws IOException {
    205                 conn.setSocketTimeout(20000);
    206                 ResponseWriter out = conn.getWriter();
    207                 out.println("HTTP/1.1 204 OK");
    208                 out.println("Connection: close");
    209                 out.println("Content-Length: 100");
    210                 out.println();
    211                 out.flush();
    212                 conn.setKeepAlive(true);
    213                 return true;
    214             }
    215         });
    216
    217         GetMethod method = new GetMethod("/");
    218         method.getParams().setSoTimeout(1000);
    219         client.executeMethod(method);
    220         assertEquals(HttpStatus.SC_NO_CONTENT, method.getStatusCode());
    221         method.getResponseBody();
    222     }
    223
    224 }