You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2014/01/15 17:37:02 UTC

[2/5] CB-5799 Update version of OkHTTP to 1.3

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/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-android/blob/e16cab6b/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-android/blob/e16cab6b/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-android/blob/e16cab6b/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-android/blob/e16cab6b/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-android/blob/e16cab6b/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-android/blob/e16cab6b/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);
+}