AbstractProxyTest.java revision bf1df887d4b87f7da69cd4fe9306eb0d19166d52
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.List;
24import junit.framework.TestCase;
25import libcore.javax.net.ssl.TestSSLContext;
26import org.apache.http.HttpHost;
27import org.apache.http.HttpRequest;
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.params.ConnRouteParams;
33import org.apache.http.conn.scheme.Scheme;
34import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
35import org.apache.http.conn.ssl.SSLSocketFactory;
36import tests.http.MockResponse;
37import tests.http.MockWebServer;
38import tests.http.RecordedRequest;
39
40public abstract class AbstractProxyTest extends TestCase {
41
42    private MockWebServer server = new MockWebServer();
43
44    protected abstract HttpClient newHttpClient();
45
46    @Override protected void tearDown() throws Exception {
47        System.clearProperty("proxyHost");
48        System.clearProperty("proxyPort");
49        System.clearProperty("http.proxyHost");
50        System.clearProperty("http.proxyPort");
51        System.clearProperty("https.proxyHost");
52        System.clearProperty("https.proxyPort");
53
54        server.shutdown();
55        super.tearDown();
56    }
57
58    public void testConnectToHttps() throws Exception {
59        TestSSLContext testSSLContext = TestSSLContext.create();
60
61        server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
62        server.enqueue(new MockResponse()
63                .setResponseCode(200)
64                .setBody("this response comes via HTTPS"));
65        server.play();
66
67        HttpClient httpClient = newHttpClient();
68
69        SSLSocketFactory sslSocketFactory = newSslSocketFactory(testSSLContext);
70        sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
71        httpClient.getConnectionManager().getSchemeRegistry()
72                .register(new Scheme("https", sslSocketFactory, server.getPort()));
73
74        HttpResponse response = httpClient.execute(
75                new HttpGet("https://localhost:" + server.getPort() + "/foo"));
76        assertEquals("this response comes via HTTPS", contentToString(response));
77
78        RecordedRequest request = server.takeRequest();
79        assertEquals("GET /foo HTTP/1.1", request.getRequestLine());
80    }
81
82    private SSLSocketFactory newSslSocketFactory(TestSSLContext testSSLContext) throws Exception {
83        // call through to Apache HTTP's non-public SSLSocketFactory constructor
84        return SSLSocketFactory.class.getConstructor(javax.net.ssl.SSLSocketFactory.class)
85                .newInstance(testSSLContext.clientContext.getSocketFactory());
86    }
87
88    /**
89     * We had bugs where proxy system properties weren't being honored.
90     * http://b/3254717
91     */
92    public void testConnectViaProxyUsingProxySystemProperty() throws Exception {
93        testConnectViaProxy(ProxyConfig.PROXY_SYSTEM_PROPERTY);
94    }
95
96    public void testConnectViaProxyUsingHttpProxySystemProperty() throws Exception {
97        testConnectViaProxy(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY);
98    }
99
100    public void testConnectViaProxyUsingRequestParameter() throws Exception {
101        testConnectViaProxy(ProxyConfig.REQUEST_PARAMETER);
102    }
103
104    public void testConnectViaProxyUsingClientParameter() throws Exception {
105        testConnectViaProxy(ProxyConfig.CLIENT_PARAMETER);
106    }
107
108    /**
109     * http://code.google.com/p/android/issues/detail?id=2690
110     */
111    private void testConnectViaProxy(ProxyConfig proxyConfig) throws Exception {
112        MockResponse mockResponse = new MockResponse()
113                .setResponseCode(200)
114                .setBody("this response comes via a proxy");
115        server.enqueue(mockResponse);
116        server.play();
117
118        HttpClient httpProxyClient = newHttpClient();
119
120        HttpGet request = new HttpGet("http://android.com/foo");
121        proxyConfig.configure(server, httpProxyClient, request);
122
123        HttpResponse response = httpProxyClient.execute(request);
124        assertEquals("this response comes via a proxy", contentToString(response));
125
126        RecordedRequest get = server.takeRequest();
127        assertEquals("GET http://android.com/foo HTTP/1.1", get.getRequestLine());
128        assertContains(get.getHeaders(), "Host: android.com");
129    }
130
131    public void testConnectViaHttpProxyToHttpsUsingProxySystemProperty() throws Exception {
132        testConnectViaHttpProxyToHttps(ProxyConfig.PROXY_SYSTEM_PROPERTY);
133    }
134
135    public void testConnectViaHttpProxyToHttpsUsingHttpsProxySystemProperty() throws Exception {
136        testConnectViaHttpProxyToHttps(ProxyConfig.HTTPS_PROXY_SYSTEM_PROPERTY);
137    }
138
139    public void testConnectViaHttpProxyToHttpsUsingClientParameter() throws Exception {
140        testConnectViaHttpProxyToHttps(ProxyConfig.CLIENT_PARAMETER);
141    }
142
143    public void testConnectViaHttpProxyToHttpsUsingRequestParameter() throws Exception {
144        testConnectViaHttpProxyToHttps(ProxyConfig.REQUEST_PARAMETER);
145    }
146
147    private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exception {
148        TestSSLContext testSSLContext = TestSSLContext.create();
149
150        server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
151        MockResponse connectResponse = new MockResponse()
152                .setResponseCode(200);
153        connectResponse.getHeaders().clear();
154        server.enqueue(connectResponse);
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    enum ProxyConfig {
223        PROXY_SYSTEM_PROPERTY() {
224            @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
225                System.setProperty("proxyHost", "localhost");
226                System.setProperty("proxyPort", Integer.toString(server.getPort()));
227            }
228        },
229        HTTP_PROXY_SYSTEM_PROPERTY() {
230            @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
231                System.setProperty("http.proxyHost", "localhost");
232                System.setProperty("http.proxyPort", Integer.toString(server.getPort()));
233            }
234        },
235        HTTPS_PROXY_SYSTEM_PROPERTY() {
236            @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
237                System.setProperty("https.proxyHost", "localhost");
238                System.setProperty("https.proxyPort", Integer.toString(server.getPort()));
239            }
240        },
241        CLIENT_PARAMETER() {
242            @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
243                client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
244                        new HttpHost("localhost", server.getPort()));
245            }
246        },
247        REQUEST_PARAMETER() {
248            @Override void configure(MockWebServer server, HttpClient client, HttpRequest request) {
249                request.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
250                        new HttpHost("localhost", server.getPort()));
251            }
252        };
253
254        abstract void configure(MockWebServer proxy, HttpClient client, HttpRequest request);
255    }
256
257    private void assertContains(List<String> headers, String header) {
258        assertTrue(headers.toString(), headers.contains(header));
259    }
260
261    private String contentToString(HttpResponse response) throws IOException {
262        StringWriter writer = new StringWriter();
263        char[] buffer = new char[1024];
264        Reader reader = new InputStreamReader(response.getEntity().getContent());
265        int length;
266        while ((length = reader.read(buffer)) != -1) {
267            writer.write(buffer, 0, length);
268        }
269        reader.close();
270        return writer.toString();
271    }
272}
273