From 957537774b319bb0109819258a11af78a98bcb97 Mon Sep 17 00:00:00 2001 From: jwilson Date: Tue, 31 Dec 2013 20:52:49 -0500 Subject: [PATCH] Clean up around HttpEngine.sendRequest(). Move gateway timeout failures to CacheStrategy, and inline methods nearby for a strict top-to-bottom flow in this method. It becomes more obvious that the end of sendRequest has two cases: we need a connection (opening if necessary) or we don't need a connection (closing if necessary). Previously this was true but not as explicit. --- .../java/com/squareup/okhttp/Connection.java | 2 +- .../squareup/okhttp/HttpResponseCache.java | 3 +- .../java/com/squareup/okhttp/Response.java | 30 +-- .../com/squareup/okhttp/ResponseSource.java | 4 + .../okhttp/internal/http/CacheStrategy.java | 60 +++++- .../okhttp/internal/http/HttpEngine.java | 175 +++++++----------- .../okhttp/internal/http/HttpTransport.java | 36 ++-- .../okhttp/internal/http/SpdyTransport.java | 26 +-- .../okhttp/internal/http/Transport.java | 6 +- .../okhttp/internal/http/HeadersTest.java | 2 +- 10 files changed, 178 insertions(+), 166 deletions(-) diff --git a/okhttp/src/main/java/com/squareup/okhttp/Connection.java b/okhttp/src/main/java/com/squareup/okhttp/Connection.java index 8f585628e..26625b15e 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/Connection.java +++ b/okhttp/src/main/java/com/squareup/okhttp/Connection.java @@ -311,7 +311,7 @@ public final class Connection implements Closeable { String requestLine = tunnelRequest.requestLine(); while (true) { HttpTransport.writeRequest(out, request.headers(), requestLine); - Response response = HttpTransport.readResponse(request, in).build(); + Response response = HttpTransport.readResponse(in).request(request).build(); switch (response.code()) { case HTTP_OK: diff --git a/okhttp/src/main/java/com/squareup/okhttp/HttpResponseCache.java b/okhttp/src/main/java/com/squareup/okhttp/HttpResponseCache.java index ebed3e5cf..e19657765 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/HttpResponseCache.java +++ b/okhttp/src/main/java/com/squareup/okhttp/HttpResponseCache.java @@ -527,7 +527,8 @@ public final class HttpResponseCache extends ResponseCache implements OkResponse public Response response(Request request, DiskLruCache.Snapshot snapshot) { String contentType = responseHeaders.get("Content-Type"); String contentLength = responseHeaders.get("Content-Length"); - return new Response.Builder(request) + return new Response.Builder() + .request(request) .statusLine(statusLine) .headers(responseHeaders) .body(new CacheResponseBody(snapshot, contentType, contentLength)) diff --git a/okhttp/src/main/java/com/squareup/okhttp/Response.java b/okhttp/src/main/java/com/squareup/okhttp/Response.java index 059621034..61a56ca81 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/Response.java +++ b/okhttp/src/main/java/com/squareup/okhttp/Response.java @@ -19,8 +19,8 @@ import com.squareup.okhttp.internal.Util; import com.squareup.okhttp.internal.http.HeaderParser; import com.squareup.okhttp.internal.http.Headers; import com.squareup.okhttp.internal.http.HttpDate; -import com.squareup.okhttp.internal.http.SyntheticHeaders; import com.squareup.okhttp.internal.http.StatusLine; +import com.squareup.okhttp.internal.http.SyntheticHeaders; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; @@ -144,12 +144,7 @@ public final class Response { } public Builder newBuilder() { - return new Builder(request) - .statusLine(statusLine) - .handshake(handshake) - .headers(headers) - .body(body) - .redirectedBy(redirectedBy); + return new Builder(this); } /** @@ -597,16 +592,29 @@ public final class Response { } public static class Builder { - private final Request request; + private Request request; private StatusLine statusLine; private Handshake handshake; - private Headers.Builder headers = new Headers.Builder(); + private Headers.Builder headers; private Body body; private Response redirectedBy; - public Builder(Request request) { - if (request == null) throw new IllegalArgumentException("request == null"); + public Builder() { + headers = new Headers.Builder(); + } + + private Builder(Response response) { + this.request = response.request; + this.statusLine = response.statusLine; + this.handshake = response.handshake; + this.headers = response.headers.newBuilder(); + this.body = response.body; + this.redirectedBy = response.redirectedBy; + } + + public Builder request(Request request) { this.request = request; + return this; } public Builder statusLine(StatusLine statusLine) { diff --git a/okhttp/src/main/java/com/squareup/okhttp/ResponseSource.java b/okhttp/src/main/java/com/squareup/okhttp/ResponseSource.java index dbe17cb47..915fa58e6 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/ResponseSource.java +++ b/okhttp/src/main/java/com/squareup/okhttp/ResponseSource.java @@ -41,4 +41,8 @@ public enum ResponseSource { public boolean requiresConnection() { return this == CONDITIONAL_CACHE || this == NETWORK; } + + public boolean usesCache() { + return this == CACHE || this == CONDITIONAL_CACHE; + } } diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/http/CacheStrategy.java b/okhttp/src/main/java/com/squareup/okhttp/internal/http/CacheStrategy.java index 5be92a820..8215f50df 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/http/CacheStrategy.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/http/CacheStrategy.java @@ -1,11 +1,16 @@ package com.squareup.okhttp.internal.http; +import com.squareup.okhttp.MediaType; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import com.squareup.okhttp.ResponseSource; +import java.io.IOException; +import java.io.InputStream; import java.net.HttpURLConnection; import java.util.concurrent.TimeUnit; +import static com.squareup.okhttp.internal.Util.EMPTY_INPUT_STREAM; + /** * Given a request and cached response, this figures out whether to use the * network, the cache, or both. @@ -15,6 +20,30 @@ import java.util.concurrent.TimeUnit; * response may gain a warning if it is potentially stale. */ public final class CacheStrategy { + private static final Response.Body EMPTY_BODY = new Response.Body() { + @Override public boolean ready() throws IOException { + return true; + } + @Override public MediaType contentType() { + return null; + } + @Override public long contentLength() { + return 0; + } + @Override public InputStream byteStream() { + return EMPTY_INPUT_STREAM; + } + }; + + private static final StatusLine GATEWAY_TIMEOUT_STATUS_LINE; + static { + try { + GATEWAY_TIMEOUT_STATUS_LINE = new StatusLine("HTTP/1.1 504 Gateway Timeout"); + } catch (IOException e) { + throw new AssertionError(); + } + } + public final Request request; public final Response response; public final ResponseSource source; @@ -114,8 +143,35 @@ public final class CacheStrategy { * Returns a strategy to satisfy {@code request} using the a cached response * {@code response}. */ - public static CacheStrategy get( - long nowMillis, Response response, Request request) { + public static CacheStrategy get(long nowMillis, Response response, Request request) { + CacheStrategy candidate = getCandidate(nowMillis, response, request); + + if (candidate.source != ResponseSource.CACHE && request.isOnlyIfCached()) { + // We're forbidden from using the network, but the cache is insufficient. + Response noneResponse = new Response.Builder() + .request(candidate.request) + .statusLine(GATEWAY_TIMEOUT_STATUS_LINE) + .setResponseSource(ResponseSource.NONE) + .body(EMPTY_BODY) + .build(); + return new CacheStrategy(candidate.request, noneResponse, ResponseSource.NONE); + } + + return candidate; + } + + /** Returns a strategy to use assuming the request can use the network. */ + private static CacheStrategy getCandidate(long nowMillis, Response response, Request request) { + // No cached response. + if (response == null) { + return new CacheStrategy(request, response, ResponseSource.NETWORK); + } + + // Drop the cached response if it's missing a required handshake. + if (request.isHttps() && response.handshake() == null) { + return new CacheStrategy(request, response, ResponseSource.NETWORK); + } + // If this response shouldn't have been stored, it should never be used // as a response source. This check should be redundant as long as the // persistence store is well-behaved and the rules are constant. diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java b/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java index 2d2f5fac8..db3f4e440 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpEngine.java @@ -38,7 +38,6 @@ import java.util.zip.GZIPInputStream; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSocketFactory; -import static com.squareup.okhttp.internal.Util.EMPTY_INPUT_STREAM; import static com.squareup.okhttp.internal.Util.closeQuietly; import static com.squareup.okhttp.internal.Util.getDefaultPort; import static com.squareup.okhttp.internal.Util.getEffectivePort; @@ -70,21 +69,6 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT; * required, use {@link #automaticallyReleaseConnectionToPool()}. */ public class HttpEngine { - private static final Response.Body EMPTY_BODY = new Response.Body() { - @Override public boolean ready() throws IOException { - return true; - } - @Override public MediaType contentType() { - return null; - } - @Override public long contentLength() { - return 0; - } - @Override public InputStream byteStream() { - return EMPTY_INPUT_STREAM; - } - }; - final Policy policy; final OkHttpClient client; @@ -155,69 +139,59 @@ public class HttpEngine { * writing the request body if it exists. */ public final void sendRequest() throws IOException { - if (responseSource != null) return; + if (responseSource != null) return; // Already sent. + if (transport != null) throw new IllegalStateException(); prepareRawRequestHeaders(); - responseSource = chooseResponseSource(); + OkResponseCache responseCache = client.getOkResponseCache(); + + Response cacheResponse = responseCache != null + ? responseCache.get(request) + : null; + long now = System.currentTimeMillis(); + CacheStrategy cacheStrategy = CacheStrategy.get(now, cacheResponse, request); + responseSource = cacheStrategy.source; + request = cacheStrategy.request; + + if (responseCache != null) { + responseCache.trackResponse(responseSource); + } + + if (responseSource != ResponseSource.NETWORK) { + validatingResponse = cacheStrategy.response; + } + + if (cacheResponse != null && !responseSource.usesCache()) { + closeQuietly(cacheResponse.body()); // We don't need this cached response. Close it. + } if (responseSource.requiresConnection()) { - sendSocketRequest(); - } else if (connection != null) { - client.getConnectionPool().recycle(connection); - connection = null; - } - } + // Open a connection unless we inherited one from a redirect. + if (connection == null) { + connect(); + } - /** Returns a source that can satisfy the request. */ - private ResponseSource chooseResponseSource() throws IOException { - OkResponseCache responseCache = client.getOkResponseCache(); - if (responseCache == null) return ResponseSource.NETWORK; // No cache? Easy decision. + transport = (Transport) connection.newTransport(this); + request = transport.prepareRequest(request); - Response candidate = responseCache.get(request); - - ResponseSource result; - if (candidate == null) { - result = ResponseSource.NETWORK; - - } else if (request.isHttps() && candidate.handshake() == null) { - // Drop the cached response if it's missing a required handshake. - result = ResponseSource.NETWORK; + // Create a request body if we don't have one already. We'll already have + // one if we're retrying a failed POST. + if (hasRequestBody() && requestBodyOut == null) { + requestBodyOut = transport.createRequestBody(request); + } } else { - // We've got a lead on a cached response. Ask response strategy to analyze it. - long now = System.currentTimeMillis(); - CacheStrategy cacheStrategy = CacheStrategy.get(now, candidate, request); - result = cacheStrategy.source; - this.request = cacheStrategy.request; - - if (result == ResponseSource.CACHE || result == ResponseSource.CONDITIONAL_CACHE) { - this.validatingResponse = cacheStrategy.response; - } - } - - if (candidate != null && result == ResponseSource.NETWORK) { - closeQuietly(candidate.body()); // We aren't using the cached response. Close it. - } - - if (result == ResponseSource.CACHE) { - promoteValidatingResponse(); - } else if (request.isOnlyIfCached()) { - // We're forbidden from using the network, but the cache is insufficient. - if (result == ResponseSource.CONDITIONAL_CACHE) { - closeQuietly(validatingResponse.body()); + // We're using a cached response. Close the connection we may have inherited from a redirect. + if (connection != null) { + disconnect(); } - result = ResponseSource.NONE; - this.validatingResponse = new Response.Builder(request) - .statusLine(new StatusLine("HTTP/1.1 504 Gateway Timeout")) - .setResponseSource(result) - .body(EMPTY_BODY) - .build(); - promoteValidatingResponse(); + // No need for the network! Promote the cached response immediately. + this.response = validatingResponse; + if (validatingResponse.body() != null) { + initContentStream(validatingResponse.body().byteStream()); + } } - - responseCache.trackResponse(result); - return result; } private Response cacheableResponse() { @@ -229,30 +203,10 @@ public class HttpEngine { .build(); } - private void sendSocketRequest() throws IOException { - if (connection == null) { - connect(); - } - - if (transport != null) { - throw new IllegalStateException(); - } - - transport = (Transport) connection.newTransport(this); - request = transport.prepareRequest(request); - - if (hasRequestBody() && requestBodyOut == null) { - // Create a request body if we don't have one already. We'll already - // have one if we're retrying a failed POST. - requestBodyOut = transport.createRequestBody(); - } - } - /** Connect to the origin server either directly or via a proxy. */ - protected final void connect() throws IOException { - if (connection != null) { - return; - } + private void connect() throws IOException { + if (connection != null) throw new IllegalStateException(); + if (routeSelector == null) { String uriHost = request.url().getHost(); if (uriHost == null || uriHost.length() == 0) { @@ -269,7 +223,9 @@ public class HttpEngine { routeSelector = new RouteSelector(address, request.uri(), client.getProxySelector(), client.getConnectionPool(), Dns.DEFAULT, client.getRoutesDatabase()); } + connection = routeSelector.next(request.method()); + if (!connection.isConnected()) { connection.connect(client.getConnectTimeout(), client.getReadTimeout(), getTunnelConfig()); client.getConnectionPool().maybeShare(connection); @@ -282,26 +238,24 @@ public class HttpEngine { policy.setSelectedProxy(connection.getRoute().getProxy()); } + /** + * Recycle the connection to the origin server. It is an error to call this + * with a request in flight. + */ + private void disconnect() { + client.getConnectionPool().recycle(connection); + connection = null; + } + /** * Called immediately before the transport transmits HTTP request headers. * This is used to observe the sent time should the request be cached. */ public void writingRequestHeaders() { - if (sentRequestMillis != -1) { - throw new IllegalStateException(); - } + if (sentRequestMillis != -1) throw new IllegalStateException(); sentRequestMillis = System.currentTimeMillis(); } - private void promoteValidatingResponse() throws IOException { - if (this.responseBodyIn != null) throw new IllegalStateException(); - - this.response = validatingResponse; - if (validatingResponse.body() != null) { - initContentStream(validatingResponse.body().byteStream()); - } - } - boolean hasRequestBody() { String method = request.method(); return method.equals("POST") || method.equals("PUT") || method.equals("PATCH"); @@ -360,8 +314,7 @@ public class HttpEngine { public final void automaticallyReleaseConnectionToPool() { automaticallyReleaseConnectionToPool = true; if (connection != null && connectionReleased) { - client.getConnectionPool().recycle(connection); - connection = null; + disconnect(); } } @@ -378,7 +331,7 @@ public class HttpEngine { closeQuietly(responseBodyIn); } - if (!connectionReleased && connection != null) { + if (connection != null && !connectionReleased) { connectionReleased = true; if (transport == null @@ -386,8 +339,7 @@ public class HttpEngine { closeQuietly(connection); connection = null; } else if (automaticallyReleaseConnectionToPool) { - client.getConnectionPool().recycle(connection); - connection = null; + disconnect(); } } } @@ -505,7 +457,7 @@ public class HttpEngine { int contentLength = ((RetryableOutputStream) requestBodyOut).contentLength(); request = request.newBuilder().setContentLength(contentLength).build(); } - transport.writeRequestHeaders(); + transport.writeRequestHeaders(request); } if (requestBodyOut != null) { @@ -518,10 +470,13 @@ public class HttpEngine { transport.flushRequest(); response = transport.readResponseHeaders() - .newBuilder() + .request(request) + .handshake(connection.getHandshake()) .setLocalTimestamps(sentRequestMillis, System.currentTimeMillis()) .setResponseSource(responseSource) .build(); + connection.setHttpMinorVersion(response.httpMinorVersion()); + receiveHeaders(response.headers()); if (responseSource == ResponseSource.CONDITIONAL_CACHE) { if (validatingResponse.validate(response)) { diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpTransport.java b/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpTransport.java index 7a98b9626..81e1216c1 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpTransport.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/http/HttpTransport.java @@ -78,23 +78,23 @@ public final class HttpTransport implements Transport { return request; } - @Override public OutputStream createRequestBody() throws IOException { + @Override public OutputStream createRequestBody(Request request) throws IOException { // Stream a request body of unknown length. - if (httpEngine.getRequest().isChunked()) { + if (request.isChunked()) { int chunkLength = httpEngine.policy.getChunkLength(); if (chunkLength == -1) chunkLength = DEFAULT_CHUNK_LENGTH; - writeRequestHeaders(); + writeRequestHeaders(request); return new ChunkedOutputStream(requestOut, chunkLength); } // Stream a request body of a known length. long fixedContentLength = httpEngine.policy.getFixedContentLength(); if (fixedContentLength != -1) { - writeRequestHeaders(); + writeRequestHeaders(request); return new FixedLengthOutputStream(requestOut, fixedContentLength); } - long contentLength = httpEngine.getRequest().getContentLength(); + long contentLength = request.getContentLength(); if (contentLength > Integer.MAX_VALUE) { throw new IllegalArgumentException("Use setFixedLengthStreamingMode() or " + "setChunkedStreamingMode() for requests larger than 2 GiB."); @@ -102,7 +102,7 @@ public final class HttpTransport implements Transport { // Buffer a request body of a known length. if (contentLength != -1) { - writeRequestHeaders(); + writeRequestHeaders(request); return new RetryableOutputStream((int) contentLength); } @@ -133,22 +133,16 @@ public final class HttpTransport implements Transport { * This ensures that the {@code Content-Length} header field receives the * proper value. */ - public void writeRequestHeaders() throws IOException { + public void writeRequestHeaders(Request request) throws IOException { httpEngine.writingRequestHeaders(); - Headers headersToSend = httpEngine.getRequest().getHeaders(); - String requestLine = RequestLine.get(httpEngine.getRequest(), + String requestLine = RequestLine.get(request, httpEngine.connection.getRoute().getProxy().type(), httpEngine.connection.getHttpMinorVersion()); - writeRequest(requestOut, headersToSend, requestLine); + writeRequest(requestOut, request.getHeaders(), requestLine); } - @Override public Response readResponseHeaders() throws IOException { - Response response = readResponse(httpEngine.getRequest(), socketIn) - .handshake(httpEngine.connection.getHandshake()) - .build(); - httpEngine.connection.setHttpMinorVersion(response.httpMinorVersion()); - httpEngine.receiveHeaders(response.headers()); - return response; + @Override public Response.Builder readResponseHeaders() throws IOException { + return readResponse(socketIn); } /** Returns bytes of a request header for sending on an HTTP transport. */ @@ -167,14 +161,14 @@ public final class HttpTransport implements Transport { } /** Parses bytes of a response header from an HTTP transport. */ - public static Response.Builder readResponse(Request request, InputStream in) throws IOException { + public static Response.Builder readResponse(InputStream in) throws IOException { while (true) { String statusLineString = Util.readAsciiLine(in); StatusLine statusLine = new StatusLine(statusLineString); - Response.Builder responseBuilder = new Response.Builder(request); - responseBuilder.statusLine(statusLine); - responseBuilder.header(SyntheticHeaders.SELECTED_TRANSPORT, "http/1.1"); + Response.Builder responseBuilder = new Response.Builder() + .statusLine(statusLine) + .header(SyntheticHeaders.SELECTED_TRANSPORT, "http/1.1"); Headers.Builder headersBuilder = new Headers.Builder(); headersBuilder.readHeaders(in); diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/http/SpdyTransport.java b/okhttp/src/main/java/com/squareup/okhttp/internal/http/SpdyTransport.java index 2118830b3..61810e118 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/http/SpdyTransport.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/http/SpdyTransport.java @@ -45,7 +45,7 @@ public final class SpdyTransport implements Transport { @Override public Request prepareRequest(Request request) { Request.Builder builder = request.newBuilder() .header(":method", request.method()) - .header(":scheme", httpEngine.getRequest().url().getProtocol()) + .header(":scheme", request.url().getProtocol()) .header(":path", RequestLine.requestPath(request.url())) .header(":version", RequestLine.version(httpEngine.connection.getHttpMinorVersion())) .header(":host", HttpEngine.hostHeader(request.url())); @@ -60,20 +60,20 @@ public final class SpdyTransport implements Transport { return builder.build(); } - @Override public OutputStream createRequestBody() throws IOException { + @Override public OutputStream createRequestBody(Request request) throws IOException { // TODO: if we aren't streaming up to the server, we should buffer the whole request - writeRequestHeaders(); + writeRequestHeaders(request); return stream.getOutputStream(); } - @Override public void writeRequestHeaders() throws IOException { + @Override public void writeRequestHeaders(Request request) throws IOException { if (stream != null) return; httpEngine.writingRequestHeaders(); boolean hasRequestBody = httpEngine.hasRequestBody(); boolean hasResponseBody = true; - stream = spdyConnection.newStream(writeNameValueBlock(httpEngine.getRequest().getHeaders()), - hasRequestBody, hasResponseBody); + stream = spdyConnection.newStream( + writeNameValueBlock(request.getHeaders()), hasRequestBody, hasResponseBody); stream.setReadTimeout(httpEngine.client.getReadTimeout()); } @@ -85,14 +85,8 @@ public final class SpdyTransport implements Transport { stream.getOutputStream().close(); } - @Override public Response readResponseHeaders() throws IOException { - List nameValueBlock = stream.getResponseHeaders(); - Response response = readNameValueBlock(httpEngine.getRequest(), nameValueBlock) - .handshake(httpEngine.connection.getHandshake()) - .build(); - httpEngine.connection.setHttpMinorVersion(response.httpMinorVersion()); - httpEngine.receiveHeaders(response.headers()); - return response; + @Override public Response.Builder readResponseHeaders() throws IOException { + return readNameValueBlock(stream.getResponseHeaders()); } /** @@ -135,7 +129,7 @@ public final class SpdyTransport implements Transport { } /** Returns headers for a name value block containing a SPDY response. */ - public static Response.Builder readNameValueBlock(Request request, List nameValueBlock) + public static Response.Builder readNameValueBlock(List nameValueBlock) throws IOException { if (nameValueBlock.size() % 2 != 0) { throw new IllegalArgumentException("Unexpected name value block: " + nameValueBlock); @@ -167,7 +161,7 @@ public final class SpdyTransport implements Transport { if (status == null) throw new ProtocolException("Expected ':status' header not present"); if (version == null) throw new ProtocolException("Expected ':version' header not present"); - return new Response.Builder(request) + return new Response.Builder() .statusLine(new StatusLine(version + " " + status)) .headers(headersBuilder.build()); } diff --git a/okhttp/src/main/java/com/squareup/okhttp/internal/http/Transport.java b/okhttp/src/main/java/com/squareup/okhttp/internal/http/Transport.java index 8119c37a5..cbe12fe35 100644 --- a/okhttp/src/main/java/com/squareup/okhttp/internal/http/Transport.java +++ b/okhttp/src/main/java/com/squareup/okhttp/internal/http/Transport.java @@ -47,10 +47,10 @@ interface Transport { */ // TODO: don't bother retransmitting the request body? It's quite a corner // case and there's uncertainty whether Firefox or Chrome do this - OutputStream createRequestBody() throws IOException; + OutputStream createRequestBody(Request request) throws IOException; /** This should update the HTTP engine's sentRequestMillis field. */ - void writeRequestHeaders() throws IOException; + void writeRequestHeaders(Request request) throws IOException; /** * Sends the request body returned by {@link #createRequestBody} to the @@ -62,7 +62,7 @@ interface Transport { void flushRequest() throws IOException; /** Read response headers and update the cookie manager. */ - Response readResponseHeaders() throws IOException; + Response.Builder readResponseHeaders() throws IOException; // TODO: make this the content stream? InputStream getTransferStream(CacheRequest cacheRequest) throws IOException; diff --git a/okhttp/src/test/java/com/squareup/okhttp/internal/http/HeadersTest.java b/okhttp/src/test/java/com/squareup/okhttp/internal/http/HeadersTest.java index 8c0c30ad4..1dce00985 100644 --- a/okhttp/src/test/java/com/squareup/okhttp/internal/http/HeadersTest.java +++ b/okhttp/src/test/java/com/squareup/okhttp/internal/http/HeadersTest.java @@ -33,7 +33,7 @@ public final class HeadersTest { ":status", "200 OK", ":version", "HTTP/1.1"); Request request = new Request.Builder().url("http://square.com/").build(); - Response response = SpdyTransport.readNameValueBlock(request, nameValueBlock).build(); + Response response = SpdyTransport.readNameValueBlock(nameValueBlock).request(request).build(); Headers headers = response.headers(); assertEquals(4, headers.length()); assertEquals("HTTP/1.1 200 OK", response.statusLine());