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:
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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) {
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user