1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-12 10:23:16 +03:00

Support querying & setting transport lists on connections.

The list is specified via a magic request property
"X-Android-Transports" and can be queried via the request
property "X-Android-Selected-Transport".

System wide defaults / switches don't need any changes
to okhttp. They can be set as options on the OkHttpClient
used by the platform UrlStreamHandlers.
This commit is contained in:
Narayan Kamath
2013-06-03 10:55:52 +01:00
parent 95beef24f0
commit 4910039a57
6 changed files with 81 additions and 9 deletions

2
.gitignore vendored
View File

@@ -15,6 +15,8 @@ release.properties
.idea
*.iml
*.ipr
*.iws
classes
obj

View File

@@ -278,7 +278,7 @@ public class HttpEngine {
hostnameVerifier = policy.hostnameVerifier;
}
Address address = new Address(uriHost, getEffectivePort(uri), sslSocketFactory,
hostnameVerifier, policy.authenticator, policy.requestedProxy, policy.transports);
hostnameVerifier, policy.authenticator, policy.requestedProxy, policy.getTransports());
routeSelector = new RouteSelector(address, uri, policy.proxySelector, policy.connectionPool,
Dns.DEFAULT, policy.getFailedRoutes());
}

View File

@@ -127,10 +127,13 @@ public final class HttpTransport implements Transport {
}
@Override public ResponseHeaders readResponseHeaders() throws IOException {
RawHeaders headers = RawHeaders.fromBytes(socketIn);
httpEngine.connection.setHttpMinorVersion(headers.getHttpMinorVersion());
httpEngine.receiveHeaders(headers);
return new ResponseHeaders(httpEngine.uri, headers);
RawHeaders rawHeaders = RawHeaders.fromBytes(socketIn);
httpEngine.connection.setHttpMinorVersion(rawHeaders.getHttpMinorVersion());
httpEngine.receiveHeaders(rawHeaders);
ResponseHeaders headers = new ResponseHeaders(httpEngine.uri, rawHeaders);
headers.setTransport("http/1.1");
return headers;
}
public boolean makeReusable(boolean streamCancelled, OutputStream requestBodyOut,

View File

@@ -40,6 +40,7 @@ import java.net.SocketPermission;
import java.net.URL;
import java.security.Permission;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -93,7 +94,7 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
/* SSL configuration; necessary for HTTP requests that get redirected to HTTPS. */
SSLSocketFactory sslSocketFactory;
HostnameVerifier hostnameVerifier;
List<String> transports;
private List<String> transports;
OkAuthenticator authenticator;
final Set<Route> failedRoutes;
@@ -125,6 +126,10 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
return failedRoutes;
}
List<String> getTransports() {
return transports;
}
@Override public final void connect() throws IOException {
initHttpEngine();
boolean success;
@@ -547,7 +552,11 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
if (field == null) {
throw new NullPointerException("field == null");
}
rawRequestHeaders.set(field, newValue);
if ("X-Android-Transports".equals(field)) {
setTransports(newValue, false /* append */);
} else {
rawRequestHeaders.set(field, newValue);
}
}
@Override public final void addRequestProperty(String field, String value) {
@@ -557,6 +566,54 @@ public class HttpURLConnectionImpl extends HttpURLConnection {
if (field == null) {
throw new NullPointerException("field == null");
}
rawRequestHeaders.add(field, value);
if ("X-Android-Transports".equals(field)) {
setTransports(value, true /* append */);
} else {
rawRequestHeaders.add(field, value);
}
}
/*
* Splits and validates a comma-separated string of transports.
* When append == false, we require that the transport list contains "http/1.1".
*/
private void setTransports(String transportsString, boolean append) {
if (transportsString == null) {
throw new NullPointerException("transportsString == null");
}
String[] transports = transportsString.split(",", -1);
ArrayList<String> transportsList = new ArrayList<String>();
if (!append) {
// If we're not appending to the list, we need to make sure
// the list contains "http/1.1". We do this in a separate loop
// to avoid modifying any state before we validate the input.
boolean containsHttp = false;
for (int i = 0; i < transports.length; ++i) {
if ("http/1.1".equals(transports[i])) {
containsHttp = true;
break;
}
}
if (!containsHttp) {
throw new IllegalArgumentException("Transport list doesn't contain http/1.1");
}
} else {
transportsList.addAll(this.transports);
}
for (int i = 0; i < transports.length; ++i) {
if (transports[i].length() == 0) {
throw new IllegalArgumentException("Transport list contains an empty transport");
}
if (!transportsList.contains(transports[i])) {
transportsList.add(transports[i]);
}
}
this.transports = Util.immutableList(transportsList);
}
}

View File

@@ -42,6 +42,9 @@ public final class ResponseHeaders {
/** HTTP synthetic header with the response source. */
static final String RESPONSE_SOURCE = "X-Android-Response-Source";
/** HTTP synthetic header with the selected transport (spdy/3, http/1.1, etc.) */
static final String SELECTED_TRANSPORT = "X-Android-Selected-Transport";
private final URI uri;
private final RawHeaders headers;
@@ -278,6 +281,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.

View File

@@ -71,7 +71,10 @@ public final class SpdyTransport implements Transport {
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 {