Skip to content

Commit 54d4fcd

Browse files
author
Adrian Cole
committed
Merge pull request square#356 from adriancole/draft6-headers
Update to http/2 draft 6 CONTINUATION after HEADERS frame
2 parents e138eb7 + f7d96b2 commit 54d4fcd

File tree

6 files changed

+44
-30
lines changed

6 files changed

+44
-30
lines changed

mockwebserver/src/main/java/com/squareup/okhttp/mockwebserver/MockWebServer.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,15 @@
7171
public final class MockWebServer {
7272
private static final byte[] NPN_PROTOCOLS = {
7373
// TODO: support HTTP/2.0.
74-
// 17, 'H', 'T', 'T', 'P', '-', 'd', 'r', 'a', 'f', 't', '-', '0', '4', '/', '2', '.', '0',
74+
// 17, 'H', 'T', 'T', 'P', '-', 'd', 'r', 'a', 'f', 't', '-', '0', '6', '/', '2', '.', '0',
7575
6, 's', 'p', 'd', 'y', '/', '3',
7676
8, 'h', 't', 't', 'p', '/', '1', '.', '1'
7777
};
7878
private static final byte[] SPDY3 = new byte[] {
7979
's', 'p', 'd', 'y', '/', '3'
8080
};
81-
private static final byte[] HTTP_20_DRAFT_04 = new byte[] {
82-
'H', 'T', 'T', 'P', '-', 'd', 'r', 'a', 'f', 't', '-', '0', '4', '/', '2', '.', '0'
81+
private static final byte[] HTTP_20_DRAFT_06 = new byte[] {
82+
'H', 'T', 'T', 'P', '-', 'd', 'r', 'a', 'f', 't', '-', '0', '6', '/', '2', '.', '0'
8383
};
8484
private static final byte[] HTTP_11 = new byte[] {
8585
'h', 't', 't', 'p', '/', '1', '.', '1'
@@ -327,8 +327,8 @@ public void processConnection() throws Exception {
327327
byte[] selectedProtocol = Platform.get().getNpnSelectedProtocol(sslSocket);
328328
if (selectedProtocol == null || Arrays.equals(selectedProtocol, HTTP_11)) {
329329
transport = Transport.HTTP_11;
330-
} else if (Arrays.equals(selectedProtocol, HTTP_20_DRAFT_04)) {
331-
transport = Transport.HTTP_20_DRAFT_04;
330+
} else if (Arrays.equals(selectedProtocol, HTTP_20_DRAFT_06)) {
331+
transport = Transport.HTTP_20_DRAFT_06;
332332
} else if (Arrays.equals(selectedProtocol, SPDY3)) {
333333
transport = Transport.SPDY_3;
334334
} else {
@@ -341,14 +341,14 @@ public void processConnection() throws Exception {
341341
socket = raw;
342342
}
343343

344-
if (transport == Transport.SPDY_3 || transport == Transport.HTTP_20_DRAFT_04) {
344+
if (transport == Transport.SPDY_3 || transport == Transport.HTTP_20_DRAFT_06) {
345345
SpdySocketHandler spdySocketHandler = new SpdySocketHandler(socket, transport);
346346
SpdyConnection.Builder builder = new SpdyConnection.Builder(false, socket)
347347
.handler(spdySocketHandler);
348348
if (transport == Transport.SPDY_3) {
349349
builder.spdy3();
350350
} else {
351-
builder.http20Draft04();
351+
builder.http20Draft06();
352352
}
353353
SpdyConnection spdyConnection = builder.build();
354354
openSpdyConnections.put(spdyConnection, Boolean.TRUE);
@@ -717,6 +717,6 @@ private void writeResponse(SpdyStream stream, MockResponse response) throws IOEx
717717
}
718718

719719
enum Transport {
720-
HTTP_11, SPDY_3, HTTP_20_DRAFT_04
720+
HTTP_11, SPDY_3, HTTP_20_DRAFT_06
721721
}
722722
}

okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Hpack.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
import java.util.List;
1010

1111
/**
12-
* Read and write HPACK v01.
13-
* http://http2.github.io/compression-spec/compression-spec.html#rfc.status
12+
* Read and write HPACK v03.
13+
* http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-03
1414
*/
1515
final class Hpack {
1616
static final int PREFIX_5_BITS = 0x1f;

okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Http20Draft04.java renamed to okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Http20Draft06.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@
2626
import java.util.Arrays;
2727
import java.util.List;
2828

29-
final class Http20Draft04 implements Variant {
29+
/**
30+
* Read and write http/2 v06 frames.
31+
* http://tools.ietf.org/html/draft-ietf-httpbis-http2-06
32+
*/
33+
final class Http20Draft06 implements Variant {
3034
private static final byte[] CONNECTION_HEADER;
3135
static {
3236
try {
@@ -45,8 +49,10 @@ final class Http20Draft04 implements Variant {
4549
static final int TYPE_PING = 0x6;
4650
static final int TYPE_GOAWAY = 0x7;
4751
static final int TYPE_WINDOW_UPDATE = 0x9;
52+
static final int TYPE_CONTINUATION = 0xa;
4853

4954
static final int FLAG_END_STREAM = 0x1;
55+
/** Used for headers, push-promise and continuation. */
5056
static final int FLAG_END_HEADERS = 0x4;
5157
static final int FLAG_PRIORITY = 0x8;
5258
static final int FLAG_PONG = 0x1;
@@ -141,31 +147,38 @@ private void readHeaders(Handler handler, int flags, int length, int streamId)
141147
throws IOException {
142148
if (streamId == 0) throw ioException("TYPE_HEADERS streamId == 0");
143149

150+
boolean inFinished = (flags & FLAG_END_STREAM) != 0;
151+
144152
while (true) {
145153
hpackReader.readHeaders(length);
146154

147155
if ((flags & FLAG_END_HEADERS) != 0) {
148156
hpackReader.emitReferenceSet();
149157
List<String> namesAndValues = hpackReader.getAndReset();
150-
boolean inFinished = (flags & FLAG_END_STREAM) != 0;
151158
int priority = -1; // TODO: priority
152159
handler.headers(false, inFinished, streamId, -1, priority, namesAndValues,
153160
HeadersMode.HTTP_20_HEADERS);
154161
return;
155162
}
156163

157-
// Read another frame of headers.
164+
// Read another continuation frame.
158165
int w1 = in.readInt();
159166
int w2 = in.readInt();
160167

161168
length = (w1 & 0xffff0000) >> 16;
162169
int newType = (w1 & 0xff00) >> 8;
163170
flags = w1 & 0xff;
164-
// boolean r = (w2 & 0x80000000) != 0; // Reserved.
171+
172+
// TODO: remove in draft 8: CONTINUATION no longer sets END_STREAM
173+
inFinished = (flags & FLAG_END_STREAM) != 0;
174+
175+
// boolean u = (w2 & 0x80000000) != 0; // Unused.
165176
int newStreamId = (w2 & 0x7fffffff);
166177

167-
if (newType != TYPE_HEADERS) throw ioException("TYPE_HEADERS didn't have FLAG_END_HEADERS");
168-
if (newStreamId != streamId) throw ioException("TYPE_HEADERS streamId changed");
178+
if (newType != TYPE_CONTINUATION) {
179+
throw ioException("TYPE_CONTINUATION didn't have FLAG_END_HEADERS");
180+
}
181+
if (newStreamId != streamId) throw ioException("TYPE_CONTINUATION streamId changed");
169182
}
170183
}
171184

@@ -302,6 +315,7 @@ private void headers(boolean outFinished, int streamId, int priority,
302315
hpackBuffer.reset();
303316
hpackWriter.writeHeaders(nameValueBlock);
304317
int type = TYPE_HEADERS;
318+
// TODO: implement CONTINUATION
305319
int length = hpackBuffer.size();
306320
int flags = FLAG_END_HEADERS;
307321
if (outFinished) flags |= FLAG_END_STREAM;

okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyConnection.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public final class SpdyConnection implements Closeable {
5959
Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
6060
Util.daemonThreadFactory("OkHttp SpdyConnection"));
6161

62-
/** The protocol variant, like SPDY/3 or HTTP-draft-04/2.0. */
62+
/** The protocol variant, like SPDY/3 or HTTP-draft-06/2.0. */
6363
final Variant variant;
6464

6565
/** True if this peer initiated the connection. */
@@ -416,8 +416,8 @@ public Builder spdy3() {
416416
return this;
417417
}
418418

419-
public Builder http20Draft04() {
420-
this.variant = Variant.HTTP_20_DRAFT_04;
419+
public Builder http20Draft06() {
420+
this.variant = Variant.HTTP_20_DRAFT_06;
421421
return this;
422422
}
423423

okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Variant.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
/** A version and dialect of the framed socket protocol. */
2222
interface Variant {
2323
Variant SPDY3 = new Spdy3();
24-
Variant HTTP_20_DRAFT_04 = new Http20Draft04();
24+
Variant HTTP_20_DRAFT_06 = new Http20Draft06();
2525

2626
/**
2727
* @param client true if this is the HTTP client's reader, reading frames from

okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/Http20Draft04Test.java renamed to okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/Http20Draft06Test.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import static org.junit.Assert.assertFalse;
2828
import static org.junit.Assert.assertTrue;
2929

30-
public class Http20Draft04Test {
30+
public class Http20Draft06Test {
3131

3232
@Test public void onlyOneLiteralHeadersFrame() throws IOException {
3333
final int expectedStreamId = 15;
@@ -40,13 +40,13 @@ public class Http20Draft04Test {
4040
{
4141
byte[] headerBytes = literalHeaders(sentHeaders);
4242
dataOut.writeShort(headerBytes.length);
43-
dataOut.write(Http20Draft04.TYPE_HEADERS);
44-
dataOut.write(Http20Draft04.FLAG_END_HEADERS | Http20Draft04.FLAG_END_STREAM);
43+
dataOut.write(Http20Draft06.TYPE_HEADERS);
44+
dataOut.write(Http20Draft06.FLAG_END_HEADERS | Http20Draft06.FLAG_END_STREAM);
4545
dataOut.writeInt(expectedStreamId & 0x7fffffff); // stream with reserved bit set
4646
dataOut.write(headerBytes);
4747
}
4848

49-
FrameReader fr = new Http20Draft04.Reader(new ByteArrayInputStream(out.toByteArray()), false);
49+
FrameReader fr = new Http20Draft06.Reader(new ByteArrayInputStream(out.toByteArray()), false);
5050

5151
// Consume the headers frame.
5252
fr.nextFrame(new BaseTestHandler() {
@@ -66,7 +66,7 @@ public void headers(boolean outFinished, boolean inFinished, int streamId,
6666
});
6767
}
6868

69-
@Test public void twoLiteralHeadersFrames() throws IOException {
69+
@Test public void headersFrameThenContinuation() throws IOException {
7070
final int expectedStreamId = 15;
7171

7272
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -76,23 +76,23 @@ public void headers(boolean outFinished, boolean inFinished, int streamId,
7676
{
7777
byte[] headerBytes = literalHeaders(Arrays.asList("foo", "bar"));
7878
dataOut.writeShort(headerBytes.length);
79-
dataOut.write(Http20Draft04.TYPE_HEADERS);
79+
dataOut.write(Http20Draft06.TYPE_HEADERS);
8080
dataOut.write(0); // no flags
8181
dataOut.writeInt(expectedStreamId & 0x7fffffff); // stream with reserved bit set
8282
dataOut.write(headerBytes);
8383
}
8484

85-
// Write the second headers frame, specifying no more frames are expected.
85+
// Write the continuation frame, specifying no more frames are expected.
8686
{
8787
byte[] headerBytes = literalHeaders(Arrays.asList("baz", "qux"));
8888
dataOut.writeShort(headerBytes.length);
89-
dataOut.write(Http20Draft04.TYPE_HEADERS);
90-
dataOut.write(Http20Draft04.FLAG_END_HEADERS | Http20Draft04.FLAG_END_STREAM);
89+
dataOut.write(Http20Draft06.TYPE_CONTINUATION);
90+
dataOut.write(Http20Draft06.FLAG_END_HEADERS | Http20Draft06.FLAG_END_STREAM);
9191
dataOut.writeInt(expectedStreamId & 0x7fffffff); // stream with reserved bit set
9292
dataOut.write(headerBytes);
9393
}
9494

95-
FrameReader fr = new Http20Draft04.Reader(new ByteArrayInputStream(out.toByteArray()), false);
95+
FrameReader fr = new Http20Draft06.Reader(new ByteArrayInputStream(out.toByteArray()), false);
9696

9797
// Reading the above frames should result in a concatenated nameValueBlock.
9898
fr.nextFrame(new BaseTestHandler() {

0 commit comments

Comments
 (0)