13713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/*
23713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Copyright (C) 2011 The Android Open Source Project
33713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
43713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Licensed under the Apache License, Version 2.0 (the "License");
53713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * you may not use this file except in compliance with the License.
63713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * You may obtain a copy of the License at
73713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
83713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *      http://www.apache.org/licenses/LICENSE-2.0
93713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Unless required by applicable law or agreed to in writing, software
113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * distributed under the License is distributed on an "AS IS" BASIS,
123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * See the License for the specific language governing permissions and
143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * limitations under the License.
153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */
163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpackage com.android.volley.toolbox;
183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
19cebf98c8edef6b3506258ddb68266febadd0db1aJeff Sharkeyimport android.test.suitebuilder.annotation.SmallTest;
20cebf98c8edef6b3506258ddb68266febadd0db1aJeff Sharkey
213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.Cache;
223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport com.android.volley.NetworkResponse;
233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.text.DateFormat;
253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.text.SimpleDateFormat;
263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.Date;
273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.HashMap;
283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.Map;
293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport junit.framework.TestCase;
313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
32cebf98c8edef6b3506258ddb68266febadd0db1aJeff Sharkey@SmallTest
333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpublic class HttpHeaderParserTest extends TestCase {
343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private static long ONE_MINUTE_MILLIS = 1000L * 60;
363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private static long ONE_HOUR_MILLIS = 1000L * 60 * 60;
373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private NetworkResponse response;
393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private Map<String, String> headers;
403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    @Override
423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    protected void setUp() throws Exception {
433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        super.setUp();
443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers = new HashMap<String, String>();
453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        response = new NetworkResponse(0, null, headers, false);
463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public void testParseCacheHeaders_noHeaders() {
493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertNotNull(entry);
523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertNull(entry.etag);
533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals(0, entry.serverDate);
543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals(0, entry.ttl);
553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals(0, entry.softTtl);
563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
583713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public void testParseCacheHeaders_etag() {
593713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("ETag", "Yow!");
603713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
613713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
623713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
633713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertNotNull(entry);
643713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals("Yow!", entry.etag);
653713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
663713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
673713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public void testParseCacheHeaders_normalExpire() {
683713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        long now = System.currentTimeMillis();
693713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Date", rfc1123Date(now));
703713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
713713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
723713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
733713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
743713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertNotNull(entry);
753713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertNull(entry.etag);
763713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
773713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertTrue(entry.softTtl >= (now + ONE_HOUR_MILLIS));
783713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertTrue(entry.ttl == entry.softTtl);
793713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
803713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
813713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public void testParseCacheHeaders_expiresInPast() {
823713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        long now = System.currentTimeMillis();
833713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Date", rfc1123Date(now));
843713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Expires", rfc1123Date(now - ONE_HOUR_MILLIS));
853713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
863713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
873713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
883713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertNotNull(entry);
893713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertNull(entry.etag);
903713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS);
913713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals(0, entry.ttl);
923713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals(0, entry.softTtl);
933713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
943713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
953713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public void testParseCacheHeaders_serverRelative() {
963713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
973713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        long now = System.currentTimeMillis();
983713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // Set "current" date as one hour in the future
993713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Date", rfc1123Date(now + ONE_HOUR_MILLIS));
1003713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // TTL four hours in the future, so should be three hours from now
1013713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Expires", rfc1123Date(now + 4 * ONE_HOUR_MILLIS));
1023713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1033713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
1043713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1053713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEqualsWithin(now + 3 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
1063713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals(entry.softTtl, entry.ttl);
1073713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1083713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
109ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta    public void testParseCacheHeaders_cacheControlOverridesExpires() {
110ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        long now = System.currentTimeMillis();
111ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        headers.put("Date", rfc1123Date(now));
112ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
113ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        headers.put("Cache-Control", "public, max-age=86400");
114ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta
115ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
116ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta
117ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        assertNotNull(entry);
118ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        assertNull(entry.etag);
119ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        assertEqualsWithin(now + 24 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS);
120ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        assertEquals(entry.softTtl, entry.ttl);
121ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta    }
122ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta
123ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta    public void testParseCacheHeaders_cacheControlNoCache() {
124ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        long now = System.currentTimeMillis();
125ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        headers.put("Date", rfc1123Date(now));
126ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
127ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        headers.put("Cache-Control", "no-cache");
128ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta
129ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
130ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta
131ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        assertNull(entry);
132ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta    }
133ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta
134ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta    public void testParseCacheHeaders_cacheControlMustRevalidate() {
135ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        long now = System.currentTimeMillis();
136ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        headers.put("Date", rfc1123Date(now));
137ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS));
138ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        headers.put("Cache-Control", "must-revalidate");
139ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta
140ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response);
141ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta
142ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        assertNotNull(entry);
143ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        assertNull(entry.etag);
144ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        assertEqualsWithin(now, entry.ttl, ONE_MINUTE_MILLIS);
145ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta        assertEquals(entry.softTtl, entry.ttl);
146ccde61ed8922020f05bd43a80dfcc130c99c00f0Scott Barta    }
1473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private void assertEqualsWithin(long expected, long value, long fudgeFactor) {
1493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        long diff = Math.abs(expected - value);
1503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertTrue(diff < fudgeFactor);
1513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private static String rfc1123Date(long millis) {
1543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
1553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        return df.format(new Date(millis));
1563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1583713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    // --------------------------
1593713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1603713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public void testParseCharset() {
1613713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // Like the ones we usually see
1623713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Content-Type", "text/plain; charset=utf-8");
1633713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
1643713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1653713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // Extra whitespace
1663713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Content-Type", "text/plain;    charset=utf-8 ");
1673713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
1683713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1693713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // Extra parameters
1703713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Content-Type", "text/plain; charset=utf-8; frozzle=bar");
1713713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals("utf-8", HttpHeaderParser.parseCharset(headers));
1723713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1733713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // No Content-Type header
1743713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.clear();
1753713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
1763713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1773713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // Empty value
1783713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Content-Type", "text/plain; charset=");
1793713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
1803713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1813713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // None specified
1823713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Content-Type", "text/plain");
1833713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
1843713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1853713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        // None specified, extra semicolon
1863713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        headers.put("Content-Type", "text/plain;");
1873713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers));
1883713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1893713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick}
190