HttpHeaderParserTest.java revision 8611e831aebbec7d6eebf02c8180e746c26dc05c
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
17package com.android.volley.toolbox;
18
19import android.test.suitebuilder.annotation.SmallTest;
20
21import com.android.volley.Cache;
22import com.android.volley.NetworkResponse;
23
24import junit.framework.TestCase;
25
26import java.text.DateFormat;
27import java.text.SimpleDateFormat;
28import java.util.Date;
29import java.util.HashMap;
30import java.util.Locale;
31import java.util.Map;
32
33@SmallTest
34public class HttpHeaderParserTest extends TestCase {
35
36    private static long ONE_MINUTE_MILLIS = 1000L * 60;
37    private static long ONE_HOUR_MILLIS = 1000L * 60 * 60;
38
39    private NetworkResponse response;
40    private Map<String, String> headers;
41
42    @Override
43    protected void setUp() throws Exception {
44        super.setUp();
45        headers = new HashMap<String, String>();
46        response = new NetworkResponse(0, null, headers, false);
47    }
48
49    public void testParseCacheHeaders_noHeaders() {
50        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
51
52        assertNotNull(entry);
53        assertNull(entry.etag);
54        assertEquals(0, entry.serverDate);
55        assertEquals(0, entry.ttl);
56        assertEquals(0, entry.softTtl);
57    }
58
59    public void testParseCacheHeaders_headersSet() {
60        headers.put("MyCustomHeader", "42");
61
62        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
63
64        assertNotNull(entry);
65        assertNotNull(entry.responseHeaders);
66        assertEquals(1, entry.responseHeaders.size());
67        assertEquals("42", entry.responseHeaders.get("MyCustomHeader"));
68    }
69
70    public void testParseCacheHeaders_etag() {
71        headers.put("ETag", "Yow!");
72
73        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
74
75        assertNotNull(entry);
76        assertEquals("Yow!", entry.etag);
77    }
78
79    public void testParseCacheHeaders_normalExpire() {
80        long now = System.currentTimeMillis();
81        headers.put("Date", rfc1123Date(now));
82        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
83
84        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
85
86        assertNotNull(entry);
87        assertNull(entry.etag);
88        assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
89        assertTrue(entry.softTtl >= (now + ONE_HOUR_MILLIS));
90        assertTrue(entry.ttl == entry.softTtl);
91    }
92
93    public void testParseCacheHeaders_expiresInPast() {
94        long now = System.currentTimeMillis();
95        headers.put("Date", rfc1123Date(now));
96        headers.put("Expires", rfc1123Date(now - ONE_HOUR_MILLIS));
97
98        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
99
100        assertNotNull(entry);
101        assertNull(entry.etag);
102        assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
103        assertEquals(0, entry.ttl);
104        assertEquals(0, entry.softTtl);
105    }
106
107    public void testParseCacheHeaders_serverRelative() {
108
109        long now = System.currentTimeMillis();
110        // Set "current" date as one hour in the future
111        headers.put("Date", rfc1123Date(now + ONE_HOUR_MILLIS));
112        // TTL four hours in the future, so should be three hours from now
113        headers.put("Expires", rfc1123Date(now + 4 * ONE_HOUR_MILLIS));
114
115        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
116
117        assertEqualsWithin(now + 3 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
118        assertEquals(entry.softTtl, entry.ttl);
119    }
120
121    public void testParseCacheHeaders_cacheControlOverridesExpires() {
122        long now = System.currentTimeMillis();
123        headers.put("Date", rfc1123Date(now));
124        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
125        headers.put("Cache-Control", "public, max-age=86400");
126
127        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
128
129        assertNotNull(entry);
130        assertNull(entry.etag);
131        assertEqualsWithin(now + 24 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
132        assertEquals(entry.softTtl, entry.ttl);
133    }
134
135    public void testParseCacheHeaders_cacheControlNoCache() {
136        long now = System.currentTimeMillis();
137        headers.put("Date", rfc1123Date(now));
138        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
139        headers.put("Cache-Control", "no-cache");
140
141        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
142
143        assertNull(entry);
144    }
145
146    public void testParseCacheHeaders_cacheControlMustRevalidate() {
147        long now = System.currentTimeMillis();
148        headers.put("Date", rfc1123Date(now));
149        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
150        headers.put("Cache-Control", "must-revalidate");
151
152        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
153
154        assertNotNull(entry);
155        assertNull(entry.etag);
156        assertEqualsWithin(now, entry.ttl, ONE_MINUTE_MILLIS);
157        assertEquals(entry.softTtl, entry.ttl);
158    }
159
160    private void assertEqualsWithin(long expected, long value, long fudgeFactor) {
161        long diff = Math.abs(expected - value);
162        assertTrue(diff < fudgeFactor);
163    }
164
165    private static String rfc1123Date(long millis) {
166        DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH);
167        return df.format(new Date(millis));
168    }
169
170    // --------------------------
171
172    public void testParseCharset() {
173        // Like the ones we usually see
174        headers.put("Content-Type", "text/plain; charset=utf-8");
175        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
176
177        // Extra whitespace
178        headers.put("Content-Type", "text/plain;    charset=utf-8 ");
179        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
180
181        // Extra parameters
182        headers.put("Content-Type", "text/plain; charset=utf-8; frozzle=bar");
183        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
184
185        // No Content-Type header
186        headers.clear();
187        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
188
189        // Empty value
190        headers.put("Content-Type", "text/plain; charset=");
191        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
192
193        // None specified
194        headers.put("Content-Type", "text/plain");
195        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
196
197        // None specified, extra semicolon
198        headers.put("Content-Type", "text/plain;");
199        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
200    }
201}
202