1
17 package okhttp3.internal.platform;
18
19 import java.io.IOException;
20 import java.lang.reflect.Field;
21 import java.net.InetSocketAddress;
22 import java.net.Socket;
23 import java.security.NoSuchAlgorithmException;
24 import java.security.Security;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.logging.Level;
28 import java.util.logging.Logger;
29 import javax.annotation.Nullable;
30 import javax.net.ssl.SSLContext;
31 import javax.net.ssl.SSLSocket;
32 import javax.net.ssl.SSLSocketFactory;
33 import javax.net.ssl.X509TrustManager;
34 import okhttp3.OkHttpClient;
35 import okhttp3.Protocol;
36 import okhttp3.internal.Util;
37 import okhttp3.internal.tls.BasicCertificateChainCleaner;
38 import okhttp3.internal.tls.BasicTrustRootIndex;
39 import okhttp3.internal.tls.CertificateChainCleaner;
40 import okhttp3.internal.tls.TrustRootIndex;
41 import okio.Buffer;
42
43
78 public class Platform {
79 private static final Platform PLATFORM = findPlatform();
80 public static final int INFO = 4;
81 public static final int WARN = 5;
82 private static final Logger logger = Logger.getLogger(OkHttpClient.class.getName());
83
84 public static Platform get() {
85 return PLATFORM;
86 }
87
88
89 public String getPrefix() {
90 return "OkHttp";
91 }
92
93 protected @Nullable X509TrustManager trustManager(SSLSocketFactory sslSocketFactory) {
94
95
96
97 try {
98 Class<?> sslContextClass = Class.forName("sun.security.ssl.SSLContextImpl");
99 Object context = readFieldOrNull(sslSocketFactory, sslContextClass, "context");
100 if (context == null) return null;
101 return readFieldOrNull(context, X509TrustManager.class, "trustManager");
102 } catch (ClassNotFoundException e) {
103 return null;
104 }
105 }
106
107
112 public void configureTlsExtensions(SSLSocket sslSocket, @Nullable String hostname,
113 List<Protocol> protocols) throws IOException {
114 }
115
116
120 public void afterHandshake(SSLSocket sslSocket) {
121 }
122
123
124 public @Nullable String getSelectedProtocol(SSLSocket socket) {
125 return null;
126 }
127
128 public void connectSocket(Socket socket, InetSocketAddress address, int connectTimeout)
129 throws IOException {
130 socket.connect(address, connectTimeout);
131 }
132
133 public void log(int level, String message, @Nullable Throwable t) {
134 Level logLevel = level == WARN ? Level.WARNING : Level.INFO;
135 logger.log(logLevel, message, t);
136 }
137
138 public boolean isCleartextTrafficPermitted(String hostname) {
139 return true;
140 }
141
142
147 public @Nullable Object getStackTraceForCloseable(String closer) {
148 if (logger.isLoggable(Level.FINE)) {
149 return new Throwable(closer);
150 }
151 return null;
152 }
153
154 public void logCloseableLeak(String message, Object stackTrace) {
155 if (stackTrace == null) {
156 message += " To see where this was allocated, set the OkHttpClient logger level to FINE: "
157 + "Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);";
158 }
159 log(WARN, message, (Throwable) stackTrace);
160 }
161
162 public static List<String> alpnProtocolNames(List<Protocol> protocols) {
163 List<String> names = new ArrayList<>(protocols.size());
164 for (int i = 0, size = protocols.size(); i < size; i++) {
165 Protocol protocol = protocols.get(i);
166 if (protocol == Protocol.HTTP_1_0) continue;
167 names.add(protocol.toString());
168 }
169 return names;
170 }
171
172 public CertificateChainCleaner buildCertificateChainCleaner(X509TrustManager trustManager) {
173 return new BasicCertificateChainCleaner(buildTrustRootIndex(trustManager));
174 }
175
176 public CertificateChainCleaner buildCertificateChainCleaner(SSLSocketFactory sslSocketFactory) {
177 X509TrustManager trustManager = trustManager(sslSocketFactory);
178
179 if (trustManager == null) {
180 throw new IllegalStateException("Unable to extract the trust manager on "
181 + Platform.get()
182 + ", sslSocketFactory is "
183 + sslSocketFactory.getClass());
184 }
185
186 return buildCertificateChainCleaner(trustManager);
187 }
188
189 public static boolean isConscryptPreferred() {
190
191 if ("conscrypt".equals(Util.getSystemProperty("okhttp.platform", null))) {
192 return true;
193 }
194
195
196 String preferredProvider = Security.getProviders()[0].getName();
197 return "Conscrypt".equals(preferredProvider);
198 }
199
200
201 private static Platform findPlatform() {
202 if (isAndroid()) {
203 return findAndroidPlatform();
204 } else {
205 return findJvmPlatform();
206 }
207 }
208
209 public static boolean isAndroid() {
210
211
212 return "Dalvik".equals(System.getProperty("java.vm.name"));
213 }
214
215 private static Platform findJvmPlatform() {
216 if (isConscryptPreferred()) {
217 Platform conscrypt = ConscryptPlatform.buildIfSupported();
218
219 if (conscrypt != null) {
220 return conscrypt;
221 }
222 }
223
224 Platform jdk9 = Jdk9Platform.buildIfSupported();
225
226 if (jdk9 != null) {
227 return jdk9;
228 }
229
230 Platform jdkWithJettyBoot = Jdk8WithJettyBootPlatform.buildIfSupported();
231
232 if (jdkWithJettyBoot != null) {
233 return jdkWithJettyBoot;
234 }
235
236
237 return new Platform();
238 }
239
240 private static Platform findAndroidPlatform() {
241 Platform android10 = Android10Platform.buildIfSupported();
242
243 if (android10 != null) {
244 return android10;
245 }
246
247 Platform android = AndroidPlatform.buildIfSupported();
248
249 if (android == null) {
250 throw new NullPointerException("No platform found on Android");
251 }
252
253 return android;
254 }
255
256
260 static byte[] concatLengthPrefixed(List<Protocol> protocols) {
261 Buffer result = new Buffer();
262 for (int i = 0, size = protocols.size(); i < size; i++) {
263 Protocol protocol = protocols.get(i);
264 if (protocol == Protocol.HTTP_1_0) continue;
265 result.writeByte(protocol.toString().length());
266 result.writeUtf8(protocol.toString());
267 }
268 return result.readByteArray();
269 }
270
271 static @Nullable <T> T readFieldOrNull(Object instance, Class<T> fieldType, String fieldName) {
272 for (Class<?> c = instance.getClass(); c != Object.class; c = c.getSuperclass()) {
273 try {
274 Field field = c.getDeclaredField(fieldName);
275 field.setAccessible(true);
276 Object value = field.get(instance);
277 if (!fieldType.isInstance(value)) return null;
278 return fieldType.cast(value);
279 } catch (NoSuchFieldException ignored) {
280 } catch (IllegalAccessException e) {
281 throw new AssertionError();
282 }
283 }
284
285
286 if (!fieldName.equals("delegate")) {
287 Object delegate = readFieldOrNull(instance, Object.class, "delegate");
288 if (delegate != null) return readFieldOrNull(delegate, fieldType, fieldName);
289 }
290
291 return null;
292 }
293
294 public SSLContext getSSLContext() {
295 try {
296 return SSLContext.getInstance("TLS");
297 } catch (NoSuchAlgorithmException e) {
298 throw new IllegalStateException("No TLS provider", e);
299 }
300 }
301
302 public TrustRootIndex buildTrustRootIndex(X509TrustManager trustManager) {
303 return new BasicTrustRootIndex(trustManager.getAcceptedIssuers());
304 }
305
306 public void configureSslSocketFactory(SSLSocketFactory socketFactory) {
307 }
308
309 @Override public String toString() {
310 return getClass().getSimpleName();
311 }
312 }
313