1d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/* 2d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Copyright (C) 2011 The Android Open Source Project 3d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 4d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Licensed under the Apache License, Version 2.0 (the "License"); 5d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * you may not use this file except in compliance with the License. 6d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * You may obtain a copy of the License at 7d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 8d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * http://www.apache.org/licenses/LICENSE-2.0 9d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 10d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Unless required by applicable law or agreed to in writing, software 11d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * distributed under the License is distributed on an "AS IS" BASIS, 12d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * See the License for the specific language governing permissions and 14d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * limitations under the License. 15d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 16d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 17d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupackage com.android.volley.toolbox; 18d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 19d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.Cache; 20d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport com.android.volley.NetworkResponse; 21d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 22ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmannimport org.apache.http.Header; 23ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmannimport org.apache.http.message.BasicHeader; 24b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrickimport org.junit.Before; 25b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrickimport org.junit.Test; 26b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrickimport org.junit.runner.RunWith; 27b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrickimport org.robolectric.RobolectricTestRunner; 28ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann 29d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.text.DateFormat; 30d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.text.SimpleDateFormat; 31d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Date; 32d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.HashMap; 338611e831aebbec7d6eebf02c8180e746c26dc05cRalph Bergmannimport java.util.Locale; 34d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Map; 35d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 36b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrickimport static org.junit.Assert.*; 37b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick 38b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick@RunWith(RobolectricTestRunner.class) 39b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrickpublic class HttpHeaderParserTest { 40d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 41d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private static long ONE_MINUTE_MILLIS = 1000L * 60; 42d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private static long ONE_HOUR_MILLIS = 1000L * 60 * 60; 439324df1b8046548587ffec89ec755264f6fbb097Ralph Bergmann private static long ONE_DAY_MILLIS = ONE_HOUR_MILLIS * 24; 44782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro private static long ONE_WEEK_MILLIS = ONE_DAY_MILLIS * 7; 45d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 46d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private NetworkResponse response; 47d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private Map<String, String> headers; 48d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 49b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Before public void setUp() throws Exception { 50d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers = new HashMap<String, String>(); 51d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru response = new NetworkResponse(0, null, headers, false); 52d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 53d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 54b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCacheHeaders_noHeaders() { 55d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 56d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 57d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNotNull(entry); 58d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNull(entry.etag); 59d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals(0, entry.serverDate); 609324df1b8046548587ffec89ec755264f6fbb097Ralph Bergmann assertEquals(0, entry.lastModified); 61d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals(0, entry.ttl); 62d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals(0, entry.softTtl); 63d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 64d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 65b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCacheHeaders_headersSet() { 66e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru headers.put("MyCustomHeader", "42"); 67e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru 68e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 69e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru 70e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru assertNotNull(entry); 71e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru assertNotNull(entry.responseHeaders); 72e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru assertEquals(1, entry.responseHeaders.size()); 73e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru assertEquals("42", entry.responseHeaders.get("MyCustomHeader")); 74e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru } 75e48f4430bfd3030350aa5ba827b449c37e2fadc9Jean-Baptiste Queru 76b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCacheHeaders_etag() { 77d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("ETag", "Yow!"); 78d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 79d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 80d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 81d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNotNull(entry); 82d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals("Yow!", entry.etag); 83d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 84d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 85b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCacheHeaders_normalExpire() { 86d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long now = System.currentTimeMillis(); 87d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Date", rfc1123Date(now)); 889324df1b8046548587ffec89ec755264f6fbb097Ralph Bergmann headers.put("Last-Modified", rfc1123Date(now - ONE_DAY_MILLIS)); 89d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); 90d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 91d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 92d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 93d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNotNull(entry); 94d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNull(entry.etag); 95d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS); 969324df1b8046548587ffec89ec755264f6fbb097Ralph Bergmann assertEqualsWithin(entry.lastModified, (now - ONE_DAY_MILLIS), ONE_MINUTE_MILLIS); 97d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertTrue(entry.softTtl >= (now + ONE_HOUR_MILLIS)); 98d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertTrue(entry.ttl == entry.softTtl); 99d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 100d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 101b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCacheHeaders_expiresInPast() { 102d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long now = System.currentTimeMillis(); 103d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Date", rfc1123Date(now)); 104d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Expires", rfc1123Date(now - ONE_HOUR_MILLIS)); 105d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 106d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 107d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 108d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNotNull(entry); 109d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNull(entry.etag); 110d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEqualsWithin(entry.serverDate, now, ONE_MINUTE_MILLIS); 111d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals(0, entry.ttl); 112d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals(0, entry.softTtl); 113d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 114d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 115b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCacheHeaders_serverRelative() { 116d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 117d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long now = System.currentTimeMillis(); 118d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Set "current" date as one hour in the future 119d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Date", rfc1123Date(now + ONE_HOUR_MILLIS)); 120d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // TTL four hours in the future, so should be three hours from now 121d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Expires", rfc1123Date(now + 4 * ONE_HOUR_MILLIS)); 122d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 123d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 124d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 125d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEqualsWithin(now + 3 * ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS); 126d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals(entry.softTtl, entry.ttl); 127d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 128d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 129b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCacheHeaders_cacheControlOverridesExpires() { 130d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long now = System.currentTimeMillis(); 131d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Date", rfc1123Date(now)); 132d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); 133d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Cache-Control", "public, max-age=86400"); 134d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 135d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 136d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 137d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNotNull(entry); 138d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNull(entry.etag); 139782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertEqualsWithin(now + ONE_DAY_MILLIS, entry.ttl, ONE_MINUTE_MILLIS); 140d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals(entry.softTtl, entry.ttl); 141d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 142d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 1438e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann @Test public void testParseCacheHeaders_staleWhileRevalidate() { 1448e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann long now = System.currentTimeMillis(); 1458e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann headers.put("Date", rfc1123Date(now)); 1468e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); 1478e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann 1488e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann // - max-age (entry.softTtl) indicates that the asset is fresh for 1 day 1498e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann // - stale-while-revalidate (entry.ttl) indicates that the asset may 1508e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann // continue to be served stale for up to additional 7 days 1518e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann headers.put("Cache-Control", "max-age=86400, stale-while-revalidate=604800"); 1528e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann 1538e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 1548e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann 1558e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann assertNotNull(entry); 1568e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann assertNull(entry.etag); 157782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertEqualsWithin(now + ONE_DAY_MILLIS, entry.softTtl, ONE_MINUTE_MILLIS); 158782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertEqualsWithin(now + ONE_DAY_MILLIS + ONE_WEEK_MILLIS, entry.ttl, ONE_MINUTE_MILLIS); 1598e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann } 1608e33d93dc1aae9bb9dbde3b80af8a76ba28f0e19Ralph Bergmann 161b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCacheHeaders_cacheControlNoCache() { 162d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long now = System.currentTimeMillis(); 163d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Date", rfc1123Date(now)); 164d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); 165d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Cache-Control", "no-cache"); 166d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 167d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 168d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 169d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNull(entry); 170d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 171d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 172782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro @Test public void parseCacheHeaders_cacheControlMustRevalidateNoMaxAge() { 173d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long now = System.currentTimeMillis(); 174d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Date", rfc1123Date(now)); 175d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); 176d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Cache-Control", "must-revalidate"); 177d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 178d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 179d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNotNull(entry); 180d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertNull(entry.etag); 181d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEqualsWithin(now, entry.ttl, ONE_MINUTE_MILLIS); 182d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals(entry.softTtl, entry.ttl); 183d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 184d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 185782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro @Test public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAge() { 186782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro long now = System.currentTimeMillis(); 187782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro headers.put("Date", rfc1123Date(now)); 188782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); 189782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro headers.put("Cache-Control", "must-revalidate, max-age=3600"); 190782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro 191782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 192782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertNotNull(entry); 193782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertNull(entry.etag); 194782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertEqualsWithin(now + ONE_HOUR_MILLIS, entry.ttl, ONE_MINUTE_MILLIS); 195782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertEquals(entry.softTtl, entry.ttl); 196782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro } 197782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro 198782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro @Test public void parseCacheHeaders_cacheControlMustRevalidateWithMaxAgeAndStale() { 199782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro long now = System.currentTimeMillis(); 200782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro headers.put("Date", rfc1123Date(now)); 201782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro headers.put("Expires", rfc1123Date(now + ONE_HOUR_MILLIS)); 202782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro 203782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro // - max-age (entry.softTtl) indicates that the asset is fresh for 1 day 204782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro // - stale-while-revalidate (entry.ttl) indicates that the asset may 205782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro // continue to be served stale for up to additional 7 days, but this is 206782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro // ignored in this case because of the must-revalidate header. 207782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro headers.put("Cache-Control", 208782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro "must-revalidate, max-age=86400, stale-while-revalidate=604800"); 209782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro 210782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 211782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertNotNull(entry); 212782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertNull(entry.etag); 213782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertEqualsWithin(now + ONE_DAY_MILLIS, entry.softTtl, ONE_MINUTE_MILLIS); 214782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertEquals(entry.softTtl, entry.ttl); 215782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro } 216782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro 217d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private void assertEqualsWithin(long expected, long value, long fudgeFactor) { 218d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru long diff = Math.abs(expected - value); 219d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertTrue(diff < fudgeFactor); 220d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 221d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 222d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private static String rfc1123Date(long millis) { 2238611e831aebbec7d6eebf02c8180e746c26dc05cRalph Bergmann DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH); 224d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return df.format(new Date(millis)); 225d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 226d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 227d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // -------------------------- 228d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 229b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCharset() { 230d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Like the ones we usually see 231d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Content-Type", "text/plain; charset=utf-8"); 232d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals("utf-8", HttpHeaderParser.parseCharset(headers)); 233d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 2346bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán // Charset specified, ignore default charset 2356bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán headers.put("Content-Type", "text/plain; charset=utf-8"); 2366bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán assertEquals("utf-8", HttpHeaderParser.parseCharset(headers, "ISO-8859-1")); 2376bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán 238d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Extra whitespace 239d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Content-Type", "text/plain; charset=utf-8 "); 240d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals("utf-8", HttpHeaderParser.parseCharset(headers)); 241d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 242d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Extra parameters 243d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Content-Type", "text/plain; charset=utf-8; frozzle=bar"); 244d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals("utf-8", HttpHeaderParser.parseCharset(headers)); 245d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 246d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // No Content-Type header 247d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.clear(); 248d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers)); 249d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 2506bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán // No Content-Type header, use default charset 2516bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán headers.clear(); 2526bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán assertEquals("utf-8", HttpHeaderParser.parseCharset(headers, "utf-8")); 2536bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán 254d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // Empty value 255d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Content-Type", "text/plain; charset="); 256d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers)); 257d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 258d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // None specified 259d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Content-Type", "text/plain"); 260d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers)); 261d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 2626bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán // None charset specified, use default charset 2636bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán headers.put("Content-Type", "application/json"); 2646bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán assertEquals("utf-8", HttpHeaderParser.parseCharset(headers, "utf-8")); 2656bafd7d28fc7947f263feb7134fc8a70084357c3Zdeněk Kořán 266d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru // None specified, extra semicolon 267d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru headers.put("Content-Type", "text/plain;"); 268d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers)); 269d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 270ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann 271b9b8dc3d98fb1a8c3f02c2c2fcc18cbd344c05cbFicus Kirkpatrick @Test public void parseCaseInsensitive() { 272ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann 273ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann long now = System.currentTimeMillis(); 274ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann 275ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann Header[] headersArray = new Header[5]; 276ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann headersArray[0] = new BasicHeader("eTAG", "Yow!"); 277ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann headersArray[1] = new BasicHeader("DATE", rfc1123Date(now)); 278ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann headersArray[2] = new BasicHeader("expires", rfc1123Date(now + ONE_HOUR_MILLIS)); 279ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann headersArray[3] = new BasicHeader("cache-control", "public, max-age=86400"); 280ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann headersArray[4] = new BasicHeader("content-type", "text/plain"); 281ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann 282ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann Map<String, String> headers = BasicNetwork.convertHeaders(headersArray); 283ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann NetworkResponse response = new NetworkResponse(0, null, headers, false); 284ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann Cache.Entry entry = HttpHeaderParser.parseCacheHeaders(response); 285ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann 286ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann assertNotNull(entry); 287ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann assertEquals("Yow!", entry.etag); 288782b52fd6f5c62f5b38148432acbc4e79351fd0bDave Santoro assertEqualsWithin(now + ONE_DAY_MILLIS, entry.ttl, ONE_MINUTE_MILLIS); 289ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann assertEquals(entry.softTtl, entry.ttl); 290ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann assertEquals("ISO-8859-1", HttpHeaderParser.parseCharset(headers)); 291ba53551261044a9811835c1fb89d4ec48a88a43bRalph Bergmann } 292d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru} 293