cordova-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From agri...@apache.org
Subject [5/5] android commit: CB-5799 Update version of OkHTTP to 1.3
Date Wed, 15 Jan 2014 16:37:05 GMT
CB-5799 Update version of OkHTTP to 1.3


Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/e16cab6b
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/e16cab6b
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/e16cab6b

Branch: refs/heads/master
Commit: e16cab6b9c685590fe58357ab66d7f6af55eb7be
Parents: a643c3d
Author: Andrew Grieve <agrieve@chromium.org>
Authored: Wed Jan 15 11:36:18 2014 -0500
Committer: Andrew Grieve <agrieve@chromium.org>
Committed: Wed Jan 15 11:36:43 2014 -0500

----------------------------------------------------------------------
 framework/src/com/squareup/okhttp/Address.java  |  33 +-
 .../src/com/squareup/okhttp/Connection.java     |  78 ++-
 .../src/com/squareup/okhttp/ConnectionPool.java |   9 +-
 .../src/com/squareup/okhttp/Dispatcher.java     |  86 +++
 framework/src/com/squareup/okhttp/Failure.java  |  59 ++
 .../com/squareup/okhttp/HttpResponseCache.java  | 119 ++--
 framework/src/com/squareup/okhttp/Job.java      | 232 +++++++
 .../src/com/squareup/okhttp/MediaType.java      | 120 ++++
 .../com/squareup/okhttp/OkAuthenticator.java    | 123 ++++
 .../src/com/squareup/okhttp/OkHttpClient.java   | 228 ++++++-
 .../com/squareup/okhttp/OkResponseCache.java    |  36 +-
 framework/src/com/squareup/okhttp/Request.java  | 284 +++++++++
 framework/src/com/squareup/okhttp/Response.java | 290 +++++++++
 .../src/com/squareup/okhttp/ResponseSource.java |   0
 framework/src/com/squareup/okhttp/Route.java    |   6 +-
 .../src/com/squareup/okhttp/RouteDatabase.java  |  57 ++
 .../src/com/squareup/okhttp/TunnelRequest.java  |   0
 .../okhttp/internal/AbstractOutputStream.java   |   0
 .../com/squareup/okhttp/internal/Base64.java    |   0
 .../squareup/okhttp/internal/DiskLruCache.java  |   0
 .../src/com/squareup/okhttp/internal/Dns.java   |   0
 .../internal/FaultRecoveringOutputStream.java   |   0
 .../squareup/okhttp/internal/NamedRunnable.java |   6 +-
 .../com/squareup/okhttp/internal/Platform.java  | 117 ++--
 .../okhttp/internal/StrictLineReader.java       |   3 +-
 .../src/com/squareup/okhttp/internal/Util.java  |  67 ++
 .../internal/http/AbstractHttpInputStream.java  |   4 +-
 .../internal/http/AbstractHttpOutputStream.java |  40 --
 .../okhttp/internal/http/HeaderParser.java      |   8 +-
 .../okhttp/internal/http/HttpAuthenticator.java | 153 +++--
 .../squareup/okhttp/internal/http/HttpDate.java |  30 +-
 .../okhttp/internal/http/HttpEngine.java        | 108 ++--
 .../okhttp/internal/http/HttpResponseCache.java | 608 -------------------
 .../okhttp/internal/http/HttpTransport.java     |  48 +-
 .../internal/http/HttpURLConnectionImpl.java    | 226 ++++---
 .../okhttp/internal/http/HttpsEngine.java       |  72 +++
 .../internal/http/HttpsURLConnectionImpl.java   | 231 +++----
 .../okhttp/internal/http/OkResponseCache.java   |  55 --
 .../internal/http/OkResponseCacheAdapter.java   |   4 +
 .../squareup/okhttp/internal/http/Policy.java   |  49 ++
 .../okhttp/internal/http/RawHeaders.java        |  73 ++-
 .../okhttp/internal/http/RequestHeaders.java    |  39 +-
 .../okhttp/internal/http/ResponseHeaders.java   |  27 +-
 .../internal/http/RetryableOutputStream.java    |   0
 .../okhttp/internal/http/RouteSelector.java     |  28 +-
 .../okhttp/internal/http/SpdyTransport.java     |  21 +-
 .../okhttp/internal/http/Transport.java         |   2 +-
 .../http/UnknownLengthHttpInputStream.java      |   6 +-
 .../okhttp/internal/spdy/ErrorCode.java         |  67 ++
 .../okhttp/internal/spdy/FrameReader.java       |  55 ++
 .../okhttp/internal/spdy/FrameWriter.java       |  43 ++
 .../okhttp/internal/spdy/HeadersMode.java       |  49 ++
 .../squareup/okhttp/internal/spdy/Hpack.java    | 371 +++++++++++
 .../okhttp/internal/spdy/Http20Draft06.java     | 385 ++++++++++++
 .../internal/spdy/IncomingStreamHandler.java    |   2 +-
 .../internal/spdy/NameValueBlockReader.java     | 123 ++++
 .../com/squareup/okhttp/internal/spdy/Ping.java |   0
 .../squareup/okhttp/internal/spdy/Settings.java |  31 +-
 .../squareup/okhttp/internal/spdy/Spdy3.java    | 463 ++++++++++++++
 .../okhttp/internal/spdy/SpdyConnection.java    | 348 ++++++-----
 .../okhttp/internal/spdy/SpdyReader.java        | 326 ----------
 .../okhttp/internal/spdy/SpdyStream.java        | 217 +++----
 .../okhttp/internal/spdy/SpdyWriter.java        | 176 ------
 .../squareup/okhttp/internal/spdy/Variant.java  |  37 ++
 .../internal/tls/DistinguishedNameParser.java   | 407 +++++++++++++
 .../okhttp/internal/tls/OkHostnameVerifier.java | 194 ++++++
 66 files changed, 4912 insertions(+), 2167 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/Address.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/Address.java b/framework/src/com/squareup/okhttp/Address.java
old mode 100644
new mode 100755
index cd41ac9..b34bd91
--- a/framework/src/com/squareup/okhttp/Address.java
+++ b/framework/src/com/squareup/okhttp/Address.java
@@ -15,8 +15,10 @@
  */
 package com.squareup.okhttp;
 
+import com.squareup.okhttp.internal.Util;
 import java.net.Proxy;
 import java.net.UnknownHostException;
+import java.util.List;
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLSocketFactory;
 
@@ -38,16 +40,23 @@ public final class Address {
   final int uriPort;
   final SSLSocketFactory sslSocketFactory;
   final HostnameVerifier hostnameVerifier;
+  final OkAuthenticator authenticator;
+  final List<String> transports;
 
   public Address(String uriHost, int uriPort, SSLSocketFactory sslSocketFactory,
-      HostnameVerifier hostnameVerifier, Proxy proxy) throws UnknownHostException {
+      HostnameVerifier hostnameVerifier, OkAuthenticator authenticator, Proxy proxy,
+      List<String> transports) throws UnknownHostException {
     if (uriHost == null) throw new NullPointerException("uriHost == null");
     if (uriPort <= 0) throw new IllegalArgumentException("uriPort <= 0: " + uriPort);
+    if (authenticator == null) throw new IllegalArgumentException("authenticator == null");
+    if (transports == null) throw new IllegalArgumentException("transports == null");
     this.proxy = proxy;
     this.uriHost = uriHost;
     this.uriPort = uriPort;
     this.sslSocketFactory = sslSocketFactory;
     this.hostnameVerifier = hostnameVerifier;
+    this.authenticator = authenticator;
+    this.transports = Util.immutableList(transports);
   }
 
   /** Returns the hostname of the origin server. */
@@ -79,6 +88,22 @@ public final class Address {
     return hostnameVerifier;
   }
 
+
+  /**
+   * Returns the client's authenticator. This method never returns null.
+   */
+  public OkAuthenticator getAuthenticator() {
+    return authenticator;
+  }
+
+  /**
+   * Returns the client's transports. This method always returns a non-null list
+   * that contains "http/1.1", possibly among other transports.
+   */
+  public List<String> getTransports() {
+    return transports;
+  }
+
   /**
    * Returns this address's explicitly-specified HTTP proxy, or null to
    * delegate to the HTTP client's proxy selector.
@@ -94,7 +119,9 @@ public final class Address {
           && this.uriHost.equals(that.uriHost)
           && this.uriPort == that.uriPort
           && equal(this.sslSocketFactory, that.sslSocketFactory)
-          && equal(this.hostnameVerifier, that.hostnameVerifier);
+          && equal(this.hostnameVerifier, that.hostnameVerifier)
+          && equal(this.authenticator, that.authenticator)
+          && equal(this.transports, that.transports);
     }
     return false;
   }
@@ -105,7 +132,9 @@ public final class Address {
     result = 31 * result + uriPort;
     result = 31 * result + (sslSocketFactory != null ? sslSocketFactory.hashCode() : 0);
     result = 31 * result + (hostnameVerifier != null ? hostnameVerifier.hashCode() : 0);
+    result = 31 * result + (authenticator != null ? authenticator.hashCode() : 0);
     result = 31 * result + (proxy != null ? proxy.hashCode() : 0);
+    result = 31 * result + transports.hashCode();
     return result;
   }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/Connection.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/Connection.java b/framework/src/com/squareup/okhttp/Connection.java
old mode 100644
new mode 100755
index 6a6c84d..6bb9cb3
--- a/framework/src/com/squareup/okhttp/Connection.java
+++ b/framework/src/com/squareup/okhttp/Connection.java
@@ -31,6 +31,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.Proxy;
 import java.net.Socket;
+import java.net.SocketTimeoutException;
 import java.net.URL;
 import java.util.Arrays;
 import javax.net.ssl.SSLSocket;
@@ -92,24 +93,20 @@ public final class Connection implements Closeable {
 
   public void connect(int connectTimeout, int readTimeout, TunnelRequest tunnelRequest)
       throws IOException {
-    if (connected) {
-      throw new IllegalStateException("already connected");
-    }
-    connected = true;
+    if (connected) throw new IllegalStateException("already connected");
+
     socket = (route.proxy.type() != Proxy.Type.HTTP) ? new Socket(route.proxy) : new Socket();
-    socket.connect(route.inetSocketAddress, connectTimeout);
+    Platform.get().connectSocket(socket, route.inetSocketAddress, connectTimeout);
     socket.setSoTimeout(readTimeout);
     in = socket.getInputStream();
     out = socket.getOutputStream();
 
     if (route.address.sslSocketFactory != null) {
       upgradeToTls(tunnelRequest);
+    } else {
+      streamWrapper();
     }
-
-    // Use MTU-sized buffers to send fewer packets.
-    int mtu = Platform.get().getMtu(socket);
-    in = new BufferedInputStream(in, mtu);
-    out = new BufferedOutputStream(out, mtu);
+    connected = true;
   }
 
   /**
@@ -134,7 +131,8 @@ public final class Connection implements Closeable {
       platform.supportTlsIntolerantServer(sslSocket);
     }
 
-    if (route.modernTls) {
+    boolean useNpn = route.modernTls && route.address.transports.contains("spdy/3");
+    if (useNpn) {
       platform.setNpnProtocols(sslSocket, NPN_PROTOCOLS);
     }
 
@@ -148,14 +146,15 @@ public final class Connection implements Closeable {
 
     out = sslSocket.getOutputStream();
     in = sslSocket.getInputStream();
+    streamWrapper();
 
     byte[] selectedProtocol;
-    if (route.modernTls
-        && (selectedProtocol = platform.getNpnSelectedProtocol(sslSocket)) != null) {
+    if (useNpn && (selectedProtocol = platform.getNpnSelectedProtocol(sslSocket)) != null) {
       if (Arrays.equals(selectedProtocol, SPDY3)) {
         sslSocket.setSoTimeout(0); // SPDY timeouts are set per-stream.
         spdyConnection = new SpdyConnection.Builder(route.address.getUriHost(), true, in, out)
             .build();
+        spdyConnection.sendConnectionHeader();
       } else if (!Arrays.equals(selectedProtocol, HTTP_11)) {
         throw new IOException(
             "Unexpected NPN transport " + new String(selectedProtocol, "ISO-8859-1"));
@@ -190,6 +189,39 @@ public final class Connection implements Closeable {
     return !socket.isClosed() && !socket.isInputShutdown() && !socket.isOutputShutdown();
   }
 
+  /**
+   * Returns true if we are confident that we can read data from this
+   * connection. This is more expensive and more accurate than {@link
+   * #isAlive()}; callers should check {@link #isAlive()} first.
+   */
+  public boolean isReadable() {
+    if (!(in instanceof BufferedInputStream)) {
+      return true; // Optimistic.
+    }
+    if (isSpdy()) {
+      return true; // Optimistic. We can't test SPDY because its streams are in use.
+    }
+    BufferedInputStream bufferedInputStream = (BufferedInputStream) in;
+    try {
+      int readTimeout = socket.getSoTimeout();
+      try {
+        socket.setSoTimeout(1);
+        bufferedInputStream.mark(1);
+        if (bufferedInputStream.read() == -1) {
+          return false; // Stream is exhausted; socket is closed.
+        }
+        bufferedInputStream.reset();
+        return true;
+      } finally {
+        socket.setSoTimeout(readTimeout);
+      }
+    } catch (SocketTimeoutException ignored) {
+      return true; // Read timed out; socket is good.
+    } catch (IOException e) {
+      return false; // Couldn't read; socket is closed.
+    }
+  }
+
   public void resetIdleStartTime() {
     if (spdyConnection != null) {
       throw new IllegalStateException("spdyConnection != null");
@@ -207,7 +239,7 @@ public final class Connection implements Closeable {
    * {@code keepAliveDurationNs}.
    */
   public boolean isExpired(long keepAliveDurationNs) {
-    return isIdle() && System.nanoTime() - getIdleStartTimeNs() > keepAliveDurationNs;
+    return getIdleStartTimeNs() < System.nanoTime() - keepAliveDurationNs;
   }
 
   /**
@@ -220,7 +252,8 @@ public final class Connection implements Closeable {
 
   /** Returns the transport appropriate for this connection. */
   public Object newTransport(HttpEngine httpEngine) throws IOException {
-    return (spdyConnection != null) ? new SpdyTransport(httpEngine, spdyConnection)
+    return (spdyConnection != null)
+        ? new SpdyTransport(httpEngine, spdyConnection)
         : new HttpTransport(httpEngine, out, in);
   }
 
@@ -258,6 +291,11 @@ public final class Connection implements Closeable {
     return route.address.sslSocketFactory != null && route.proxy.type() == Proxy.Type.HTTP;
   }
 
+  public void updateReadTimeout(int newTimeout) throws IOException {
+    if (!connected) throw new IllegalStateException("updateReadTimeout - not connected");
+    socket.setSoTimeout(newTimeout);
+  }
+
   /**
    * To make an HTTPS connection over an HTTP proxy, send an unencrypted
    * CONNECT request to create the proxy connection. This may need to be
@@ -275,8 +313,9 @@ public final class Connection implements Closeable {
         case HTTP_PROXY_AUTH:
           requestHeaders = new RawHeaders(requestHeaders);
           URL url = new URL("https", tunnelRequest.host, tunnelRequest.port, "/");
-          boolean credentialsFound = HttpAuthenticator.processAuthHeader(HTTP_PROXY_AUTH,
-              responseHeaders, requestHeaders, route.proxy, url);
+          boolean credentialsFound = HttpAuthenticator.processAuthHeader(
+              route.address.authenticator, HTTP_PROXY_AUTH, responseHeaders, requestHeaders,
+              route.proxy, url);
           if (credentialsFound) {
             continue;
           } else {
@@ -288,4 +327,9 @@ public final class Connection implements Closeable {
       }
     }
   }
+
+  private void streamWrapper() throws IOException {
+    in = new BufferedInputStream(in, 4096);
+    out = new BufferedOutputStream(out, 256);
+  }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/ConnectionPool.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/ConnectionPool.java b/framework/src/com/squareup/okhttp/ConnectionPool.java
old mode 100644
new mode 100755
index 933bd73..42b70b9
--- a/framework/src/com/squareup/okhttp/ConnectionPool.java
+++ b/framework/src/com/squareup/okhttp/ConnectionPool.java
@@ -80,8 +80,9 @@ public class ConnectionPool {
   private final LinkedList<Connection> connections = new LinkedList<Connection>();
 
   /** We use a single background thread to cleanup expired connections. */
-  private final ExecutorService executorService =
-      new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
+  private final ExecutorService executorService = new ThreadPoolExecutor(0, 1,
+      60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
+      Util.daemonThreadFactory("OkHttp ConnectionPool"));
   private final Callable<Void> connectionsCleanupCallable = new Callable<Void>() {
     @Override public Void call() throws Exception {
       List<Connection> expiredConnections = new ArrayList<Connection>(MAX_CONNECTIONS_TO_CLEANUP);
@@ -215,8 +216,6 @@ public class ConnectionPool {
    * <p>It is an error to use {@code connection} after calling this method.
    */
   public void recycle(Connection connection) {
-    executorService.submit(connectionsCleanupCallable);
-
     if (connection.isSpdy()) {
       return;
     }
@@ -239,6 +238,8 @@ public class ConnectionPool {
       connections.addFirst(connection);
       connection.resetIdleStartTime();
     }
+
+    executorService.submit(connectionsCleanupCallable);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/Dispatcher.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/Dispatcher.java b/framework/src/com/squareup/okhttp/Dispatcher.java
new file mode 100755
index 0000000..1982a8a
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/Dispatcher.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+import com.squareup.okhttp.internal.http.ResponseHeaders;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+final class Dispatcher {
+  // TODO: thread pool size should be configurable; possibly configurable per host.
+  private final ThreadPoolExecutor executorService = new ThreadPoolExecutor(
+      8, 8, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
+  private final Map<Object, List<Job>> enqueuedJobs = new LinkedHashMap<Object, List<Job>>();
+
+  public synchronized void enqueue(
+      OkHttpClient client, Request request, Response.Receiver responseReceiver) {
+    Job job = new Job(this, client, request, responseReceiver);
+    List<Job> jobsForTag = enqueuedJobs.get(request.tag());
+    if (jobsForTag == null) {
+      jobsForTag = new ArrayList<Job>(2);
+      enqueuedJobs.put(request.tag(), jobsForTag);
+    }
+    jobsForTag.add(job);
+    executorService.execute(job);
+  }
+
+  public synchronized void cancel(Object tag) {
+    List<Job> jobs = enqueuedJobs.remove(tag);
+    if (jobs == null) return;
+    for (Job job : jobs) {
+      executorService.remove(job);
+    }
+  }
+
+  synchronized void finished(Job job) {
+    List<Job> jobs = enqueuedJobs.get(job.tag());
+    if (jobs != null) jobs.remove(job);
+  }
+
+  static class RealResponseBody extends Response.Body {
+    private final ResponseHeaders responseHeaders;
+    private final InputStream in;
+
+    RealResponseBody(ResponseHeaders responseHeaders, InputStream in) {
+      this.responseHeaders = responseHeaders;
+      this.in = in;
+    }
+
+    @Override public boolean ready() throws IOException {
+      return true;
+    }
+
+    @Override public MediaType contentType() {
+      String contentType = responseHeaders.getContentType();
+      return contentType != null ? MediaType.parse(contentType) : null;
+    }
+
+    @Override public long contentLength() {
+      return responseHeaders.getContentLength();
+    }
+
+    @Override public InputStream byteStream() throws IOException {
+      return in;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/Failure.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/Failure.java b/framework/src/com/squareup/okhttp/Failure.java
new file mode 100755
index 0000000..a354700
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/Failure.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+/**
+ * A failure attempting to retrieve an HTTP response.
+ *
+ * <h3>Warning: Experimental OkHttp 2.0 API</h3>
+ * This class is in beta. APIs are subject to change!
+ */
+/* OkHttp 2.0: public */ class Failure {
+  private final Request request;
+  private final Throwable exception;
+
+  private Failure(Builder builder) {
+    this.request = builder.request;
+    this.exception = builder.exception;
+  }
+
+  public Request request() {
+    return request;
+  }
+
+  public Throwable exception() {
+    return exception;
+  }
+
+  public static class Builder {
+    private Request request;
+    private Throwable exception;
+
+    public Builder request(Request request) {
+      this.request = request;
+      return this;
+    }
+
+    public Builder exception(Throwable exception) {
+      this.exception = exception;
+      return this;
+    }
+
+    public Failure build() {
+      return new Failure(this);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/HttpResponseCache.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/HttpResponseCache.java b/framework/src/com/squareup/okhttp/HttpResponseCache.java
old mode 100644
new mode 100755
index a6d380a..8210318
--- a/framework/src/com/squareup/okhttp/HttpResponseCache.java
+++ b/framework/src/com/squareup/okhttp/HttpResponseCache.java
@@ -22,8 +22,8 @@ import com.squareup.okhttp.internal.StrictLineReader;
 import com.squareup.okhttp.internal.Util;
 import com.squareup.okhttp.internal.http.HttpEngine;
 import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
+import com.squareup.okhttp.internal.http.HttpsEngine;
 import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
-import com.squareup.okhttp.internal.http.OkResponseCache;
 import com.squareup.okhttp.internal.http.RawHeaders;
 import com.squareup.okhttp.internal.http.ResponseHeaders;
 import java.io.BufferedWriter;
@@ -35,7 +35,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
 import java.io.Writer;
 import java.net.CacheRequest;
 import java.net.CacheResponse;
@@ -44,8 +43,6 @@ import java.net.ResponseCache;
 import java.net.SecureCacheResponse;
 import java.net.URI;
 import java.net.URLConnection;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateEncodingException;
@@ -55,8 +52,8 @@ import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSocket;
 
 import static com.squareup.okhttp.internal.Util.US_ASCII;
 import static com.squareup.okhttp.internal.Util.UTF_8;
@@ -119,9 +116,6 @@ import static com.squareup.okhttp.internal.Util.UTF_8;
  * }</pre>
  */
 public final class HttpResponseCache extends ResponseCache {
-  private static final char[] DIGITS =
-      { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
   // TODO: add APIs to iterate the cache?
   private static final int VERSION = 201105;
   private static final int ENTRY_METADATA = 0;
@@ -153,6 +147,10 @@ public final class HttpResponseCache extends ResponseCache {
       return HttpResponseCache.this.put(uri, connection);
     }
 
+    @Override public void maybeRemove(String requestMethod, URI uri) throws IOException {
+      HttpResponseCache.this.maybeRemove(requestMethod, uri);
+    }
+
     @Override public void update(
         CacheResponse conditionalCacheHit, HttpURLConnection connection) throws IOException {
       HttpResponseCache.this.update(conditionalCacheHit, connection);
@@ -172,26 +170,7 @@ public final class HttpResponseCache extends ResponseCache {
   }
 
   private String uriToKey(URI uri) {
-    try {
-      MessageDigest messageDigest = MessageDigest.getInstance("MD5");
-      byte[] md5bytes = messageDigest.digest(uri.toString().getBytes("UTF-8"));
-      return bytesToHexString(md5bytes);
-    } catch (NoSuchAlgorithmException e) {
-      throw new AssertionError(e);
-    } catch (UnsupportedEncodingException e) {
-      throw new AssertionError(e);
-    }
-  }
-
-  private static String bytesToHexString(byte[] bytes) {
-    char[] digits = DIGITS;
-    char[] buf = new char[bytes.length * 2];
-    int c = 0;
-    for (byte b : bytes) {
-      buf[c++] = digits[(b >> 4) & 0xf];
-      buf[c++] = digits[b & 0xf];
-    }
-    return new String(buf);
+    return Util.hash(uri.toString());
   }
 
   @Override public CacheResponse get(URI uri, String requestMethod,
@@ -226,17 +205,11 @@ public final class HttpResponseCache extends ResponseCache {
 
     HttpURLConnection httpConnection = (HttpURLConnection) urlConnection;
     String requestMethod = httpConnection.getRequestMethod();
-    String key = uriToKey(uri);
 
-    if (requestMethod.equals("POST") || requestMethod.equals("PUT") || requestMethod.equals(
-        "DELETE")) {
-      try {
-        cache.remove(key);
-      } catch (IOException ignored) {
-        // The cache cannot be written.
-      }
+    if (maybeRemove(requestMethod, uri)) {
       return null;
-    } else if (!requestMethod.equals("GET")) {
+    }
+    if (!requestMethod.equals("GET")) {
       // Don't cache non-GET responses. We're technically allowed to cache
       // HEAD requests and some POST requests, but the complexity of doing
       // so is high and the benefit is low.
@@ -259,7 +232,7 @@ public final class HttpResponseCache extends ResponseCache {
     Entry entry = new Entry(uri, varyHeaders, httpConnection);
     DiskLruCache.Editor editor = null;
     try {
-      editor = cache.edit(key);
+      editor = cache.edit(uriToKey(uri));
       if (editor == null) {
         return null;
       }
@@ -271,6 +244,23 @@ public final class HttpResponseCache extends ResponseCache {
     }
   }
 
+  /**
+   * Returns true if the supplied {@code requestMethod} potentially invalidates an entry in the
+   * cache.
+   */
+  private boolean maybeRemove(String requestMethod, URI uri) {
+    if (requestMethod.equals("POST") || requestMethod.equals("PUT") || requestMethod.equals(
+        "DELETE")) {
+      try {
+        cache.remove(uriToKey(uri));
+      } catch (IOException ignored) {
+        // The cache cannot be written.
+      }
+      return true;
+    }
+    return false;
+  }
+
   private void update(CacheResponse conditionalCacheHit, HttpURLConnection httpConnection)
       throws IOException {
     HttpEngine httpEngine = getHttpEngine(httpConnection);
@@ -331,6 +321,30 @@ public final class HttpResponseCache extends ResponseCache {
     return writeSuccessCount;
   }
 
+  public long getSize() {
+    return cache.size();
+  }
+
+  public long getMaxSize() {
+    return cache.getMaxSize();
+  }
+
+  public void flush() throws IOException {
+    cache.flush();
+  }
+
+  public void close() throws IOException {
+    cache.close();
+  }
+
+  public File getDirectory() {
+    return cache.getDirectory();
+  }
+
+  public boolean isClosed() {
+    return cache.isClosed();
+  }
+
   private synchronized void trackResponse(ResponseSource source) {
     requestCount++;
 
@@ -383,8 +397,7 @@ public final class HttpResponseCache extends ResponseCache {
           editor.commit();
         }
 
-        @Override
-        public void write(byte[] buffer, int offset, int length) throws IOException {
+        @Override public void write(byte[] buffer, int offset, int length) throws IOException {
           // Since we don't override "write(int oneByte)", we can write directly to "out"
           // and avoid the inefficient implementation from the FilterOutputStream.
           out.write(buffer, offset, length);
@@ -513,16 +526,16 @@ public final class HttpResponseCache extends ResponseCache {
       this.requestMethod = httpConnection.getRequestMethod();
       this.responseHeaders = RawHeaders.fromMultimap(httpConnection.getHeaderFields(), true);
 
-      if (isHttps()) {
-        HttpsURLConnection httpsConnection = (HttpsURLConnection) httpConnection;
-        cipherSuite = httpsConnection.getCipherSuite();
+      SSLSocket sslSocket = getSslSocket(httpConnection);
+      if (sslSocket != null) {
+        cipherSuite = sslSocket.getSession().getCipherSuite();
         Certificate[] peerCertificatesNonFinal = null;
         try {
-          peerCertificatesNonFinal = httpsConnection.getServerCertificates();
+          peerCertificatesNonFinal = sslSocket.getSession().getPeerCertificates();
         } catch (SSLPeerUnverifiedException ignored) {
         }
         peerCertificates = peerCertificatesNonFinal;
-        localCertificates = httpsConnection.getLocalCertificates();
+        localCertificates = sslSocket.getSession().getLocalCertificates();
       } else {
         cipherSuite = null;
         peerCertificates = null;
@@ -530,6 +543,22 @@ public final class HttpResponseCache extends ResponseCache {
       }
     }
 
+    /**
+     * Returns the SSL socket used by {@code httpConnection} for HTTPS, nor null
+     * if the connection isn't using HTTPS. Since we permit redirects across
+     * protocols (HTTP to HTTPS or vice versa), the implementation type of the
+     * connection doesn't necessarily match the implementation type of its HTTP
+     * engine.
+     */
+    private SSLSocket getSslSocket(HttpURLConnection httpConnection) {
+      HttpEngine engine = httpConnection instanceof HttpsURLConnectionImpl
+          ? ((HttpsURLConnectionImpl) httpConnection).getHttpEngine()
+          : ((HttpURLConnectionImpl) httpConnection).getHttpEngine();
+      return engine instanceof HttpsEngine
+          ? ((HttpsEngine) engine).getSslSocket()
+          : null;
+    }
+
     public void writeTo(DiskLruCache.Editor editor) throws IOException {
       OutputStream out = editor.newOutputStream(ENTRY_METADATA);
       Writer writer = new BufferedWriter(new OutputStreamWriter(out, UTF_8));

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/Job.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/Job.java b/framework/src/com/squareup/okhttp/Job.java
new file mode 100755
index 0000000..1bfeb1d
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/Job.java
@@ -0,0 +1,232 @@
+/*
+ * 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;
+
+import com.squareup.okhttp.internal.http.HttpAuthenticator;
+import com.squareup.okhttp.internal.http.HttpEngine;
+import com.squareup.okhttp.internal.http.HttpTransport;
+import com.squareup.okhttp.internal.http.HttpsEngine;
+import com.squareup.okhttp.internal.http.Policy;
+import com.squareup.okhttp.internal.http.RawHeaders;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.ProtocolException;
+import java.net.Proxy;
+import java.net.URL;
+
+import static com.squareup.okhttp.internal.Util.getEffectivePort;
+import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_MOVED_PERM;
+import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_MOVED_TEMP;
+import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_MULT_CHOICE;
+import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_PROXY_AUTH;
+import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_SEE_OTHER;
+import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_TEMP_REDIRECT;
+import static com.squareup.okhttp.internal.http.HttpURLConnectionImpl.HTTP_UNAUTHORIZED;
+
+final class Job implements Runnable, Policy {
+  private final Dispatcher dispatcher;
+  private final OkHttpClient client;
+  private final Response.Receiver responseReceiver;
+
+  /** The request; possibly a consequence of redirects or auth headers. */
+  private Request request;
+
+  public Job(Dispatcher dispatcher, OkHttpClient client, Request request,
+      Response.Receiver responseReceiver) {
+    this.dispatcher = dispatcher;
+    this.client = client;
+    this.request = request;
+    this.responseReceiver = responseReceiver;
+  }
+
+  @Override public int getChunkLength() {
+    return request.body().contentLength() == -1 ? HttpTransport.DEFAULT_CHUNK_LENGTH : -1;
+  }
+
+  @Override public long getFixedContentLength() {
+    return request.body().contentLength();
+  }
+
+  @Override public boolean getUseCaches() {
+    return false; // TODO.
+  }
+
+  @Override public HttpURLConnection getHttpConnectionToCache() {
+    return null;
+  }
+
+  @Override public URL getURL() {
+    return request.url();
+  }
+
+  @Override public long getIfModifiedSince() {
+    return 0; // For HttpURLConnection only. We let the cache drive this.
+  }
+
+  @Override public boolean usingProxy() {
+    return false; // We let the connection decide this.
+  }
+
+  @Override public void setSelectedProxy(Proxy proxy) {
+    // Do nothing.
+  }
+
+  Object tag() {
+    return request.tag();
+  }
+
+  @Override public void run() {
+    try {
+      Response response = execute();
+      responseReceiver.onResponse(response);
+    } catch (IOException e) {
+      responseReceiver.onFailure(new Failure.Builder()
+          .request(request)
+          .exception(e)
+          .build());
+    } finally {
+      // TODO: close the response body
+      // TODO: release the HTTP engine (potentially multiple!)
+      dispatcher.finished(this);
+    }
+  }
+
+  private Response execute() throws IOException {
+    Connection connection = null;
+    Response redirectedBy = null;
+
+    while (true) {
+      HttpEngine engine = newEngine(connection);
+
+      Request.Body body = request.body();
+      if (body != null) {
+        MediaType contentType = body.contentType();
+        if (contentType == null) throw new IllegalStateException("contentType == null");
+        if (engine.getRequestHeaders().getContentType() == null) {
+          engine.getRequestHeaders().setContentType(contentType.toString());
+        }
+      }
+
+      engine.sendRequest();
+
+      if (body != null) {
+        body.writeTo(engine.getRequestBody());
+      }
+
+      engine.readResponse();
+
+      int responseCode = engine.getResponseCode();
+      Dispatcher.RealResponseBody responseBody = new Dispatcher.RealResponseBody(
+          engine.getResponseHeaders(), engine.getResponseBody());
+
+      Response response = new Response.Builder(request, responseCode)
+          .rawHeaders(engine.getResponseHeaders().getHeaders())
+          .body(responseBody)
+          .redirectedBy(redirectedBy)
+          .build();
+
+      Request redirect = processResponse(engine, response);
+
+      if (redirect == null) {
+        engine.automaticallyReleaseConnectionToPool();
+        return response;
+      }
+
+      // TODO: fail if too many redirects
+      // TODO: fail if not following redirects
+      // TODO: release engine
+
+      connection = sameConnection(request, redirect) ? engine.getConnection() : null;
+      redirectedBy = response;
+      request = redirect;
+    }
+  }
+
+  HttpEngine newEngine(Connection connection) throws IOException {
+    String protocol = request.url().getProtocol();
+    RawHeaders requestHeaders = request.rawHeaders();
+    if (protocol.equals("http")) {
+      return new HttpEngine(client, this, request.method(), requestHeaders, connection, null);
+    } else if (protocol.equals("https")) {
+      return new HttpsEngine(client, this, request.method(), requestHeaders, connection, null);
+    } else {
+      throw new AssertionError();
+    }
+  }
+
+  /**
+   * Figures out the HTTP request to make in response to receiving {@code
+   * response}. This will either add authentication headers or follow
+   * redirects. If a follow-up is either unnecessary or not applicable, this
+   * returns null.
+   */
+  private Request processResponse(HttpEngine engine, Response response) throws IOException {
+    Request request = response.request();
+    Proxy selectedProxy = engine.getConnection() != null
+        ? engine.getConnection().getRoute().getProxy()
+        : client.getProxy();
+    int responseCode = response.code();
+
+    switch (responseCode) {
+      case HTTP_PROXY_AUTH:
+        if (selectedProxy.type() != Proxy.Type.HTTP) {
+          throw new ProtocolException("Received HTTP_PROXY_AUTH (407) code while not using proxy");
+        }
+        // fall-through
+      case HTTP_UNAUTHORIZED:
+        RawHeaders successorRequestHeaders = request.rawHeaders();
+        boolean credentialsFound = HttpAuthenticator.processAuthHeader(client.getAuthenticator(),
+            response.code(), response.rawHeaders(), successorRequestHeaders, selectedProxy,
+            this.request.url());
+        return credentialsFound
+            ? request.newBuilder().rawHeaders(successorRequestHeaders).build()
+            : null;
+
+      case HTTP_MULT_CHOICE:
+      case HTTP_MOVED_PERM:
+      case HTTP_MOVED_TEMP:
+      case HTTP_SEE_OTHER:
+      case HTTP_TEMP_REDIRECT:
+        String method = request.method();
+        if (responseCode == HTTP_TEMP_REDIRECT && !method.equals("GET") && !method.equals("HEAD")) {
+          // "If the 307 status code is received in response to a request other than GET or HEAD,
+          // the user agent MUST NOT automatically redirect the request"
+          return null;
+        }
+
+        String location = response.header("Location");
+        if (location == null) {
+          return null;
+        }
+
+        URL url = new URL(request.url(), location);
+        if (!url.getProtocol().equals("https") && !url.getProtocol().equals("http")) {
+          return null; // Don't follow redirects to unsupported protocols.
+        }
+
+        return this.request.newBuilder().url(url).build();
+
+      default:
+        return null;
+    }
+  }
+
+  private boolean sameConnection(Request a, Request b) {
+    return a.url().getHost().equals(b.url().getHost())
+        && getEffectivePort(a.url()) == getEffectivePort(b.url())
+        && a.url().getProtocol().equals(b.url().getProtocol());
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/MediaType.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/MediaType.java b/framework/src/com/squareup/okhttp/MediaType.java
new file mode 100755
index 0000000..2c09596
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/MediaType.java
@@ -0,0 +1,120 @@
+/*
+ * 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;
+
+import java.nio.charset.Charset;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * An <a href="http://tools.ietf.org/html/rfc2045">RFC 2045</a> Media Type,
+ * appropriate to describe the content type of an HTTP request or response body.
+ */
+public final class MediaType {
+  private static final String TOKEN = "([a-zA-Z0-9-!#$%&'*+.^_`{|}~]+)";
+  private static final String QUOTED = "\"([^\"]*)\"";
+  private static final Pattern TYPE_SUBTYPE = Pattern.compile(TOKEN + "/" + TOKEN);
+  private static final Pattern PARAMETER = Pattern.compile(
+      ";\\s*" + TOKEN + "=(?:" + TOKEN + "|" + QUOTED + ")");
+
+  private final String mediaType;
+  private final String type;
+  private final String subtype;
+  private final String charset;
+
+  private MediaType(String mediaType, String type, String subtype, String charset) {
+    this.mediaType = mediaType;
+    this.type = type;
+    this.subtype = subtype;
+    this.charset = charset;
+  }
+
+  /**
+   * Returns a media type for {@code string}, or null if {@code string} is not a
+   * well-formed media type.
+   */
+  public static MediaType parse(String string) {
+    Matcher typeSubtype = TYPE_SUBTYPE.matcher(string);
+    if (!typeSubtype.lookingAt()) return null;
+    String type = typeSubtype.group(1).toLowerCase(Locale.US);
+    String subtype = typeSubtype.group(2).toLowerCase(Locale.US);
+
+    String charset = null;
+    Matcher parameter = PARAMETER.matcher(string);
+    for (int s = typeSubtype.end(); s < string.length(); s = parameter.end()) {
+      parameter.region(s, string.length());
+      if (!parameter.lookingAt()) return null; // This is not a well-formed media type.
+
+      String name = parameter.group(1);
+      if (name == null || !name.equalsIgnoreCase("charset")) continue;
+      if (charset != null) throw new IllegalArgumentException("Multiple charsets: " + string);
+      charset = parameter.group(2) != null
+          ? parameter.group(2)  // Value is a token.
+          : parameter.group(3); // Value is a quoted string.
+    }
+
+    return new MediaType(string, type, subtype, charset);
+  }
+
+  /**
+   * Returns the high-level media type, such as "text", "image", "audio",
+   * "video", or "application".
+   */
+  public String type() {
+    return type;
+  }
+
+  /**
+   * Returns a specific media subtype, such as "plain" or "png", "mpeg",
+   * "mp4" or "xml".
+   */
+  public String subtype() {
+    return subtype;
+  }
+
+  /**
+   * Returns the charset of this media type, or null if this media type doesn't
+   * specify a charset.
+   */
+  public Charset charset() {
+    return charset != null ? Charset.forName(charset) : null;
+  }
+
+  /**
+   * Returns the charset of this media type, or {@code defaultValue} if this
+   * media type doesn't specify a charset.
+   */
+  public Charset charset(Charset defaultValue) {
+    return charset != null ? Charset.forName(charset) : defaultValue;
+  }
+
+  /**
+   * Returns the encoded media type, like "text/plain; charset=utf-8",
+   * appropriate for use in a Content-Type header.
+   */
+  @Override public String toString() {
+    return mediaType;
+  }
+
+  @Override public boolean equals(Object o) {
+    return o instanceof MediaType && ((MediaType) o).mediaType.equals(mediaType);
+  }
+
+  @Override public int hashCode() {
+    return mediaType.hashCode();
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/OkAuthenticator.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/OkAuthenticator.java b/framework/src/com/squareup/okhttp/OkAuthenticator.java
new file mode 100755
index 0000000..a505419
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/OkAuthenticator.java
@@ -0,0 +1,123 @@
+/*
+ * 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;
+
+import com.squareup.okhttp.internal.Base64;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.Proxy;
+import java.net.URL;
+import java.util.List;
+
+/**
+ * Responds to authentication challenges from the remote web or proxy server by
+ * returning credentials.
+ */
+public interface OkAuthenticator {
+  /**
+   * Returns a credential that satisfies the authentication challenge made by
+   * {@code url}. Returns null if the challenge cannot be satisfied. This method
+   * is called in response to an HTTP 401 unauthorized status code sent by the
+   * origin server.
+   *
+   * @param challenges parsed "WWW-Authenticate" challenge headers from the HTTP
+   *     response.
+   */
+  Credential authenticate(Proxy proxy, URL url, List<Challenge> challenges) throws IOException;
+
+  /**
+   * Returns a credential that satisfies the authentication challenge made by
+   * {@code proxy}. Returns null if the challenge cannot be satisfied. This
+   * method is called in response to an HTTP 401 unauthorized status code sent
+   * by the proxy server.
+   *
+   * @param challenges parsed "Proxy-Authenticate" challenge headers from the
+   *     HTTP response.
+   */
+  Credential authenticateProxy(Proxy proxy, URL url, List<Challenge> challenges) throws IOException;
+
+  /** An RFC 2617 challenge. */
+  public final class Challenge {
+    private final String scheme;
+    private final String realm;
+
+    public Challenge(String scheme, String realm) {
+      this.scheme = scheme;
+      this.realm = realm;
+    }
+
+    /** Returns the authentication scheme, like {@code Basic}. */
+    public String getScheme() {
+      return scheme;
+    }
+
+    /** Returns the protection space. */
+    public String getRealm() {
+      return realm;
+    }
+
+    @Override public boolean equals(Object o) {
+      return o instanceof Challenge
+          && ((Challenge) o).scheme.equals(scheme)
+          && ((Challenge) o).realm.equals(realm);
+    }
+
+    @Override public int hashCode() {
+      return scheme.hashCode() + 31 * realm.hashCode();
+    }
+
+    @Override public String toString() {
+      return scheme + " realm=\"" + realm + "\"";
+    }
+  }
+
+  /** An RFC 2617 credential. */
+  public final class Credential {
+    private final String headerValue;
+
+    private Credential(String headerValue) {
+      this.headerValue = headerValue;
+    }
+
+    /** Returns an auth credential for the Basic scheme. */
+    public static Credential basic(String userName, String password) {
+      try {
+        String usernameAndPassword = userName + ":" + password;
+        byte[] bytes = usernameAndPassword.getBytes("ISO-8859-1");
+        String encoded = Base64.encode(bytes);
+        return new Credential("Basic " + encoded);
+      } catch (UnsupportedEncodingException e) {
+        throw new AssertionError();
+      }
+    }
+
+    public String getHeaderValue() {
+      return headerValue;
+    }
+
+    @Override public boolean equals(Object o) {
+      return o instanceof Credential && ((Credential) o).headerValue.equals(headerValue);
+    }
+
+    @Override public int hashCode() {
+      return headerValue.hashCode();
+    }
+
+    @Override public String toString() {
+      return headerValue;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/OkHttpClient.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/OkHttpClient.java b/framework/src/com/squareup/okhttp/OkHttpClient.java
old mode 100644
new mode 100755
index 7834bd6..f78592f
--- a/framework/src/com/squareup/okhttp/OkHttpClient.java
+++ b/framework/src/com/squareup/okhttp/OkHttpClient.java
@@ -15,34 +15,105 @@
  */
 package com.squareup.okhttp;
 
+import com.squareup.okhttp.internal.Util;
+import com.squareup.okhttp.internal.http.HttpAuthenticator;
 import com.squareup.okhttp.internal.http.HttpURLConnectionImpl;
 import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl;
-import com.squareup.okhttp.internal.http.OkResponseCache;
 import com.squareup.okhttp.internal.http.OkResponseCacheAdapter;
+import com.squareup.okhttp.internal.tls.OkHostnameVerifier;
 import java.net.CookieHandler;
 import java.net.HttpURLConnection;
 import java.net.Proxy;
 import java.net.ProxySelector;
 import java.net.ResponseCache;
 import java.net.URL;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Set;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLSocketFactory;
 
 /** Configures and creates HTTP connections. */
-public final class OkHttpClient {
+public final class OkHttpClient implements URLStreamHandlerFactory {
+  private static final List<String> DEFAULT_TRANSPORTS
+      = Util.immutableList(Arrays.asList("spdy/3", "http/1.1"));
+
+  private final RouteDatabase routeDatabase;
+  private final Dispatcher dispatcher;
   private Proxy proxy;
-  private Set<Route> failedRoutes = Collections.synchronizedSet(new LinkedHashSet<Route>());
+  private List<String> transports;
   private ProxySelector proxySelector;
   private CookieHandler cookieHandler;
   private ResponseCache responseCache;
   private SSLSocketFactory sslSocketFactory;
   private HostnameVerifier hostnameVerifier;
+  private OkAuthenticator authenticator;
   private ConnectionPool connectionPool;
   private boolean followProtocolRedirects = true;
+  private int connectTimeout;
+  private int readTimeout;
+
+  public OkHttpClient() {
+    routeDatabase = new RouteDatabase();
+    dispatcher = new Dispatcher();
+  }
+
+  private OkHttpClient(OkHttpClient copyFrom) {
+    routeDatabase = copyFrom.routeDatabase;
+    dispatcher = copyFrom.dispatcher;
+  }
+
+  /**
+   * Sets the default connect timeout for new connections. A value of 0 means no timeout.
+   *
+   * @see URLConnection#setConnectTimeout(int)
+   */
+  public void setConnectTimeout(long timeout, TimeUnit unit) {
+    if (timeout < 0) {
+      throw new IllegalArgumentException("timeout < 0");
+    }
+    if (unit == null) {
+      throw new IllegalArgumentException("unit == null");
+    }
+    long millis = unit.toMillis(timeout);
+    if (millis > Integer.MAX_VALUE) {
+      throw new IllegalArgumentException("Timeout too large.");
+    }
+    connectTimeout = (int) millis;
+  }
+
+  /** Default connect timeout (in milliseconds). */
+  public int getConnectTimeout() {
+    return connectTimeout;
+  }
+
+  /**
+   * Sets the default read timeout for new connections. A value of 0 means no timeout.
+   *
+   * @see URLConnection#setReadTimeout(int)
+   */
+  public void setReadTimeout(long timeout, TimeUnit unit) {
+    if (timeout < 0) {
+      throw new IllegalArgumentException("timeout < 0");
+    }
+    if (unit == null) {
+      throw new IllegalArgumentException("unit == null");
+    }
+    long millis = unit.toMillis(timeout);
+    if (millis > Integer.MAX_VALUE) {
+      throw new IllegalArgumentException("Timeout too large.");
+    }
+    readTimeout = (int) millis;
+  }
+
+  /** Default read timeout (in milliseconds). */
+  public int getReadTimeout() {
+    return readTimeout;
+  }
 
   /**
    * Sets the HTTP proxy that will be used by connections created by this
@@ -108,7 +179,7 @@ public final class OkHttpClient {
     return responseCache;
   }
 
-  private OkResponseCache okResponseCache() {
+  public OkResponseCache getOkResponseCache() {
     if (responseCache instanceof HttpResponseCache) {
       return ((HttpResponseCache) responseCache).okResponseCache;
     } else if (responseCache != null) {
@@ -124,7 +195,7 @@ public final class OkHttpClient {
    * <p>If unset, the {@link HttpsURLConnection#getDefaultSSLSocketFactory()
    * system-wide default} SSL socket factory will be used.
    */
-  public OkHttpClient setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
+  public OkHttpClient setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
     this.sslSocketFactory = sslSocketFactory;
     return this;
   }
@@ -150,6 +221,22 @@ public final class OkHttpClient {
   }
 
   /**
+   * Sets the authenticator used to respond to challenges from the remote web
+   * server or proxy server.
+   *
+   * <p>If unset, the {@link java.net.Authenticator#setDefault system-wide default}
+   * authenticator will be used.
+   */
+  public OkHttpClient setAuthenticator(OkAuthenticator authenticator) {
+    this.authenticator = authenticator;
+    return this;
+  }
+
+  public OkAuthenticator getAuthenticator() {
+    return authenticator;
+  }
+
+  /**
    * Sets the connection pool used to recycle HTTP and HTTPS connections.
    *
    * <p>If unset, the {@link ConnectionPool#getDefault() system-wide
@@ -180,16 +267,86 @@ public final class OkHttpClient {
     return followProtocolRedirects;
   }
 
+  public RouteDatabase getRoutesDatabase() {
+    return routeDatabase;
+  }
+
+  /**
+   * Configure the transports used by this client to communicate with remote
+   * servers. By default this client will prefer the most efficient transport
+   * available, falling back to more ubiquitous transports. Applications should
+   * only call this method to avoid specific compatibility problems, such as web
+   * servers that behave incorrectly when SPDY is enabled.
+   *
+   * <p>The following transports are currently supported:
+   * <ul>
+   *   <li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">http/1.1</a>
+   *   <li><a href="http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3">spdy/3</a>
+   * </ul>
+   *
+   * <p><strong>This is an evolving set.</strong> Future releases may drop
+   * support for transitional transports (like spdy/3), in favor of their
+   * successors (spdy/4 or http/2.0). The http/1.1 transport will never be
+   * dropped.
+   *
+   * <p>If multiple protocols are specified, <a
+   * href="https://technotes.googlecode.com/git/nextprotoneg.html">NPN</a> will
+   * be used to negotiate a transport. Future releases may use another mechanism
+   * (such as <a href="http://tools.ietf.org/html/draft-friedl-tls-applayerprotoneg-02">ALPN</a>)
+   * to negotiate a transport.
+   *
+   * @param transports the transports to use, in order of preference. The list
+   *     must contain "http/1.1". It must not contain null.
+   */
+  public OkHttpClient setTransports(List<String> transports) {
+    transports = Util.immutableList(transports);
+    if (!transports.contains("http/1.1")) {
+      throw new IllegalArgumentException("transports doesn't contain http/1.1: " + transports);
+    }
+    if (transports.contains(null)) {
+      throw new IllegalArgumentException("transports must not contain null");
+    }
+    if (transports.contains("")) {
+      throw new IllegalArgumentException("transports contains an empty string");
+    }
+    this.transports = transports;
+    return this;
+  }
+
+  public List<String> getTransports() {
+    return transports;
+  }
+
+  /**
+   * Schedules {@code request} to be executed.
+   */
+  /* OkHttp 2.0: public */ void enqueue(Request request, Response.Receiver responseReceiver) {
+    // Create the HttpURLConnection immediately so the enqueued job gets the current settings of
+    // this client. Otherwise changes to this client (socket factory, redirect policy, etc.) may
+    // incorrectly be reflected in the request when it is dispatched later.
+    dispatcher.enqueue(copyWithDefaults(), request, responseReceiver);
+  }
+
+  /**
+   * Cancels all scheduled tasks tagged with {@code tag}. Requests that are already
+   * in flight might not be canceled.
+   */
+  /* OkHttp 2.0: public */ void cancel(Object tag) {
+    dispatcher.cancel(tag);
+  }
+
   public HttpURLConnection open(URL url) {
+    return open(url, proxy);
+  }
+
+  HttpURLConnection open(URL url, Proxy proxy) {
     String protocol = url.getProtocol();
     OkHttpClient copy = copyWithDefaults();
-    if (protocol.equals("http")) {
-      return new HttpURLConnectionImpl(url, copy, copy.okResponseCache(), copy.failedRoutes);
-    } else if (protocol.equals("https")) {
-      return new HttpsURLConnectionImpl(url, copy, copy.okResponseCache(), copy.failedRoutes);
-    } else {
-      throw new IllegalArgumentException("Unexpected protocol: " + protocol);
-    }
+    copy.proxy = proxy;
+
+    if (protocol.equals("http")) return new HttpURLConnectionImpl(url, copy);
+    if (protocol.equals("https")) return new HttpsURLConnectionImpl(url, copy);
+    throw new IllegalArgumentException("Unexpected protocol: " + protocol);
   }
 
   /**
@@ -197,9 +354,8 @@ public final class OkHttpClient {
    * each field that hasn't been explicitly configured.
    */
   private OkHttpClient copyWithDefaults() {
-    OkHttpClient result = new OkHttpClient();
+    OkHttpClient result = new OkHttpClient(this);
     result.proxy = proxy;
-    result.failedRoutes = failedRoutes;
     result.proxySelector = proxySelector != null ? proxySelector : ProxySelector.getDefault();
     result.cookieHandler = cookieHandler != null ? cookieHandler : CookieHandler.getDefault();
     result.responseCache = responseCache != null ? responseCache : ResponseCache.getDefault();
@@ -208,9 +364,45 @@ public final class OkHttpClient {
         : HttpsURLConnection.getDefaultSSLSocketFactory();
     result.hostnameVerifier = hostnameVerifier != null
         ? hostnameVerifier
-        : HttpsURLConnection.getDefaultHostnameVerifier();
+        : OkHostnameVerifier.INSTANCE;
+    result.authenticator = authenticator != null
+        ? authenticator
+        : HttpAuthenticator.SYSTEM_DEFAULT;
     result.connectionPool = connectionPool != null ? connectionPool : ConnectionPool.getDefault();
     result.followProtocolRedirects = followProtocolRedirects;
+    result.transports = transports != null ? transports : DEFAULT_TRANSPORTS;
+    result.connectTimeout = connectTimeout;
+    result.readTimeout = readTimeout;
     return result;
   }
+
+  /**
+   * Creates a URLStreamHandler as a {@link URL#setURLStreamHandlerFactory}.
+   *
+   * <p>This code configures OkHttp to handle all HTTP and HTTPS connections
+   * created with {@link URL#openConnection()}: <pre>   {@code
+   *
+   *   OkHttpClient okHttpClient = new OkHttpClient();
+   *   URL.setURLStreamHandlerFactory(okHttpClient);
+   * }</pre>
+   */
+  public URLStreamHandler createURLStreamHandler(final String protocol) {
+    if (!protocol.equals("http") && !protocol.equals("https")) return null;
+
+    return new URLStreamHandler() {
+      @Override protected URLConnection openConnection(URL url) {
+        return open(url);
+      }
+
+      @Override protected URLConnection openConnection(URL url, Proxy proxy) {
+        return open(url, proxy);
+      }
+
+      @Override protected int getDefaultPort() {
+        if (protocol.equals("http")) return 80;
+        if (protocol.equals("https")) return 443;
+        throw new AssertionError();
+      }
+    };
+  }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/OkResponseCache.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/OkResponseCache.java b/framework/src/com/squareup/okhttp/OkResponseCache.java
old mode 100644
new mode 100755
index b7e3801..ffe6f54
--- a/framework/src/com/squareup/okhttp/OkResponseCache.java
+++ b/framework/src/com/squareup/okhttp/OkResponseCache.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -16,23 +16,41 @@
 package com.squareup.okhttp;
 
 import java.io.IOException;
+import java.net.CacheRequest;
 import java.net.CacheResponse;
 import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URLConnection;
+import java.util.List;
+import java.util.Map;
 
 /**
- * A response cache that supports statistics tracking and updating stored
- * responses. Implementations of {@link java.net.ResponseCache} should implement
- * this interface to receive additional support from the HTTP engine.
+ * An extended response cache API. Unlike {@link java.net.ResponseCache}, this
+ * interface supports conditional caching and statistics.
+ *
+ * <h3>Warning: Experimental OkHttp 2.0 API</h3>
+ * This class is in beta. APIs are subject to change!
  */
 public interface OkResponseCache {
+  CacheResponse get(URI uri, String requestMethod, Map<String, List<String>> requestHeaders)
+      throws IOException;
 
-  /** Track an HTTP response being satisfied by {@code source}. */
-  void trackResponse(ResponseSource source);
+  CacheRequest put(URI uri, URLConnection urlConnection) throws IOException;
+
+  /** Remove any cache entries for the supplied {@code uri} if the request method invalidates. */
+  void maybeRemove(String requestMethod, URI uri) throws IOException;
+
+  /**
+   * Handles a conditional request hit by updating the stored cache response
+   * with the headers from {@code httpConnection}. The cached response body is
+   * not updated. If the stored response has changed since {@code
+   * conditionalCacheHit} was returned, this does nothing.
+   */
+  void update(CacheResponse conditionalCacheHit, HttpURLConnection connection) throws IOException;
 
   /** Track an conditional GET that was satisfied by this cache. */
   void trackConditionalCacheHit();
 
-  /** Updates stored HTTP headers using a hit on a conditional GET. */
-  void update(CacheResponse conditionalCacheHit, HttpURLConnection httpConnection)
-      throws IOException;
+  /** Track an HTTP response being satisfied by {@code source}. */
+  void trackResponse(ResponseSource source);
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/Request.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/Request.java b/framework/src/com/squareup/okhttp/Request.java
new file mode 100755
index 0000000..f95303e
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/Request.java
@@ -0,0 +1,284 @@
+/*
+ * 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;
+
+import com.squareup.okhttp.internal.Util;
+import com.squareup.okhttp.internal.http.RawHeaders;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * An HTTP request. Instances of this class are immutable if their {@link #body}
+ * is null or itself immutable.
+ *
+ * <h3>Warning: Experimental OkHttp 2.0 API</h3>
+ * This class is in beta. APIs are subject to change!
+ */
+/* OkHttp 2.0: public */ final class Request {
+  private final URL url;
+  private final String method;
+  private final RawHeaders headers;
+  private final Body body;
+  private final Object tag;
+
+  private Request(Builder builder) {
+    this.url = builder.url;
+    this.method = builder.method;
+    this.headers = new RawHeaders(builder.headers);
+    this.body = builder.body;
+    this.tag = builder.tag != null ? builder.tag : this;
+  }
+
+  public URL url() {
+    return url;
+  }
+
+  public String urlString() {
+    return url.toString();
+  }
+
+  public String method() {
+    return method;
+  }
+
+  public String header(String name) {
+    return headers.get(name);
+  }
+
+  public List<String> headers(String name) {
+    return headers.values(name);
+  }
+
+  public Set<String> headerNames() {
+    return headers.names();
+  }
+
+  RawHeaders rawHeaders() {
+    return new RawHeaders(headers);
+  }
+
+  public int headerCount() {
+    return headers.length();
+  }
+
+  public String headerName(int index) {
+    return headers.getFieldName(index);
+  }
+
+  public String headerValue(int index) {
+    return headers.getValue(index);
+  }
+
+  public Body body() {
+    return body;
+  }
+
+  public Object tag() {
+    return tag;
+  }
+
+  Builder newBuilder() {
+    return new Builder(url)
+        .method(method, body)
+        .rawHeaders(headers)
+        .tag(tag);
+  }
+
+  public abstract static class Body {
+    /** Returns the Content-Type header for this body. */
+    public abstract MediaType contentType();
+
+    /**
+     * Returns the number of bytes that will be written to {@code out} in a call
+     * to {@link #writeTo}, or -1 if that count is unknown.
+     */
+    public long contentLength() {
+      return -1;
+    }
+
+    /** Writes the content of this request to {@code out}. */
+    public abstract void writeTo(OutputStream out) throws IOException;
+
+    /**
+     * Returns a new request body that transmits {@code content}. If {@code
+     * contentType} lacks a charset, this will use UTF-8.
+     */
+    public static Body create(MediaType contentType, String content) {
+      contentType = contentType.charset() != null
+          ? contentType
+          : MediaType.parse(contentType + "; charset=utf-8");
+      try {
+        byte[] bytes = content.getBytes(contentType.charset().name());
+        return create(contentType, bytes);
+      } catch (UnsupportedEncodingException e) {
+        throw new AssertionError();
+      }
+    }
+
+    /** Returns a new request body that transmits {@code content}. */
+    public static Body create(final MediaType contentType, final byte[] content) {
+      if (contentType == null) throw new NullPointerException("contentType == null");
+      if (content == null) throw new NullPointerException("content == null");
+
+      return new Body() {
+        @Override public MediaType contentType() {
+          return contentType;
+        }
+
+        @Override public long contentLength() {
+          return content.length;
+        }
+
+        @Override public void writeTo(OutputStream out) throws IOException {
+          out.write(content);
+        }
+      };
+    }
+
+    /** Returns a new request body that transmits the content of {@code file}. */
+    public static Body create(final MediaType contentType, final File file) {
+      if (contentType == null) throw new NullPointerException("contentType == null");
+      if (file == null) throw new NullPointerException("content == null");
+
+      return new Body() {
+        @Override public MediaType contentType() {
+          return contentType;
+        }
+
+        @Override public long contentLength() {
+          return file.length();
+        }
+
+        @Override public void writeTo(OutputStream out) throws IOException {
+          long length = contentLength();
+          if (length == 0) return;
+
+          InputStream in = null;
+          try {
+            in = new FileInputStream(file);
+            byte[] buffer = new byte[(int) Math.min(8192, length)];
+            for (int c; (c = in.read(buffer)) != -1; ) {
+              out.write(buffer, 0, c);
+            }
+          } finally {
+            Util.closeQuietly(in);
+          }
+        }
+      };
+    }
+  }
+
+  public static class Builder {
+    private URL url;
+    private String method = "GET";
+    private RawHeaders headers = new RawHeaders();
+    private Body body;
+    private Object tag;
+
+    public Builder(String url) {
+      url(url);
+    }
+
+    public Builder(URL url) {
+      url(url);
+    }
+
+    public Builder url(String url) {
+      try {
+        this.url = new URL(url);
+        return this;
+      } catch (MalformedURLException e) {
+        throw new IllegalArgumentException("Malformed URL: " + url);
+      }
+    }
+
+    public Builder url(URL url) {
+      if (url == null) throw new IllegalStateException("url == null");
+      this.url = url;
+      return this;
+    }
+
+    /**
+     * Sets the header named {@code name} to {@code value}. If this request
+     * already has any headers with that name, they are all replaced.
+     */
+    public Builder header(String name, String value) {
+      headers.set(name, value);
+      return this;
+    }
+
+    /**
+     * Adds a header with {@code name} and {@code value}. Prefer this method for
+     * multiply-valued headers like "Cookie".
+     */
+    public Builder addHeader(String name, String value) {
+      headers.add(name, value);
+      return this;
+    }
+
+    Builder rawHeaders(RawHeaders rawHeaders) {
+      headers = new RawHeaders(rawHeaders);
+      return this;
+    }
+
+    public Builder get() {
+      return method("GET", null);
+    }
+
+    public Builder head() {
+      return method("HEAD", null);
+    }
+
+    public Builder post(Body body) {
+      return method("POST", body);
+    }
+
+    public Builder put(Body body) {
+      return method("PUT", body);
+    }
+
+    public Builder method(String method, Body body) {
+      if (method == null || method.length() == 0) {
+        throw new IllegalArgumentException("method == null || method.length() == 0");
+      }
+      this.method = method;
+      this.body = body;
+      return this;
+    }
+
+    /**
+     * Attaches {@code tag} to the request. It can be used later to cancel the
+     * request. If the tag is unspecified or null, the request is canceled by
+     * using the request itself as the tag.
+     */
+    public Builder tag(Object tag) {
+      this.tag = tag;
+      return this;
+    }
+
+    public Request build() {
+      return new Request(this);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/Response.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/Response.java b/framework/src/com/squareup/okhttp/Response.java
new file mode 100755
index 0000000..1e67968
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/Response.java
@@ -0,0 +1,290 @@
+/*
+ * 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;
+
+import com.squareup.okhttp.internal.Util;
+import com.squareup.okhttp.internal.http.RawHeaders;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Set;
+
+import static com.squareup.okhttp.internal.Util.UTF_8;
+
+/**
+ * An HTTP response. Instances of this class are not immutable: the response
+ * body is a one-shot value that may be consumed only once. All other properties
+ * are immutable.
+ *
+ * <h3>Warning: Experimental OkHttp 2.0 API</h3>
+ * This class is in beta. APIs are subject to change!
+ */
+/* OkHttp 2.0: public */ final class Response {
+  private final Request request;
+  private final int code;
+  private final RawHeaders headers;
+  private final Body body;
+  private final Response redirectedBy;
+
+  private Response(Builder builder) {
+    this.request = builder.request;
+    this.code = builder.code;
+    this.headers = new RawHeaders(builder.headers);
+    this.body = builder.body;
+    this.redirectedBy = builder.redirectedBy;
+  }
+
+  /**
+   * The wire-level request that initiated this HTTP response. This is usually
+   * <strong>not</strong> the same request instance provided to the HTTP client:
+   * <ul>
+   *     <li>It may be transformed by the HTTP client. For example, the client
+   *         may have added its own {@code Content-Encoding} header to enable
+   *         response compression.
+   *     <li>It may be the request generated in response to an HTTP redirect.
+   *         In this case the request URL may be different than the initial
+   *         request URL.
+   * </ul>
+   */
+  public Request request() {
+    return request;
+  }
+
+  public int code() {
+    return code;
+  }
+
+  public String header(String name) {
+    return header(name, null);
+  }
+
+  public String header(String name, String defaultValue) {
+    String result = headers.get(name);
+    return result != null ? result : defaultValue;
+  }
+
+  public List<String> headers(String name) {
+    return headers.values(name);
+  }
+
+  public Set<String> headerNames() {
+    return headers.names();
+  }
+
+  public int headerCount() {
+    return headers.length();
+  }
+
+  public String headerName(int index) {
+    return headers.getFieldName(index);
+  }
+
+  RawHeaders rawHeaders() {
+    return new RawHeaders(headers);
+  }
+
+  public String headerValue(int index) {
+    return headers.getValue(index);
+  }
+
+  public Body body() {
+    return body;
+  }
+
+  /**
+   * Returns the response for the HTTP redirect that triggered this response, or
+   * null if this response wasn't triggered by an automatic redirect. The body
+   * of the returned response should not be read because it has already been
+   * consumed by the redirecting client.
+   */
+  public Response redirectedBy() {
+    return redirectedBy;
+  }
+
+  public abstract static class Body {
+    /** Multiple calls to {@link #charStream()} must return the same instance. */
+    private Reader reader;
+
+    /**
+     * Returns true if further data from this response body should be read at
+     * this time. For asynchronous transports like SPDY and HTTP/2.0, this will
+     * return false once all locally-available body bytes have been read.
+     *
+     * <p>Clients with many concurrent downloads can use this method to reduce
+     * the number of idle threads blocking on reads. See {@link
+     * Receiver#onResponse} for details.
+     */
+    // <h3>Body.ready() vs. InputStream.available()</h3>
+    // TODO: Can we fix response bodies to implement InputStream.available well?
+    // The deflater implementation is broken by default but we could do better.
+    public abstract boolean ready() throws IOException;
+
+    public abstract MediaType contentType();
+
+    /**
+     * Returns the number of bytes in that will returned by {@link #bytes}, or
+     * {@link #byteStream}, or -1 if unknown.
+     */
+    public abstract long contentLength();
+
+    public abstract InputStream byteStream() throws IOException;
+
+    public final byte[] bytes() throws IOException {
+      long contentLength = contentLength();
+      if (contentLength > Integer.MAX_VALUE) {
+        throw new IOException("Cannot buffer entire body for content length: " + contentLength);
+      }
+
+      if (contentLength != -1) {
+        byte[] content = new byte[(int) contentLength];
+        InputStream in = byteStream();
+        Util.readFully(in, content);
+        if (in.read() != -1) throw new IOException("Content-Length and stream length disagree");
+        return content;
+
+      } else {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        Util.copy(byteStream(), out);
+        return out.toByteArray();
+      }
+    }
+
+    /**
+     * Returns the response as a character stream decoded with the charset
+     * of the Content-Type header. If that header is either absent or lacks a
+     * charset, this will attempt to decode the response body as UTF-8.
+     */
+    public final Reader charStream() throws IOException {
+      if (reader == null) {
+        reader = new InputStreamReader(byteStream(), charset());
+      }
+      return reader;
+    }
+
+    /**
+     * Returns the response as a string decoded with the charset of the
+     * Content-Type header. If that header is either absent or lacks a charset,
+     * this will attempt to decode the response body as UTF-8.
+     */
+    public final String string() throws IOException {
+      return new String(bytes(), charset().name());
+    }
+
+    private Charset charset() {
+      MediaType contentType = contentType();
+      return contentType != null ? contentType.charset(UTF_8) : UTF_8;
+    }
+  }
+
+  public interface Receiver {
+    /**
+     * Called when the request could not be executed due to a connectivity
+     * problem or timeout. Because networks can fail during an exchange, it is
+     * possible that the remote server accepted the request before the failure.
+     */
+    void onFailure(Failure failure);
+
+    /**
+     * Called when the HTTP response was successfully returned by the remote
+     * server. The receiver may proceed to read the response body with the
+     * response's {@link #body} method.
+     *
+     * <p>Note that transport-layer success (receiving a HTTP response code,
+     * headers and body) does not necessarily indicate application-layer
+     * success: {@code response} may still indicate an unhappy HTTP response
+     * code like 404 or 500.
+     *
+     * <h3>Non-blocking responses</h3>
+     *
+     * <p>Receivers do not need to block while waiting for the response body to
+     * download. Instead, they can get called back as data arrives. Use {@link
+     * Body#ready} to check if bytes should be read immediately. While there is
+     * data ready, read it. If there isn't, return false: receivers will be
+     * called back with {@code onResponse()} as additional data is downloaded.
+     *
+     * <p>Return true to indicate that the receiver has finished handling the
+     * response body. If the response body has unread data, it will be
+     * discarded.
+     *
+     * <p>When the response body has been fully consumed the returned value is
+     * undefined.
+     *
+     * <p>The current implementation of {@link Body#ready} always returns true
+     * when the underlying transport is HTTP/1. This results in blocking on that
+     * transport. For effective non-blocking your server must support SPDY or
+     * HTTP/2.
+     */
+    boolean onResponse(Response response) throws IOException;
+  }
+
+  public static class Builder {
+    private final Request request;
+    private final int code;
+    private RawHeaders headers = new RawHeaders();
+    private Body body;
+    private Response redirectedBy;
+
+    public Builder(Request request, int code) {
+      if (request == null) throw new IllegalArgumentException("request == null");
+      if (code <= 0) throw new IllegalArgumentException("code <= 0");
+      this.request = request;
+      this.code = code;
+    }
+
+    /**
+     * Sets the header named {@code name} to {@code value}. If this request
+     * already has any headers with that name, they are all replaced.
+     */
+    public Builder header(String name, String value) {
+      headers.set(name, value);
+      return this;
+    }
+
+    /**
+     * Adds a header with {@code name} and {@code value}. Prefer this method for
+     * multiply-valued headers like "Set-Cookie".
+     */
+    public Builder addHeader(String name, String value) {
+      headers.add(name, value);
+      return this;
+    }
+
+    Builder rawHeaders(RawHeaders rawHeaders) {
+      headers = new RawHeaders(rawHeaders);
+      return this;
+    }
+
+    public Builder body(Body body) {
+      this.body = body;
+      return this;
+    }
+
+    public Builder redirectedBy(Response redirectedBy) {
+      this.redirectedBy = redirectedBy;
+      return this;
+    }
+
+    public Response build() {
+      if (request == null) throw new IllegalStateException("Response has no request.");
+      if (code == -1) throw new IllegalStateException("Response has no code.");
+      return new Response(this);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/ResponseSource.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/ResponseSource.java b/framework/src/com/squareup/okhttp/ResponseSource.java
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/Route.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/Route.java b/framework/src/com/squareup/okhttp/Route.java
old mode 100644
new mode 100755
index 6968c60..4b8786d
--- a/framework/src/com/squareup/okhttp/Route.java
+++ b/framework/src/com/squareup/okhttp/Route.java
@@ -59,13 +59,13 @@ public class Route {
     return inetSocketAddress;
   }
 
-  /** Returns true if this route uses modern tls. */
+  /** Returns true if this route uses modern TLS. */
   public boolean isModernTls() {
     return modernTls;
   }
 
-  /** Returns a copy of this route with flipped tls mode. */
-  public Route flipTlsMode() {
+  /** Returns a copy of this route with flipped TLS mode. */
+  Route flipTlsMode() {
     return new Route(address, proxy, inetSocketAddress, !modernTls);
   }
 

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/RouteDatabase.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/RouteDatabase.java b/framework/src/com/squareup/okhttp/RouteDatabase.java
new file mode 100755
index 0000000..9cbeaa7
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/RouteDatabase.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.net.ssl.SSLHandshakeException;
+
+/**
+ * A blacklist of failed routes to avoid when creating a new connection to a
+ * target address. This is used so that OkHttp can learn from its mistakes: if
+ * there was a failure attempting to connect to a specific IP address, proxy
+ * server or TLS mode, that failure is remembered and alternate routes are
+ * preferred.
+ */
+public final class RouteDatabase {
+  private final Set<Route> failedRoutes = new LinkedHashSet<Route>();
+
+  /** Records a failure connecting to {@code failedRoute}. */
+  public synchronized void failed(Route failedRoute, IOException failure) {
+    failedRoutes.add(failedRoute);
+
+    if (!(failure instanceof SSLHandshakeException)) {
+      // If the problem was not related to SSL then it will also fail with
+      // a different TLS mode therefore we can be proactive about it.
+      failedRoutes.add(failedRoute.flipTlsMode());
+    }
+  }
+
+  /** Records success connecting to {@code failedRoute}. */
+  public synchronized void connected(Route route) {
+    failedRoutes.remove(route);
+  }
+
+  /** Returns true if {@code route} has failed recently and should be avoided. */
+  public synchronized boolean shouldPostpone(Route route) {
+    return failedRoutes.contains(route);
+  }
+
+  public synchronized int failedRoutesCount() {
+    return failedRoutes.size();
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/TunnelRequest.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/TunnelRequest.java b/framework/src/com/squareup/okhttp/TunnelRequest.java
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/internal/AbstractOutputStream.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/AbstractOutputStream.java b/framework/src/com/squareup/okhttp/internal/AbstractOutputStream.java
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/internal/Base64.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/Base64.java b/framework/src/com/squareup/okhttp/internal/Base64.java
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/internal/DiskLruCache.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/DiskLruCache.java b/framework/src/com/squareup/okhttp/internal/DiskLruCache.java
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/internal/Dns.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/Dns.java b/framework/src/com/squareup/okhttp/internal/Dns.java
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/internal/FaultRecoveringOutputStream.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/FaultRecoveringOutputStream.java b/framework/src/com/squareup/okhttp/internal/FaultRecoveringOutputStream.java
old mode 100644
new mode 100755

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e16cab6b/framework/src/com/squareup/okhttp/internal/NamedRunnable.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/NamedRunnable.java b/framework/src/com/squareup/okhttp/internal/NamedRunnable.java
old mode 100644
new mode 100755
index ce430b2..992b2ae
--- a/framework/src/com/squareup/okhttp/internal/NamedRunnable.java
+++ b/framework/src/com/squareup/okhttp/internal/NamedRunnable.java
@@ -20,10 +20,10 @@ package com.squareup.okhttp.internal;
  * Runnable implementation which always sets its thread name.
  */
 public abstract class NamedRunnable implements Runnable {
-  private String name;
+  private final String name;
 
-  public NamedRunnable(String name) {
-    this.name = name;
+  public NamedRunnable(String format, Object... args) {
+    this.name = String.format(format, args);
   }
 
   @Override public final void run() {


Mime
View raw message