1 /* 2 * Copyright (C) 2013 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; 17 18 import com.squareup.okhttp.internal.DoubleInetAddressNetwork; 19 import com.squareup.okhttp.internal.Internal; 20 import com.squareup.okhttp.internal.RecordingOkAuthenticator; 21 import com.squareup.okhttp.internal.SingleInetAddressNetwork; 22 import com.squareup.okhttp.internal.SslContextBuilder; 23 import com.squareup.okhttp.internal.Util; 24 import com.squareup.okhttp.internal.Version; 25 import com.squareup.okhttp.internal.io.FileSystem; 26 import com.squareup.okhttp.internal.io.InMemoryFileSystem; 27 import com.squareup.okhttp.mockwebserver.Dispatcher; 28 import com.squareup.okhttp.mockwebserver.MockResponse; 29 import com.squareup.okhttp.mockwebserver.MockWebServer; 30 import com.squareup.okhttp.mockwebserver.RecordedRequest; 31 import com.squareup.okhttp.mockwebserver.SocketPolicy; 32 import com.squareup.okhttp.testing.RecordingHostnameVerifier; 33 import java.io.File; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.io.InterruptedIOException; 37 import java.net.CookieManager; 38 import java.net.HttpCookie; 39 import java.net.HttpURLConnection; 40 import java.net.InetAddress; 41 import java.net.InetSocketAddress; 42 import java.net.ProtocolException; 43 import java.net.ServerSocket; 44 import java.net.UnknownServiceException; 45 import java.security.cert.Certificate; 46 import java.util.ArrayList; 47 import java.util.Arrays; 48 import java.util.List; 49 import java.util.concurrent.BlockingQueue; 50 import java.util.concurrent.Callable; 51 import java.util.concurrent.CountDownLatch; 52 import java.util.concurrent.ExecutorService; 53 import java.util.concurrent.Executors; 54 import java.util.concurrent.Future; 55 import java.util.concurrent.SynchronousQueue; 56 import java.util.concurrent.TimeUnit; 57 import java.util.concurrent.atomic.AtomicBoolean; 58 import java.util.concurrent.atomic.AtomicReference; 59 import javax.net.ServerSocketFactory; 60 import javax.net.ssl.SSLContext; 61 import javax.net.ssl.SSLHandshakeException; 62 import javax.net.ssl.SSLPeerUnverifiedException; 63 import javax.net.ssl.SSLProtocolException; 64 import javax.net.ssl.SSLSocket; 65 import javax.net.ssl.SSLSocketFactory; 66 import okio.Buffer; 67 import okio.BufferedSink; 68 import okio.BufferedSource; 69 import okio.GzipSink; 70 import okio.Okio; 71 import org.junit.After; 72 import org.junit.Before; 73 import org.junit.Rule; 74 import org.junit.Test; 75 import org.junit.rules.TestRule; 76 import org.junit.rules.Timeout; 77 78 import static com.squareup.okhttp.internal.Internal.logger; 79 import static java.net.CookiePolicy.ACCEPT_ORIGINAL_SERVER; 80 import static org.junit.Assert.assertEquals; 81 import static org.junit.Assert.assertFalse; 82 import static org.junit.Assert.assertNotSame; 83 import static org.junit.Assert.assertNull; 84 import static org.junit.Assert.assertTrue; 85 import static org.junit.Assert.fail; 86 87 public final class CallTest { 88 @Rule public final TestRule timeout = new Timeout(30_000); 89 @Rule public final MockWebServer server = new MockWebServer(); 90 @Rule public final MockWebServer server2 = new MockWebServer(); 91 92 private SSLContext sslContext = SslContextBuilder.localhost(); 93 private FileSystem fileSystem = new InMemoryFileSystem(); 94 private OkHttpClient client = new OkHttpClient(); 95 private RecordingCallback callback = new RecordingCallback(); 96 private TestLogHandler logHandler = new TestLogHandler(); 97 private Cache cache = new Cache(new File("/cache/"), Integer.MAX_VALUE, fileSystem); 98 private ServerSocket nullServer; 99 setUp()100 @Before public void setUp() throws Exception { 101 logger.addHandler(logHandler); 102 } 103 tearDown()104 @After public void tearDown() throws Exception { 105 cache.delete(); 106 Util.closeQuietly(nullServer); 107 logger.removeHandler(logHandler); 108 } 109 get()110 @Test public void get() throws Exception { 111 server.enqueue(new MockResponse().setBody("abc").addHeader("Content-Type: text/plain")); 112 113 Request request = new Request.Builder() 114 .url(server.url("/")) 115 .header("User-Agent", "SyncApiTest") 116 .build(); 117 118 executeSynchronously(request) 119 .assertCode(200) 120 .assertSuccessful() 121 .assertHeader("Content-Type", "text/plain") 122 .assertBody("abc"); 123 124 RecordedRequest recordedRequest = server.takeRequest(); 125 assertEquals("GET", recordedRequest.getMethod()); 126 assertEquals("SyncApiTest", recordedRequest.getHeader("User-Agent")); 127 assertEquals(0, recordedRequest.getBody().size()); 128 assertNull(recordedRequest.getHeader("Content-Length")); 129 } 130 buildRequestUsingHttpUrl()131 @Test public void buildRequestUsingHttpUrl() throws Exception { 132 server.enqueue(new MockResponse()); 133 134 HttpUrl httpUrl = server.url("/"); 135 Request request = new Request.Builder() 136 .url(httpUrl) 137 .build(); 138 assertEquals(httpUrl, request.httpUrl()); 139 140 executeSynchronously(request).assertSuccessful(); 141 } 142 invalidScheme()143 @Test public void invalidScheme() throws Exception { 144 Request.Builder requestBuilder = new Request.Builder(); 145 try { 146 requestBuilder.url("ftp://hostname/path"); 147 fail(); 148 } catch (IllegalArgumentException expected) { 149 assertEquals(expected.getMessage(), "unexpected url: ftp://hostname/path"); 150 } 151 } 152 invalidPort()153 @Test public void invalidPort() throws Exception { 154 Request.Builder requestBuilder = new Request.Builder(); 155 try { 156 requestBuilder.url("http://localhost:65536/"); 157 fail(); 158 } catch (IllegalArgumentException expected) { 159 assertEquals(expected.getMessage(), "unexpected url: http://localhost:65536/"); 160 } 161 } 162 getReturns500()163 @Test public void getReturns500() throws Exception { 164 server.enqueue(new MockResponse().setResponseCode(500)); 165 166 Request request = new Request.Builder() 167 .url(server.url("/")) 168 .build(); 169 170 executeSynchronously(request) 171 .assertCode(500) 172 .assertNotSuccessful(); 173 } 174 get_SPDY_3()175 @Test public void get_SPDY_3() throws Exception { 176 enableProtocol(Protocol.SPDY_3); 177 get(); 178 } 179 get_HTTP_2()180 @Test public void get_HTTP_2() throws Exception { 181 enableProtocol(Protocol.HTTP_2); 182 get(); 183 } 184 getWithRequestBody()185 @Test public void getWithRequestBody() throws Exception { 186 server.enqueue(new MockResponse()); 187 188 try { 189 new Request.Builder().method("GET", RequestBody.create(MediaType.parse("text/plain"), "abc")); 190 fail(); 191 } catch (IllegalArgumentException expected) { 192 } 193 } 194 head()195 @Test public void head() throws Exception { 196 server.enqueue(new MockResponse().addHeader("Content-Type: text/plain")); 197 198 Request request = new Request.Builder() 199 .url(server.url("/")) 200 .head() 201 .header("User-Agent", "SyncApiTest") 202 .build(); 203 204 executeSynchronously(request) 205 .assertCode(200) 206 .assertHeader("Content-Type", "text/plain"); 207 208 RecordedRequest recordedRequest = server.takeRequest(); 209 assertEquals("HEAD", recordedRequest.getMethod()); 210 assertEquals("SyncApiTest", recordedRequest.getHeader("User-Agent")); 211 assertEquals(0, recordedRequest.getBody().size()); 212 assertNull(recordedRequest.getHeader("Content-Length")); 213 } 214 head_SPDY_3()215 @Test public void head_SPDY_3() throws Exception { 216 enableProtocol(Protocol.SPDY_3); 217 head(); 218 } 219 head_HTTP_2()220 @Test public void head_HTTP_2() throws Exception { 221 enableProtocol(Protocol.HTTP_2); 222 head(); 223 } 224 post()225 @Test public void post() throws Exception { 226 server.enqueue(new MockResponse().setBody("abc")); 227 228 Request request = new Request.Builder() 229 .url(server.url("/")) 230 .post(RequestBody.create(MediaType.parse("text/plain"), "def")) 231 .build(); 232 233 executeSynchronously(request) 234 .assertCode(200) 235 .assertBody("abc"); 236 237 RecordedRequest recordedRequest = server.takeRequest(); 238 assertEquals("POST", recordedRequest.getMethod()); 239 assertEquals("def", recordedRequest.getBody().readUtf8()); 240 assertEquals("3", recordedRequest.getHeader("Content-Length")); 241 assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type")); 242 } 243 post_SPDY_3()244 @Test public void post_SPDY_3() throws Exception { 245 enableProtocol(Protocol.SPDY_3); 246 post(); 247 } 248 post_HTTP_2()249 @Test public void post_HTTP_2() throws Exception { 250 enableProtocol(Protocol.HTTP_2); 251 post(); 252 } 253 postZeroLength()254 @Test public void postZeroLength() throws Exception { 255 server.enqueue(new MockResponse().setBody("abc")); 256 257 Request request = new Request.Builder() 258 .url(server.url("/")) 259 .method("POST", RequestBody.create(null, new byte[0])) 260 .build(); 261 262 executeSynchronously(request) 263 .assertCode(200) 264 .assertBody("abc"); 265 266 RecordedRequest recordedRequest = server.takeRequest(); 267 assertEquals("POST", recordedRequest.getMethod()); 268 assertEquals(0, recordedRequest.getBody().size()); 269 assertEquals("0", recordedRequest.getHeader("Content-Length")); 270 assertEquals(null, recordedRequest.getHeader("Content-Type")); 271 } 272 postZeroLength_SPDY_3()273 @Test public void postZeroLength_SPDY_3() throws Exception { 274 enableProtocol(Protocol.SPDY_3); 275 postZeroLength(); 276 } 277 postZerolength_HTTP_2()278 @Test public void postZerolength_HTTP_2() throws Exception { 279 enableProtocol(Protocol.HTTP_2); 280 postZeroLength(); 281 } 282 postBodyRetransmittedAfterAuthorizationFail()283 @Test public void postBodyRetransmittedAfterAuthorizationFail() throws Exception { 284 postBodyRetransmittedAfterAuthorizationFail("abc"); 285 } 286 postBodyRetransmittedAfterAuthorizationFail_SPDY_3()287 @Test public void postBodyRetransmittedAfterAuthorizationFail_SPDY_3() throws Exception { 288 enableProtocol(Protocol.SPDY_3); 289 postBodyRetransmittedAfterAuthorizationFail("abc"); 290 } 291 postBodyRetransmittedAfterAuthorizationFail_HTTP_2()292 @Test public void postBodyRetransmittedAfterAuthorizationFail_HTTP_2() throws Exception { 293 enableProtocol(Protocol.HTTP_2); 294 postBodyRetransmittedAfterAuthorizationFail("abc"); 295 } 296 297 /** Don't explode when resending an empty post. https://github.com/square/okhttp/issues/1131 */ postEmptyBodyRetransmittedAfterAuthorizationFail()298 @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail() throws Exception { 299 postBodyRetransmittedAfterAuthorizationFail(""); 300 } 301 postEmptyBodyRetransmittedAfterAuthorizationFail_SPDY_3()302 @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail_SPDY_3() throws Exception { 303 enableProtocol(Protocol.SPDY_3); 304 postBodyRetransmittedAfterAuthorizationFail(""); 305 } 306 postEmptyBodyRetransmittedAfterAuthorizationFail_HTTP_2()307 @Test public void postEmptyBodyRetransmittedAfterAuthorizationFail_HTTP_2() throws Exception { 308 enableProtocol(Protocol.HTTP_2); 309 postBodyRetransmittedAfterAuthorizationFail(""); 310 } 311 postBodyRetransmittedAfterAuthorizationFail(String body)312 private void postBodyRetransmittedAfterAuthorizationFail(String body) throws Exception { 313 server.enqueue(new MockResponse().setResponseCode(401)); 314 server.enqueue(new MockResponse()); 315 316 Request request = new Request.Builder() 317 .url(server.url("/")) 318 .method("POST", RequestBody.create(null, body)) 319 .build(); 320 321 String credential = Credentials.basic("jesse", "secret"); 322 client.setAuthenticator(new RecordingOkAuthenticator(credential)); 323 324 Response response = client.newCall(request).execute(); 325 assertEquals(200, response.code()); 326 327 RecordedRequest recordedRequest1 = server.takeRequest(); 328 assertEquals("POST", recordedRequest1.getMethod()); 329 assertEquals(body, recordedRequest1.getBody().readUtf8()); 330 assertNull(recordedRequest1.getHeader("Authorization")); 331 332 RecordedRequest recordedRequest2 = server.takeRequest(); 333 assertEquals("POST", recordedRequest2.getMethod()); 334 assertEquals(body, recordedRequest2.getBody().readUtf8()); 335 assertEquals(credential, recordedRequest2.getHeader("Authorization")); 336 } 337 attemptAuthorization20Times()338 @Test public void attemptAuthorization20Times() throws Exception { 339 for (int i = 0; i < 20; i++) { 340 server.enqueue(new MockResponse().setResponseCode(401)); 341 } 342 server.enqueue(new MockResponse().setBody("Success!")); 343 344 String credential = Credentials.basic("jesse", "secret"); 345 client.setAuthenticator(new RecordingOkAuthenticator(credential)); 346 347 Request request = new Request.Builder().url(server.url("/")).build(); 348 executeSynchronously(request) 349 .assertCode(200) 350 .assertBody("Success!"); 351 } 352 doesNotAttemptAuthorization21Times()353 @Test public void doesNotAttemptAuthorization21Times() throws Exception { 354 for (int i = 0; i < 21; i++) { 355 server.enqueue(new MockResponse().setResponseCode(401)); 356 } 357 358 String credential = Credentials.basic("jesse", "secret"); 359 client.setAuthenticator(new RecordingOkAuthenticator(credential)); 360 361 try { 362 client.newCall(new Request.Builder().url(server.url("/0")).build()).execute(); 363 fail(); 364 } catch (IOException expected) { 365 assertEquals("Too many follow-up requests: 21", expected.getMessage()); 366 } 367 } 368 delete()369 @Test public void delete() throws Exception { 370 server.enqueue(new MockResponse().setBody("abc")); 371 372 Request request = new Request.Builder() 373 .url(server.url("/")) 374 .delete() 375 .build(); 376 377 executeSynchronously(request) 378 .assertCode(200) 379 .assertBody("abc"); 380 381 RecordedRequest recordedRequest = server.takeRequest(); 382 assertEquals("DELETE", recordedRequest.getMethod()); 383 assertEquals(0, recordedRequest.getBody().size()); 384 assertEquals("0", recordedRequest.getHeader("Content-Length")); 385 assertEquals(null, recordedRequest.getHeader("Content-Type")); 386 } 387 delete_SPDY_3()388 @Test public void delete_SPDY_3() throws Exception { 389 enableProtocol(Protocol.SPDY_3); 390 delete(); 391 } 392 delete_HTTP_2()393 @Test public void delete_HTTP_2() throws Exception { 394 enableProtocol(Protocol.HTTP_2); 395 delete(); 396 } 397 deleteWithRequestBody()398 @Test public void deleteWithRequestBody() throws Exception { 399 server.enqueue(new MockResponse().setBody("abc")); 400 401 Request request = new Request.Builder() 402 .url(server.url("/")) 403 .method("DELETE", RequestBody.create(MediaType.parse("text/plain"), "def")) 404 .build(); 405 406 executeSynchronously(request) 407 .assertCode(200) 408 .assertBody("abc"); 409 410 RecordedRequest recordedRequest = server.takeRequest(); 411 assertEquals("DELETE", recordedRequest.getMethod()); 412 assertEquals("def", recordedRequest.getBody().readUtf8()); 413 } 414 put()415 @Test public void put() throws Exception { 416 server.enqueue(new MockResponse().setBody("abc")); 417 418 Request request = new Request.Builder() 419 .url(server.url("/")) 420 .put(RequestBody.create(MediaType.parse("text/plain"), "def")) 421 .build(); 422 423 executeSynchronously(request) 424 .assertCode(200) 425 .assertBody("abc"); 426 427 RecordedRequest recordedRequest = server.takeRequest(); 428 assertEquals("PUT", recordedRequest.getMethod()); 429 assertEquals("def", recordedRequest.getBody().readUtf8()); 430 assertEquals("3", recordedRequest.getHeader("Content-Length")); 431 assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type")); 432 } 433 put_SPDY_3()434 @Test public void put_SPDY_3() throws Exception { 435 enableProtocol(Protocol.SPDY_3); 436 put(); 437 } 438 put_HTTP_2()439 @Test public void put_HTTP_2() throws Exception { 440 enableProtocol(Protocol.HTTP_2); 441 put(); 442 } 443 patch()444 @Test public void patch() throws Exception { 445 server.enqueue(new MockResponse().setBody("abc")); 446 447 Request request = new Request.Builder() 448 .url(server.url("/")) 449 .patch(RequestBody.create(MediaType.parse("text/plain"), "def")) 450 .build(); 451 452 executeSynchronously(request) 453 .assertCode(200) 454 .assertBody("abc"); 455 456 RecordedRequest recordedRequest = server.takeRequest(); 457 assertEquals("PATCH", recordedRequest.getMethod()); 458 assertEquals("def", recordedRequest.getBody().readUtf8()); 459 assertEquals("3", recordedRequest.getHeader("Content-Length")); 460 assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type")); 461 } 462 patch_SPDY_3()463 @Test public void patch_SPDY_3() throws Exception { 464 enableProtocol(Protocol.SPDY_3); 465 patch(); 466 } 467 patch_HTTP_2()468 @Test public void patch_HTTP_2() throws Exception { 469 enableProtocol(Protocol.HTTP_2); 470 patch(); 471 } 472 unspecifiedRequestBodyContentTypeDoesNotGetDefault()473 @Test public void unspecifiedRequestBodyContentTypeDoesNotGetDefault() throws Exception { 474 server.enqueue(new MockResponse()); 475 476 Request request = new Request.Builder() 477 .url(server.url("/")) 478 .method("POST", RequestBody.create(null, "abc")) 479 .build(); 480 481 executeSynchronously(request).assertCode(200); 482 483 RecordedRequest recordedRequest = server.takeRequest(); 484 assertEquals(null, recordedRequest.getHeader("Content-Type")); 485 assertEquals("3", recordedRequest.getHeader("Content-Length")); 486 assertEquals("abc", recordedRequest.getBody().readUtf8()); 487 } 488 illegalToExecuteTwice()489 @Test public void illegalToExecuteTwice() throws Exception { 490 server.enqueue(new MockResponse() 491 .setBody("abc") 492 .addHeader("Content-Type: text/plain")); 493 494 Request request = new Request.Builder() 495 .url(server.url("/")) 496 .header("User-Agent", "SyncApiTest") 497 .build(); 498 499 Call call = client.newCall(request); 500 call.execute(); 501 502 try { 503 call.execute(); 504 fail(); 505 } catch (IllegalStateException e){ 506 assertEquals("Already Executed", e.getMessage()); 507 } 508 509 try { 510 call.enqueue(callback); 511 fail(); 512 } catch (IllegalStateException e){ 513 assertEquals("Already Executed", e.getMessage()); 514 } 515 516 assertEquals("SyncApiTest", server.takeRequest().getHeader("User-Agent")); 517 } 518 illegalToExecuteTwice_Async()519 @Test public void illegalToExecuteTwice_Async() throws Exception { 520 server.enqueue(new MockResponse() 521 .setBody("abc") 522 .addHeader("Content-Type: text/plain")); 523 524 Request request = new Request.Builder() 525 .url(server.url("/")) 526 .header("User-Agent", "SyncApiTest") 527 .build(); 528 529 Call call = client.newCall(request); 530 call.enqueue(callback); 531 532 try { 533 call.execute(); 534 fail(); 535 } catch (IllegalStateException e){ 536 assertEquals("Already Executed", e.getMessage()); 537 } 538 539 try { 540 call.enqueue(callback); 541 fail(); 542 } catch (IllegalStateException e){ 543 assertEquals("Already Executed", e.getMessage()); 544 } 545 546 assertEquals("SyncApiTest", server.takeRequest().getHeader("User-Agent")); 547 } 548 get_Async()549 @Test public void get_Async() throws Exception { 550 server.enqueue(new MockResponse() 551 .setBody("abc") 552 .addHeader("Content-Type: text/plain")); 553 554 Request request = new Request.Builder() 555 .url(server.url("/")) 556 .header("User-Agent", "AsyncApiTest") 557 .build(); 558 client.newCall(request).enqueue(callback); 559 560 callback.await(request.httpUrl()) 561 .assertCode(200) 562 .assertHeader("Content-Type", "text/plain") 563 .assertBody("abc"); 564 565 assertEquals("AsyncApiTest", server.takeRequest().getHeader("User-Agent")); 566 } 567 exceptionThrownByOnResponseIsRedactedAndLogged()568 @Test public void exceptionThrownByOnResponseIsRedactedAndLogged() throws Exception { 569 server.enqueue(new MockResponse()); 570 571 Request request = new Request.Builder() 572 .url(server.url("/secret")) 573 .build(); 574 575 client.newCall(request).enqueue(new Callback() { 576 @Override public void onFailure(Request request, IOException e) { 577 fail(); 578 } 579 580 @Override public void onResponse(Response response) throws IOException { 581 throw new IOException("a"); 582 } 583 }); 584 585 assertEquals("INFO: Callback failure for call to " + server.url("/") + "...", 586 logHandler.take()); 587 } 588 connectionPooling()589 @Test public void connectionPooling() throws Exception { 590 server.enqueue(new MockResponse().setBody("abc")); 591 server.enqueue(new MockResponse().setBody("def")); 592 server.enqueue(new MockResponse().setBody("ghi")); 593 594 executeSynchronously(new Request.Builder().url(server.url("/a")).build()) 595 .assertBody("abc"); 596 597 executeSynchronously(new Request.Builder().url(server.url("/b")).build()) 598 .assertBody("def"); 599 600 executeSynchronously(new Request.Builder().url(server.url("/c")).build()) 601 .assertBody("ghi"); 602 603 assertEquals(0, server.takeRequest().getSequenceNumber()); 604 assertEquals(1, server.takeRequest().getSequenceNumber()); 605 assertEquals(2, server.takeRequest().getSequenceNumber()); 606 } 607 connectionPooling_Async()608 @Test public void connectionPooling_Async() throws Exception { 609 server.enqueue(new MockResponse().setBody("abc")); 610 server.enqueue(new MockResponse().setBody("def")); 611 server.enqueue(new MockResponse().setBody("ghi")); 612 613 client.newCall(new Request.Builder().url(server.url("/a")).build()).enqueue(callback); 614 callback.await(server.url("/a")).assertBody("abc"); 615 616 client.newCall(new Request.Builder().url(server.url("/b")).build()).enqueue(callback); 617 callback.await(server.url("/b")).assertBody("def"); 618 619 client.newCall(new Request.Builder().url(server.url("/c")).build()).enqueue(callback); 620 callback.await(server.url("/c")).assertBody("ghi"); 621 622 assertEquals(0, server.takeRequest().getSequenceNumber()); 623 assertEquals(1, server.takeRequest().getSequenceNumber()); 624 assertEquals(2, server.takeRequest().getSequenceNumber()); 625 } 626 connectionReuseWhenResponseBodyConsumed_Async()627 @Test public void connectionReuseWhenResponseBodyConsumed_Async() throws Exception { 628 server.enqueue(new MockResponse().setBody("abc")); 629 server.enqueue(new MockResponse().setBody("def")); 630 631 Request request = new Request.Builder().url(server.url("/a")).build(); 632 client.newCall(request).enqueue(new Callback() { 633 @Override public void onFailure(Request request, IOException e) { 634 throw new AssertionError(); 635 } 636 637 @Override public void onResponse(Response response) throws IOException { 638 InputStream bytes = response.body().byteStream(); 639 assertEquals('a', bytes.read()); 640 assertEquals('b', bytes.read()); 641 assertEquals('c', bytes.read()); 642 643 // This request will share a connection with 'A' cause it's all done. 644 client.newCall(new Request.Builder().url(server.url("/b")).build()).enqueue(callback); 645 } 646 }); 647 648 callback.await(server.url("/b")).assertCode(200).assertBody("def"); 649 assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection. 650 assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reuse! 651 } 652 timeoutsUpdatedOnReusedConnections()653 @Test public void timeoutsUpdatedOnReusedConnections() throws Exception { 654 server.enqueue(new MockResponse().setBody("abc")); 655 server.enqueue(new MockResponse().setBody("def").throttleBody(1, 750, TimeUnit.MILLISECONDS)); 656 657 // First request: time out after 1000ms. 658 client.setReadTimeout(1000, TimeUnit.MILLISECONDS); 659 executeSynchronously(new Request.Builder().url(server.url("/a")).build()).assertBody("abc"); 660 661 // Second request: time out after 250ms. 662 client.setReadTimeout(250, TimeUnit.MILLISECONDS); 663 Request request = new Request.Builder().url(server.url("/b")).build(); 664 Response response = client.newCall(request).execute(); 665 BufferedSource bodySource = response.body().source(); 666 assertEquals('d', bodySource.readByte()); 667 668 // The second byte of this request will be delayed by 750ms so we should time out after 250ms. 669 long startNanos = System.nanoTime(); 670 try { 671 bodySource.readByte(); 672 fail(); 673 } catch (IOException expected) { 674 // Timed out as expected. 675 long elapsedNanos = System.nanoTime() - startNanos; 676 long elapsedMillis = TimeUnit.NANOSECONDS.toMillis(elapsedNanos); 677 assertTrue(String.format("Timed out: %sms", elapsedMillis), elapsedMillis < 500); 678 } 679 } 680 681 // https://github.com/square/okhttp/issues/442 timeoutsNotRetried()682 @Test public void timeoutsNotRetried() throws Exception { 683 server.enqueue(new MockResponse() 684 .setSocketPolicy(SocketPolicy.NO_RESPONSE)); 685 server.enqueue(new MockResponse() 686 .setBody("unreachable!")); 687 688 Internal.instance.setNetwork(client, new DoubleInetAddressNetwork()); 689 client.setReadTimeout(100, TimeUnit.MILLISECONDS); 690 691 Request request = new Request.Builder().url(server.url("/")).build(); 692 try { 693 // If this succeeds, too many requests were made. 694 client.newCall(request).execute(); 695 fail(); 696 } catch (InterruptedIOException expected) { 697 } 698 } 699 reusedSinksGetIndependentTimeoutInstances()700 @Test public void reusedSinksGetIndependentTimeoutInstances() throws Exception { 701 server.enqueue(new MockResponse()); 702 server.enqueue(new MockResponse()); 703 704 // Call 1: set a deadline on the request body. 705 RequestBody requestBody1 = new RequestBody() { 706 @Override public MediaType contentType() { 707 return MediaType.parse("text/plain"); 708 } 709 @Override public void writeTo(BufferedSink sink) throws IOException { 710 sink.writeUtf8("abc"); 711 sink.timeout().deadline(5, TimeUnit.SECONDS); 712 } 713 }; 714 Request request1 = new Request.Builder() 715 .url(server.url("/")) 716 .method("POST", requestBody1) 717 .build(); 718 Response response1 = client.newCall(request1).execute(); 719 assertEquals(200, response1.code()); 720 721 // Call 2: check for the absence of a deadline on the request body. 722 RequestBody requestBody2 = new RequestBody() { 723 @Override public MediaType contentType() { 724 return MediaType.parse("text/plain"); 725 } 726 @Override public void writeTo(BufferedSink sink) throws IOException { 727 assertFalse(sink.timeout().hasDeadline()); 728 sink.writeUtf8("def"); 729 } 730 }; 731 Request request2 = new Request.Builder() 732 .url(server.url("/")) 733 .method("POST", requestBody2) 734 .build(); 735 Response response2 = client.newCall(request2).execute(); 736 assertEquals(200, response2.code()); 737 738 // Use sequence numbers to confirm the connection was pooled. 739 assertEquals(0, server.takeRequest().getSequenceNumber()); 740 assertEquals(1, server.takeRequest().getSequenceNumber()); 741 } 742 reusedSourcesGetIndependentTimeoutInstances()743 @Test public void reusedSourcesGetIndependentTimeoutInstances() throws Exception { 744 server.enqueue(new MockResponse().setBody("abc")); 745 server.enqueue(new MockResponse().setBody("def")); 746 747 // Call 1: set a deadline on the response body. 748 Request request1 = new Request.Builder().url(server.url("/")).build(); 749 Response response1 = client.newCall(request1).execute(); 750 BufferedSource body1 = response1.body().source(); 751 assertEquals("abc", body1.readUtf8()); 752 body1.timeout().deadline(5, TimeUnit.SECONDS); 753 754 // Call 2: check for the absence of a deadline on the request body. 755 Request request2 = new Request.Builder().url(server.url("/")).build(); 756 Response response2 = client.newCall(request2).execute(); 757 BufferedSource body2 = response2.body().source(); 758 assertEquals("def", body2.readUtf8()); 759 assertFalse(body2.timeout().hasDeadline()); 760 761 // Use sequence numbers to confirm the connection was pooled. 762 assertEquals(0, server.takeRequest().getSequenceNumber()); 763 assertEquals(1, server.takeRequest().getSequenceNumber()); 764 } 765 tls()766 @Test public void tls() throws Exception { 767 server.useHttps(sslContext.getSocketFactory(), false); 768 server.enqueue(new MockResponse() 769 .setBody("abc") 770 .addHeader("Content-Type: text/plain")); 771 772 client.setSslSocketFactory(sslContext.getSocketFactory()); 773 client.setHostnameVerifier(new RecordingHostnameVerifier()); 774 775 executeSynchronously(new Request.Builder().url(server.url("/")).build()) 776 .assertHandshake(); 777 } 778 tls_Async()779 @Test public void tls_Async() throws Exception { 780 server.useHttps(sslContext.getSocketFactory(), false); 781 server.enqueue(new MockResponse() 782 .setBody("abc") 783 .addHeader("Content-Type: text/plain")); 784 785 client.setSslSocketFactory(sslContext.getSocketFactory()); 786 client.setHostnameVerifier(new RecordingHostnameVerifier()); 787 788 Request request = new Request.Builder() 789 .url(server.url("/")) 790 .build(); 791 client.newCall(request).enqueue(callback); 792 793 callback.await(request.httpUrl()).assertHandshake(); 794 } 795 recoverWhenRetryOnConnectionFailureIsTrue()796 @Test public void recoverWhenRetryOnConnectionFailureIsTrue() throws Exception { 797 server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AT_START)); 798 server.enqueue(new MockResponse().setBody("retry success")); 799 800 Internal.instance.setNetwork(client, new DoubleInetAddressNetwork()); 801 assertTrue(client.getRetryOnConnectionFailure()); 802 803 Request request = new Request.Builder().url(server.url("/")).build(); 804 Response response = client.newCall(request).execute(); 805 assertEquals("retry success", response.body().string()); 806 } 807 noRecoverWhenRetryOnConnectionFailureIsFalse()808 @Test public void noRecoverWhenRetryOnConnectionFailureIsFalse() throws Exception { 809 server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AT_START)); 810 server.enqueue(new MockResponse().setBody("unreachable!")); 811 812 Internal.instance.setNetwork(client, new DoubleInetAddressNetwork()); 813 client.setRetryOnConnectionFailure(false); 814 815 Request request = new Request.Builder().url(server.url("/")).build(); 816 try { 817 // If this succeeds, too many requests were made. 818 client.newCall(request).execute(); 819 fail(); 820 } catch (IOException expected) { 821 } 822 } 823 recoverFromTlsHandshakeFailure()824 @Test public void recoverFromTlsHandshakeFailure() throws Exception { 825 server.useHttps(sslContext.getSocketFactory(), false); 826 server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE)); 827 server.enqueue(new MockResponse().setBody("abc")); 828 829 suppressTlsFallbackScsv(client); 830 client.setHostnameVerifier(new RecordingHostnameVerifier()); 831 Internal.instance.setNetwork(client, new SingleInetAddressNetwork()); 832 833 executeSynchronously(new Request.Builder().url(server.url("/")).build()) 834 .assertBody("abc"); 835 } 836 recoverFromTlsHandshakeFailure_tlsFallbackScsvEnabled()837 @Test public void recoverFromTlsHandshakeFailure_tlsFallbackScsvEnabled() throws Exception { 838 final String tlsFallbackScsv = "TLS_FALLBACK_SCSV"; 839 List<String> supportedCiphers = 840 Arrays.asList(sslContext.getSocketFactory().getSupportedCipherSuites()); 841 if (!supportedCiphers.contains(tlsFallbackScsv)) { 842 // This only works if the client socket supports TLS_FALLBACK_SCSV. 843 return; 844 } 845 846 server.useHttps(sslContext.getSocketFactory(), false); 847 server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE)); 848 849 RecordingSSLSocketFactory clientSocketFactory = 850 new RecordingSSLSocketFactory(sslContext.getSocketFactory()); 851 client.setSslSocketFactory(clientSocketFactory); 852 client.setHostnameVerifier(new RecordingHostnameVerifier()); 853 Internal.instance.setNetwork(client, new SingleInetAddressNetwork()); 854 855 Request request = new Request.Builder().url(server.url("/")).build(); 856 try { 857 client.newCall(request).execute(); 858 fail(); 859 } catch (SSLHandshakeException expected) { 860 } 861 862 List<SSLSocket> clientSockets = clientSocketFactory.getSocketsCreated(); 863 SSLSocket firstSocket = clientSockets.get(0); 864 assertFalse(Arrays.asList(firstSocket.getEnabledCipherSuites()).contains(tlsFallbackScsv)); 865 SSLSocket secondSocket = clientSockets.get(1); 866 assertTrue(Arrays.asList(secondSocket.getEnabledCipherSuites()).contains(tlsFallbackScsv)); 867 } 868 recoverFromTlsHandshakeFailure_Async()869 @Test public void recoverFromTlsHandshakeFailure_Async() throws Exception { 870 server.useHttps(sslContext.getSocketFactory(), false); 871 server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE)); 872 server.enqueue(new MockResponse().setBody("abc")); 873 874 suppressTlsFallbackScsv(client); 875 client.setHostnameVerifier(new RecordingHostnameVerifier()); 876 877 Request request = new Request.Builder() 878 .url(server.url("/")) 879 .build(); 880 client.newCall(request).enqueue(callback); 881 882 callback.await(request.httpUrl()).assertBody("abc"); 883 } 884 noRecoveryFromTlsHandshakeFailureWhenTlsFallbackIsDisabled()885 @Test public void noRecoveryFromTlsHandshakeFailureWhenTlsFallbackIsDisabled() throws Exception { 886 client.setConnectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.CLEARTEXT)); 887 888 server.useHttps(sslContext.getSocketFactory(), false); 889 server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.FAIL_HANDSHAKE)); 890 891 suppressTlsFallbackScsv(client); 892 client.setHostnameVerifier(new RecordingHostnameVerifier()); 893 Internal.instance.setNetwork(client, new SingleInetAddressNetwork()); 894 895 Request request = new Request.Builder().url(server.url("/")).build(); 896 try { 897 client.newCall(request).execute(); 898 fail(); 899 } catch (SSLProtocolException expected) { 900 // RI response to the FAIL_HANDSHAKE 901 } catch (SSLHandshakeException expected) { 902 // Android's response to the FAIL_HANDSHAKE 903 } 904 } 905 cleartextCallsFailWhenCleartextIsDisabled()906 @Test public void cleartextCallsFailWhenCleartextIsDisabled() throws Exception { 907 // Configure the client with only TLS configurations. No cleartext! 908 client.setConnectionSpecs( 909 Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS)); 910 911 server.enqueue(new MockResponse()); 912 913 Request request = new Request.Builder().url(server.url("/")).build(); 914 try { 915 client.newCall(request).execute(); 916 fail(); 917 } catch (UnknownServiceException expected) { 918 assertTrue(expected.getMessage().contains("CLEARTEXT communication not supported")); 919 } 920 } 921 setFollowSslRedirectsFalse()922 @Test public void setFollowSslRedirectsFalse() throws Exception { 923 server.useHttps(sslContext.getSocketFactory(), false); 924 server.enqueue(new MockResponse().setResponseCode(301).addHeader("Location: http://square.com")); 925 926 client.setFollowSslRedirects(false); 927 client.setSslSocketFactory(sslContext.getSocketFactory()); 928 client.setHostnameVerifier(new RecordingHostnameVerifier()); 929 930 Request request = new Request.Builder().url(server.url("/")).build(); 931 Response response = client.newCall(request).execute(); 932 assertEquals(301, response.code()); 933 } 934 matchingPinnedCertificate()935 @Test public void matchingPinnedCertificate() throws Exception { 936 server.useHttps(sslContext.getSocketFactory(), false); 937 server.enqueue(new MockResponse()); 938 server.enqueue(new MockResponse()); 939 940 client.setSslSocketFactory(sslContext.getSocketFactory()); 941 client.setHostnameVerifier(new RecordingHostnameVerifier()); 942 943 // Make a first request without certificate pinning. Use it to collect certificates to pin. 944 Request request1 = new Request.Builder().url(server.url("/")).build(); 945 Response response1 = client.newCall(request1).execute(); 946 CertificatePinner.Builder certificatePinnerBuilder = new CertificatePinner.Builder(); 947 for (Certificate certificate : response1.handshake().peerCertificates()) { 948 certificatePinnerBuilder.add(server.getHostName(), CertificatePinner.pin(certificate)); 949 } 950 951 // Make another request with certificate pinning. It should complete normally. 952 client.setCertificatePinner(certificatePinnerBuilder.build()); 953 Request request2 = new Request.Builder().url(server.url("/")).build(); 954 Response response2 = client.newCall(request2).execute(); 955 assertNotSame(response2.handshake(), response1.handshake()); 956 } 957 unmatchingPinnedCertificate()958 @Test public void unmatchingPinnedCertificate() throws Exception { 959 server.useHttps(sslContext.getSocketFactory(), false); 960 server.enqueue(new MockResponse()); 961 962 client.setSslSocketFactory(sslContext.getSocketFactory()); 963 client.setHostnameVerifier(new RecordingHostnameVerifier()); 964 965 // Pin publicobject.com's cert. 966 client.setCertificatePinner(new CertificatePinner.Builder() 967 .add(server.getHostName(), "sha1/DmxUShsZuNiqPQsX2Oi9uv2sCnw=") 968 .build()); 969 970 // When we pin the wrong certificate, connectivity fails. 971 Request request = new Request.Builder().url(server.url("/")).build(); 972 try { 973 client.newCall(request).execute(); 974 fail(); 975 } catch (SSLPeerUnverifiedException expected) { 976 assertTrue(expected.getMessage().startsWith("Certificate pinning failure!")); 977 } 978 } 979 post_Async()980 @Test public void post_Async() throws Exception { 981 server.enqueue(new MockResponse().setBody("abc")); 982 983 Request request = new Request.Builder() 984 .url(server.url("/")) 985 .post(RequestBody.create(MediaType.parse("text/plain"), "def")) 986 .build(); 987 client.newCall(request).enqueue(callback); 988 989 callback.await(request.httpUrl()) 990 .assertCode(200) 991 .assertBody("abc"); 992 993 RecordedRequest recordedRequest = server.takeRequest(); 994 assertEquals("def", recordedRequest.getBody().readUtf8()); 995 assertEquals("3", recordedRequest.getHeader("Content-Length")); 996 assertEquals("text/plain; charset=utf-8", recordedRequest.getHeader("Content-Type")); 997 } 998 postBodyRetransmittedOnFailureRecovery()999 @Test public void postBodyRetransmittedOnFailureRecovery() throws Exception { 1000 server.enqueue(new MockResponse().setBody("abc")); 1001 server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.DISCONNECT_AFTER_REQUEST)); 1002 server.enqueue(new MockResponse().setBody("def")); 1003 1004 // Seed the connection pool so we have something that can fail. 1005 Request request1 = new Request.Builder().url(server.url("/")).build(); 1006 Response response1 = client.newCall(request1).execute(); 1007 assertEquals("abc", response1.body().string()); 1008 1009 Request request2 = new Request.Builder() 1010 .url(server.url("/")) 1011 .post(RequestBody.create(MediaType.parse("text/plain"), "body!")) 1012 .build(); 1013 Response response2 = client.newCall(request2).execute(); 1014 assertEquals("def", response2.body().string()); 1015 1016 RecordedRequest get = server.takeRequest(); 1017 assertEquals(0, get.getSequenceNumber()); 1018 1019 RecordedRequest post1 = server.takeRequest(); 1020 assertEquals("body!", post1.getBody().readUtf8()); 1021 assertEquals(1, post1.getSequenceNumber()); 1022 1023 RecordedRequest post2 = server.takeRequest(); 1024 assertEquals("body!", post2.getBody().readUtf8()); 1025 assertEquals(0, post2.getSequenceNumber()); 1026 } 1027 cacheHit()1028 @Test public void cacheHit() throws Exception { 1029 server.enqueue(new MockResponse() 1030 .addHeader("ETag: v1") 1031 .addHeader("Cache-Control: max-age=60") 1032 .addHeader("Vary: Accept-Charset") 1033 .setBody("A")); 1034 1035 client.setCache(cache); 1036 1037 // Store a response in the cache. 1038 HttpUrl url = server.url("/"); 1039 Request cacheStoreRequest = new Request.Builder() 1040 .url(url) 1041 .addHeader("Accept-Language", "fr-CA") 1042 .addHeader("Accept-Charset", "UTF-8") 1043 .build(); 1044 executeSynchronously(cacheStoreRequest) 1045 .assertCode(200) 1046 .assertBody("A"); 1047 assertNull(server.takeRequest().getHeader("If-None-Match")); 1048 1049 // Hit that stored response. 1050 Request cacheHitRequest = new Request.Builder() 1051 .url(url) 1052 .addHeader("Accept-Language", "en-US") // Different, but Vary says it doesn't matter. 1053 .addHeader("Accept-Charset", "UTF-8") 1054 .build(); 1055 RecordedResponse cacheHit = executeSynchronously(cacheHitRequest); 1056 1057 // Check the merged response. The request is the application's original request. 1058 cacheHit.assertCode(200) 1059 .assertBody("A") 1060 .assertHeader("ETag", "v1") 1061 .assertRequestUrl(cacheStoreRequest.url()) 1062 .assertRequestHeader("Accept-Language", "en-US") 1063 .assertRequestHeader("Accept-Charset", "UTF-8"); 1064 1065 // Check the cached response. Its request contains only the saved Vary headers. 1066 cacheHit.cacheResponse() 1067 .assertCode(200) 1068 .assertHeader("ETag", "v1") 1069 .assertRequestMethod("GET") 1070 .assertRequestUrl(cacheStoreRequest.url()) 1071 .assertRequestHeader("Accept-Language") 1072 .assertRequestHeader("Accept-Charset", "UTF-8"); 1073 1074 cacheHit.assertNoNetworkResponse(); 1075 } 1076 conditionalCacheHit()1077 @Test public void conditionalCacheHit() throws Exception { 1078 server.enqueue(new MockResponse() 1079 .addHeader("ETag: v1") 1080 .addHeader("Vary: Accept-Charset") 1081 .addHeader("Donut: a") 1082 .setBody("A")); 1083 server.enqueue(new MockResponse().clearHeaders() 1084 .addHeader("Donut: b") 1085 .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1086 1087 client.setCache(cache); 1088 1089 // Store a response in the cache. 1090 HttpUrl url = server.url("/"); 1091 Request cacheStoreRequest = new Request.Builder() 1092 .url(url) 1093 .addHeader("Accept-Language", "fr-CA") 1094 .addHeader("Accept-Charset", "UTF-8") 1095 .build(); 1096 executeSynchronously(cacheStoreRequest) 1097 .assertCode(200) 1098 .assertHeader("Donut", "a") 1099 .assertBody("A"); 1100 assertNull(server.takeRequest().getHeader("If-None-Match")); 1101 1102 // Hit that stored response. 1103 Request cacheHitRequest = new Request.Builder() 1104 .url(url) 1105 .addHeader("Accept-Language", "en-US") // Different, but Vary says it doesn't matter. 1106 .addHeader("Accept-Charset", "UTF-8") 1107 .build(); 1108 RecordedResponse cacheHit = executeSynchronously(cacheHitRequest); 1109 assertEquals("v1", server.takeRequest().getHeader("If-None-Match")); 1110 1111 // Check the merged response. The request is the application's original request. 1112 cacheHit.assertCode(200) 1113 .assertBody("A") 1114 .assertHeader("Donut", "b") 1115 .assertRequestUrl(cacheStoreRequest.url()) 1116 .assertRequestHeader("Accept-Language", "en-US") 1117 .assertRequestHeader("Accept-Charset", "UTF-8") 1118 .assertRequestHeader("If-None-Match"); // No If-None-Match on the user's request. 1119 1120 // Check the cached response. Its request contains only the saved Vary headers. 1121 cacheHit.cacheResponse() 1122 .assertCode(200) 1123 .assertHeader("Donut", "a") 1124 .assertHeader("ETag", "v1") 1125 .assertRequestUrl(cacheStoreRequest.url()) 1126 .assertRequestHeader("Accept-Language") // No Vary on Accept-Language. 1127 .assertRequestHeader("Accept-Charset", "UTF-8") // Because of Vary on Accept-Charset. 1128 .assertRequestHeader("If-None-Match"); // This wasn't present in the original request. 1129 1130 // Check the network response. It has the caller's request, plus some caching headers. 1131 cacheHit.networkResponse() 1132 .assertCode(304) 1133 .assertHeader("Donut", "b") 1134 .assertRequestHeader("Accept-Language", "en-US") 1135 .assertRequestHeader("Accept-Charset", "UTF-8") 1136 .assertRequestHeader("If-None-Match", "v1"); // If-None-Match in the validation request. 1137 } 1138 conditionalCacheHit_Async()1139 @Test public void conditionalCacheHit_Async() throws Exception { 1140 server.enqueue(new MockResponse().setBody("A").addHeader("ETag: v1")); 1141 server.enqueue(new MockResponse() 1142 .clearHeaders() 1143 .setResponseCode(HttpURLConnection.HTTP_NOT_MODIFIED)); 1144 1145 client.setCache(cache); 1146 1147 Request request1 = new Request.Builder() 1148 .url(server.url("/")) 1149 .build(); 1150 client.newCall(request1).enqueue(callback); 1151 callback.await(request1.httpUrl()).assertCode(200).assertBody("A"); 1152 assertNull(server.takeRequest().getHeader("If-None-Match")); 1153 1154 Request request2 = new Request.Builder() 1155 .url(server.url("/")) 1156 .build(); 1157 client.newCall(request2).enqueue(callback); 1158 callback.await(request2.httpUrl()).assertCode(200).assertBody("A"); 1159 assertEquals("v1", server.takeRequest().getHeader("If-None-Match")); 1160 } 1161 conditionalCacheMiss()1162 @Test public void conditionalCacheMiss() throws Exception { 1163 server.enqueue(new MockResponse() 1164 .addHeader("ETag: v1") 1165 .addHeader("Vary: Accept-Charset") 1166 .addHeader("Donut: a") 1167 .setBody("A")); 1168 server.enqueue(new MockResponse() 1169 .addHeader("Donut: b") 1170 .setBody("B")); 1171 1172 client.setCache(cache); 1173 1174 Request cacheStoreRequest = new Request.Builder() 1175 .url(server.url("/")) 1176 .addHeader("Accept-Language", "fr-CA") 1177 .addHeader("Accept-Charset", "UTF-8") 1178 .build(); 1179 executeSynchronously(cacheStoreRequest) 1180 .assertCode(200) 1181 .assertBody("A"); 1182 assertNull(server.takeRequest().getHeader("If-None-Match")); 1183 1184 Request cacheMissRequest = new Request.Builder() 1185 .url(server.url("/")) 1186 .addHeader("Accept-Language", "en-US") // Different, but Vary says it doesn't matter. 1187 .addHeader("Accept-Charset", "UTF-8") 1188 .build(); 1189 RecordedResponse cacheHit = executeSynchronously(cacheMissRequest); 1190 assertEquals("v1", server.takeRequest().getHeader("If-None-Match")); 1191 1192 // Check the user response. It has the application's original request. 1193 cacheHit.assertCode(200) 1194 .assertBody("B") 1195 .assertHeader("Donut", "b") 1196 .assertRequestUrl(cacheStoreRequest.url()); 1197 1198 // Check the cache response. Even though it's a miss, we used the cache. 1199 cacheHit.cacheResponse() 1200 .assertCode(200) 1201 .assertHeader("Donut", "a") 1202 .assertHeader("ETag", "v1") 1203 .assertRequestUrl(cacheStoreRequest.url()); 1204 1205 // Check the network response. It has the network request, plus caching headers. 1206 cacheHit.networkResponse() 1207 .assertCode(200) 1208 .assertHeader("Donut", "b") 1209 .assertRequestHeader("If-None-Match", "v1") // If-None-Match in the validation request. 1210 .assertRequestUrl(cacheStoreRequest.url()); 1211 } 1212 conditionalCacheMiss_Async()1213 @Test public void conditionalCacheMiss_Async() throws Exception { 1214 server.enqueue(new MockResponse().setBody("A").addHeader("ETag: v1")); 1215 server.enqueue(new MockResponse().setBody("B")); 1216 1217 client.setCache(cache); 1218 1219 Request request1 = new Request.Builder() 1220 .url(server.url("/")) 1221 .build(); 1222 client.newCall(request1).enqueue(callback); 1223 callback.await(request1.httpUrl()).assertCode(200).assertBody("A"); 1224 assertNull(server.takeRequest().getHeader("If-None-Match")); 1225 1226 Request request2 = new Request.Builder() 1227 .url(server.url("/")) 1228 .build(); 1229 client.newCall(request2).enqueue(callback); 1230 callback.await(request2.httpUrl()).assertCode(200).assertBody("B"); 1231 assertEquals("v1", server.takeRequest().getHeader("If-None-Match")); 1232 } 1233 onlyIfCachedReturns504WhenNotCached()1234 @Test public void onlyIfCachedReturns504WhenNotCached() throws Exception { 1235 Request request = new Request.Builder() 1236 .url(server.url("/")) 1237 .header("Cache-Control", "only-if-cached") 1238 .build(); 1239 1240 executeSynchronously(request) 1241 .assertCode(504) 1242 .assertBody("") 1243 .assertNoNetworkResponse() 1244 .assertNoCacheResponse(); 1245 } 1246 redirect()1247 @Test public void redirect() throws Exception { 1248 server.enqueue(new MockResponse() 1249 .setResponseCode(301) 1250 .addHeader("Location: /b") 1251 .addHeader("Test", "Redirect from /a to /b") 1252 .setBody("/a has moved!")); 1253 server.enqueue(new MockResponse() 1254 .setResponseCode(302) 1255 .addHeader("Location: /c") 1256 .addHeader("Test", "Redirect from /b to /c") 1257 .setBody("/b has moved!")); 1258 server.enqueue(new MockResponse().setBody("C")); 1259 1260 executeSynchronously(new Request.Builder().url(server.url("/a")).build()) 1261 .assertCode(200) 1262 .assertBody("C") 1263 .priorResponse() 1264 .assertCode(302) 1265 .assertHeader("Test", "Redirect from /b to /c") 1266 .priorResponse() 1267 .assertCode(301) 1268 .assertHeader("Test", "Redirect from /a to /b"); 1269 1270 assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection. 1271 assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reused. 1272 assertEquals(2, server.takeRequest().getSequenceNumber()); // Connection reused again! 1273 } 1274 postRedirectsToGet()1275 @Test public void postRedirectsToGet() throws Exception { 1276 server.enqueue(new MockResponse() 1277 .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) 1278 .addHeader("Location: /page2") 1279 .setBody("This page has moved!")); 1280 server.enqueue(new MockResponse().setBody("Page 2")); 1281 1282 Response response = client.newCall(new Request.Builder() 1283 .url(server.url("/page1")) 1284 .post(RequestBody.create(MediaType.parse("text/plain"), "Request Body")) 1285 .build()).execute(); 1286 assertEquals("Page 2", response.body().string()); 1287 1288 RecordedRequest page1 = server.takeRequest(); 1289 assertEquals("POST /page1 HTTP/1.1", page1.getRequestLine()); 1290 assertEquals("Request Body", page1.getBody().readUtf8()); 1291 1292 RecordedRequest page2 = server.takeRequest(); 1293 assertEquals("GET /page2 HTTP/1.1", page2.getRequestLine()); 1294 } 1295 redirectsDoNotIncludeTooManyCookies()1296 @Test public void redirectsDoNotIncludeTooManyCookies() throws Exception { 1297 server2.enqueue(new MockResponse().setBody("Page 2")); 1298 server.enqueue(new MockResponse() 1299 .setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP) 1300 .addHeader("Location: " + server2.url("/"))); 1301 1302 CookieManager cookieManager = new CookieManager(null, ACCEPT_ORIGINAL_SERVER); 1303 HttpCookie cookie = new HttpCookie("c", "cookie"); 1304 cookie.setDomain(server.getCookieDomain()); 1305 cookie.setPath("/"); 1306 String portList = Integer.toString(server.getPort()); 1307 cookie.setPortlist(portList); 1308 cookieManager.getCookieStore().add(server.url("/").uri(), cookie); 1309 client.setCookieHandler(cookieManager); 1310 1311 Response response = client.newCall(new Request.Builder() 1312 .url(server.url("/page1")) 1313 .build()).execute(); 1314 assertEquals("Page 2", response.body().string()); 1315 1316 RecordedRequest request1 = server.takeRequest(); 1317 assertEquals("$Version=\"1\"; c=\"cookie\";$Path=\"/\";$Domain=\"" 1318 + server.getCookieDomain() 1319 + "\";$Port=\"" 1320 + portList 1321 + "\"", request1.getHeader("Cookie")); 1322 1323 RecordedRequest request2 = server2.takeRequest(); 1324 assertNull(request2.getHeader("Cookie")); 1325 } 1326 redirectsDoNotIncludeTooManyAuthHeaders()1327 @Test public void redirectsDoNotIncludeTooManyAuthHeaders() throws Exception { 1328 server2.enqueue(new MockResponse().setBody("Page 2")); 1329 server.enqueue(new MockResponse() 1330 .setResponseCode(401)); 1331 server.enqueue(new MockResponse() 1332 .setResponseCode(302) 1333 .addHeader("Location: " + server2.url("/b"))); 1334 1335 client.setAuthenticator(new RecordingOkAuthenticator(Credentials.basic("jesse", "secret"))); 1336 1337 Request request = new Request.Builder().url(server.url("/a")).build(); 1338 Response response = client.newCall(request).execute(); 1339 assertEquals("Page 2", response.body().string()); 1340 1341 RecordedRequest redirectRequest = server2.takeRequest(); 1342 assertNull(redirectRequest.getHeader("Authorization")); 1343 assertEquals("/b", redirectRequest.getPath()); 1344 } 1345 redirect_Async()1346 @Test public void redirect_Async() throws Exception { 1347 server.enqueue(new MockResponse() 1348 .setResponseCode(301) 1349 .addHeader("Location: /b") 1350 .addHeader("Test", "Redirect from /a to /b") 1351 .setBody("/a has moved!")); 1352 server.enqueue(new MockResponse() 1353 .setResponseCode(302) 1354 .addHeader("Location: /c") 1355 .addHeader("Test", "Redirect from /b to /c") 1356 .setBody("/b has moved!")); 1357 server.enqueue(new MockResponse().setBody("C")); 1358 1359 Request request = new Request.Builder().url(server.url("/a")).build(); 1360 client.newCall(request).enqueue(callback); 1361 1362 callback.await(server.url("/c")) 1363 .assertCode(200) 1364 .assertBody("C") 1365 .priorResponse() 1366 .assertCode(302) 1367 .assertHeader("Test", "Redirect from /b to /c") 1368 .priorResponse() 1369 .assertCode(301) 1370 .assertHeader("Test", "Redirect from /a to /b"); 1371 1372 assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection. 1373 assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reused. 1374 assertEquals(2, server.takeRequest().getSequenceNumber()); // Connection reused again! 1375 } 1376 follow20Redirects()1377 @Test public void follow20Redirects() throws Exception { 1378 for (int i = 0; i < 20; i++) { 1379 server.enqueue(new MockResponse() 1380 .setResponseCode(301) 1381 .addHeader("Location: /" + (i + 1)) 1382 .setBody("Redirecting to /" + (i + 1))); 1383 } 1384 server.enqueue(new MockResponse().setBody("Success!")); 1385 1386 executeSynchronously(new Request.Builder().url(server.url("/0")).build()) 1387 .assertCode(200) 1388 .assertBody("Success!"); 1389 } 1390 follow20Redirects_Async()1391 @Test public void follow20Redirects_Async() throws Exception { 1392 for (int i = 0; i < 20; i++) { 1393 server.enqueue(new MockResponse() 1394 .setResponseCode(301) 1395 .addHeader("Location: /" + (i + 1)) 1396 .setBody("Redirecting to /" + (i + 1))); 1397 } 1398 server.enqueue(new MockResponse().setBody("Success!")); 1399 1400 Request request = new Request.Builder().url(server.url("/0")).build(); 1401 client.newCall(request).enqueue(callback); 1402 callback.await(server.url("/20")) 1403 .assertCode(200) 1404 .assertBody("Success!"); 1405 } 1406 doesNotFollow21Redirects()1407 @Test public void doesNotFollow21Redirects() throws Exception { 1408 for (int i = 0; i < 21; i++) { 1409 server.enqueue(new MockResponse() 1410 .setResponseCode(301) 1411 .addHeader("Location: /" + (i + 1)) 1412 .setBody("Redirecting to /" + (i + 1))); 1413 } 1414 1415 try { 1416 client.newCall(new Request.Builder().url(server.url("/0")).build()).execute(); 1417 fail(); 1418 } catch (IOException expected) { 1419 assertEquals("Too many follow-up requests: 21", expected.getMessage()); 1420 } 1421 } 1422 doesNotFollow21Redirects_Async()1423 @Test public void doesNotFollow21Redirects_Async() throws Exception { 1424 for (int i = 0; i < 21; i++) { 1425 server.enqueue(new MockResponse() 1426 .setResponseCode(301) 1427 .addHeader("Location: /" + (i + 1)) 1428 .setBody("Redirecting to /" + (i + 1))); 1429 } 1430 1431 Request request = new Request.Builder().url(server.url("/0")).build(); 1432 client.newCall(request).enqueue(callback); 1433 callback.await(server.url("/20")).assertFailure("Too many follow-up requests: 21"); 1434 } 1435 http204WithBodyDisallowed()1436 @Test public void http204WithBodyDisallowed() throws IOException { 1437 server.enqueue(new MockResponse() 1438 .setResponseCode(204) 1439 .setBody("I'm not even supposed to be here today.")); 1440 1441 try { 1442 executeSynchronously(new Request.Builder().url(server.url("/")).build()); 1443 fail(); 1444 } catch (ProtocolException e) { 1445 assertEquals("HTTP 204 had non-zero Content-Length: 39", e.getMessage()); 1446 } 1447 } 1448 http205WithBodyDisallowed()1449 @Test public void http205WithBodyDisallowed() throws IOException { 1450 server.enqueue(new MockResponse() 1451 .setResponseCode(205) 1452 .setBody("I'm not even supposed to be here today.")); 1453 1454 try { 1455 executeSynchronously(new Request.Builder().url(server.url("/")).build()); 1456 fail(); 1457 } catch (ProtocolException e) { 1458 assertEquals("HTTP 205 had non-zero Content-Length: 39", e.getMessage()); 1459 } 1460 } 1461 canceledBeforeExecute()1462 @Test public void canceledBeforeExecute() throws Exception { 1463 Call call = client.newCall(new Request.Builder().url(server.url("/a")).build()); 1464 call.cancel(); 1465 1466 try { 1467 call.execute(); 1468 fail(); 1469 } catch (IOException expected) { 1470 } 1471 assertEquals(0, server.getRequestCount()); 1472 } 1473 cancelDuringHttpConnect()1474 @Test public void cancelDuringHttpConnect() throws Exception { 1475 cancelDuringConnect("http"); 1476 } 1477 cancelDuringHttpsConnect()1478 @Test public void cancelDuringHttpsConnect() throws Exception { 1479 cancelDuringConnect("https"); 1480 } 1481 1482 /** Cancel a call that's waiting for connect to complete. */ cancelDuringConnect(String scheme)1483 private void cancelDuringConnect(String scheme) throws Exception { 1484 InetSocketAddress socketAddress = startNullServer(); 1485 1486 HttpUrl url = new HttpUrl.Builder() 1487 .scheme(scheme) 1488 .host(socketAddress.getHostName()) 1489 .port(socketAddress.getPort()) 1490 .build(); 1491 1492 long cancelDelayMillis = 300L; 1493 Call call = client.newCall(new Request.Builder().url(url).build()); 1494 cancelLater(call, cancelDelayMillis); 1495 1496 long startNanos = System.nanoTime(); 1497 try { 1498 call.execute(); 1499 fail(); 1500 } catch (IOException expected) { 1501 } 1502 long elapsedNanos = System.nanoTime() - startNanos; 1503 assertEquals(cancelDelayMillis, TimeUnit.NANOSECONDS.toMillis(elapsedNanos), 100f); 1504 } 1505 startNullServer()1506 private InetSocketAddress startNullServer() throws IOException { 1507 InetSocketAddress address = new InetSocketAddress(InetAddress.getByName("localhost"), 0); 1508 nullServer = ServerSocketFactory.getDefault().createServerSocket(); 1509 nullServer.bind(address); 1510 return new InetSocketAddress(address.getAddress(), nullServer.getLocalPort()); 1511 } 1512 cancelTagImmediatelyAfterEnqueue()1513 @Test public void cancelTagImmediatelyAfterEnqueue() throws Exception { 1514 Call call = client.newCall(new Request.Builder() 1515 .url(server.url("/a")) 1516 .tag("request") 1517 .build()); 1518 call.enqueue(callback); 1519 client.cancel("request"); 1520 assertEquals(0, server.getRequestCount()); 1521 callback.await(server.url("/a")).assertFailure("Canceled"); 1522 } 1523 cancelBeforeBodyIsRead()1524 @Test public void cancelBeforeBodyIsRead() throws Exception { 1525 server.enqueue(new MockResponse().setBody("def").throttleBody(1, 750, TimeUnit.MILLISECONDS)); 1526 1527 final Call call = client.newCall(new Request.Builder().url(server.url("/a")).build()); 1528 ExecutorService executor = Executors.newSingleThreadExecutor(); 1529 Future<Response> result = executor.submit(new Callable<Response>() { 1530 @Override public Response call() throws Exception { 1531 return call.execute(); 1532 } 1533 }); 1534 1535 Thread.sleep(100); // wait for it to go in flight. 1536 1537 call.cancel(); 1538 try { 1539 result.get().body().bytes(); 1540 fail(); 1541 } catch (IOException expected) { 1542 } 1543 assertEquals(1, server.getRequestCount()); 1544 } 1545 cancelInFlightBeforeResponseReadThrowsIOE()1546 @Test public void cancelInFlightBeforeResponseReadThrowsIOE() throws Exception { 1547 server.setDispatcher(new Dispatcher() { 1548 @Override public MockResponse dispatch(RecordedRequest request) { 1549 client.cancel("request"); 1550 return new MockResponse().setBody("A"); 1551 } 1552 }); 1553 1554 Request request = new Request.Builder().url(server.url("/a")).tag("request").build(); 1555 try { 1556 client.newCall(request).execute(); 1557 fail(); 1558 } catch (IOException expected) { 1559 } 1560 } 1561 cancelInFlightBeforeResponseReadThrowsIOE_HTTP_2()1562 @Test public void cancelInFlightBeforeResponseReadThrowsIOE_HTTP_2() throws Exception { 1563 enableProtocol(Protocol.HTTP_2); 1564 cancelInFlightBeforeResponseReadThrowsIOE(); 1565 } 1566 cancelInFlightBeforeResponseReadThrowsIOE_SPDY_3()1567 @Test public void cancelInFlightBeforeResponseReadThrowsIOE_SPDY_3() throws Exception { 1568 enableProtocol(Protocol.SPDY_3); 1569 cancelInFlightBeforeResponseReadThrowsIOE(); 1570 } 1571 1572 /** 1573 * This test puts a request in front of one that is to be canceled, so that it is canceled before 1574 * I/O takes place. 1575 */ canceledBeforeIOSignalsOnFailure()1576 @Test public void canceledBeforeIOSignalsOnFailure() throws Exception { 1577 client.getDispatcher().setMaxRequests(1); // Force requests to be executed serially. 1578 server.setDispatcher(new Dispatcher() { 1579 char nextResponse = 'A'; 1580 1581 @Override public MockResponse dispatch(RecordedRequest request) { 1582 client.cancel("request B"); 1583 return new MockResponse().setBody(Character.toString(nextResponse++)); 1584 } 1585 }); 1586 1587 Request requestA = new Request.Builder().url(server.url("/a")).tag("request A").build(); 1588 client.newCall(requestA).enqueue(callback); 1589 assertEquals("/a", server.takeRequest().getPath()); 1590 1591 Request requestB = new Request.Builder().url(server.url("/b")).tag("request B").build(); 1592 client.newCall(requestB).enqueue(callback); 1593 1594 callback.await(requestA.httpUrl()).assertBody("A"); 1595 // At this point we know the callback is ready, and that it will receive a cancel failure. 1596 callback.await(requestB.httpUrl()).assertFailure("Canceled"); 1597 } 1598 canceledBeforeIOSignalsOnFailure_HTTP_2()1599 @Test public void canceledBeforeIOSignalsOnFailure_HTTP_2() throws Exception { 1600 enableProtocol(Protocol.HTTP_2); 1601 canceledBeforeIOSignalsOnFailure(); 1602 } 1603 canceledBeforeIOSignalsOnFailure_SPDY_3()1604 @Test public void canceledBeforeIOSignalsOnFailure_SPDY_3() throws Exception { 1605 enableProtocol(Protocol.SPDY_3); 1606 canceledBeforeIOSignalsOnFailure(); 1607 } 1608 canceledBeforeResponseReadSignalsOnFailure()1609 @Test public void canceledBeforeResponseReadSignalsOnFailure() throws Exception { 1610 Request requestA = new Request.Builder().url(server.url("/a")).tag("request A").build(); 1611 final Call call = client.newCall(requestA); 1612 server.setDispatcher(new Dispatcher() { 1613 @Override public MockResponse dispatch(RecordedRequest request) { 1614 call.cancel(); 1615 return new MockResponse().setBody("A"); 1616 } 1617 }); 1618 1619 call.enqueue(callback); 1620 assertEquals("/a", server.takeRequest().getPath()); 1621 1622 callback.await(requestA.httpUrl()).assertFailure("Canceled", "stream was reset: CANCEL", 1623 "Socket closed"); 1624 } 1625 canceledBeforeResponseReadSignalsOnFailure_HTTP_2()1626 @Test public void canceledBeforeResponseReadSignalsOnFailure_HTTP_2() throws Exception { 1627 enableProtocol(Protocol.HTTP_2); 1628 canceledBeforeResponseReadSignalsOnFailure(); 1629 } 1630 canceledBeforeResponseReadSignalsOnFailure_SPDY_3()1631 @Test public void canceledBeforeResponseReadSignalsOnFailure_SPDY_3() throws Exception { 1632 enableProtocol(Protocol.SPDY_3); 1633 canceledBeforeResponseReadSignalsOnFailure(); 1634 } 1635 1636 /** 1637 * There's a race condition where the cancel may apply after the stream has already been 1638 * processed. 1639 */ canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce()1640 @Test public void canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce() throws Exception { 1641 server.enqueue(new MockResponse().setBody("A")); 1642 1643 final CountDownLatch latch = new CountDownLatch(1); 1644 final AtomicReference<String> bodyRef = new AtomicReference<>(); 1645 final AtomicBoolean failureRef = new AtomicBoolean(); 1646 1647 Request request = new Request.Builder().url(server.url("/a")).tag("request A").build(); 1648 final Call call = client.newCall(request); 1649 call.enqueue(new Callback() { 1650 @Override public void onFailure(Request request, IOException e) { 1651 failureRef.set(true); 1652 latch.countDown(); 1653 } 1654 1655 @Override public void onResponse(Response response) throws IOException { 1656 call.cancel(); 1657 try { 1658 bodyRef.set(response.body().string()); 1659 } catch (IOException e) { // It is ok if this broke the stream. 1660 bodyRef.set("A"); 1661 throw e; // We expect to not loop into onFailure in this case. 1662 } finally { 1663 latch.countDown(); 1664 } 1665 } 1666 }); 1667 1668 latch.await(); 1669 assertEquals("A", bodyRef.get()); 1670 assertFalse(failureRef.get()); 1671 } 1672 canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce_HTTP_2()1673 @Test public void canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce_HTTP_2() 1674 throws Exception { 1675 enableProtocol(Protocol.HTTP_2); 1676 canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce(); 1677 } 1678 canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce_SPDY_3()1679 @Test public void canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce_SPDY_3() 1680 throws Exception { 1681 enableProtocol(Protocol.SPDY_3); 1682 canceledAfterResponseIsDeliveredBreaksStreamButSignalsOnce(); 1683 } 1684 cancelWithInterceptor()1685 @Test public void cancelWithInterceptor() throws Exception { 1686 client.interceptors().add(new Interceptor() { 1687 @Override public Response intercept(Chain chain) throws IOException { 1688 chain.proceed(chain.request()); 1689 throw new AssertionError(); // We expect an exception. 1690 } 1691 }); 1692 1693 Call call = client.newCall(new Request.Builder().url(server.url("/a")).build()); 1694 call.cancel(); 1695 1696 try { 1697 call.execute(); 1698 fail(); 1699 } catch (IOException expected) { 1700 } 1701 assertEquals(0, server.getRequestCount()); 1702 } 1703 gzip()1704 @Test public void gzip() throws Exception { 1705 Buffer gzippedBody = gzip("abcabcabc"); 1706 String bodySize = Long.toString(gzippedBody.size()); 1707 1708 server.enqueue(new MockResponse() 1709 .setBody(gzippedBody) 1710 .addHeader("Content-Encoding: gzip")); 1711 1712 Request request = new Request.Builder() 1713 .url(server.url("/")) 1714 .build(); 1715 1716 // Confirm that the user request doesn't have Accept-Encoding, and the user 1717 // response doesn't have a Content-Encoding or Content-Length. 1718 RecordedResponse userResponse = executeSynchronously(request); 1719 userResponse.assertCode(200) 1720 .assertRequestHeader("Accept-Encoding") 1721 .assertHeader("Content-Encoding") 1722 .assertHeader("Content-Length") 1723 .assertBody("abcabcabc"); 1724 1725 // But the network request doesn't lie. OkHttp used gzip for this call. 1726 userResponse.networkResponse() 1727 .assertHeader("Content-Encoding", "gzip") 1728 .assertHeader("Content-Length", bodySize) 1729 .assertRequestHeader("Accept-Encoding", "gzip"); 1730 } 1731 asyncResponseCanBeConsumedLater()1732 @Test public void asyncResponseCanBeConsumedLater() throws Exception { 1733 server.enqueue(new MockResponse().setBody("abc")); 1734 server.enqueue(new MockResponse().setBody("def")); 1735 1736 Request request = new Request.Builder() 1737 .url(server.url("/")) 1738 .header("User-Agent", "SyncApiTest") 1739 .build(); 1740 1741 final BlockingQueue<Response> responseRef = new SynchronousQueue<>(); 1742 client.newCall(request).enqueue(new Callback() { 1743 @Override public void onFailure(Request request, IOException e) { 1744 throw new AssertionError(); 1745 } 1746 1747 @Override public void onResponse(Response response) throws IOException { 1748 try { 1749 responseRef.put(response); 1750 } catch (InterruptedException e) { 1751 throw new AssertionError(); 1752 } 1753 } 1754 }); 1755 1756 Response response = responseRef.take(); 1757 assertEquals(200, response.code()); 1758 assertEquals("abc", response.body().string()); 1759 1760 // Make another request just to confirm that that connection can be reused... 1761 executeSynchronously(new Request.Builder().url(server.url("/")).build()).assertBody("def"); 1762 assertEquals(0, server.takeRequest().getSequenceNumber()); // New connection. 1763 assertEquals(1, server.takeRequest().getSequenceNumber()); // Connection reused. 1764 1765 // ... even before we close the response body! 1766 response.body().close(); 1767 } 1768 userAgentIsIncludedByDefault()1769 @Test public void userAgentIsIncludedByDefault() throws Exception { 1770 server.enqueue(new MockResponse()); 1771 1772 executeSynchronously(new Request.Builder().url(server.url("/")).build()); 1773 1774 RecordedRequest recordedRequest = server.takeRequest(); 1775 assertTrue(recordedRequest.getHeader("User-Agent") 1776 .matches(Version.userAgent())); 1777 } 1778 setFollowRedirectsFalse()1779 @Test public void setFollowRedirectsFalse() throws Exception { 1780 server.enqueue(new MockResponse() 1781 .setResponseCode(302) 1782 .addHeader("Location: /b") 1783 .setBody("A")); 1784 server.enqueue(new MockResponse().setBody("B")); 1785 1786 client.setFollowRedirects(false); 1787 RecordedResponse recordedResponse = executeSynchronously( 1788 new Request.Builder().url(server.url("/a")).build()); 1789 1790 recordedResponse 1791 .assertBody("A") 1792 .assertCode(302); 1793 } 1794 expect100ContinueNonEmptyRequestBody()1795 @Test public void expect100ContinueNonEmptyRequestBody() throws Exception { 1796 server.enqueue(new MockResponse()); 1797 1798 Request request = new Request.Builder() 1799 .url(server.url("/")) 1800 .header("Expect", "100-continue") 1801 .post(RequestBody.create(MediaType.parse("text/plain"), "abc")) 1802 .build(); 1803 1804 executeSynchronously(request) 1805 .assertCode(200) 1806 .assertSuccessful(); 1807 1808 assertEquals("abc", server.takeRequest().getBody().readUtf8()); 1809 } 1810 expect100ContinueEmptyRequestBody()1811 @Test public void expect100ContinueEmptyRequestBody() throws Exception { 1812 server.enqueue(new MockResponse()); 1813 1814 Request request = new Request.Builder() 1815 .url(server.url("/")) 1816 .header("Expect", "100-continue") 1817 .post(RequestBody.create(MediaType.parse("text/plain"), "")) 1818 .build(); 1819 1820 executeSynchronously(request) 1821 .assertCode(200) 1822 .assertSuccessful(); 1823 } 1824 1825 /** We forbid non-ASCII characters in outgoing request headers, but accept UTF-8. */ responseHeaderParsingIsLenient()1826 @Test public void responseHeaderParsingIsLenient() throws Exception { 1827 Headers headers = new Headers.Builder() 1828 .add("Content-Length", "0") 1829 .addLenient("a\tb: c\u007fd") 1830 .addLenient(": ef") 1831 .addLenient("\ud83c\udf69: \u2615\ufe0f") 1832 .build(); 1833 server.enqueue(new MockResponse().setHeaders(headers)); 1834 1835 Request request = new Request.Builder() 1836 .url(server.url("/")) 1837 .build(); 1838 1839 executeSynchronously(request) 1840 .assertHeader("a\tb", "c\u007fd") 1841 .assertHeader("\ud83c\udf69", "\u2615\ufe0f") 1842 .assertHeader("", "ef"); 1843 } 1844 executeSynchronously(Request request)1845 private RecordedResponse executeSynchronously(Request request) throws IOException { 1846 Response response = client.newCall(request).execute(); 1847 return new RecordedResponse(request, response, null, response.body().string(), null); 1848 } 1849 1850 /** 1851 * Tests that use this will fail unless boot classpath is set. Ex. {@code 1852 * -Xbootclasspath/p:/tmp/alpn-boot-8.0.0.v20140317} 1853 */ enableProtocol(Protocol protocol)1854 private void enableProtocol(Protocol protocol) { 1855 client.setSslSocketFactory(sslContext.getSocketFactory()); 1856 client.setHostnameVerifier(new RecordingHostnameVerifier()); 1857 client.setProtocols(Arrays.asList(protocol, Protocol.HTTP_1_1)); 1858 server.useHttps(sslContext.getSocketFactory(), false); 1859 server.setProtocols(client.getProtocols()); 1860 } 1861 gzip(String data)1862 private Buffer gzip(String data) throws IOException { 1863 Buffer result = new Buffer(); 1864 BufferedSink sink = Okio.buffer(new GzipSink(result)); 1865 sink.writeUtf8(data); 1866 sink.close(); 1867 return result; 1868 } 1869 cancelLater(final Call call, final long delay)1870 private void cancelLater(final Call call, final long delay) { 1871 new Thread("canceler") { 1872 @Override public void run() { 1873 try { 1874 Thread.sleep(delay); 1875 } catch (InterruptedException e) { 1876 throw new AssertionError(); 1877 } 1878 call.cancel(); 1879 } 1880 }.start(); 1881 } 1882 1883 private static class RecordingSSLSocketFactory extends DelegatingSSLSocketFactory { 1884 1885 private List<SSLSocket> socketsCreated = new ArrayList<>(); 1886 RecordingSSLSocketFactory(SSLSocketFactory delegate)1887 public RecordingSSLSocketFactory(SSLSocketFactory delegate) { 1888 super(delegate); 1889 } 1890 1891 @Override configureSocket(SSLSocket sslSocket)1892 protected SSLSocket configureSocket(SSLSocket sslSocket) throws IOException { 1893 socketsCreated.add(sslSocket); 1894 return sslSocket; 1895 } 1896 getSocketsCreated()1897 public List<SSLSocket> getSocketsCreated() { 1898 return socketsCreated; 1899 } 1900 } 1901 1902 /** 1903 * Used during tests that involve TLS connection fallback attempts. OkHttp includes the 1904 * TLS_FALLBACK_SCSV cipher on fallback connections. See 1905 * {@link com.squareup.okhttp.FallbackTestClientSocketFactory} for details. 1906 */ suppressTlsFallbackScsv(OkHttpClient client)1907 private void suppressTlsFallbackScsv(OkHttpClient client) { 1908 FallbackTestClientSocketFactory clientSocketFactory = 1909 new FallbackTestClientSocketFactory(sslContext.getSocketFactory()); 1910 client.setSslSocketFactory(clientSocketFactory); 1911 } 1912 } 1913