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:24 UTC
[11/33] CB-5799 Update version of OkHTTP to 1.3
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/HttpsEngine.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/HttpsEngine.java b/framework/src/com/squareup/okhttp/internal/http/HttpsEngine.java
new file mode 100755
index 0000000..2bc1d68
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/http/HttpsEngine.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.squareup.okhttp.internal.http;
+
+import com.squareup.okhttp.Connection;
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.TunnelRequest;
+import java.io.IOException;
+import java.net.CacheResponse;
+import java.net.SecureCacheResponse;
+import java.net.URL;
+import javax.net.ssl.SSLSocket;
+
+import static com.squareup.okhttp.internal.Util.getEffectivePort;
+
+public final class HttpsEngine extends HttpEngine {
+ /**
+ * Stash of HttpsEngine.connection.socket to implement requests like {@code
+ * HttpsURLConnection#getCipherSuite} even after the connection has been
+ * recycled.
+ */
+ private SSLSocket sslSocket;
+
+ public HttpsEngine(OkHttpClient client, Policy policy, String method, RawHeaders requestHeaders,
+ Connection connection, RetryableOutputStream requestBody) throws IOException {
+ super(client, policy, method, requestHeaders, connection, requestBody);
+ this.sslSocket = connection != null ? (SSLSocket) connection.getSocket() : null;
+ }
+
+ @Override protected void connected(Connection connection) {
+ this.sslSocket = (SSLSocket) connection.getSocket();
+ super.connected(connection);
+ }
+
+ @Override protected boolean acceptCacheResponseType(CacheResponse cacheResponse) {
+ return cacheResponse instanceof SecureCacheResponse;
+ }
+
+ @Override protected boolean includeAuthorityInRequestLine() {
+ // Even if there is a proxy, it isn't involved. Always request just the path.
+ return false;
+ }
+
+ public SSLSocket getSslSocket() {
+ return sslSocket;
+ }
+
+ @Override protected TunnelRequest getTunnelConfig() {
+ String userAgent = requestHeaders.getUserAgent();
+ if (userAgent == null) {
+ userAgent = getDefaultUserAgent();
+ }
+
+ URL url = policy.getURL();
+ return new TunnelRequest(url.getHost(), getEffectivePort(url), userAgent,
+ requestHeaders.getProxyAuthorization());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java b/framework/src/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java
old mode 100644
new mode 100755
index 235f862..e64fb98
--- a/framework/src/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java
+++ b/framework/src/com/squareup/okhttp/internal/http/HttpsURLConnectionImpl.java
@@ -16,14 +16,11 @@
*/
package com.squareup.okhttp.internal.http;
-import com.squareup.okhttp.Connection;
+import android.annotation.SuppressLint;
import com.squareup.okhttp.OkHttpClient;
-import com.squareup.okhttp.Route;
-import com.squareup.okhttp.TunnelRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.CacheResponse;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.SecureCacheResponse;
@@ -33,24 +30,20 @@ import java.security.Principal;
import java.security.cert.Certificate;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
-import static com.squareup.okhttp.internal.Util.getEffectivePort;
-
public final class HttpsURLConnectionImpl extends HttpsURLConnection {
/** HttpUrlConnectionDelegate allows reuse of HttpURLConnectionImpl. */
private final HttpUrlConnectionDelegate delegate;
- public HttpsURLConnectionImpl(URL url, OkHttpClient client, OkResponseCache responseCache,
- Set<Route> failedRoutes) {
+ public HttpsURLConnectionImpl(URL url, OkHttpClient client) {
super(url);
- delegate = new HttpUrlConnectionDelegate(url, client, responseCache, failedRoutes);
+ delegate = new HttpUrlConnectionDelegate(url, client);
}
@Override public String getCipherSuite() {
@@ -120,294 +113,247 @@ public final class HttpsURLConnectionImpl extends HttpsURLConnection {
}
private SSLSocket getSslSocket() {
- if (delegate.httpEngine == null || delegate.httpEngine.sentRequestMillis == -1) {
+ if (delegate.httpEngine == null || !delegate.httpEngine.connected) {
throw new IllegalStateException("Connection has not yet been established");
}
return delegate.httpEngine instanceof HttpsEngine
- ? ((HttpsEngine) delegate.httpEngine).sslSocket
+ ? ((HttpsEngine) delegate.httpEngine).getSslSocket()
: null; // Not HTTPS! Probably an https:// to http:// redirect.
}
- @Override
- public void disconnect() {
+ @Override public void disconnect() {
delegate.disconnect();
}
- @Override
- public InputStream getErrorStream() {
+ @Override public InputStream getErrorStream() {
return delegate.getErrorStream();
}
- @Override
- public String getRequestMethod() {
+ @Override public String getRequestMethod() {
return delegate.getRequestMethod();
}
- @Override
- public int getResponseCode() throws IOException {
+ @Override public int getResponseCode() throws IOException {
return delegate.getResponseCode();
}
- @Override
- public String getResponseMessage() throws IOException {
+ @Override public String getResponseMessage() throws IOException {
return delegate.getResponseMessage();
}
- @Override
- public void setRequestMethod(String method) throws ProtocolException {
+ @Override public void setRequestMethod(String method) throws ProtocolException {
delegate.setRequestMethod(method);
}
- @Override
- public boolean usingProxy() {
+ @Override public boolean usingProxy() {
return delegate.usingProxy();
}
- @Override
- public boolean getInstanceFollowRedirects() {
+ @Override public boolean getInstanceFollowRedirects() {
return delegate.getInstanceFollowRedirects();
}
- @Override
- public void setInstanceFollowRedirects(boolean followRedirects) {
+ @Override public void setInstanceFollowRedirects(boolean followRedirects) {
delegate.setInstanceFollowRedirects(followRedirects);
}
- @Override
- public void connect() throws IOException {
+ @Override public void connect() throws IOException {
connected = true;
delegate.connect();
}
- @Override
- public boolean getAllowUserInteraction() {
+ @Override public boolean getAllowUserInteraction() {
return delegate.getAllowUserInteraction();
}
- @Override
- public Object getContent() throws IOException {
+ @Override public Object getContent() throws IOException {
return delegate.getContent();
}
@SuppressWarnings("unchecked") // Spec does not generify
- @Override
- public Object getContent(Class[] types) throws IOException {
+ @Override public Object getContent(Class[] types) throws IOException {
return delegate.getContent(types);
}
- @Override
- public String getContentEncoding() {
+ @Override public String getContentEncoding() {
return delegate.getContentEncoding();
}
- @Override
- public int getContentLength() {
+ @Override public int getContentLength() {
return delegate.getContentLength();
}
- @Override
- public String getContentType() {
+ @Override public String getContentType() {
return delegate.getContentType();
}
- @Override
- public long getDate() {
+ @Override public long getDate() {
return delegate.getDate();
}
- @Override
- public boolean getDefaultUseCaches() {
+ @Override public boolean getDefaultUseCaches() {
return delegate.getDefaultUseCaches();
}
- @Override
- public boolean getDoInput() {
+ @Override public boolean getDoInput() {
return delegate.getDoInput();
}
- @Override
- public boolean getDoOutput() {
+ @Override public boolean getDoOutput() {
return delegate.getDoOutput();
}
- @Override
- public long getExpiration() {
+ @Override public long getExpiration() {
return delegate.getExpiration();
}
- @Override
- public String getHeaderField(int pos) {
+ @Override public String getHeaderField(int pos) {
return delegate.getHeaderField(pos);
}
- @Override
- public Map<String, List<String>> getHeaderFields() {
+ @Override public Map<String, List<String>> getHeaderFields() {
return delegate.getHeaderFields();
}
- @Override
- public Map<String, List<String>> getRequestProperties() {
+ @Override public Map<String, List<String>> getRequestProperties() {
return delegate.getRequestProperties();
}
- @Override
- public void addRequestProperty(String field, String newValue) {
+ @Override public void addRequestProperty(String field, String newValue) {
delegate.addRequestProperty(field, newValue);
}
- @Override
- public String getHeaderField(String key) {
+ @Override public String getHeaderField(String key) {
return delegate.getHeaderField(key);
}
- @Override
- public long getHeaderFieldDate(String field, long defaultValue) {
+ @Override public long getHeaderFieldDate(String field, long defaultValue) {
return delegate.getHeaderFieldDate(field, defaultValue);
}
- @Override
- public int getHeaderFieldInt(String field, int defaultValue) {
+ @Override public int getHeaderFieldInt(String field, int defaultValue) {
return delegate.getHeaderFieldInt(field, defaultValue);
}
- @Override
- public String getHeaderFieldKey(int position) {
+ @Override public String getHeaderFieldKey(int position) {
return delegate.getHeaderFieldKey(position);
}
- @Override
- public long getIfModifiedSince() {
+ @Override public long getIfModifiedSince() {
return delegate.getIfModifiedSince();
}
- @Override
- public InputStream getInputStream() throws IOException {
+ @Override public InputStream getInputStream() throws IOException {
return delegate.getInputStream();
}
- @Override
- public long getLastModified() {
+ @Override public long getLastModified() {
return delegate.getLastModified();
}
- @Override
- public OutputStream getOutputStream() throws IOException {
+ @Override public OutputStream getOutputStream() throws IOException {
return delegate.getOutputStream();
}
- @Override
- public Permission getPermission() throws IOException {
+ @Override public Permission getPermission() throws IOException {
return delegate.getPermission();
}
- @Override
- public String getRequestProperty(String field) {
+ @Override public String getRequestProperty(String field) {
return delegate.getRequestProperty(field);
}
- @Override
- public URL getURL() {
+ @Override public URL getURL() {
return delegate.getURL();
}
- @Override
- public boolean getUseCaches() {
+ @Override public boolean getUseCaches() {
return delegate.getUseCaches();
}
- @Override
- public void setAllowUserInteraction(boolean newValue) {
+ @Override public void setAllowUserInteraction(boolean newValue) {
delegate.setAllowUserInteraction(newValue);
}
- @Override
- public void setDefaultUseCaches(boolean newValue) {
+ @Override public void setDefaultUseCaches(boolean newValue) {
delegate.setDefaultUseCaches(newValue);
}
- @Override
- public void setDoInput(boolean newValue) {
+ @Override public void setDoInput(boolean newValue) {
delegate.setDoInput(newValue);
}
- @Override
- public void setDoOutput(boolean newValue) {
+ @Override public void setDoOutput(boolean newValue) {
delegate.setDoOutput(newValue);
}
- @Override
- public void setIfModifiedSince(long newValue) {
+ @Override public void setIfModifiedSince(long newValue) {
delegate.setIfModifiedSince(newValue);
}
- @Override
- public void setRequestProperty(String field, String newValue) {
+ @Override public void setRequestProperty(String field, String newValue) {
delegate.setRequestProperty(field, newValue);
}
- @Override
- public void setUseCaches(boolean newValue) {
+ @Override public void setUseCaches(boolean newValue) {
delegate.setUseCaches(newValue);
}
- @Override
- public void setConnectTimeout(int timeoutMillis) {
+ @Override public void setConnectTimeout(int timeoutMillis) {
delegate.setConnectTimeout(timeoutMillis);
}
- @Override
- public int getConnectTimeout() {
+ @Override public int getConnectTimeout() {
return delegate.getConnectTimeout();
}
- @Override
- public void setReadTimeout(int timeoutMillis) {
+ @Override public void setReadTimeout(int timeoutMillis) {
delegate.setReadTimeout(timeoutMillis);
}
- @Override
- public int getReadTimeout() {
+ @Override public int getReadTimeout() {
return delegate.getReadTimeout();
}
- @Override
- public String toString() {
+ @Override public String toString() {
return delegate.toString();
}
- @Override
- public void setFixedLengthStreamingMode(int contentLength) {
+ @Override public void setFixedLengthStreamingMode(int contentLength) {
delegate.setFixedLengthStreamingMode(contentLength);
}
- @Override
- public void setChunkedStreamingMode(int chunkLength) {
+ @Override public void setChunkedStreamingMode(int chunkLength) {
delegate.setChunkedStreamingMode(chunkLength);
}
@Override public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
- delegate.hostnameVerifier = hostnameVerifier;
+ delegate.client.setHostnameVerifier(hostnameVerifier);
}
@Override public HostnameVerifier getHostnameVerifier() {
- return delegate.hostnameVerifier;
+ return delegate.client.getHostnameVerifier();
}
@Override public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) {
- delegate.sslSocketFactory = sslSocketFactory;
+ delegate.client.setSslSocketFactory(sslSocketFactory);
}
@Override public SSLSocketFactory getSSLSocketFactory() {
- return delegate.sslSocketFactory;
+ return delegate.client.getSslSocketFactory();
+ }
+
+ @SuppressLint("NewApi")
+ @Override public void setFixedLengthStreamingMode(long contentLength) {
+ delegate.setFixedLengthStreamingMode(contentLength);
}
private final class HttpUrlConnectionDelegate extends HttpURLConnectionImpl {
- private HttpUrlConnectionDelegate(URL url, OkHttpClient client, OkResponseCache responseCache,
- Set<Route> failedRoutes) {
- super(url, client, responseCache, failedRoutes);
+ private HttpUrlConnectionDelegate(URL url, OkHttpClient client) {
+ super(url, client);
}
- @Override protected HttpURLConnection getHttpConnectionToCache() {
+ @Override public HttpURLConnection getHttpConnectionToCache() {
return HttpsURLConnectionImpl.this;
}
@@ -417,45 +363,4 @@ public final class HttpsURLConnectionImpl extends HttpsURLConnection {
: null;
}
}
-
- public static final class HttpsEngine extends HttpEngine {
- /**
- * Stash of HttpsEngine.connection.socket to implement requests like
- * {@link #getCipherSuite} even after the connection has been recycled.
- */
- private SSLSocket sslSocket;
-
- /**
- * @param policy the HttpURLConnectionImpl with connection configuration
- */
- public HttpsEngine(HttpURLConnectionImpl policy, String method, RawHeaders requestHeaders,
- Connection connection, RetryableOutputStream requestBody) throws IOException {
- super(policy, method, requestHeaders, connection, requestBody);
- this.sslSocket = connection != null ? (SSLSocket) connection.getSocket() : null;
- }
-
- @Override protected void connected(Connection connection) {
- this.sslSocket = (SSLSocket) connection.getSocket();
- }
-
- @Override protected boolean acceptCacheResponseType(CacheResponse cacheResponse) {
- return cacheResponse instanceof SecureCacheResponse;
- }
-
- @Override protected boolean includeAuthorityInRequestLine() {
- // Even if there is a proxy, it isn't involved. Always request just the file.
- return false;
- }
-
- @Override protected TunnelRequest getTunnelConfig() {
- String userAgent = requestHeaders.getUserAgent();
- if (userAgent == null) {
- userAgent = getDefaultUserAgent();
- }
-
- URL url = policy.getURL();
- return new TunnelRequest(url.getHost(), getEffectivePort(url), userAgent,
- requestHeaders.getProxyAuthorization());
- }
- }
}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/OkResponseCache.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/OkResponseCache.java b/framework/src/com/squareup/okhttp/internal/http/OkResponseCache.java
deleted file mode 100644
index 5829f02..0000000
--- a/framework/src/com/squareup/okhttp/internal/http/OkResponseCache.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2013 Square, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.squareup.okhttp.internal.http;
-
-import com.squareup.okhttp.ResponseSource;
-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;
-
-/**
- * An extended response cache API. Unlike {@link java.net.ResponseCache}, this
- * interface supports conditional caching and statistics.
- *
- * <p>Along with the rest of the {@code internal} package, this is not a public
- * API. Applications wishing to supply their own caches must use the more
- * limited {@link java.net.ResponseCache} interface.
- */
-public interface OkResponseCache {
- CacheResponse get(URI uri, String requestMethod, Map<String, List<String>> requestHeaders)
- throws IOException;
-
- CacheRequest put(URI uri, URLConnection urlConnection) 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();
-
- /** 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/internal/http/OkResponseCacheAdapter.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/OkResponseCacheAdapter.java b/framework/src/com/squareup/okhttp/internal/http/OkResponseCacheAdapter.java
old mode 100644
new mode 100755
index 2ac915a..5335c2b
--- a/framework/src/com/squareup/okhttp/internal/http/OkResponseCacheAdapter.java
+++ b/framework/src/com/squareup/okhttp/internal/http/OkResponseCacheAdapter.java
@@ -15,6 +15,7 @@
*/
package com.squareup.okhttp.internal.http;
+import com.squareup.okhttp.OkResponseCache;
import com.squareup.okhttp.ResponseSource;
import java.io.IOException;
import java.net.CacheRequest;
@@ -41,6 +42,9 @@ public final class OkResponseCacheAdapter implements OkResponseCache {
return responseCache.put(uri, urlConnection);
}
+ @Override public void maybeRemove(String requestMethod, URI uri) throws IOException {
+ }
+
@Override public void update(CacheResponse conditionalCacheHit, HttpURLConnection connection)
throws IOException {
}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/Policy.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/Policy.java b/framework/src/com/squareup/okhttp/internal/http/Policy.java
new file mode 100755
index 0000000..0a29d4b
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/http/Policy.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.squareup.okhttp.internal.http;
+
+import java.net.HttpURLConnection;
+import java.net.Proxy;
+import java.net.URL;
+
+public interface Policy {
+ /** Returns true if HTTP response caches should be used. */
+ boolean getUseCaches();
+
+ /** Returns the HttpURLConnection instance to store in the cache. */
+ HttpURLConnection getHttpConnectionToCache();
+
+ /** Returns the current destination URL, possibly a redirect. */
+ URL getURL();
+
+ /** Returns the If-Modified-Since timestamp, or 0 if none is set. */
+ long getIfModifiedSince();
+
+ /** Returns true if a non-direct proxy is specified. */
+ boolean usingProxy();
+
+ /** @see java.net.HttpURLConnection#setChunkedStreamingMode(int) */
+ int getChunkLength();
+
+ /** @see java.net.HttpURLConnection#setFixedLengthStreamingMode(int) */
+ long getFixedContentLength();
+
+ /**
+ * Sets the current proxy that this connection is using.
+ * @see java.net.HttpURLConnection#usingProxy
+ */
+ void setSelectedProxy(Proxy proxy);
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/RawHeaders.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/RawHeaders.java b/framework/src/com/squareup/okhttp/internal/http/RawHeaders.java
old mode 100644
new mode 100755
index eba887e..8b45320
--- a/framework/src/com/squareup/okhttp/internal/http/RawHeaders.java
+++ b/framework/src/com/squareup/okhttp/internal/http/RawHeaders.java
@@ -32,6 +32,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
+import java.util.TreeSet;
/**
* The HTTP status and unparsed header fields of a single HTTP message. Values
@@ -122,23 +123,6 @@ public final class RawHeaders {
this.httpMinorVersion = httpMinorVersion;
}
- public void computeResponseStatusLineFromSpdyHeaders() throws IOException {
- String status = null;
- String version = null;
- for (int i = 0; i < namesAndValues.size(); i += 2) {
- String name = namesAndValues.get(i);
- if (":status".equals(name)) {
- status = namesAndValues.get(i + 1);
- } else if (":version".equals(name)) {
- version = namesAndValues.get(i + 1);
- }
- }
- if (status == null || version == null) {
- throw new ProtocolException("Expected ':status' and ':version' headers not present");
- }
- setStatusLine(version + " " + status);
- }
-
/**
* @param method like "GET", "POST", "HEAD", etc.
* @param path like "/foo/bar.html"
@@ -180,14 +164,17 @@ public final class RawHeaders {
/**
* Add an HTTP header line containing a field name, a literal colon, and a
- * value.
+ * value. This works around empty header names and header names that start
+ * with a colon (created by old broken SPDY versions of the response cache).
*/
public void addLine(String line) {
- int index = line.indexOf(":");
- if (index == -1) {
- addLenient("", line);
- } else {
+ int index = line.indexOf(":", 1);
+ if (index != -1) {
addLenient(line.substring(0, index), line.substring(index + 1));
+ } else if (line.startsWith(":")) {
+ addLenient("", line.substring(1)); // Empty header name.
+ } else {
+ addLenient("", line); // No header name.
}
}
@@ -248,6 +235,15 @@ public final class RawHeaders {
return namesAndValues.get(fieldNameIndex);
}
+ /** Returns an immutable case-insensitive set of header names. */
+ public Set<String> names() {
+ TreeSet<String> result = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+ for (int i = 0; i < length(); i++) {
+ result.add(getFieldName(i));
+ }
+ return Collections.unmodifiableSet(result);
+ }
+
/** Returns the value at {@code index} or null if that is out of range. */
public String getValue(int index) {
int valueIndex = index * 2 + 1;
@@ -267,6 +263,20 @@ public final class RawHeaders {
return null;
}
+ /** Returns an immutable list of the header values for {@code name}. */
+ public List<String> values(String name) {
+ List<String> result = null;
+ for (int i = 0; i < length(); i++) {
+ if (name.equalsIgnoreCase(getFieldName(i))) {
+ if (result == null) result = new ArrayList<String>(2);
+ result.add(getValue(i));
+ }
+ }
+ return result != null
+ ? Collections.unmodifiableList(result)
+ : Collections.<String>emptyList();
+ }
+
/** @param fieldNames a case-insensitive set of HTTP header field names. */
public RawHeaders getAll(Set<String> fieldNames) {
RawHeaders result = new RawHeaders();
@@ -401,10 +411,13 @@ public final class RawHeaders {
return result;
}
- public static RawHeaders fromNameValueBlock(List<String> nameValueBlock) {
+ /** Returns headers for a name value block containing a SPDY response. */
+ public static RawHeaders fromNameValueBlock(List<String> nameValueBlock) throws IOException {
if (nameValueBlock.size() % 2 != 0) {
throw new IllegalArgumentException("Unexpected name value block: " + nameValueBlock);
}
+ String status = null;
+ String version = null;
RawHeaders result = new RawHeaders();
for (int i = 0; i < nameValueBlock.size(); i += 2) {
String name = nameValueBlock.get(i);
@@ -414,11 +427,21 @@ public final class RawHeaders {
if (end == -1) {
end = values.length();
}
- result.namesAndValues.add(name);
- result.namesAndValues.add(values.substring(start, end));
+ String value = values.substring(start, end);
+ if (":status".equals(name)) {
+ status = value;
+ } else if (":version".equals(name)) {
+ version = value;
+ } else {
+ result.namesAndValues.add(name);
+ result.namesAndValues.add(value);
+ }
start = end + 1;
}
}
+ if (status == null) throw new ProtocolException("Expected ':status' header not present");
+ if (version == null) throw new ProtocolException("Expected ':version' header not present");
+ result.setStatusLine(version + " " + status);
return result;
}
}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/RequestHeaders.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/RequestHeaders.java b/framework/src/com/squareup/okhttp/internal/http/RequestHeaders.java
old mode 100644
new mode 100755
index 5ec4fcc..71c3cd0
--- a/framework/src/com/squareup/okhttp/internal/http/RequestHeaders.java
+++ b/framework/src/com/squareup/okhttp/internal/http/RequestHeaders.java
@@ -48,7 +48,7 @@ public final class RequestHeaders {
*/
private boolean hasAuthorization;
- private int contentLength = -1;
+ private long contentLength = -1;
private String transferEncoding;
private String userAgent;
private String host;
@@ -157,7 +157,7 @@ public final class RequestHeaders {
return hasAuthorization;
}
- public int getContentLength() {
+ public long getContentLength() {
return contentLength;
}
@@ -205,14 +205,26 @@ public final class RequestHeaders {
this.transferEncoding = "chunked";
}
- public void setContentLength(int contentLength) {
+ public void setContentLength(long contentLength) {
if (this.contentLength != -1) {
headers.removeAll("Content-Length");
}
- headers.add("Content-Length", Integer.toString(contentLength));
+ headers.add("Content-Length", Long.toString(contentLength));
this.contentLength = contentLength;
}
+ /**
+ * Remove the Content-Length headers. Call this when dropping the body on a
+ * request or response, such as when a redirect changes the method from POST
+ * to GET.
+ */
+ public void removeContentLength() {
+ if (contentLength != -1) {
+ headers.removeAll("Content-Length");
+ contentLength = -1;
+ }
+ }
+
public void setUserAgent(String userAgent) {
if (this.userAgent != null) {
headers.removeAll("User-Agent");
@@ -282,9 +294,24 @@ public final class RequestHeaders {
public void addCookies(Map<String, List<String>> allCookieHeaders) {
for (Map.Entry<String, List<String>> entry : allCookieHeaders.entrySet()) {
String key = entry.getKey();
- if ("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key)) {
- headers.addAll(key, entry.getValue());
+ if (("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key))
+ && !entry.getValue().isEmpty()) {
+ headers.add(key, buildCookieHeader(entry.getValue()));
}
}
}
+
+ /**
+ * Send all cookies in one big header, as recommended by
+ * <a href="http://tools.ietf.org/html/rfc6265#section-4.2.1">RFC 6265</a>.
+ */
+ private String buildCookieHeader(List<String> cookies) {
+ if (cookies.size() == 1) return cookies.get(0);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < cookies.size(); i++) {
+ if (i > 0) sb.append("; ");
+ sb.append(cookies.get(i));
+ }
+ return sb.toString();
+ }
}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/ResponseHeaders.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/ResponseHeaders.java b/framework/src/com/squareup/okhttp/internal/http/ResponseHeaders.java
old mode 100644
new mode 100755
index 2ab564d..69e8656
--- a/framework/src/com/squareup/okhttp/internal/http/ResponseHeaders.java
+++ b/framework/src/com/squareup/okhttp/internal/http/ResponseHeaders.java
@@ -17,6 +17,7 @@
package com.squareup.okhttp.internal.http;
import com.squareup.okhttp.ResponseSource;
+import com.squareup.okhttp.internal.Platform;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
@@ -34,13 +35,16 @@ import static com.squareup.okhttp.internal.Util.equal;
public final class ResponseHeaders {
/** HTTP header name for the local time when the request was sent. */
- private static final String SENT_MILLIS = "X-Android-Sent-Millis";
+ private static final String SENT_MILLIS = Platform.get().getPrefix() + "-Sent-Millis";
/** HTTP header name for the local time when the response was received. */
- private static final String RECEIVED_MILLIS = "X-Android-Received-Millis";
+ private static final String RECEIVED_MILLIS = Platform.get().getPrefix() + "-Received-Millis";
/** HTTP synthetic header with the response source. */
- static final String RESPONSE_SOURCE = "X-Android-Response-Source";
+ static final String RESPONSE_SOURCE = Platform.get().getPrefix() + "-Response-Source";
+
+ /** HTTP synthetic header with the selected transport (spdy/3, http/1.1, etc). */
+ static final String SELECTED_TRANSPORT = Platform.get().getPrefix() + "-Selected-Transport";
private final URI uri;
private final RawHeaders headers;
@@ -110,8 +114,9 @@ public final class ResponseHeaders {
private String contentEncoding;
private String transferEncoding;
- private int contentLength = -1;
+ private long contentLength = -1;
private String connection;
+ private String contentType;
public ResponseHeaders(URI uri, RawHeaders headers) {
this.uri = uri;
@@ -168,9 +173,11 @@ public final class ResponseHeaders {
transferEncoding = value;
} else if ("Content-Length".equalsIgnoreCase(fieldName)) {
try {
- contentLength = Integer.parseInt(value);
+ contentLength = Long.parseLong(value);
} catch (NumberFormatException ignored) {
}
+ } else if ("Content-Type".equalsIgnoreCase(fieldName)) {
+ contentType = value;
} else if ("Connection".equalsIgnoreCase(fieldName)) {
connection = value;
} else if (SENT_MILLIS.equalsIgnoreCase(fieldName)) {
@@ -259,10 +266,14 @@ public final class ResponseHeaders {
return contentEncoding;
}
- public int getContentLength() {
+ public long getContentLength() {
return contentLength;
}
+ public String getContentType() {
+ return contentType;
+ }
+
public String getConnection() {
return connection;
}
@@ -278,6 +289,10 @@ public final class ResponseHeaders {
headers.set(RESPONSE_SOURCE, responseSource.toString() + " " + headers.getResponseCode());
}
+ public void setTransport(String transport) {
+ headers.set(SELECTED_TRANSPORT, transport);
+ }
+
/**
* Returns the current age of the response, in milliseconds. The calculation
* is specified by RFC 2616, 13.2.3 Age Calculations.
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/RetryableOutputStream.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/RetryableOutputStream.java b/framework/src/com/squareup/okhttp/internal/http/RetryableOutputStream.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/http/RouteSelector.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/RouteSelector.java b/framework/src/com/squareup/okhttp/internal/http/RouteSelector.java
old mode 100644
new mode 100755
index ce0a71d..1055e4f
--- a/framework/src/com/squareup/okhttp/internal/http/RouteSelector.java
+++ b/framework/src/com/squareup/okhttp/internal/http/RouteSelector.java
@@ -19,6 +19,7 @@ import com.squareup.okhttp.Address;
import com.squareup.okhttp.Connection;
import com.squareup.okhttp.ConnectionPool;
import com.squareup.okhttp.Route;
+import com.squareup.okhttp.RouteDatabase;
import com.squareup.okhttp.internal.Dns;
import java.io.IOException;
import java.net.InetAddress;
@@ -32,8 +33,6 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
-import java.util.Set;
-import javax.net.ssl.SSLHandshakeException;
import static com.squareup.okhttp.internal.Util.getEffectivePort;
@@ -55,7 +54,7 @@ public final class RouteSelector {
private final ProxySelector proxySelector;
private final ConnectionPool pool;
private final Dns dns;
- private final Set<Route> failedRoutes;
+ private final RouteDatabase routeDatabase;
/* The most recently attempted route. */
private Proxy lastProxy;
@@ -78,13 +77,13 @@ public final class RouteSelector {
private final List<Route> postponedRoutes;
public RouteSelector(Address address, URI uri, ProxySelector proxySelector, ConnectionPool pool,
- Dns dns, Set<Route> failedRoutes) {
+ Dns dns, RouteDatabase routeDatabase) {
this.address = address;
this.uri = uri;
this.proxySelector = proxySelector;
this.pool = pool;
this.dns = dns;
- this.failedRoutes = failedRoutes;
+ this.routeDatabase = routeDatabase;
this.postponedRoutes = new LinkedList<Route>();
resetNextProxy(uri, address.getProxy());
@@ -103,11 +102,11 @@ public final class RouteSelector {
*
* @throws NoSuchElementException if there are no more routes to attempt.
*/
- public Connection next() throws IOException {
+ public Connection next(String method) throws IOException {
// Always prefer pooled connections over new connections.
- Connection pooled = pool.get(address);
- if (pooled != null) {
- return pooled;
+ for (Connection pooled; (pooled = pool.get(address)) != null; ) {
+ if (method.equals("GET") || pooled.isReadable()) return pooled;
+ pooled.close();
}
// Compute the next route to attempt.
@@ -128,11 +127,11 @@ public final class RouteSelector {
boolean modernTls = nextTlsMode() == TLS_MODE_MODERN;
Route route = new Route(address, lastProxy, lastInetSocketAddress, modernTls);
- if (failedRoutes.contains(route)) {
+ if (routeDatabase.shouldPostpone(route)) {
postponedRoutes.add(route);
// We will only recurse in order to skip previously failed routes. They will be
// tried last.
- return next();
+ return next(method);
}
return new Connection(route);
@@ -149,12 +148,7 @@ public final class RouteSelector {
proxySelector.connectFailed(uri, failedRoute.getProxy().address(), 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());
- }
+ routeDatabase.failed(failedRoute, failure);
}
/** Resets {@link #nextProxy} to the first option. */
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/SpdyTransport.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/SpdyTransport.java b/framework/src/com/squareup/okhttp/internal/http/SpdyTransport.java
old mode 100644
new mode 100755
index 18ab566..471539a
--- a/framework/src/com/squareup/okhttp/internal/http/SpdyTransport.java
+++ b/framework/src/com/squareup/okhttp/internal/http/SpdyTransport.java
@@ -16,6 +16,7 @@
package com.squareup.okhttp.internal.http;
+import com.squareup.okhttp.internal.spdy.ErrorCode;
import com.squareup.okhttp.internal.spdy.SpdyConnection;
import com.squareup.okhttp.internal.spdy.SpdyStream;
import java.io.IOException;
@@ -36,6 +37,10 @@ public final class SpdyTransport implements Transport {
}
@Override public OutputStream createRequestBody() throws IOException {
+ long fixedContentLength = httpEngine.policy.getFixedContentLength();
+ if (fixedContentLength != -1) {
+ httpEngine.requestHeaders.setContentLength(fixedContentLength);
+ }
// TODO: if we aren't streaming up to the server, we should buffer the whole request
writeRequestHeaders();
return stream.getOutputStream();
@@ -55,7 +60,7 @@ public final class SpdyTransport implements Transport {
boolean hasResponseBody = true;
stream = spdyConnection.newStream(requestHeaders.toNameValueBlock(), hasRequestBody,
hasResponseBody);
- stream.setReadTimeout(httpEngine.policy.getReadTimeout());
+ stream.setReadTimeout(httpEngine.client.getReadTimeout());
}
@Override public void writeRequestBody(RetryableOutputStream requestBody) throws IOException {
@@ -69,24 +74,26 @@ public final class SpdyTransport implements Transport {
@Override public ResponseHeaders readResponseHeaders() throws IOException {
List<String> nameValueBlock = stream.getResponseHeaders();
RawHeaders rawHeaders = RawHeaders.fromNameValueBlock(nameValueBlock);
- rawHeaders.computeResponseStatusLineFromSpdyHeaders();
httpEngine.receiveHeaders(rawHeaders);
- return new ResponseHeaders(httpEngine.uri, rawHeaders);
+
+ ResponseHeaders headers = new ResponseHeaders(httpEngine.uri, rawHeaders);
+ headers.setTransport("spdy/3");
+ return headers;
}
@Override public InputStream getTransferStream(CacheRequest cacheRequest) throws IOException {
return new UnknownLengthHttpInputStream(stream.getInputStream(), cacheRequest, httpEngine);
}
- @Override public boolean makeReusable(boolean streamCancelled, OutputStream requestBodyOut,
+ @Override public boolean makeReusable(boolean streamCanceled, OutputStream requestBodyOut,
InputStream responseBodyIn) {
- if (streamCancelled) {
+ if (streamCanceled) {
if (stream != null) {
- stream.closeLater(SpdyStream.RST_CANCEL);
+ stream.closeLater(ErrorCode.CANCEL);
return true;
} else {
// If stream is null, it either means that writeRequestHeaders wasn't called
- // or that SpdyConnection#newStream threw an IOEXception. In both cases there's
+ // or that SpdyConnection#newStream threw an IOException. In both cases there's
// nothing to do here and this stream can't be reused.
return false;
}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/Transport.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/Transport.java b/framework/src/com/squareup/okhttp/internal/http/Transport.java
old mode 100644
new mode 100755
index 518827e..d408bfe
--- a/framework/src/com/squareup/okhttp/internal/http/Transport.java
+++ b/framework/src/com/squareup/okhttp/internal/http/Transport.java
@@ -59,6 +59,6 @@ interface Transport {
InputStream getTransferStream(CacheRequest cacheRequest) throws IOException;
/** Returns true if the underlying connection can be recycled. */
- boolean makeReusable(boolean streamReusable, OutputStream requestBodyOut,
+ boolean makeReusable(boolean streamCanceled, OutputStream requestBodyOut,
InputStream responseBodyIn);
}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.java b/framework/src/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.java
old mode 100644
new mode 100755
index 729e0b9..ca6bb59
--- a/framework/src/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.java
+++ b/framework/src/com/squareup/okhttp/internal/http/UnknownLengthHttpInputStream.java
@@ -25,9 +25,9 @@ import static com.squareup.okhttp.internal.Util.checkOffsetAndCount;
final class UnknownLengthHttpInputStream extends AbstractHttpInputStream {
private boolean inputExhausted;
- UnknownLengthHttpInputStream(InputStream is, CacheRequest cacheRequest, HttpEngine httpEngine)
+ UnknownLengthHttpInputStream(InputStream in, CacheRequest cacheRequest, HttpEngine httpEngine)
throws IOException {
- super(is, httpEngine, cacheRequest);
+ super(in, httpEngine, cacheRequest);
}
@Override public int read(byte[] buffer, int offset, int count) throws IOException {
@@ -39,7 +39,7 @@ final class UnknownLengthHttpInputStream extends AbstractHttpInputStream {
int read = in.read(buffer, offset, count);
if (read == -1) {
inputExhausted = true;
- endOfInput(false);
+ endOfInput();
return -1;
}
cacheWrite(buffer, offset, read);
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/spdy/ErrorCode.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/ErrorCode.java b/framework/src/com/squareup/okhttp/internal/spdy/ErrorCode.java
new file mode 100755
index 0000000..d3a32e1
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/spdy/ErrorCode.java
@@ -0,0 +1,67 @@
+package com.squareup.okhttp.internal.spdy;
+
+public enum ErrorCode {
+ /** Not an error! For SPDY stream resets, prefer null over NO_ERROR. */
+ NO_ERROR(0, -1, 0),
+
+ PROTOCOL_ERROR(1, 1, 1),
+
+ /** A subtype of PROTOCOL_ERROR used by SPDY. */
+ INVALID_STREAM(1, 2, -1),
+
+ /** A subtype of PROTOCOL_ERROR used by SPDY. */
+ UNSUPPORTED_VERSION(1, 4, -1),
+
+ /** A subtype of PROTOCOL_ERROR used by SPDY. */
+ STREAM_IN_USE(1, 8, -1),
+
+ /** A subtype of PROTOCOL_ERROR used by SPDY. */
+ STREAM_ALREADY_CLOSED(1, 9, -1),
+
+ INTERNAL_ERROR(2, 6, 2),
+
+ FLOW_CONTROL_ERROR(3, 7, -1),
+
+ STREAM_CLOSED(5, -1, -1),
+
+ FRAME_TOO_LARGE(6, 11, -1),
+
+ REFUSED_STREAM(7, 3, -1),
+
+ CANCEL(8, 5, -1),
+
+ COMPRESSION_ERROR(9, -1, -1),
+
+ INVALID_CREDENTIALS(-1, 10, -1);
+
+ public final int httpCode;
+ public final int spdyRstCode;
+ public final int spdyGoAwayCode;
+
+ private ErrorCode(int httpCode, int spdyRstCode, int spdyGoAwayCode) {
+ this.httpCode = httpCode;
+ this.spdyRstCode = spdyRstCode;
+ this.spdyGoAwayCode = spdyGoAwayCode;
+ }
+
+ public static ErrorCode fromSpdy3Rst(int code) {
+ for (ErrorCode errorCode : ErrorCode.values()) {
+ if (errorCode.spdyRstCode == code) return errorCode;
+ }
+ return null;
+ }
+
+ public static ErrorCode fromHttp2(int code) {
+ for (ErrorCode errorCode : ErrorCode.values()) {
+ if (errorCode.httpCode == code) return errorCode;
+ }
+ return null;
+ }
+
+ public static ErrorCode fromSpdyGoAway(int code) {
+ for (ErrorCode errorCode : ErrorCode.values()) {
+ if (errorCode.spdyGoAwayCode == code) return errorCode;
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/spdy/FrameReader.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/FrameReader.java b/framework/src/com/squareup/okhttp/internal/spdy/FrameReader.java
new file mode 100755
index 0000000..1371262
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/spdy/FrameReader.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.squareup.okhttp.internal.spdy;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+/** Reads transport frames for SPDY/3 or HTTP/2.0. */
+public interface FrameReader extends Closeable {
+ void readConnectionHeader() throws IOException;
+ boolean nextFrame(Handler handler) throws IOException;
+
+ public interface Handler {
+ void data(boolean inFinished, int streamId, InputStream in, int length) throws IOException;
+ /**
+ * Create or update incoming headers, creating the corresponding streams
+ * if necessary. Frames that trigger this are SPDY SYN_STREAM, HEADERS, and
+ * SYN_REPLY, and HTTP/2.0 HEADERS and PUSH_PROMISE.
+ *
+ * @param inFinished true if the sender will not send further frames.
+ * @param outFinished true if the receiver should not send further frames.
+ * @param streamId the stream owning these headers.
+ * @param associatedStreamId the stream that triggered the sender to create
+ * this stream.
+ * @param priority or -1 for no priority. For SPDY, priorities range from 0
+ * (highest) thru 7 (lowest). For HTTP/2.0, priorities range from 0
+ * (highest) thru 2**31-1 (lowest).
+ */
+ void headers(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId,
+ int priority, List<String> nameValueBlock, HeadersMode headersMode);
+ void rstStream(int streamId, ErrorCode errorCode);
+ void settings(boolean clearPrevious, Settings settings);
+ void noop();
+ void ping(boolean reply, int payload1, int payload2);
+ void goAway(int lastGoodStreamId, ErrorCode errorCode);
+ void windowUpdate(int streamId, int deltaWindowSize, boolean endFlowControl);
+ void priority(int streamId, int priority);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/spdy/FrameWriter.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/FrameWriter.java b/framework/src/com/squareup/okhttp/internal/spdy/FrameWriter.java
new file mode 100755
index 0000000..354f43d
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/spdy/FrameWriter.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.squareup.okhttp.internal.spdy;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.List;
+
+/** Writes transport frames for SPDY/3 or HTTP/2.0. */
+public interface FrameWriter extends Closeable {
+ /** HTTP/2.0 only. */
+ void connectionHeader() throws IOException;
+
+ /** SPDY/3 only. */
+ void flush() throws IOException;
+ void synStream(boolean outFinished, boolean inFinished, int streamId, int associatedStreamId,
+ int priority, int slot, List<String> nameValueBlock) throws IOException;
+ void synReply(boolean outFinished, int streamId, List<String> nameValueBlock) throws IOException;
+ void headers(int streamId, List<String> nameValueBlock) throws IOException;
+ void rstStream(int streamId, ErrorCode errorCode) throws IOException;
+ void data(boolean outFinished, int streamId, byte[] data) throws IOException;
+ void data(boolean outFinished, int streamId, byte[] data, int offset, int byteCount)
+ throws IOException;
+ void settings(Settings settings) throws IOException;
+ void noop() throws IOException;
+ void ping(boolean reply, int payload1, int payload2) throws IOException;
+ void goAway(int lastGoodStreamId, ErrorCode errorCode) throws IOException;
+ void windowUpdate(int streamId, int deltaWindowSize) throws IOException;
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/spdy/HeadersMode.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/HeadersMode.java b/framework/src/com/squareup/okhttp/internal/spdy/HeadersMode.java
new file mode 100755
index 0000000..e16e176
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/spdy/HeadersMode.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.squareup.okhttp.internal.spdy;
+
+enum HeadersMode {
+ SPDY_SYN_STREAM,
+ SPDY_REPLY,
+ SPDY_HEADERS,
+ HTTP_20_HEADERS;
+
+ /** Returns true if it is an error these headers to create a new stream. */
+ public boolean failIfStreamAbsent() {
+ return this == SPDY_REPLY || this == SPDY_HEADERS;
+ }
+
+ /** Returns true if it is an error these headers to update an existing stream. */
+ public boolean failIfStreamPresent() {
+ return this == SPDY_SYN_STREAM;
+ }
+
+ /**
+ * Returns true if it is an error these headers to be the initial headers of a
+ * response.
+ */
+ public boolean failIfHeadersAbsent() {
+ return this == SPDY_HEADERS;
+ }
+
+ /**
+ * Returns true if it is an error these headers to be update existing headers
+ * of a response.
+ */
+ public boolean failIfHeadersPresent() {
+ return this == SPDY_REPLY;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/spdy/Hpack.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/Hpack.java b/framework/src/com/squareup/okhttp/internal/spdy/Hpack.java
new file mode 100755
index 0000000..c3ca8f1
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/spdy/Hpack.java
@@ -0,0 +1,371 @@
+package com.squareup.okhttp.internal.spdy;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * Read and write HPACK v03.
+ * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-03
+ */
+final class Hpack {
+
+ static class HeaderEntry {
+ private final String name;
+ private final String value;
+
+ HeaderEntry(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ // TODO: This needs to be the length in UTF-8 bytes, not the length in chars.
+ int length() {
+ return 32 + name.length() + value.length();
+ }
+ }
+
+ static final int PREFIX_5_BITS = 0x1f;
+ static final int PREFIX_6_BITS = 0x3f;
+ static final int PREFIX_7_BITS = 0x7f;
+ static final int PREFIX_8_BITS = 0xff;
+
+ static final List<HeaderEntry> INITIAL_CLIENT_TO_SERVER_HEADER_TABLE = Arrays.asList(
+ new HeaderEntry(":scheme", "http"),
+ new HeaderEntry(":scheme", "https"),
+ new HeaderEntry(":host", ""),
+ new HeaderEntry(":path", "/"),
+ new HeaderEntry(":method", "GET"),
+ new HeaderEntry("accept", ""),
+ new HeaderEntry("accept-charset", ""),
+ new HeaderEntry("accept-encoding", ""),
+ new HeaderEntry("accept-language", ""),
+ new HeaderEntry("cookie", ""),
+ new HeaderEntry("if-modified-since", ""),
+ new HeaderEntry("user-agent", ""),
+ new HeaderEntry("referer", ""),
+ new HeaderEntry("authorization", ""),
+ new HeaderEntry("allow", ""),
+ new HeaderEntry("cache-control", ""),
+ new HeaderEntry("connection", ""),
+ new HeaderEntry("content-length", ""),
+ new HeaderEntry("content-type", ""),
+ new HeaderEntry("date", ""),
+ new HeaderEntry("expect", ""),
+ new HeaderEntry("from", ""),
+ new HeaderEntry("if-match", ""),
+ new HeaderEntry("if-none-match", ""),
+ new HeaderEntry("if-range", ""),
+ new HeaderEntry("if-unmodified-since", ""),
+ new HeaderEntry("max-forwards", ""),
+ new HeaderEntry("proxy-authorization", ""),
+ new HeaderEntry("range", ""),
+ new HeaderEntry("via", "")
+ );
+
+ static final List<HeaderEntry> INITIAL_SERVER_TO_CLIENT_HEADER_TABLE = Arrays.asList(
+ new HeaderEntry(":status", "200"),
+ new HeaderEntry("age", ""),
+ new HeaderEntry("cache-control", ""),
+ new HeaderEntry("content-length", ""),
+ new HeaderEntry("content-type", ""),
+ new HeaderEntry("date", ""),
+ new HeaderEntry("etag", ""),
+ new HeaderEntry("expires", ""),
+ new HeaderEntry("last-modified", ""),
+ new HeaderEntry("server", ""),
+ new HeaderEntry("set-cookie", ""),
+ new HeaderEntry("vary", ""),
+ new HeaderEntry("via", ""),
+ new HeaderEntry("access-control-allow-origin", ""),
+ new HeaderEntry("accept-ranges", ""),
+ new HeaderEntry("allow", ""),
+ new HeaderEntry("connection", ""),
+ new HeaderEntry("content-disposition", ""),
+ new HeaderEntry("content-encoding", ""),
+ new HeaderEntry("content-language", ""),
+ new HeaderEntry("content-location", ""),
+ new HeaderEntry("content-range", ""),
+ new HeaderEntry("link", ""),
+ new HeaderEntry("location", ""),
+ new HeaderEntry("proxy-authenticate", ""),
+ new HeaderEntry("refresh", ""),
+ new HeaderEntry("retry-after", ""),
+ new HeaderEntry("strict-transport-security", ""),
+ new HeaderEntry("transfer-encoding", ""),
+ new HeaderEntry("www-authenticate", "")
+ );
+
+ // Update these when initial tables change to sum of each entry length.
+ static final int INITIAL_CLIENT_TO_SERVER_HEADER_TABLE_LENGTH = 1262;
+ static final int INITIAL_SERVER_TO_CLIENT_HEADER_TABLE_LENGTH = 1304;
+
+ private Hpack() {
+ }
+
+ static class Reader {
+ private final long maxBufferSize = 4096; // TODO: needs to come from settings.
+ private final DataInputStream in;
+
+ private final BitSet referenceSet = new BitSet();
+ private final List<HeaderEntry> headerTable;
+ private final List<String> emittedHeaders = new ArrayList<String>();
+ private long bufferSize = 0;
+ private long bytesLeft = 0;
+
+ Reader(DataInputStream in, boolean client) {
+ this.in = in;
+ if (client) { // we are reading from the server
+ this.headerTable = new ArrayList<HeaderEntry>(INITIAL_SERVER_TO_CLIENT_HEADER_TABLE);
+ this.bufferSize = INITIAL_SERVER_TO_CLIENT_HEADER_TABLE_LENGTH;
+ } else {
+ this.headerTable = new ArrayList<HeaderEntry>(INITIAL_CLIENT_TO_SERVER_HEADER_TABLE);
+ this.bufferSize = INITIAL_CLIENT_TO_SERVER_HEADER_TABLE_LENGTH;
+ }
+ }
+
+ /**
+ * Read {@code byteCount} bytes of headers from the source stream into the
+ * set of emitted headers.
+ */
+ public void readHeaders(int byteCount) throws IOException {
+ bytesLeft += byteCount;
+ // TODO: limit to 'byteCount' bytes?
+
+ while (bytesLeft > 0) {
+ int b = readByte();
+
+ if ((b & 0x80) != 0) {
+ int index = readInt(b, PREFIX_7_BITS);
+ readIndexedHeader(index);
+ } else if (b == 0x60) {
+ readLiteralHeaderWithoutIndexingNewName();
+ } else if ((b & 0xe0) == 0x60) {
+ int index = readInt(b, PREFIX_5_BITS);
+ readLiteralHeaderWithoutIndexingIndexedName(index - 1);
+ } else if (b == 0x40) {
+ readLiteralHeaderWithIncrementalIndexingNewName();
+ } else if ((b & 0xe0) == 0x40) {
+ int index = readInt(b, PREFIX_5_BITS);
+ readLiteralHeaderWithIncrementalIndexingIndexedName(index - 1);
+ } else if (b == 0) {
+ readLiteralHeaderWithSubstitutionIndexingNewName();
+ } else if ((b & 0xc0) == 0) {
+ int index = readInt(b, PREFIX_6_BITS);
+ readLiteralHeaderWithSubstitutionIndexingIndexedName(index - 1);
+ } else {
+ throw new AssertionError();
+ }
+ }
+ }
+
+ public void emitReferenceSet() {
+ for (int i = referenceSet.nextSetBit(0); i != -1; i = referenceSet.nextSetBit(i + 1)) {
+ emittedHeaders.add(getName(i));
+ emittedHeaders.add(getValue(i));
+ }
+ }
+
+ /**
+ * Returns all headers emitted since they were last cleared, then clears the
+ * emitted headers.
+ */
+ public List<String> getAndReset() {
+ List<String> result = new ArrayList<String>(emittedHeaders);
+ emittedHeaders.clear();
+ return result;
+ }
+
+ private void readIndexedHeader(int index) {
+ if (referenceSet.get(index)) {
+ referenceSet.clear(index);
+ } else {
+ referenceSet.set(index);
+ }
+ }
+
+ private void readLiteralHeaderWithoutIndexingIndexedName(int index)
+ throws IOException {
+ String name = getName(index);
+ String value = readString();
+ emittedHeaders.add(name);
+ emittedHeaders.add(value);
+ }
+
+ private void readLiteralHeaderWithoutIndexingNewName()
+ throws IOException {
+ String name = readString();
+ String value = readString();
+ emittedHeaders.add(name);
+ emittedHeaders.add(value);
+ }
+
+ private void readLiteralHeaderWithIncrementalIndexingIndexedName(int nameIndex)
+ throws IOException {
+ String name = getName(nameIndex);
+ String value = readString();
+ int index = headerTable.size(); // append to tail
+ insertIntoHeaderTable(index, new HeaderEntry(name, value));
+ }
+
+ private void readLiteralHeaderWithIncrementalIndexingNewName() throws IOException {
+ String name = readString();
+ String value = readString();
+ int index = headerTable.size(); // append to tail
+ insertIntoHeaderTable(index, new HeaderEntry(name, value));
+ }
+
+ private void readLiteralHeaderWithSubstitutionIndexingIndexedName(int nameIndex)
+ throws IOException {
+ int index = readInt(readByte(), PREFIX_8_BITS);
+ String name = getName(nameIndex);
+ String value = readString();
+ insertIntoHeaderTable(index, new HeaderEntry(name, value));
+ }
+
+ private void readLiteralHeaderWithSubstitutionIndexingNewName() throws IOException {
+ String name = readString();
+ int index = readInt(readByte(), PREFIX_8_BITS);
+ String value = readString();
+ insertIntoHeaderTable(index, new HeaderEntry(name, value));
+ }
+
+ private String getName(int index) {
+ return headerTable.get(index).name;
+ }
+
+ private String getValue(int index) {
+ return headerTable.get(index).value;
+ }
+
+ private void insertIntoHeaderTable(int index, HeaderEntry entry) {
+ int delta = entry.length();
+ if (index != headerTable.size()) {
+ delta -= headerTable.get(index).length();
+ }
+
+ // if the new or replacement header is too big, drop all entries.
+ if (delta > maxBufferSize) {
+ headerTable.clear();
+ bufferSize = 0;
+ // emit the large header to the callback.
+ emittedHeaders.add(entry.name);
+ emittedHeaders.add(entry.value);
+ return;
+ }
+
+ // Prune headers to the required length.
+ while (bufferSize + delta > maxBufferSize) {
+ remove(0);
+ index--;
+ }
+
+ if (index < 0) { // we pruned it, so insert at beginning
+ index = 0;
+ headerTable.add(index, entry);
+ } else if (index == headerTable.size()) { // append to the end
+ headerTable.add(index, entry);
+ } else { // replace value at same position
+ headerTable.set(index, entry);
+ }
+
+ bufferSize += delta;
+ referenceSet.set(index);
+ }
+
+ private void remove(int index) {
+ bufferSize -= headerTable.remove(index).length();
+ }
+
+ private int readByte() throws IOException {
+ bytesLeft--;
+ return in.readByte() & 0xff;
+ }
+
+ int readInt(int firstByte, int prefixMask) throws IOException {
+ int prefix = firstByte & prefixMask;
+ if (prefix < prefixMask) {
+ return prefix; // This was a single byte value.
+ }
+
+ // This is a multibyte value. Read 7 bits at a time.
+ int result = prefixMask;
+ int shift = 0;
+ while (true) {
+ int b = readByte();
+ if ((b & 0x80) != 0) { // Equivalent to (b >= 128) since b is in [0..255].
+ result += (b & 0x7f) << shift;
+ shift += 7;
+ } else {
+ result += b << shift; // Last byte.
+ break;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Reads a UTF-8 encoded string. Since ASCII is a subset of UTF-8, this method
+ * may be used to read strings that are known to be ASCII-only.
+ */
+ public String readString() throws IOException {
+ int firstByte = readByte();
+ int length = readInt(firstByte, PREFIX_8_BITS);
+ byte[] encoded = new byte[length];
+ bytesLeft -= length;
+ in.readFully(encoded);
+ return new String(encoded, "UTF-8");
+ }
+ }
+
+ static class Writer {
+ private final OutputStream out;
+
+ Writer(OutputStream out) {
+ this.out = out;
+ }
+
+ public void writeHeaders(List<String> nameValueBlock) throws IOException {
+ // TODO: implement a compression strategy.
+ for (int i = 0, size = nameValueBlock.size(); i < size; i += 2) {
+ out.write(0x60); // Literal Header without Indexing - New Name.
+ writeString(nameValueBlock.get(i));
+ writeString(nameValueBlock.get(i + 1));
+ }
+ }
+
+ public void writeInt(int value, int prefixMask, int bits) throws IOException {
+ // Write the raw value for a single byte value.
+ if (value < prefixMask) {
+ out.write(bits | value);
+ return;
+ }
+
+ // Write the mask to start a multibyte value.
+ out.write(bits | prefixMask);
+ value -= prefixMask;
+
+ // Write 7 bits at a time 'til we're done.
+ while (value >= 0x80) {
+ int b = value & 0x7f;
+ out.write(b | 0x80);
+ value >>>= 7;
+ }
+ out.write(value);
+ }
+
+ /**
+ * Writes a UTF-8 encoded string. Since ASCII is a subset of UTF-8, this
+ * method can be used to write strings that are known to be ASCII-only.
+ */
+ public void writeString(String headerName) throws IOException {
+ byte[] bytes = headerName.getBytes("UTF-8");
+ writeInt(bytes.length, PREFIX_8_BITS, 0);
+ out.write(bytes);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/spdy/Http20Draft06.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/Http20Draft06.java b/framework/src/com/squareup/okhttp/internal/spdy/Http20Draft06.java
new file mode 100755
index 0000000..3d53f48
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/spdy/Http20Draft06.java
@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2013 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.squareup.okhttp.internal.spdy;
+
+import com.squareup.okhttp.internal.Util;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Read and write http/2 v06 frames.
+ * http://tools.ietf.org/html/draft-ietf-httpbis-http2-06
+ */
+final class Http20Draft06 implements Variant {
+ private static final byte[] CONNECTION_HEADER;
+ static {
+ try {
+ CONNECTION_HEADER = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new AssertionError();
+ }
+ }
+
+ static final int TYPE_DATA = 0x0;
+ static final int TYPE_HEADERS = 0x1;
+ static final int TYPE_PRIORITY = 0x2;
+ static final int TYPE_RST_STREAM = 0x3;
+ static final int TYPE_SETTINGS = 0x4;
+ static final int TYPE_PUSH_PROMISE = 0x5;
+ static final int TYPE_PING = 0x6;
+ static final int TYPE_GOAWAY = 0x7;
+ static final int TYPE_WINDOW_UPDATE = 0x9;
+ static final int TYPE_CONTINUATION = 0xa;
+
+ static final int FLAG_END_STREAM = 0x1;
+ /** Used for headers, push-promise and continuation. */
+ static final int FLAG_END_HEADERS = 0x4;
+ static final int FLAG_PRIORITY = 0x8;
+ static final int FLAG_PONG = 0x1;
+ static final int FLAG_END_FLOW_CONTROL = 0x1;
+
+ @Override public FrameReader newReader(InputStream in, boolean client) {
+ return new Reader(in, client);
+ }
+
+ @Override public FrameWriter newWriter(OutputStream out, boolean client) {
+ return new Writer(out, client);
+ }
+
+ static final class Reader implements FrameReader {
+ private final DataInputStream in;
+ private final boolean client;
+ private final Hpack.Reader hpackReader;
+
+ Reader(InputStream in, boolean client) {
+ this.in = new DataInputStream(in);
+ this.client = client;
+ this.hpackReader = new Hpack.Reader(this.in, client);
+ }
+
+ @Override public void readConnectionHeader() throws IOException {
+ if (client) return; // Nothing to read; servers don't send connection headers!
+ byte[] connectionHeader = new byte[CONNECTION_HEADER.length];
+ in.readFully(connectionHeader);
+ if (!Arrays.equals(connectionHeader, CONNECTION_HEADER)) {
+ throw ioException("Expected a connection header but was "
+ + Arrays.toString(connectionHeader));
+ }
+ }
+
+ @Override public boolean nextFrame(Handler handler) throws IOException {
+ int w1;
+ try {
+ w1 = in.readInt();
+ } catch (IOException e) {
+ return false; // This might be a normal socket close.
+ }
+ int w2 = in.readInt();
+
+ int length = (w1 & 0xffff0000) >> 16;
+ int type = (w1 & 0xff00) >> 8;
+ int flags = w1 & 0xff;
+ // boolean r = (w2 & 0x80000000) != 0; // Reserved.
+ int streamId = (w2 & 0x7fffffff);
+
+ switch (type) {
+ case TYPE_DATA:
+ readData(handler, flags, length, streamId);
+ return true;
+
+ case TYPE_HEADERS:
+ readHeaders(handler, flags, length, streamId);
+ return true;
+
+ case TYPE_PRIORITY:
+ readPriority(handler, flags, length, streamId);
+ return true;
+
+ case TYPE_RST_STREAM:
+ readRstStream(handler, flags, length, streamId);
+ return true;
+
+ case TYPE_SETTINGS:
+ readSettings(handler, flags, length, streamId);
+ return true;
+
+ case TYPE_PUSH_PROMISE:
+ readPushPromise(handler, flags, length, streamId);
+ return true;
+
+ case TYPE_PING:
+ readPing(handler, flags, length, streamId);
+ return true;
+
+ case TYPE_GOAWAY:
+ readGoAway(handler, flags, length, streamId);
+ return true;
+
+ case TYPE_WINDOW_UPDATE:
+ readWindowUpdate(handler, flags, length, streamId);
+ return true;
+ }
+
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ private void readHeaders(Handler handler, int flags, int length, int streamId)
+ throws IOException {
+ if (streamId == 0) throw ioException("TYPE_HEADERS streamId == 0");
+
+ boolean inFinished = (flags & FLAG_END_STREAM) != 0;
+
+ while (true) {
+ hpackReader.readHeaders(length);
+
+ if ((flags & FLAG_END_HEADERS) != 0) {
+ hpackReader.emitReferenceSet();
+ List<String> namesAndValues = hpackReader.getAndReset();
+ int priority = -1; // TODO: priority
+ handler.headers(false, inFinished, streamId, -1, priority, namesAndValues,
+ HeadersMode.HTTP_20_HEADERS);
+ return;
+ }
+
+ // Read another continuation frame.
+ int w1 = in.readInt();
+ int w2 = in.readInt();
+
+ length = (w1 & 0xffff0000) >> 16;
+ int newType = (w1 & 0xff00) >> 8;
+ flags = w1 & 0xff;
+
+ // TODO: remove in draft 8: CONTINUATION no longer sets END_STREAM
+ inFinished = (flags & FLAG_END_STREAM) != 0;
+
+ // boolean u = (w2 & 0x80000000) != 0; // Unused.
+ int newStreamId = (w2 & 0x7fffffff);
+
+ if (newType != TYPE_CONTINUATION) {
+ throw ioException("TYPE_CONTINUATION didn't have FLAG_END_HEADERS");
+ }
+ if (newStreamId != streamId) throw ioException("TYPE_CONTINUATION streamId changed");
+ }
+ }
+
+ private void readData(Handler handler, int flags, int length, int streamId) throws IOException {
+ boolean inFinished = (flags & FLAG_END_STREAM) != 0;
+ handler.data(inFinished, streamId, in, length);
+ }
+
+ private void readPriority(Handler handler, int flags, int length, int streamId)
+ throws IOException {
+ if (length != 4) throw ioException("TYPE_PRIORITY length: %d != 4", length);
+ if (streamId == 0) throw ioException("TYPE_PRIORITY streamId == 0");
+ int w1 = in.readInt();
+ // boolean r = (w1 & 0x80000000) != 0; // Reserved.
+ int priority = (w1 & 0x7fffffff);
+ handler.priority(streamId, priority);
+ }
+
+ private void readRstStream(Handler handler, int flags, int length, int streamId)
+ throws IOException {
+ if (length != 4) throw ioException("TYPE_RST_STREAM length: %d != 4", length);
+ if (streamId == 0) throw ioException("TYPE_RST_STREAM streamId == 0");
+ int errorCodeInt = in.readInt();
+ ErrorCode errorCode = ErrorCode.fromHttp2(errorCodeInt);
+ if (errorCode == null) {
+ throw ioException("TYPE_RST_STREAM unexpected error code: %d", errorCodeInt);
+ }
+ handler.rstStream(streamId, errorCode);
+ }
+
+ private void readSettings(Handler handler, int flags, int length, int streamId)
+ throws IOException {
+ if (length % 8 != 0) throw ioException("TYPE_SETTINGS length %% 8 != 0: %s", length);
+ if (streamId != 0) throw ioException("TYPE_SETTINGS streamId != 0");
+ Settings settings = new Settings();
+ for (int i = 0; i < length; i += 8) {
+ int w1 = in.readInt();
+ int value = in.readInt();
+ // int r = (w1 & 0xff000000) >>> 24; // Reserved.
+ int id = w1 & 0xffffff;
+ settings.set(id, 0, value);
+ }
+ handler.settings(false, settings);
+ }
+
+ private void readPushPromise(Handler handler, int flags, int length, int streamId) {
+ // TODO:
+ }
+
+ private void readPing(Handler handler, int flags, int length, int streamId) throws IOException {
+ if (length != 8) throw ioException("TYPE_PING length != 8: %s", length);
+ if (streamId != 0) throw ioException("TYPE_PING streamId != 0");
+ int payload1 = in.readInt();
+ int payload2 = in.readInt();
+ boolean reply = (flags & FLAG_PONG) != 0;
+ handler.ping(reply, payload1, payload2);
+ }
+
+ private void readGoAway(Handler handler, int flags, int length, int streamId)
+ throws IOException {
+ if (length < 8) throw ioException("TYPE_GOAWAY length < 8: %s", length);
+ int lastStreamId = in.readInt();
+ int errorCodeInt = in.readInt();
+ int opaqueDataLength = length - 8;
+ ErrorCode errorCode = ErrorCode.fromHttp2(errorCodeInt);
+ if (errorCode == null) {
+ throw ioException("TYPE_RST_STREAM unexpected error code: %d", errorCodeInt);
+ }
+ if (Util.skipByReading(in, opaqueDataLength) != opaqueDataLength) {
+ throw new IOException("TYPE_GOAWAY opaque data was truncated");
+ }
+ handler.goAway(lastStreamId, errorCode);
+ }
+
+ private void readWindowUpdate(Handler handler, int flags, int length, int streamId)
+ throws IOException {
+ int w1 = in.readInt();
+ // boolean r = (w1 & 0x80000000) != 0; // Reserved.
+ int windowSizeIncrement = (w1 & 0x7fffffff);
+ boolean endFlowControl = (flags & FLAG_END_FLOW_CONTROL) != 0;
+ handler.windowUpdate(streamId, windowSizeIncrement, endFlowControl);
+ }
+
+ private static IOException ioException(String message, Object... args) throws IOException {
+ throw new IOException(String.format(message, args));
+ }
+
+ @Override public void close() throws IOException {
+ in.close();
+ }
+ }
+
+ static final class Writer implements FrameWriter {
+ private final DataOutputStream out;
+ private final boolean client;
+ private final ByteArrayOutputStream hpackBuffer;
+ private final Hpack.Writer hpackWriter;
+
+ Writer(OutputStream out, boolean client) {
+ this.out = new DataOutputStream(out);
+ this.client = client;
+ this.hpackBuffer = new ByteArrayOutputStream();
+ this.hpackWriter = new Hpack.Writer(hpackBuffer);
+ }
+
+ @Override public synchronized void flush() throws IOException {
+ out.flush();
+ }
+
+ @Override public synchronized void connectionHeader() throws IOException {
+ if (!client) return; // Nothing to write; servers don't send connection headers!
+ out.write(CONNECTION_HEADER);
+ }
+
+ @Override public synchronized void synStream(boolean outFinished, boolean inFinished,
+ int streamId, int associatedStreamId, int priority, int slot, List<String> nameValueBlock)
+ throws IOException {
+ if (inFinished) throw new UnsupportedOperationException();
+ headers(outFinished, streamId, priority, nameValueBlock);
+ }
+
+ @Override public synchronized void synReply(boolean outFinished, int streamId,
+ List<String> nameValueBlock) throws IOException {
+ headers(outFinished, streamId, -1, nameValueBlock);
+ }
+
+ @Override public synchronized void headers(int streamId, List<String> nameValueBlock)
+ throws IOException {
+ headers(false, streamId, -1, nameValueBlock);
+ }
+
+ private void headers(boolean outFinished, int streamId, int priority,
+ List<String> nameValueBlock) throws IOException {
+ hpackBuffer.reset();
+ hpackWriter.writeHeaders(nameValueBlock);
+ int type = TYPE_HEADERS;
+ // TODO: implement CONTINUATION
+ int length = hpackBuffer.size();
+ int flags = FLAG_END_HEADERS;
+ if (outFinished) flags |= FLAG_END_STREAM;
+ if (priority != -1) flags |= FLAG_PRIORITY;
+ out.writeInt((length & 0xffff) << 16 | (type & 0xff) << 8 | (flags & 0xff));
+ out.writeInt(streamId & 0x7fffffff);
+ if (priority != -1) out.writeInt(priority & 0x7fffffff);
+ hpackBuffer.writeTo(out);
+ }
+
+ @Override public synchronized void rstStream(int streamId, ErrorCode errorCode)
+ throws IOException {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ @Override public void data(boolean outFinished, int streamId, byte[] data) throws IOException {
+ data(outFinished, streamId, data, 0, data.length);
+ }
+
+ @Override public synchronized void data(boolean outFinished, int streamId, byte[] data,
+ int offset, int byteCount) throws IOException {
+ int type = TYPE_DATA;
+ int flags = 0;
+ if (outFinished) flags |= FLAG_END_STREAM;
+ out.writeInt((byteCount & 0xffff) << 16 | (type & 0xff) << 8 | (flags & 0xff));
+ out.writeInt(streamId & 0x7fffffff);
+ out.write(data, offset, byteCount);
+ }
+
+ @Override public synchronized void settings(Settings settings) throws IOException {
+ int type = TYPE_SETTINGS;
+ int length = settings.size() * 8;
+ int flags = 0;
+ int streamId = 0;
+ out.writeInt((length & 0xffff) << 16 | (type & 0xff) << 8 | (flags & 0xff));
+ out.writeInt(streamId & 0x7fffffff);
+ for (int i = 0; i < Settings.COUNT; i++) {
+ if (!settings.isSet(i)) continue;
+ out.writeInt(i & 0xffffff);
+ out.writeInt(settings.get(i));
+ }
+ }
+
+ @Override public synchronized void noop() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public synchronized void ping(boolean reply, int payload1, int payload2)
+ throws IOException {
+ // TODO
+ }
+
+ @Override public synchronized void goAway(int lastGoodStreamId, ErrorCode errorCode)
+ throws IOException {
+ // TODO
+ }
+
+ @Override public synchronized void windowUpdate(int streamId, int deltaWindowSize)
+ throws IOException {
+ // TODO
+ }
+
+ @Override public void close() throws IOException {
+ out.close();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.java b/framework/src/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.java
old mode 100644
new mode 100755
index 875fff0..44d4ea2
--- a/framework/src/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.java
+++ b/framework/src/com/squareup/okhttp/internal/spdy/IncomingStreamHandler.java
@@ -22,7 +22,7 @@ import java.io.IOException;
public interface IncomingStreamHandler {
IncomingStreamHandler REFUSE_INCOMING_STREAMS = new IncomingStreamHandler() {
@Override public void receive(SpdyStream stream) throws IOException {
- stream.close(SpdyStream.RST_REFUSED_STREAM);
+ stream.close(ErrorCode.REFUSED_STREAM);
}
};
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/spdy/NameValueBlockReader.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/NameValueBlockReader.java b/framework/src/com/squareup/okhttp/internal/spdy/NameValueBlockReader.java
new file mode 100755
index 0000000..b95d013
--- /dev/null
+++ b/framework/src/com/squareup/okhttp/internal/spdy/NameValueBlockReader.java
@@ -0,0 +1,123 @@
+package com.squareup.okhttp.internal.spdy;
+
+import com.squareup.okhttp.internal.Util;
+import java.io.Closeable;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+
+/**
+ * Reads a SPDY/3 Name/Value header block. This class is made complicated by the
+ * requirement that we're strict with which bytes we put in the compressed bytes
+ * buffer. We need to put all compressed bytes into that buffer -- but no other
+ * bytes.
+ */
+class NameValueBlockReader implements Closeable {
+ private final DataInputStream nameValueBlockIn;
+ private final FillableInflaterInputStream fillableInflaterInputStream;
+ private int compressedLimit;
+
+ NameValueBlockReader(final InputStream in) {
+ // Limit the inflater input stream to only those bytes in the Name/Value block. We cut the
+ // inflater off at its source because we can't predict the ratio of compressed bytes to
+ // uncompressed bytes.
+ InputStream throttleStream = new InputStream() {
+ @Override public int read() throws IOException {
+ return Util.readSingleByte(this);
+ }
+
+ @Override public int read(byte[] buffer, int offset, int byteCount) throws IOException {
+ byteCount = Math.min(byteCount, compressedLimit);
+ int consumed = in.read(buffer, offset, byteCount);
+ compressedLimit -= consumed;
+ return consumed;
+ }
+
+ @Override public void close() throws IOException {
+ in.close();
+ }
+ };
+
+ // Subclass inflater to install a dictionary when it's needed.
+ Inflater inflater = new Inflater() {
+ @Override public int inflate(byte[] buffer, int offset, int count)
+ throws DataFormatException {
+ int result = super.inflate(buffer, offset, count);
+ if (result == 0 && needsDictionary()) {
+ setDictionary(Spdy3.DICTIONARY);
+ result = super.inflate(buffer, offset, count);
+ }
+ return result;
+ }
+ };
+
+ fillableInflaterInputStream = new FillableInflaterInputStream(throttleStream, inflater);
+ nameValueBlockIn = new DataInputStream(fillableInflaterInputStream);
+ }
+
+ /** Extend the inflater stream so we can eagerly fill the compressed bytes buffer if necessary. */
+ static class FillableInflaterInputStream extends InflaterInputStream {
+ public FillableInflaterInputStream(InputStream in, Inflater inf) {
+ super(in, inf);
+ }
+
+ @Override public void fill() throws IOException {
+ super.fill(); // This method is protected in the superclass.
+ }
+ }
+
+ public List<String> readNameValueBlock(int length) throws IOException {
+ this.compressedLimit += length;
+ try {
+ int numberOfPairs = nameValueBlockIn.readInt();
+ if (numberOfPairs < 0) {
+ throw new IOException("numberOfPairs < 0: " + numberOfPairs);
+ }
+ if (numberOfPairs > 1024) {
+ throw new IOException("numberOfPairs > 1024: " + numberOfPairs);
+ }
+ List<String> entries = new ArrayList<String>(numberOfPairs * 2);
+ for (int i = 0; i < numberOfPairs; i++) {
+ String name = readString();
+ String values = readString();
+ if (name.length() == 0) throw new IOException("name.length == 0");
+ entries.add(name);
+ entries.add(values);
+ }
+
+ doneReading();
+
+ return entries;
+ } catch (DataFormatException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+ private void doneReading() throws IOException {
+ if (compressedLimit == 0) return;
+
+ // Read any outstanding unread bytes. One side-effect of deflate compression is that sometimes
+ // there are bytes remaining in the stream after we've consumed all of the content.
+ fillableInflaterInputStream.fill();
+
+ if (compressedLimit != 0) {
+ throw new IOException("compressedLimit > 0: " + compressedLimit);
+ }
+ }
+
+ private String readString() throws DataFormatException, IOException {
+ int length = nameValueBlockIn.readInt();
+ byte[] bytes = new byte[length];
+ Util.readFully(nameValueBlockIn, bytes);
+ return new String(bytes, 0, length, "UTF-8");
+ }
+
+ @Override public void close() throws IOException {
+ nameValueBlockIn.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cordova-amazon-fireos/blob/185547ef/framework/src/com/squareup/okhttp/internal/spdy/Ping.java
----------------------------------------------------------------------
diff --git a/framework/src/com/squareup/okhttp/internal/spdy/Ping.java b/framework/src/com/squareup/okhttp/internal/spdy/Ping.java
old mode 100644
new mode 100755