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