13c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpackage com.squareup.okhttp.internal.http;
23c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
33c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.Headers;
43c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.Request;
53c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.Response;
63c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.Platform;
73c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.ArrayList;
83c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.Collections;
93c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.Comparator;
103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.List;
113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.Map;
123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport java.util.TreeMap;
133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/** Headers and utilities for internal use by OkHttp. */
153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpublic final class OkHeaders {
163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private static final Comparator<String> FIELD_NAME_COMPARATOR = new Comparator<String>() {
173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    // @FindBugsSuppressWarnings("ES_COMPARING_PARAMETER_STRING_WITH_EQ")
183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    @Override public int compare(String a, String b) {
193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      if (a == b) {
203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        return 0;
213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      } else if (a == null) {
223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        return -1;
233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      } else if (b == null) {
243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        return 1;
253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      } else {
263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        return String.CASE_INSENSITIVE_ORDER.compare(a, b);
273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  };
303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  static final String PREFIX = Platform.get().getPrefix();
323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * Synthetic response header: the local time when the request was sent.
353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public static final String SENT_MILLIS = PREFIX + "-Sent-Millis";
373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * Synthetic response header: the local time when the response was received.
403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public static final String RECEIVED_MILLIS = PREFIX + "-Received-Millis";
423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * Synthetic response header: the response source and status code like
453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * "CONDITIONAL_CACHE 304".
463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public static final String RESPONSE_SOURCE = PREFIX + "-Response-Source";
483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * Synthetic response header: the selected
513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * {@link com.squareup.okhttp.Protocol protocol} ("spdy/3.1", "http/1.1", etc).
523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public static final String SELECTED_PROTOCOL = PREFIX + "-Selected-Protocol";
543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private OkHeaders() {
563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public static long contentLength(Request request) {
593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return contentLength(request.headers());
603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public static long contentLength(Response response) {
633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return contentLength(response.headers());
643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public static long contentLength(Headers headers) {
673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return stringToLong(headers.get("Content-Length"));
683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private static long stringToLong(String s) {
713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    if (s == null) return -1;
723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    try {
733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      return Long.parseLong(s);
743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    } catch (NumberFormatException e) {
753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      return -1;
763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * Returns an immutable map containing each field to its list of values.
813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   *
823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * @param valueForNullKey the request line for requests, or the status line
833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   *     for responses. If non-null, this value is mapped to the null key.
843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public static Map<String, List<String>> toMultimap(Headers headers, String valueForNullKey) {
863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    Map<String, List<String>> result = new TreeMap<String, List<String>>(FIELD_NAME_COMPARATOR);
873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    for (int i = 0; i < headers.size(); i++) {
883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      String fieldName = headers.name(i);
893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      String value = headers.value(i);
903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      List<String> allValues = new ArrayList<String>();
923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      List<String> otherValues = result.get(fieldName);
933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      if (otherValues != null) {
943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        allValues.addAll(otherValues);
953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      allValues.add(value);
973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      result.put(fieldName, Collections.unmodifiableList(allValues));
983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    if (valueForNullKey != null) {
1003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      result.put(null, Collections.unmodifiableList(Collections.singletonList(valueForNullKey)));
1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
1023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return Collections.unmodifiableMap(result);
1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  public static void addCookies(Request.Builder builder, Map<String, List<String>> cookieHeaders) {
1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    for (Map.Entry<String, List<String>> entry : cookieHeaders.entrySet()) {
1073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      String key = entry.getKey();
1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      if (("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key))
1093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller          && !entry.getValue().isEmpty()) {
1103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller        builder.addHeader(key, buildCookieHeader(entry.getValue()));
1113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      }
1123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
1133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller
1153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  /**
1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * Send all cookies in one big header, as recommended by
1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   * <a href="http://tools.ietf.org/html/rfc6265#section-4.2.1">RFC 6265</a>.
1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller   */
1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  private static String buildCookieHeader(List<String> cookies) {
1203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    if (cookies.size() == 1) return cookies.get(0);
1213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    StringBuilder sb = new StringBuilder();
1223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    for (int i = 0; i < cookies.size(); i++) {
1233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      if (i > 0) sb.append("; ");
1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller      sb.append(cookies.get(i));
1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    }
1263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller    return sb.toString();
1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller  }
1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller}
129