private static SSLSocketFactory newSslSocketFactory(X509TrustManager trustManager) { try { SSLContext sslContext = Platform.get().getSSLContext(); sslContext.init(null, new TrustManager[] { trustManager }, null); return sslContext.getSocketFactory(); } catch (GeneralSecurityException e) { throw new AssertionError("No System TLS", e); // The system has no TLS. Just give up. } }
private void captureCallStackTrace() { Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()"); retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace); }
@Override public @Nullable String getSelectedProtocol(SSLSocket socket) { try { AlpnProvider provider = (AlpnProvider) Proxy.getInvocationHandler(getMethod.invoke(null, socket)); if (!provider.unsupported && provider.selected == null) { Platform.get().log(INFO, "ALPN callback dropped: HTTP/2 is disabled. " + "Is alpn-boot on the boot class path?", null); return null; } return provider.unsupported ? null : provider.selected; } catch (InvocationTargetException | IllegalAccessException e) { throw new AssertionError("failed to get ALPN selected protocol", e); } }
public static CertificateChainCleaner get(X509TrustManager trustManager) { return Platform.get().buildCertificateChainCleaner(trustManager); }
private static SSLSocketFactory createInsecureSslSocketFactory(TrustManager trustManager) { try { SSLContext context = Platform.get().getSSLContext(); context.init(null, new TrustManager[] {trustManager}, null); return context.getSocketFactory(); } catch (Exception e) { throw new AssertionError(e); } }
/** * Sets the socket factory used to secure HTTPS connections. If unset, the system default will * be used. * * @deprecated {@code SSLSocketFactory} does not expose its {@link X509TrustManager}, which is * a field that OkHttp needs to build a clean certificate chain. This method instead must * use reflection to extract the trust manager. Applications should prefer to call {@link * #sslSocketFactory(SSLSocketFactory, X509TrustManager)}, which avoids such reflection. */ public Builder sslSocketFactory(SSLSocketFactory sslSocketFactory) { if (sslSocketFactory == null) throw new NullPointerException("sslSocketFactory == null"); this.sslSocketFactory = sslSocketFactory; this.certificateChainCleaner = Platform.get().buildCertificateChainCleaner(sslSocketFactory); return this; }
public SSLContext sslContext() { try { SSLContext sslContext = Platform.get().getSSLContext(); sslContext.init(new KeyManager[] { keyManager }, new TrustManager[] { trustManager }, new SecureRandom()); return sslContext; } catch (KeyManagementException e) { throw new AssertionError(e); } }
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); }
@Override public void setRequestProperty(String field, String newValue) { if (connected) { throw new IllegalStateException("Cannot set request property after connection is made"); } if (field == null) { throw new NullPointerException("field == null"); } if (newValue == null) { // Silently ignore null header values for backwards compatibility with older // android versions as well as with other URLConnection implementations. // // Some implementations send a malformed HTTP header when faced with // such requests, we respect the spec and ignore the header. Platform.get().log(WARN, "Ignoring header " + field + " because its value was null.", null); return; } requestHeaders.set(field, newValue); }
@Override public void addRequestProperty(String field, String value) { if (connected) { throw new IllegalStateException("Cannot add request property after connection is made"); } if (field == null) { throw new NullPointerException("field == null"); } if (value == null) { // Silently ignore null header values for backwards compatibility with older // android versions as well as with other URLConnection implementations. // // Some implementations send a malformed HTTP header when faced with // such requests, we respect the spec and ignore the header. Platform.get().log(WARN, "Ignoring header " + field + " because its value was null.", null); return; } requestHeaders.add(field, value); }
/** * Reads the public suffix list treating the operation as uninterruptible. We always want to read * the list otherwise we'll be left in a bad state. If the thread was interrupted prior to this * operation, it will be re-interrupted after the list is read. */ private void readTheListUninterruptibly() { boolean interrupted = false; try { while (true) { try { readTheList(); return; } catch (InterruptedIOException e) { Thread.interrupted(); // Temporarily clear the interrupted state. interrupted = true; } catch (IOException e) { Platform.get().log(Platform.WARN, "Failed to read public suffix list", e); return; } } } finally { if (interrupted) { Thread.currentThread().interrupt(); // Retain interrupted status. } } }
private static void sendRequest(OkHttpClient client, String url) { System.out.printf("%-40s ", url); System.out.flush(); System.out.println(Platform.get()); Request request = new Request.Builder().url(url).build(); try (Response response = client.newCall(request).execute()) { Handshake handshake = response.handshake(); System.out.println(handshake.tlsVersion() + " " + handshake.cipherSuite() + " " + response.protocol() + " " + response.code + " " + response.body.bytes().length + "b"); } catch (IOException ioe) { System.out.println(ioe.toString()); } } }
@Override public List<Cookie> loadForRequest(HttpUrl url) { // The RI passes all headers. We don't have 'em, so we don't pass 'em! Map<String, List<String>> headers = Collections.emptyMap(); Map<String, List<String>> cookieHeaders; try { cookieHeaders = cookieHandler.get(url.uri(), headers); } catch (IOException e) { Platform.get().log(WARN, "Loading cookies failed for " + url.resolve("/..."), e); return Collections.emptyList(); } List<Cookie> cookies = null; for (Map.Entry<String, List<String>> entry : cookieHeaders.entrySet()) { String key = entry.getKey(); if (("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key)) && !entry.getValue().isEmpty()) { for (String header : entry.getValue()) { if (cookies == null) cookies = new ArrayList<>(); cookies.addAll(decodeHeaderAsJavaNetCookies(url, header)); } } } return cookies != null ? Collections.unmodifiableList(cookies) : Collections.emptyList(); }
@Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { if (cookieHandler != null) { List<String> cookieStrings = new ArrayList<>(); for (Cookie cookie : cookies) { cookieStrings.add(cookie.toString(true)); } Map<String, List<String>> multimap = Collections.singletonMap("Set-Cookie", cookieStrings); try { cookieHandler.put(url.uri(), multimap); } catch (IOException e) { Platform.get().log(WARN, "Saving cookies failed for " + url.resolve("/..."), e); } } }
String message = "A connection to " + connection.route().address().url() + " was leaked. Did you forget to close a response body?"; Platform.get().logCloseableLeak(message, streamAllocRef.callStackTrace);
@Override public void execute() { try { listener.onStream(newStream); } catch (IOException e) { Platform.get().log( INFO, "Http2Connection.Listener failure for " + connectionName, e); try { newStream.close(ErrorCode.PROTOCOL_ERROR); } catch (IOException ignored) { } } } });
private List<InetAddress> readResponse(String hostname, Response response) throws Exception { if (response.cacheResponse() == null && response.protocol() != Protocol.HTTP_2) { Platform.get().log(Platform.WARN, "Incorrect protocol: " + response.protocol(), null); } try { if (!response.isSuccessful()) { throw new IOException("response: " + response.code() + " " + response.message()); } ResponseBody body = response.body(); if (body.contentLength() > MAX_RESPONSE_SIZE) { throw new IOException("response size exceeds limit (" + MAX_RESPONSE_SIZE + " bytes): " + body.contentLength() + " bytes"); } ByteString responseBytes = body.source().readByteString(); return DnsRecordCodec.decodeAnswers(hostname, responseBytes); } finally { response.close(); } }
public static void main(String[] args) { //System.setProperty("javax.net.debug", "ssl:handshake:verbose"); Security.insertProviderAt(Conscrypt.newProviderBuilder().provideTrustManager().build(), 1); System.out.println( "Running tests using " + Platform.get() + " " + System.getProperty("java.vm.version")); // https://github.com/tlswg/tls13-spec/wiki/Implementations List<String> urls = Arrays.asList("https://enabled.tls13.com", "https://www.howsmyssl.com/a/check", "https://tls13.cloudflare.com", "https://www.allizom.org/robots.txt", "https://tls13.crypto.mozilla.org/", "https://tls.ctf.network/robots.txt", "https://rustls.jbp.io/", "https://h2o.examp1e.net", "https://mew.org/", "https://tls13.baishancloud.com/", "https://tls13.akamai.io/", "https://swifttls.org/", "https://www.googleapis.com/robots.txt", "https://graph.facebook.com/robots.txt", "https://api.twitter.com/robots.txt", "https://connect.squareup.com/robots.txt"); System.out.println("TLS1.3+TLS1.2"); testClient(urls, buildClient(ConnectionSpec.RESTRICTED_TLS)); System.out.println("\nTLS1.3 only"); testClient(urls, buildClient(TLS_13)); System.out.println("\nTLS1.3 then fallback"); testClient(urls, buildClient(TLS_13, TLS_12)); }
/** Does all the work necessary to build a full HTTP or HTTPS connection on a raw socket. */ private void connectSocket(int connectTimeout, int readTimeout, Call call, EventListener eventListener) throws IOException { Proxy proxy = route.proxy(); Address address = route.address(); rawSocket = proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.HTTP ? address.socketFactory().createSocket() : new Socket(proxy); eventListener.connectStart(call, route.socketAddress(), proxy); rawSocket.setSoTimeout(readTimeout); try { Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout); } catch (ConnectException e) { ConnectException ce = new ConnectException("Failed to connect to " + route.socketAddress()); ce.initCause(e); throw ce; } // The following try/catch block is a pseudo hacky way to get around a crash on Android 7.0 // More details: // https://github.com/square/okhttp/issues/3245 // https://android-review.googlesource.com/#/c/271775/ try { source = Okio.buffer(Okio.source(rawSocket)); sink = Okio.buffer(Okio.sink(rawSocket)); } catch (NullPointerException npe) { if (NPE_THROW_WITH_NULL.equals(npe.getMessage())) { throw new IOException(npe); } } }
@Override protected void execute() { boolean signalledCallback = false; timeout.enter(); try { Response response = getResponseWithInterceptorChain(); if (retryAndFollowUpInterceptor.isCanceled()) { signalledCallback = true; responseCallback.onFailure(RealCall.this, new IOException("Canceled")); } else { signalledCallback = true; responseCallback.onResponse(RealCall.this, response); } } catch (IOException e) { e = timeoutExit(e); if (signalledCallback) { // Do not signal the callback twice! Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e); } else { eventListener.callFailed(RealCall.this, e); responseCallback.onFailure(RealCall.this, e); } } finally { client.dispatcher().finished(this); } } }