1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-18 20:40:58 +03:00

Implement HTTP/2 Draft 13; HPACK Draft 08.

This commit is contained in:
Adrian Cole
2014-06-21 11:39:39 -07:00
parent c0e0b25635
commit 802b773994
16 changed files with 242 additions and 633 deletions

View File

@@ -25,7 +25,8 @@ import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.internal.http.StatusLine;
import com.squareup.okhttp.internal.spdy.Http20Draft12;
import com.squareup.okhttp.internal.spdy.Http20Draft13;
import io.airlift.command.Arguments;
import io.airlift.command.Command;
import io.airlift.command.HelpOption;
@@ -265,7 +266,7 @@ public class Main extends HelpOption implements Runnable {
}
private static void enableHttp2FrameLogging() {
Logger logger = Logger.getLogger(Http20Draft12.class.getName());
Logger logger = Logger.getLogger(Http20Draft13.class.getName());
logger.setLevel(Level.FINE);
ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.FINE);

View File

@@ -24,9 +24,9 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class HttpOverHttp20Draft12Test extends HttpOverSpdyTest {
public class HttpOverHttp20Draft13Test extends HttpOverSpdyTest {
public HttpOverHttp20Draft12Test() {
public HttpOverHttp20Draft13Test() {
super(Protocol.HTTP_2);
this.hostHeader = ":authority";
}

View File

@@ -30,23 +30,23 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class HpackDraft07Test {
public class HpackDraft08Test {
private final Buffer bytesIn = new Buffer();
private HpackDraft07.Reader hpackReader;
private HpackDraft08.Reader hpackReader;
private Buffer bytesOut = new Buffer();
private HpackDraft07.Writer hpackWriter;
private HpackDraft08.Writer hpackWriter;
@Before public void reset() {
hpackReader = newReader(bytesIn);
hpackWriter = new HpackDraft07.Writer(bytesOut);
hpackWriter = new HpackDraft08.Writer(bytesOut);
}
/**
* Variable-length quantity special cases strings which are longer than 127
* bytes. Values such as cookies can be 4KiB, and should be possible to send.
*
* <p> http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#section-4.1.1
* <p> http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#section-4.1.1
*/
@Test public void largeHeaderValue() throws IOException {
char[] value = new char[4096];
@@ -157,7 +157,7 @@ public class HpackDraft07Test {
// Indexed name (idx = 4) -> :path
bytesIn.writeByte(0x8c); // Literal value Huffman encoded 12 bytes
// decodes to www.example.com which is length 15
bytesIn.write(decodeHex("e7cf9bebe89b6fb16fa9b6ff"));
bytesIn.write(decodeHex("f1e3c2e5f23a6ba0ab90f4ff"));
hpackReader.readHeaders();
hpackReader.emitReferenceSet();
@@ -171,7 +171,7 @@ public class HpackDraft07Test {
}
/**
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-D.1.1
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#appendix-D.1.1
*/
@Test public void readLiteralHeaderFieldWithIndexing() throws IOException {
bytesIn.writeByte(0x40); // Literal indexed
@@ -195,7 +195,7 @@ public class HpackDraft07Test {
}
/**
* https://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-D.2.2
* https://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#appendix-D.2.2
*/
@Test public void literalHeaderFieldWithoutIndexingIndexedName() throws IOException {
List<Header> headerBlock = headerEntries(":path", "/sample/path");
@@ -268,7 +268,7 @@ public class HpackDraft07Test {
}
/**
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-D.1.3
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#appendix-D.1.3
*/
@Test public void readIndexedHeaderField() throws IOException {
bytesIn.writeByte(0x82); // == Indexed - Add ==
@@ -379,7 +379,7 @@ public class HpackDraft07Test {
}
/**
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#section-3.2.1
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#section-3.2.1
*/
@Test public void toggleIndex() throws IOException {
// Static table entries are copied to the top of the reference set.
@@ -444,7 +444,7 @@ public class HpackDraft07Test {
}
/**
* https://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-D.2.4
* https://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#appendix-D.2.4
*/
@Test public void readIndexedHeaderFieldFromStaticTableWithoutBuffering() throws IOException {
bytesIn.writeByte(0x82); // == Indexed - Add ==
@@ -461,7 +461,7 @@ public class HpackDraft07Test {
}
/**
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-D.2
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#appendix-D.2
*/
@Test public void readRequestExamplesWithoutHuffman() throws IOException {
firstRequestWithoutHuffman();
@@ -648,7 +648,7 @@ public class HpackDraft07Test {
}
/**
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-D.3
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#appendix-D.3
*/
@Test public void readRequestExamplesWithHuffman() throws IOException {
firstRequestWithHuffman();
@@ -676,9 +676,9 @@ public class HpackDraft07Test {
// idx = 6 -> :path: /
bytesIn.writeByte(0x44); // == Literal indexed ==
// Indexed name (idx = 4) -> :authority
bytesIn.writeByte(0x8c); // Literal value Huffman encoded 12 bytes
bytesIn.writeByte(0x0f); // Literal value Huffman encoded 12 bytes
// decodes to www.example.com which is length 15
bytesIn.write(decodeHex("e7cf9bebe89b6fb16fa9b6ff"));
bytesIn.write(decodeHex("7777772e6578616d706c652e636f6d"));
}
private void checkReadFirstRequestWithHuffman() {
@@ -720,7 +720,7 @@ public class HpackDraft07Test {
// Indexed name (idx = 28) -> cache-control
bytesIn.writeByte(0x86); // Literal value Huffman encoded 6 bytes
// decodes to no-cache which is length 8
bytesIn.write(decodeHex("b9b9949556bf"));
bytesIn.write(decodeHex("a8eb10649cbf"));
}
private void checkReadSecondRequestWithHuffman() {
@@ -776,10 +776,10 @@ public class HpackDraft07Test {
bytesIn.writeByte(0x40); // Literal indexed
bytesIn.writeByte(0x88); // Literal name Huffman encoded 8 bytes
// decodes to custom-key which is length 10
bytesIn.write(decodeHex("571c5cdb737b2faf"));
bytesIn.writeByte(0x89); // Literal value Huffman encoded 6 bytes
bytesIn.write(decodeHex("25a849e95ba97d7f"));
bytesIn.writeByte(0x89); // Literal value Huffman encoded 9 bytes
// decodes to custom-value which is length 12
bytesIn.write(decodeHex("571c5cdb73724d9c57"));
bytesIn.write(decodeHex("25a849e95bb8e8b4bf"));
}
private void checkReadThirdRequestWithHuffman() {
@@ -906,8 +906,8 @@ public class HpackDraft07Test {
assertEquals(ByteString.EMPTY, newReader(byteStream(0)).readByteString());
}
private HpackDraft07.Reader newReader(Buffer source) {
return new HpackDraft07.Reader(4096, source);
private HpackDraft08.Reader newReader(Buffer source) {
return new HpackDraft08.Reader(4096, source);
}
private Buffer byteStream(int... bytes) {

View File

@@ -20,22 +20,22 @@ import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_ACK;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_END_HEADERS;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_END_STREAM;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_NONE;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FrameLogger.formatFlags;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FrameLogger.formatHeader;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.TYPE_CONTINUATION;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.TYPE_DATA;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.TYPE_GOAWAY;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.TYPE_HEADERS;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.TYPE_PING;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.TYPE_PUSH_PROMISE;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.TYPE_SETTINGS;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_ACK;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_END_HEADERS;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_END_STREAM;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_NONE;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FrameLogger.formatFlags;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FrameLogger.formatHeader;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.TYPE_CONTINUATION;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.TYPE_DATA;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.TYPE_GOAWAY;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.TYPE_HEADERS;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.TYPE_PING;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.TYPE_PUSH_PROMISE;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.TYPE_SETTINGS;
import static org.junit.Assert.assertEquals;
public class Http20Draft12FrameLoggerTest {
public class Http20Draft13FrameLoggerTest {
/** Real stream traffic applied to the log format. */
@Test public void exampleStream() {
@@ -103,14 +103,14 @@ public class Http20Draft12FrameLoggerTest {
"END_STREAM|END_HEADERS",
"END_SEGMENT|END_HEADERS",
"END_STREAM|END_SEGMENT|END_HEADERS",
"PAD_LOW",
"END_STREAM|PAD_LOW",
"END_SEGMENT|PAD_LOW",
"END_STREAM|END_SEGMENT|PAD_LOW",
"PADDED",
"END_STREAM|PADDED",
"END_SEGMENT|PADDED",
"END_STREAM|END_SEGMENT|PADDED",
"00001100",
"END_STREAM|END_HEADERS|PAD_LOW",
"END_SEGMENT|END_HEADERS|PAD_LOW",
"END_STREAM|END_SEGMENT|END_HEADERS|PAD_LOW",
"END_STREAM|END_HEADERS|PADDED",
"END_SEGMENT|END_HEADERS|PADDED",
"END_STREAM|END_SEGMENT|END_HEADERS|PADDED",
"00010000",
"00010001",
"00010010",
@@ -119,14 +119,14 @@ public class Http20Draft12FrameLoggerTest {
"00010101",
"00010110",
"00010111",
"PAD_LOW|PAD_HIGH",
"END_STREAM|PAD_LOW|PAD_HIGH",
"END_SEGMENT|PAD_LOW|PAD_HIGH",
"END_STREAM|END_SEGMENT|PAD_LOW|PAD_HIGH",
"00011000",
"00011001",
"00011010",
"00011011",
"00011100",
"END_STREAM|END_HEADERS|PAD_LOW|PAD_HIGH",
"END_SEGMENT|END_HEADERS|PAD_LOW|PAD_HIGH",
"END_STREAM|END_SEGMENT|END_HEADERS|PAD_LOW|PAD_HIGH",
"00011101",
"00011110",
"00011111",
"PRIORITY",
"END_STREAM|PRIORITY",
"END_SEGMENT|PRIORITY",
@@ -136,13 +136,13 @@ public class Http20Draft12FrameLoggerTest {
"END_SEGMENT|END_HEADERS|PRIORITY",
"END_STREAM|END_SEGMENT|END_HEADERS|PRIORITY",
"00101000",
"END_STREAM|PRIORITY|PAD_LOW",
"END_SEGMENT|PRIORITY|PAD_LOW",
"END_STREAM|END_SEGMENT|PRIORITY|PAD_LOW",
"END_STREAM|PRIORITY|PADDED",
"END_SEGMENT|PRIORITY|PADDED",
"END_STREAM|END_SEGMENT|PRIORITY|PADDED",
"00101100",
"END_STREAM|END_HEADERS|PRIORITY|PAD_LOW",
"END_SEGMENT|END_HEADERS|PRIORITY|PAD_LOW",
"END_STREAM|END_SEGMENT|END_HEADERS|PRIORITY|PAD_LOW",
"END_STREAM|END_HEADERS|PRIORITY|PADDED",
"END_SEGMENT|END_HEADERS|PRIORITY|PADDED",
"END_STREAM|END_SEGMENT|END_HEADERS|PRIORITY|PADDED",
"00110000",
"00110001",
"00110010",
@@ -152,13 +152,13 @@ public class Http20Draft12FrameLoggerTest {
"00110110",
"00110111",
"00111000",
"END_STREAM|PRIORITY|PAD_LOW|PAD_HIGH",
"END_SEGMENT|PRIORITY|PAD_LOW|PAD_HIGH",
"END_STREAM|END_SEGMENT|PRIORITY|PAD_LOW|PAD_HIGH",
"00111001",
"00111010",
"00111011",
"00111100",
"END_STREAM|END_HEADERS|PRIORITY|PAD_LOW|PAD_HIGH",
"END_SEGMENT|END_HEADERS|PRIORITY|PAD_LOW|PAD_HIGH",
"END_STREAM|END_SEGMENT|END_HEADERS|PRIORITY|PAD_LOW|PAD_HIGH"
"00111101",
"00111110",
"00111111"
), formattedFlags);
}
}

View File

@@ -15,49 +15,44 @@
*/
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.Protocol;
import com.squareup.okhttp.internal.Util;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import com.squareup.okhttp.internal.Util;
import org.junit.Test;
import okio.Buffer;
import okio.BufferedSource;
import okio.ByteString;
import okio.GzipSink;
import okio.Okio;
import org.junit.Test;
import static com.squareup.okhttp.internal.Util.headerEntries;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_COMPRESSED;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_END_HEADERS;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_END_STREAM;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_NONE;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_PAD_HIGH;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_PAD_LOW;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FLAG_PRIORITY;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_COMPRESSED;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_END_HEADERS;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_END_STREAM;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_NONE;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_PADDED;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FLAG_PRIORITY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class Http20Draft12Test {
public class Http20Draft13Test {
final Buffer frame = new Buffer();
final FrameReader fr = new Http20Draft12.Reader(frame, 4096, false);
final FrameReader fr = new Http20Draft13.Reader(frame, 4096, false);
final int expectedStreamId = 15;
@Test public void unknownFrameTypeProtocolError() throws IOException {
@Test public void unknownFrameTypeSkipped() throws IOException {
frame.writeShort(4); // has a 4-byte field
frame.writeByte(99); // type 99
frame.writeByte(0); // no flags
frame.writeInt(expectedStreamId);
frame.writeInt(111111111); // custom data
try {
fr.nextFrame(new BaseTestHandler());
fail();
} catch (IOException e) {
assertEquals("PROTOCOL_ERROR: unknown frame type 99", e.getMessage());
}
fr.nextFrame(new BaseTestHandler()); // Should not callback.
}
@Test public void onlyOneLiteralHeadersFrame() throws IOException {
@@ -65,7 +60,7 @@ public class Http20Draft12Test {
Buffer headerBytes = literalHeaders(sentHeaders);
frame.writeShort((int) headerBytes.size());
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(Http20Draft13.TYPE_HEADERS);
frame.writeByte(FLAG_END_HEADERS | FLAG_END_STREAM);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeAll(headerBytes);
@@ -91,7 +86,7 @@ public class Http20Draft12Test {
Buffer headerBytes = literalHeaders(sentHeaders);
frame.writeShort((int) (headerBytes.size() + 5));
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(Http20Draft13.TYPE_HEADERS);
frame.writeByte(FLAG_END_HEADERS | FLAG_PRIORITY);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeInt(0); // Independent stream.
@@ -126,15 +121,15 @@ public class Http20Draft12Test {
Buffer headerBlock = literalHeaders(sentHeaders);
// Write the first headers frame.
frame.writeShort(Http20Draft12.MAX_FRAME_SIZE);
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeShort(Http20Draft13.MAX_FRAME_SIZE);
frame.writeByte(Http20Draft13.TYPE_HEADERS);
frame.writeByte(0); // no flags
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.write(headerBlock, Http20Draft12.MAX_FRAME_SIZE);
frame.write(headerBlock, Http20Draft13.MAX_FRAME_SIZE);
// Write the continuation frame, specifying no more frames are expected.
frame.writeShort((int) headerBlock.size());
frame.writeByte(Http20Draft12.TYPE_CONTINUATION);
frame.writeByte(Http20Draft13.TYPE_CONTINUATION);
frame.writeByte(FLAG_END_HEADERS);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeAll(headerBlock);
@@ -168,8 +163,8 @@ public class Http20Draft12Test {
// Write the push promise frame, specifying the associated stream ID.
Buffer headerBytes = literalHeaders(pushPromise);
frame.writeShort((int) (headerBytes.size() + 4));
frame.writeByte(Http20Draft12.TYPE_PUSH_PROMISE);
frame.writeByte(Http20Draft12.FLAG_END_PUSH_PROMISE);
frame.writeByte(Http20Draft13.TYPE_PUSH_PROMISE);
frame.writeByte(Http20Draft13.FLAG_END_PUSH_PROMISE);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeInt(expectedPromisedStreamId & 0x7fffffff);
frame.writeAll(headerBytes);
@@ -195,8 +190,8 @@ public class Http20Draft12Test {
Buffer headerBlock = literalHeaders(pushPromise);
// Write the first headers frame.
frame.writeShort(Http20Draft12.MAX_FRAME_SIZE);
frame.writeByte(Http20Draft12.TYPE_PUSH_PROMISE);
frame.writeShort(Http20Draft13.MAX_FRAME_SIZE);
frame.writeByte(Http20Draft13.TYPE_PUSH_PROMISE);
frame.writeByte(0); // no flags
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeInt(expectedPromisedStreamId & 0x7fffffff);
@@ -204,7 +199,7 @@ public class Http20Draft12Test {
// Write the continuation frame, specifying no more frames are expected.
frame.writeShort((int) headerBlock.size());
frame.writeByte(Http20Draft12.TYPE_CONTINUATION);
frame.writeByte(Http20Draft13.TYPE_CONTINUATION);
frame.writeByte(FLAG_END_HEADERS);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeAll(headerBlock);
@@ -224,7 +219,7 @@ public class Http20Draft12Test {
@Test public void readRstStreamFrame() throws IOException {
frame.writeShort(4);
frame.writeByte(Http20Draft12.TYPE_RST_STREAM);
frame.writeByte(Http20Draft13.TYPE_RST_STREAM);
frame.writeByte(0); // No flags
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeInt(ErrorCode.COMPRESSION_ERROR.httpCode);
@@ -240,15 +235,13 @@ public class Http20Draft12Test {
@Test public void readSettingsFrame() throws IOException {
final int reducedTableSizeBytes = 16;
frame.writeShort(15); // 3 settings * 5 bytes (1 for the code and 4 for the value).
frame.writeByte(Http20Draft12.TYPE_SETTINGS);
frame.writeShort(12); // 2 settings * 6 bytes (2 for the code and 4 for the value).
frame.writeByte(Http20Draft13.TYPE_SETTINGS);
frame.writeByte(0); // No flags
frame.writeInt(0); // Settings are always on the connection stream 0.
frame.writeByte(1); // SETTINGS_HEADER_TABLE_SIZE
frame.writeShort(1); // SETTINGS_HEADER_TABLE_SIZE
frame.writeInt(reducedTableSizeBytes);
frame.writeByte(2); // SETTINGS_ENABLE_PUSH
frame.writeInt(0);
frame.writeByte(5); // SETTINGS_COMPRESS_DATA
frame.writeShort(2); // SETTINGS_ENABLE_PUSH
frame.writeInt(0);
fr.nextFrame(new BaseTestHandler() {
@@ -256,17 +249,16 @@ public class Http20Draft12Test {
assertFalse(clearPrevious); // No clearPrevious in HTTP/2.
assertEquals(reducedTableSizeBytes, settings.getHeaderTableSize());
assertEquals(false, settings.getEnablePush(true));
assertEquals(false, settings.getCompressData(true));
}
});
}
@Test public void readSettingsFrameInvalidPushValue() throws IOException {
frame.writeShort(5); // 1 for the code and 4 for the value
frame.writeByte(Http20Draft12.TYPE_SETTINGS);
frame.writeShort(6); // 2 for the code and 4 for the value
frame.writeByte(Http20Draft13.TYPE_SETTINGS);
frame.writeByte(0); // No flags
frame.writeInt(0); // Settings are always on the connection stream 0.
frame.writeByte(2);
frame.writeShort(2);
frame.writeInt(2);
try {
@@ -278,11 +270,11 @@ public class Http20Draft12Test {
}
@Test public void readSettingsFrameInvalidSettingId() throws IOException {
frame.writeShort(5); // 1 for the code and 4 for the value
frame.writeByte(Http20Draft12.TYPE_SETTINGS);
frame.writeShort(6); // 2 for the code and 4 for the value
frame.writeByte(Http20Draft13.TYPE_SETTINGS);
frame.writeByte(0); // No flags
frame.writeInt(0); // Settings are always on the connection stream 0.
frame.writeByte(7); // old number for SETTINGS_INITIAL_WINDOW_SIZE
frame.writeShort(7); // old number for SETTINGS_INITIAL_WINDOW_SIZE
frame.writeInt(1);
try {
@@ -294,11 +286,11 @@ public class Http20Draft12Test {
}
@Test public void readSettingsFrameNegativeWindowSize() throws IOException {
frame.writeShort(5); // 1 for the code and 4 for the value
frame.writeByte(Http20Draft12.TYPE_SETTINGS);
frame.writeShort(6); // 2 for the code and 4 for the value
frame.writeByte(Http20Draft13.TYPE_SETTINGS);
frame.writeByte(0); // No flags
frame.writeInt(0); // Settings are always on the connection stream 0.
frame.writeByte(4); // SETTINGS_INITIAL_WINDOW_SIZE
frame.writeShort(4); // SETTINGS_INITIAL_WINDOW_SIZE
frame.writeInt(Integer.MIN_VALUE);
try {
@@ -314,8 +306,8 @@ public class Http20Draft12Test {
final int expectedPayload2 = 8;
frame.writeShort(8); // length
frame.writeByte(Http20Draft12.TYPE_PING);
frame.writeByte(Http20Draft12.FLAG_ACK);
frame.writeByte(Http20Draft13.TYPE_PING);
frame.writeByte(Http20Draft13.FLAG_ACK);
frame.writeInt(0); // connection-level
frame.writeInt(expectedPayload1);
frame.writeInt(expectedPayload2);
@@ -333,11 +325,11 @@ public class Http20Draft12Test {
}
@Test public void maxLengthDataFrame() throws IOException {
final byte[] expectedData = new byte[Http20Draft12.MAX_FRAME_SIZE];
final byte[] expectedData = new byte[Http20Draft13.MAX_FRAME_SIZE];
Arrays.fill(expectedData, (byte) 2);
frame.writeShort(expectedData.length);
frame.writeByte(Http20Draft12.TYPE_DATA);
frame.writeByte(Http20Draft13.TYPE_DATA);
frame.writeByte(0); // no flags
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.write(expectedData);
@@ -350,7 +342,7 @@ public class Http20Draft12Test {
int length) throws IOException {
assertFalse(inFinished);
assertEquals(expectedStreamId, streamId);
assertEquals(Http20Draft12.MAX_FRAME_SIZE, length);
assertEquals(Http20Draft13.MAX_FRAME_SIZE, length);
ByteString data = source.readByteString(length);
for (byte b : data.toByteArray()) {
assertEquals(2, b);
@@ -361,13 +353,13 @@ public class Http20Draft12Test {
/** We do not send SETTINGS_COMPRESS_DATA = 1, nor want to. Let's make sure we error. */
@Test public void compressedDataFrameWhenSettingDisabled() throws IOException {
byte[] expectedData = new byte[Http20Draft12.MAX_FRAME_SIZE];
byte[] expectedData = new byte[Http20Draft13.MAX_FRAME_SIZE];
Arrays.fill(expectedData, (byte) 2);
Buffer zipped = gzip(expectedData);
int zippedSize = (int) zipped.size();
frame.writeShort(zippedSize);
frame.writeByte(Http20Draft12.TYPE_DATA);
frame.writeByte(Http20Draft13.TYPE_DATA);
frame.writeByte(FLAG_COMPRESSED);
frame.writeInt(expectedStreamId & 0x7fffffff);
zipped.readAll(frame);
@@ -386,15 +378,15 @@ public class Http20Draft12Test {
byte[] expectedData = new byte[dataLength];
Arrays.fill(expectedData, (byte) 2);
int paddingLength = 257;
int paddingLength = 254;
byte[] padding = new byte[paddingLength];
Arrays.fill(padding, (byte) 0);
frame.writeShort(dataLength + paddingLength + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_DATA);
frame.writeByte(FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeShort(dataLength + paddingLength + 1);
frame.writeByte(Http20Draft13.TYPE_DATA);
frame.writeByte(FLAG_PADDED);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(paddingLength);
frame.writeByte(paddingLength);
frame.write(expectedData);
frame.write(padding);
@@ -402,29 +394,14 @@ public class Http20Draft12Test {
assertTrue(frame.exhausted()); // Padding was skipped.
}
@Test public void readPaddedDataFrameZeroPaddingHigh() throws IOException {
int dataLength = 1123;
byte[] expectedData = new byte[dataLength];
Arrays.fill(expectedData, (byte) 2);
frame.writeShort(dataLength + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_DATA);
frame.writeByte(FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(0);
frame.write(expectedData);
fr.nextFrame(assertData());
}
@Test public void readPaddedDataFrameZeroPaddingLow() throws IOException {
@Test public void readPaddedDataFrameZeroPadding() throws IOException {
int dataLength = 1123;
byte[] expectedData = new byte[dataLength];
Arrays.fill(expectedData, (byte) 2);
frame.writeShort(dataLength + 1);
frame.writeByte(Http20Draft12.TYPE_DATA);
frame.writeByte(FLAG_PAD_LOW);
frame.writeByte(Http20Draft13.TYPE_DATA);
frame.writeByte(FLAG_PADDED);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeByte(0);
frame.write(expectedData);
@@ -432,69 +409,17 @@ public class Http20Draft12Test {
fr.nextFrame(assertData());
}
@Test public void readPaddedDataFrameMissingLowFlag() throws IOException {
int dataLength = 1123;
byte[] expectedData = new byte[dataLength];
Arrays.fill(expectedData, (byte) 2);
int paddingLength = 257;
byte[] padding = new byte[paddingLength];
Arrays.fill(padding, (byte) 0);
frame.writeShort(dataLength + paddingLength + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_DATA);
frame.writeByte(FLAG_PAD_HIGH);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(paddingLength);
frame.write(expectedData);
frame.write(padding);
try {
fr.nextFrame(new BaseTestHandler());
fail();
} catch (IOException e) {
assertEquals("PROTOCOL_ERROR FLAG_PAD_HIGH set without FLAG_PAD_LOW", e.getMessage());
}
}
/**
* Padding is encoded over 2 bytes, so maximum value is 65535, but maximum frame size is Http20Draft12.MAX_FRAME_SIZE.
*/
@Test public void readPaddedDataFrameWithTooMuchPadding() throws IOException {
int dataLength = 1123;
byte[] expectedData = new byte[dataLength];
Arrays.fill(expectedData, (byte) 2);
final byte[] padding = new byte[0xffff];
Arrays.fill(padding, (byte) 0);
frame.writeShort(dataLength + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(0xffff);
frame.write(expectedData);
frame.write(padding);
try {
fr.nextFrame(new BaseTestHandler());
fail();
} catch (IOException e) {
assertEquals("PROTOCOL_ERROR padding > 16383: 65535", e.getMessage());
}
}
@Test public void readPaddedHeadersFrame() throws IOException {
int paddingLength = 257;
int paddingLength = 254;
byte[] padding = new byte[paddingLength];
Arrays.fill(padding, (byte) 0);
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
frame.writeShort((int) headerBlock.size() + paddingLength + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(FLAG_END_HEADERS | FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeShort((int) headerBlock.size() + paddingLength + 1);
frame.writeByte(Http20Draft13.TYPE_HEADERS);
frame.writeByte(FLAG_END_HEADERS | FLAG_PADDED);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(paddingLength);
frame.writeByte(paddingLength);
frame.writeAll(headerBlock);
frame.write(padding);
@@ -502,23 +427,11 @@ public class Http20Draft12Test {
assertTrue(frame.exhausted()); // Padding was skipped.
}
@Test public void readPaddedHeadersFrameZeroPaddingHigh() throws IOException {
@Test public void readPaddedHeadersFrameZeroPadding() throws IOException {
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
frame.writeShort((int) headerBlock.size() + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(FLAG_END_HEADERS | FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(0);
frame.writeAll(headerBlock);
fr.nextFrame(assertHeaderBlock());
}
@Test public void readPaddedHeadersFrameZeroPaddingLow() throws IOException {
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
frame.writeShort((int) headerBlock.size() + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(FLAG_END_HEADERS | FLAG_PAD_LOW);
frame.writeShort((int) headerBlock.size() + 1);
frame.writeByte(Http20Draft13.TYPE_HEADERS);
frame.writeByte(FLAG_END_HEADERS | FLAG_PADDED);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeByte(0);
frame.writeAll(headerBlock);
@@ -526,55 +439,9 @@ public class Http20Draft12Test {
fr.nextFrame(assertHeaderBlock());
}
@Test public void readPaddedHeadersFrameMissingLowFlag() throws IOException {
int paddingLength = 257;
byte[] padding = new byte[paddingLength];
Arrays.fill(padding, (byte) 0);
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
frame.writeShort((int) headerBlock.size() + 1);
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(FLAG_PAD_HIGH);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(paddingLength);
frame.writeAll(headerBlock);
frame.write(padding);
try {
fr.nextFrame(new BaseTestHandler());
fail();
} catch (IOException e) {
assertEquals("PROTOCOL_ERROR FLAG_PAD_HIGH set without FLAG_PAD_LOW", e.getMessage());
}
}
/**
* Padding is encoded over 2 bytes, so maximum value is 65535, but maximum frame size is Http20Draft12.MAX_FRAME_SIZE.
*/
@Test public void readPaddedHeadersFrameWithTooMuchPadding() throws IOException {
byte[] padding = new byte[0xffff];
Arrays.fill(padding, (byte) 0);
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
frame.writeShort((int) headerBlock.size() + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(0xffff);
frame.writeAll(headerBlock);
frame.write(padding);
try {
fr.nextFrame(new BaseTestHandler());
fail();
} catch (IOException e) {
assertEquals("PROTOCOL_ERROR padding > 16383: 65535", e.getMessage());
}
}
/** Headers are compressed, then framed. */
@Test public void readPaddedHeadersFrameThenContinuation() throws IOException {
int paddingLength = 257;
int paddingLength = 254;
byte[] padding = new byte[paddingLength];
Arrays.fill(padding, (byte) 0);
@@ -582,130 +449,23 @@ public class Http20Draft12Test {
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
// Write the first headers frame.
frame.writeShort((int) (headerBlock.size() / 2) + paddingLength + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeShort((int) (headerBlock.size() / 2) + paddingLength + 1);
frame.writeByte(Http20Draft13.TYPE_HEADERS);
frame.writeByte(FLAG_PADDED);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(paddingLength);
frame.writeByte(paddingLength);
frame.write(headerBlock, headerBlock.size() / 2);
frame.write(padding);
// Write the continuation frame, specifying no more frames are expected.
frame.writeShort((int) headerBlock.size() + paddingLength + 2);
frame.writeByte(Http20Draft12.TYPE_CONTINUATION); // 2 for PAD_HIGH,LOW.
frame.writeByte(FLAG_END_HEADERS | FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeShort((int) headerBlock.size());
frame.writeByte(Http20Draft13.TYPE_CONTINUATION);
frame.writeByte(FLAG_END_HEADERS);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(paddingLength);
frame.writeAll(headerBlock);
frame.write(padding);
fr.nextFrame(assertHeaderBlock());
assertTrue(frame.exhausted()); // Padding was skipped.
}
@Test public void readPaddedContinuationFrameZeroPaddingHigh() throws IOException {
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
// Write the first headers frame.
frame.writeShort((int) (headerBlock.size() / 2));
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(0);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.write(headerBlock, headerBlock.size() / 2);
// Write the continuation frame, specifying no more frames are expected.
frame.writeShort((int) headerBlock.size() + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_CONTINUATION);
frame.writeByte(FLAG_END_HEADERS | FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(0);
frame.writeAll(headerBlock);
fr.nextFrame(assertHeaderBlock());
}
@Test public void readPaddedContinuationFrameZeroPaddingLow() throws IOException {
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
// Write the first headers frame.
frame.writeShort((int) (headerBlock.size() / 2));
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(0);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.write(headerBlock, headerBlock.size() / 2);
// Write the continuation frame, specifying no more frames are expected.
frame.writeShort((int) headerBlock.size() + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_CONTINUATION);
frame.writeByte(FLAG_END_HEADERS | FLAG_PAD_LOW);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeByte(0);
frame.writeAll(headerBlock);
fr.nextFrame(assertHeaderBlock());
}
@Test public void readPaddedContinuationFrameMissingLowFlag() throws IOException {
int paddingLength = 257;
byte[] padding = new byte[paddingLength];
Arrays.fill(padding, (byte) 0);
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
// Write the first headers frame.
frame.writeShort((int) (headerBlock.size() / 2));
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(0);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.write(headerBlock, headerBlock.size() / 2);
// Write the continuation frame, specifying no more frames are expected.
frame.writeShort((int) headerBlock.size() + 1);
frame.writeByte(Http20Draft12.TYPE_CONTINUATION);
frame.writeByte(FLAG_PAD_HIGH);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(paddingLength);
frame.writeAll(headerBlock);
frame.write(padding);
try {
fr.nextFrame(new BaseTestHandler());
fail();
} catch (IOException e) {
assertEquals("PROTOCOL_ERROR FLAG_PAD_HIGH set without FLAG_PAD_LOW", e.getMessage());
}
}
/**
* Padding is encoded over 2 bytes, so maximum value is 65535, but maximum frame size is Http20Draft12.MAX_FRAME_SIZE.
*/
@Test public void readPaddedContinuationFrameWithTooMuchPadding() throws IOException {
byte[] padding = new byte[0xffff];
Arrays.fill(padding, (byte) 0);
Buffer headerBlock = literalHeaders(headerEntries("foo", "barrr", "baz", "qux"));
// Write the first headers frame.
frame.writeShort((int) (headerBlock.size() / 2));
frame.writeByte(Http20Draft12.TYPE_HEADERS);
frame.writeByte(0);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.write(headerBlock, headerBlock.size() / 2);
// Write the continuation frame, specifying no more frames are expected.
frame.writeShort((int) (headerBlock.size() / 2) + 2); // 2 for PAD_HIGH,LOW.
frame.writeByte(Http20Draft12.TYPE_CONTINUATION);
frame.writeByte(FLAG_PAD_HIGH | FLAG_PAD_LOW);
frame.writeInt(expectedStreamId & 0x7fffffff);
frame.writeShort(0xffff);
frame.write(headerBlock, (headerBlock.size() / 2));
frame.write(padding);
try {
fr.nextFrame(new BaseTestHandler());
fail();
} catch (IOException e) {
assertEquals("PROTOCOL_ERROR padding > 16383: 65535", e.getMessage());
}
assertTrue(frame.exhausted());
}
@Test public void tooLargeDataFrame() throws IOException {
@@ -721,7 +481,7 @@ public class Http20Draft12Test {
final long expectedWindowSizeIncrement = 0x7fffffff;
frame.writeShort(4); // length
frame.writeByte(Http20Draft12.TYPE_WINDOW_UPDATE);
frame.writeByte(Http20Draft13.TYPE_WINDOW_UPDATE);
frame.writeByte(0); // No flags.
frame.writeInt(expectedStreamId);
frame.writeInt((int) expectedWindowSizeIncrement);
@@ -758,7 +518,7 @@ public class Http20Draft12Test {
final ErrorCode expectedError = ErrorCode.PROTOCOL_ERROR;
frame.writeShort(8); // Without debug data there's only 2 32-bit fields.
frame.writeByte(Http20Draft12.TYPE_GOAWAY);
frame.writeByte(Http20Draft13.TYPE_GOAWAY);
frame.writeByte(0); // no flags.
frame.writeInt(0); // connection-scope
frame.writeInt(expectedStreamId); // last good stream.
@@ -783,7 +543,7 @@ public class Http20Draft12Test {
// Compose the expected GOAWAY frame without debug data.
frame.writeShort(8 + expectedData.size());
frame.writeByte(Http20Draft12.TYPE_GOAWAY);
frame.writeByte(Http20Draft13.TYPE_GOAWAY);
frame.writeByte(0); // no flags.
frame.writeInt(0); // connection-scope
frame.writeInt(0); // never read any stream!
@@ -804,10 +564,10 @@ public class Http20Draft12Test {
}
@Test public void frameSizeError() throws IOException {
Http20Draft12.Writer writer = new Http20Draft12.Writer(new Buffer(), true);
Http20Draft13.Writer writer = new Http20Draft13.Writer(new Buffer(), true);
try {
writer.frameHeader(0, 16384, Http20Draft12.TYPE_DATA, FLAG_NONE);
writer.frameHeader(0, 16384, Http20Draft13.TYPE_DATA, FLAG_NONE);
fail();
} catch (IllegalArgumentException e) {
assertEquals("FRAME_SIZE_ERROR length > 16383: 16384", e.getMessage());
@@ -815,140 +575,59 @@ public class Http20Draft12Test {
}
@Test public void streamIdHasReservedBit() throws IOException {
Http20Draft12.Writer writer = new Http20Draft12.Writer(new Buffer(), true);
Http20Draft13.Writer writer = new Http20Draft13.Writer(new Buffer(), true);
try {
int streamId = 3;
streamId |= 1L << 31; // set reserved bit
writer.frameHeader(streamId, Http20Draft12.MAX_FRAME_SIZE, Http20Draft12.TYPE_DATA, FLAG_NONE);
writer.frameHeader(streamId, Http20Draft13.MAX_FRAME_SIZE, Http20Draft13.TYPE_DATA, FLAG_NONE);
fail();
} catch (IllegalArgumentException e) {
assertEquals("reserved bit set: -2147483645", e.getMessage());
}
}
@Test public void blockedFrameIgnored() throws IOException {
frame.writeShort(0);
frame.writeByte(Http20Draft12.TYPE_BLOCKED);
frame.writeByte(0); // no flags.
frame.writeInt(0); // connection-scope.
fr.nextFrame(new BaseTestHandler()); // Should not callback.
}
@Test public void blockedFrameIOEWithPayload() throws IOException {
frame.writeShort(4);
frame.writeByte(Http20Draft12.TYPE_BLOCKED);
frame.writeByte(0); // no flags.
frame.writeInt(0); // connection-scope.
frame.writeUtf8("abcd"); // Send a payload even though it is illegal.
// Consume the unknown frame.
try {
fr.nextFrame(new BaseTestHandler());
fail();
} catch (IOException e) {
assertEquals("TYPE_BLOCKED length != 0: 4", e.getMessage());
}
}
@Test public void readAltSvcStreamOrigin() throws IOException {
frame.writeShort(9 + Protocol.HTTP_2.toString().length() + "www-2.example.com".length());
frame.writeByte(Http20Draft12.TYPE_ALTSVC);
frame.writeByte(0); // No flags.
frame.writeInt(expectedStreamId); // Use stream origin.
frame.writeInt(0xffffffff); // Max-Age 32bit number.
frame.writeShort(443); // Port.
frame.writeByte(0); // Reserved.
frame.writeByte(Protocol.HTTP_2.toString().length()); // Proto-Len.
frame.writeUtf8(Protocol.HTTP_2.toString()); // Protocol-ID.
frame.writeByte("www-2.example.com".length()); // Host-Len.
frame.writeUtf8("www-2.example.com");
fr.nextFrame(new BaseTestHandler() { // Consume the alt-svc frame.
@Override public void alternateService(int streamId, String origin, ByteString protocol,
String host, int port, long maxAge) {
assertEquals(expectedStreamId, streamId);
assertEquals("", origin);
assertEquals(Protocol.HTTP_2.toString(), protocol.utf8());
assertEquals("www-2.example.com", host);
assertEquals(443, port);
assertEquals(0xffffffffL, maxAge);
}
});
}
@Test public void readAltSvcAlternateOrigin() throws IOException {
frame.writeShort(9
+ Protocol.HTTP_2.toString().length()
+ "www-2.example.com".length()
+ "https://example.com:443".length());
frame.writeByte(Http20Draft12.TYPE_ALTSVC);
frame.writeByte(0); // No flags.
frame.writeInt(0); // Specify origin.
frame.writeInt(0xffffffff); // Max-Age 32bit number.
frame.writeShort(443); // Port.
frame.writeByte(0); // Reserved.
frame.writeByte(Protocol.HTTP_2.toString().length()); // Proto-Len.
frame.writeUtf8(Protocol.HTTP_2.toString()); // Protocol-ID.
frame.writeByte("www-2.example.com".length()); // Host-Len.
frame.writeUtf8("www-2.example.com");
frame.writeUtf8("https://example.com:443"); // Remainder is Origin.
fr.nextFrame(new BaseTestHandler() { // Consume the alt-svc frame.
@Override public void alternateService(int streamId, String origin, ByteString protocol,
String host, int port, long maxAge) {
assertEquals(0, streamId);
assertEquals("https://example.com:443", origin);
assertEquals(Protocol.HTTP_2.toString(), protocol.utf8());
assertEquals("www-2.example.com", host);
assertEquals(443, port);
assertEquals(0xffffffffL, maxAge);
}
});
}
private Buffer literalHeaders(List<Header> sentHeaders) throws IOException {
Buffer out = new Buffer();
new HpackDraft07.Writer(out).writeHeaders(sentHeaders);
new HpackDraft08.Writer(out).writeHeaders(sentHeaders);
return out;
}
private Buffer sendHeaderFrames(boolean outFinished, List<Header> headers) throws IOException {
Buffer out = new Buffer();
new Http20Draft12.Writer(out, true).headers(outFinished, expectedStreamId, headers);
new Http20Draft13.Writer(out, true).headers(outFinished, expectedStreamId, headers);
return out;
}
private Buffer sendPushPromiseFrames(int streamId, List<Header> headers) throws IOException {
Buffer out = new Buffer();
new Http20Draft12.Writer(out, true).pushPromise(expectedStreamId, streamId, headers);
new Http20Draft13.Writer(out, true).pushPromise(expectedStreamId, streamId, headers);
return out;
}
private Buffer sendPingFrame(boolean ack, int payload1, int payload2) throws IOException {
Buffer out = new Buffer();
new Http20Draft12.Writer(out, true).ping(ack, payload1, payload2);
new Http20Draft13.Writer(out, true).ping(ack, payload1, payload2);
return out;
}
private Buffer sendGoAway(int lastGoodStreamId, ErrorCode errorCode, byte[] debugData)
throws IOException {
Buffer out = new Buffer();
new Http20Draft12.Writer(out, true).goAway(lastGoodStreamId, errorCode, debugData);
new Http20Draft13.Writer(out, true).goAway(lastGoodStreamId, errorCode, debugData);
return out;
}
private Buffer sendDataFrame(Buffer data) throws IOException {
Buffer out = new Buffer();
new Http20Draft12.Writer(out, true).dataFrame(expectedStreamId, FLAG_NONE, data,
new Http20Draft13.Writer(out, true).dataFrame(expectedStreamId, FLAG_NONE, data,
(int) data.size());
return out;
}
private Buffer windowUpdate(long windowSizeIncrement) throws IOException {
Buffer out = new Buffer();
new Http20Draft12.Writer(out, true).windowUpdate(expectedStreamId, windowSizeIncrement);
new Http20Draft13.Writer(out, true).windowUpdate(expectedStreamId, windowSizeIncrement);
return out;
}

View File

@@ -46,7 +46,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public final class Http2ConnectionTest {
private static final Variant HTTP_2 = new Http20Draft12();
private static final Variant HTTP_2 = new Http20Draft13();
private final MockSpdyPeer peer = new MockSpdyPeer();
@After public void tearDown() throws Exception {
@@ -140,7 +140,7 @@ public final class Http2ConnectionTest {
// verify the peer's settings were read and applied.
assertEquals(0, connection.peerSettings.getHeaderTableSize());
Http20Draft12.Reader frameReader = (Http20Draft12.Reader) connection.readerRunnable.frameReader;
Http20Draft13.Reader frameReader = (Http20Draft13.Reader) connection.readerRunnable.frameReader;
assertEquals(0, frameReader.hpackReader.maxHeaderTableByteCount());
// TODO: when supported, check the frameWriter's compression table is unaffected.
}

View File

@@ -278,7 +278,7 @@ public final class MockSpdyPeer implements Closeable {
@Override
public void pushPromise(int streamId, int associatedStreamId, List<Header> headerBlock) {
this.type = Http20Draft12.TYPE_PUSH_PROMISE;
this.type = Http20Draft13.TYPE_PUSH_PROMISE;
this.streamId = streamId;
this.associatedStreamId = associatedStreamId;
this.headerBlock = headerBlock;

View File

@@ -62,14 +62,9 @@ public final class SettingsTest {
settings.set(MAX_CONCURRENT_STREAMS, 0, 75);
assertEquals(75, settings.getMaxConcurrentStreams(-3));
// WARNING: clash on flags between spdy/3 and HTTP/2!
assertEquals(-3, settings.getCurrentCwnd(-3));
settings.set(Settings.CURRENT_CWND, 0, 86);
assertEquals(86, settings.getCurrentCwnd(-3));
settings.clear();
assertEquals(true, settings.getCompressData(true));
settings.set(Settings.COMPRESS_DATA, 0, 1);
assertEquals(true, settings.getCompressData(false));
assertEquals(-3, settings.getDownloadRetransRate(-3));
settings.set(DOWNLOAD_RETRANS_RATE, 0, 97);

View File

@@ -399,11 +399,11 @@ public final class OkHttpClient implements Cloneable {
* <ul>
* <li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">http/1.1</a>
* <li><a href="http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1">spdy/3.1</a>
* <li><a href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-12">h2-12</a>
* <li><a href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-13">h2-13</a>
* </ul>
*
* <p><strong>This is an evolving set.</strong> Future releases may drop
* support for transitional protocols (like h2-12), in favor of their
* support for transitional protocols (like h2-13), in favor of their
* successors (h2). The http/1.1 transport will never be dropped.
*
* <p>If multiple protocols are specified, <a

View File

@@ -63,13 +63,13 @@ public enum Protocol {
* HTTP/1.1 semantics are layered on HTTP/2.
*
* <p>This version of OkHttp implements HTTP/2 <a
* href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-12">draft 12</a>
* href="http://tools.ietf.org/html/draft-ietf-httpbis-http2-13">draft 12</a>
* with HPACK <a
* href="http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07">draft
* href="http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08">draft
* 6</a>. Future releases of OkHttp may use this identifier for a newer draft
* of these specs.
*/
HTTP_2("h2-12");
HTTP_2("h2-13");
private final String protocol;
@@ -92,7 +92,7 @@ public enum Protocol {
/**
* Returns the string used to identify this protocol for ALPN and NPN, like
* "http/1.1", "spdy/3.1" or "h2-12".
* "http/1.1", "spdy/3.1" or "h2-13".
*/
@Override public String toString() {
return protocol;

View File

@@ -15,7 +15,7 @@
*/
package com.squareup.okhttp.internal.spdy;
// http://tools.ietf.org/html/draft-ietf-httpbis-http2-12#section-7
// http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-7
public enum ErrorCode {
/** Not an error! For SPDY stream resets, prefer null over NO_ERROR. */
NO_ERROR(0, -1, 0),

View File

@@ -30,15 +30,15 @@ import okio.Okio;
import okio.Source;
/**
* Read and write HPACK v07.
* Read and write HPACK v08.
*
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08
*
* This implementation uses an array for the header table with a bitset for
* references. Dynamic entries are added to the array, starting in the last
* position moving forward. When the array fills, it is doubled.
*/
final class HpackDraft07 {
final class HpackDraft08 {
private static final int PREFIX_4_BITS = 0x0f;
private static final int PREFIX_6_BITS = 0x3f;
private static final int PREFIX_7_BITS = 0x7f;
@@ -59,7 +59,7 @@ final class HpackDraft07 {
new Header(Header.RESPONSE_STATUS, "404"),
new Header(Header.RESPONSE_STATUS, "500"),
new Header("accept-charset", ""),
new Header("accept-encoding", ""),
new Header("accept-encoding", "gzip, deflate"),
new Header("accept-language", ""),
new Header("accept-ranges", ""),
new Header("accept", ""),
@@ -107,10 +107,10 @@ final class HpackDraft07 {
new Header("www-authenticate", "")
};
private HpackDraft07() {
private HpackDraft08() {
}
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#section-3.2
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#section-3.2
static final class Reader {
private final List<Header> emittedHeaders = new ArrayList<>();
@@ -429,7 +429,7 @@ final class HpackDraft07 {
}
/** This does not use "never indexed" semantics for sensitive headers. */
// https://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#section-4.3.3
// https://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#section-4.3.3
void writeHeaders(List<Header> headerBlock) throws IOException {
// TODO: implement index tracking
for (int i = 0, size = headerBlock.size(); i < size; i++) {
@@ -447,7 +447,7 @@ final class HpackDraft07 {
}
}
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#section-4.1.1
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#section-4.1.1
void writeInt(int value, int prefixMask, int bits) throws IOException {
// Write the raw value for a single byte value.
if (value < prefixMask) {

View File

@@ -15,28 +15,29 @@
*/
package com.squareup.okhttp.internal.spdy;
import com.squareup.okhttp.Protocol;
import java.io.IOException;
import java.util.List;
import java.util.logging.Logger;
import com.squareup.okhttp.Protocol;
import okio.Buffer;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.ByteString;
import okio.Source;
import okio.Timeout;
import static com.squareup.okhttp.internal.spdy.Http20Draft12.FrameLogger.formatHeader;
import static com.squareup.okhttp.internal.spdy.Http20Draft13.FrameLogger.formatHeader;
import static java.lang.String.format;
import static java.util.logging.Level.FINE;
import static okio.ByteString.EMPTY;
/**
* Read and write HTTP/2 v12 frames.
* <p>http://tools.ietf.org/html/draft-ietf-httpbis-http2-12
* Read and write HTTP/2 v13 frames.
* <p>http://tools.ietf.org/html/draft-ietf-httpbis-http2-13
*/
public final class Http20Draft12 implements Variant {
private static final Logger logger = Logger.getLogger(Http20Draft12.class.getName());
public final class Http20Draft13 implements Variant {
private static final Logger logger = Logger.getLogger(Http20Draft13.class.getName());
@Override public Protocol getProtocol() {
return Protocol.HTTP_2;
@@ -57,8 +58,6 @@ public final class Http20Draft12 implements Variant {
static final byte TYPE_GOAWAY = 0x7;
static final byte TYPE_WINDOW_UPDATE = 0x8;
static final byte TYPE_CONTINUATION = 0x9;
static final byte TYPE_ALTSVC = 0xa;
static final byte TYPE_BLOCKED = 0xb;
static final byte FLAG_NONE = 0x0;
static final byte FLAG_ACK = 0x1; // Used for settings and ping.
@@ -66,8 +65,7 @@ public final class Http20Draft12 implements Variant {
static final byte FLAG_END_SEGMENT = 0x2;
static final byte FLAG_END_HEADERS = 0x4; // Used for headers and continuation.
static final byte FLAG_END_PUSH_PROMISE = 0x4;
static final byte FLAG_PAD_LOW = 0x8; // Used for headers, data, and continuation.
static final byte FLAG_PAD_HIGH = 0x10; // Used for headers, data, and continuation.
static final byte FLAG_PADDED = 0x8; // Used for headers and data.
static final byte FLAG_PRIORITY = 0x20; // Used for headers.
static final byte FLAG_COMPRESSED = 0x20; // Used for data.
@@ -93,13 +91,13 @@ public final class Http20Draft12 implements Variant {
private final boolean client;
// Visible for testing.
final HpackDraft07.Reader hpackReader;
final HpackDraft08.Reader hpackReader;
Reader(BufferedSource source, int headerTableSize, boolean client) {
this.source = source;
this.client = client;
this.continuation = new ContinuationSource(this.source);
this.hpackReader = new HpackDraft07.Reader(headerTableSize, continuation);
this.hpackReader = new HpackDraft08.Reader(headerTableSize, continuation);
}
@Override public void readConnectionPreface() throws IOException {
@@ -166,16 +164,9 @@ public final class Http20Draft12 implements Variant {
readWindowUpdate(handler, length, flags, streamId);
break;
case TYPE_ALTSVC:
readAlternateService(handler, length, flags, streamId);
break;
case TYPE_BLOCKED: // Ignore as this is experimental.
if (length != 0) throw ioException("TYPE_BLOCKED length != 0: %s", length);
break;
default:
throw ioException("PROTOCOL_ERROR: unknown frame type %s", type);
// Implementations MUST discard frames that have unknown or unsupported types.
source.skip(length);
}
return true;
}
@@ -186,7 +177,7 @@ public final class Http20Draft12 implements Variant {
boolean endStream = (flags & FLAG_END_STREAM) != 0;
short padding = readPadding(source, flags);
short padding = (flags & FLAG_PADDED) != 0 ? (short) (source.readByte() & 0xff) : 0;
if ((flags & FLAG_PRIORITY) != 0) {
readPriority(handler, streamId);
@@ -223,7 +214,7 @@ public final class Http20Draft12 implements Variant {
throw ioException("PROTOCOL_ERROR: FLAG_COMPRESSED without SETTINGS_COMPRESS_DATA");
}
short padding = readPadding(source, flags);
short padding = (flags & FLAG_PADDED) != 0 ? (short) (source.readByte() & 0xff) : 0;
length = lengthWithoutPadding(length, flags, padding);
handler.data(inFinished, streamId, source, length);
@@ -266,10 +257,10 @@ public final class Http20Draft12 implements Variant {
return;
}
if (length % 5 != 0) throw ioException("TYPE_SETTINGS length %% 5 != 0: %s", length);
if (length % 6 != 0) throw ioException("TYPE_SETTINGS length %% 6 != 0: %s", length);
Settings settings = new Settings();
for (int i = 0; i < length; i += 5) {
int id = source.readByte();
for (int i = 0; i < length; i += 6) {
short id = source.readShort();
int value = source.readInt();
switch (id) {
@@ -307,9 +298,10 @@ public final class Http20Draft12 implements Variant {
if (streamId == 0) {
throw ioException("PROTOCOL_ERROR: TYPE_PUSH_PROMISE streamId == 0");
}
short padding = readPadding(source, flags);
short padding = (flags & FLAG_PADDED) != 0 ? (short) (source.readByte() & 0xff) : 0;
int promisedStreamId = source.readInt() & 0x7fffffff;
length -= 4; // account for above read.
length = lengthWithoutPadding(length, flags, padding);
List<Header> headerBlock = readHeaderBlock(length, padding, flags, streamId);
handler.pushPromise(streamId, promisedStreamId, headerBlock);
}
@@ -350,20 +342,6 @@ public final class Http20Draft12 implements Variant {
handler.windowUpdate(streamId, increment);
}
private void readAlternateService(Handler handler, short length, byte flags, int streamId)
throws IOException {
long maxAge = source.readInt() & 0xffffffffL;
int port = source.readShort() & 0xffff;
source.readByte(); // Reserved.
int protocolLength = source.readByte() & 0xff;
ByteString protocol = source.readByteString(protocolLength);
int hostLength = source.readByte() & 0xff;
String host = source.readUtf8(hostLength);
int originLength = length - 9 - protocolLength - hostLength;
String origin = source.readUtf8(originLength);
handler.alternateService(streamId, origin, protocol, host, port, maxAge);
}
@Override public void close() throws IOException {
source.close();
}
@@ -373,14 +351,14 @@ public final class Http20Draft12 implements Variant {
private final BufferedSink sink;
private final boolean client;
private final Buffer hpackBuffer;
private final HpackDraft07.Writer hpackWriter;
private final HpackDraft08.Writer hpackWriter;
private boolean closed;
Writer(BufferedSink sink, boolean client) {
this.sink = sink;
this.client = client;
this.hpackBuffer = new Buffer();
this.hpackWriter = new HpackDraft07.Writer(hpackBuffer);
this.hpackWriter = new HpackDraft08.Writer(hpackBuffer);
}
@Override public synchronized void flush() throws IOException {
@@ -506,7 +484,7 @@ public final class Http20Draft12 implements Variant {
@Override public synchronized void settings(Settings settings) throws IOException {
if (closed) throw new IOException("closed");
int length = settings.size() * 5;
int length = settings.size() * 6;
byte type = TYPE_SETTINGS;
byte flags = FLAG_NONE;
int streamId = 0;
@@ -516,7 +494,7 @@ public final class Http20Draft12 implements Variant {
int id = i;
if (id == 4) id = 3; // SETTINGS_MAX_CONCURRENT_STREAMS renumbered.
else if (id == 7) id = 4; // SETTINGS_INITIAL_WINDOW_SIZE renumbered.
sink.writeByte(id);
sink.writeShort(id);
sink.writeInt(settings.get(i));
}
sink.flush();
@@ -594,7 +572,7 @@ public final class Http20Draft12 implements Variant {
/**
* Decompression of the header block occurs above the framing layer. This
* class lazily reads continuation frames as they are needed by {@link
* HpackDraft07.Reader#readHeaders()}.
* HpackDraft08.Reader#readHeaders()}.
*/
static final class ContinuationSource implements Source {
private final BufferedSource source;
@@ -636,41 +614,19 @@ public final class Http20Draft12 implements Variant {
int previousStreamId = streamId;
int w1 = source.readInt();
int w2 = source.readInt();
length = (short) ((w1 & 0x3fff0000) >> 16);
length = left = (short) ((w1 & 0x3fff0000) >> 16);
byte type = (byte) ((w1 & 0xff00) >> 8);
flags = (byte) (w1 & 0xff);
if (logger.isLoggable(FINE)) logger.fine(formatHeader(true, streamId, length, type, flags));
padding = readPadding(source, flags);
length = left = lengthWithoutPadding(length, flags, padding);
streamId = (w2 & 0x7fffffff);
if (type != TYPE_CONTINUATION) throw ioException("%s != TYPE_CONTINUATION", type);
if (streamId != previousStreamId) throw ioException("TYPE_CONTINUATION streamId changed");
}
}
private static short readPadding(BufferedSource source, byte flags) throws IOException {
if ((flags & FLAG_PAD_HIGH) != 0 && (flags & FLAG_PAD_LOW) == 0) {
throw ioException("PROTOCOL_ERROR FLAG_PAD_HIGH set without FLAG_PAD_LOW");
}
int padding = 0;
if ((flags & FLAG_PAD_HIGH) != 0) {
padding = source.readShort() & 0xffff;
} else if ((flags & FLAG_PAD_LOW) != 0) {
padding = source.readByte() & 0xff;
}
if (padding > MAX_FRAME_SIZE) {
throw ioException("PROTOCOL_ERROR padding > %d: %d", MAX_FRAME_SIZE, padding);
}
return (short) padding;
}
private static short lengthWithoutPadding(short length, byte flags, short padding)
throws IOException {
if ((flags & FLAG_PAD_HIGH) != 0) { // account for reading the padding length.
length -= 2;
} else if ((flags & FLAG_PAD_LOW) != 0) {
length--;
}
if ((flags & FLAG_PADDED) != 0) length--; // Account for reading the padding length.
if (padding > length) {
throw ioException("PROTOCOL_ERROR padding %s > remaining length %s", padding, length);
}
@@ -719,8 +675,6 @@ public final class Http20Draft12 implements Variant {
case TYPE_RST_STREAM:
case TYPE_GOAWAY:
case TYPE_WINDOW_UPDATE:
case TYPE_ALTSVC:
case TYPE_BLOCKED:
return BINARY[flags];
}
String result = flags < FLAGS.length ? FLAGS[flags] : BINARY[flags];
@@ -744,9 +698,7 @@ public final class Http20Draft12 implements Variant {
"PING",
"GOAWAY",
"WINDOW_UPDATE",
"CONTINUATION",
"ALTSVC",
"BLOCKED"
"CONTINUATION"
};
/**
@@ -768,14 +720,9 @@ public final class Http20Draft12 implements Variant {
int[] prefixFlags =
new int[] {FLAG_END_STREAM, FLAG_END_SEGMENT, FLAG_END_SEGMENT | FLAG_END_STREAM};
FLAGS[FLAG_PAD_LOW] = "PAD_LOW";
FLAGS[FLAG_PAD_LOW | FLAG_PAD_HIGH] = "PAD_LOW|PAD_HIGH";
int[] suffixFlags = new int[] {FLAG_PAD_LOW, FLAG_PAD_LOW | FLAG_PAD_HIGH};
FLAGS[FLAG_PADDED] = "PADDED";
for (int prefixFlag : prefixFlags) {
for (int suffixFlag : suffixFlags) {
FLAGS[prefixFlag | suffixFlag] = FLAGS[prefixFlag] + '|' + FLAGS[suffixFlag];
}
FLAGS[prefixFlag | FLAG_PADDED] = FLAGS[prefixFlag] + "|PADDED";
}
FLAGS[FLAG_END_HEADERS] = "END_HEADERS"; // Same as END_PUSH_PROMISE.
@@ -787,10 +734,8 @@ public final class Http20Draft12 implements Variant {
for (int frameFlag : frameFlags) {
for (int prefixFlag : prefixFlags) {
FLAGS[prefixFlag | frameFlag] = FLAGS[prefixFlag] + '|' + FLAGS[frameFlag];
for (int suffixFlag : suffixFlags) {
FLAGS[prefixFlag | frameFlag | suffixFlag] =
FLAGS[prefixFlag] + '|' + FLAGS[frameFlag] + '|' + FLAGS[suffixFlag];
}
FLAGS[prefixFlag | frameFlag | FLAG_PADDED] =
FLAGS[prefixFlag] + '|' + FLAGS[frameFlag] + "|PADDED";
}
}

View File

@@ -31,49 +31,47 @@ import java.io.OutputStream;
class Huffman {
// Appendix C: Huffman Codes
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-C
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-08#appendix-C
private static final int[] CODES = {
0x3ffffba, 0x3ffffbb, 0x3ffffbc, 0x3ffffbd, 0x3ffffbe, 0x3ffffbf, 0x3ffffc0, 0x3ffffc1,
0x3ffffc2, 0x3ffffc3, 0x3ffffc4, 0x3ffffc5, 0x3ffffc6, 0x3ffffc7, 0x3ffffc8, 0x3ffffc9,
0x3ffffca, 0x3ffffcb, 0x3ffffcc, 0x3ffffcd, 0x3ffffce, 0x3ffffcf, 0x3ffffd0, 0x3ffffd1,
0x3ffffd2, 0x3ffffd3, 0x3ffffd4, 0x3ffffd5, 0x3ffffd6, 0x3ffffd7, 0x3ffffd8, 0x3ffffd9, 0x6,
0x1ffc, 0x1f0, 0x3ffc, 0x7ffc, 0x1e, 0x64, 0x1ffd, 0x3fa, 0x1f1, 0x3fb, 0x3fc, 0x65, 0x66,
0x1f, 0x7, 0x0, 0x1, 0x2, 0x8, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0xec, 0x1fffc, 0x27,
0x7ffd, 0x3fd, 0x7ffe, 0x67, 0xed, 0xee, 0x68, 0xef, 0x69, 0x6a, 0x1f2, 0xf0, 0x1f3, 0x1f4,
0x1f5, 0x6b, 0x6c, 0xf1, 0xf2, 0x1f6, 0x1f7, 0x6d, 0x28, 0xf3, 0x1f8, 0x1f9, 0xf4, 0x1fa,
0x1fb, 0x7fc, 0x3ffffda, 0x7fd, 0x3ffd, 0x6e, 0x3fffe, 0x9, 0x6f, 0xa, 0x29, 0xb, 0x70, 0x2a,
0x2b, 0xc, 0xf5, 0xf6, 0x2c, 0x2d, 0x2e, 0xd, 0x2f, 0x1fc, 0x30, 0x31, 0xe, 0x71, 0x72, 0x73,
0x74, 0x75, 0xf7, 0x1fffd, 0xffc, 0x1fffe, 0xffd, 0x3ffffdb, 0x3ffffdc, 0x3ffffdd, 0x3ffffde,
0x3ffffdf, 0x3ffffe0, 0x3ffffe1, 0x3ffffe2, 0x3ffffe3, 0x3ffffe4, 0x3ffffe5, 0x3ffffe6,
0x3ffffe7, 0x3ffffe8, 0x3ffffe9, 0x3ffffea, 0x3ffffeb, 0x3ffffec, 0x3ffffed, 0x3ffffee,
0x3ffffef, 0x3fffff0, 0x3fffff1, 0x3fffff2, 0x3fffff3, 0x3fffff4, 0x3fffff5, 0x3fffff6,
0x3fffff7, 0x3fffff8, 0x3fffff9, 0x3fffffa, 0x3fffffb, 0x3fffffc, 0x3fffffd, 0x3fffffe,
0x3ffffff, 0x1ffff80, 0x1ffff81, 0x1ffff82, 0x1ffff83, 0x1ffff84, 0x1ffff85, 0x1ffff86,
0x1ffff87, 0x1ffff88, 0x1ffff89, 0x1ffff8a, 0x1ffff8b, 0x1ffff8c, 0x1ffff8d, 0x1ffff8e,
0x1ffff8f, 0x1ffff90, 0x1ffff91, 0x1ffff92, 0x1ffff93, 0x1ffff94, 0x1ffff95, 0x1ffff96,
0x1ffff97, 0x1ffff98, 0x1ffff99, 0x1ffff9a, 0x1ffff9b, 0x1ffff9c, 0x1ffff9d, 0x1ffff9e,
0x1ffff9f, 0x1ffffa0, 0x1ffffa1, 0x1ffffa2, 0x1ffffa3, 0x1ffffa4, 0x1ffffa5, 0x1ffffa6,
0x1ffffa7, 0x1ffffa8, 0x1ffffa9, 0x1ffffaa, 0x1ffffab, 0x1ffffac, 0x1ffffad, 0x1ffffae,
0x1ffffaf, 0x1ffffb0, 0x1ffffb1, 0x1ffffb2, 0x1ffffb3, 0x1ffffb4, 0x1ffffb5, 0x1ffffb6,
0x1ffffb7, 0x1ffffb8, 0x1ffffb9, 0x1ffffba, 0x1ffffbb, 0x1ffffbc, 0x1ffffbd, 0x1ffffbe,
0x1ffffbf, 0x1ffffc0, 0x1ffffc1, 0x1ffffc2, 0x1ffffc3, 0x1ffffc4, 0x1ffffc5, 0x1ffffc6,
0x1ffffc7, 0x1ffffc8, 0x1ffffc9, 0x1ffffca, 0x1ffffcb, 0x1ffffcc, 0x1ffffcd, 0x1ffffce,
0x1ffffcf, 0x1ffffd0, 0x1ffffd1, 0x1ffffd2, 0x1ffffd3, 0x1ffffd4, 0x1ffffd5, 0x1ffffd6,
0x1ffffd7, 0x1ffffd8, 0x1ffffd9, 0x1ffffda, 0x1ffffdb
0x1ff8, 0x7fffd8, 0xfffffe2, 0xfffffe3, 0xfffffe4, 0xfffffe5, 0xfffffe6, 0xfffffe7, 0xfffffe8,
0xffffea, 0x3ffffffc, 0xfffffe9, 0xfffffea, 0x3ffffffd, 0xfffffeb, 0xfffffec, 0xfffffed,
0xfffffee, 0xfffffef, 0xffffff0, 0xffffff1, 0xffffff2, 0x3ffffffe, 0xffffff3, 0xffffff4,
0xffffff5, 0xffffff6, 0xffffff7, 0xffffff8, 0xffffff9, 0xffffffa, 0xffffffb, 0x14, 0x3f8,
0x3f9, 0xffa, 0x1ff9, 0x15, 0xf8, 0x7fa, 0x3fa, 0x3fb, 0xf9, 0x7fb, 0xfa, 0x16, 0x17, 0x18,
0x0, 0x1, 0x2, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x5c, 0xfb, 0x7ffc, 0x20, 0xffb,
0x3fc, 0x1ffa, 0x21, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0xfc, 0x73, 0xfd, 0x1ffb, 0x7fff0,
0x1ffc, 0x3ffc, 0x22, 0x7ffd, 0x3, 0x23, 0x4, 0x24, 0x5, 0x25, 0x26, 0x27, 0x6, 0x74, 0x75,
0x28, 0x29, 0x2a, 0x7, 0x2b, 0x76, 0x2c, 0x8, 0x9, 0x2d, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7ffe,
0x7fc, 0x3ffd, 0x1ffd, 0xffffffc, 0xfffe6, 0x3fffd2, 0xfffe7, 0xfffe8, 0x3fffd3, 0x3fffd4,
0x3fffd5, 0x7fffd9, 0x3fffd6, 0x7fffda, 0x7fffdb, 0x7fffdc, 0x7fffdd, 0x7fffde, 0xffffeb,
0x7fffdf, 0xffffec, 0xffffed, 0x3fffd7, 0x7fffe0, 0xffffee, 0x7fffe1, 0x7fffe2, 0x7fffe3,
0x7fffe4, 0x1fffdc, 0x3fffd8, 0x7fffe5, 0x3fffd9, 0x7fffe6, 0x7fffe7, 0xffffef, 0x3fffda,
0x1fffdd, 0xfffe9, 0x3fffdb, 0x3fffdc, 0x7fffe8, 0x7fffe9, 0x1fffde, 0x7fffea, 0x3fffdd,
0x3fffde, 0xfffff0, 0x1fffdf, 0x3fffdf, 0x7fffeb, 0x7fffec, 0x1fffe0, 0x1fffe1, 0x3fffe0,
0x1fffe2, 0x7fffed, 0x3fffe1, 0x7fffee, 0x7fffef, 0xfffea, 0x3fffe2, 0x3fffe3, 0x3fffe4,
0x7ffff0, 0x3fffe5, 0x3fffe6, 0x7ffff1, 0x3ffffe0, 0x3ffffe1, 0xfffeb, 0x7fff1, 0x3fffe7,
0x7ffff2, 0x3fffe8, 0x1ffffec, 0x3ffffe2, 0x3ffffe3, 0x3ffffe4, 0x7ffffde, 0x7ffffdf,
0x3ffffe5, 0xfffff1, 0x1ffffed, 0x7fff2, 0x1fffe3, 0x3ffffe6, 0x7ffffe0, 0x7ffffe1, 0x3ffffe7,
0x7ffffe2, 0xfffff2, 0x1fffe4, 0x1fffe5, 0x3ffffe8, 0x3ffffe9, 0xffffffd, 0x7ffffe3,
0x7ffffe4, 0x7ffffe5, 0xfffec, 0xfffff3, 0xfffed, 0x1fffe6, 0x3fffe9, 0x1fffe7, 0x1fffe8,
0x7ffff3, 0x3fffea, 0x3fffeb, 0x1ffffee, 0x1ffffef, 0xfffff4, 0xfffff5, 0x3ffffea, 0x7ffff4,
0x3ffffeb, 0x7ffffe6, 0x3ffffec, 0x3ffffed, 0x7ffffe7, 0x7ffffe8, 0x7ffffe9, 0x7ffffea,
0x7ffffeb, 0xffffffe, 0x7ffffec, 0x7ffffed, 0x7ffffee, 0x7ffffef, 0x7fffff0, 0x3ffffee
};
private static final byte[] CODE_LENGTHS = {
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 5, 13, 9, 14, 15, 6, 7, 13, 10, 9, 10, 10, 7, 7, 6, 5, 4,
4, 4, 5, 6, 6, 6, 6, 6, 6, 6, 8, 17, 6, 15, 10, 15, 7, 8, 8, 7, 8, 7, 7, 9, 8, 9, 9, 9, 7, 7,
8, 8, 9, 9, 7, 6, 8, 9, 9, 8, 9, 9, 11, 26, 11, 14, 7, 18, 5, 7, 5, 6, 5, 7, 6, 6, 5, 8, 8, 6,
6, 6, 5, 6, 9, 6, 6, 5, 7, 7, 7, 7, 7, 8, 17, 12, 17, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
26, 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
25, 25, 25, 25, 25
13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 30,
28, 28, 28, 28, 28, 28, 28, 28, 28, 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6, 5,
5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10, 13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6, 15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6,
6, 6, 5, 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28, 20, 22, 20, 20, 22, 22, 22, 23,
22, 23, 23, 23, 23, 23, 24, 23, 24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23,
24, 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23, 21, 21, 22, 21, 23, 22,
23, 23, 20, 22, 22, 22, 23, 22, 22, 23, 26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27,
26, 24, 25, 19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27, 20, 24, 20, 21,
22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23, 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27,
27, 27, 27, 27, 26
};
private static final Huffman INSTANCE = new Huffman();

View File

@@ -50,8 +50,6 @@ public final class Settings {
static final int MAX_CONCURRENT_STREAMS = 4;
/** spdy/3: Current CWND in Packets. */
static final int CURRENT_CWND = 5;
/** HTTP/2: The peer must not gzip a DATA frame when this is 0. */
static final int COMPRESS_DATA = 5;
/** spdy/3: Retransmission rate. Percentage */
static final int DOWNLOAD_RETRANS_RATE = 6;
/** Window size in bytes. */
@@ -173,13 +171,6 @@ public final class Settings {
return (bit & set) != 0 ? values[CURRENT_CWND] : defaultValue;
}
/** HTTP/2 only. */
// TODO: honor this setting in HTTP/2.
boolean getCompressData(boolean defaultValue) {
int bit = 1 << COMPRESS_DATA;
return ((bit & set) != 0 ? values[COMPRESS_DATA] : defaultValue ? 1 : 0) == 1;
}
/** spdy/3 only. */
int getDownloadRetransRate(int defaultValue) {
int bit = 1 << DOWNLOAD_RETRANS_RATE;

View File

@@ -133,7 +133,7 @@ public final class SpdyConnection implements Closeable {
pushObserver = builder.pushObserver;
client = builder.client;
handler = builder.handler;
// http://tools.ietf.org/html/draft-ietf-httpbis-http2-12#section-5.1.1
// http://tools.ietf.org/html/draft-ietf-httpbis-http2-13#section-5.1.1
nextStreamId = builder.client ? 1 : 2;
if (builder.client && protocol == Protocol.HTTP_2) {
nextStreamId += 2; // In HTTP/2, 1 on client is reserved for Upgrade.
@@ -152,7 +152,7 @@ public final class SpdyConnection implements Closeable {
hostName = builder.hostName;
if (protocol == Protocol.HTTP_2) {
variant = new Http20Draft12();
variant = new Http20Draft13();
// Like newSingleThreadExecutor, except lazy creates the thread.
pushExecutor = new ThreadPoolExecutor(0, 1,
0L, TimeUnit.MILLISECONDS,