Home | History | Annotate | Download | only in huc
      1 /*
      2  * Copyright (C) 2014 Square, Inc.
      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 package com.squareup.okhttp.internal.huc;
     17 
     18 import com.squareup.okhttp.AbstractResponseCache;
     19 import com.squareup.okhttp.OkHttpClient;
     20 import com.squareup.okhttp.OkUrlFactory;
     21 import com.squareup.okhttp.internal.Internal;
     22 import com.squareup.okhttp.internal.SslContextBuilder;
     23 import com.squareup.okhttp.mockwebserver.MockResponse;
     24 import com.squareup.okhttp.mockwebserver.MockWebServer;
     25 import com.squareup.okhttp.testing.RecordingHostnameVerifier;
     26 import java.io.IOException;
     27 import java.net.CacheRequest;
     28 import java.net.CacheResponse;
     29 import java.net.HttpURLConnection;
     30 import java.net.ResponseCache;
     31 import java.net.URI;
     32 import java.net.URL;
     33 import java.net.URLConnection;
     34 import java.nio.charset.StandardCharsets;
     35 import java.util.Collections;
     36 import java.util.List;
     37 import java.util.Map;
     38 import javax.net.ssl.HostnameVerifier;
     39 import javax.net.ssl.HttpsURLConnection;
     40 import javax.net.ssl.SSLContext;
     41 import okio.Buffer;
     42 import org.junit.After;
     43 import org.junit.Before;
     44 import org.junit.Test;
     45 
     46 import static org.junit.Assert.assertArrayEquals;
     47 import static org.junit.Assert.assertEquals;
     48 import static org.junit.Assert.assertFalse;
     49 import static org.junit.Assert.assertTrue;
     50 
     51 /**
     52  * A white-box test for {@link CacheAdapter}. See also:
     53  * <ul>
     54  *   <li>{@link ResponseCacheTest} for black-box tests that check that {@link ResponseCache}
     55  *   classes are called correctly by OkHttp.</li>
     56  *   <li>{@link JavaApiConverterTest} for tests that check Java API classes / OkHttp conversion
     57  *   logic. </li>
     58  * </ul>
     59  */
     60 public class CacheAdapterTest {
     61   private SSLContext sslContext = SslContextBuilder.localhost();
     62   private HostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
     63   private MockWebServer server;
     64   private OkHttpClient client;
     65   private HttpURLConnection connection;
     66 
     67   @Before public void setUp() throws Exception {
     68     server = new MockWebServer();
     69     client = new OkHttpClient();
     70   }
     71 
     72   @After public void tearDown() throws Exception {
     73     if (connection != null) {
     74       connection.disconnect();
     75     }
     76     server.shutdown();
     77   }
     78 
     79   @Test public void get_httpGet() throws Exception {
     80     final URL serverUrl = configureServer(new MockResponse());
     81     assertEquals("http", serverUrl.getProtocol());
     82 
     83     ResponseCache responseCache = new AbstractResponseCache() {
     84       @Override
     85       public CacheResponse get(URI uri, String method, Map<String, List<String>> headers) throws IOException {
     86         assertEquals(toUri(serverUrl), uri);
     87         assertEquals("GET", method);
     88         assertTrue("Arbitrary standard header not present", headers.containsKey("User-Agent"));
     89         assertEquals(Collections.singletonList("value1"), headers.get("key1"));
     90         return null;
     91       }
     92     };
     93     Internal.instance.setCache(client, new CacheAdapter(responseCache));
     94 
     95     connection = new OkUrlFactory(client).open(serverUrl);
     96     connection.setRequestProperty("key1", "value1");
     97 
     98     executeGet(connection);
     99   }
    100 
    101   @Test public void get_httpsGet() throws Exception {
    102     final URL serverUrl = configureHttpsServer(new MockResponse());
    103     assertEquals("https", serverUrl.getProtocol());
    104 
    105     ResponseCache responseCache = new AbstractResponseCache() {
    106       @Override public CacheResponse get(URI uri, String method, Map<String, List<String>> headers)
    107           throws IOException {
    108         assertEquals("https", uri.getScheme());
    109         assertEquals(toUri(serverUrl), uri);
    110         assertEquals("GET", method);
    111         assertTrue("Arbitrary standard header not present", headers.containsKey("User-Agent"));
    112         assertEquals(Collections.singletonList("value1"), headers.get("key1"));
    113         return null;
    114       }
    115     };
    116     Internal.instance.setCache(client, new CacheAdapter(responseCache));
    117     client.setSslSocketFactory(sslContext.getSocketFactory());
    118     client.setHostnameVerifier(hostnameVerifier);
    119 
    120     connection = new OkUrlFactory(client).open(serverUrl);
    121     connection.setRequestProperty("key1", "value1");
    122 
    123     executeGet(connection);
    124   }
    125 
    126   @Test public void put_httpGet() throws Exception {
    127     final String statusLine = "HTTP/1.1 200 Fantastic";
    128     final byte[] response = "ResponseString".getBytes(StandardCharsets.UTF_8);
    129     final URL serverUrl = configureServer(
    130         new MockResponse()
    131             .setStatus(statusLine)
    132             .addHeader("A", "c")
    133             .setBody(new Buffer().write(response)));
    134 
    135     ResponseCache responseCache = new AbstractResponseCache() {
    136       @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException {
    137         assertTrue(connection instanceof HttpURLConnection);
    138         assertFalse(connection instanceof HttpsURLConnection);
    139 
    140         assertEquals(response.length, connection.getContentLength());
    141 
    142         HttpURLConnection httpUrlConnection = (HttpURLConnection) connection;
    143         assertEquals("GET", httpUrlConnection.getRequestMethod());
    144         assertTrue(httpUrlConnection.getDoInput());
    145         assertFalse(httpUrlConnection.getDoOutput());
    146 
    147         assertEquals("Fantastic", httpUrlConnection.getResponseMessage());
    148         assertEquals(toUri(serverUrl), uri);
    149         assertEquals(serverUrl, connection.getURL());
    150         assertEquals("value", connection.getRequestProperty("key"));
    151 
    152         // Check retrieval by string key.
    153         assertEquals(statusLine, httpUrlConnection.getHeaderField(null));
    154         assertEquals("c", httpUrlConnection.getHeaderField("A"));
    155         // The RI and OkHttp supports case-insensitive matching for this method.
    156         assertEquals("c", httpUrlConnection.getHeaderField("a"));
    157         return null;
    158       }
    159     };
    160     Internal.instance.setCache(client, new CacheAdapter(responseCache));
    161 
    162     connection = new OkUrlFactory(client).open(serverUrl);
    163     connection.setRequestProperty("key", "value");
    164     executeGet(connection);
    165   }
    166 
    167   @Test public void put_httpPost() throws Exception {
    168     final String statusLine = "HTTP/1.1 200 Fantastic";
    169     final URL serverUrl = configureServer(
    170         new MockResponse()
    171             .setStatus(statusLine)
    172             .addHeader("A", "c"));
    173 
    174     ResponseCache responseCache = new AbstractResponseCache() {
    175       @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException {
    176         assertTrue(connection instanceof HttpURLConnection);
    177         assertFalse(connection instanceof HttpsURLConnection);
    178 
    179         assertEquals(0, connection.getContentLength());
    180 
    181         HttpURLConnection httpUrlConnection = (HttpURLConnection) connection;
    182         assertEquals("POST", httpUrlConnection.getRequestMethod());
    183         assertTrue(httpUrlConnection.getDoInput());
    184         assertTrue(httpUrlConnection.getDoOutput());
    185 
    186         assertEquals("Fantastic", httpUrlConnection.getResponseMessage());
    187         assertEquals(toUri(serverUrl), uri);
    188         assertEquals(serverUrl, connection.getURL());
    189         assertEquals("value", connection.getRequestProperty("key"));
    190 
    191         // Check retrieval by string key.
    192         assertEquals(statusLine, httpUrlConnection.getHeaderField(null));
    193         assertEquals("c", httpUrlConnection.getHeaderField("A"));
    194         // The RI and OkHttp supports case-insensitive matching for this method.
    195         assertEquals("c", httpUrlConnection.getHeaderField("a"));
    196         return null;
    197       }
    198     };
    199     Internal.instance.setCache(client, new CacheAdapter(responseCache));
    200 
    201     connection = new OkUrlFactory(client).open(serverUrl);
    202 
    203     executePost(connection);
    204   }
    205 
    206   @Test public void put_httpsGet() throws Exception {
    207     final URL serverUrl = configureHttpsServer(new MockResponse());
    208     assertEquals("https", serverUrl.getProtocol());
    209 
    210     ResponseCache responseCache = new AbstractResponseCache() {
    211       @Override public CacheRequest put(URI uri, URLConnection connection) throws IOException {
    212         assertTrue(connection instanceof HttpsURLConnection);
    213         assertEquals(toUri(serverUrl), uri);
    214         assertEquals(serverUrl, connection.getURL());
    215 
    216         HttpsURLConnection cacheHttpsUrlConnection = (HttpsURLConnection) connection;
    217         HttpsURLConnection realHttpsUrlConnection = (HttpsURLConnection) CacheAdapterTest.this.connection;
    218         assertEquals(realHttpsUrlConnection.getCipherSuite(),
    219             cacheHttpsUrlConnection.getCipherSuite());
    220         assertEquals(realHttpsUrlConnection.getPeerPrincipal(),
    221             cacheHttpsUrlConnection.getPeerPrincipal());
    222         assertArrayEquals(realHttpsUrlConnection.getLocalCertificates(),
    223             cacheHttpsUrlConnection.getLocalCertificates());
    224         assertArrayEquals(realHttpsUrlConnection.getServerCertificates(),
    225             cacheHttpsUrlConnection.getServerCertificates());
    226         assertEquals(realHttpsUrlConnection.getLocalPrincipal(),
    227             cacheHttpsUrlConnection.getLocalPrincipal());
    228         return null;
    229       }
    230     };
    231     Internal.instance.setCache(client, new CacheAdapter(responseCache));
    232     client.setSslSocketFactory(sslContext.getSocketFactory());
    233     client.setHostnameVerifier(hostnameVerifier);
    234 
    235     connection = new OkUrlFactory(client).open(serverUrl);
    236     executeGet(connection);
    237   }
    238 
    239   private void executeGet(HttpURLConnection connection) throws IOException {
    240     connection.connect();
    241     connection.getHeaderFields();
    242     connection.disconnect();
    243   }
    244 
    245   private void executePost(HttpURLConnection connection) throws IOException {
    246     connection.setDoOutput(true);
    247     connection.connect();
    248     connection.getOutputStream().write("Hello World".getBytes());
    249     connection.disconnect();
    250   }
    251 
    252   private URL configureServer(MockResponse mockResponse) throws Exception {
    253     server.enqueue(mockResponse);
    254     server.start();
    255     return server.getUrl("/");
    256   }
    257 
    258   private URL configureHttpsServer(MockResponse mockResponse) throws Exception {
    259     server.useHttps(sslContext.getSocketFactory(), false /* tunnelProxy */);
    260     server.enqueue(mockResponse);
    261     server.start();
    262     return server.getUrl("/");
    263   }
    264 }
    265