1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-18 20:40:58 +03:00

Merge pull request #645 from square/jwilson_0311_push_socket

Push Socket into HttpConnection/SpdyConnection.
This commit is contained in:
Jesse Wilson
2014-03-12 00:35:14 -04:00
3 changed files with 54 additions and 70 deletions

View File

@@ -25,16 +25,10 @@ import com.squareup.okhttp.internal.http.SpdyTransport;
import com.squareup.okhttp.internal.spdy.SpdyConnection;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Proxy;
import java.net.Socket;
import java.net.SocketTimeoutException;
import javax.net.ssl.SSLSocket;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.ByteString;
import okio.Okio;
import static java.net.HttpURLConnection.HTTP_OK;
import static java.net.HttpURLConnection.HTTP_PROXY_AUTH;
@@ -70,10 +64,6 @@ public final class Connection implements Closeable {
private final Route route;
private Socket socket;
private InputStream in;
private OutputStream out;
private BufferedSource source;
private BufferedSink sink;
private boolean connected = false;
private HttpConnection httpConnection;
private SpdyConnection spdyConnection;
@@ -94,14 +84,11 @@ public final class Connection implements Closeable {
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 {
initSourceAndSink();
httpConnection = new HttpConnection(pool, this, source, sink);
httpConnection = new HttpConnection(pool, this, socket);
}
connected = true;
}
@@ -128,19 +115,19 @@ public final class Connection implements Closeable {
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)) {
boolean useNpn = false;
if (route.modernTls) {
boolean http2 = route.address.protocols.contains(Protocol.HTTP_2);
boolean spdy3 = route.address.protocols.contains(Protocol.SPDY_3);
if (http2 && spdy3) {
platform.setNpnProtocols(sslSocket, Protocol.HTTP2_SPDY3_AND_HTTP);
} else if (route.address.protocols.contains(Protocol.HTTP_2)) {
useNpn = true;
} else if (http2) {
platform.setNpnProtocols(sslSocket, Protocol.HTTP2_AND_HTTP_11);
} else {
useNpn = true;
} else if (spdy3) {
platform.setNpnProtocols(sslSocket, Protocol.SPDY3_AND_HTTP11);
useNpn = true;
}
}
@@ -152,10 +139,7 @@ public final class Connection implements Closeable {
throw new IOException("Hostname '" + route.address.uriHost + "' was not verified");
}
out = sslSocket.getOutputStream();
in = sslSocket.getInputStream();
handshake = Handshake.get(sslSocket.getSession());
initSourceAndSink();
ByteString maybeProtocol;
Protocol selectedProtocol = Protocol.HTTP_11;
@@ -165,11 +149,11 @@ public final class Connection implements Closeable {
if (selectedProtocol.spdyVariant) {
sslSocket.setSoTimeout(0); // SPDY timeouts are set per-stream.
spdyConnection = new SpdyConnection.Builder(route.address.getUriHost(), true, source, sink)
spdyConnection = new SpdyConnection.Builder(route.address.getUriHost(), true, socket)
.protocol(selectedProtocol).build();
spdyConnection.sendConnectionHeader();
} else {
httpConnection = new HttpConnection(pool, this, source, sink);
httpConnection = new HttpConnection(pool, this, socket);
}
}
@@ -206,28 +190,8 @@ public final class Connection implements Closeable {
* #isAlive()}; callers should check {@link #isAlive()} first.
*/
public boolean isReadable() {
if (source == null) {
return true; // Optimistic.
}
if (isSpdy()) {
return true; // Optimistic. We can't test SPDY because its streams are in use.
}
try {
int readTimeout = socket.getSoTimeout();
try {
socket.setSoTimeout(1);
if (source.exhausted()) {
return false; // Stream is exhausted; socket is closed.
}
return true;
} finally {
socket.setSoTimeout(readTimeout);
}
} catch (SocketTimeoutException ignored) {
return true; // Read timed out; socket is good.
} catch (IOException e) {
return false; // Couldn't read; socket is closed.
}
if (httpConnection != null) return httpConnection.isReadable();
return true; // SPDY connections, and connections before connect() are both optimistic.
}
public void resetIdleStartTime() {
@@ -320,9 +284,7 @@ public final class Connection implements Closeable {
* retried if the proxy requires authorization.
*/
private void makeTunnel(TunnelRequest tunnelRequest) throws IOException {
BufferedSource tunnelSource = Okio.buffer(Okio.source(in));
BufferedSink tunnelSink = Okio.buffer(Okio.sink(out));
HttpConnection tunnelConnection = new HttpConnection(pool, this, tunnelSource, tunnelSink);
HttpConnection tunnelConnection = new HttpConnection(pool, this, socket);
Request request = tunnelRequest.getRequest();
String requestLine = tunnelRequest.requestLine();
while (true) {
@@ -335,7 +297,7 @@ public final class Connection implements Closeable {
case HTTP_OK:
// Assume the server won't send a TLS ServerHello until we send a TLS ClientHello. If that
// happens, then we will have buffered bytes that are needed by the SSLSocket!
if (tunnelSource.buffer().size() > 0) {
if (tunnelConnection.bufferSize() > 0) {
throw new IOException("TLS tunnel buffered too many bytes!");
}
return;
@@ -352,9 +314,4 @@ public final class Connection implements Closeable {
}
}
}
private void initSourceAndSink() throws IOException {
source = Okio.buffer(Okio.source(in));
sink = Okio.buffer(Okio.sink(out));
}
}

View File

@@ -27,6 +27,7 @@ import java.io.OutputStream;
import java.net.CacheRequest;
import java.net.ProtocolException;
import java.net.Socket;
import java.net.SocketTimeoutException;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.Deadline;
@@ -72,18 +73,20 @@ public final class HttpConnection {
private final ConnectionPool pool;
private final Connection connection;
private final Socket socket;
private final BufferedSource source;
private final BufferedSink sink;
private int state = STATE_IDLE;
private int onIdle = ON_IDLE_HOLD;
public HttpConnection(ConnectionPool pool, Connection connection, BufferedSource source,
BufferedSink sink) {
public HttpConnection(ConnectionPool pool, Connection connection, Socket socket)
throws IOException {
this.pool = pool;
this.connection = connection;
this.source = source;
this.sink = sink;
this.socket = socket;
this.source = Okio.buffer(Okio.source(socket.getInputStream()));
this.sink = Okio.buffer(Okio.sink(socket.getOutputStream()));
}
/**
@@ -123,6 +126,31 @@ public final class HttpConnection {
sink.flush();
}
/** Returns the number of buffered bytes immediately readable. */
public long bufferSize() {
return source.buffer().size();
}
/** Test for a stale socket. */
public boolean isReadable() {
try {
int readTimeout = socket.getSoTimeout();
try {
socket.setSoTimeout(1);
if (source.exhausted()) {
return false; // Stream is exhausted; socket is closed.
}
return true;
} finally {
socket.setSoTimeout(readTimeout);
}
} catch (SocketTimeoutException ignored) {
return true; // Read timed out; socket is good.
} catch (IOException e) {
return false; // Couldn't read; socket is closed.
}
}
/** Returns bytes of a request header for sending on an HTTP transport. */
public void writeRequest(Headers headers, String requestLine) throws IOException {
if (state != STATE_IDLE) throw new IllegalStateException("state: " + state);
@@ -177,7 +205,6 @@ public final class HttpConnection {
* that may never occur.
*/
public boolean discard(Source in, int timeoutMillis) {
Socket socket = connection.getSocket();
try {
int socketTimeout = socket.getSoTimeout();
socket.setSoTimeout(timeoutMillis);

View File

@@ -21,6 +21,7 @@ import com.squareup.okhttp.internal.Util;
import java.io.Closeable;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
@@ -499,19 +500,18 @@ public final class SpdyConnection implements Closeable {
private boolean client;
public Builder(boolean client, Socket socket) throws IOException {
this("", client, Okio.buffer(Okio.source(socket.getInputStream())),
Okio.buffer(Okio.sink(socket.getOutputStream())));
this(((InetSocketAddress) socket.getRemoteSocketAddress()).getHostName(), client, socket);
}
/**
* @param client true if this peer initiated the connection; false if this
* peer accepted the connection.
*/
public Builder(String hostName, boolean client, BufferedSource source, BufferedSink sink) {
public Builder(String hostName, boolean client, Socket socket) throws IOException {
this.hostName = hostName;
this.client = client;
this.source = source;
this.sink = sink;
this.source = Okio.buffer(Okio.source(socket.getInputStream()));
this.sink = Okio.buffer(Okio.sink(socket.getOutputStream()));
}
public Builder handler(IncomingStreamHandler handler) {