@Override public String toString() { return "Connection{" + route.address().url().host() + ":" + route.address().url().port() + ", proxy=" + route.proxy() + " hostAddress=" + route.socketAddress() + " cipherSuite=" + (handshake != null ? handshake.cipherSuite() : "none") + " protocol=" + protocol + '}'; } }
List<ConnectionSpec> connectionSpecs = route.address().connectionSpecs(); ConnectionSpecSelector connectionSpecSelector = new ConnectionSpecSelector(connectionSpecs); if (route.address().sslSocketFactory() == null) { if (!connectionSpecs.contains(ConnectionSpec.CLEARTEXT)) { throw new RouteException(new UnknownServiceException( "CLEARTEXT communication not enabled for client")); String host = route.address().url().host(); if (!Platform.get().isCleartextTrafficPermitted(host)) { throw new RouteException(new UnknownServiceException( if (route.address().protocols().contains(Protocol.H2_PRIOR_KNOWLEDGE)) { throw new RouteException(new UnknownServiceException( "H2_PRIOR_KNOWLEDGE cannot be used with HTTPS")); if (route.requiresTunnel()) { connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener); if (rawSocket == null) { eventListener.connectEnd(call, route.socketAddress(), route.proxy(), protocol); break; } catch (IOException e) { eventListener.connectFailed(call, route.socketAddress(), route.proxy(), null, e); if (route.requiresTunnel() && rawSocket == null) { ProtocolException exception = new ProtocolException("Too many tunnel connections attempted: " + MAX_TUNNEL_ATTEMPTS);
public Selection next() throws IOException { if (!hasNext()) { throw new NoSuchElementException(); } // Compute the next set of routes to attempt. List<Route> routes = new ArrayList<>(); while (hasNextProxy()) { // Postponed routes are always tried last. For example, if we have 2 proxies and all the // routes for proxy1 should be postponed, we'll move to proxy2. Only after we've exhausted // all the good routes will we attempt the postponed routes. Proxy proxy = nextProxy(); for (int i = 0, size = inetSocketAddresses.size(); i < size; i++) { Route route = new Route(address, proxy, inetSocketAddresses.get(i)); if (routeDatabase.shouldPostpone(route)) { postponedRoutes.add(route); } else { routes.add(route); } } if (!routes.isEmpty()) { break; } } if (routes.isEmpty()) { // We've exhausted all Proxies so fallback to the postponed routes. routes.addAll(postponedRoutes); postponedRoutes.clear(); } return new Selection(routes); }
/** * Does all the work to build an HTTPS connection over a proxy tunnel. The catch here is that a * proxy server can issue an auth challenge and then close the connection. */ private void connectTunnel(int connectTimeout, int readTimeout, int writeTimeout, Call call, EventListener eventListener) throws IOException { Request tunnelRequest = createTunnelRequest(); HttpUrl url = tunnelRequest.url(); for (int i = 0; i < MAX_TUNNEL_ATTEMPTS; i++) { connectSocket(connectTimeout, readTimeout, call, eventListener); tunnelRequest = createTunnel(readTimeout, writeTimeout, tunnelRequest, url); if (tunnelRequest == null) break; // Tunnel successfully created. // The proxy decided to close the connection after an auth challenge. We need to create a new // connection, but this time with the auth credentials. closeQuietly(rawSocket); rawSocket = null; sink = null; source = null; eventListener.connectEnd(call, route.socketAddress(), route.proxy(), null); } }
/** * Clients should invoke this method when they encounter a connectivity failure on a connection * returned by this route selector. */ public void connectFailed(Route failedRoute, IOException failure) { if (failedRoute.proxy().type() != Proxy.Type.DIRECT && address.proxySelector() != null) { // Tell the proxy selector when we fail to connect on a fresh connection. address.proxySelector().connectFailed( address.url().uri(), failedRoute.proxy().address(), failure); } routeDatabase.failed(failedRoute); }
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);
/** Does all the work necessary to build a full HTTP or HTTPS connection on a raw socket. */ private void connectSocket(int connectTimeout, int readTimeout, int writeTimeout, ConnectionSpecSelector connectionSpecSelector) throws IOException { rawSocket.setSoTimeout(readTimeout); try { Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout); } catch (ConnectException e) { throw new ConnectException("Failed to connect to " + route.socketAddress()); } source = Okio.buffer(Okio.source(rawSocket)); sink = Okio.buffer(Okio.sink(rawSocket)); if (route.address().sslSocketFactory() != null) { connectTls(readTimeout, writeTimeout, connectionSpecSelector); } else { protocol = Protocol.HTTP_1_1; socket = rawSocket; } if (protocol == Protocol.SPDY_3 || protocol == Protocol.HTTP_2) { socket.setSoTimeout(0); // Framed connection timeouts are set per-stream. FramedConnection framedConnection = new FramedConnection.Builder(true) .socket(socket, route.address().url().host(), source, sink) .protocol(protocol) .build(); framedConnection.sendConnectionPreface(); // Only assign the framed connection once the preface has been sent successfully. this.framedConnection = framedConnection; } }
private void connectTls(int readTimeout, int writeTimeout, ConnectionSpecSelector connectionSpecSelector) throws IOException { if (route.requiresTunnel()) { createTunnel(readTimeout, writeTimeout); Address address = route.address(); SSLSocketFactory sslSocketFactory = address.sslSocketFactory(); boolean success = false;
static void parseRouteAddress(Chain chain, Span span) { if (span.isNoop()) return; Connection connection = chain.connection(); if (connection == null) return; InetSocketAddress socketAddress = connection.route().socketAddress(); span.remoteIpAndPort(socketAddress.getHostString(), socketAddress.getPort()); }
if (route == null || !route.requiresTunnel()) { final String method = request.method(); final String uri = RequestLine.requestPath(request.url());
proxy = chain.connection().route().proxy(); handshake = chain.connection().handshake(); lock.notifyAll();
/** * Does all the work to build an HTTPS connection over a proxy tunnel. The catch here is that a * proxy server can issue an auth challenge and then close the connection. */ private void connectTunnel(int connectTimeout, int readTimeout, int writeTimeout, Call call, EventListener eventListener) throws IOException { Request tunnelRequest = createTunnelRequest(); HttpUrl url = tunnelRequest.url(); for (int i = 0; i < MAX_TUNNEL_ATTEMPTS; i++) { connectSocket(connectTimeout, readTimeout, call, eventListener); tunnelRequest = createTunnel(readTimeout, writeTimeout, tunnelRequest, url); if (tunnelRequest == null) break; // Tunnel successfully created. // The proxy decided to close the connection after an auth challenge. We need to create a new // connection, but this time with the auth credentials. closeQuietly(rawSocket); rawSocket = null; sink = null; source = null; eventListener.connectEnd(call, route.socketAddress(), route.proxy(), null); } }
public boolean supportsUrl(HttpUrl url) { if (url.port() != route.address().url().port()) { return false; // Port mismatch. } if (!url.host().equals(route.address().url().host())) { // We have a host mismatch. But if the certificate matches, we're still good. return handshake != null && OkHostnameVerifier.INSTANCE.verify( url.host(), (X509Certificate) handshake.peerCertificates().get(0)); } return true; // Success. The URL is supported. }
/** Does all the work necessary to build a full HTTP or HTTPS connection on a raw socket. */ private void connectSocket(int connectTimeout, int readTimeout, int writeTimeout, ConnectionSpecSelector connectionSpecSelector) throws IOException { rawSocket.setSoTimeout(readTimeout); try { Platform.get().connectSocket(rawSocket, route.socketAddress(), connectTimeout); } catch (ConnectException e) { throw new ConnectException("Failed to connect to " + route.socketAddress()); } source = Okio.buffer(Okio.source(rawSocket)); sink = Okio.buffer(Okio.sink(rawSocket)); if (route.address().sslSocketFactory() != null) { connectTls(readTimeout, writeTimeout, connectionSpecSelector); } else { protocol = Protocol.HTTP_1_1; socket = rawSocket; } if (protocol == Protocol.SPDY_3 || protocol == Protocol.HTTP_2) { socket.setSoTimeout(0); // Framed connection timeouts are set per-stream. FramedConnection framedConnection = new FramedConnection.Builder(true) .socket(socket, route.address().url().host(), source, sink) .protocol(protocol) .build(); framedConnection.sendConnectionPreface(); // Only assign the framed connection once the preface has been sent successfully. this.framedConnection = framedConnection; } }
private void connectTls(int readTimeout, int writeTimeout, ConnectionSpecSelector connectionSpecSelector) throws IOException { if (route.requiresTunnel()) { createTunnel(readTimeout, writeTimeout); Address address = route.address(); SSLSocketFactory sslSocketFactory = address.sslSocketFactory(); boolean success = false;
@Override public InetSocketAddress getInetSocketAddress() { return route.socketAddress(); }
if (route == null || !route.requiresTunnel()) { final String method = request.method(); final String uri = RequestLine.requestPath(request.url());
/** 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); } } }
List<ConnectionSpec> connectionSpecs = route.address().connectionSpecs(); ConnectionSpecSelector connectionSpecSelector = new ConnectionSpecSelector(connectionSpecs); if (route.address().sslSocketFactory() == null) { if (!connectionSpecs.contains(ConnectionSpec.CLEARTEXT)) { throw new RouteException(new UnknownServiceException( "CLEARTEXT communication not enabled for client")); String host = route.address().url().host(); if (!Platform.get().isCleartextTrafficPermitted(host)) { throw new RouteException(new UnknownServiceException( if (route.address().protocols().contains(Protocol.H2_PRIOR_KNOWLEDGE)) { throw new RouteException(new UnknownServiceException( "H2_PRIOR_KNOWLEDGE cannot be used with HTTPS")); if (route.requiresTunnel()) { connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener); if (rawSocket == null) { eventListener.connectEnd(call, route.socketAddress(), route.proxy(), protocol); break; } catch (IOException e) { eventListener.connectFailed(call, route.socketAddress(), route.proxy(), null, e); if (route.requiresTunnel() && rawSocket == null) { ProtocolException exception = new ProtocolException("Too many tunnel connections attempted: " + MAX_TUNNEL_ATTEMPTS);