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
17package android.net.http;
18
19import java.io.IOException;
20import java.io.InputStreamReader;
21import java.io.Reader;
22import java.io.StringWriter;
23import java.util.Arrays;
24import java.util.List;
25import junit.framework.TestCase;
26import libcore.javax.net.ssl.TestSSLContext;
27import org.apache.http.HttpHost;
28import org.apache.http.HttpResponse;
29import org.apache.http.client.HttpClient;
30import org.apache.http.client.methods.HttpGet;
31import org.apache.http.conn.params.ConnRoutePNames;
32import org.apache.http.conn.scheme.Scheme;
33import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
34import org.apache.http.conn.ssl.SSLSocketFactory;
35import org.apache.http.impl.client.DefaultHttpClient;
36import tests.http.MockResponse;
37import tests.http.MockWebServer;
38import tests.http.RecordedRequest;
39
40public class HttpsThroughHttpProxyTest extends TestCase {
41
42    public void testConnectViaHttps() throws IOException, InterruptedException {
43        TestSSLContext testSSLContext = TestSSLContext.create();
44
45        MockWebServer server = new MockWebServer();
46        server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
47        server.enqueue(new MockResponse()
48                .setResponseCode(200)
49                .setBody("this response comes via HTTPS"));
50        server.play();
51
52        HttpClient httpClient = new DefaultHttpClient();
53        SSLSocketFactory sslSocketFactory = new SSLSocketFactory(
54                testSSLContext.clientContext.getSocketFactory());
55        sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
56        httpClient.getConnectionManager().getSchemeRegistry()
57                .register(new Scheme("https", sslSocketFactory, server.getPort()));
58
59        HttpResponse response = httpClient.execute(
60                new HttpGet("https://localhost:" + server.getPort() + "/foo"));
61        assertEquals("this response comes via HTTPS", contentToString(response));
62
63        RecordedRequest request = server.takeRequest();
64        assertEquals("GET /foo HTTP/1.1", request.getRequestLine());
65    }
66
67    /**
68     * http://code.google.com/p/android/issues/detail?id=2690
69     */
70    public void testConnectViaProxy() throws IOException, InterruptedException {
71        MockWebServer proxy = new MockWebServer();
72        MockResponse mockResponse = new MockResponse()
73                .setResponseCode(200)
74                .setBody("this response comes via a proxy");
75        proxy.enqueue(mockResponse);
76        proxy.play();
77
78        HttpClient httpProxyClient = new DefaultHttpClient();
79        httpProxyClient.getParams().setParameter(
80                ConnRoutePNames.DEFAULT_PROXY, new HttpHost("localhost", proxy.getPort()));
81
82        HttpResponse response = httpProxyClient.execute(new HttpGet("http://android.com/foo"));
83        assertEquals("this response comes via a proxy", contentToString(response));
84
85        RecordedRequest request = proxy.takeRequest();
86        assertEquals("GET http://android.com/foo HTTP/1.1", request.getRequestLine());
87        assertContains(request.getHeaders(), "Host: android.com");
88    }
89
90    public void testConnectViaHttpProxyToHttps() throws IOException, InterruptedException {
91        TestSSLContext testSSLContext = TestSSLContext.create();
92
93        MockWebServer proxy = new MockWebServer();
94        proxy.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
95        MockResponse connectResponse = new MockResponse()
96                .setResponseCode(200);
97        connectResponse.getHeaders().clear();
98        proxy.enqueue(connectResponse);
99        proxy.enqueue(new MockResponse()
100                .setResponseCode(200)
101                .setBody("this response comes via a secure proxy"));
102        proxy.play();
103
104        HttpClient httpProxyClient = new DefaultHttpClient();
105        HttpHost proxyHost = new HttpHost("localhost", proxy.getPort());
106        httpProxyClient.getParams().setParameter(
107                ConnRoutePNames.DEFAULT_PROXY, proxyHost);
108        SSLSocketFactory sslSocketFactory = new SSLSocketFactory(
109                testSSLContext.clientContext.getSocketFactory());
110        sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
111        httpProxyClient.getConnectionManager().getSchemeRegistry()
112                .register(new Scheme("https", sslSocketFactory, 443));
113
114        HttpResponse response = httpProxyClient.execute(new HttpGet("https://android.com/foo"));
115        assertEquals("this response comes via a secure proxy", contentToString(response));
116
117        RecordedRequest connect = proxy.takeRequest();
118        assertEquals("Connect line failure on proxy " + proxyHost.toHostString(),
119                "CONNECT android.com:443 HTTP/1.1", connect.getRequestLine());
120        assertContains(connect.getHeaders(), "Host: android.com");
121
122        RecordedRequest get = proxy.takeRequest();
123        assertEquals("GET /foo HTTP/1.1", get.getRequestLine());
124        assertContains(get.getHeaders(), "Host: android.com");
125    }
126
127    private void assertContains(List<String> headers, String header) {
128        assertTrue(headers.toString(), headers.contains(header));
129    }
130
131    private String contentToString(HttpResponse response) throws IOException {
132        StringWriter writer = new StringWriter();
133        char[] buffer = new char[1024];
134        Reader reader = new InputStreamReader(response.getEntity().getContent());
135        int length;
136        while ((length = reader.read(buffer)) != -1) {
137            writer.write(buffer, 0, length);
138        }
139        reader.close();
140        return writer.toString();
141    }
142}
143