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 
newHttpClient()45     protected abstract HttpClient newHttpClient();
46 
tearDown()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 
testConnectToHttps()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 
newSslSocketFactory(TestSSLContext testSSLContext)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      */
testConnectViaProxyUsingProxySystemProperty()93     public void testConnectViaProxyUsingProxySystemProperty() throws Exception {
94         testConnectViaProxy(ProxyConfig.PROXY_SYSTEM_PROPERTY);
95     }
96 
testConnectViaProxyUsingHttpProxySystemProperty()97     public void testConnectViaProxyUsingHttpProxySystemProperty() throws Exception {
98         testConnectViaProxy(ProxyConfig.HTTP_PROXY_SYSTEM_PROPERTY);
99     }
100 
testConnectViaProxyUsingRequestParameter()101     public void testConnectViaProxyUsingRequestParameter() throws Exception {
102         testConnectViaProxy(ProxyConfig.REQUEST_PARAMETER);
103     }
104 
testConnectViaProxyUsingClientParameter()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      */
testConnectViaProxy(ProxyConfig proxyConfig)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 
testConnectViaHttpProxyToHttpsUsingProxySystemProperty()132     public void testConnectViaHttpProxyToHttpsUsingProxySystemProperty() throws Exception {
133         testConnectViaHttpProxyToHttps(ProxyConfig.PROXY_SYSTEM_PROPERTY);
134     }
135 
testConnectViaHttpProxyToHttpsUsingHttpsProxySystemProperty()136     public void testConnectViaHttpProxyToHttpsUsingHttpsProxySystemProperty() throws Exception {
137         testConnectViaHttpProxyToHttps(ProxyConfig.HTTPS_PROXY_SYSTEM_PROPERTY);
138     }
139 
testConnectViaHttpProxyToHttpsUsingClientParameter()140     public void testConnectViaHttpProxyToHttpsUsingClientParameter() throws Exception {
141         testConnectViaHttpProxyToHttps(ProxyConfig.CLIENT_PARAMETER);
142     }
143 
testConnectViaHttpProxyToHttpsUsingRequestParameter()144     public void testConnectViaHttpProxyToHttpsUsingRequestParameter() throws Exception {
145         testConnectViaHttpProxyToHttps(ProxyConfig.REQUEST_PARAMETER);
146     }
147 
testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig)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 
testClientParamPreferredOverSystemProperty()182     public void testClientParamPreferredOverSystemProperty() throws Exception {
183         testParamPreferredOverSystemProperty(ProxyConfig.CLIENT_PARAMETER);
184     }
185 
testRequestParamPreferredOverSystemProperty()186     public void testRequestParamPreferredOverSystemProperty() throws Exception {
187         testParamPreferredOverSystemProperty(ProxyConfig.REQUEST_PARAMETER);
188     }
189 
testParamPreferredOverSystemProperty(ProxyConfig proxyConfig)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 
testExplicitNoProxyCancelsSystemProperty()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
testRetryWithProxy()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 {
PROXY_SYSTEM_PROPERTY()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         },
HTTP_PROXY_SYSTEM_PROPERTY()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         },
HTTPS_PROXY_SYSTEM_PROPERTY()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         },
CLIENT_PARAMETER()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         },
REQUEST_PARAMETER()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 
configure(MockWebServer proxy, HttpClient client, HttpRequest request)271         abstract void configure(MockWebServer proxy, HttpClient client, HttpRequest request);
272     }
273 
assertContains(List<String> headers, String header)274     private void assertContains(List<String> headers, String header) {
275         assertTrue(headers.toString(), headers.contains(header));
276     }
277 
contentToString(HttpResponse response)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