1e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerpackage com.squareup.okhttp;
2e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
36c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport com.squareup.okhttp.internal.http.OkHeaders;
4ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubakerimport com.squareup.okhttp.internal.Platform;
5ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubakerimport com.squareup.okhttp.internal.URLFilter;
6ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubakerimport com.squareup.okhttp.internal.io.FileSystem;
771b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport com.squareup.okhttp.internal.io.InMemoryFileSystem;
8e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.mockwebserver.MockResponse;
9e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport com.squareup.okhttp.mockwebserver.MockWebServer;
1071b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fullerimport java.io.File;
11e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.io.IOException;
12e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.net.HttpURLConnection;
13ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubakerimport java.net.URL;
14e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.text.DateFormat;
15e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.text.SimpleDateFormat;
16e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.Date;
17e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.Locale;
18e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.TimeZone;
19e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport java.util.concurrent.TimeUnit;
206c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport okio.BufferedSource;
216c251e20f00c7574b217bd4351ac81666f574380Tobias Thiererimport org.junit.After;
22e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.Before;
23e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.Rule;
24e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport org.junit.Test;
25e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
26e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static java.nio.charset.StandardCharsets.US_ASCII;
27e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static okio.Okio.buffer;
28e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static okio.Okio.source;
29e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.assertEquals;
30e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerimport static org.junit.Assert.fail;
31e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
32e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fullerpublic class OkUrlFactoryTest {
3371b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller  @Rule public MockWebServer server = new MockWebServer();
346c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  @Rule public InMemoryFileSystem fileSystem = new InMemoryFileSystem();
35e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
36e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private OkUrlFactory factory;
376c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  private Cache cache;
38e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
39e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Before public void setUp() throws IOException {
40e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    OkHttpClient client = new OkHttpClient();
416c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    cache = new Cache(new File("/cache/"), 10 * 1024 * 1024, fileSystem);
426c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    client.setCache(cache);
43e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    factory = new OkUrlFactory(client);
44e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
45e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
466c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  @After public void tearDown() throws IOException {
476c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    cache.delete();
486c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer  }
496c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer
50e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  /**
51e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller   * Response code 407 should only come from proxy servers. Android's client
52e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller   * throws if it is sent by an origin server.
53e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller   */
54e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void originServerSends407() throws Exception {
55e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setResponseCode(407));
56e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
57e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection conn = factory.open(server.getUrl("/"));
58e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    try {
59e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      conn.getResponseCode();
60e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller      fail();
61e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    } catch (IOException ignored) {
62e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    }
63e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
64e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
65e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void networkResponseSourceHeader() throws Exception {
66e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("Isla Sorna"));
67e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
68e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection = factory.open(server.getUrl("/"));
69e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection, "NETWORK 200");
70e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseBody(connection, "Isla Sorna");
71e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
72e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
73e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void networkFailureResponseSourceHeader() throws Exception {
74e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setResponseCode(404));
75e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
76e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection = factory.open(server.getUrl("/"));
77e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection, "NETWORK 404");
786c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    connection.getErrorStream().close();
79e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
80e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
81e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void conditionalCacheHitResponseSourceHeaders() throws Exception {
82e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse()
83e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS))
84e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .addHeader("Cache-Control: max-age=0")
85e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody("Isla Nublar"));
86e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setResponseCode(304));
87e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
88e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection1 = factory.open(server.getUrl("/"));
89e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection1, "NETWORK 200");
90e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseBody(connection1, "Isla Nublar");
91e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
92e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection2 = factory.open(server.getUrl("/"));
93e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection2, "CONDITIONAL_CACHE 304");
94e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseBody(connection2, "Isla Nublar");
95e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
96e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
97e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void conditionalCacheMissResponseSourceHeaders() throws Exception {
98e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse()
99e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .addHeader("Last-Modified: " + formatDate(0, TimeUnit.SECONDS))
100e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .addHeader("Cache-Control: max-age=0")
101e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody("Isla Nublar"));
102e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("Isla Sorna"));
103e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
104e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection1 = factory.open(server.getUrl("/"));
105e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection1, "NETWORK 200");
106e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseBody(connection1, "Isla Nublar");
107e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
108e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection2 = factory.open(server.getUrl("/"));
109e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection2, "CONDITIONAL_CACHE 200");
110e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseBody(connection2, "Isla Sorna");
111e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
112e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
113e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void cacheResponseSourceHeaders() throws Exception {
114e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse()
115e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .addHeader("Expires: " + formatDate(2, TimeUnit.HOURS))
116e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody("Isla Nublar"));
117e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
118e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection1 = factory.open(server.getUrl("/"));
119e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection1, "NETWORK 200");
120e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseBody(connection1, "Isla Nublar");
121e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
122e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection2 = factory.open(server.getUrl("/"));
123e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection2, "CACHE 200");
124e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseBody(connection2, "Isla Nublar");
125e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
126e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
127e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test public void noneResponseSourceHeaders() throws Exception {
128e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse().setBody("Isla Nublar"));
129e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
130e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection1 = factory.open(server.getUrl("/"));
131e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection1, "NETWORK 200");
132e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseBody(connection1, "Isla Nublar");
133e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
134e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection2 = factory.open(server.getUrl("/"));
135e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection2.setRequestProperty("Cache-Control", "only-if-cached");
136e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseHeader(connection2, "NONE");
137e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
138e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
139e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  @Test
140e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  public void setInstanceFollowRedirectsFalse() throws Exception {
141e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse()
142e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setResponseCode(302)
143e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .addHeader("Location: /b")
144e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody("A"));
145e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    server.enqueue(new MockResponse()
146e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller        .setBody("B"));
147e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
148e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    HttpURLConnection connection = factory.open(server.getUrl("/a"));
149e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    connection.setInstanceFollowRedirects(false);
150e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseBody(connection, "A");
151e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertResponseCode(connection, 302);
152e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
153e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
154ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker  @Test
155ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker  public void testURLFilter() throws Exception {
156ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker    server.enqueue(new MockResponse()
157ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker        .setBody("B"));
158ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker    final URL blockedURL = server.url("/a").url();
159ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker    factory.setUrlFilter(new URLFilter() {
160ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker      @Override
161ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker      public void checkURLPermitted(URL url) throws IOException {
162ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker        if (blockedURL.equals(url)) {
163ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker          throw new IOException("Blocked");
164ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker        }
165ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker      }
166ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker    });
167ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker    try {
168ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker      HttpURLConnection connection = factory.open(server.url("/a").url());
169ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker      connection.getInputStream();
170ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker      fail("Connection was successful");
171ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker    } catch (IOException e) {
172ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker      assertEquals("Blocked", e.getMessage());
173ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker    }
174ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker    HttpURLConnection connection = factory.open(server.url("/b").url());
175ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker    assertResponseBody(connection, "B");
176ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker  }
177ef5fc4b73ae643fa290ff6a473ade29f7f6526f7Chad Brubaker
178e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private void assertResponseBody(HttpURLConnection connection, String expected) throws Exception {
1796c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    BufferedSource source = buffer(source(connection.getInputStream()));
1806c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    String actual = source.readString(US_ASCII);
1816c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    source.close();
182e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(expected, actual);
183e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
184e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
185e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private void assertResponseHeader(HttpURLConnection connection, String expected) {
1866c251e20f00c7574b217bd4351ac81666f574380Tobias Thierer    assertEquals(expected, connection.getHeaderField(OkHeaders.RESPONSE_SOURCE));
187e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
188e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
189e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private void assertResponseCode(HttpURLConnection connection, int expected) throws IOException {
190e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    assertEquals(expected, connection.getResponseCode());
191e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
192e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
193e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private static String formatDate(long delta, TimeUnit timeUnit) {
194e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    return formatDate(new Date(System.currentTimeMillis() + timeUnit.toMillis(delta)));
195e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
196e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller
197e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  private static String formatDate(Date date) {
198e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    DateFormat rfc1123 = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
199e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    rfc1123.setTimeZone(TimeZone.getTimeZone("GMT"));
200e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller    return rfc1123.format(date);
201e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller  }
202e78f117bcbd6b57d783737107f445ef75ecb474aNeil Fuller}
203