From 39c0d7d56397ab14892db8032464cb8a9f983ff1 Mon Sep 17 00:00:00 2001 From: jwilson Date: Wed, 14 Aug 2013 01:00:07 -0400 Subject: [PATCH] Push stream flags into Spdy3. Previously flags were being interpretted in SpdyConnection and SpdyStream. This won't work for HTTP/2.0, which has its own flag setup. --- checkstyle.xml | 1 - .../okhttp/internal/spdy/Http20Draft04.java | 36 +++-- .../squareup/okhttp/internal/spdy/Spdy3.java | 113 ++++++++------ .../okhttp/internal/spdy/SpdyConnection.java | 56 +++---- .../okhttp/internal/spdy/SpdyReader.java | 9 +- .../okhttp/internal/spdy/SpdyStream.java | 52 ++----- .../okhttp/internal/spdy/SpdyWriter.java | 12 +- .../okhttp/internal/spdy/MockSpdyPeer.java | 47 +++--- .../internal/spdy/SpdyConnectionTest.java | 146 +++++++++--------- 9 files changed, 248 insertions(+), 224 deletions(-) diff --git a/checkstyle.xml b/checkstyle.xml index 631cbf9a4..794af42b6 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -65,7 +65,6 @@ - diff --git a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Http20Draft04.java b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Http20Draft04.java index ef832a560..515a43064 100644 --- a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Http20Draft04.java +++ b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Http20Draft04.java @@ -39,7 +39,21 @@ final class Http20Draft04 implements Variant { } @Override public boolean nextFrame(Handler handler) throws IOException { - return false; + int w1; + try { + w1 = in.readInt(); + } catch (IOException e) { + return false; // This might be a normal socket close. + } + int w2 = in.readInt(); + + int length = w1 & 0xffff; + int type = (w1 & 0xff0000) >> 16; + int flags = (w1 & 0xff000000) >> 24; + boolean r = (w2 & 0x80000000) != 0; + int streamId = (w2 & 0x7fffffff); + + throw new UnsupportedOperationException("TODO"); } @Override public void close() throws IOException { @@ -54,12 +68,6 @@ final class Http20Draft04 implements Variant { this.out = new DataOutputStream(out); } - @Override public synchronized void writeFrame(byte[] data, int offset, int length) - throws IOException { - // TODO: this method no longer makes sense; the raw frame can't support all variants! - throw new UnsupportedOperationException("TODO"); - } - @Override public synchronized void flush() throws IOException { out.flush(); } @@ -68,12 +76,13 @@ final class Http20Draft04 implements Variant { throw new UnsupportedOperationException("TODO"); } - @Override public synchronized void synStream(int flags, int streamId, int associatedStreamId, - int priority, int slot, List nameValueBlock) throws IOException { + @Override public synchronized void synStream(boolean outFinished, boolean inFinished, + int streamId, int associatedStreamId, int priority, int slot, List nameValueBlock) + throws IOException { throw new UnsupportedOperationException("TODO"); } - @Override public synchronized void synReply(int flags, int streamId, + @Override public synchronized void synReply(boolean outFinished, int streamId, List nameValueBlock) throws IOException { throw new UnsupportedOperationException("TODO"); } @@ -87,8 +96,13 @@ final class Http20Draft04 implements Variant { throw new UnsupportedOperationException("TODO"); } - @Override public synchronized void data(int flags, int streamId, byte[] data) + @Override public synchronized void data(boolean outFinished, int streamId, byte[] data) throws IOException { + data(outFinished, streamId, data, 0, data.length); + } + + @Override public void data(boolean outFinished, int streamId, byte[] data, int offset, + int byteCount) throws IOException { throw new UnsupportedOperationException("TODO"); } diff --git a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Spdy3.java b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Spdy3.java index a1993901d..a86c71ec1 100644 --- a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Spdy3.java +++ b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/Spdy3.java @@ -34,6 +34,23 @@ import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; final class Spdy3 implements Variant { + static final int TYPE_DATA = 0x0; + static final int TYPE_SYN_STREAM = 0x1; + static final int TYPE_SYN_REPLY = 0x2; + static final int TYPE_RST_STREAM = 0x3; + static final int TYPE_SETTINGS = 0x4; + static final int TYPE_NOOP = 0x5; + static final int TYPE_PING = 0x6; + static final int TYPE_GOAWAY = 0x7; + static final int TYPE_HEADERS = 0x8; + static final int TYPE_WINDOW_UPDATE = 0x9; + static final int TYPE_CREDENTIAL = 0x10; + + static final int FLAG_FIN = 0x1; + static final int FLAG_UNIDIRECTIONAL = 0x2; + + static final int VERSION = 3; + static final byte[] DICTIONARY; static { try { @@ -120,44 +137,44 @@ final class Spdy3 implements Variant { } switch (type) { - case SpdyConnection.TYPE_SYN_STREAM: + case TYPE_SYN_STREAM: readSynStream(handler, flags, length); return true; - case SpdyConnection.TYPE_SYN_REPLY: + case TYPE_SYN_REPLY: readSynReply(handler, flags, length); return true; - case SpdyConnection.TYPE_RST_STREAM: + case TYPE_RST_STREAM: readRstStream(handler, flags, length); return true; - case SpdyConnection.TYPE_SETTINGS: + case TYPE_SETTINGS: readSettings(handler, flags, length); return true; - case SpdyConnection.TYPE_NOOP: + case TYPE_NOOP: if (length != 0) throw ioException("TYPE_NOOP length: %d != 0", length); handler.noop(); return true; - case SpdyConnection.TYPE_PING: + case TYPE_PING: readPing(handler, flags, length); return true; - case SpdyConnection.TYPE_GOAWAY: + case TYPE_GOAWAY: readGoAway(handler, flags, length); return true; - case SpdyConnection.TYPE_HEADERS: + case TYPE_HEADERS: readHeaders(handler, flags, length); return true; - case SpdyConnection.TYPE_WINDOW_UPDATE: + case TYPE_WINDOW_UPDATE: readWindowUpdate(handler, flags, length); return true; - case SpdyConnection.TYPE_CREDENTIAL: + case TYPE_CREDENTIAL: Util.skipByReading(in, length); throw new UnsupportedOperationException("TODO"); // TODO: implement @@ -166,7 +183,8 @@ final class Spdy3 implements Variant { } } else { int streamId = w1 & 0x7fffffff; - handler.data(flags, streamId, in, length); + boolean inFinished = (flags & FLAG_FIN) != 0; + handler.data(inFinished, streamId, in, length); return true; } } @@ -180,14 +198,19 @@ final class Spdy3 implements Variant { int priority = (s3 & 0xe000) >>> 13; int slot = s3 & 0xff; List nameValueBlock = readNameValueBlock(length - 10); - handler.synStream(flags, streamId, associatedStreamId, priority, slot, nameValueBlock); + + boolean inFinished = (flags & FLAG_FIN) != 0; + boolean outFinished = (flags & FLAG_UNIDIRECTIONAL) != 0; + handler.synStream(outFinished, inFinished, streamId, associatedStreamId, priority, slot, + nameValueBlock); } private void readSynReply(Handler handler, int flags, int length) throws IOException { int w1 = in.readInt(); int streamId = w1 & 0x7fffffff; List nameValueBlock = readNameValueBlock(length - 4); - handler.synReply(flags, streamId, nameValueBlock); + boolean inFinished = (flags & FLAG_FIN) != 0; + handler.synReply(inFinished, streamId, nameValueBlock); } private void readRstStream(Handler handler, int flags, int length) throws IOException { @@ -341,23 +364,20 @@ final class Spdy3 implements Variant { // Do nothing: no connection header for SPDY/3. } - @Override public synchronized void writeFrame(byte[] data, int offset, int length) - throws IOException { - out.write(data, offset, length); - } - @Override public synchronized void flush() throws IOException { out.flush(); } - @Override public synchronized void synStream(int flags, int streamId, int associatedStreamId, - int priority, int slot, List nameValueBlock) throws IOException { + @Override public synchronized void synStream(boolean outFinished, boolean inFinished, + int streamId, int associatedStreamId, int priority, int slot, List nameValueBlock) + throws IOException { writeNameValueBlockToBuffer(nameValueBlock); int length = 10 + nameValueBlockBuffer.size(); - int type = SpdyConnection.TYPE_SYN_STREAM; + int type = TYPE_SYN_STREAM; + int flags = (outFinished ? FLAG_FIN : 0) | (inFinished ? FLAG_UNIDIRECTIONAL : 0); int unused = 0; - out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); out.writeInt((flags & 0xff) << 24 | length & 0xffffff); out.writeInt(streamId & 0x7fffffff); out.writeInt(associatedStreamId & 0x7fffffff); @@ -367,12 +387,13 @@ final class Spdy3 implements Variant { } @Override public synchronized void synReply( - int flags, int streamId, List nameValueBlock) throws IOException { + boolean outFinished, int streamId, List nameValueBlock) throws IOException { writeNameValueBlockToBuffer(nameValueBlock); - int type = SpdyConnection.TYPE_SYN_REPLY; + int type = TYPE_SYN_REPLY; + int flags = (outFinished ? FLAG_FIN : 0); int length = nameValueBlockBuffer.size() + 4; - out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); out.writeInt((flags & 0xff) << 24 | length & 0xffffff); out.writeInt(streamId & 0x7fffffff); nameValueBlockBuffer.writeTo(out); @@ -382,10 +403,10 @@ final class Spdy3 implements Variant { @Override public synchronized void headers(int flags, int streamId, List nameValueBlock) throws IOException { writeNameValueBlockToBuffer(nameValueBlock); - int type = SpdyConnection.TYPE_HEADERS; + int type = TYPE_HEADERS; int length = nameValueBlockBuffer.size() + 4; - out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); out.writeInt((flags & 0xff) << 24 | length & 0xffffff); out.writeInt(streamId & 0x7fffffff); nameValueBlockBuffer.writeTo(out); @@ -394,22 +415,26 @@ final class Spdy3 implements Variant { @Override public synchronized void rstStream(int streamId, int statusCode) throws IOException { int flags = 0; - int type = SpdyConnection.TYPE_RST_STREAM; + int type = TYPE_RST_STREAM; int length = 8; - out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); out.writeInt((flags & 0xff) << 24 | length & 0xffffff); out.writeInt(streamId & 0x7fffffff); out.writeInt(statusCode); out.flush(); } - @Override public synchronized void data(int flags, int streamId, byte[] data) + @Override public synchronized void data(boolean outFinished, int streamId, byte[] data) throws IOException { - int length = data.length; + data(outFinished, streamId, data, 0, data.length); + } + + @Override public synchronized void data(boolean outFinished, int streamId, byte[] data, + int offset, int byteCount) throws IOException { + int flags = (outFinished ? FLAG_FIN : 0); out.writeInt(streamId & 0x7fffffff); - out.writeInt((flags & 0xff) << 24 | length & 0xffffff); - out.write(data); - out.flush(); + out.writeInt((flags & 0xff) << 24 | byteCount & 0xffffff); + out.write(data, offset, byteCount); } private void writeNameValueBlockToBuffer(List nameValueBlock) throws IOException { @@ -424,10 +449,10 @@ final class Spdy3 implements Variant { } @Override public synchronized void settings(int flags, Settings settings) throws IOException { - int type = SpdyConnection.TYPE_SETTINGS; + int type = TYPE_SETTINGS; int size = settings.size(); int length = 4 + size * 8; - out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); out.writeInt((flags & 0xff) << 24 | length & 0xffffff); out.writeInt(size); for (int i = 0; i <= Settings.COUNT; i++) { @@ -440,18 +465,18 @@ final class Spdy3 implements Variant { } @Override public synchronized void noop() throws IOException { - int type = SpdyConnection.TYPE_NOOP; + int type = TYPE_NOOP; int length = 0; int flags = 0; - out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); out.writeInt((flags & 0xff) << 24 | length & 0xffffff); out.flush(); } @Override public synchronized void ping(int flags, int id) throws IOException { - int type = SpdyConnection.TYPE_PING; + int type = TYPE_PING; int length = 4; - out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); out.writeInt((flags & 0xff) << 24 | length & 0xffffff); out.writeInt(id); out.flush(); @@ -459,9 +484,9 @@ final class Spdy3 implements Variant { @Override public synchronized void goAway(int flags, int lastGoodStreamId, int statusCode) throws IOException { - int type = SpdyConnection.TYPE_GOAWAY; + int type = TYPE_GOAWAY; int length = 8; - out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); out.writeInt((flags & 0xff) << 24 | length & 0xffffff); out.writeInt(lastGoodStreamId); out.writeInt(statusCode); @@ -470,10 +495,10 @@ final class Spdy3 implements Variant { @Override public synchronized void windowUpdate(int streamId, int deltaWindowSize) throws IOException { - int type = SpdyConnection.TYPE_WINDOW_UPDATE; + int type = TYPE_WINDOW_UPDATE; int flags = 0; int length = 8; - out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff); + out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff); out.writeInt((flags & 0xff) << 24 | length & 0xffffff); out.writeInt(streamId); out.writeInt(deltaWindowSize); diff --git a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyConnection.java b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyConnection.java index a20462154..aaac730ce 100644 --- a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyConnection.java +++ b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyConnection.java @@ -55,22 +55,6 @@ public final class SpdyConnection implements Closeable { // operations must synchronize on 'this' last. This ensures that we never // wait for a blocking operation while holding 'this'. - static final int FLAG_FIN = 0x1; - static final int FLAG_UNIDIRECTIONAL = 0x2; - - static final int TYPE_DATA = 0x0; - static final int TYPE_SYN_STREAM = 0x1; - static final int TYPE_SYN_REPLY = 0x2; - static final int TYPE_RST_STREAM = 0x3; - static final int TYPE_SETTINGS = 0x4; - static final int TYPE_NOOP = 0x5; - static final int TYPE_PING = 0x6; - static final int TYPE_GOAWAY = 0x7; - static final int TYPE_HEADERS = 0x8; - static final int TYPE_WINDOW_UPDATE = 0x9; - static final int TYPE_CREDENTIAL = 0x10; - static final int VERSION = 3; - static final int GOAWAY_OK = 0; static final int GOAWAY_PROTOCOL_ERROR = 1; static final int GOAWAY_INTERNAL_ERROR = 2; @@ -159,13 +143,14 @@ public final class SpdyConnection implements Closeable { * Returns a new locally-initiated stream. * * @param out true to create an output stream that we can use to send data - * to the remote peer. Corresponds to {@code FLAG_FIN}. + * to the remote peer. Corresponds to {@code FLAG_FIN}. * @param in true to create an input stream that the remote peer can use to - * send data to us. Corresponds to {@code FLAG_UNIDIRECTIONAL}. + * send data to us. Corresponds to {@code FLAG_UNIDIRECTIONAL}. */ public SpdyStream newStream(List requestHeaders, boolean out, boolean in) throws IOException { - int flags = (out ? 0 : FLAG_FIN) | (in ? 0 : FLAG_UNIDIRECTIONAL); + boolean outFinished = !out; + boolean inFinished = !in; int associatedStreamId = 0; // TODO: permit the caller to specify an associated stream? int priority = 0; // TODO: permit the caller to specify a priority? int slot = 0; // TODO: permit the caller to specify a slot? @@ -179,25 +164,29 @@ public final class SpdyConnection implements Closeable { } streamId = nextStreamId; nextStreamId += 2; - stream = new SpdyStream(streamId, this, flags, priority, slot, requestHeaders, settings); + stream = new SpdyStream(streamId, this, outFinished, inFinished, priority, slot, + requestHeaders, settings); if (stream.isOpen()) { streams.put(streamId, stream); setIdle(false); } } - spdyWriter.synStream(flags, streamId, associatedStreamId, priority, slot, requestHeaders); + spdyWriter.synStream(outFinished, inFinished, streamId, associatedStreamId, priority, slot, + requestHeaders); } return stream; } - void writeSynReply(int streamId, int flags, List alternating) throws IOException { - spdyWriter.synReply(flags, streamId, alternating); + void writeSynReply(int streamId, boolean outFinished, List alternating) + throws IOException { + spdyWriter.synReply(outFinished, streamId, alternating); } - void writeFrame(byte[] bytes, int offset, int length) throws IOException { - spdyWriter.writeFrame(bytes, offset, length); + public void writeData(int streamId, boolean outFinished, byte[] buffer, int offset, int byteCount) + throws IOException { + spdyWriter.data(outFinished, streamId, buffer, offset, byteCount); } void writeSynResetLater(final int streamId, final int statusCode) { @@ -450,7 +439,7 @@ public final class SpdyConnection implements Closeable { } } - @Override public void data(int flags, int streamId, InputStream in, int length) + @Override public void data(boolean inFinished, int streamId, InputStream in, int length) throws IOException { SpdyStream dataStream = getStream(streamId); if (dataStream == null) { @@ -459,19 +448,18 @@ public final class SpdyConnection implements Closeable { return; } dataStream.receiveData(in, length); - if ((flags & SpdyConnection.FLAG_FIN) != 0) { + if (inFinished) { dataStream.receiveFin(); } } - @Override public void synStream(int flags, int streamId, int associatedStreamId, int priority, - int slot, List nameValueBlock) { + @Override public void synStream(boolean outFinished, boolean inFinished, int streamId, + int associatedStreamId, int priority, int slot, List nameValueBlock) { final SpdyStream synStream; final SpdyStream previous; synchronized (SpdyConnection.this) { - synStream = - new SpdyStream(streamId, SpdyConnection.this, flags, priority, slot, nameValueBlock, - settings); + synStream = new SpdyStream(streamId, SpdyConnection.this, outFinished, inFinished, priority, + slot, nameValueBlock, settings); if (shutdown) { return; } @@ -495,7 +483,7 @@ public final class SpdyConnection implements Closeable { }); } - @Override public void synReply(int flags, int streamId, List nameValueBlock) + @Override public void synReply(boolean inFinished, int streamId, List nameValueBlock) throws IOException { SpdyStream replyStream = getStream(streamId); if (replyStream == null) { @@ -503,7 +491,7 @@ public final class SpdyConnection implements Closeable { return; } replyStream.receiveReply(nameValueBlock); - if ((flags & SpdyConnection.FLAG_FIN) != 0) { + if (inFinished) { replyStream.receiveFin(); } } diff --git a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyReader.java b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyReader.java index d330a304b..0d81cabc6 100644 --- a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyReader.java +++ b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyReader.java @@ -26,10 +26,11 @@ public interface SpdyReader extends Closeable { boolean nextFrame(Handler handler) throws IOException; public interface Handler { - void data(int flags, int streamId, InputStream in, int length) throws IOException; - void synStream(int flags, int streamId, int associatedStreamId, int priority, int slot, - List nameValueBlock); - void synReply(int flags, int streamId, List nameValueBlock) throws IOException; + void data(boolean inFinished, int streamId, InputStream in, int length) + throws IOException; + void synStream(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId, + int priority, int slot, List nameValueBlock); + void synReply(boolean inFinished, int streamId, List nameValueBlock) throws IOException; void headers(int flags, int streamId, List nameValueBlock) throws IOException; void rstStream(int flags, int streamId, int statusCode); void settings(int flags, Settings settings); diff --git a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyStream.java b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyStream.java index a6b39be67..b5f255594 100644 --- a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyStream.java +++ b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyStream.java @@ -26,8 +26,6 @@ import java.util.ArrayList; import java.util.List; import static com.squareup.okhttp.internal.Util.checkOffsetAndCount; -import static com.squareup.okhttp.internal.Util.pokeInt; -import static java.nio.ByteOrder.BIG_ENDIAN; /** A logical bidirectional stream. */ public final class SpdyStream { @@ -35,8 +33,6 @@ public final class SpdyStream { // Internal state is guarded by this. No long-running or potentially // blocking operations are performed while the lock is held. - private static final int DATA_FRAME_HEADER_LENGTH = 8; - private static final String[] STATUS_CODE_NAMES = { null, "PROTOCOL_ERROR", @@ -95,26 +91,18 @@ public final class SpdyStream { */ private int rstStatusCode = -1; - SpdyStream(int id, SpdyConnection connection, int flags, int priority, int slot, - List requestHeaders, Settings settings) { + SpdyStream(int id, SpdyConnection connection, boolean outFinished, boolean inFinished, + int priority, int slot, List requestHeaders, Settings settings) { if (connection == null) throw new NullPointerException("connection == null"); if (requestHeaders == null) throw new NullPointerException("requestHeaders == null"); this.id = id; this.connection = connection; + this.in.finished = inFinished; + this.out.finished = outFinished; this.priority = priority; this.slot = slot; this.requestHeaders = requestHeaders; - if (isLocallyInitiated()) { - // I am the sender - in.finished = (flags & SpdyConnection.FLAG_UNIDIRECTIONAL) != 0; - out.finished = (flags & SpdyConnection.FLAG_FIN) != 0; - } else { - // I am the receiver - in.finished = (flags & SpdyConnection.FLAG_FIN) != 0; - out.finished = (flags & SpdyConnection.FLAG_UNIDIRECTIONAL) != 0; - } - setSettings(settings); } @@ -192,7 +180,7 @@ public final class SpdyStream { */ public void reply(List responseHeaders, boolean out) throws IOException { assert (!Thread.holdsLock(SpdyStream.this)); - int flags = 0; + boolean outFinished = false; synchronized (this) { if (responseHeaders == null) { throw new NullPointerException("responseHeaders == null"); @@ -206,10 +194,10 @@ public final class SpdyStream { this.responseHeaders = responseHeaders; if (!out) { this.out.finished = true; - flags |= SpdyConnection.FLAG_FIN; + outFinished = true; } } - connection.writeSynReply(id, flags, responseHeaders); + connection.writeSynReply(id, outFinished, responseHeaders); } /** @@ -348,9 +336,9 @@ public final class SpdyStream { private void setSettings(Settings settings) { assert (Thread.holdsLock(connection)); // Because 'settings' is guarded by 'connection'. - this.writeWindowSize = - settings != null ? settings.getInitialWindowSize(Settings.DEFAULT_INITIAL_WINDOW_SIZE) - : Settings.DEFAULT_INITIAL_WINDOW_SIZE; + this.writeWindowSize = settings != null + ? settings.getInitialWindowSize(Settings.DEFAULT_INITIAL_WINDOW_SIZE) + : Settings.DEFAULT_INITIAL_WINDOW_SIZE; } void receiveSettings(Settings settings) { @@ -614,7 +602,7 @@ public final class SpdyStream { */ private final class SpdyDataOutputStream extends OutputStream { private final byte[] buffer = new byte[8192]; - private int pos = DATA_FRAME_HEADER_LENGTH; + private int pos = 0; /** True if the caller has closed this stream. */ private boolean closed; @@ -656,7 +644,7 @@ public final class SpdyStream { @Override public void flush() throws IOException { assert (!Thread.holdsLock(SpdyStream.this)); checkNotClosed(); - if (pos > DATA_FRAME_HEADER_LENGTH) { + if (pos > 0) { writeFrame(false); connection.flush(); } @@ -677,22 +665,16 @@ public final class SpdyStream { cancelStreamIfNecessary(); } - private void writeFrame(boolean last) throws IOException { + private void writeFrame(boolean outFinished) throws IOException { assert (!Thread.holdsLock(SpdyStream.this)); - int length = pos - DATA_FRAME_HEADER_LENGTH; + int length = pos; synchronized (SpdyStream.this) { - waitUntilWritable(length, last); + waitUntilWritable(length, outFinished); unacknowledgedBytes += length; } - int flags = 0; - if (last) { - flags |= SpdyConnection.FLAG_FIN; - } - pokeInt(buffer, 0, id & 0x7fffffff, BIG_ENDIAN); - pokeInt(buffer, 4, (flags & 0xff) << 24 | length & 0xffffff, BIG_ENDIAN); - connection.writeFrame(buffer, 0, pos); - pos = DATA_FRAME_HEADER_LENGTH; + connection.writeData(id, outFinished, buffer, 0, pos); + pos = 0; } /** diff --git a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyWriter.java b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyWriter.java index acf63df30..4853e09c8 100644 --- a/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyWriter.java +++ b/okhttp-protocols/src/main/java/com/squareup/okhttp/internal/spdy/SpdyWriter.java @@ -23,15 +23,15 @@ import java.util.List; /** Writes transport frames for SPDY/3 or HTTP/2.0. */ public interface SpdyWriter extends Closeable { void connectionHeader(); - /** Writes a complete variant-specific frame. */ - void writeFrame(byte[] data, int offset, int length) throws IOException; void flush() throws IOException; - void synStream(int flags, int streamId, int associatedStreamId, int priority, int slot, - List nameValueBlock) throws IOException; - void synReply(int flags, int streamId, List nameValueBlock) throws IOException; + void synStream(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId, + int priority, int slot, List nameValueBlock) throws IOException; + void synReply(boolean outFinished, int streamId, List nameValueBlock) throws IOException; void headers(int flags, int streamId, List nameValueBlock) throws IOException; void rstStream(int streamId, int statusCode) throws IOException; - void data(int flags, int streamId, byte[] data) throws IOException; + void data(boolean outFinished, int streamId, byte[] data) throws IOException; + void data(boolean outFinished, int streamId, byte[] data, int offset, int byteCount) + throws IOException; void settings(int flags, Settings settings) throws IOException; void noop() throws IOException; void ping(int flags, int id) throws IOException; diff --git a/okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/MockSpdyPeer.java b/okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/MockSpdyPeer.java index eb346dde1..65cf20e67 100644 --- a/okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/MockSpdyPeer.java +++ b/okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/MockSpdyPeer.java @@ -37,8 +37,9 @@ import static java.util.concurrent.Executors.defaultThreadFactory; /** Replays prerecorded outgoing frames and records incoming frames. */ public final class MockSpdyPeer implements Closeable { private int frameCount = 0; + private final boolean client; private final ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); - private final SpdyWriter spdyWriter = Variant.SPDY3.newWriter(bytesOut); + private final SpdyWriter spdyWriter; private final List outFrames = new ArrayList(); private final BlockingQueue inFrames = new LinkedBlockingQueue(); private int port; @@ -46,6 +47,11 @@ public final class MockSpdyPeer implements Closeable { private ServerSocket serverSocket; private Socket socket; + public MockSpdyPeer(boolean client) { + this.client = client; + this.spdyWriter = Variant.SPDY3.newWriter(bytesOut); + } + public void acceptFrame() { frameCount++; } @@ -162,7 +168,9 @@ public final class MockSpdyPeer implements Closeable { public final int sequence; public final SpdyReader reader; public int type = -1; - public int flags; + public int flags = -1; + public boolean outFinished; + public boolean inFinished; public int streamId; public int associatedStreamId; public int priority; @@ -180,16 +188,17 @@ public final class MockSpdyPeer implements Closeable { @Override public void settings(int flags, Settings settings) { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_SETTINGS; + this.type = Spdy3.TYPE_SETTINGS; this.flags = flags; this.settings = settings; } - @Override public void synStream(int flags, int streamId, int associatedStreamId, int priority, - int slot, List nameValueBlock) { + @Override public void synStream(boolean outFinished, boolean inFinished, int streamId, + int associatedStreamId, int priority, int slot, List nameValueBlock) { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_SYN_STREAM; - this.flags = flags; + this.type = Spdy3.TYPE_SYN_STREAM; + this.outFinished = outFinished; + this.inFinished = inFinished; this.streamId = streamId; this.associatedStreamId = associatedStreamId; this.priority = priority; @@ -197,27 +206,27 @@ public final class MockSpdyPeer implements Closeable { this.nameValueBlock = nameValueBlock; } - @Override public void synReply(int flags, int streamId, List nameValueBlock) { + @Override public void synReply(boolean inFinished, int streamId, List nameValueBlock) { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_SYN_REPLY; + this.type = Spdy3.TYPE_SYN_REPLY; + this.inFinished = inFinished; this.streamId = streamId; - this.flags = flags; this.nameValueBlock = nameValueBlock; } @Override public void headers(int flags, int streamId, List nameValueBlock) { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_HEADERS; + this.type = Spdy3.TYPE_HEADERS; this.streamId = streamId; this.flags = flags; this.nameValueBlock = nameValueBlock; } - @Override public void data(int flags, int streamId, InputStream in, int length) + @Override public void data(boolean inFinished, int streamId, InputStream in, int length) throws IOException { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_DATA; - this.flags = flags; + this.type = Spdy3.TYPE_DATA; + this.inFinished = inFinished; this.streamId = streamId; this.data = new byte[length]; Util.readFully(in, this.data); @@ -225,7 +234,7 @@ public final class MockSpdyPeer implements Closeable { @Override public void rstStream(int flags, int streamId, int statusCode) { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_RST_STREAM; + this.type = Spdy3.TYPE_RST_STREAM; this.flags = flags; this.streamId = streamId; this.statusCode = statusCode; @@ -233,19 +242,19 @@ public final class MockSpdyPeer implements Closeable { @Override public void ping(int flags, int streamId) { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_PING; + this.type = Spdy3.TYPE_PING; this.flags = flags; this.streamId = streamId; } @Override public void noop() { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_NOOP; + this.type = Spdy3.TYPE_NOOP; } @Override public void goAway(int flags, int lastGoodStreamId, int statusCode) { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_GOAWAY; + this.type = Spdy3.TYPE_GOAWAY; this.flags = flags; this.streamId = lastGoodStreamId; this.statusCode = statusCode; @@ -253,7 +262,7 @@ public final class MockSpdyPeer implements Closeable { @Override public void windowUpdate(int flags, int streamId, int deltaWindowSize) { if (this.type != -1) throw new IllegalStateException(); - this.type = SpdyConnection.TYPE_WINDOW_UPDATE; + this.type = Spdy3.TYPE_WINDOW_UPDATE; this.flags = flags; this.streamId = streamId; this.deltaWindowSize = deltaWindowSize; diff --git a/okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/SpdyConnectionTest.java b/okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/SpdyConnectionTest.java index 7dd23f620..f713221f0 100644 --- a/okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/SpdyConnectionTest.java +++ b/okhttp-protocols/src/test/java/com/squareup/okhttp/internal/spdy/SpdyConnectionTest.java @@ -30,18 +30,16 @@ import org.junit.Test; import static com.squareup.okhttp.internal.Util.UTF_8; import static com.squareup.okhttp.internal.spdy.Settings.PERSIST_VALUE; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.FLAG_FIN; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.FLAG_UNIDIRECTIONAL; +import static com.squareup.okhttp.internal.spdy.Spdy3.TYPE_DATA; +import static com.squareup.okhttp.internal.spdy.Spdy3.TYPE_GOAWAY; +import static com.squareup.okhttp.internal.spdy.Spdy3.TYPE_NOOP; +import static com.squareup.okhttp.internal.spdy.Spdy3.TYPE_PING; +import static com.squareup.okhttp.internal.spdy.Spdy3.TYPE_RST_STREAM; +import static com.squareup.okhttp.internal.spdy.Spdy3.TYPE_SYN_REPLY; +import static com.squareup.okhttp.internal.spdy.Spdy3.TYPE_SYN_STREAM; +import static com.squareup.okhttp.internal.spdy.Spdy3.TYPE_WINDOW_UPDATE; import static com.squareup.okhttp.internal.spdy.SpdyConnection.GOAWAY_INTERNAL_ERROR; import static com.squareup.okhttp.internal.spdy.SpdyConnection.GOAWAY_PROTOCOL_ERROR; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.TYPE_DATA; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.TYPE_GOAWAY; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.TYPE_NOOP; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.TYPE_PING; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.TYPE_RST_STREAM; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.TYPE_SYN_REPLY; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.TYPE_SYN_STREAM; -import static com.squareup.okhttp.internal.spdy.SpdyConnection.TYPE_WINDOW_UPDATE; import static com.squareup.okhttp.internal.spdy.SpdyStream.RST_FLOW_CONTROL_ERROR; import static com.squareup.okhttp.internal.spdy.SpdyStream.RST_INVALID_STREAM; import static com.squareup.okhttp.internal.spdy.SpdyStream.RST_PROTOCOL_ERROR; @@ -49,6 +47,7 @@ import static com.squareup.okhttp.internal.spdy.SpdyStream.RST_REFUSED_STREAM; import static com.squareup.okhttp.internal.spdy.SpdyStream.RST_STREAM_IN_USE; import static com.squareup.okhttp.internal.spdy.SpdyStream.WINDOW_UPDATE_THRESHOLD; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -58,7 +57,7 @@ public final class SpdyConnectionTest { throw new AssertionError(); } }; - private final MockSpdyPeer peer = new MockSpdyPeer(); + private final MockSpdyPeer peer = new MockSpdyPeer(false); @After public void tearDown() throws Exception { peer.close(); @@ -67,8 +66,8 @@ public final class SpdyConnectionTest { @Test public void clientCreatesStreamAndServerReplies() throws Exception { // write the mocking script peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("a", "android")); - peer.sendFrame().data(SpdyConnection.FLAG_FIN, 1, "robot".getBytes("UTF-8")); + peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android")); + peer.sendFrame().data(true, 1, "robot".getBytes("UTF-8")); peer.acceptFrame(); // DATA peer.play(); @@ -83,7 +82,8 @@ public final class SpdyConnectionTest { // verify the peer received what was expected MockSpdyPeer.InFrame synStream = peer.takeFrame(); assertEquals(TYPE_SYN_STREAM, synStream.type); - assertEquals(0, synStream.flags); + assertFalse(synStream.inFinished); + assertFalse(synStream.outFinished); assertEquals(1, synStream.streamId); assertEquals(0, synStream.associatedStreamId); assertEquals(Arrays.asList("b", "banana"), synStream.nameValueBlock); @@ -93,7 +93,7 @@ public final class SpdyConnectionTest { @Test public void headersOnlyStreamIsClosedAfterReplyHeaders() throws Exception { peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("b", "banana")); + peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana")); peer.play(); SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()).build(); @@ -107,7 +107,7 @@ public final class SpdyConnectionTest { // write the mocking script peer.acceptFrame(); // SYN_STREAM peer.acceptFrame(); // PING - peer.sendFrame().synReply(FLAG_FIN, 1, Arrays.asList("a", "android")); + peer.sendFrame().synReply(true, 1, Arrays.asList("a", "android")); peer.sendFrame().ping(0, 1); peer.play(); @@ -127,7 +127,7 @@ public final class SpdyConnectionTest { @Test public void serverCreatesStreamAndClientReplies() throws Exception { // write the mocking script - peer.sendFrame().synStream(0, 2, 0, 5, 129, Arrays.asList("a", "android")); + peer.sendFrame().synStream(false, false, 2, 0, 5, 129, Arrays.asList("a", "android")); peer.acceptFrame(); // SYN_REPLY peer.play(); @@ -148,7 +148,7 @@ public final class SpdyConnectionTest { // verify the peer received what was expected MockSpdyPeer.InFrame reply = peer.takeFrame(); assertEquals(TYPE_SYN_REPLY, reply.type); - assertEquals(0, reply.flags); + assertFalse(reply.inFinished); assertEquals(2, reply.streamId); assertEquals(Arrays.asList("b", "banana"), reply.nameValueBlock); assertEquals(1, receiveCount.get()); @@ -156,7 +156,7 @@ public final class SpdyConnectionTest { @Test public void replyWithNoData() throws Exception { // write the mocking script - peer.sendFrame().synStream(0, 2, 0, 0, 0, Arrays.asList("a", "android")); + peer.sendFrame().synStream(false, false, 2, 0, 0, 0, Arrays.asList("a", "android")); peer.acceptFrame(); // SYN_REPLY peer.play(); @@ -173,7 +173,7 @@ public final class SpdyConnectionTest { // verify the peer received what was expected MockSpdyPeer.InFrame reply = peer.takeFrame(); assertEquals(TYPE_SYN_REPLY, reply.type); - assertEquals(FLAG_FIN, reply.flags); + assertTrue(reply.inFinished); assertEquals(Arrays.asList("b", "banana"), reply.nameValueBlock); assertEquals(1, receiveCount.get()); } @@ -192,7 +192,6 @@ public final class SpdyConnectionTest { // verify the peer received what was expected MockSpdyPeer.InFrame ping = peer.takeFrame(); assertEquals(TYPE_NOOP, ping.type); - assertEquals(0, ping.flags); } @Test public void serverPingsClient() throws Exception { @@ -288,9 +287,9 @@ public final class SpdyConnectionTest { peer.play(); // play it back - SpdyConnection connection = - new SpdyConnection.Builder(true, peer.openSocket()).handler(REJECT_INCOMING_STREAMS) - .build(); + SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()) + .handler(REJECT_INCOMING_STREAMS) + .build(); peer.takeFrame(); // Guarantees that the Settings frame has been processed. synchronized (connection) { @@ -307,7 +306,7 @@ public final class SpdyConnectionTest { @Test public void bogusDataFrameDoesNotDisruptConnection() throws Exception { // write the mocking script - peer.sendFrame().data(SpdyConnection.FLAG_FIN, 42, "bogus".getBytes("UTF-8")); + peer.sendFrame().data(true, 42, "bogus".getBytes("UTF-8")); peer.acceptFrame(); // RST_STREAM peer.sendFrame().ping(0, 2); peer.acceptFrame(); // PING @@ -328,7 +327,7 @@ public final class SpdyConnectionTest { @Test public void bogusReplyFrameDoesNotDisruptConnection() throws Exception { // write the mocking script - peer.sendFrame().synReply(0, 42, Arrays.asList("a", "android")); + peer.sendFrame().synReply(false, 42, Arrays.asList("a", "android")); peer.acceptFrame(); // RST_STREAM peer.sendFrame().ping(0, 2); peer.acceptFrame(); // PING @@ -350,7 +349,7 @@ public final class SpdyConnectionTest { @Test public void clientClosesClientOutputStream() throws Exception { // write the mocking script peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("b", "banana")); + peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana")); peer.acceptFrame(); // TYPE_DATA peer.acceptFrame(); // TYPE_DATA with FLAG_FIN peer.acceptFrame(); // PING @@ -358,9 +357,9 @@ public final class SpdyConnectionTest { peer.play(); // play it back - SpdyConnection connection = - new SpdyConnection.Builder(true, peer.openSocket()).handler(REJECT_INCOMING_STREAMS) - .build(); + SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()) + .handler(REJECT_INCOMING_STREAMS) + .build(); SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), true, false); OutputStream out = stream.getOutputStream(); out.write("square".getBytes(UTF_8)); @@ -379,14 +378,15 @@ public final class SpdyConnectionTest { // verify the peer received what was expected MockSpdyPeer.InFrame synStream = peer.takeFrame(); assertEquals(TYPE_SYN_STREAM, synStream.type); - assertEquals(FLAG_UNIDIRECTIONAL, synStream.flags); + assertFalse(synStream.inFinished); + assertTrue(synStream.outFinished); MockSpdyPeer.InFrame data = peer.takeFrame(); assertEquals(TYPE_DATA, data.type); - assertEquals(0, data.flags); + assertFalse(data.inFinished); assertTrue(Arrays.equals("square".getBytes("UTF-8"), data.data)); MockSpdyPeer.InFrame fin = peer.takeFrame(); assertEquals(TYPE_DATA, fin.type); - assertEquals(FLAG_FIN, fin.flags); + assertTrue(fin.inFinished); MockSpdyPeer.InFrame ping = peer.takeFrame(); assertEquals(TYPE_PING, ping.type); assertEquals(1, ping.streamId); @@ -402,9 +402,9 @@ public final class SpdyConnectionTest { peer.play(); // play it back - SpdyConnection connection = - new SpdyConnection.Builder(true, peer.openSocket()).handler(REJECT_INCOMING_STREAMS) - .build(); + SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()) + .handler(REJECT_INCOMING_STREAMS) + .build(); SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), true, true); OutputStream out = stream.getOutputStream(); connection.ping().roundTripTime(); // Ensure that the RST_CANCEL has been received. @@ -420,14 +420,16 @@ public final class SpdyConnectionTest { // verify the peer received what was expected MockSpdyPeer.InFrame synStream = peer.takeFrame(); assertEquals(TYPE_SYN_STREAM, synStream.type); - assertEquals(0, synStream.flags); + assertFalse(synStream.inFinished); + assertFalse(synStream.outFinished); MockSpdyPeer.InFrame ping = peer.takeFrame(); assertEquals(TYPE_PING, ping.type); assertEquals(1, ping.streamId); MockSpdyPeer.InFrame data = peer.takeFrame(); assertEquals(TYPE_DATA, data.type); assertEquals(1, data.streamId); - assertEquals(FLAG_FIN, data.flags); + assertTrue(data.inFinished); + assertFalse(data.outFinished); } /** @@ -441,9 +443,9 @@ public final class SpdyConnectionTest { peer.play(); // play it back - SpdyConnection connection = - new SpdyConnection.Builder(true, peer.openSocket()).handler(REJECT_INCOMING_STREAMS) - .build(); + SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()) + .handler(REJECT_INCOMING_STREAMS) + .build(); SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), false, true); InputStream in = stream.getInputStream(); OutputStream out = stream.getOutputStream(); @@ -465,7 +467,8 @@ public final class SpdyConnectionTest { // verify the peer received what was expected MockSpdyPeer.InFrame synStream = peer.takeFrame(); assertEquals(TYPE_SYN_STREAM, synStream.type); - assertEquals(SpdyConnection.FLAG_FIN, synStream.flags); + assertTrue(synStream.inFinished); + assertFalse(synStream.outFinished); MockSpdyPeer.InFrame rstStream = peer.takeFrame(); assertEquals(TYPE_RST_STREAM, rstStream.type); assertEquals(SpdyStream.RST_CANCEL, rstStream.statusCode); @@ -484,9 +487,9 @@ public final class SpdyConnectionTest { peer.play(); // play it back - SpdyConnection connection = - new SpdyConnection.Builder(true, peer.openSocket()).handler(REJECT_INCOMING_STREAMS) - .build(); + SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()) + .handler(REJECT_INCOMING_STREAMS) + .build(); SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), true, true); InputStream in = stream.getInputStream(); OutputStream out = stream.getOutputStream(); @@ -505,13 +508,15 @@ public final class SpdyConnectionTest { // verify the peer received what was expected MockSpdyPeer.InFrame synStream = peer.takeFrame(); assertEquals(TYPE_SYN_STREAM, synStream.type); - assertEquals(0, synStream.flags); + assertFalse(synStream.inFinished); + assertFalse(synStream.outFinished); MockSpdyPeer.InFrame data = peer.takeFrame(); assertEquals(TYPE_DATA, data.type); assertTrue(Arrays.equals("square".getBytes("UTF-8"), data.data)); MockSpdyPeer.InFrame fin = peer.takeFrame(); assertEquals(TYPE_DATA, fin.type); - assertEquals(FLAG_FIN, fin.flags); + assertTrue(fin.inFinished); + assertFalse(fin.outFinished); MockSpdyPeer.InFrame rstStream = peer.takeFrame(); assertEquals(TYPE_RST_STREAM, rstStream.type); assertEquals(SpdyStream.RST_CANCEL, rstStream.statusCode); @@ -520,14 +525,14 @@ public final class SpdyConnectionTest { @Test public void serverClosesClientInputStream() throws Exception { // write the mocking script peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("b", "banana")); - peer.sendFrame().data(FLAG_FIN, 1, "square".getBytes(UTF_8)); + peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana")); + peer.sendFrame().data(true, 1, "square".getBytes(UTF_8)); peer.play(); // play it back - SpdyConnection connection = - new SpdyConnection.Builder(true, peer.openSocket()).handler(REJECT_INCOMING_STREAMS) - .build(); + SpdyConnection connection = new SpdyConnection.Builder(true, peer.openSocket()) + .handler(REJECT_INCOMING_STREAMS) + .build(); SpdyStream stream = connection.newStream(Arrays.asList("a", "android"), false, true); InputStream in = stream.getInputStream(); assertStreamData("square", in); @@ -536,15 +541,16 @@ public final class SpdyConnectionTest { // verify the peer received what was expected MockSpdyPeer.InFrame synStream = peer.takeFrame(); assertEquals(TYPE_SYN_STREAM, synStream.type); - assertEquals(SpdyConnection.FLAG_FIN, synStream.flags); + assertTrue(synStream.inFinished); + assertFalse(synStream.outFinished); } @Test public void remoteDoubleSynReply() throws Exception { // write the mocking script peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("a", "android")); + peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android")); peer.acceptFrame(); // PING - peer.sendFrame().synReply(0, 1, Arrays.asList("b", "banana")); + peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana")); peer.sendFrame().ping(0, 1); peer.acceptFrame(); // RST_STREAM peer.play(); @@ -575,9 +581,9 @@ public final class SpdyConnectionTest { @Test public void remoteDoubleSynStream() throws Exception { // write the mocking script - peer.sendFrame().synStream(0, 2, 0, 0, 0, Arrays.asList("a", "android")); + peer.sendFrame().synStream(false, false, 2, 0, 0, 0, Arrays.asList("a", "android")); peer.acceptFrame(); // SYN_REPLY - peer.sendFrame().synStream(0, 2, 0, 0, 0, Arrays.asList("b", "banana")); + peer.sendFrame().synStream(false, false, 2, 0, 0, 0, Arrays.asList("b", "banana")); peer.acceptFrame(); // RST_STREAM peer.play(); @@ -607,9 +613,9 @@ public final class SpdyConnectionTest { @Test public void remoteSendsDataAfterInFinished() throws Exception { // write the mocking script peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("a", "android")); - peer.sendFrame().data(SpdyConnection.FLAG_FIN, 1, "robot".getBytes("UTF-8")); - peer.sendFrame().data(SpdyConnection.FLAG_FIN, 1, "c3po".getBytes("UTF-8")); // Ignored. + peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android")); + peer.sendFrame().data(true, 1, "robot".getBytes("UTF-8")); + peer.sendFrame().data(true, 1, "c3po".getBytes("UTF-8")); // Ignored. peer.sendFrame().ping(0, 2); // Ping just to make sure the stream was fastforwarded. peer.acceptFrame(); // PING peer.play(); @@ -632,8 +638,8 @@ public final class SpdyConnectionTest { @Test public void remoteSendsTooMuchData() throws Exception { // write the mocking script peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("b", "banana")); - peer.sendFrame().data(0, 1, new byte[64 * 1024 + 1]); + peer.sendFrame().synReply(false, 1, Arrays.asList("b", "banana")); + peer.sendFrame().data(false, 1, new byte[64 * 1024 + 1]); peer.acceptFrame(); // RST_STREAM peer.sendFrame().ping(0, 2); // Ping just to make sure the stream was fastforwarded. peer.acceptFrame(); // PING @@ -735,7 +741,7 @@ public final class SpdyConnectionTest { peer.acceptFrame(); // SYN_STREAM 1 peer.acceptFrame(); // GOAWAY peer.acceptFrame(); // PING - peer.sendFrame().synStream(0, 2, 0, 0, 0, Arrays.asList("b", "b")); // Should be ignored! + peer.sendFrame().synStream(false, false, 2, 0, 0, 0, Arrays.asList("b", "b")); // Should be ignored! peer.sendFrame().ping(0, 1); peer.play(); @@ -837,7 +843,7 @@ public final class SpdyConnectionTest { @Test public void readTimeoutExpires() throws Exception { // write the mocking script peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("a", "android")); + peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android")); peer.acceptFrame(); // PING peer.sendFrame().ping(0, 1); peer.play(); @@ -867,7 +873,7 @@ public final class SpdyConnectionTest { // write the mocking script peer.acceptFrame(); // SYN_STREAM peer.acceptFrame(); // PING - peer.sendFrame().synReply(0, 1, Arrays.asList("a", "android")); + peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android")); peer.sendFrame().headers(0, 1, Arrays.asList("c", "c3po")); peer.sendFrame().ping(0, 1); peer.play(); @@ -918,12 +924,12 @@ public final class SpdyConnectionTest { @Test public void readSendsWindowUpdate() throws Exception { // Write the mocking script. peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("a", "android")); + peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android")); for (int i = 0; i < 3; i++) { - peer.sendFrame().data(0, 1, new byte[WINDOW_UPDATE_THRESHOLD]); + peer.sendFrame().data(false, 1, new byte[WINDOW_UPDATE_THRESHOLD]); peer.acceptFrame(); // WINDOW UPDATE } - peer.sendFrame().data(FLAG_FIN, 1, new byte[0]); + peer.sendFrame().data(true, 1, new byte[0]); peer.play(); // Play it back. @@ -982,8 +988,8 @@ public final class SpdyConnectionTest { @Test public void testTruncatedDataFrame() throws Exception { // write the mocking script peer.acceptFrame(); // SYN_STREAM - peer.sendFrame().synReply(0, 1, Arrays.asList("a", "android")); - peer.sendTruncatedFrame(8 + 100).data(0, 1, new byte[1024]); + peer.sendFrame().synReply(false, 1, Arrays.asList("a", "android")); + peer.sendTruncatedFrame(8 + 100).data(false, 1, new byte[1024]); peer.play(); // play it back