Home | History | Annotate | Download | only in http
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.squareup.okhttp.internal.http;
     18 
     19 import java.net.URI;
     20 import java.util.Date;
     21 import java.util.List;
     22 import java.util.Map;
     23 
     24 /** Parsed HTTP request headers. */
     25 public final class RequestHeaders {
     26   private final URI uri;
     27   private final RawHeaders headers;
     28 
     29   /** Don't use a cache to satisfy this request. */
     30   private boolean noCache;
     31   private int maxAgeSeconds = -1;
     32   private int maxStaleSeconds = -1;
     33   private int minFreshSeconds = -1;
     34 
     35   /**
     36    * This field's name "only-if-cached" is misleading. It actually means "do
     37    * not use the network". It is set by a client who only wants to make a
     38    * request if it can be fully satisfied by the cache. Cached responses that
     39    * would require validation (ie. conditional gets) are not permitted if this
     40    * header is set.
     41    */
     42   private boolean onlyIfCached;
     43 
     44   /**
     45    * True if the request contains an authorization field. Although this isn't
     46    * necessarily a shared cache, it follows the spec's strict requirements for
     47    * shared caches.
     48    */
     49   private boolean hasAuthorization;
     50 
     51   private long contentLength = -1;
     52   private String transferEncoding;
     53   private String userAgent;
     54   private String host;
     55   private String connection;
     56   private String acceptEncoding;
     57   private String contentType;
     58   private String ifModifiedSince;
     59   private String ifNoneMatch;
     60   private String proxyAuthorization;
     61 
     62   public RequestHeaders(URI uri, RawHeaders headers) {
     63     this.uri = uri;
     64     this.headers = headers;
     65 
     66     HeaderParser.CacheControlHandler handler = new HeaderParser.CacheControlHandler() {
     67       @Override public void handle(String directive, String parameter) {
     68         if ("no-cache".equalsIgnoreCase(directive)) {
     69           noCache = true;
     70         } else if ("max-age".equalsIgnoreCase(directive)) {
     71           maxAgeSeconds = HeaderParser.parseSeconds(parameter);
     72         } else if ("max-stale".equalsIgnoreCase(directive)) {
     73           maxStaleSeconds = HeaderParser.parseSeconds(parameter);
     74         } else if ("min-fresh".equalsIgnoreCase(directive)) {
     75           minFreshSeconds = HeaderParser.parseSeconds(parameter);
     76         } else if ("only-if-cached".equalsIgnoreCase(directive)) {
     77           onlyIfCached = true;
     78         }
     79       }
     80     };
     81 
     82     for (int i = 0; i < headers.length(); i++) {
     83       String fieldName = headers.getFieldName(i);
     84       String value = headers.getValue(i);
     85       if ("Cache-Control".equalsIgnoreCase(fieldName)) {
     86         HeaderParser.parseCacheControl(value, handler);
     87       } else if ("Pragma".equalsIgnoreCase(fieldName)) {
     88         if ("no-cache".equalsIgnoreCase(value)) {
     89           noCache = true;
     90         }
     91       } else if ("If-None-Match".equalsIgnoreCase(fieldName)) {
     92         ifNoneMatch = value;
     93       } else if ("If-Modified-Since".equalsIgnoreCase(fieldName)) {
     94         ifModifiedSince = value;
     95       } else if ("Authorization".equalsIgnoreCase(fieldName)) {
     96         hasAuthorization = true;
     97       } else if ("Content-Length".equalsIgnoreCase(fieldName)) {
     98         try {
     99           contentLength = Integer.parseInt(value);
    100         } catch (NumberFormatException ignored) {
    101         }
    102       } else if ("Transfer-Encoding".equalsIgnoreCase(fieldName)) {
    103         transferEncoding = value;
    104       } else if ("User-Agent".equalsIgnoreCase(fieldName)) {
    105         userAgent = value;
    106       } else if ("Host".equalsIgnoreCase(fieldName)) {
    107         host = value;
    108       } else if ("Connection".equalsIgnoreCase(fieldName)) {
    109         connection = value;
    110       } else if ("Accept-Encoding".equalsIgnoreCase(fieldName)) {
    111         acceptEncoding = value;
    112       } else if ("Content-Type".equalsIgnoreCase(fieldName)) {
    113         contentType = value;
    114       } else if ("Proxy-Authorization".equalsIgnoreCase(fieldName)) {
    115         proxyAuthorization = value;
    116       }
    117     }
    118   }
    119 
    120   public boolean isChunked() {
    121     return "chunked".equalsIgnoreCase(transferEncoding);
    122   }
    123 
    124   public boolean hasConnectionClose() {
    125     return "close".equalsIgnoreCase(connection);
    126   }
    127 
    128   public URI getUri() {
    129     return uri;
    130   }
    131 
    132   public RawHeaders getHeaders() {
    133     return headers;
    134   }
    135 
    136   public boolean isNoCache() {
    137     return noCache;
    138   }
    139 
    140   public int getMaxAgeSeconds() {
    141     return maxAgeSeconds;
    142   }
    143 
    144   public int getMaxStaleSeconds() {
    145     return maxStaleSeconds;
    146   }
    147 
    148   public int getMinFreshSeconds() {
    149     return minFreshSeconds;
    150   }
    151 
    152   public boolean isOnlyIfCached() {
    153     return onlyIfCached;
    154   }
    155 
    156   public boolean hasAuthorization() {
    157     return hasAuthorization;
    158   }
    159 
    160   public long getContentLength() {
    161     return contentLength;
    162   }
    163 
    164   public String getTransferEncoding() {
    165     return transferEncoding;
    166   }
    167 
    168   public String getUserAgent() {
    169     return userAgent;
    170   }
    171 
    172   public String getHost() {
    173     return host;
    174   }
    175 
    176   public String getConnection() {
    177     return connection;
    178   }
    179 
    180   public String getAcceptEncoding() {
    181     return acceptEncoding;
    182   }
    183 
    184   public String getContentType() {
    185     return contentType;
    186   }
    187 
    188   public String getIfModifiedSince() {
    189     return ifModifiedSince;
    190   }
    191 
    192   public String getIfNoneMatch() {
    193     return ifNoneMatch;
    194   }
    195 
    196   public String getProxyAuthorization() {
    197     return proxyAuthorization;
    198   }
    199 
    200   public void setChunked() {
    201     if (this.transferEncoding != null) {
    202       headers.removeAll("Transfer-Encoding");
    203     }
    204     headers.add("Transfer-Encoding", "chunked");
    205     this.transferEncoding = "chunked";
    206   }
    207 
    208   public void setContentLength(long contentLength) {
    209     if (this.contentLength != -1) {
    210       headers.removeAll("Content-Length");
    211     }
    212     headers.add("Content-Length", Long.toString(contentLength));
    213     this.contentLength = contentLength;
    214   }
    215 
    216   public void setUserAgent(String userAgent) {
    217     if (this.userAgent != null) {
    218       headers.removeAll("User-Agent");
    219     }
    220     headers.add("User-Agent", userAgent);
    221     this.userAgent = userAgent;
    222   }
    223 
    224   public void setHost(String host) {
    225     if (this.host != null) {
    226       headers.removeAll("Host");
    227     }
    228     headers.add("Host", host);
    229     this.host = host;
    230   }
    231 
    232   public void setConnection(String connection) {
    233     if (this.connection != null) {
    234       headers.removeAll("Connection");
    235     }
    236     headers.add("Connection", connection);
    237     this.connection = connection;
    238   }
    239 
    240   public void setAcceptEncoding(String acceptEncoding) {
    241     if (this.acceptEncoding != null) {
    242       headers.removeAll("Accept-Encoding");
    243     }
    244     headers.add("Accept-Encoding", acceptEncoding);
    245     this.acceptEncoding = acceptEncoding;
    246   }
    247 
    248   public void setContentType(String contentType) {
    249     if (this.contentType != null) {
    250       headers.removeAll("Content-Type");
    251     }
    252     headers.add("Content-Type", contentType);
    253     this.contentType = contentType;
    254   }
    255 
    256   public void setIfModifiedSince(Date date) {
    257     if (ifModifiedSince != null) {
    258       headers.removeAll("If-Modified-Since");
    259     }
    260     String formattedDate = HttpDate.format(date);
    261     headers.add("If-Modified-Since", formattedDate);
    262     ifModifiedSince = formattedDate;
    263   }
    264 
    265   public void setIfNoneMatch(String ifNoneMatch) {
    266     if (this.ifNoneMatch != null) {
    267       headers.removeAll("If-None-Match");
    268     }
    269     headers.add("If-None-Match", ifNoneMatch);
    270     this.ifNoneMatch = ifNoneMatch;
    271   }
    272 
    273   /**
    274    * Returns true if the request contains conditions that save the server from
    275    * sending a response that the client has locally. When the caller adds
    276    * conditions, this cache won't participate in the request.
    277    */
    278   public boolean hasConditions() {
    279     return ifModifiedSince != null || ifNoneMatch != null;
    280   }
    281 
    282   public void addCookies(Map<String, List<String>> allCookieHeaders) {
    283     for (Map.Entry<String, List<String>> entry : allCookieHeaders.entrySet()) {
    284       String key = entry.getKey();
    285       if ("Cookie".equalsIgnoreCase(key) || "Cookie2".equalsIgnoreCase(key)) {
    286         headers.addAll(key, entry.getValue());
    287       }
    288     }
    289   }
    290 }
    291