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.Header;
23
import org.apache.http.message.BasicHeader;
24
import org.junit.Before;
25
import org.junit.Test;
26
import org.junit.runner.RunWith;
27
import org.robolectric.RobolectricTestRunner;
28
 
29
import java.text.DateFormat;
30
import java.text.SimpleDateFormat;
31
import java.util.Date;
32
import java.util.HashMap;
33
import java.util.Locale;
34
import java.util.Map;
35
 
36
import static org.junit.Assert.assertEquals;
37
import static org.junit.Assert.assertNotNull;
38
import static org.junit.Assert.assertNull;
39
import static org.junit.Assert.assertTrue;
40
 
41
@RunWith(RobolectricTestRunner.class)
42
public class HttpHeaderParserTest {
43
 
44
    private static long ONE_MINUTE_MILLIS = 1000L * 60;
45
    private static long ONE_HOUR_MILLIS = 1000L * 60 * 60;
46
    private static long ONE_DAY_MILLIS = ONE_HOUR_MILLIS * 24;
47
    private static long ONE_WEEK_MILLIS = ONE_DAY_MILLIS * 7;
48
 
49
    private NetworkResponse response;
50
    private Map<String, String> headers;
51
 
52
    @Before public void setUp() throws Exception {
53
        headers = new HashMap<String, String>();
54
        response = new NetworkResponse(0, null, headers, false);
55
    }
56
 
57
    @Test public void parseCacheHeaders_noHeaders() {
58
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
59
 
60
        assertNotNull(entry);
61
        assertNull(entry.etag);
62
        assertEquals(0, entry.serverDate);
63
        assertEquals(0, entry.lastModified);
64
        assertEquals(0, entry.ttl);
65
        assertEquals(0, entry.softTtl);
66
    }
67
 
68
    @Test public void parseCacheHeaders_headersSet() {
69
        headers.put("MyCustomHeader", "42");
70
 
71
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
72
 
73
        assertNotNull(entry);
74
        assertNotNull(entry.responseHeaders);
75
        assertEquals(1, entry.responseHeaders.size());
76
        assertEquals("42", entry.responseHeaders.get("MyCustomHeader"));
77
    }
78
 
79
    @Test public void parseCacheHeaders_etag() {
80
        headers.put("ETag", "Yow!");
81
 
82
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
83
 
84
        assertNotNull(entry);
85
        assertEquals("Yow!", entry.etag);
86
    }
87
 
88
    @Test public void parseCacheHeaders_normalExpire() {
89
        long now = System.currentTimeMillis();
90
        headers.put("Date", rfc1123Date(now));
91
        headers.put("Last-Modified", rfc1123Date(now - ONE_DAY_MILLIS));
92
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
93
 
94
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
95
 
96
        assertNotNull(entry);
97
        assertNull(entry.etag);
98
        assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
99
        assertEqualsWithin(entry.lastModified, (now - ONE_DAY_MILLIS), ONE_MINUTE_MILLIS);
100
        assertTrue(entry.softTtl >= (now + ONE_HOUR_MILLIS));
101
        assertTrue(entry.ttl == entry.softTtl);
102
    }
103
 
104
    @Test public void parseCacheHeaders_expiresInPast() {
105
        long now = System.currentTimeMillis();
106
        headers.put("Date", rfc1123Date(now));
107
        headers.put("Expires", rfc1123Date(now - ONE_HOUR_MILLIS));
108
 
109
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
110
 
111
        assertNotNull(entry);
112
        assertNull(entry.etag);
113
        assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
114
        assertEquals(0, entry.ttl);
115
        assertEquals(0, entry.softTtl);
116
    }
117
 
118
    @Test public void parseCacheHeaders_serverRelative() {
119
 
120
        long now = System.currentTimeMillis();
121
        // Set "current" date as one hour in the future
122
        headers.put("Date", rfc1123Date(now + ONE_HOUR_MILLIS));
123
        // TTL four hours in the future, so should be three hours from now
124
        headers.put("Expires", rfc1123Date(now + 4 * ONE_HOUR_MILLIS));
125
 
126
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
127
 
128
        assertEqualsWithin(now + 3 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
129
        assertEquals(entry.softTtl, entry.ttl);
130
    }
131
 
132
    @Test public void parseCacheHeaders_cacheControlOverridesExpires() {
133
        long now = System.currentTimeMillis();
134
        headers.put("Date", rfc1123Date(now));
135
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
136
        headers.put("Cache-Control", "public, max-age=86400");
137
 
138
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
139
 
140
        assertNotNull(entry);
141
        assertNull(entry.etag);
142
        assertEqualsWithin(now + ONE_DAY_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
143
        assertEquals(entry.softTtl, entry.ttl);
144
    }
145
 
146
    @Test public void testParseCacheHeaders_staleWhileRevalidate() {
147
        long now = System.currentTimeMillis();
148
        headers.put("Date", rfc1123Date(now));
149
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
150
 
151
        // - max-age (entry.softTtl) indicates that the asset is fresh for 1 day
152
        // - stale-while-revalidate (entry.ttl) indicates that the asset may
153
        // continue to be served stale for up to additional 7 days
154
        headers.put("Cache-Control", "max-age=86400, stale-while-revalidate=604800");
155
 
156
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
157
 
158
        assertNotNull(entry);
159
        assertNull(entry.etag);
160
        assertEqualsWithin(now + ONE_DAY_MILLIS, entry.softTtl, ONE_MINUTE_MILLIS);
161
        assertEqualsWithin(now + ONE_DAY_MILLIS + ONE_WEEK_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
162
    }
163
 
164
    @Test public void parseCacheHeaders_cacheControlNoCache() {
165
        long now = System.currentTimeMillis();
166
        headers.put("Date", rfc1123Date(now));
167
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
168
        headers.put("Cache-Control", "no-cache");
169
 
170
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
171
 
172
        assertNull(entry);
173
    }
174
 
175
    @Test public void parseCacheHeaders_cacheControlMustRevalidateNoMaxAge() {
176
        long now = System.currentTimeMillis();
177
        headers.put("Date", rfc1123Date(now));
178
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
179
        headers.put("Cache-Control", "must-revalidate");
180
 
181
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
182
        assertNotNull(entry);
183
        assertNull(entry.etag);
184
        assertEqualsWithin(now, entry.ttl, ONE_MINUTE_MILLIS);
185
        assertEquals(entry.softTtl, entry.ttl);
186
    }
187
 
188
    @Test public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAge() {
189
        long now = System.currentTimeMillis();
190
        headers.put("Date", rfc1123Date(now));
191
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
192
        headers.put("Cache-Control", "must-revalidate, max-age=3600");
193
 
194
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
195
        assertNotNull(entry);
196
        assertNull(entry.etag);
197
        assertEqualsWithin(now + ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
198
        assertEquals(entry.softTtl, entry.ttl);
199
    }
200
 
201
    @Test public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAgeAndStale() {
202
        long now = System.currentTimeMillis();
203
        headers.put("Date", rfc1123Date(now));
204
        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
205
 
206
        // - max-age (entry.softTtl) indicates that the asset is fresh for 1 day
207
        // - stale-while-revalidate (entry.ttl) indicates that the asset may
208
        // continue to be served stale for up to additional 7 days, but this is
209
        // ignored in this case because of the must-revalidate header.
210
        headers.put("Cache-Control",
211
                "must-revalidate, max-age=86400, stale-while-revalidate=604800");
212
 
213
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
214
        assertNotNull(entry);
215
        assertNull(entry.etag);
216
        assertEqualsWithin(now + ONE_DAY_MILLIS, entry.softTtl, ONE_MINUTE_MILLIS);
217
        assertEquals(entry.softTtl, entry.ttl);
218
    }
219
 
220
    private void assertEqualsWithin(long expected, long value, long fudgeFactor) {
221
        long diff = Math.abs(expected - value);
222
        assertTrue(diff < fudgeFactor);
223
    }
224
 
225
    private static String rfc1123Date(long millis) {
226
        DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
227
        return df.format(new Date(millis));
228
    }
229
 
230
    // --------------------------
231
 
232
    @Test public void parseCharset() {
233
        // Like the ones we usually see
234
        headers.put("Content-Type", "text/plain; charset=utf-8");
235
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
236
 
237
        // Charset specified, ignore default charset
238
        headers.put("Content-Type", "text/plain; charset=utf-8");
239
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers, "ISO-8859-1"));
240
 
241
        // Extra whitespace
242
        headers.put("Content-Type", "text/plain;    charset=utf-8 ");
243
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
244
 
245
        // Extra parameters
246
        headers.put("Content-Type", "text/plain; charset=utf-8; frozzle=bar");
247
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
248
 
249
        // No Content-Type header
250
        headers.clear();
251
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
252
 
253
        // No Content-Type header, use default charset
254
        headers.clear();
255
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers, "utf-8"));
256
 
257
        // Empty value
258
        headers.put("Content-Type", "text/plain; charset=");
259
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
260
 
261
        // None specified
262
        headers.put("Content-Type", "text/plain");
263
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
264
 
265
        // None charset specified, use default charset
266
        headers.put("Content-Type", "application/json");
267
        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers, "utf-8"));
268
 
269
        // None specified, extra semicolon
270
        headers.put("Content-Type", "text/plain;");
271
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
272
    }
273
 
274
    @Test public void parseCaseInsensitive() {
275
 
276
        long now = System.currentTimeMillis();
277
 
278
        Header[] headersArray = new Header[5];
279
        headersArray[0] = new BasicHeader("eTAG", "Yow!");
280
        headersArray[1] = new BasicHeader("DATE", rfc1123Date(now));
281
        headersArray[2] = new BasicHeader("expires", rfc1123Date(now + ONE_HOUR_MILLIS));
282
        headersArray[3] = new BasicHeader("cache-control", "public, max-age=86400");
283
        headersArray[4] = new BasicHeader("content-type", "text/plain");
284
 
285
        Map<String, String> headers = BasicNetwork.convertHeaders(headersArray);
286
        NetworkResponse response = new NetworkResponse(0, null, headers, false);
287
        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
288
 
289
        assertNotNull(entry);
290
        assertEquals("Yow!", entry.etag);
291
        assertEqualsWithin(now + ONE_DAY_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
292
        assertEquals(entry.softTtl, entry.ttl);
293
        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
294
    }
295
}