|
29 | 29 | import java.util.concurrent.ExecutorService;
|
30 | 30 | import java.util.concurrent.Executors;
|
31 | 31 | import java.util.concurrent.SynchronousQueue;
|
32 |
| - |
33 | 32 | import javax.net.ssl.HostnameVerifier;
|
34 | 33 | import okhttp3.Cache;
|
35 | 34 | import okhttp3.Call;
|
|
46 | 45 | import okhttp3.Request;
|
47 | 46 | import okhttp3.RequestBody;
|
48 | 47 | import okhttp3.Response;
|
| 48 | +import okhttp3.Route; |
49 | 49 | import okhttp3.TestUtil;
|
50 | 50 | import okhttp3.internal.DoubleInetAddressDns;
|
51 | 51 | import okhttp3.internal.RecordingOkAuthenticator;
|
@@ -736,6 +736,74 @@ private void noRecoveryFromErrorWithRetryDisabled(ErrorCode errorCode) throws Ex
|
736 | 736 | }
|
737 | 737 | }
|
738 | 738 |
|
| 739 | + @Test public void recoverFromConnectionNoNewStreamsOnFollowUp() throws InterruptedException { |
| 740 | + server.enqueue(new MockResponse() |
| 741 | + .setResponseCode(401)); |
| 742 | + server.enqueue(new MockResponse() |
| 743 | + .setSocketPolicy(SocketPolicy.RESET_STREAM_AT_START) |
| 744 | + .setHttp2ErrorCode(ErrorCode.CANCEL.httpCode)); |
| 745 | + server.enqueue(new MockResponse() |
| 746 | + .setBody("DEF")); |
| 747 | + server.enqueue(new MockResponse() |
| 748 | + .setResponseCode(301) |
| 749 | + .addHeader("Location", "/foo")); |
| 750 | + server.enqueue(new MockResponse() |
| 751 | + .setBody("ABC")); |
| 752 | + |
| 753 | + final CountDownLatch latch = new CountDownLatch(1); |
| 754 | + final BlockingQueue<String> responses = new SynchronousQueue<>(); |
| 755 | + okhttp3.Authenticator authenticator = new okhttp3.Authenticator() { |
| 756 | + @Override public Request authenticate(Route route, Response response) throws IOException { |
| 757 | + responses.offer(response.body().string()); |
| 758 | + try { |
| 759 | + latch.await(); |
| 760 | + } catch (InterruptedException e) { |
| 761 | + throw new AssertionError(); |
| 762 | + } |
| 763 | + return response.request(); |
| 764 | + } |
| 765 | + }; |
| 766 | + |
| 767 | + OkHttpClient blockingAuthClient = client.newBuilder() |
| 768 | + .authenticator(authenticator) |
| 769 | + .build(); |
| 770 | + |
| 771 | + Callback callback = new Callback() { |
| 772 | + @Override public void onFailure(Call call, IOException e) { |
| 773 | + fail(); |
| 774 | + } |
| 775 | + |
| 776 | + @Override public void onResponse(Call call, Response response) throws IOException { |
| 777 | + responses.offer(response.body().string()); |
| 778 | + } |
| 779 | + }; |
| 780 | + |
| 781 | + // Make the first request waiting until we get our auth challenge. |
| 782 | + Request request = new Request.Builder() |
| 783 | + .url(server.url("/")) |
| 784 | + .build(); |
| 785 | + blockingAuthClient.newCall(request).enqueue(callback); |
| 786 | + String response1 = responses.take(); |
| 787 | + assertEquals("", response1); |
| 788 | + assertEquals(0, server.takeRequest().getSequenceNumber()); |
| 789 | + |
| 790 | + // Now make the second request which will restrict the first HTTP/2 connection from creating new |
| 791 | + // streams. |
| 792 | + client.newCall(request).enqueue(callback); |
| 793 | + String response2 = responses.take(); |
| 794 | + assertEquals("DEF", response2); |
| 795 | + assertEquals(1, server.takeRequest().getSequenceNumber()); |
| 796 | + assertEquals(0, server.takeRequest().getSequenceNumber()); |
| 797 | + |
| 798 | + // Let the first request proceed. It should discard the the held HTTP/2 connection and get a new |
| 799 | + // one. |
| 800 | + latch.countDown(); |
| 801 | + String response3 = responses.take(); |
| 802 | + assertEquals("ABC", response3); |
| 803 | + assertEquals(1, server.takeRequest().getSequenceNumber()); |
| 804 | + assertEquals(2, server.takeRequest().getSequenceNumber()); |
| 805 | + } |
| 806 | + |
739 | 807 | @Test public void nonAsciiResponseHeader() throws Exception {
|
740 | 808 | server.enqueue(new MockResponse()
|
741 | 809 | .addHeaderLenient("Alpha", "α")
|
|
0 commit comments