All Downloads are FREE. Search and download functionalities are using the official Maven repository.

okhttp3.internal.platform.Platform Maven / Gradle / Ivy

/*
 * Copyright (C) 2012 Square, Inc.
 * Copyright (C) 2012 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 okhttp3.internal.platform;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.internal.tls.BasicCertificateChainCleaner;
import okhttp3.internal.tls.BasicTrustRootIndex;
import okhttp3.internal.tls.CertificateChainCleaner;
import okhttp3.internal.tls.TrustRootIndex;
import okio.Buffer;

/**
 * Access to platform-specific features.
 *
 * 

Server name indication (SNI)

* *

Supported on Android 2.3+. * * Supported on OpenJDK 7+ * *

Session Tickets

* *

Supported on Android 2.3+. * *

Android Traffic Stats (Socket Tagging)

* *

Supported on Android 4.0+. * *

ALPN (Application Layer Protocol Negotiation)

* *

Supported on Android 5.0+. The APIs were present in Android 4.4, but that implementation was * unstable. * * Supported on OpenJDK 7 and 8 (via the JettyALPN-boot library). * * Supported on OpenJDK 9 via SSLParameters and SSLSocket features. * *

Trust Manager Extraction

* *

Supported on Android 2.3+ and OpenJDK 7+. There are no public APIs to recover the trust * manager that was used to create an {@link SSLSocketFactory}. * *

Android Cleartext Permit Detection

* *

Supported on Android 6.0+ via {@code NetworkSecurityPolicy}. */ public class Platform { private static final Platform PLATFORM = findPlatform(); public static final int INFO = 4; public static final int WARN = 5; private static final Logger logger = Logger.getLogger(OkHttpClient.class.getName()); public static Platform get() { return PLATFORM; } /** Prefix used on custom headers. */ public String getPrefix() { return "OkHttp"; } protected @Nullable X509TrustManager trustManager(SSLSocketFactory sslSocketFactory) { // Attempt to get the trust manager from an OpenJDK socket factory. We attempt this on all // platforms in order to support Robolectric, which mixes classes from both Android and the // Oracle JDK. Note that we don't support HTTP/2 or other nice features on Robolectric. try { Class sslContextClass = Class.forName("sun.security.ssl.SSLContextImpl"); Object context = readFieldOrNull(sslSocketFactory, sslContextClass, "context"); if (context == null) return null; return readFieldOrNull(context, X509TrustManager.class, "trustManager"); } catch (ClassNotFoundException e) { return null; } } /** * Configure TLS extensions on {@code sslSocket} for {@code route}. * * @param hostname non-null for client-side handshakes; null for server-side handshakes. */ public void configureTlsExtensions(SSLSocket sslSocket, @Nullable String hostname, List protocols) throws IOException { } /** * Called after the TLS handshake to release resources allocated by {@link * #configureTlsExtensions}. */ public void afterHandshake(SSLSocket sslSocket) { } /** Returns the negotiated protocol, or null if no protocol was negotiated. */ public @Nullable String getSelectedProtocol(SSLSocket socket) { return null; } public void connectSocket(Socket socket, InetSocketAddress address, int connectTimeout) throws IOException { socket.connect(address, connectTimeout); } public void log(int level, String message, @Nullable Throwable t) { Level logLevel = level == WARN ? Level.WARNING : Level.INFO; logger.log(logLevel, message, t); } public boolean isCleartextTrafficPermitted(String hostname) { return true; } /** * Returns an object that holds a stack trace created at the moment this method is executed. This * should be used specifically for {@link java.io.Closeable} objects and in conjunction with * {@link #logCloseableLeak(String, Object)}. */ public Object getStackTraceForCloseable(String closer) { if (logger.isLoggable(Level.FINE)) { return new Throwable(closer); // These are expensive to allocate. } return null; } public void logCloseableLeak(String message, Object stackTrace) { if (stackTrace == null) { message += " To see where this was allocated, set the OkHttpClient logger level to FINE: " + "Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);"; } log(WARN, message, (Throwable) stackTrace); } public static List alpnProtocolNames(List protocols) { List names = new ArrayList<>(protocols.size()); for (int i = 0, size = protocols.size(); i < size; i++) { Protocol protocol = protocols.get(i); if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for ALPN. names.add(protocol.toString()); } return names; } public CertificateChainCleaner buildCertificateChainCleaner(X509TrustManager trustManager) { return new BasicCertificateChainCleaner(buildTrustRootIndex(trustManager)); } public CertificateChainCleaner buildCertificateChainCleaner(SSLSocketFactory sslSocketFactory) { X509TrustManager trustManager = trustManager(sslSocketFactory); if (trustManager == null) { throw new IllegalStateException("Unable to extract the trust manager on " + Platform.get() + ", sslSocketFactory is " + sslSocketFactory.getClass()); } return buildCertificateChainCleaner(trustManager); } public static boolean isConscryptPreferred() { // mainly to allow tests to run cleanly if ("conscrypt".equals(System.getProperty("okhttp.platform"))) { return true; } // check if Provider manually installed String preferredProvider = Security.getProviders()[0].getName(); return "Conscrypt".equals(preferredProvider); } /** Attempt to match the host runtime to a capable Platform implementation. */ private static Platform findPlatform() { if (isAndroid()) { return findAndroidPlatform(); } else { return findJvmPlatform(); } } public static boolean isAndroid() { // This explicit check avoids activating in Android Studio with Android specific classes // available when running plugins inside the IDE. return "Dalvik".equals(System.getProperty("java.vm.name")); } private static Platform findJvmPlatform() { if (isConscryptPreferred()) { Platform conscrypt = ConscryptPlatform.buildIfSupported(); if (conscrypt != null) { return conscrypt; } } Platform jdk9 = Jdk9Platform.buildIfSupported(); if (jdk9 != null) { return jdk9; } Platform jdkWithJettyBoot = JdkWithJettyBootPlatform.buildIfSupported(); if (jdkWithJettyBoot != null) { return jdkWithJettyBoot; } // Probably an Oracle JDK like OpenJDK. return new Platform(); } private static Platform findAndroidPlatform() { Platform android10 = Android10Platform.buildIfSupported(); if (android10 != null) { return android10; } Platform android = AndroidPlatform.buildIfSupported(); if (android == null) { throw new NullPointerException("No platform found on Android"); } return android; } /** * Returns the concatenation of 8-bit, length prefixed protocol names. * http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04#page-4 */ static byte[] concatLengthPrefixed(List protocols) { Buffer result = new Buffer(); for (int i = 0, size = protocols.size(); i < size; i++) { Protocol protocol = protocols.get(i); if (protocol == Protocol.HTTP_1_0) continue; // No HTTP/1.0 for ALPN. result.writeByte(protocol.toString().length()); result.writeUtf8(protocol.toString()); } return result.readByteArray(); } static @Nullable T readFieldOrNull(Object instance, Class fieldType, String fieldName) { for (Class c = instance.getClass(); c != Object.class; c = c.getSuperclass()) { try { Field field = c.getDeclaredField(fieldName); field.setAccessible(true); Object value = field.get(instance); if (value == null || !fieldType.isInstance(value)) return null; return fieldType.cast(value); } catch (NoSuchFieldException ignored) { } catch (IllegalAccessException e) { throw new AssertionError(); } } // Didn't find the field we wanted. As a last gasp attempt, try to find the value on a delegate. if (!fieldName.equals("delegate")) { Object delegate = readFieldOrNull(instance, Object.class, "delegate"); if (delegate != null) return readFieldOrNull(delegate, fieldType, fieldName); } return null; } public SSLContext getSSLContext() { String jvmVersion = System.getProperty("java.specification.version"); if ("1.7".equals(jvmVersion)) { try { // JDK 1.7 (public version) only support > TLSv1 with named protocols return SSLContext.getInstance("TLSv1.2"); } catch (NoSuchAlgorithmException e) { // fallback to TLS } } try { return SSLContext.getInstance("TLS"); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException("No TLS provider", e); } } public TrustRootIndex buildTrustRootIndex(X509TrustManager trustManager) { return new BasicTrustRootIndex(trustManager.getAcceptedIssuers()); } public void configureSslSocketFactory(SSLSocketFactory socketFactory) { } @Override public String toString() { return getClass().getSimpleName(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy