diff options
author | Tobias Thierer <tobiast@google.com> | 2017-10-30 18:33:01 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2017-10-30 18:33:01 +0000 |
commit | 48afde8fe9e9d49527fe8016be69b362710d5e24 (patch) | |
tree | 08d510ae0e06daa63025c3f6526438a147943d07 /android/main/java/com/squareup | |
parent | b41a71cc51a05150a9e39dbf2bbfc88fb91d4c54 (diff) | |
parent | 3607e90501aa0c2a980342e1205fd5202488fa02 (diff) | |
download | okhttp-48afde8fe9e9d49527fe8016be69b362710d5e24.tar.gz |
Merge "Move of OkHttp facade API to new package." am: be2eb23cf4 am: d154dd4e4c
am: 3607e90501
Change-Id: I372cfde359137267b67de89972613006b7cc695c
Diffstat (limited to 'android/main/java/com/squareup')
5 files changed, 427 insertions, 0 deletions
diff --git a/android/main/java/com/squareup/okhttp/HttpHandler.java b/android/main/java/com/squareup/okhttp/HttpHandler.java new file mode 100644 index 0000000..ef9a56b --- /dev/null +++ b/android/main/java/com/squareup/okhttp/HttpHandler.java @@ -0,0 +1,119 @@ +/* + * 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; + +import com.squareup.okhttp.internal.URLFilter; +import libcore.net.NetworkSecurityPolicy; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.Proxy; +import java.net.ResponseCache; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class HttpHandler extends URLStreamHandler { + + private final static List<ConnectionSpec> CLEARTEXT_ONLY = + Collections.singletonList(ConnectionSpec.CLEARTEXT); + + private static final CleartextURLFilter CLEARTEXT_FILTER = new CleartextURLFilter(); + + private final ConfigAwareConnectionPool configAwareConnectionPool = + ConfigAwareConnectionPool.getInstance(); + + @Override protected URLConnection openConnection(URL url) throws IOException { + return newOkUrlFactory(null /* proxy */).open(url); + } + + @Override protected URLConnection openConnection(URL url, Proxy proxy) throws IOException { + if (url == null || proxy == null) { + throw new IllegalArgumentException("url == null || proxy == null"); + } + return newOkUrlFactory(proxy).open(url); + } + + @Override protected int getDefaultPort() { + return 80; + } + + protected OkUrlFactory newOkUrlFactory(Proxy proxy) { + OkUrlFactory okUrlFactory = createHttpOkUrlFactory(proxy); + // For HttpURLConnections created through java.net.URL Android uses a connection pool that + // is aware when the default network changes so that pooled connections are not re-used when + // the default network changes. + okUrlFactory.client().setConnectionPool(configAwareConnectionPool.get()); + return okUrlFactory; + } + + /** + * Creates an OkHttpClient suitable for creating {@link java.net.HttpURLConnection} instances on + * Android. + */ + // Visible for android.net.Network. + public static OkUrlFactory createHttpOkUrlFactory(Proxy proxy) { + OkHttpClient client = new OkHttpClient(); + + // Explicitly set the timeouts to infinity. + client.setConnectTimeout(0, TimeUnit.MILLISECONDS); + client.setReadTimeout(0, TimeUnit.MILLISECONDS); + client.setWriteTimeout(0, TimeUnit.MILLISECONDS); + + // Set the default (same protocol) redirect behavior. The default can be overridden for + // each instance using HttpURLConnection.setInstanceFollowRedirects(). + client.setFollowRedirects(HttpURLConnection.getFollowRedirects()); + + // Do not permit http -> https and https -> http redirects. + client.setFollowSslRedirects(false); + + // Permit cleartext traffic only (this is a handler for HTTP, not for HTTPS). + client.setConnectionSpecs(CLEARTEXT_ONLY); + + // When we do not set the Proxy explicitly OkHttp picks up a ProxySelector using + // ProxySelector.getDefault(). + if (proxy != null) { + client.setProxy(proxy); + } + + // OkHttp requires that we explicitly set the response cache. + OkUrlFactory okUrlFactory = new OkUrlFactory(client); + + // Use the installed NetworkSecurityPolicy to determine which requests are permitted over + // http. + OkUrlFactories.setUrlFilter(okUrlFactory, CLEARTEXT_FILTER); + + ResponseCache responseCache = ResponseCache.getDefault(); + if (responseCache != null) { + AndroidInternal.setResponseCache(okUrlFactory, responseCache); + } + return okUrlFactory; + } + + private static final class CleartextURLFilter implements URLFilter { + @Override + public void checkURLPermitted(URL url) throws IOException { + String host = url.getHost(); + if (!NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(host)) { + throw new IOException("Cleartext HTTP traffic to " + host + " not permitted"); + } + } + } +} diff --git a/android/main/java/com/squareup/okhttp/HttpsHandler.java b/android/main/java/com/squareup/okhttp/HttpsHandler.java new file mode 100644 index 0000000..d4c0b8b --- /dev/null +++ b/android/main/java/com/squareup/okhttp/HttpsHandler.java @@ -0,0 +1,96 @@ +/* + * 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; + +import java.net.Proxy; +import java.util.Collections; +import java.util.List; + +import javax.net.ssl.HttpsURLConnection; + +public final class HttpsHandler extends HttpHandler { + + /** + * The connection spec to use when connecting to an https:// server. Note that Android does + * not set the cipher suites or TLS versions to use so the socket's defaults will be used + * instead. When the SSLSocketFactory is provided by the app or GMS core we will not + * override the enabled ciphers or TLS versions set on the sockets it produces with a + * list hardcoded at release time. This is deliberate. + */ + private static final ConnectionSpec TLS_CONNECTION_SPEC = ConnectionSpecs.builder(true) + .allEnabledCipherSuites() + .allEnabledTlsVersions() + .supportsTlsExtensions(true) + .build(); + + private static final List<Protocol> HTTP_1_1_ONLY = + Collections.singletonList(Protocol.HTTP_1_1); + + private final ConfigAwareConnectionPool configAwareConnectionPool = + ConfigAwareConnectionPool.getInstance(); + + @Override protected int getDefaultPort() { + return 443; + } + + @Override + protected OkUrlFactory newOkUrlFactory(Proxy proxy) { + OkUrlFactory okUrlFactory = createHttpsOkUrlFactory(proxy); + // For HttpsURLConnections created through java.net.URL Android uses a connection pool that + // is aware when the default network changes so that pooled connections are not re-used when + // the default network changes. + okUrlFactory.client().setConnectionPool(configAwareConnectionPool.get()); + return okUrlFactory; + } + + /** + * Creates an OkHttpClient suitable for creating {@link HttpsURLConnection} instances on + * Android. + */ + // Visible for android.net.Network. + public static OkUrlFactory createHttpsOkUrlFactory(Proxy proxy) { + // The HTTPS OkHttpClient is an HTTP OkHttpClient with extra configuration. + OkUrlFactory okUrlFactory = HttpHandler.createHttpOkUrlFactory(proxy); + + // All HTTPS requests are allowed. + OkUrlFactories.setUrlFilter(okUrlFactory, null); + + OkHttpClient okHttpClient = okUrlFactory.client(); + + // Only enable HTTP/1.1 (implies HTTP/1.0). Disable SPDY / HTTP/2.0. + okHttpClient.setProtocols(HTTP_1_1_ONLY); + + okHttpClient.setConnectionSpecs(Collections.singletonList(TLS_CONNECTION_SPEC)); + + // Android support certificate pinning via NetworkSecurityConfig so there is no need to + // also expose OkHttp's mechanism. The OkHttpClient underlying https HttpsURLConnections + // in Android should therefore always use the default certificate pinner, whose set of + // {@code hostNamesToPin} is empty. + okHttpClient.setCertificatePinner(CertificatePinner.DEFAULT); + + // OkHttp does not automatically honor the system-wide HostnameVerifier set with + // HttpsURLConnection.setDefaultHostnameVerifier(). + okUrlFactory.client().setHostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier()); + // OkHttp does not automatically honor the system-wide SSLSocketFactory set with + // HttpsURLConnection.setDefaultSSLSocketFactory(). + // See https://github.com/square/okhttp/issues/184 for details. + okHttpClient.setSslSocketFactory(HttpsURLConnection.getDefaultSSLSocketFactory()); + + return okUrlFactory; + } +} diff --git a/android/main/java/com/squareup/okhttp/internalandroidapi/Dns.java b/android/main/java/com/squareup/okhttp/internalandroidapi/Dns.java new file mode 100644 index 0000000..349fade --- /dev/null +++ b/android/main/java/com/squareup/okhttp/internalandroidapi/Dns.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2017 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.internalandroidapi; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; + +/** + * A domain name service that resolves IP addresses for host names. + */ +public interface Dns { + /** + * Returns the IP addresses of {@code hostname}, in the order they should + * be attempted. + */ + List<InetAddress> lookup(String hostname) throws UnknownHostException; +} diff --git a/android/main/java/com/squareup/okhttp/internalandroidapi/HttpURLConnectionFactory.java b/android/main/java/com/squareup/okhttp/internalandroidapi/HttpURLConnectionFactory.java new file mode 100644 index 0000000..f1da451 --- /dev/null +++ b/android/main/java/com/squareup/okhttp/internalandroidapi/HttpURLConnectionFactory.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2017 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.internalandroidapi; + +import com.squareup.okhttp.ConnectionPool; +import com.squareup.okhttp.HttpHandler; +import com.squareup.okhttp.HttpsHandler; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.OkUrlFactories; +import com.squareup.okhttp.OkUrlFactory; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import javax.net.SocketFactory; + +/** + * A way to construct {@link java.net.HttpURLConnection}s that supports some + * configuration on a per-factory or per-connection basis rather than only via + * global static state such as {@link CookieHandler#setDefault(CookieHandler)}. + * The per-factory configuration is <b>optional</b>; if not set, global + * configuration or default behavior is used. + * + * This facade prevents tight coupling with the underlying implementation (on + * top of a particular version of OkHttp). Android code outside of libcore + * should never depend directly on OkHttp. + * + * This abstraction is not suitable for general use. Talk to the maintainers of + * this class before modifying it or adding additional dependencies. + * + * @hide + */ +public final class HttpURLConnectionFactory { + + private ConnectionPool connectionPool; + private com.squareup.okhttp.Dns dns; + + /** + * Sets a new ConnectionPool, specific to this URLFactory and not shared with + * any other connections, with the given configuration. + */ + public void setNewConnectionPool(int maxIdleConnections, long keepAliveDuration, + TimeUnit timeUnit) { + this.connectionPool = new ConnectionPool(maxIdleConnections, keepAliveDuration, timeUnit); + } + + public void setDns(Dns dns) { + Objects.requireNonNull(dns); + this.dns = new DnsAdapter(dns); + } + + /** + * Opens a connection that uses the system default proxy settings and SocketFactory. + */ + public URLConnection openConnection(URL url) throws IOException { + return internalOpenConnection(url, null /* socketFactory */, null /* proxy */); + } + + /** + * Opens a connection that uses the system default SocketFactory and the specified + * proxy settings. + */ + public URLConnection openConnection(URL url, Proxy proxy) throws IOException { + Objects.requireNonNull(proxy); + return internalOpenConnection(url, null /* socketFactory */, proxy); + } + + /** + * Opens a connection that uses the specified SocketFactory and the system default + * proxy settings. + */ + public URLConnection openConnection(URL url, SocketFactory socketFactory) throws IOException { + Objects.requireNonNull(socketFactory); + return internalOpenConnection(url, socketFactory, null /* proxy */); + } + + /** + * Opens a connection using the specified SocketFactory and the specified proxy + * settings, overriding any system wide configuration. + */ + public URLConnection openConnection(URL url, SocketFactory socketFactory, Proxy proxy) + throws IOException { + Objects.requireNonNull(socketFactory); + Objects.requireNonNull(proxy); + return internalOpenConnection(url, socketFactory, proxy); + } + + private URLConnection internalOpenConnection(URL url, SocketFactory socketFactoryOrNull, + Proxy proxyOrNull) throws IOException { + String protocol = url.getProtocol(); + OkUrlFactory okUrlFactory; + // TODO: HttpHandler creates OkUrlFactory instances that share the default ResponseCache. + // Could this cause unexpected behavior? + if (protocol.equals("http")) { + okUrlFactory = HttpHandler.createHttpOkUrlFactory(proxyOrNull); + } else if (protocol.equals("https")) { + okUrlFactory = HttpsHandler.createHttpsOkUrlFactory(proxyOrNull); + } else { + // OkHttp only supports HTTP and HTTPS. + throw new MalformedURLException("Invalid URL or unrecognized protocol " + protocol); + } + + OkHttpClient client = okUrlFactory.client(); + if (connectionPool != null) { + client.setConnectionPool(connectionPool); + } + if (dns != null) { + client.setDns(dns); + } + if (socketFactoryOrNull != null) { + client.setSocketFactory(socketFactoryOrNull); + } + if (proxyOrNull == null) { + return okUrlFactory.open(url); + } else { + return OkUrlFactories.open(okUrlFactory, url, proxyOrNull); + } + } + + /** + * Adapts a {@link Dns} as a {@link com.squareup.okhttp.Dns}. + */ + static final class DnsAdapter implements com.squareup.okhttp.Dns { + private final Dns adaptee; + + DnsAdapter(Dns adaptee) { + this.adaptee = Objects.requireNonNull(adaptee); + } + + @Override + public List<InetAddress> lookup(String hostname) throws UnknownHostException { + return adaptee.lookup(hostname); + } + + @Override + public int hashCode() { + return 31 * DnsAdapter.class.hashCode() + adaptee.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof DnsAdapter)) { + return false; + } + return adaptee.equals(((DnsAdapter) obj).adaptee); + } + + @Override + public String toString() { + return adaptee.toString(); + } + } + +} diff --git a/android/main/java/com/squareup/okhttp/internalandroidapi/README b/android/main/java/com/squareup/okhttp/internalandroidapi/README new file mode 100644 index 0000000..e332837 --- /dev/null +++ b/android/main/java/com/squareup/okhttp/internalandroidapi/README @@ -0,0 +1,5 @@ +This package contains a facade over OkHttp that some parts of Android framework are allowed to +depend on. This is not a stable API; it is an attempt to decouple framework code from OkHttp as +much as is practical where public APIs cannot be used. + +Please talk to the maintainers before adding any new dependencies. |