@Override
 public void setIfModifiedSince(long newValue) {
   super.setIfModifiedSince(newValue);
   if (ifModifiedSince != 0) {
     requestHeaders.set("If-Modified-Since", HttpDate.format(new Date(ifModifiedSince)));
   } else {
     requestHeaders.removeAll("If-Modified-Since");
   }
 }
  protected void appendHeaders(Request.Builder builder, Map<String, String> headers) {
    if (builder == null) {
      throw new IllegalArgumentException("builder can not be empty!");
    }

    Headers.Builder headerBuilder = new Headers.Builder();
    if (headers == null || headers.isEmpty()) return;

    for (String key : headers.keySet()) {
      headerBuilder.add(key, headers.get(key));
    }
    builder.headers(headerBuilder.build());
  }
  private HttpEngine newHttpEngine(
      String method, Connection connection, RetryableOutputStream requestBody) throws IOException {
    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;
    if (fixedContentLength != -1) {
      bufferRequestBody = false;
      builder.header("Content-Length", Long.toString(fixedContentLength));
    } else if (chunkLength > 0) {
      bufferRequestBody = false;
      builder.header("Transfer-Encoding", "chunked");
    } else {
      bufferRequestBody = true;
    }

    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 (engineClient.getOkResponseCache() != null && !getUseCaches()) {
      engineClient = client.clone().setOkResponseCache(null);
    }

    return new HttpEngine(engineClient, request, bufferRequestBody, connection, requestBody);
  }
    /**
     * Reads an entry from an input stream. A typical entry looks like this:
     *
     * <pre>{@code
     * http://google.com/foo
     * GET
     * 2
     * Accept-Language: fr-CA
     * Accept-Charset: UTF-8
     * HTTP/1.1 200 OK
     * 3
     * Content-Type: image/png
     * Content-Length: 100
     * Cache-Control: max-age=600
     * }</pre>
     *
     * <p>A typical HTTPS file looks like this:
     *
     * <pre>{@code
     * https://google.com/foo
     * GET
     * 2
     * Accept-Language: fr-CA
     * Accept-Charset: UTF-8
     * HTTP/1.1 200 OK
     * 3
     * Content-Type: image/png
     * Content-Length: 100
     * Cache-Control: max-age=600
     *
     * AES_256_WITH_MD5
     * 2
     * base64-encoded peerCertificate[0]
     * base64-encoded peerCertificate[1]
     * -1
     * }</pre>
     *
     * The file is newline separated. The first two lines are the URL and the request method. Next
     * is the number of HTTP Vary request header lines, followed by those lines.
     *
     * <p>Next is the response status line, followed by the number of HTTP response header lines,
     * followed by those lines.
     *
     * <p>HTTPS responses also contain SSL session information. This begins with a blank line, and
     * then a line containing the cipher suite. Next is the length of the peer certificate chain.
     * These certificates are base64-encoded and appear each on their own line. The next line
     * contains the length of the local certificate chain. These certificates are also
     * base64-encoded and appear each on their own line. A length of -1 is used to encode a null
     * array.
     */
    public Entry(Source in) throws IOException {
      try {
        BufferedSource source = Okio.buffer(in);
        url = source.readUtf8LineStrict();
        requestMethod = source.readUtf8LineStrict();
        if (readInt(source) == 1) {
          MediaType contentType = MediaType.parse(source.readUtf8LineStrict());
          int contentLength = readInt(source);
          requestBody = RequestBody.create(contentType, source.readByteArray(contentLength));
        } else {
          requestBody = null;
        }
        Headers.Builder varyHeadersBuilder = new Headers.Builder();
        int varyRequestHeaderLineCount = readInt(source);
        for (int i = 0; i < varyRequestHeaderLineCount; i++) {
          OkHttpAccess.addLenient(varyHeadersBuilder, source.readUtf8LineStrict());
        }
        varyHeaders = varyHeadersBuilder.build();

        StatusLine statusLine = StatusLine.parse(source.readUtf8LineStrict());
        protocol = statusLine.protocol;
        code = statusLine.code;
        message = statusLine.message;
        Headers.Builder responseHeadersBuilder = new Headers.Builder();
        int responseHeaderLineCount = readInt(source);
        for (int i = 0; i < responseHeaderLineCount; i++) {
          OkHttpAccess.addLenient(responseHeadersBuilder, source.readUtf8LineStrict());
        }
        responseHeaders = responseHeadersBuilder.build();

        if (isHttps()) {
          String blank = source.readUtf8LineStrict();
          if (blank.length() > 0) {
            throw new IOException("expected \"\" but was \"" + blank + "\"");
          }
          String cipherSuite = source.readUtf8LineStrict();
          List<Certificate> peerCertificates = readCertificateList(source);
          List<Certificate> localCertificates = readCertificateList(source);
          handshake = Handshake.get(cipherSuite, peerCertificates, localCertificates);
        } else {
          handshake = null;
        }
      } finally {
        in.close();
      }
    }
  @Override
  public final Map<String, List<String>> getRequestProperties() {
    if (connected) {
      throw new IllegalStateException(
          "Cannot access request header fields after connection is set");
    }

    // For the request line property assigned to the null key, just use no proxy and HTTP 1.1.
    Request request = new Request.Builder().url(getURL()).method(method, null).build();
    String requestLine = RequestLine.get(request, null, 1);
    return OkHeaders.toMultimap(requestHeaders.build(), requestLine);
  }
 private static Headers combine(Headers headers, Headers headers1)
 {
     boolean flag = false;
     com.squareup.okhttp.Headers.Builder builder = new com.squareup.okhttp.Headers.Builder();
     int k = headers.size();
     int j = 0;
     do
     {
         if (j >= k)
         {
             break;
         }
         String s = headers.name(j);
         String s1 = headers.value(j);
         if ((!"Warning".equalsIgnoreCase(s) || !s1.startsWith("1")) && (!OkHeaders.isEndToEnd(s) || headers1.get(s) == null))
         {
             builder.add(s, s1);
         }
         j++;
     } while (true);
     k = headers1.size();
     j = ((flag) ? 1 : 0);
     do
     {
         if (j >= k)
         {
             break;
         }
         headers = headers1.name(j);
         if (!"Content-Length".equalsIgnoreCase(headers) && OkHeaders.isEndToEnd(headers))
         {
             builder.add(headers, headers1.value(j));
         }
         j++;
     } while (true);
     return builder.build();
 }
  /**
   * Aggressively tries to get the final HTTP response, potentially making many HTTP requests in the
   * process in order to cope with redirects and authentication.
   */
  private HttpEngine getResponse() throws IOException {
    initHttpEngine();

    if (httpEngine.hasResponse()) {
      return httpEngine;
    }

    while (true) {
      if (!execute(true)) {
        continue;
      }

      Retry retry = processResponseHeaders();
      if (retry == Retry.NONE) {
        httpEngine.automaticallyReleaseConnectionToPool();
        return httpEngine;
      }

      // The first request was insufficient. Prepare for another...
      String retryMethod = method;
      OutputStream requestBody = httpEngine.getRequestBody();

      // Although RFC 2616 10.3.2 specifies that a HTTP_MOVED_PERM
      // redirect should keep the same method, Chrome, Firefox and the
      // RI all issue GETs when following any redirect.
      int responseCode = httpEngine.getResponse().code();
      if (responseCode == HTTP_MULT_CHOICE
          || responseCode == HTTP_MOVED_PERM
          || responseCode == HTTP_MOVED_TEMP
          || responseCode == HTTP_SEE_OTHER) {
        retryMethod = "GET";
        requestHeaders.removeAll("Content-Length");
        requestBody = null;
      }

      if (requestBody != null && !(requestBody instanceof RetryableOutputStream)) {
        throw new HttpRetryException("Cannot retry streamed HTTP body", responseCode);
      }

      if (retry == Retry.DIFFERENT_CONNECTION) {
        httpEngine.automaticallyReleaseConnectionToPool();
      }

      httpEngine.release(false);
      httpEngine =
          newHttpEngine(
              retryMethod, httpEngine.getConnection(), (RetryableOutputStream) requestBody);
    }
  }
  @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 final String getRequestProperty(String field) {
   if (field == null) return null;
   return requestHeaders.get(field);
 }