You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by na...@apache.org on 2014/02/03 19:37:26 UTC
[13/33] git commit: CB-5799 Update version of OkHTTP to 1.3
CB-5799 Update version of OkHTTP to 1.3
Project: http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/commit/185547ef
Tree: http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/tree/185547ef
Diff: http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/diff/185547ef
Branch: refs/heads/master
Commit: 185547ef152ddc6359e843c3e1c49fb34b3fb935
Parents: 7996e04
Author: Andrew Grieve <ag...@chromium.org>
Authored: Wed Jan 15 11:36:18 2014 -0500
Committer: Archana Naik <na...@lab126.com>
Committed: Fri Jan 31 14:55:54 2014 -0800
----------------------------------------------------------------------
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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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-amazon-fireos/blob/185547ef/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