Example #1
0
  /**
   * When writing a set of headers fails due to an {@code IOException}, make sure the writer is left
   * in a consistent state so the next writer also gets an {@code IOException} also instead of
   * something worse (like an {@link IllegalStateException}.
   *
   * <p>See https://github.com/square/okhttp/issues/1651
   */
  @Test
  public void socketExceptionWhileWritingHeaders() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);
    peer.acceptFrame(); // SYN_STREAM.
    peer.play();

    String longString = repeat('a', Http2.INITIAL_MAX_FRAME_SIZE + 1);
    Socket socket = peer.openSocket();
    FramedConnection connection =
        new FramedConnection.Builder(true)
            .socket(socket)
            .pushObserver(IGNORE)
            .protocol(HTTP_2.getProtocol())
            .build();
    socket.shutdownOutput();
    try {
      connection.newStream(headerEntries("a", longString), false, true);
      fail();
    } catch (IOException expected) {
    }
    try {
      connection.newStream(headerEntries("b", longString), false, true);
      fail();
    } catch (IOException expected) {
    }
  }
Example #2
0
  @Test
  public void maxFrameSizeHonored() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    byte[] buff = new byte[peer.maxOutboundDataLength() + 1];
    Arrays.fill(buff, (byte) '*');

    // write the mocking script
    peer.acceptFrame(); // SYN_STREAM
    peer.sendFrame().synReply(false, 3, headerEntries("a", "android"));
    peer.acceptFrame(); // DATA
    peer.acceptFrame(); // DATA
    peer.play();

    // play it back
    FramedConnection connection = connection(peer, HTTP_2);
    FramedStream stream = connection.newStream(headerEntries("b", "banana"), true, true);
    BufferedSink out = Okio.buffer(stream.getSink());
    out.write(buff);
    out.flush();
    out.close();

    MockSpdyPeer.InFrame synStream = peer.takeFrame();
    assertEquals(TYPE_HEADERS, synStream.type);
    MockSpdyPeer.InFrame data = peer.takeFrame();
    assertEquals(peer.maxOutboundDataLength(), data.data.length);
    data = peer.takeFrame();
    assertEquals(1, data.data.length);
  }
Example #3
0
 private FramedConnection.Builder connectionBuilder(MockSpdyPeer peer, Variant variant)
     throws IOException {
   return new FramedConnection.Builder(true)
       .socket(peer.openSocket())
       .pushObserver(IGNORE)
       .protocol(variant.getProtocol());
 }
Example #4
0
  @Test
  public void readSendsWindowUpdateHttp2() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    int windowSize = 100;
    int windowUpdateThreshold = 50;

    // Write the mocking script.
    peer.acceptFrame(); // SYN_STREAM
    peer.sendFrame().synReply(false, 3, headerEntries("a", "android"));
    for (int i = 0; i < 3; i++) {
      // Send frames of summing to size 50, which is windowUpdateThreshold.
      peer.sendFrame().data(false, 3, data(24), 24);
      peer.sendFrame().data(false, 3, data(25), 25);
      peer.sendFrame().data(false, 3, data(1), 1);
      peer.acceptFrame(); // connection WINDOW UPDATE
      peer.acceptFrame(); // stream WINDOW UPDATE
    }
    peer.sendFrame().data(true, 3, data(0), 0);
    peer.play();

    // Play it back.
    FramedConnection connection = connection(peer, HTTP_2);
    connection.okHttpSettings.set(INITIAL_WINDOW_SIZE, 0, windowSize);
    FramedStream stream = connection.newStream(headerEntries("b", "banana"), false, true);
    assertEquals(0, stream.unacknowledgedBytesRead);
    assertEquals(headerEntries("a", "android"), stream.getResponseHeaders());
    Source in = stream.getSource();
    Buffer buffer = new Buffer();
    buffer.writeAll(in);
    assertEquals(-1, in.read(buffer, 1));
    assertEquals(150, buffer.size());

    MockSpdyPeer.InFrame synStream = peer.takeFrame();
    assertEquals(TYPE_HEADERS, synStream.type);
    for (int i = 0; i < 3; i++) {
      List<Integer> windowUpdateStreamIds = new ArrayList<>(2);
      for (int j = 0; j < 2; j++) {
        MockSpdyPeer.InFrame windowUpdate = peer.takeFrame();
        assertEquals(TYPE_WINDOW_UPDATE, windowUpdate.type);
        windowUpdateStreamIds.add(windowUpdate.streamId);
        assertEquals(windowUpdateThreshold, windowUpdate.windowSizeIncrement);
      }
      assertTrue(windowUpdateStreamIds.contains(0)); // connection
      assertTrue(windowUpdateStreamIds.contains(3)); // stream
    }
  }
Example #5
0
  @Test
  public void pushPromiseStream() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    // write the mocking script
    peer.acceptFrame(); // SYN_STREAM
    peer.sendFrame().synReply(false, 3, headerEntries("a", "android"));
    final List<Header> expectedRequestHeaders =
        Arrays.asList(
            new Header(Header.TARGET_METHOD, "GET"),
            new Header(Header.TARGET_SCHEME, "https"),
            new Header(Header.TARGET_AUTHORITY, "squareup.com"),
            new Header(Header.TARGET_PATH, "/cached"));
    peer.sendFrame().pushPromise(3, 2, expectedRequestHeaders);
    final List<Header> expectedResponseHeaders =
        Arrays.asList(new Header(Header.RESPONSE_STATUS, "200"));
    peer.sendFrame().synReply(true, 2, expectedResponseHeaders);
    peer.sendFrame().data(true, 3, data(0), 0);
    peer.play();

    RecordingPushObserver observer = new RecordingPushObserver();

    // play it back
    FramedConnection connection = connectionBuilder(peer, HTTP_2).pushObserver(observer).build();
    FramedStream client = connection.newStream(headerEntries("b", "banana"), false, true);
    assertEquals(-1, client.getSource().read(new Buffer(), 1));

    // verify the peer received what was expected
    assertEquals(TYPE_HEADERS, peer.takeFrame().type);

    assertEquals(expectedRequestHeaders, observer.takeEvent());
    assertEquals(expectedResponseHeaders, observer.takeEvent());
  }
Example #6
0
  @Test
  public void serverPingsClientHttp2() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    // write the mocking script
    peer.sendFrame().ping(false, 2, 3);
    peer.acceptFrame(); // PING
    peer.play();

    // play it back
    connection(peer, HTTP_2);

    // verify the peer received what was expected
    MockSpdyPeer.InFrame ping = peer.takeFrame();
    assertEquals(TYPE_PING, ping.type);
    assertEquals(0, ping.streamId);
    assertEquals(2, ping.payload1);
    assertEquals(3, ping.payload2);
    assertTrue(ping.ack);
  }
Example #7
0
  @Test
  public void pushPromiseStreamsAutomaticallyCancel() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    // write the mocking script
    peer.sendFrame()
        .pushPromise(
            3,
            2,
            Arrays.asList(
                new Header(Header.TARGET_METHOD, "GET"),
                new Header(Header.TARGET_SCHEME, "https"),
                new Header(Header.TARGET_AUTHORITY, "squareup.com"),
                new Header(Header.TARGET_PATH, "/cached")));
    peer.sendFrame().synReply(true, 2, Arrays.asList(new Header(Header.RESPONSE_STATUS, "200")));
    peer.acceptFrame(); // RST_STREAM
    peer.play();

    // play it back
    connectionBuilder(peer, HTTP_2).pushObserver(PushObserver.CANCEL).build();

    // verify the peer received what was expected
    MockSpdyPeer.InFrame rstStream = peer.takeFrame();
    assertEquals(TYPE_RST_STREAM, rstStream.type);
    assertEquals(2, rstStream.streamId);
    assertEquals(CANCEL, rstStream.errorCode);
  }
Example #8
0
  @Test
  public void clientPingsServerHttp2() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    // write the mocking script
    peer.acceptFrame(); // PING
    peer.sendFrame().ping(true, 1, 5);
    peer.play();

    // play it back
    FramedConnection connection = connection(peer, HTTP_2);
    Ping ping = connection.ping();
    assertTrue(ping.roundTripTime() > 0);
    assertTrue(ping.roundTripTime() < TimeUnit.SECONDS.toNanos(1));

    // verify the peer received what was expected
    MockSpdyPeer.InFrame pingFrame = peer.takeFrame();
    assertEquals(0, pingFrame.streamId);
    assertEquals(1, pingFrame.payload1);
    assertEquals(0x4f4b6f6b, pingFrame.payload2); // connection.ping() sets this.
    assertFalse(pingFrame.ack);
  }
Example #9
0
  @Test
  public void doublePushPromise() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    // write the mocking script
    peer.sendFrame().pushPromise(3, 2, headerEntries("a", "android"));
    peer.acceptFrame(); // SYN_REPLY
    peer.sendFrame().pushPromise(3, 2, headerEntries("b", "banana"));
    peer.acceptFrame(); // RST_STREAM
    peer.play();

    // play it back
    FramedConnection connection = connectionBuilder(peer, HTTP_2).build();
    connection.newStream(headerEntries("b", "banana"), false, true);

    // verify the peer received what was expected
    assertEquals(TYPE_HEADERS, peer.takeFrame().type);
    assertEquals(PROTOCOL_ERROR, peer.takeFrame().errorCode);
  }
Example #10
0
  @Test
  public void peerHttp2ServerLowersInitialWindowSize() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    Settings initial = new Settings();
    initial.set(INITIAL_WINDOW_SIZE, PERSIST_VALUE, 1684);
    Settings shouldntImpactConnection = new Settings();
    shouldntImpactConnection.set(INITIAL_WINDOW_SIZE, PERSIST_VALUE, 3368);

    peer.sendFrame().settings(initial);
    peer.acceptFrame(); // ACK
    peer.sendFrame().settings(shouldntImpactConnection);
    peer.acceptFrame(); // ACK 2
    peer.acceptFrame(); // HEADERS
    peer.play();

    FramedConnection connection = connection(peer, HTTP_2);

    // Default is 64KiB - 1.
    assertEquals(65535, connection.peerSettings.getInitialWindowSize(-1));

    // Verify the peer received the ACK.
    MockSpdyPeer.InFrame ackFrame = peer.takeFrame();
    assertEquals(TYPE_SETTINGS, ackFrame.type);
    assertEquals(0, ackFrame.streamId);
    assertTrue(ackFrame.ack);
    ackFrame = peer.takeFrame();
    assertEquals(TYPE_SETTINGS, ackFrame.type);
    assertEquals(0, ackFrame.streamId);
    assertTrue(ackFrame.ack);

    // This stream was created *after* the connection settings were adjusted.
    FramedStream stream = connection.newStream(headerEntries("a", "android"), false, true);

    assertEquals(3368, connection.peerSettings.getInitialWindowSize(DEFAULT_INITIAL_WINDOW_SIZE));
    assertEquals(1684, connection.bytesLeftInWriteWindow); // initial wasn't affected.
    // New Stream is has the most recent initial window size.
    assertEquals(3368, stream.bytesLeftInWriteWindow);
  }
Example #11
0
  @Test
  public void clientSendsEmptyDataServerDoesntSendWindowUpdateHttp2() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    // Write the mocking script.
    peer.acceptFrame(); // SYN_STREAM
    peer.acceptFrame(); // DATA
    peer.sendFrame().synReply(false, 3, headerEntries("a", "android"));
    peer.play();

    // Play it back.
    FramedConnection connection = connection(peer, HTTP_2);
    FramedStream client = connection.newStream(headerEntries("b", "banana"), true, true);
    BufferedSink out = Okio.buffer(client.getSink());
    out.write(EMPTY_BYTE_ARRAY);
    out.flush();
    out.close();

    // Verify the peer received what was expected.
    assertEquals(TYPE_HEADERS, peer.takeFrame().type);
    assertEquals(TYPE_DATA, peer.takeFrame().type);
    assertEquals(3, peer.frameCount());
  }
Example #12
0
  @Test
  public void serverSendsEmptyDataClientDoesntSendWindowUpdateHttp2() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    // Write the mocking script.
    peer.acceptFrame(); // SYN_STREAM
    peer.sendFrame().synReply(false, 3, headerEntries("a", "android"));
    peer.sendFrame().data(true, 3, data(0), 0);
    peer.play();

    // Play it back.
    FramedConnection connection = connection(peer, HTTP_2);
    FramedStream client = connection.newStream(headerEntries("b", "banana"), false, true);
    assertEquals(-1, client.getSource().read(new Buffer(), 1));

    // Verify the peer received what was expected.
    MockSpdyPeer.InFrame synStream = peer.takeFrame();
    assertEquals(TYPE_HEADERS, synStream.type);
    assertEquals(3, peer.frameCount());
  }
Example #13
0
  private FramedConnection sendHttp2SettingsAndCheckForAck(boolean client, Settings settings)
      throws IOException, InterruptedException {
    peer.setVariantAndClient(HTTP_2, client);
    peer.sendFrame().settings(settings);
    peer.acceptFrame(); // ACK
    peer.acceptFrame(); // PING
    peer.sendFrame().ping(true, 1, 0);
    peer.play();

    // play it back
    FramedConnection connection = connection(peer, HTTP_2);

    // verify the peer received the ACK
    MockSpdyPeer.InFrame ackFrame = peer.takeFrame();
    assertEquals(TYPE_SETTINGS, ackFrame.type);
    assertEquals(0, ackFrame.streamId);
    assertTrue(ackFrame.ack);

    connection.ping().roundTripTime(); // Ensure that settings have been applied before returning.
    return connection;
  }
Example #14
0
 @After
 public void tearDown() throws Exception {
   peer.close();
 }
Example #15
0
  @Test
  public void receiveGoAwayHttp2() throws Exception {
    peer.setVariantAndClient(HTTP_2, false);

    // write the mocking script
    peer.acceptFrame(); // SYN_STREAM 3
    peer.acceptFrame(); // SYN_STREAM 5
    peer.sendFrame().goAway(3, PROTOCOL_ERROR, EMPTY_BYTE_ARRAY);
    peer.acceptFrame(); // PING
    peer.sendFrame().ping(true, 1, 0);
    peer.acceptFrame(); // DATA STREAM 3
    peer.play();

    // play it back
    FramedConnection connection = connection(peer, HTTP_2);
    FramedStream stream1 = connection.newStream(headerEntries("a", "android"), true, true);
    FramedStream stream2 = connection.newStream(headerEntries("b", "banana"), true, true);
    connection.ping().roundTripTime(); // Ensure the GO_AWAY that resets stream2 has been received.
    BufferedSink sink1 = Okio.buffer(stream1.getSink());
    BufferedSink sink2 = Okio.buffer(stream2.getSink());
    sink1.writeUtf8("abc");
    try {
      sink2.writeUtf8("abc");
      sink2.flush();
      fail();
    } catch (IOException expected) {
      assertEquals("stream was reset: REFUSED_STREAM", expected.getMessage());
    }
    sink1.writeUtf8("def");
    sink1.close();
    try {
      connection.newStream(headerEntries("c", "cola"), true, true);
      fail();
    } catch (IOException expected) {
      assertEquals("shutdown", expected.getMessage());
    }
    assertTrue(stream1.isOpen());
    assertFalse(stream2.isOpen());
    assertEquals(1, connection.openStreamCount());

    // verify the peer received what was expected
    MockSpdyPeer.InFrame synStream1 = peer.takeFrame();
    assertEquals(TYPE_HEADERS, synStream1.type);
    MockSpdyPeer.InFrame synStream2 = peer.takeFrame();
    assertEquals(TYPE_HEADERS, synStream2.type);
    MockSpdyPeer.InFrame ping = peer.takeFrame();
    assertEquals(TYPE_PING, ping.type);
    MockSpdyPeer.InFrame data1 = peer.takeFrame();
    assertEquals(TYPE_DATA, data1.type);
    assertEquals(3, data1.streamId);
    assertTrue(Arrays.equals("abcdef".getBytes("UTF-8"), data1.data));
  }