You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by na...@apache.org on 2014/02/03 21:26:14 UTC
[13/32] CB-5799 Update version of OkHTTP to 1.3
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/166d26a3/framework/src/com/squareup/okhttp/internal/spdy/Settings.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/Settings.java b/framework/src/com/squareup/okhttp/internal/spdy/Settings.java
old mode 100644
new mode 100755
index 774d791..05380e2
--- a/framework/src/com/squareup/okhttp/internal/spdy/Settings.java
+++ b/framework/src/com/squareup/okhttp/internal/spdy/Settings.java
@@ -31,23 +31,29 @@ final class Settings {
static final int PERSISTED = 0x2;
/** Sender's estimate of max incoming kbps. */
- static final int UPLOAD_BANDWIDTH = 0x1;
+ static final int UPLOAD_BANDWIDTH = 1;
/** Sender's estimate of max outgoing kbps. */
- static final int DOWNLOAD_BANDWIDTH = 0x2;
+ static final int DOWNLOAD_BANDWIDTH = 2;
/** Sender's estimate of milliseconds between sending a request and receiving a response. */
- static final int ROUND_TRIP_TIME = 0x3;
+ static final int ROUND_TRIP_TIME = 3;
/** Sender's maximum number of concurrent streams. */
- static final int MAX_CONCURRENT_STREAMS = 0x4;
+ static final int MAX_CONCURRENT_STREAMS = 4;
/** Current CWND in Packets. */
- static final int CURRENT_CWND = 0x5;
+ static final int CURRENT_CWND = 5;
/** Retransmission rate. Percentage */
- static final int DOWNLOAD_RETRANS_RATE = 0x6;
+ static final int DOWNLOAD_RETRANS_RATE = 6;
/** Window size in bytes. */
- static final int INITIAL_WINDOW_SIZE = 0x7;
+ static final int INITIAL_WINDOW_SIZE = 7;
/** Window size in bytes. */
- static final int CLIENT_CERTIFICATE_VECTOR_SIZE = 0x8;
+ static final int CLIENT_CERTIFICATE_VECTOR_SIZE = 8;
+ /** Flow control options. */
+ static final int FLOW_CONTROL_OPTIONS = 9;
+
/** Total number of settings. */
- static final int COUNT = 0x9;
+ static final int COUNT = 10;
+
+ /** If set, flow control is disabled for streams directed to the sender of these settings. */
+ static final int FLOW_CONTROL_OPTIONS_DISABLED = 0x1;
/** Bitfield of which flags that values. */
private int set;
@@ -146,6 +152,13 @@ final class Settings {
return (bit & set) != 0 ? values[CLIENT_CERTIFICATE_VECTOR_SIZE] : defaultValue;
}
+ // TODO: honor this setting.
+ boolean isFlowControlDisabled() {
+ int bit = 1 << FLOW_CONTROL_OPTIONS;
+ int value = (bit & set) != 0 ? values[FLOW_CONTROL_OPTIONS] : 0;
+ return (value & FLOW_CONTROL_OPTIONS_DISABLED) != 0;
+ }
+
/**
* Returns true if this user agent should use this setting in future SPDY
* connections to the same host.
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/166d26a3/framework/src/com/squareup/okhttp/internal/spdy/Spdy3.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/Spdy3.java b/framework/src/com/squareup/okhttp/internal/spdy/Spdy3.java
new file mode 100755
index 0000000..5d9a49b
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/spdy/Spdy3.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.squareup.okhttp.internal.spdy;
+
+import com.squareup.okhttp.internal.Platform;
+import com.squareup.okhttp.internal.Util;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.ProtocolException;
+import java.util.List;
+import java.util.zip.Deflater;
+
+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 {
+ DICTIONARY = ("\u0000\u0000\u0000\u0007options\u0000\u0000\u0000\u0004hea"
+ + "d\u0000\u0000\u0000\u0004post\u0000\u0000\u0000\u0003put\u0000\u0000\u0000\u0006dele"
+ + "te\u0000\u0000\u0000\u0005trace\u0000\u0000\u0000\u0006accept\u0000\u0000\u0000"
+ + "\u000Eaccept-charset\u0000\u0000\u0000\u000Faccept-encoding\u0000\u0000\u0000\u000Fa"
+ + "ccept-language\u0000\u0000\u0000\raccept-ranges\u0000\u0000\u0000\u0003age\u0000"
+ + "\u0000\u0000\u0005allow\u0000\u0000\u0000\rauthorization\u0000\u0000\u0000\rcache-co"
+ + "ntrol\u0000\u0000\u0000\nconnection\u0000\u0000\u0000\fcontent-base\u0000\u0000"
+ + "\u0000\u0010content-encoding\u0000\u0000\u0000\u0010content-language\u0000\u0000"
+ + "\u0000\u000Econtent-length\u0000\u0000\u0000\u0010content-location\u0000\u0000\u0000"
+ + "\u000Bcontent-md5\u0000\u0000\u0000\rcontent-range\u0000\u0000\u0000\fcontent-type"
+ + "\u0000\u0000\u0000\u0004date\u0000\u0000\u0000\u0004etag\u0000\u0000\u0000\u0006expe"
+ + "ct\u0000\u0000\u0000\u0007expires\u0000\u0000\u0000\u0004from\u0000\u0000\u0000"
+ + "\u0004host\u0000\u0000\u0000\bif-match\u0000\u0000\u0000\u0011if-modified-since"
+ + "\u0000\u0000\u0000\rif-none-match\u0000\u0000\u0000\bif-range\u0000\u0000\u0000"
+ + "\u0013if-unmodified-since\u0000\u0000\u0000\rlast-modified\u0000\u0000\u0000\blocati"
+ + "on\u0000\u0000\u0000\fmax-forwards\u0000\u0000\u0000\u0006pragma\u0000\u0000\u0000"
+ + "\u0012proxy-authenticate\u0000\u0000\u0000\u0013proxy-authorization\u0000\u0000"
+ + "\u0000\u0005range\u0000\u0000\u0000\u0007referer\u0000\u0000\u0000\u000Bretry-after"
+ + "\u0000\u0000\u0000\u0006server\u0000\u0000\u0000\u0002te\u0000\u0000\u0000\u0007trai"
+ + "ler\u0000\u0000\u0000\u0011transfer-encoding\u0000\u0000\u0000\u0007upgrade\u0000"
+ + "\u0000\u0000\nuser-agent\u0000\u0000\u0000\u0004vary\u0000\u0000\u0000\u0003via"
+ + "\u0000\u0000\u0000\u0007warning\u0000\u0000\u0000\u0010www-authenticate\u0000\u0000"
+ + "\u0000\u0006method\u0000\u0000\u0000\u0003get\u0000\u0000\u0000\u0006status\u0000"
+ + "\u0000\u0000\u0006200 OK\u0000\u0000\u0000\u0007version\u0000\u0000\u0000\bHTTP/1.1"
+ + "\u0000\u0000\u0000\u0003url\u0000\u0000\u0000\u0006public\u0000\u0000\u0000\nset-coo"
+ + "kie\u0000\u0000\u0000\nkeep-alive\u0000\u0000\u0000\u0006origin100101201202205206300"
+ + "302303304305306307402405406407408409410411412413414415416417502504505203 Non-Authori"
+ + "tative Information204 No Content301 Moved Permanently400 Bad Request401 Unauthorized"
+ + "403 Forbidden404 Not Found500 Internal Server Error501 Not Implemented503 Service Un"
+ + "availableJan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec 00:00:00 Mon, Tue, Wed, Th"
+ + "u, Fri, Sat, Sun, GMTchunked,text/html,image/png,image/jpg,image/gif,application/xml"
+ + ",application/xhtml+xml,text/plain,text/javascript,publicprivatemax-age=gzip,deflate,"
+ + "sdchcharset=utf-8charset=iso-8859-1,utf-,*,enq=0.").getBytes(Util.UTF_8.name());
+ } catch (UnsupportedEncodingException e) {
+ throw new AssertionError();
+ }
+ }
+
+ @Override public FrameReader newReader(InputStream in, boolean client) {
+ return new Reader(in, client);
+ }
+
+ @Override public FrameWriter newWriter(OutputStream out, boolean client) {
+ return new Writer(out, client);
+ }
+
+ /** Read spdy/3 frames. */
+ static final class Reader implements FrameReader {
+ private final DataInputStream in;
+ private final boolean client;
+ private final NameValueBlockReader nameValueBlockReader;
+
+ Reader(InputStream in, boolean client) {
+ this.in = new DataInputStream(in);
+ this.nameValueBlockReader = new NameValueBlockReader(in);
+ this.client = client;
+ }
+
+ @Override public void readConnectionHeader() {
+ }
+
+ /**
+ * Send the next frame to {@code handler}. Returns true unless there are no
+ * more frames on the stream.
+ */
+ @Override public boolean nextFrame(Handler handler) throws IOException {
+ int w1;
+ try {
+ w1 = in.readInt();
+ } catch (IOException e) {
+ return false; // This might be a normal socket close.
+ }
+ int w2 = in.readInt();
+
+ boolean control = (w1 & 0x80000000) != 0;
+ int flags = (w2 & 0xff000000) >>> 24;
+ int length = (w2 & 0xffffff);
+
+ if (control) {
+ int version = (w1 & 0x7fff0000) >>> 16;
+ int type = (w1 & 0xffff);
+
+ if (version != 3) {
+ throw new ProtocolException("version != 3: " + version);
+ }
+
+ switch (type) {
+ case TYPE_SYN_STREAM:
+ readSynStream(handler, flags, length);
+ return true;
+
+ case TYPE_SYN_REPLY:
+ readSynReply(handler, flags, length);
+ return true;
+
+ case TYPE_RST_STREAM:
+ readRstStream(handler, flags, length);
+ return true;
+
+ case TYPE_SETTINGS:
+ readSettings(handler, flags, length);
+ return true;
+
+ case TYPE_NOOP:
+ if (length != 0) throw ioException("TYPE_NOOP length: %d != 0", length);
+ handler.noop();
+ return true;
+
+ case TYPE_PING:
+ readPing(handler, flags, length);
+ return true;
+
+ case TYPE_GOAWAY:
+ readGoAway(handler, flags, length);
+ return true;
+
+ case TYPE_HEADERS:
+ readHeaders(handler, flags, length);
+ return true;
+
+ case TYPE_WINDOW_UPDATE:
+ readWindowUpdate(handler, flags, length);
+ return true;
+
+ case TYPE_CREDENTIAL:
+ Util.skipByReading(in, length);
+ throw new UnsupportedOperationException("TODO"); // TODO: implement
+
+ default:
+ throw new IOException("Unexpected frame");
+ }
+ } else {
+ int streamId = w1 & 0x7fffffff;
+ boolean inFinished = (flags & FLAG_FIN) != 0;
+ handler.data(inFinished, streamId, in, length);
+ return true;
+ }
+ }
+
+ private void readSynStream(Handler handler, int flags, int length) throws IOException {
+ int w1 = in.readInt();
+ int w2 = in.readInt();
+ int s3 = in.readShort();
+ int streamId = w1 & 0x7fffffff;
+ int associatedStreamId = w2 & 0x7fffffff;
+ int priority = (s3 & 0xe000) >>> 13;
+ int slot = s3 & 0xff;
+ List<String> nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 10);
+
+ boolean inFinished = (flags & FLAG_FIN) != 0;
+ boolean outFinished = (flags & FLAG_UNIDIRECTIONAL) != 0;
+ handler.headers(outFinished, inFinished, streamId, associatedStreamId, priority,
+ nameValueBlock, HeadersMode.SPDY_SYN_STREAM);
+ }
+
+ private void readSynReply(Handler handler, int flags, int length) throws IOException {
+ int w1 = in.readInt();
+ int streamId = w1 & 0x7fffffff;
+ List<String> nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 4);
+ boolean inFinished = (flags & FLAG_FIN) != 0;
+ handler.headers(false, inFinished, streamId, -1, -1, nameValueBlock, HeadersMode.SPDY_REPLY);
+ }
+
+ private void readRstStream(Handler handler, int flags, int length) throws IOException {
+ if (length != 8) throw ioException("TYPE_RST_STREAM length: %d != 8", length);
+ int streamId = in.readInt() & 0x7fffffff;
+ int errorCodeInt = in.readInt();
+ ErrorCode errorCode = ErrorCode.fromSpdy3Rst(errorCodeInt);
+ if (errorCode == null) {
+ throw ioException("TYPE_RST_STREAM unexpected error code: %d", errorCodeInt);
+ }
+ handler.rstStream(streamId, errorCode);
+ }
+
+ private void readHeaders(Handler handler, int flags, int length) throws IOException {
+ int w1 = in.readInt();
+ int streamId = w1 & 0x7fffffff;
+ List<String> nameValueBlock = nameValueBlockReader.readNameValueBlock(length - 4);
+ handler.headers(false, false, streamId, -1, -1, nameValueBlock, HeadersMode.SPDY_HEADERS);
+ }
+
+ private void readWindowUpdate(Handler handler, int flags, int length) throws IOException {
+ if (length != 8) throw ioException("TYPE_WINDOW_UPDATE length: %d != 8", length);
+ int w1 = in.readInt();
+ int w2 = in.readInt();
+ int streamId = w1 & 0x7fffffff;
+ int deltaWindowSize = w2 & 0x7fffffff;
+ handler.windowUpdate(streamId, deltaWindowSize, false);
+ }
+
+ private void readPing(Handler handler, int flags, int length) throws IOException {
+ if (length != 4) throw ioException("TYPE_PING length: %d != 4", length);
+ int id = in.readInt();
+ boolean reply = client == ((id % 2) == 1);
+ handler.ping(reply, id, 0);
+ }
+
+ private void readGoAway(Handler handler, int flags, int length) throws IOException {
+ if (length != 8) throw ioException("TYPE_GOAWAY length: %d != 8", length);
+ int lastGoodStreamId = in.readInt() & 0x7fffffff;
+ int errorCodeInt = in.readInt();
+ ErrorCode errorCode = ErrorCode.fromSpdyGoAway(errorCodeInt);
+ if (errorCode == null) {
+ throw ioException("TYPE_GOAWAY unexpected error code: %d", errorCodeInt);
+ }
+ handler.goAway(lastGoodStreamId, errorCode);
+ }
+
+ private void readSettings(Handler handler, int flags, int length) throws IOException {
+ int numberOfEntries = in.readInt();
+ if (length != 4 + 8 * numberOfEntries) {
+ throw ioException("TYPE_SETTINGS length: %d != 4 + 8 * %d", length, numberOfEntries);
+ }
+ Settings settings = new Settings();
+ for (int i = 0; i < numberOfEntries; i++) {
+ int w1 = in.readInt();
+ int value = in.readInt();
+ int idFlags = (w1 & 0xff000000) >>> 24;
+ int id = w1 & 0xffffff;
+ settings.set(id, idFlags, value);
+ }
+ boolean clearPrevious = (flags & Settings.FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) != 0;
+ handler.settings(clearPrevious, settings);
+ }
+
+ private static IOException ioException(String message, Object... args) throws IOException {
+ throw new IOException(String.format(message, args));
+ }
+
+ @Override public void close() throws IOException {
+ Util.closeAll(in, nameValueBlockReader);
+ }
+ }
+
+ /** Write spdy/3 frames. */
+ static final class Writer implements FrameWriter {
+ private final DataOutputStream out;
+ private final ByteArrayOutputStream nameValueBlockBuffer;
+ private final DataOutputStream nameValueBlockOut;
+ private final boolean client;
+
+ Writer(OutputStream out, boolean client) {
+ this.out = new DataOutputStream(out);
+ this.client = client;
+
+ Deflater deflater = new Deflater();
+ deflater.setDictionary(DICTIONARY);
+ nameValueBlockBuffer = new ByteArrayOutputStream();
+ nameValueBlockOut = new DataOutputStream(
+ Platform.get().newDeflaterOutputStream(nameValueBlockBuffer, deflater, true));
+ }
+
+ @Override public synchronized void connectionHeader() {
+ // Do nothing: no connection header for SPDY/3.
+ }
+
+ @Override public synchronized void flush() throws IOException {
+ out.flush();
+ }
+
+ @Override public synchronized void synStream(boolean outFinished, boolean inFinished,
+ int streamId, int associatedStreamId, int priority, int slot, List<String> nameValueBlock)
+ throws IOException {
+ writeNameValueBlockToBuffer(nameValueBlock);
+ int length = 10 + nameValueBlockBuffer.size();
+ int type = TYPE_SYN_STREAM;
+ int flags = (outFinished ? FLAG_FIN : 0) | (inFinished ? FLAG_UNIDIRECTIONAL : 0);
+
+ int unused = 0;
+ out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff);
+ out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
+ out.writeInt(streamId & 0x7fffffff);
+ out.writeInt(associatedStreamId & 0x7fffffff);
+ out.writeShort((priority & 0x7) << 13 | (unused & 0x1f) << 8 | (slot & 0xff));
+ nameValueBlockBuffer.writeTo(out);
+ out.flush();
+ }
+
+ @Override public synchronized void synReply(
+ boolean outFinished, int streamId, List<String> nameValueBlock) throws IOException {
+ writeNameValueBlockToBuffer(nameValueBlock);
+ int type = TYPE_SYN_REPLY;
+ int flags = (outFinished ? FLAG_FIN : 0);
+ int length = nameValueBlockBuffer.size() + 4;
+
+ out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff);
+ out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
+ out.writeInt(streamId & 0x7fffffff);
+ nameValueBlockBuffer.writeTo(out);
+ out.flush();
+ }
+
+ @Override public synchronized void headers(int streamId, List<String> nameValueBlock)
+ throws IOException {
+ writeNameValueBlockToBuffer(nameValueBlock);
+ int flags = 0;
+ int type = TYPE_HEADERS;
+ int length = nameValueBlockBuffer.size() + 4;
+
+ out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff);
+ out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
+ out.writeInt(streamId & 0x7fffffff);
+ nameValueBlockBuffer.writeTo(out);
+ out.flush();
+ }
+
+ @Override public synchronized void rstStream(int streamId, ErrorCode errorCode)
+ throws IOException {
+ if (errorCode.spdyRstCode == -1) throw new IllegalArgumentException();
+ int flags = 0;
+ int type = TYPE_RST_STREAM;
+ int length = 8;
+ out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff);
+ out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
+ out.writeInt(streamId & 0x7fffffff);
+ out.writeInt(errorCode.spdyRstCode);
+ out.flush();
+ }
+
+ @Override public synchronized void data(boolean outFinished, int streamId, byte[] data)
+ throws IOException {
+ 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 | byteCount & 0xffffff);
+ out.write(data, offset, byteCount);
+ }
+
+ private void writeNameValueBlockToBuffer(List<String> nameValueBlock) throws IOException {
+ nameValueBlockBuffer.reset();
+ int numberOfPairs = nameValueBlock.size() / 2;
+ nameValueBlockOut.writeInt(numberOfPairs);
+ for (String s : nameValueBlock) {
+ nameValueBlockOut.writeInt(s.length());
+ nameValueBlockOut.write(s.getBytes("UTF-8"));
+ }
+ nameValueBlockOut.flush();
+ }
+
+ @Override public synchronized void settings(Settings settings) throws IOException {
+ int type = TYPE_SETTINGS;
+ int flags = 0;
+ int size = settings.size();
+ int length = 4 + size * 8;
+ 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++) {
+ if (!settings.isSet(i)) continue;
+ int settingsFlags = settings.flags(i);
+ out.writeInt((settingsFlags & 0xff) << 24 | (i & 0xffffff));
+ out.writeInt(settings.get(i));
+ }
+ out.flush();
+ }
+
+ @Override public synchronized void noop() throws IOException {
+ int type = TYPE_NOOP;
+ int length = 0;
+ int flags = 0;
+ out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff);
+ out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
+ out.flush();
+ }
+
+ @Override public synchronized void ping(boolean reply, int payload1, int payload2)
+ throws IOException {
+ boolean payloadIsReply = client != ((payload1 % 2) == 1);
+ if (reply != payloadIsReply) throw new IllegalArgumentException("payload != reply");
+ int type = TYPE_PING;
+ int flags = 0;
+ int length = 4;
+ out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff);
+ out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
+ out.writeInt(payload1);
+ out.flush();
+ }
+
+ @Override public synchronized void goAway(int lastGoodStreamId, ErrorCode errorCode)
+ throws IOException {
+ if (errorCode.spdyGoAwayCode == -1) throw new IllegalArgumentException();
+ int type = TYPE_GOAWAY;
+ int flags = 0;
+ int length = 8;
+ out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff);
+ out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
+ out.writeInt(lastGoodStreamId);
+ out.writeInt(errorCode.spdyGoAwayCode);
+ out.flush();
+ }
+
+ @Override public synchronized void windowUpdate(int streamId, int deltaWindowSize)
+ throws IOException {
+ int type = TYPE_WINDOW_UPDATE;
+ int flags = 0;
+ int length = 8;
+ out.writeInt(0x80000000 | (VERSION & 0x7fff) << 16 | type & 0xffff);
+ out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
+ out.writeInt(streamId);
+ out.writeInt(deltaWindowSize);
+ out.flush();
+ }
+
+ @Override public void close() throws IOException {
+ Util.closeAll(out, nameValueBlockOut);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/166d26a3/framework/src/com/squareup/okhttp/internal/spdy/SpdyConnection.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/SpdyConnection.java b/framework/src/com/squareup/okhttp/internal/spdy/SpdyConnection.java
old mode 100644
new mode 100755
index fccd14f..41724f0
--- a/framework/src/com/squareup/okhttp/internal/spdy/SpdyConnection.java
+++ b/framework/src/com/squareup/okhttp/internal/spdy/SpdyConnection.java
@@ -32,8 +32,6 @@ import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import static java.util.concurrent.Executors.defaultThreadFactory;
-
/**
* A socket connection to a remote peer. A connection hosts streams which can
* send and receive data.
@@ -48,38 +46,21 @@ public final class SpdyConnection implements Closeable {
// Internal state of this connection is guarded by 'this'. No blocking
// operations may be performed while holding this lock!
//
- // Socket writes are guarded by spdyWriter.
+ // Socket writes are guarded by frameWriter.
//
// Socket reads are unguarded but are only made by the reader thread.
//
// Certain operations (like SYN_STREAM) need to synchronize on both the
- // spdyWriter (to do blocking I/O) and this (to create streams). Such
+ // frameWriter (to do blocking I/O) and this (to create streams). Such
// 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;
-
- private static final ExecutorService executor =
- new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>(), defaultThreadFactory());
+ private static final ExecutorService executor = new ThreadPoolExecutor(0,
+ Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
+ Util.daemonThreadFactory("OkHttp SpdyConnection"));
+
+ /** The protocol variant, like SPDY/3 or HTTP-draft-06/2.0. */
+ final Variant variant;
/** True if this peer initiated the connection. */
final boolean client;
@@ -89,8 +70,8 @@ public final class SpdyConnection implements Closeable {
* run on the callback executor.
*/
private final IncomingStreamHandler handler;
- private final SpdyReader spdyReader;
- private final SpdyWriter spdyWriter;
+ private final FrameReader frameReader;
+ private final FrameWriter frameWriter;
private final Map<Integer, SpdyStream> streams = new HashMap<Integer, SpdyStream>();
private final String hostName;
@@ -103,14 +84,15 @@ public final class SpdyConnection implements Closeable {
private Map<Integer, Ping> pings;
private int nextPingId;
- /** Lazily-created settings for this connection. */
+ /** Lazily-created settings for the peer. */
Settings settings;
private SpdyConnection(Builder builder) {
+ variant = builder.variant;
client = builder.client;
handler = builder.handler;
- spdyReader = new SpdyReader(builder.in);
- spdyWriter = new SpdyWriter(builder.out);
+ frameReader = variant.newReader(builder.in, client);
+ frameWriter = variant.newWriter(builder.out, client);
nextStreamId = builder.client ? 1 : 2;
nextPingId = builder.client ? 1 : 2;
@@ -140,15 +122,18 @@ public final class SpdyConnection implements Closeable {
}
private synchronized void setIdle(boolean value) {
- idleStartTimeNs = value ? System.nanoTime() : 0L;
+ idleStartTimeNs = value ? System.nanoTime() : Long.MAX_VALUE;
}
/** Returns true if this connection is idle. */
public synchronized boolean isIdle() {
- return idleStartTimeNs != 0L;
+ return idleStartTimeNs != Long.MAX_VALUE;
}
- /** Returns the time in ns when this connection became idle or 0L if connection is not idle. */
+ /**
+ * Returns the time in ns when this connection became idle or Long.MAX_VALUE
+ * if connection is not idle.
+ */
public synchronized long getIdleStartTimeNs() {
return idleStartTimeNs;
}
@@ -157,80 +142,80 @@ 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<String> 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?
SpdyStream stream;
int streamId;
- synchronized (spdyWriter) {
+ synchronized (frameWriter) {
synchronized (this) {
if (shutdown) {
throw new IOException("shutdown");
}
streamId = nextStreamId;
nextStreamId += 2;
- stream = new SpdyStream(streamId, this, flags, priority, slot, requestHeaders, settings);
+ stream = new SpdyStream(
+ streamId, this, outFinished, inFinished, priority, requestHeaders, settings);
if (stream.isOpen()) {
streams.put(streamId, stream);
setIdle(false);
}
}
- spdyWriter.synStream(flags, streamId, associatedStreamId, priority, slot, requestHeaders);
+ frameWriter.synStream(outFinished, inFinished, streamId, associatedStreamId, priority, slot,
+ requestHeaders);
}
return stream;
}
- void writeSynReply(int streamId, int flags, List<String> alternating) throws IOException {
- spdyWriter.synReply(flags, streamId, alternating);
+ void writeSynReply(int streamId, boolean outFinished, List<String> alternating)
+ throws IOException {
+ frameWriter.synReply(outFinished, streamId, alternating);
}
- /** Writes a complete data frame. */
- void writeFrame(byte[] bytes, int offset, int length) throws IOException {
- synchronized (spdyWriter) {
- spdyWriter.out.write(bytes, offset, length);
- }
+ public void writeData(int streamId, boolean outFinished, byte[] buffer, int offset, int byteCount)
+ throws IOException {
+ frameWriter.data(outFinished, streamId, buffer, offset, byteCount);
}
- void writeSynResetLater(final int streamId, final int statusCode) {
- executor.submit(
- new NamedRunnable(String.format("Spdy Writer %s stream %d", hostName, streamId)) {
- @Override public void execute() {
- try {
- writeSynReset(streamId, statusCode);
- } catch (IOException ignored) {
- }
- }
- });
+ void writeSynResetLater(final int streamId, final ErrorCode errorCode) {
+ executor.submit(new NamedRunnable("OkHttp SPDY Writer %s stream %d", hostName, streamId) {
+ @Override public void execute() {
+ try {
+ writeSynReset(streamId, errorCode);
+ } catch (IOException ignored) {
+ }
+ }
+ });
}
- void writeSynReset(int streamId, int statusCode) throws IOException {
- spdyWriter.rstStream(streamId, statusCode);
+ void writeSynReset(int streamId, ErrorCode statusCode) throws IOException {
+ frameWriter.rstStream(streamId, statusCode);
}
void writeWindowUpdateLater(final int streamId, final int deltaWindowSize) {
- executor.submit(
- new NamedRunnable(String.format("Spdy Writer %s stream %d", hostName, streamId)) {
- @Override public void execute() {
- try {
- writeWindowUpdate(streamId, deltaWindowSize);
- } catch (IOException ignored) {
- }
- }
- });
+ executor.submit(new NamedRunnable("OkHttp SPDY Writer %s stream %d", hostName, streamId) {
+ @Override public void execute() {
+ try {
+ writeWindowUpdate(streamId, deltaWindowSize);
+ } catch (IOException ignored) {
+ }
+ }
+ });
}
void writeWindowUpdate(int streamId, int deltaWindowSize) throws IOException {
- spdyWriter.windowUpdate(streamId, deltaWindowSize);
+ frameWriter.windowUpdate(streamId, deltaWindowSize);
}
/**
@@ -249,26 +234,28 @@ public final class SpdyConnection implements Closeable {
if (pings == null) pings = new HashMap<Integer, Ping>();
pings.put(pingId, ping);
}
- writePing(pingId, ping);
+ writePing(false, pingId, 0x4f4b6f6b /* ASCII "OKok" */, ping);
return ping;
}
- private void writePingLater(final int streamId, final Ping ping) {
- executor.submit(new NamedRunnable(String.format("Spdy Writer %s ping %d", hostName, streamId)) {
+ private void writePingLater(
+ final boolean reply, final int payload1, final int payload2, final Ping ping) {
+ executor.submit(new NamedRunnable("OkHttp SPDY Writer %s ping %08x%08x",
+ hostName, payload1, payload2) {
@Override public void execute() {
try {
- writePing(streamId, ping);
+ writePing(reply, payload1, payload2, ping);
} catch (IOException ignored) {
}
}
});
}
- private void writePing(int id, Ping ping) throws IOException {
- synchronized (spdyWriter) {
+ private void writePing(boolean reply, int payload1, int payload2, Ping ping) throws IOException {
+ synchronized (frameWriter) {
// Observe the sent time immediately before performing I/O.
if (ping != null) ping.send();
- spdyWriter.ping(0, id);
+ frameWriter.ping(reply, payload1, payload2);
}
}
@@ -278,13 +265,11 @@ public final class SpdyConnection implements Closeable {
/** Sends a noop frame to the peer. */
public void noop() throws IOException {
- spdyWriter.noop();
+ frameWriter.noop();
}
public void flush() throws IOException {
- synchronized (spdyWriter) {
- spdyWriter.out.flush();
- }
+ frameWriter.flush();
}
/**
@@ -292,12 +277,9 @@ public final class SpdyConnection implements Closeable {
* locally, nor accepted from the remote peer. Existing streams are not
* impacted. This is intended to permit an endpoint to gracefully stop
* accepting new requests without harming previously established streams.
- *
- * @param statusCode one of {@link #GOAWAY_OK}, {@link
- * #GOAWAY_INTERNAL_ERROR} or {@link #GOAWAY_PROTOCOL_ERROR}.
*/
- public void shutdown(int statusCode) throws IOException {
- synchronized (spdyWriter) {
+ public void shutdown(ErrorCode statusCode) throws IOException {
+ synchronized (frameWriter) {
int lastGoodStreamId;
synchronized (this) {
if (shutdown) {
@@ -306,7 +288,7 @@ public final class SpdyConnection implements Closeable {
shutdown = true;
lastGoodStreamId = this.lastGoodStreamId;
}
- spdyWriter.goAway(0, lastGoodStreamId, statusCode);
+ frameWriter.goAway(lastGoodStreamId, statusCode);
}
}
@@ -316,14 +298,14 @@ public final class SpdyConnection implements Closeable {
* internal executor services.
*/
@Override public void close() throws IOException {
- close(GOAWAY_OK, SpdyStream.RST_CANCEL);
+ close(ErrorCode.NO_ERROR, ErrorCode.CANCEL);
}
- private void close(int shutdownStatusCode, int rstStatusCode) throws IOException {
+ private void close(ErrorCode connectionCode, ErrorCode streamCode) throws IOException {
assert (!Thread.holdsLock(this));
IOException thrown = null;
try {
- shutdown(shutdownStatusCode);
+ shutdown(connectionCode);
} catch (IOException e) {
thrown = e;
}
@@ -345,7 +327,7 @@ public final class SpdyConnection implements Closeable {
if (streamsToClose != null) {
for (SpdyStream stream : streamsToClose) {
try {
- stream.close(rstStatusCode);
+ stream.close(streamCode);
} catch (IOException e) {
if (thrown != null) thrown = e;
}
@@ -359,12 +341,12 @@ public final class SpdyConnection implements Closeable {
}
try {
- spdyReader.close();
+ frameReader.close();
} catch (IOException e) {
thrown = e;
}
try {
- spdyWriter.close();
+ frameWriter.close();
} catch (IOException e) {
if (thrown == null) thrown = e;
}
@@ -372,12 +354,30 @@ public final class SpdyConnection implements Closeable {
if (thrown != null) throw thrown;
}
+ /**
+ * Sends a connection header if the current variant requires it. This should
+ * be called after {@link Builder#build} for all new connections.
+ */
+ public void sendConnectionHeader() throws IOException {
+ frameWriter.connectionHeader();
+ frameWriter.settings(new Settings());
+ }
+
+ /**
+ * Reads a connection header if the current variant requires it. This should
+ * be called after {@link Builder#build} for all new connections.
+ */
+ public void readConnectionHeader() throws IOException {
+ frameReader.readConnectionHeader();
+ }
+
public static class Builder {
private String hostName;
private InputStream in;
private OutputStream out;
private IncomingStreamHandler handler = IncomingStreamHandler.REFUSE_INCOMING_STREAMS;
- public boolean client;
+ private Variant variant = Variant.SPDY3;
+ private boolean client;
public Builder(boolean client, Socket socket) throws IOException {
this("", client, socket.getInputStream(), socket.getOutputStream());
@@ -411,110 +411,119 @@ public final class SpdyConnection implements Closeable {
return this;
}
+ public Builder spdy3() {
+ this.variant = Variant.SPDY3;
+ return this;
+ }
+
+ public Builder http20Draft06() {
+ this.variant = Variant.HTTP_20_DRAFT_06;
+ return this;
+ }
+
public SpdyConnection build() {
return new SpdyConnection(this);
}
}
- private class Reader implements Runnable, SpdyReader.Handler {
+ private class Reader implements Runnable, FrameReader.Handler {
@Override public void run() {
- int shutdownStatusCode = GOAWAY_INTERNAL_ERROR;
- int rstStatusCode = SpdyStream.RST_INTERNAL_ERROR;
+ ErrorCode connectionErrorCode = ErrorCode.INTERNAL_ERROR;
+ ErrorCode streamErrorCode = ErrorCode.INTERNAL_ERROR;
try {
- while (spdyReader.nextFrame(this)) {
+ while (frameReader.nextFrame(this)) {
}
- shutdownStatusCode = GOAWAY_OK;
- rstStatusCode = SpdyStream.RST_CANCEL;
+ connectionErrorCode = ErrorCode.NO_ERROR;
+ streamErrorCode = ErrorCode.CANCEL;
} catch (IOException e) {
- shutdownStatusCode = GOAWAY_PROTOCOL_ERROR;
- rstStatusCode = SpdyStream.RST_PROTOCOL_ERROR;
+ connectionErrorCode = ErrorCode.PROTOCOL_ERROR;
+ streamErrorCode = ErrorCode.PROTOCOL_ERROR;
} finally {
try {
- close(shutdownStatusCode, rstStatusCode);
+ close(connectionErrorCode, streamErrorCode);
} catch (IOException ignored) {
}
}
}
- @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) {
- writeSynResetLater(streamId, SpdyStream.RST_INVALID_STREAM);
+ writeSynResetLater(streamId, ErrorCode.INVALID_STREAM);
Util.skipByReading(in, length);
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<String> nameValueBlock) {
- final SpdyStream synStream;
- final SpdyStream previous;
+ @Override public void headers(boolean outFinished, boolean inFinished, int streamId,
+ int associatedStreamId, int priority, List<String> nameValueBlock,
+ HeadersMode headersMode) {
+ SpdyStream stream;
synchronized (SpdyConnection.this) {
- synStream =
- new SpdyStream(streamId, SpdyConnection.this, flags, priority, slot, nameValueBlock,
- settings);
- if (shutdown) {
- return;
- }
- lastGoodStreamId = streamId;
- previous = streams.put(streamId, synStream);
- }
- if (previous != null) {
- previous.closeLater(SpdyStream.RST_PROTOCOL_ERROR);
- removeStream(streamId);
- return;
- }
+ // If we're shutdown, don't bother with this stream.
+ if (shutdown) return;
+
+ stream = getStream(streamId);
- executor.submit(
- new NamedRunnable(String.format("Callback %s stream %d", hostName, streamId)) {
- @Override public void execute() {
- try {
- handler.receive(synStream);
- } catch (IOException e) {
- throw new RuntimeException(e);
+ if (stream == null) {
+ // The headers claim to be for an existing stream, but we don't have one.
+ if (headersMode.failIfStreamAbsent()) {
+ writeSynResetLater(streamId, ErrorCode.INVALID_STREAM);
+ return;
}
+
+ // If the stream ID is less than the last created ID, assume it's already closed.
+ if (streamId <= lastGoodStreamId) return;
+
+ // If the stream ID is in the client's namespace, assume it's already closed.
+ if (streamId % 2 == nextStreamId % 2) return;
+
+ // Create a stream.
+ final SpdyStream newStream = new SpdyStream(streamId, SpdyConnection.this, outFinished,
+ inFinished, priority, nameValueBlock, settings);
+ lastGoodStreamId = streamId;
+ streams.put(streamId, newStream);
+ executor.submit(new NamedRunnable("OkHttp Callback %s stream %d", hostName, streamId) {
+ @Override public void execute() {
+ try {
+ handler.receive(newStream);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ return;
}
- });
- }
+ }
- @Override public void synReply(int flags, int streamId, List<String> nameValueBlock)
- throws IOException {
- SpdyStream replyStream = getStream(streamId);
- if (replyStream == null) {
- writeSynResetLater(streamId, SpdyStream.RST_INVALID_STREAM);
+ // The headers claim to be for a new stream, but we already have one.
+ if (headersMode.failIfStreamPresent()) {
+ stream.closeLater(ErrorCode.PROTOCOL_ERROR);
+ removeStream(streamId);
return;
}
- replyStream.receiveReply(nameValueBlock);
- if ((flags & SpdyConnection.FLAG_FIN) != 0) {
- replyStream.receiveFin();
- }
- }
- @Override public void headers(int flags, int streamId, List<String> nameValueBlock)
- throws IOException {
- SpdyStream replyStream = getStream(streamId);
- if (replyStream != null) {
- replyStream.receiveHeaders(nameValueBlock);
- }
+ // Update an existing stream.
+ stream.receiveHeaders(nameValueBlock, headersMode);
+ if (inFinished) stream.receiveFin();
}
- @Override public void rstStream(int flags, int streamId, int statusCode) {
+ @Override public void rstStream(int streamId, ErrorCode errorCode) {
SpdyStream rstStream = removeStream(streamId);
if (rstStream != null) {
- rstStream.receiveRstStream(statusCode);
+ rstStream.receiveRstStream(errorCode);
}
}
- @Override public void settings(int flags, Settings newSettings) {
+ @Override public void settings(boolean clearPrevious, Settings newSettings) {
SpdyStream[] streamsToNotify = null;
synchronized (SpdyConnection.this) {
- if (settings == null || (flags & Settings.FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS) != 0) {
+ if (settings == null || clearPrevious) {
settings = newSettings;
} else {
settings.merge(newSettings);
@@ -528,8 +537,9 @@ public final class SpdyConnection implements Closeable {
// The synchronization here is ugly. We need to synchronize on 'this' to guard
// reads to 'settings'. We synchronize on 'stream' to guard the state change.
// And we need to acquire the 'stream' lock first, since that may block.
+ // TODO: this can block the reader thread until a write completes. That's bad!
synchronized (stream) {
- synchronized (this) {
+ synchronized (SpdyConnection.this) {
stream.receiveSettings(settings);
}
}
@@ -540,19 +550,19 @@ public final class SpdyConnection implements Closeable {
@Override public void noop() {
}
- @Override public void ping(int flags, int streamId) {
- if (client != (streamId % 2 == 1)) {
- // Respond to a client ping if this is a server and vice versa.
- writePingLater(streamId, null);
- } else {
- Ping ping = removePing(streamId);
+ @Override public void ping(boolean reply, int payload1, int payload2) {
+ if (reply) {
+ Ping ping = removePing(payload1);
if (ping != null) {
ping.receive();
}
+ } else {
+ // Send a reply to a client ping if this is a server and vice versa.
+ writePingLater(true, payload1, payload2, null);
}
}
- @Override public void goAway(int flags, int lastGoodStreamId, int statusCode) {
+ @Override public void goAway(int lastGoodStreamId, ErrorCode errorCode) {
synchronized (SpdyConnection.this) {
shutdown = true;
@@ -562,18 +572,28 @@ public final class SpdyConnection implements Closeable {
Map.Entry<Integer, SpdyStream> entry = i.next();
int streamId = entry.getKey();
if (streamId > lastGoodStreamId && entry.getValue().isLocallyInitiated()) {
- entry.getValue().receiveRstStream(SpdyStream.RST_REFUSED_STREAM);
+ entry.getValue().receiveRstStream(ErrorCode.REFUSED_STREAM);
i.remove();
}
}
}
}
- @Override public void windowUpdate(int flags, int streamId, int deltaWindowSize) {
+ @Override public void windowUpdate(int streamId, int deltaWindowSize, boolean endFlowControl) {
+ if (streamId == 0) {
+ // TODO: honor whole-stream flow control
+ return;
+ }
+
+ // TODO: honor endFlowControl
SpdyStream stream = getStream(streamId);
if (stream != null) {
stream.receiveWindowUpdate(deltaWindowSize);
}
}
+
+ @Override public void priority(int streamId, int priority) {
+ // TODO: honor priority.
+ }
}
}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/166d26a3/framework/src/com/squareup/okhttp/internal/spdy/SpdyReader.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/SpdyReader.java b/framework/src/com/squareup/okhttp/internal/spdy/SpdyReader.java
deleted file mode 100644
index 7d3f2bd..0000000
--- a/framework/src/com/squareup/okhttp/internal/spdy/SpdyReader.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.squareup.okhttp.internal.spdy;
-
-import com.squareup.okhttp.internal.Util;
-import java.io.Closeable;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.ProtocolException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Logger;
-import java.util.zip.DataFormatException;
-import java.util.zip.Inflater;
-import java.util.zip.InflaterInputStream;
-
-/** Read spdy/3 frames. */
-final class SpdyReader implements Closeable {
- static final byte[] DICTIONARY;
- static {
- try {
- DICTIONARY = ("\u0000\u0000\u0000\u0007options\u0000\u0000\u0000\u0004hea"
- + "d\u0000\u0000\u0000\u0004post\u0000\u0000\u0000\u0003put\u0000\u0000\u0000\u0006dele"
- + "te\u0000\u0000\u0000\u0005trace\u0000\u0000\u0000\u0006accept\u0000\u0000\u0000"
- + "\u000Eaccept-charset\u0000\u0000\u0000\u000Faccept-encoding\u0000\u0000\u0000\u000Fa"
- + "ccept-language\u0000\u0000\u0000\raccept-ranges\u0000\u0000\u0000\u0003age\u0000"
- + "\u0000\u0000\u0005allow\u0000\u0000\u0000\rauthorization\u0000\u0000\u0000\rcache-co"
- + "ntrol\u0000\u0000\u0000\nconnection\u0000\u0000\u0000\fcontent-base\u0000\u0000"
- + "\u0000\u0010content-encoding\u0000\u0000\u0000\u0010content-language\u0000\u0000"
- + "\u0000\u000Econtent-length\u0000\u0000\u0000\u0010content-location\u0000\u0000\u0000"
- + "\u000Bcontent-md5\u0000\u0000\u0000\rcontent-range\u0000\u0000\u0000\fcontent-type"
- + "\u0000\u0000\u0000\u0004date\u0000\u0000\u0000\u0004etag\u0000\u0000\u0000\u0006expe"
- + "ct\u0000\u0000\u0000\u0007expires\u0000\u0000\u0000\u0004from\u0000\u0000\u0000"
- + "\u0004host\u0000\u0000\u0000\bif-match\u0000\u0000\u0000\u0011if-modified-since"
- + "\u0000\u0000\u0000\rif-none-match\u0000\u0000\u0000\bif-range\u0000\u0000\u0000"
- + "\u0013if-unmodified-since\u0000\u0000\u0000\rlast-modified\u0000\u0000\u0000\blocati"
- + "on\u0000\u0000\u0000\fmax-forwards\u0000\u0000\u0000\u0006pragma\u0000\u0000\u0000"
- + "\u0012proxy-authenticate\u0000\u0000\u0000\u0013proxy-authorization\u0000\u0000"
- + "\u0000\u0005range\u0000\u0000\u0000\u0007referer\u0000\u0000\u0000\u000Bretry-after"
- + "\u0000\u0000\u0000\u0006server\u0000\u0000\u0000\u0002te\u0000\u0000\u0000\u0007trai"
- + "ler\u0000\u0000\u0000\u0011transfer-encoding\u0000\u0000\u0000\u0007upgrade\u0000"
- + "\u0000\u0000\nuser-agent\u0000\u0000\u0000\u0004vary\u0000\u0000\u0000\u0003via"
- + "\u0000\u0000\u0000\u0007warning\u0000\u0000\u0000\u0010www-authenticate\u0000\u0000"
- + "\u0000\u0006method\u0000\u0000\u0000\u0003get\u0000\u0000\u0000\u0006status\u0000"
- + "\u0000\u0000\u0006200 OK\u0000\u0000\u0000\u0007version\u0000\u0000\u0000\bHTTP/1.1"
- + "\u0000\u0000\u0000\u0003url\u0000\u0000\u0000\u0006public\u0000\u0000\u0000\nset-coo"
- + "kie\u0000\u0000\u0000\nkeep-alive\u0000\u0000\u0000\u0006origin100101201202205206300"
- + "302303304305306307402405406407408409410411412413414415416417502504505203 Non-Authori"
- + "tative Information204 No Content301 Moved Permanently400 Bad Request401 Unauthorized"
- + "403 Forbidden404 Not Found500 Internal Server Error501 Not Implemented503 Service Un"
- + "availableJan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec 00:00:00 Mon, Tue, Wed, Th"
- + "u, Fri, Sat, Sun, GMTchunked,text/html,image/png,image/jpg,image/gif,application/xml"
- + ",application/xhtml+xml,text/plain,text/javascript,publicprivatemax-age=gzip,deflate,"
- + "sdchcharset=utf-8charset=iso-8859-1,utf-,*,enq=0.").getBytes(Util.UTF_8.name());
- } catch (UnsupportedEncodingException e) {
- throw new AssertionError();
- }
- }
-
- private final DataInputStream in;
- private final DataInputStream nameValueBlockIn;
- private int compressedLimit;
-
- SpdyReader(InputStream in) {
- this.in = new DataInputStream(in);
- this.nameValueBlockIn = newNameValueBlockStream();
- }
-
- /**
- * Send the next frame to {@code handler}. Returns true unless there are no
- * more frames on the stream.
- */
- public boolean nextFrame(Handler handler) throws IOException {
- int w1;
- try {
- w1 = in.readInt();
- } catch (IOException e) {
- return false; // This might be a normal socket close.
- }
- int w2 = in.readInt();
-
- boolean control = (w1 & 0x80000000) != 0;
- int flags = (w2 & 0xff000000) >>> 24;
- int length = (w2 & 0xffffff);
-
- if (control) {
- int version = (w1 & 0x7fff0000) >>> 16;
- int type = (w1 & 0xffff);
-
- if (version != 3) {
- throw new ProtocolException("version != 3: " + version);
- }
-
- switch (type) {
- case SpdyConnection.TYPE_SYN_STREAM:
- readSynStream(handler, flags, length);
- return true;
-
- case SpdyConnection.TYPE_SYN_REPLY:
- readSynReply(handler, flags, length);
- return true;
-
- case SpdyConnection.TYPE_RST_STREAM:
- readRstStream(handler, flags, length);
- return true;
-
- case SpdyConnection.TYPE_SETTINGS:
- readSettings(handler, flags, length);
- return true;
-
- case SpdyConnection.TYPE_NOOP:
- if (length != 0) throw ioException("TYPE_NOOP length: %d != 0", length);
- handler.noop();
- return true;
-
- case SpdyConnection.TYPE_PING:
- readPing(handler, flags, length);
- return true;
-
- case SpdyConnection.TYPE_GOAWAY:
- readGoAway(handler, flags, length);
- return true;
-
- case SpdyConnection.TYPE_HEADERS:
- readHeaders(handler, flags, length);
- return true;
-
- case SpdyConnection.TYPE_WINDOW_UPDATE:
- readWindowUpdate(handler, flags, length);
- return true;
-
- case SpdyConnection.TYPE_CREDENTIAL:
- Util.skipByReading(in, length);
- throw new UnsupportedOperationException("TODO"); // TODO: implement
-
- default:
- throw new IOException("Unexpected frame");
- }
- } else {
- int streamId = w1 & 0x7fffffff;
- handler.data(flags, streamId, in, length);
- return true;
- }
- }
-
- private void readSynStream(Handler handler, int flags, int length) throws IOException {
- int w1 = in.readInt();
- int w2 = in.readInt();
- int s3 = in.readShort();
- int streamId = w1 & 0x7fffffff;
- int associatedStreamId = w2 & 0x7fffffff;
- int priority = (s3 & 0xe000) >>> 13;
- int slot = s3 & 0xff;
- List<String> nameValueBlock = readNameValueBlock(length - 10);
- handler.synStream(flags, 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<String> nameValueBlock = readNameValueBlock(length - 4);
- handler.synReply(flags, streamId, nameValueBlock);
- }
-
- private void readRstStream(Handler handler, int flags, int length) throws IOException {
- if (length != 8) throw ioException("TYPE_RST_STREAM length: %d != 8", length);
- int streamId = in.readInt() & 0x7fffffff;
- int statusCode = in.readInt();
- handler.rstStream(flags, streamId, statusCode);
- }
-
- private void readHeaders(Handler handler, int flags, int length) throws IOException {
- int w1 = in.readInt();
- int streamId = w1 & 0x7fffffff;
- List<String> nameValueBlock = readNameValueBlock(length - 4);
- handler.headers(flags, streamId, nameValueBlock);
- }
-
- private void readWindowUpdate(Handler handler, int flags, int length) throws IOException {
- if (length != 8) throw ioException("TYPE_WINDOW_UPDATE length: %d != 8", length);
- int w1 = in.readInt();
- int w2 = in.readInt();
- int streamId = w1 & 0x7fffffff;
- int deltaWindowSize = w2 & 0x7fffffff;
- handler.windowUpdate(flags, streamId, deltaWindowSize);
- }
-
- private DataInputStream newNameValueBlockStream() {
- // Limit the inflater input stream to only those bytes in the Name/Value block.
- final InputStream throttleStream = new InputStream() {
- @Override public int read() throws IOException {
- return Util.readSingleByte(this);
- }
-
- @Override public int read(byte[] buffer, int offset, int byteCount) throws IOException {
- byteCount = Math.min(byteCount, compressedLimit);
- int consumed = in.read(buffer, offset, byteCount);
- compressedLimit -= consumed;
- return consumed;
- }
-
- @Override public void close() throws IOException {
- in.close();
- }
- };
-
- // Subclass inflater to install a dictionary when it's needed.
- Inflater inflater = new Inflater() {
- @Override
- public int inflate(byte[] buffer, int offset, int count) throws DataFormatException {
- int result = super.inflate(buffer, offset, count);
- if (result == 0 && needsDictionary()) {
- setDictionary(DICTIONARY);
- result = super.inflate(buffer, offset, count);
- }
- return result;
- }
- };
-
- return new DataInputStream(new InflaterInputStream(throttleStream, inflater));
- }
-
- private List<String> readNameValueBlock(int length) throws IOException {
- this.compressedLimit += length;
- try {
- int numberOfPairs = nameValueBlockIn.readInt();
- if (numberOfPairs < 0) {
- Logger.getLogger(getClass().getName()).warning("numberOfPairs < 0: " + numberOfPairs);
- throw ioException("numberOfPairs < 0");
- }
- List<String> entries = new ArrayList<String>(numberOfPairs * 2);
- for (int i = 0; i < numberOfPairs; i++) {
- String name = readString();
- String values = readString();
- if (name.length() == 0) throw ioException("name.length == 0");
- if (values.length() == 0) throw ioException("values.length == 0");
- entries.add(name);
- entries.add(values);
- }
-
- if (compressedLimit != 0) {
- Logger.getLogger(getClass().getName()).warning("compressedLimit > 0: " + compressedLimit);
- }
-
- return entries;
- } catch (DataFormatException e) {
- throw new IOException(e.getMessage());
- }
- }
-
- private String readString() throws DataFormatException, IOException {
- int length = nameValueBlockIn.readInt();
- byte[] bytes = new byte[length];
- Util.readFully(nameValueBlockIn, bytes);
- return new String(bytes, 0, length, "UTF-8");
- }
-
- private void readPing(Handler handler, int flags, int length) throws IOException {
- if (length != 4) throw ioException("TYPE_PING length: %d != 4", length);
- int id = in.readInt();
- handler.ping(flags, id);
- }
-
- private void readGoAway(Handler handler, int flags, int length) throws IOException {
- if (length != 8) throw ioException("TYPE_GOAWAY length: %d != 8", length);
- int lastGoodStreamId = in.readInt() & 0x7fffffff;
- int statusCode = in.readInt();
- handler.goAway(flags, lastGoodStreamId, statusCode);
- }
-
- private void readSettings(Handler handler, int flags, int length) throws IOException {
- int numberOfEntries = in.readInt();
- if (length != 4 + 8 * numberOfEntries) {
- throw ioException("TYPE_SETTINGS length: %d != 4 + 8 * %d", length, numberOfEntries);
- }
- Settings settings = new Settings();
- for (int i = 0; i < numberOfEntries; i++) {
- int w1 = in.readInt();
- int value = in.readInt();
- int idFlags = (w1 & 0xff000000) >>> 24;
- int id = w1 & 0xffffff;
- settings.set(id, idFlags, value);
- }
- handler.settings(flags, settings);
- }
-
- private static IOException ioException(String message, Object... args) throws IOException {
- throw new IOException(String.format(message, args));
- }
-
- @Override public void close() throws IOException {
- Util.closeAll(in, nameValueBlockIn);
- }
-
- 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<String> nameValueBlock);
-
- void synReply(int flags, int streamId, List<String> nameValueBlock) throws IOException;
- void headers(int flags, int streamId, List<String> nameValueBlock) throws IOException;
- void rstStream(int flags, int streamId, int statusCode);
- void settings(int flags, Settings settings);
- void noop();
- void ping(int flags, int streamId);
- void goAway(int flags, int lastGoodStreamId, int statusCode);
- void windowUpdate(int flags, int streamId, int deltaWindowSize);
- }
-}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/166d26a3/framework/src/com/squareup/okhttp/internal/spdy/SpdyStream.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/SpdyStream.java b/framework/src/com/squareup/okhttp/internal/spdy/SpdyStream.java
old mode 100644
new mode 100755
index 744a04e..a3ab3a4
--- a/framework/src/com/squareup/okhttp/internal/spdy/SpdyStream.java
+++ b/framework/src/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,35 +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",
- "INVALID_STREAM",
- "REFUSED_STREAM",
- "UNSUPPORTED_VERSION",
- "CANCEL",
- "INTERNAL_ERROR",
- "FLOW_CONTROL_ERROR",
- "STREAM_IN_USE",
- "STREAM_ALREADY_CLOSED",
- "INVALID_CREDENTIALS",
- "FRAME_TOO_LARGE"
- };
-
- public static final int RST_PROTOCOL_ERROR = 1;
- public static final int RST_INVALID_STREAM = 2;
- public static final int RST_REFUSED_STREAM = 3;
- public static final int RST_UNSUPPORTED_VERSION = 4;
- public static final int RST_CANCEL = 5;
- public static final int RST_INTERNAL_ERROR = 6;
- public static final int RST_FLOW_CONTROL_ERROR = 7;
- public static final int RST_STREAM_IN_USE = 8;
- public static final int RST_STREAM_ALREADY_CLOSED = 9;
- public static final int RST_INVALID_CREDENTIALS = 10;
- public static final int RST_FRAME_TOO_LARGE = 11;
-
/**
* The number of unacknowledged bytes at which the input stream will send
* the peer a {@code WINDOW_UPDATE} frame. Must be less than this client's
@@ -75,7 +44,6 @@ public final class SpdyStream {
private final int id;
private final SpdyConnection connection;
private final int priority;
- private final int slot;
private long readTimeoutMillis = 0;
private int writeWindowSize;
@@ -93,28 +61,19 @@ public final class SpdyStream {
* reasons to abnormally close this stream (such as both peers closing it
* near-simultaneously) then this is the first reason known to this peer.
*/
- private int rstStatusCode = -1;
+ private ErrorCode errorCode = null;
- SpdyStream(int id, SpdyConnection connection, int flags, int priority, int slot,
- List<String> requestHeaders, Settings settings) {
+ SpdyStream(int id, SpdyConnection connection, boolean outFinished, boolean inFinished,
+ int priority, List<String> 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);
}
@@ -129,7 +88,7 @@ public final class SpdyStream {
* reports itself as not open. This is because input data is buffered.
*/
public synchronized boolean isOpen() {
- if (rstStatusCode != -1) {
+ if (errorCode != null) {
return false;
}
if ((in.finished || in.closed) && (out.finished || out.closed) && responseHeaders != null) {
@@ -157,14 +116,28 @@ public final class SpdyStream {
* have not been received yet.
*/
public synchronized List<String> getResponseHeaders() throws IOException {
+ long remaining = 0;
+ long start = 0;
+ if (readTimeoutMillis != 0) {
+ start = (System.nanoTime() / 1000000);
+ remaining = readTimeoutMillis;
+ }
try {
- while (responseHeaders == null && rstStatusCode == -1) {
- wait();
+ while (responseHeaders == null && errorCode == null) {
+ if (readTimeoutMillis == 0) { // No timeout configured.
+ wait();
+ } else if (remaining > 0) {
+ wait(remaining);
+ remaining = start + readTimeoutMillis - (System.nanoTime() / 1000000);
+ } else {
+ throw new SocketTimeoutException("Read response header timeout. readTimeoutMillis: "
+ + readTimeoutMillis);
+ }
}
if (responseHeaders != null) {
return responseHeaders;
}
- throw new IOException("stream was reset: " + rstStatusString());
+ throw new IOException("stream was reset: " + errorCode);
} catch (InterruptedException e) {
InterruptedIOException rethrow = new InterruptedIOException();
rethrow.initCause(e);
@@ -173,15 +146,11 @@ public final class SpdyStream {
}
/**
- * Returns the reason why this stream was closed, or -1 if it closed
- * normally or has not yet been closed. Valid reasons are {@link
- * #RST_PROTOCOL_ERROR}, {@link #RST_INVALID_STREAM}, {@link
- * #RST_REFUSED_STREAM}, {@link #RST_UNSUPPORTED_VERSION}, {@link
- * #RST_CANCEL}, {@link #RST_INTERNAL_ERROR} and {@link
- * #RST_FLOW_CONTROL_ERROR}.
+ * Returns the reason why this stream was closed, or null if it closed
+ * normally or has not yet been closed.
*/
- public synchronized int getRstStatusCode() {
- return rstStatusCode;
+ public synchronized ErrorCode getErrorCode() {
+ return errorCode;
}
/**
@@ -192,7 +161,7 @@ public final class SpdyStream {
*/
public void reply(List<String> 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 +175,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);
}
/**
@@ -248,7 +217,7 @@ public final class SpdyStream {
* Abnormally terminate this stream. This blocks until the {@code RST_STREAM}
* frame has been transmitted.
*/
- public void close(int rstStatusCode) throws IOException {
+ public void close(ErrorCode rstStatusCode) throws IOException {
if (!closeInternal(rstStatusCode)) {
return; // Already closed.
}
@@ -259,68 +228,61 @@ public final class SpdyStream {
* Abnormally terminate this stream. This enqueues a {@code RST_STREAM}
* frame and returns immediately.
*/
- public void closeLater(int rstStatusCode) {
- if (!closeInternal(rstStatusCode)) {
+ public void closeLater(ErrorCode errorCode) {
+ if (!closeInternal(errorCode)) {
return; // Already closed.
}
- connection.writeSynResetLater(id, rstStatusCode);
+ connection.writeSynResetLater(id, errorCode);
}
/** Returns true if this stream was closed. */
- private boolean closeInternal(int rstStatusCode) {
+ private boolean closeInternal(ErrorCode errorCode) {
assert (!Thread.holdsLock(this));
synchronized (this) {
- if (this.rstStatusCode != -1) {
+ if (this.errorCode != null) {
return false;
}
if (in.finished && out.finished) {
return false;
}
- this.rstStatusCode = rstStatusCode;
+ this.errorCode = errorCode;
notifyAll();
}
connection.removeStream(id);
return true;
}
- void receiveReply(List<String> strings) throws IOException {
+ void receiveHeaders(List<String> headers, HeadersMode headersMode) {
assert (!Thread.holdsLock(SpdyStream.this));
- boolean streamInUseError = false;
+ ErrorCode errorCode = null;
boolean open = true;
synchronized (this) {
- if (isLocallyInitiated() && responseHeaders == null) {
- responseHeaders = strings;
- open = isOpen();
- notifyAll();
+ if (responseHeaders == null) {
+ if (headersMode.failIfHeadersAbsent()) {
+ errorCode = ErrorCode.PROTOCOL_ERROR;
+ } else {
+ responseHeaders = headers;
+ open = isOpen();
+ notifyAll();
+ }
} else {
- streamInUseError = true;
+ if (headersMode.failIfHeadersPresent()) {
+ errorCode = ErrorCode.STREAM_IN_USE;
+ } else {
+ List<String> newHeaders = new ArrayList<String>();
+ newHeaders.addAll(responseHeaders);
+ newHeaders.addAll(headers);
+ this.responseHeaders = newHeaders;
+ }
}
}
- if (streamInUseError) {
- closeLater(SpdyStream.RST_STREAM_IN_USE);
+ if (errorCode != null) {
+ closeLater(errorCode);
} else if (!open) {
connection.removeStream(id);
}
}
- void receiveHeaders(List<String> headers) throws IOException {
- assert (!Thread.holdsLock(SpdyStream.this));
- boolean protocolError = false;
- synchronized (this) {
- if (responseHeaders != null) {
- List<String> newHeaders = new ArrayList<String>();
- newHeaders.addAll(responseHeaders);
- newHeaders.addAll(headers);
- this.responseHeaders = newHeaders;
- } else {
- protocolError = true;
- }
- }
- if (protocolError) {
- closeLater(SpdyStream.RST_PROTOCOL_ERROR);
- }
- }
-
void receiveData(InputStream in, int length) throws IOException {
assert (!Thread.holdsLock(SpdyStream.this));
this.in.receive(in, length);
@@ -339,18 +301,20 @@ public final class SpdyStream {
}
}
- synchronized void receiveRstStream(int statusCode) {
- if (rstStatusCode == -1) {
- rstStatusCode = statusCode;
+ synchronized void receiveRstStream(ErrorCode errorCode) {
+ if (this.errorCode == null) {
+ this.errorCode = errorCode;
notifyAll();
}
}
private void setSettings(Settings settings) {
+ // TODO: For HTTP/2.0, also adjust the stream flow control window size
+ // by the difference between the new value and the old value.
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) {
@@ -364,19 +328,10 @@ public final class SpdyStream {
notifyAll();
}
- private String rstStatusString() {
- return rstStatusCode > 0 && rstStatusCode < STATUS_CODE_NAMES.length
- ? STATUS_CODE_NAMES[rstStatusCode] : Integer.toString(rstStatusCode);
- }
-
int getPriority() {
return priority;
}
- int getSlot() {
- return slot;
- }
-
/**
* An input stream that reads the incoming data frames of a stream. Although
* this class uses synchronization to safely receive incoming data frames,
@@ -496,7 +451,7 @@ public final class SpdyStream {
remaining = readTimeoutMillis;
}
try {
- while (pos == -1 && !finished && !closed && rstStatusCode == -1) {
+ while (pos == -1 && !finished && !closed && errorCode == null) {
if (readTimeoutMillis == 0) {
SpdyStream.this.wait();
} else if (remaining > 0) {
@@ -534,7 +489,7 @@ public final class SpdyStream {
// If the peer sends more data than we can handle, discard it and close the connection.
if (flowControlError) {
Util.skipByReading(in, byteCount);
- closeLater(SpdyStream.RST_FLOW_CONTROL_ERROR);
+ closeLater(ErrorCode.FLOW_CONTROL_ERROR);
return;
}
@@ -583,8 +538,8 @@ public final class SpdyStream {
if (closed) {
throw new IOException("stream closed");
}
- if (rstStatusCode != -1) {
- throw new IOException("stream was reset: " + rstStatusString());
+ if (errorCode != null) {
+ throw new IOException("stream was reset: " + errorCode);
}
}
}
@@ -602,7 +557,7 @@ public final class SpdyStream {
// is safe because the input stream is closed (we won't use any
// further bytes) and the output stream is either finished or closed
// (so RSTing both streams doesn't cause harm).
- SpdyStream.this.close(RST_CANCEL);
+ SpdyStream.this.close(ErrorCode.CANCEL);
} else if (!open) {
connection.removeStream(id);
}
@@ -614,7 +569,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 +611,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();
}
@@ -670,27 +625,23 @@ public final class SpdyStream {
}
closed = true;
}
- writeFrame(true);
+ if (!out.finished) {
+ writeFrame(true);
+ }
connection.flush();
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;
}
/**
@@ -709,8 +660,8 @@ public final class SpdyStream {
throw new IOException("stream closed");
} else if (finished) {
throw new IOException("stream finished");
- } else if (rstStatusCode != -1) {
- throw new IOException("stream was reset: " + rstStatusString());
+ } else if (errorCode != null) {
+ throw new IOException("stream was reset: " + errorCode);
}
}
} catch (InterruptedException e) {
@@ -724,8 +675,8 @@ public final class SpdyStream {
throw new IOException("stream closed");
} else if (finished) {
throw new IOException("stream finished");
- } else if (rstStatusCode != -1) {
- throw new IOException("stream was reset: " + rstStatusString());
+ } else if (errorCode != null) {
+ throw new IOException("stream was reset: " + errorCode);
}
}
}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/166d26a3/framework/src/com/squareup/okhttp/internal/spdy/SpdyWriter.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/SpdyWriter.java b/framework/src/com/squareup/okhttp/internal/spdy/SpdyWriter.java
deleted file mode 100644
index b3d1d1f..0000000
--- a/framework/src/com/squareup/okhttp/internal/spdy/SpdyWriter.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.squareup.okhttp.internal.spdy;
-
-import com.squareup.okhttp.internal.Platform;
-import com.squareup.okhttp.internal.Util;
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.zip.Deflater;
-
-/** Write spdy/3 frames. */
-final class SpdyWriter implements Closeable {
- final DataOutputStream out;
- private final ByteArrayOutputStream nameValueBlockBuffer;
- private final DataOutputStream nameValueBlockOut;
-
- SpdyWriter(OutputStream out) {
- this.out = new DataOutputStream(out);
-
- Deflater deflater = new Deflater();
- deflater.setDictionary(SpdyReader.DICTIONARY);
- nameValueBlockBuffer = new ByteArrayOutputStream();
- nameValueBlockOut = new DataOutputStream(
- Platform.get().newDeflaterOutputStream(nameValueBlockBuffer, deflater, true));
- }
-
- public synchronized void synStream(int flags, int streamId, int associatedStreamId, int priority,
- int slot, List<String> nameValueBlock) throws IOException {
- writeNameValueBlockToBuffer(nameValueBlock);
- int length = 10 + nameValueBlockBuffer.size();
- int type = SpdyConnection.TYPE_SYN_STREAM;
-
- int unused = 0;
- out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.writeInt(streamId & 0x7fffffff);
- out.writeInt(associatedStreamId & 0x7fffffff);
- out.writeShort((priority & 0x7) << 13 | (unused & 0x1f) << 8 | (slot & 0xff));
- nameValueBlockBuffer.writeTo(out);
- out.flush();
- }
-
- public synchronized void synReply(int flags, int streamId, List<String> nameValueBlock)
- throws IOException {
- writeNameValueBlockToBuffer(nameValueBlock);
- int type = SpdyConnection.TYPE_SYN_REPLY;
- int length = nameValueBlockBuffer.size() + 4;
-
- out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.writeInt(streamId & 0x7fffffff);
- nameValueBlockBuffer.writeTo(out);
- out.flush();
- }
-
- public synchronized void headers(int flags, int streamId, List<String> nameValueBlock)
- throws IOException {
- writeNameValueBlockToBuffer(nameValueBlock);
- int type = SpdyConnection.TYPE_HEADERS;
- int length = nameValueBlockBuffer.size() + 4;
-
- out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.writeInt(streamId & 0x7fffffff);
- nameValueBlockBuffer.writeTo(out);
- out.flush();
- }
-
- public synchronized void rstStream(int streamId, int statusCode) throws IOException {
- int flags = 0;
- int type = SpdyConnection.TYPE_RST_STREAM;
- int length = 8;
- out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.writeInt(streamId & 0x7fffffff);
- out.writeInt(statusCode);
- out.flush();
- }
-
- public synchronized void data(int flags, int streamId, byte[] data) throws IOException {
- int length = data.length;
- out.writeInt(streamId & 0x7fffffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.write(data);
- out.flush();
- }
-
- private void writeNameValueBlockToBuffer(List<String> nameValueBlock) throws IOException {
- nameValueBlockBuffer.reset();
- int numberOfPairs = nameValueBlock.size() / 2;
- nameValueBlockOut.writeInt(numberOfPairs);
- for (String s : nameValueBlock) {
- nameValueBlockOut.writeInt(s.length());
- nameValueBlockOut.write(s.getBytes("UTF-8"));
- }
- nameValueBlockOut.flush();
- }
-
- public synchronized void settings(int flags, Settings settings) throws IOException {
- int type = SpdyConnection.TYPE_SETTINGS;
- int size = settings.size();
- int length = 4 + size * 8;
- out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.writeInt(size);
- for (int i = 0; i <= Settings.COUNT; i++) {
- if (!settings.isSet(i)) continue;
- int settingsFlags = settings.flags(i);
- out.writeInt((settingsFlags & 0xff) << 24 | (i & 0xffffff));
- out.writeInt(settings.get(i));
- }
- out.flush();
- }
-
- public synchronized void noop() throws IOException {
- int type = SpdyConnection.TYPE_NOOP;
- int length = 0;
- int flags = 0;
- out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.flush();
- }
-
- public synchronized void ping(int flags, int id) throws IOException {
- int type = SpdyConnection.TYPE_PING;
- int length = 4;
- out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.writeInt(id);
- out.flush();
- }
-
- public synchronized void goAway(int flags, int lastGoodStreamId, int statusCode)
- throws IOException {
- int type = SpdyConnection.TYPE_GOAWAY;
- int length = 8;
- out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.writeInt(lastGoodStreamId);
- out.writeInt(statusCode);
- out.flush();
- }
-
- public synchronized void windowUpdate(int streamId, int deltaWindowSize) throws IOException {
- int type = SpdyConnection.TYPE_WINDOW_UPDATE;
- int flags = 0;
- int length = 8;
- out.writeInt(0x80000000 | (SpdyConnection.VERSION & 0x7fff) << 16 | type & 0xffff);
- out.writeInt((flags & 0xff) << 24 | length & 0xffffff);
- out.writeInt(streamId);
- out.writeInt(deltaWindowSize);
- out.flush();
- }
-
- @Override public void close() throws IOException {
- Util.closeAll(out, nameValueBlockOut);
- }
-}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/166d26a3/framework/src/com/squareup/okhttp/internal/spdy/Variant.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/Variant.java b/framework/src/com/squareup/okhttp/internal/spdy/Variant.java
new file mode 100755
index 0000000..8f48bcd
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/spdy/Variant.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.squareup.okhttp.internal.spdy;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/** A version and dialect of the framed socket protocol. */
+interface Variant {
+ Variant SPDY3 = new Spdy3();
+ Variant HTTP_20_DRAFT_06 = new Http20Draft06();
+
+ /**
+ * @param client true if this is the HTTP client's reader, reading frames from
+ * a peer SPDY or HTTP/2 server.
+ */
+ FrameReader newReader(InputStream in, boolean client);
+
+ /**
+ * @param client true if this is the HTTP client's writer, writing frames to a
+ * peer SPDY or HTTP/2 server.
+ */
+ FrameWriter newWriter(OutputStream out, boolean client);
+}