Home | History | Annotate | Download | only in http
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net.http;
     18 
     19 import com.google.mockwebserver.MockResponse;
     20 import com.google.mockwebserver.MockWebServer;
     21 import com.google.mockwebserver.RecordedRequest;
     22 import com.google.mockwebserver.SocketPolicy;
     23 import java.io.IOException;
     24 import java.io.InputStreamReader;
     25 import java.io.Reader;
     26 import java.io.StringWriter;
     27 import java.util.List;
     28 import junit.framework.TestCase;
     29 import libcore.javax.net.ssl.TestSSLContext;
     30 import org.apache.http.HttpHost;
     31 import org.apache.http.HttpRequest;
     32 import org.apache.http.HttpResponse;
     33 import org.apache.http.client.HttpClient;
     34 import org.apache.http.client.methods.HttpGet;
     35 import org.apache.http.conn.params.ConnRoutePNames;
     36 import org.apache.http.conn.params.ConnRouteParams;
     37 import org.apache.http.conn.scheme.Scheme;
     38 import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
     39 import org.apache.http.conn.ssl.SSLSocketFactory;
     40 
     41 public abstract class AbstractProxyTest extends TestCase {
     42 
     43     private MockWebServer server = new MockWebServer();
     44 
     45     protected abstract HttpClient newHttpClient();
     46 
     47     @Override protected void tearDown() throws Exception {
     48         System.clearProperty("proxyHost");
     49         System.clearProperty("proxyPort");
     50         System.clearProperty("http.proxyHost");
     51         System.clearProperty("http.proxyPort");
     52         System.clearProperty("https.proxyHost");
     53         System.clearProperty("https.proxyPort");
     54 
     55         server.shutdown();
     56         super.tearDown();
     57     }
     58 
     59     public void testConnectToHttps() throws Exception {
     60         TestSSLContext testSSLContext = TestSSLContext.create();
     61 
     62         server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
     63         server.enqueue(new MockResponse()
     64                 .setResponseCode(200)
     65                 .setBody("this response comes via HTTPS"));
     66         server.play();
     67 
     68         HttpClient httpClient = newHttpClient();
     69 
     70         SSLSocketFactory sslSocketFactory = newSslSocketFactory(testSSLContext);
     71         sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
     72         httpClient.getConnectionManager().getSchemeRegistry()
     73                 .register(new Scheme("https", sslSocketFactory, server.getPort()));
     74 
     75         HttpResponse response = httpClient.execute(
     76                 new HttpGet("https://localhost:" + server.getPort() + "/foo"));
     77         assertEquals("this response comes via HTTPS", contentToString(response));
     78 
     79         RecordedRequest request = server.takeRequest();
     80         assertEquals("GET /foo HTTP/1.1", request.getRequestLine());
     81     }
     82 
     83     private SSLSocketFactory newSslSocketFactory(TestSSLContext testSSLContext) throws Exception {
     84         // call through to Apache HTTP's non-public SSLSocketFactory constructor
     85         return SSLSocketFactory.class.getConstructor(javax.net.ssl.SSLSocketFactory.class)
     86                 .newInstance(testSSLContext.clientContext.getSocketFactory());
     87     }
     88 
     89     /**
     90      * We had bugs where proxy system properties weren't being honored.
     91      * http://b/3254717
     92      */
     93     public void testConnectViaProxyUsingProxySystemProperty() throws Exception {
     94         testConnectViaProxy(ProxyConfig.PROXY_SYSTEM_PROPERTY);
     95     }
     96 
     97     public void testConnectViaProxyUsingHttpProxySystemProperty() throws Exception {
     98         testConnectViaProxy(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY);
     99     }
    100 
    101     public void testConnectViaProxyUsingRequestParameter() throws Exception {
    102         testConnectViaProxy(ProxyConfig.REQUEST_PARAMETER);
    103     }
    104 
    105     public void testConnectViaProxyUsingClientParameter() throws Exception {
    106         testConnectViaProxy(ProxyConfig.CLIENT_PARAMETER);
    107     }
    108 
    109     /**
    110      * http://code.google.com/p/android/issues/detail?id=2690
    111      */
    112     private void testConnectViaProxy(ProxyConfig proxyConfig) throws Exception {
    113         MockResponse mockResponse = new MockResponse()
    114                 .setResponseCode(200)
    115                 .setBody("this response comes via a proxy");
    116         server.enqueue(mockResponse);
    117         server.play();
    118 
    119         HttpClient httpProxyClient = newHttpClient();
    120 
    121         HttpGet request = new HttpGet("http://android.com/foo");
    122         proxyConfig.configure(server, httpProxyClient, request);
    123 
    124         HttpResponse response = httpProxyClient.execute(request);
    125         assertEquals("this response comes via a proxy", contentToString(response));
    126 
    127         RecordedRequest get = server.takeRequest();
    128         assertEquals("GET http://android.com/foo HTTP/1.1", get.getRequestLine());
    129         assertContains(get.getHeaders(), "Host: android.com");
    130     }
    131 
    132     public void testConnectViaHttpProxyToHttpsUsingProxySystemProperty() throws Exception {
    133         testConnectViaHttpProxyToHttps(ProxyConfig.PROXY_SYSTEM_PROPERTY);
    134     }
    135 
    136     public void testConnectViaHttpProxyToHttpsUsingHttpsProxySystemProperty() throws Exception {
    137         testConnectViaHttpProxyToHttps(ProxyConfig.HTTPS_PROXY_SYSTEM_PROPERTY);
    138     }
    139 
    140     public void testConnectViaHttpProxyToHttpsUsingClientParameter() throws Exception {
    141         testConnectViaHttpProxyToHttps(ProxyConfig.CLIENT_PARAMETER);
    142     }
    143 
    144     public void testConnectViaHttpProxyToHttpsUsingRequestParameter() throws Exception {
    145         testConnectViaHttpProxyToHttps(ProxyConfig.REQUEST_PARAMETER);
    146     }
    147 
    148     private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exception {
    149         TestSSLContext testSSLContext = TestSSLContext.create();
    150 
    151         server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
    152         server.enqueue(new MockResponse()
    153                 .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
    154                 .clearHeaders());
    155         server.enqueue(new MockResponse()
    156                 .setResponseCode(200)
    157                 .setBody("this response comes via a secure proxy"));
    158         server.play();
    159 
    160         HttpClient httpProxyClient = newHttpClient();
    161         SSLSocketFactory sslSocketFactory = newSslSocketFactory(testSSLContext);
    162         sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
    163         httpProxyClient.getConnectionManager().getSchemeRegistry()
    164                 .register(new Scheme("https", sslSocketFactory, 443));
    165 
    166         HttpGet request = new HttpGet("https://android.com/foo");
    167         proxyConfig.configure(server, httpProxyClient, request);
    168 
    169         HttpResponse response = httpProxyClient.execute(request);
    170         assertEquals("this response comes via a secure proxy", contentToString(response));
    171 
    172         RecordedRequest connect = server.takeRequest();
    173         assertEquals("Connect line failure on proxy " + proxyConfig,
    174                 "CONNECT android.com:443 HTTP/1.1", connect.getRequestLine());
    175         assertContains(connect.getHeaders(), "Host: android.com");
    176 
    177         RecordedRequest get = server.takeRequest();
    178         assertEquals("GET /foo HTTP/1.1", get.getRequestLine());
    179         assertContains(get.getHeaders(), "Host: android.com");
    180     }
    181 
    182     public void testClientParamPreferredOverSystemProperty() throws Exception {
    183         testParamPreferredOverSystemProperty(ProxyConfig.CLIENT_PARAMETER);
    184     }
    185 
    186     public void testRequestParamPreferredOverSystemProperty() throws Exception {
    187         testParamPreferredOverSystemProperty(ProxyConfig.REQUEST_PARAMETER);
    188     }
    189 
    190     private void testParamPreferredOverSystemProperty(ProxyConfig proxyConfig) throws Exception {
    191         server.enqueue(new MockResponse().setBody("Via request parameter proxy!"));
    192         server.play();
    193         System.setProperty("http.proxyHost", "proxy.foo");
    194         System.setProperty("http.proxyPort", "8080");
    195 
    196         HttpClient client = newHttpClient();
    197         HttpGet request = new HttpGet("http://origin.foo/bar");
    198         proxyConfig.configure(server, client, request);
    199         HttpResponse response = client.execute(request);
    200         assertEquals("Via request parameter proxy!", contentToString(response));
    201 
    202         RecordedRequest recordedRequest = server.takeRequest();
    203         assertEquals("GET http://origin.foo/bar HTTP/1.1", recordedRequest.getRequestLine());
    204     }
    205 
    206     public void testExplicitNoProxyCancelsSystemProperty() throws Exception {
    207         server.enqueue(new MockResponse().setBody("Via the origin server!"));
    208         server.play();
    209         System.setProperty("http.proxyHost", "proxy.foo");
    210         System.setProperty("http.proxyPort", "8080");
    211 
    212         HttpClient client = newHttpClient();
    213         HttpGet request = new HttpGet(server.getUrl("/bar").toURI());
    214         request.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, ConnRouteParams.NO_HOST);
    215         HttpResponse response = client.execute(request);
    216         assertEquals("Via the origin server!", contentToString(response));
    217 
    218         RecordedRequest recordedRequest = server.takeRequest();
    219         assertEquals("GET /bar HTTP/1.1", recordedRequest.getRequestLine());
    220     }
    221 
    222     // http://b/5372438
    223     public void testRetryWithProxy() throws Exception {
    224         server.enqueue(new MockResponse()
    225                 .setSocketPolicy(SocketPolicy.DISCONNECT_AT_START));
    226         server.play();
    227 
    228         HttpClient httpProxyClient = newHttpClient();
    229         HttpGet request = new HttpGet("http://android.com/foo");
    230         ProxyConfig.REQUEST_PARAMETER.configure(server, httpProxyClient, request);
    231 
    232         try {
    233             httpProxyClient.execute(request);
    234             fail();
    235         } catch (IOException expected) {
    236         }
    237     }
    238 
    239     enum ProxyConfig {
    240         PROXY_SYSTEM_PROPERTY() {
    241             @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
    242                 System.setProperty("proxyHost", "localhost");
    243                 System.setProperty("proxyPort", Integer.toString(server.getPort()));
    244             }
    245         },
    246         HTTP_PROXY_SYSTEM_PROPERTY() {
    247             @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
    248                 System.setProperty("http.proxyHost", "localhost");
    249                 System.setProperty("http.proxyPort", Integer.toString(server.getPort()));
    250             }
    251         },
    252         HTTPS_PROXY_SYSTEM_PROPERTY() {
    253             @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
    254                 System.setProperty("https.proxyHost", "localhost");
    255                 System.setProperty("https.proxyPort", Integer.toString(server.getPort()));
    256             }
    257         },
    258         CLIENT_PARAMETER() {
    259             @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
    260                 client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
    261                         new HttpHost("localhost", server.getPort()));
    262             }
    263         },
    264         REQUEST_PARAMETER() {
    265             @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
    266                 request.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
    267                         new HttpHost("localhost", server.getPort()));
    268             }
    269         };
    270 
    271         abstract void configure(MockWebServer proxy, HttpClient client, HttpRequest request);
    272     }
    273 
    274     private void assertContains(List<String> headers, String header) {
    275         assertTrue(headers.toString(), headers.contains(header));
    276     }
    277 
    278     private String contentToString(HttpResponse response) throws IOException {
    279         StringWriter writer = new StringWriter();
    280         char[] buffer = new char[1024];
    281         Reader reader = new InputStreamReader(response.getEntity().getContent());
    282         int length;
    283         while ((length = reader.read(buffer)) != -1) {
    284             writer.write(buffer, 0, length);
    285         }
    286         reader.close();
    287         return writer.toString();
    288     }
    289 }
    290