private int pruneAndGetAllocationCount(RealConnection connection, long now) { List<Reference<StreamAllocation>> references = connection.allocations; int i = 0; while (i < references.size()) { if (((Reference) references.get(i)).get() != null) { i++; } else { Internal.logger.warning("A connection to " + connection.getRoute().getAddress() .url() + " was leaked. Did you forget to close a response body?"); references.remove(i); connection.noNewStreams = true; if (references.isEmpty()) { connection.idleAtNanos = now - this.keepAliveDurationNs; return 0; } } } return references.size(); }
protected void execute() { boolean signalledCallback = false; try { Response response = Call.this.getResponseWithInterceptorChain(this.forWebSocket); if (Call.this.canceled) { this.responseCallback.onFailure(Call.this.originalRequest, new IOException ("Canceled")); } else { signalledCallback = true; this.responseCallback.onResponse(response); } Call.this.client.getDispatcher().finished(this); } catch (IOException e) { if (signalledCallback) { Internal.logger.log(Level.INFO, "Callback failure for " + Call.this .toLoggableString(), e); } else { this.responseCallback.onFailure(Call.this.engine == null ? Call.this .originalRequest : Call.this.engine.getRequest(), e); } Call.this.client.getDispatcher().finished(this); } catch (Throwable th) { Call.this.client.getDispatcher().finished(this); } }
protected final void endOfInput(boolean paramBoolean) throws IOException { if (HttpConnection.this.state != 5) { throw new IllegalStateException("state: " + HttpConnection.this.state); } HttpConnection.access$402(HttpConnection.this, 0); if ((paramBoolean) && (HttpConnection.this.onIdle == 1)) { HttpConnection.access$902$76e0d70f(HttpConnection.this); Internal.instance.recycle(HttpConnection.this.pool, HttpConnection.this.connection); } while (HttpConnection.this.onIdle != 2) { return; } HttpConnection.access$402(HttpConnection.this, 6); HttpConnection.this.connection.socket.close(); }
public RouteSelector(Address paramAddress, URI paramURI, OkHttpClient paramOkHttpClient, Request paramRequest) { this.address = paramAddress; this.uri = paramURI; this.client = paramOkHttpClient; this.pool = paramOkHttpClient.connectionPool; this.routeDatabase = Internal.instance.routeDatabase(paramOkHttpClient); this.network = Internal.instance.network(paramOkHttpClient); this.request = paramRequest; Proxy localProxy = paramAddress.proxy; if (localProxy != null) { this.proxies = Collections.singletonList(localProxy); } for (;;) { this.nextProxyIndex = 0; return; this.proxies = new ArrayList(); List localList = this.client.proxySelector.select(paramURI); if (localList != null) { this.proxies.addAll(localList); } this.proxies.removeAll(Collections.singleton(Proxy.NO_PROXY)); this.proxies.add(Proxy.NO_PROXY); } }
public final void connectFailed(Connection paramConnection, IOException paramIOException) { if (Internal.instance.recycleCount(paramConnection) > 0) {} for (;;) { return; Route localRoute1 = paramConnection.route; if ((localRoute1.proxy.type() != Proxy.Type.DIRECT) && (this.address.proxySelector != null)) { this.address.proxySelector.connectFailed(this.uri, localRoute1.proxy.address(), paramIOException); } this.routeDatabase.failed(localRoute1); if ((!(paramIOException instanceof SSLHandshakeException)) && (!(paramIOException instanceof SSLProtocolException))) { while (this.nextSpecIndex < this.connectionSpecs.size()) { List localList = this.connectionSpecs; int i = this.nextSpecIndex; this.nextSpecIndex = (i + 1); ConnectionSpec localConnectionSpec = (ConnectionSpec)localList.get(i); boolean bool = shouldSendTlsFallbackIndicator(localConnectionSpec); Route localRoute2 = new Route(this.address, this.lastProxy, this.lastInetSocketAddress, localConnectionSpec, bool); this.routeDatabase.failed(localRoute2); } } } }
public HttpEngine(OkHttpClient paramOkHttpClient, Request paramRequest, boolean paramBoolean1, boolean paramBoolean2, boolean paramBoolean3, Connection paramConnection, RouteSelector paramRouteSelector, RetryableSink paramRetryableSink, Response paramResponse) { this.client = paramOkHttpClient; this.userRequest = paramRequest; this.bufferRequestBody = paramBoolean1; this.callerWritesRequestBody = paramBoolean2; this.forWebSocket = paramBoolean3; this.connection = paramConnection; this.routeSelector = paramRouteSelector; this.requestBodyOut = null; this.priorResponse = paramResponse; if (paramConnection != null) { Internal.instance.setOwner(paramConnection, this); this.route = paramConnection.route; return; } this.route = null; }
public final Response readNetworkResponse() throws IOException { this.transport.finishRequest(); Response.Builder localBuilder1 = this.transport.readResponseHeaders(); localBuilder1.request = this.networkRequest; localBuilder1.handshake = this.connection.handshake; Response localResponse = localBuilder1.header(OkHeaders.SENT_MILLIS, Long.toString(this.sentRequestMillis)).header(OkHeaders.RECEIVED_MILLIS, Long.toString(System.currentTimeMillis())).build(); if (!this.forWebSocket) { Response.Builder localBuilder2 = localResponse.newBuilder(); localBuilder2.body = this.transport.openResponseBody(localResponse); localResponse = localBuilder2.build(); } Internal.instance.setProtocol(this.connection, localResponse.protocol); return localResponse; }
public final void releaseConnectionOnIdle() throws IOException { if (canReuseConnection()) { HttpConnection localHttpConnection2 = this.httpConnection; localHttpConnection2.onIdle = 1; if (localHttpConnection2.state == 0) { localHttpConnection2.onIdle = 0; Internal.instance.recycle(localHttpConnection2.pool, localHttpConnection2.connection); } } HttpConnection localHttpConnection1; do { return; localHttpConnection1 = this.httpConnection; localHttpConnection1.onIdle = 2; } while (localHttpConnection1.state != 0); localHttpConnection1.state = 6; localHttpConnection1.connection.socket.close(); }
/** * Closes the cache entry and makes the socket available for reuse. This * should be invoked when the end of the body has been reached. */ protected final void endOfInput(boolean recyclable) throws IOException { if (state != STATE_READING_RESPONSE_BODY) throw new IllegalStateException("state: " + state); if (cacheRequest != null) { cacheBody.close(); } state = STATE_IDLE; if (recyclable && onIdle == ON_IDLE_POOL) { onIdle = ON_IDLE_HOLD; // Set the on idle policy back to the default. Internal.instance.recycle(pool, connection); } else if (onIdle == ON_IDLE_CLOSE) { state = STATE_CLOSED; connection.getSocket().close(); } }
/** * Clients should invoke this method when they encounter a connectivity * failure on a connection returned by this route selector. */ public void connectFailed(Connection connection, IOException failure) { // If this is a recycled connection, don't count its failure against the route. if (Internal.instance.recycleCount(connection) > 0) return; Route failedRoute = connection.getRoute(); if (failedRoute.getProxy().type() != Proxy.Type.DIRECT && proxySelector != null) { // Tell the proxy selector when we fail to connect on a fresh connection. proxySelector.connectFailed(uri, failedRoute.getProxy().address(), failure); } routeDatabase.failed(failedRoute); // If the previously returned route's problem was not related to TLS, and // the next route only changes the TLS mode, we shouldn't even attempt it. // This suppresses it in both this selector and also in the route database. if (!(failure instanceof SSLHandshakeException) && !(failure instanceof SSLProtocolException)) { while (hasNextTlsVersion()) { Route toSuppress = new Route(address, lastProxy, lastInetSocketAddress, nextTlsVersion()); routeDatabase.failed(toSuppress); } } }
/** * @param request the HTTP request without a body. The body must be * written via the engine's request body stream. * @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. * @param routeSelector the route selector used for a failed attempt * immediately preceding this attempt, or null if this request doesn't * recover from a failure. */ public HttpEngine(OkHttpClient client, Request request, boolean bufferRequestBody, Connection connection, RouteSelector routeSelector, RetryableSink requestBodyOut, Response priorResponse) { this.client = client; this.userRequest = request; this.bufferRequestBody = bufferRequestBody; this.connection = connection; this.routeSelector = routeSelector; this.requestBodyOut = requestBodyOut; this.priorResponse = priorResponse; if (connection != null) { Internal.instance.setOwner(connection, this); this.route = connection.getRoute(); } else { this.route = null; } }
private void maybeCache() throws IOException { InternalCache responseCache = Internal.instance.internalCache(client); if (responseCache == null) return; // Should we cache this response for this request? if (!CacheStrategy.isCacheable(userResponse, networkRequest)) { if (HttpMethod.invalidatesCache(networkRequest.method())) { try { responseCache.remove(networkRequest); } catch (IOException ignored) { // The cache cannot be written. } } return; } // Offer this request to the cache. storeRequest = responseCache.put(stripBody(userResponse)); }
/** * @return a new http client */ private OkHttpClient createHttpClient() { OkHttpClient client = new OkHttpClient(); client.setReadTimeout(connectorOptions.getReadTimeout(), TimeUnit.SECONDS); client.setWriteTimeout(connectorOptions.getWriteTimeout(), TimeUnit.SECONDS); client.setConnectTimeout(connectorOptions.getConnectTimeout(), TimeUnit.SECONDS); client.setFollowRedirects(connectorOptions.isFollowRedirects()); client.setFollowSslRedirects(connectorOptions.isFollowRedirects()); client.setProxySelector(ProxySelector.getDefault()); client.setCookieHandler(CookieHandler.getDefault()); client.setCertificatePinner(CertificatePinner.DEFAULT); client.setAuthenticator(AuthenticatorAdapter.INSTANCE); client.setConnectionPool(ConnectionPool.getDefault()); client.setProtocols(Util.immutableList(Protocol.HTTP_1_1)); client.setConnectionSpecs(DEFAULT_CONNECTION_SPECS); client.setSocketFactory(SocketFactory.getDefault()); Internal.instance.setNetwork(client, Network.DEFAULT); return client; }
/** * Constructor. * @param metricsServer */ public HawkularMetricsClient(URL metricsServer) { this.serverUrl = metricsServer; httpClient = new OkHttpClient(); httpClient.setReadTimeout(DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS); httpClient.setWriteTimeout(DEFAULT_WRITE_TIMEOUT, TimeUnit.SECONDS); httpClient.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS); httpClient.setFollowRedirects(true); httpClient.setFollowSslRedirects(true); httpClient.setProxySelector(ProxySelector.getDefault()); httpClient.setCookieHandler(CookieHandler.getDefault()); httpClient.setCertificatePinner(CertificatePinner.DEFAULT); httpClient.setAuthenticator(AuthenticatorAdapter.INSTANCE); httpClient.setConnectionPool(ConnectionPool.getDefault()); httpClient.setProtocols(Util.immutableList(Protocol.HTTP_1_1)); httpClient.setConnectionSpecs(DEFAULT_CONNECTION_SPECS); httpClient.setSocketFactory(SocketFactory.getDefault()); Internal.instance.setNetwork(httpClient, Network.DEFAULT); }
public Headers readHeaders() throws IOException { Builder headers = new Builder(); while (true) { String line = this.source.readUtf8LineStrict(); if (line.length() == 0) { return headers.build(); } Internal.instance.addLenient(headers, line); } }
private void maybeCache() throws IOException { InternalCache responseCache = Internal.instance.internalCache(this.client); if (responseCache != null) { if (CacheStrategy.isCacheable(this.userResponse, this.networkRequest)) { this.storeRequest = responseCache.put(stripBody(this.userResponse)); } else if (HttpMethod.invalidatesCache(this.networkRequest.method())) { try { responseCache.remove(this.networkRequest); } catch (IOException e) { } } } }
private void deallocate(boolean noNewStreams, boolean released, boolean streamFinished) { RealConnection connectionToClose = null; synchronized (this.connectionPool) { if (streamFinished) { this.stream = null; } if (released) { this.released = true; } if (this.connection != null) { if (noNewStreams) { this.connection.noNewStreams = true; } if (this.stream == null && (this.released || this.connection.noNewStreams)) { release(this.connection); if (this.connection.streamCount > 0) { this.routeSelector = null; } if (this.connection.allocations.isEmpty()) { this.connection.idleAtNanos = System.nanoTime(); if (Internal.instance.connectionBecameIdle(this.connectionPool, this .connection)) { connectionToClose = this.connection; } } this.connection = null; } } } if (connectionToClose != null) { Util.closeQuietly(connectionToClose.getSocket()); } }
private HttpEngine newHttpEngine(String method, StreamAllocation streamAllocation, RetryableSink requestBody, Response priorResponse) throws MalformedURLException, UnknownHostException { Request.Builder builder = new Request.Builder().url(Internal.instance.getHttpUrlChecked (getURL().toString())).method(method, HttpMethod.requiresRequestBody(method) ? EMPTY_REQUEST_BODY : null); Headers headers = this.requestHeaders.build(); int size = headers.size(); for (int i = 0; i < size; i++) { builder.addHeader(headers.name(i), headers.value(i)); } boolean bufferRequestBody = false; if (HttpMethod.permitsRequestBody(method)) { if (this.fixedContentLength != -1) { builder.header("Content-Length", Long.toString(this.fixedContentLength)); } else if (this.chunkLength > 0) { builder.header("Transfer-Encoding", "chunked"); } else { bufferRequestBody = true; } if (headers.get("Content-Type") == null) { builder.header("Content-Type", Client.FormMime); } } if (headers.get(Network.USER_AGENT) == null) { builder.header(Network.USER_AGENT, defaultUserAgent()); } Request request = builder.build(); OkHttpClient engineClient = this.client; if (!(Internal.instance.internalCache(engineClient) == null || getUseCaches())) { engineClient = this.client.clone().setCache(null); } return new HttpEngine(engineClient, request, bufferRequestBody, true, false, streamAllocation, requestBody, priorResponse); }
public final void readHeaders(Headers.Builder paramBuilder) throws IOException { for (;;) { String str = this.source.readUtf8LineStrict(); if (str.length() == 0) { break; } Internal.instance.addLine(paramBuilder, str); } }
public final Connection close() { if (this.bufferedRequestBody != null) { Util.closeQuietly(this.bufferedRequestBody); } while (this.userResponse == null) { if (this.connection != null) { Util.closeQuietly(this.connection.socket); } this.connection = null; return null; if (this.requestBodyOut != null) { Util.closeQuietly(this.requestBodyOut); } } Util.closeQuietly(this.userResponse.body); if ((this.transport != null) && (this.connection != null) && (!this.transport.canReuseConnection())) { Util.closeQuietly(this.connection.socket); this.connection = null; return null; } if ((this.connection != null) && (!Internal.instance.clearOwner(this.connection))) { this.connection = null; } Connection localConnection = this.connection; this.connection = null; return localConnection; }
/** * Configure this connection to put itself back into the connection pool when * the HTTP response body is exhausted. */ public void poolOnIdle() { onIdle = ON_IDLE_POOL; // If we're already idle, go to the pool immediately. if (state == STATE_IDLE) { onIdle = ON_IDLE_HOLD; // Set the on idle policy back to the default. Internal.instance.recycle(pool, connection); } }
/** Reads headers or trailers into {@code builder}. */ public void readHeaders(Headers.Builder builder) throws IOException { // parse the result headers until the first blank line for (String line; (line = source.readUtf8LineStrict()).length() != 0; ) { Internal.instance.addLine(builder, line); } }
/** * Returns the next route address to attempt. * * @throws NoSuchElementException if there are no more routes to attempt. */ public Connection next(String method) throws IOException { // Always prefer pooled connections over new connections. for (Connection pooled; (pooled = pool.get(address)) != null; ) { if (method.equals("GET") || Internal.instance.isReadable(pooled)) return pooled; pooled.getSocket().close(); } // Compute the next route to attempt. if (!hasNextTlsVersion()) { if (!hasNextInetSocketAddress()) { if (!hasNextProxy()) { if (!hasNextPostponed()) { throw new NoSuchElementException(); } return new Connection(pool, nextPostponed()); } lastProxy = nextProxy(); resetNextInetSocketAddress(lastProxy); } lastInetSocketAddress = nextInetSocketAddress(); resetNextTlsVersion(); } String tlsVersion = nextTlsVersion(); Route route = new Route(address, lastProxy, lastInetSocketAddress, tlsVersion); if (routeDatabase.shouldPostpone(route)) { postponedRoutes.add(route); // We will only recurse in order to skip previously failed routes. They will be // tried last. return next(method); } return new Connection(pool, route); }
/** Connect to the origin server either directly or via a proxy. */ private void connect(Request request) throws IOException { if (connection != null) throw new IllegalStateException(); if (routeSelector == null) { String uriHost = request.url().getHost(); if (uriHost == null || uriHost.length() == 0) { throw new UnknownHostException(request.url().toString()); } SSLSocketFactory sslSocketFactory = null; HostnameVerifier hostnameVerifier = null; if (request.isHttps()) { sslSocketFactory = client.getSslSocketFactory(); } hostnameVerifier = client.getHostnameVerifier(); Address address = new Address(uriHost, getEffectivePort(request.url()), client.getSocketFactory(), sslSocketFactory, hostnameVerifier, client.getAuthenticator(), client.getProxy(), client.getProtocols()); routeSelector = new RouteSelector(address, request.uri(), client.getProxySelector(), client.getConnectionPool(), Dns.DEFAULT, Internal.instance.routeDatabase(client)); } connection = routeSelector.next(request.method()); Internal.instance.setOwner(connection, this); if (!Internal.instance.isConnected(connection)) { Internal.instance.connect(connection, client.getConnectTimeout(), client.getReadTimeout(), client.getWriteTimeout(), tunnelRequest(connection, request)); if (Internal.instance.isSpdy(connection)) { Internal.instance.share(client.getConnectionPool(), connection); } Internal.instance.routeDatabase(client).connected(connection.getRoute()); } Internal.instance.setTimeouts(connection, client.getReadTimeout(), client.getWriteTimeout()); route = connection.getRoute(); }
/** * Release any resources held by this engine. If a connection is still held by * this engine, it is returned. */ public Connection close() { if (bufferedRequestBody != null) { // This also closes the wrapped requestBodyOut. closeQuietly(bufferedRequestBody); } else if (requestBodyOut != null) { closeQuietly(requestBodyOut); } // If this engine never achieved a response body, its connection cannot be reused. if (responseBody == null) { if (connection != null) closeQuietly(connection.getSocket()); // TODO: does this break SPDY? connection = null; return null; } // Close the response body. This will recycle the connection if it is eligible. closeQuietly(responseBody); // Clear the buffer held by the response body input stream adapter. closeQuietly(responseBodyBytes); // Close the connection if it cannot be reused. if (transport != null && connection != null && !transport.canReuseConnection()) { closeQuietly(connection.getSocket()); connection = null; return null; } // Prevent this engine from disconnecting a connection it no longer owns. if (connection != null && !Internal.instance.clearOwner(connection)) { connection = null; } Connection result = connection; connection = null; return result; }
public void sendRequest() throws RequestException, RouteException, IOException { if (this.cacheStrategy == null) { if (this.httpStream != null) { throw new IllegalStateException(); } Request request = networkRequest(this.userRequest); InternalCache responseCache = Internal.instance.internalCache(this.client); Response cacheCandidate = responseCache != null ? responseCache.get(request) : null; this.cacheStrategy = new Factory(System.currentTimeMillis(), request, cacheCandidate) .get(); this.networkRequest = this.cacheStrategy.networkRequest; this.cacheResponse = this.cacheStrategy.cacheResponse; if (responseCache != null) { responseCache.trackResponse(this.cacheStrategy); } if (cacheCandidate != null && this.cacheResponse == null) { Util.closeQuietly(cacheCandidate.body()); } if (this.networkRequest != null) { this.httpStream = connect(); this.httpStream.setHttpEngine(this); if (this.callerWritesRequestBody && permitsRequestBody(this.networkRequest) && this.requestBodyOut == null) { long contentLength = OkHeaders.contentLength(request); if (!this.bufferRequestBody) { this.httpStream.writeRequestHeaders(this.networkRequest); this.requestBodyOut = this.httpStream.createRequestBody(this .networkRequest, contentLength); return; } else if (contentLength > 2147483647L) { throw new IllegalStateException("Use setFixedLengthStreamingMode() or " + "setChunkedStreamingMode() for requests larger than 2 GiB."); } else if (contentLength != -1) { this.httpStream.writeRequestHeaders(this.networkRequest); this.requestBodyOut = new RetryableSink((int) contentLength); return; } else { this.requestBodyOut = new RetryableSink(); return; } } return; } if (this.cacheResponse != null) { this.userResponse = this.cacheResponse.newBuilder().request(this.userRequest) .priorResponse(stripBody(this.priorResponse)).cacheResponse(stripBody (this.cacheResponse)).build(); } else { this.userResponse = new Builder().request(this.userRequest).priorResponse (stripBody(this.priorResponse)).protocol(Protocol.HTTP_1_1).code(504) .message("Unsatisfiable Request (only-if-cached)").body(EMPTY_BODY).build(); } this.userResponse = unzip(this.userResponse); } }
public void readResponse() throws IOException { if (this.userResponse == null) { if (this.networkRequest == null && this.cacheResponse == null) { throw new IllegalStateException("call sendRequest() first!"); } else if (this.networkRequest != null) { Response networkResponse; if (this.forWebSocket) { this.httpStream.writeRequestHeaders(this.networkRequest); networkResponse = readNetworkResponse(); } else if (this.callerWritesRequestBody) { if (this.bufferedRequestBody != null && this.bufferedRequestBody.buffer() .size() > 0) { this.bufferedRequestBody.emit(); } if (this.sentRequestMillis == -1) { if (OkHeaders.contentLength(this.networkRequest) == -1 && (this .requestBodyOut instanceof RetryableSink)) { this.networkRequest = this.networkRequest.newBuilder().header ("Content-Length", Long.toString(((RetryableSink) this .requestBodyOut).contentLength())).build(); } this.httpStream.writeRequestHeaders(this.networkRequest); } if (this.requestBodyOut != null) { if (this.bufferedRequestBody != null) { this.bufferedRequestBody.close(); } else { this.requestBodyOut.close(); } if (this.requestBodyOut instanceof RetryableSink) { this.httpStream.writeRequestBody((RetryableSink) this.requestBodyOut); } } networkResponse = readNetworkResponse(); } else { networkResponse = new NetworkInterceptorChain(this, 0, this.networkRequest) .proceed(this.networkRequest); } receiveHeaders(networkResponse.headers()); if (this.cacheResponse != null) { if (validate(this.cacheResponse, networkResponse)) { this.userResponse = this.cacheResponse.newBuilder().request(this .userRequest).priorResponse(stripBody(this.priorResponse)) .headers(combine(this.cacheResponse.headers(), networkResponse .headers())).cacheResponse(stripBody(this.cacheResponse)) .networkResponse(stripBody(networkResponse)).build(); networkResponse.body().close(); releaseStreamAllocation(); InternalCache responseCache = Internal.instance.internalCache(this.client); responseCache.trackConditionalCacheHit(); responseCache.update(this.cacheResponse, stripBody(this.userResponse)); this.userResponse = unzip(this.userResponse); return; } Util.closeQuietly(this.cacheResponse.body()); } this.userResponse = networkResponse.newBuilder().request(this.userRequest) .priorResponse(stripBody(this.priorResponse)).cacheResponse(stripBody (this.cacheResponse)).networkResponse(stripBody(networkResponse)) .build(); if (hasBody(this.userResponse)) { maybeCache(); this.userResponse = unzip(cacheWritingResponse(this.storeRequest, this .userResponse)); } } } }
private RouteDatabase routeDatabase() { return Internal.instance.routeDatabase(this.connectionPool); }
public void closeIfOwnedBy(Object owner) throws IOException { Internal.instance.closeIfOwnedBy(connection, owner); }
/** * Figures out what the response source will be, and opens a socket to that * source if necessary. Prepares the request headers and gets ready to start * writing the request body if it exists. */ public void sendRequest() throws IOException { if (cacheStrategy != null) return; // Already sent. if (transport != null) throw new IllegalStateException(); Request request = networkRequest(userRequest); InternalCache responseCache = Internal.instance.internalCache(client); Response cacheCandidate = responseCache != null ? responseCache.get(request) : null; long now = System.currentTimeMillis(); cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get(); networkRequest = cacheStrategy.networkRequest; cacheResponse = cacheStrategy.cacheResponse; if (responseCache != null) { responseCache.trackResponse(cacheStrategy); } if (cacheCandidate != null && cacheResponse == null) { closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it. } if (networkRequest != null) { // Open a connection unless we inherited one from a redirect. if (connection == null) { connect(networkRequest); } // Blow up if we aren't the current owner of the connection. if (Internal.instance.getOwner(connection) != this && !Internal.instance.isSpdy(connection)) { throw new AssertionError(); } transport = Internal.instance.newTransport(connection, this); // 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 aren't using the network. Recycle a connection we may have inherited from a redirect. if (connection != null) { Internal.instance.recycle(client.getConnectionPool(), connection); connection = null; } if (cacheResponse != null) { // We have a valid cached response. Promote it to the user response immediately. this.userResponse = cacheResponse.newBuilder() .request(userRequest) .priorResponse(stripBody(priorResponse)) .cacheResponse(stripBody(cacheResponse)) .build(); } else { // We're forbidden from using the network, and the cache is insufficient. this.userResponse = new Response.Builder() .request(userRequest) .priorResponse(stripBody(priorResponse)) .protocol(Protocol.HTTP_1_1) .code(504) .message("Unsatisfiable Request (only-if-cached)") .body(EMPTY_BODY) .build(); } if (userResponse.body() != null) { initContentStream(userResponse.body().source()); } } }
private HttpEngine newHttpEngine(String method, Connection connection, RetryableSink requestBody, Response priorResponse) { Request.Builder builder = new Request.Builder() .url(getURL()) .method(method, null /* No body; that's passed separately. */); Headers headers = requestHeaders.build(); for (int i = 0; i < headers.size(); i++) { builder.addHeader(headers.name(i), headers.value(i)); } boolean bufferRequestBody = false; if (HttpMethod.hasRequestBody(method)) { // Specify how the request body is terminated. if (fixedContentLength != -1) { builder.header("Content-Length", Long.toString(fixedContentLength)); } else if (chunkLength > 0) { builder.header("Transfer-Encoding", "chunked"); } else { bufferRequestBody = true; } // Add a content type for the request body, if one isn't already present. if (headers.get("Content-Type") == null) { builder.header("Content-Type", "application/x-www-form-urlencoded"); } } if (headers.get("User-Agent") == null) { builder.header("User-Agent", defaultUserAgent()); } Request request = builder.build(); // If we're currently not using caches, make sure the engine's client doesn't have one. OkHttpClient engineClient = client; if (Internal.instance.internalCache(engineClient) != null && !getUseCaches()) { engineClient = client.clone().setCache(null); } request = client.preConfigRequest(request); return new HttpEngine(engineClient, request, bufferRequestBody, connection, null, requestBody, priorResponse); }
private HttpEngine newHttpEngine(String method, Connection connection, RetryableSink requestBody, Response priorResponse) { // OkHttp's Call API requires a placeholder body; the real body will be streamed separately. RequestBody placeholderBody = HttpMethod.requiresRequestBody(method) ? EMPTY_REQUEST_BODY : null; Request.Builder builder = new Request.Builder() .url(getURL()) .method(method, placeholderBody); Headers headers = requestHeaders.build(); for (int i = 0, size = headers.size(); i < size; i++) { builder.addHeader(headers.name(i), headers.value(i)); } boolean bufferRequestBody = false; if (HttpMethod.permitsRequestBody(method)) { // Specify how the request body is terminated. if (fixedContentLength != -1) { builder.header("Content-Length", Long.toString(fixedContentLength)); } else if (chunkLength > 0) { builder.header("Transfer-Encoding", "chunked"); } else { bufferRequestBody = true; } // Add a content type for the request body, if one isn't already present. if (headers.get("Content-Type") == null) { builder.header("Content-Type", "application/x-www-form-urlencoded"); } } if (headers.get("User-Agent") == null) { builder.header("User-Agent", defaultUserAgent()); } Request request = builder.build(); // If we're currently not using caches, make sure the engine's client doesn't have one. OkHttpClient engineClient = client; if (Internal.instance.internalCache(engineClient) != null && !getUseCaches()) { engineClient = client.clone().setCache(null); } return new HttpEngine(engineClient, request, bufferRequestBody, true, false, connection, null, requestBody, priorResponse); }