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