All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.squareup.okhttp.internal.http.HttpTransport Maven / Gradle / Ivy

There is a newer version: 2.7.5
Show newest version
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.squareup.okhttp.internal.http;

import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.io.IOException;
import java.net.CacheRequest;
import okio.Sink;
import okio.Source;

public final class HttpTransport implements Transport {
  private final HttpEngine httpEngine;
  private final HttpConnection httpConnection;

  public HttpTransport(HttpEngine httpEngine, HttpConnection httpConnection) {
    this.httpEngine = httpEngine;
    this.httpConnection = httpConnection;
  }

  @Override public Sink createRequestBody(Request request) throws IOException {
    long contentLength = OkHeaders.contentLength(request);

    if (httpEngine.bufferRequestBody) {
      if (contentLength > Integer.MAX_VALUE) {
        throw new IllegalStateException("Use setFixedLengthStreamingMode() or "
            + "setChunkedStreamingMode() for requests larger than 2 GiB.");
      }

      if (contentLength != -1) {
        // Buffer a request body of a known length.
        writeRequestHeaders(request);
        return new RetryableSink((int) contentLength);
      } else {
        // Buffer a request body of an unknown length. Don't write request
        // headers until the entire body is ready; otherwise we can't set the
        // Content-Length header correctly.
        return new RetryableSink();
      }
    }

    if ("chunked".equalsIgnoreCase(request.header("Transfer-Encoding"))) {
      // Stream a request body of unknown length.
      writeRequestHeaders(request);
      return httpConnection.newChunkedSink();
    }

    if (contentLength != -1) {
      // Stream a request body of a known length.
      writeRequestHeaders(request);
      return httpConnection.newFixedLengthSink(contentLength);
    }

    throw new IllegalStateException(
        "Cannot stream a request body without chunked encoding or a known content length!");
  }

  @Override public void flushRequest() throws IOException {
    httpConnection.flush();
  }

  @Override public void writeRequestBody(RetryableSink requestBody) throws IOException {
    httpConnection.writeRequestBody(requestBody);
  }

  /**
   * Prepares the HTTP headers and sends them to the server.
   *
   * 

For streaming requests with a body, headers must be prepared * before the output stream has been written to. Otherwise * the body would need to be buffered! * *

For non-streaming requests with a body, headers must be prepared * after the output stream has been written to and closed. * This ensures that the {@code Content-Length} header field receives the * proper value. */ public void writeRequestHeaders(Request request) throws IOException { httpEngine.writingRequestHeaders(); String requestLine = RequestLine.get(request, httpEngine.getConnection().getRoute().getProxy().type(), httpEngine.getConnection().getProtocol()); httpConnection.writeRequest(request.headers(), requestLine); } @Override public Response.Builder readResponseHeaders() throws IOException { return httpConnection.readResponse(); } @Override public void releaseConnectionOnIdle() throws IOException { if (canReuseConnection()) { httpConnection.poolOnIdle(); } else { httpConnection.closeOnIdle(); } } @Override public boolean canReuseConnection() { // If the request specified that the connection shouldn't be reused, don't reuse it. if ("close".equalsIgnoreCase(httpEngine.getRequest().header("Connection"))) { return false; } // If the response specified that the connection shouldn't be reused, don't reuse it. if ("close".equalsIgnoreCase(httpEngine.getResponse().header("Connection"))) { return false; } if (httpConnection.isClosed()) { return false; } return true; } @Override public void emptyTransferStream() throws IOException { httpConnection.emptyResponseBody(); } @Override public Source getTransferStream(CacheRequest cacheRequest) throws IOException { if (!httpEngine.hasResponseBody()) { return httpConnection.newFixedLengthSource(cacheRequest, 0); } if ("chunked".equalsIgnoreCase(httpEngine.getResponse().header("Transfer-Encoding"))) { return httpConnection.newChunkedSource(cacheRequest, httpEngine); } long contentLength = OkHeaders.contentLength(httpEngine.getResponse()); if (contentLength != -1) { return httpConnection.newFixedLengthSource(cacheRequest, contentLength); } // Wrap the input stream from the connection (rather than just returning // "socketIn" directly here), so that we can control its use after the // reference escapes. return httpConnection.newUnknownLengthSource(cacheRequest); } @Override public void disconnect(HttpEngine engine) throws IOException { httpConnection.closeIfOwnedBy(engine); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy