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