Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
21478 rajender 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.android.volley.toolbox;
18
 
19
import com.android.volley.Cache;
20
import com.android.volley.NetworkResponse;
21
 
22
import org.apache.http.impl.cookie.DateParseException;
23
import org.apache.http.impl.cookie.DateUtils;
24
import org.apache.http.protocol.HTTP;
25
 
26
import java.util.Map;
27
 
28
/**
29
 * Utility methods for parsing HTTP headers.
30
 */
31
public class HttpHeaderParser {
32
 
33
    /**
34
     * Extracts a {@link Cache.Entry} from a {@link NetworkResponse}.
35
     *
36
     * @param response The network response to parse headers from
37
     * @return a cache entry for the given response, or null if the response is not cacheable.
38
     */
39
    public static Cache.Entry parseCacheHeaders(NetworkResponse response) {
40
        long now = System.currentTimeMillis();
41
 
42
        Map<String, String> headers = response.headers;
43
 
44
        long serverDate = 0;
45
        long lastModified = 0;
46
        long serverExpires = 0;
47
        long softExpire = 0;
48
        long finalExpire = 0;
49
        long maxAge = 0;
50
        long staleWhileRevalidate = 0;
51
        boolean hasCacheControl = false;
52
        boolean mustRevalidate = false;
53
 
54
        String serverEtag = null;
55
        String headerValue;
56
 
57
        headerValue = headers.get("Date");
58
        if (headerValue != null) {
59
            serverDate = parseDateAsEpoch(headerValue);
60
        }
61
 
62
        headerValue = headers.get("Cache-Control");
63
        if (headerValue != null) {
64
            hasCacheControl = true;
65
            String[] tokens = headerValue.split(",");
66
            for (int i = 0; i < tokens.length; i++) {
67
                String token = tokens[i].trim();
68
                if (token.equals("no-cache") || token.equals("no-store")) {
69
                    return null;
70
                } else if (token.startsWith("max-age=")) {
71
                    try {
72
                        maxAge = Long.parseLong(token.substring(8));
73
                    } catch (Exception e) {
74
                    }
75
                } else if (token.startsWith("stale-while-revalidate=")) {
76
                    try {
77
                        staleWhileRevalidate = Long.parseLong(token.substring(23));
78
                    } catch (Exception e) {
79
                    }
80
                } else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) {
81
                    mustRevalidate = true;
82
                }
83
            }
84
        }
85
 
86
        headerValue = headers.get("Expires");
87
        if (headerValue != null) {
88
            serverExpires = parseDateAsEpoch(headerValue);
89
        }
90
 
91
        headerValue = headers.get("Last-Modified");
92
        if (headerValue != null) {
93
            lastModified = parseDateAsEpoch(headerValue);
94
        }
95
 
96
        serverEtag = headers.get("ETag");
97
 
98
        // Cache-Control takes precedence over an Expires header, even if both exist and Expires
99
        // is more restrictive.
100
        if (hasCacheControl) {
101
            softExpire = now + maxAge * 1000;
102
            finalExpire = mustRevalidate
103
                    ? softExpire
104
                    : softExpire + staleWhileRevalidate * 1000;
105
        } else if (serverDate > 0 && serverExpires >= serverDate) {
106
            // Default semantic for Expire header in HTTP specification is softExpire.
107
            softExpire = now + (serverExpires - serverDate);
108
            finalExpire = softExpire;
109
        }
110
 
111
        Cache.Entry entry = new Cache.Entry();
112
        entry.data = response.data;
113
        entry.etag = serverEtag;
114
        entry.softTtl = softExpire;
115
        entry.ttl = finalExpire;
116
        entry.serverDate = serverDate;
117
        entry.lastModified = lastModified;
118
        entry.responseHeaders = headers;
119
 
120
        return entry;
121
    }
122
 
123
    /**
124
     * Parse date in RFC1123 format, and return its value as epoch
125
     */
126
    public static long parseDateAsEpoch(String dateStr) {
127
        try {
128
            // Parse date in RFC1123 format if this header contains one
129
            return DateUtils.parseDate(dateStr).getTime();
130
        } catch (DateParseException e) {
131
            // Date in invalid format, fallback to 0
132
            return 0;
133
        }
134
    }
135
 
136
    /**
137
     * Retrieve a charset from headers
138
     *
139
     * @param headers An {@link java.util.Map} of headers
140
     * @param defaultCharset Charset to return if none can be found
141
     * @return Returns the charset specified in the Content-Type of this header,
142
     * or the defaultCharset if none can be found.
143
     */
144
    public static String parseCharset(Map<String, String> headers, String defaultCharset) {
145
        String contentType = headers.get(HTTP.CONTENT_TYPE);
146
        if (contentType != null) {
147
            String[] params = contentType.split(";");
148
            for (int i = 1; i < params.length; i++) {
149
                String[] pair = params[i].trim().split("=");
150
                if (pair.length == 2) {
151
                    if (pair[0].equals("charset")) {
152
                        return pair[1];
153
                    }
154
                }
155
            }
156
        }
157
 
158
        return defaultCharset;
159
    }
160
 
161
    /**
162
     * Returns the charset specified in the Content-Type of this header,
163
     * or the HTTP default (ISO-8859-1) if none can be found.
164
     */
165
    public static String parseCharset(Map<String, String> headers) {
166
        return parseCharset(headers, HTTP.DEFAULT_CONTENT_CHARSET);
167
    }
168
}