public void connect(int connectTimeout, int readTimeout, TunnelRequest tunnelRequest) throws IOException { if (connected) { throw new IllegalStateException("already connected"); } connected = true; socket = (route.proxy.type() != Proxy.Type.HTTP) ? new Socket(route.proxy) : new Socket(); Platform.get().connectSocket(socket, route.inetSocketAddress, connectTimeout); socket.setSoTimeout(readTimeout); in = socket.getInputStream(); out = socket.getOutputStream(); if (route.address.sslSocketFactory != null) { upgradeToTls(tunnelRequest); } // Use MTU-sized buffers to send fewer packets. int mtu = Platform.get().getMtu(socket); if (mtu < 1024) mtu = 1024; if (mtu > 8192) mtu = 8192; in = new BufferedInputStream(in, mtu); out = new BufferedOutputStream(out, mtu); }
@Override public void configureTls(SSLSocket socket, String uriHost, String tlsVersion) { super.configureTls(socket, uriHost, tlsVersion); if (tlsVersion.equals("TLSv1") && openSslSocketClass.isInstance(socket)) { try { setUseSessionTickets.invoke(socket, true); setHostname.invoke(socket, uriHost); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new AssertionError(e); } } }
public void connect(int connectTimeout, int readTimeout, TunnelRequest tunnelRequest) throws IOException { if (connected) throw new IllegalStateException("already connected"); socket = (route.proxy.type() != Proxy.Type.HTTP) ? new Socket(route.proxy) : new Socket(); Platform.get().connectSocket(socket, route.inetSocketAddress, connectTimeout); socket.setSoTimeout(readTimeout); if (route.address.sslSocketFactory != null) { upgradeToTls(tunnelRequest); } else { httpConnection = new HttpConnection(pool, this, socket); } connected = true; }
public void connect(int connectTimeout, int readTimeout, TunnelRequest tunnelRequest) throws IOException { if (connected) throw new IllegalStateException("already connected"); connected = true; socket = (route.proxy.type() != Proxy.Type.HTTP) ? new Socket(route.proxy) : new Socket(); Platform.get().connectSocket(socket, route.inetSocketAddress, connectTimeout); socket.setSoTimeout(readTimeout); in = socket.getInputStream(); out = socket.getOutputStream(); if (route.address.sslSocketFactory != null) { upgradeToTls(tunnelRequest); } else { streamWrapper(); } }
/** Create an {@code SSLSocket} and perform the TLS handshake and certificate validation. */ private void upgradeToTls(TunnelRequest tunnelRequest) throws IOException { Platform platform = Platform.get(); // Make an SSL Tunnel on the first message pair of each SSL + proxy connection. if (requiresTunnel()) { makeTunnel(tunnelRequest); } // Create the wrapper over connected socket. socket = route.address.sslSocketFactory.createSocket( socket, route.address.uriHost, route.address.uriPort, true /* autoClose */); SSLSocket sslSocket = (SSLSocket) socket; if (route.modernTls) { platform.enableTlsExtensions(sslSocket, route.address.uriHost); } else { platform.supportTlsIntolerantServer(sslSocket); } boolean useNpn = route.modernTls && route.address.transports.contains("spdy/3"); if (useNpn) { platform.setNpnProtocols(sslSocket, NPN_PROTOCOLS); } // Force handshake. This can throw! sslSocket.startHandshake(); // Verify that the socket's certificates are acceptable for the target host. if (!route.address.hostnameVerifier.verify(route.address.uriHost, sslSocket.getSession())) { throw new IOException("Hostname '" + route.address.uriHost + "' was not verified"); } out = sslSocket.getOutputStream(); in = sslSocket.getInputStream(); byte[] selectedProtocol; if (useNpn && (selectedProtocol = platform.getNpnSelectedProtocol(sslSocket)) != null) { if (Arrays.equals(selectedProtocol, SPDY3)) { sslSocket.setSoTimeout(0); // SPDY timeouts are set per-stream. spdyConnection = new SpdyConnection.Builder(route.address.getUriHost(), true, in, out).build(); spdyConnection.sendConnectionHeader(); } else if (!Arrays.equals(selectedProtocol, HTTP_11)) { throw new IOException( "Unexpected NPN transport " + new String(selectedProtocol, "ISO-8859-1")); } } }
/** * @param requestHeaders the client's supplied request headers. This class creates a private copy * that it can mutate. * @param connection the connection used for an intermediate response immediately prior to this * request/response pair, such as a same-host redirect. This engine assumes ownership of the * connection and must release it when it is unneeded. */ public HttpEngine( OkHttpClient client, Policy policy, String method, RawHeaders requestHeaders, Connection connection, RetryableOutputStream requestBodyOut) throws IOException { this.client = client; this.policy = policy; this.method = method; this.connection = connection; this.requestBodyOut = requestBodyOut; try { uri = Platform.get().toUriLenient(policy.getURL()); } catch (URISyntaxException e) { throw new IOException(e.getMessage()); } this.requestHeaders = new RequestHeaders(uri, new RawHeaders(requestHeaders)); }
@Override public final 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().logW("Ignoring header " + field + " because its value was null."); return; } if ("X-Android-Transports".equals(field)) { setTransports(value, true /* append */); } else { requestHeaders.add(field, value); } }
@Override public void log(String message) { Platform.get().logW(message); }
/** Create an {@code SSLSocket} and perform the TLS handshake and certificate validation. */ private void upgradeToTls(TunnelRequest tunnelRequest) throws IOException { Platform platform = Platform.get(); // Make an SSL Tunnel on the first message pair of each SSL + proxy connection. if (requiresTunnel()) { makeTunnel(tunnelRequest); } // Create the wrapper over connected socket. socket = route.address.sslSocketFactory.createSocket( socket, route.address.uriHost, route.address.uriPort, true /* autoClose */); SSLSocket sslSocket = (SSLSocket) socket; if (route.modernTls) { platform.enableTlsExtensions(sslSocket, route.address.uriHost); } else { platform.supportTlsIntolerantServer(sslSocket); } boolean useNpn = route.modernTls && ( // Contains a spdy variant. route.address.protocols.contains(Protocol.HTTP_2) || route.address.protocols.contains(Protocol.SPDY_3)); if (useNpn) { if (route.address.protocols.contains(Protocol.HTTP_2) // Contains both spdy variants. && route.address.protocols.contains(Protocol.SPDY_3)) { platform.setNpnProtocols(sslSocket, Protocol.HTTP2_SPDY3_AND_HTTP); } else if (route.address.protocols.contains(Protocol.HTTP_2)) { platform.setNpnProtocols(sslSocket, Protocol.HTTP2_AND_HTTP_11); } else { platform.setNpnProtocols(sslSocket, Protocol.SPDY3_AND_HTTP11); } } // Force handshake. This can throw! sslSocket.startHandshake(); // Verify that the socket's certificates are acceptable for the target host. if (!route.address.hostnameVerifier.verify(route.address.uriHost, sslSocket.getSession())) { throw new IOException("Hostname '" + route.address.uriHost + "' was not verified"); } out = sslSocket.getOutputStream(); in = sslSocket.getInputStream(); handshake = Handshake.get(sslSocket.getSession()); streamWrapper(); ByteString maybeProtocol; if (useNpn && (maybeProtocol = platform.getNpnSelectedProtocol(sslSocket)) != null) { Protocol selectedProtocol = Protocol.find(maybeProtocol); // Throws IOE on unknown. if (selectedProtocol.spdyVariant) { sslSocket.setSoTimeout(0); // SPDY timeouts are set per-stream. spdyConnection = new SpdyConnection.Builder(route.address.getUriHost(), true, in, out) .protocol(selectedProtocol) .build(); spdyConnection.sendConnectionHeader(); } } }
private void assertResponseHeader(HttpURLConnection connection, String expected) { final String headerFieldPrefix = Platform.get().getPrefix(); assertEquals(expected, connection.getHeaderField(headerFieldPrefix + "-Response-Source")); }