CacheManager.java revision 303bc083c5a158ff240be658ac30d201cad56a18
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.webkit; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 207cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilsonimport android.net.http.AndroidHttpClient; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.http.Headers; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.FileUtils; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileInputStream; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileNotFoundException; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream; 282036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Klobaimport java.io.FilenameFilter; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.InputStream; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.OutputStream; 322036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Klobaimport java.util.List; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3545a9a14006214e6478311ffcb980e766702d5a76Doug Zongker 364140faeebbfa23d56068c1862b2913fb62145f4fBrian Carlstromimport com.android.org.bouncycastle.crypto.Digest; 374140faeebbfa23d56068c1862b2913fb62145f4fBrian Carlstromimport com.android.org.bouncycastle.crypto.digests.SHA1Digest; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 40303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Manages the HTTP cache used by an application's {@link WebView} instances. 41c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 43303bc083c5a158ff240be658ac30d201cad56a18Steve Block// The class CacheManager provides the persistent cache of content that is 44303bc083c5a158ff240be658ac30d201cad56a18Steve Block// received over the network. The component handles parsing of HTTP headers and 45303bc083c5a158ff240be658ac30d201cad56a18Steve Block// utilizes the relevant cache headers to determine if the content should be 46303bc083c5a158ff240be658ac30d201cad56a18Steve Block// stored and if so, how long it is valid for. Network requests are provided to 47303bc083c5a158ff240be658ac30d201cad56a18Steve Block// this component and if they can not be resolved by the cache, the HTTP headers 48303bc083c5a158ff240be658ac30d201cad56a18Steve Block// are attached, as appropriate, to the request for revalidation of content. The 49303bc083c5a158ff240be658ac30d201cad56a18Steve Block// class also manages the cache size. 50303bc083c5a158ff240be658ac30d201cad56a18Steve Block// 51303bc083c5a158ff240be658ac30d201cad56a18Steve Block// CacheManager may only be used if your activity contains a WebView. 52c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick@Deprecated 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic final class CacheManager { 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String LOGTAG = "cache"; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String HEADER_KEY_IFMODIFIEDSINCE = "if-modified-since"; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String HEADER_KEY_IFNONEMATCH = "if-none-match"; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String NO_STORE = "no-store"; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String NO_CACHE = "no-cache"; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String MAX_AGE = "max-age"; 63a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu private static final String MANIFEST_MIME = "text/cache-manifest"; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static long CACHE_THRESHOLD = 6 * 1024 * 1024; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static long CACHE_TRIM_AMOUNT = 2 * 1024 * 1024; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 68998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba // Limit the maximum cache file size to half of the normal capacity 69998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba static long CACHE_MAX_SIZE = (CACHE_THRESHOLD - CACHE_TRIM_AMOUNT) / 2; 70998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean mDisabled; 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Reference count the enable/disable transaction 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int mRefCount; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // trimCacheIfNeeded() is called when a page is fully loaded. But JavaScript 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // can load the content, e.g. in a slideshow, continuously, so we need to 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // trim the cache on a timer base too. endCacheTransaction() is called on a 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // timer base. We share the same timer with less frequent update. 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int mTrimCacheCount = 0; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TRIM_CACHE_INTERVAL = 5; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static WebViewDatabase mDataBase; 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static File mBaseDir; 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Flag to clear the cache when the CacheManager is initialized 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean mClearCacheOnInit = false; 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 89f0c443deca49d597c8268ef3b0f7198976073241Ben Murdoch /** 90303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Represents a resource stored in the HTTP cache. Instances of this class 91303bc083c5a158ff240be658ac30d201cad56a18Steve Block * can be obtained by calling 92303bc083c5a158ff240be658ac30d201cad56a18Steve Block * {@link CacheManager#getCacheFile CacheManager.getCacheFile(String, Map<String, String>))}. 93c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 94f0c443deca49d597c8268ef3b0f7198976073241Ben Murdoch */ 95c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static class CacheResult { 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // these fields are saved to the database 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int httpStatusCode; 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long contentLength; 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long expires; 101e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba String expiresString; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String localPath; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String lastModified; 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String etag; 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String mimeType; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String location; 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String encoding; 1080b956e1353a691674cb22c899c5a444b92532b60Grace Kloba String contentdisposition; 10960708a75120c4469dc2683485301ff9ee3b022e0Leon Clarke String crossDomain; 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // these fields are NOT saved to the database 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project InputStream inStream; 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OutputStream outStream; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File outFile; 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 116303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 117303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the status code of this cache entry. 118303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The status code of this cache entry 119303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getHttpStatusCode() { 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return httpStatusCode; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 124303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 125303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the content length of this cache entry. 126303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The content length of this cache entry 127303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getContentLength() { 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return contentLength; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 132303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 133303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the path of the file used to store the content of this cache 134303bc083c5a158ff240be658ac30d201cad56a18Steve Block * entry, relative to the base directory of the cache. See 135303bc083c5a158ff240be658ac30d201cad56a18Steve Block * {@link CacheManager#getCacheFileBaseDir CacheManager.getCacheFileBaseDir()}. 136303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The path of the file used to store this cache entry 137303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getLocalPath() { 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return localPath; 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 142303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 143303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the expiry date of this cache entry, expressed in milliseconds 144303bc083c5a158ff240be658ac30d201cad56a18Steve Block * since midnight, January 1, 1970 UTC. 145303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The expiry date of this cache entry 146303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getExpires() { 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return expires; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 151303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 152303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the expiry date of this cache entry, expressed as a string. 153303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The expiry date of this cache entry 154303bc083c5a158ff240be658ac30d201cad56a18Steve Block * 155303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 156e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba public String getExpiresString() { 157e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba return expiresString; 158e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba } 159e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba 160303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 161303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the date at which this cache entry was last modified, expressed 162303bc083c5a158ff240be658ac30d201cad56a18Steve Block * as a string. 163303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The date at which this cache entry was last modified 164303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getLastModified() { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return lastModified; 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 169303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 170303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the entity tag of this cache entry. 171303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The entity tag of this cache entry 172303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getETag() { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return etag; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 177303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 178303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the MIME type of this cache entry. 179303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The MIME type of this cache entry 180303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getMimeType() { 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mimeType; 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 185303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 186303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the value of the HTTP 'Location' header with which this cache 187303bc083c5a158ff240be658ac30d201cad56a18Steve Block * entry was received. 188303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The HTTP 'Location' header for this cache entry 189303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getLocation() { 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return location; 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 194303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 195303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the encoding of this cache entry. 196303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The encoding of this cache entry 197303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncoding() { 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return encoding; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 202303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 203303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the value of the HTTP 'Content-Disposition' header with which 204303bc083c5a158ff240be658ac30d201cad56a18Steve Block * this cache entry was received. 205303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The HTTP 'Content-Disposition' header for this cache entry 206303bc083c5a158ff240be658ac30d201cad56a18Steve Block * 207303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 2080b956e1353a691674cb22c899c5a444b92532b60Grace Kloba public String getContentDisposition() { 2090b956e1353a691674cb22c899c5a444b92532b60Grace Kloba return contentdisposition; 2100b956e1353a691674cb22c899c5a444b92532b60Grace Kloba } 2110b956e1353a691674cb22c899c5a444b92532b60Grace Kloba 212303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 213303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the input stream to the content of this cache entry, to allow 214303bc083c5a158ff240be658ac30d201cad56a18Steve Block * content to be read. See 215303bc083c5a158ff240be658ac30d201cad56a18Steve Block * {@link CacheManager#getCacheFile CacheManager.getCacheFile(String, Map<String, String>)}. 216303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return An input stream to the content of this cache entry 217303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public InputStream getInputStream() { 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return inStream; 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 222303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 223303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets an output stream to the content of this cache entry, to allow 224303bc083c5a158ff240be658ac30d201cad56a18Steve Block * content to be written. See 225303bc083c5a158ff240be658ac30d201cad56a18Steve Block * {@link CacheManager#saveCacheFile CacheManager.saveCacheFile(String, CacheResult)}. 226303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return An output stream to the content of this cache entry 227303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 228303bc083c5a158ff240be658ac30d201cad56a18Steve Block // Note that this is always null for objects returned by getCacheFile()! 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public OutputStream getOutputStream() { 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return outStream; 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 233303bc083c5a158ff240be658ac30d201cad56a18Steve Block 234303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 235303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Sets an input stream to the content of this cache entry. 236303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @param stream An input stream to the content of this cache entry 237303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setInputStream(InputStream stream) { 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.inStream = stream; 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 242303bc083c5a158ff240be658ac30d201cad56a18Steve Block /** 243303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Sets the encoding of this cache entry. 244303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @param encoding The encoding of this cache entry 245303bc083c5a158ff240be658ac30d201cad56a18Steve Block */ 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setEncoding(String encoding) { 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.encoding = encoding; 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 249b67529b905440e2ba550742773b927abad882c19Iain Merrick 250b67529b905440e2ba550742773b927abad882c19Iain Merrick /** 251b67529b905440e2ba550742773b927abad882c19Iain Merrick * @hide 252b67529b905440e2ba550742773b927abad882c19Iain Merrick */ 253b67529b905440e2ba550742773b927abad882c19Iain Merrick public void setContentLength(long contentLength) { 254b67529b905440e2ba550742773b927abad882c19Iain Merrick this.contentLength = contentLength; 255b67529b905440e2ba550742773b927abad882c19Iain Merrick } 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 259303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Initializes the HTTP cache. This method must be called before any 260303bc083c5a158ff240be658ac30d201cad56a18Steve Block * CacheManager methods are used. Note that this is called automatically 261303bc083c5a158ff240be658ac30d201cad56a18Steve Block * when a {@link WebView} is created. 262303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @param context The application context 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void init(Context context) { 265808751fe7ac16bf7224cba284a318695d8093355Steve Block if (JniUtil.useChromiumHttpStack()) { 266e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // This isn't actually where the real cache lives, but where we put files for the 267e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // purpose of getCacheFile(). 268e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block mBaseDir = new File(context.getCacheDir(), "webviewCacheChromiumStaging"); 269e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block if (!mBaseDir.exists()) { 270e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block mBaseDir.mkdirs(); 271e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block } 272808751fe7ac16bf7224cba284a318695d8093355Steve Block return; 273808751fe7ac16bf7224cba284a318695d8093355Steve Block } 274808751fe7ac16bf7224cba284a318695d8093355Steve Block 27501d0fbfa683012623f030ec75a63e1a9fabcb916Romain Guy mDataBase = WebViewDatabase.getInstance(context.getApplicationContext()); 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBaseDir = new File(context.getCacheDir(), "webviewCache"); 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (createCacheDirectory() && mClearCacheOnInit) { 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project removeAllCacheFiles(); 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mClearCacheOnInit = false; 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create the cache directory if it does not already exist. 28567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the cache directory didn't exist and was created. 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static private boolean createCacheDirectory() { 289808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 290808751fe7ac16bf7224cba284a318695d8093355Steve Block 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mBaseDir.exists()) { 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if(!mBaseDir.mkdirs()) { 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(LOGTAG, "Unable to create webviewCache directory"); 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileUtils.setPermissions( 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBaseDir.toString(), 29811c1a0be5d8332e662ccc00f4cb66d821e79c8dfJohn Reck FileUtils.S_IRWXU | FileUtils.S_IRWXG, 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project -1, -1); 30067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // If we did create the directory, we need to flush 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the cache database. The directory could be recreated 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // because the system flushed all the data/cache directories 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to free up disk space. 3042036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // delete rows in the cache database 3052036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba WebViewWorker.getHandler().sendEmptyMessage( 3062036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba WebViewWorker.MSG_CLEAR_CACHE); 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 313303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets the base directory in which the files used to store the contents of 314303bc083c5a158ff240be658ac30d201cad56a18Steve Block * cache entries are placed. See 315303bc083c5a158ff240be658ac30d201cad56a18Steve Block * {@link CacheManager.CacheResult#getLocalPath CacheManager.CacheResult.getLocalPath()}. 316303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return The base directory of the cache 317c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 319c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static File getCacheFileBaseDir() { 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBaseDir; 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 325303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Sets whether the HTTP cache should be disabled. 32667ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * @param disabled Whether the cache should be disabled 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void setCacheDisabled(boolean disabled) { 329808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 330808751fe7ac16bf7224cba284a318695d8093355Steve Block 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (disabled == mDisabled) { 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDisabled = disabled; 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDisabled) { 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project removeAllCacheFiles(); 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 341303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Gets whether the HTTP cache is disabled. 342303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return True if the HTTP cache is disabled 343c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 345c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static boolean cacheDisabled() { 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDisabled; 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3502036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebViewWorkerThread 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // make sure to call enableTransaction/disableTransaction in pair 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static boolean enableTransaction() { 353808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 354808751fe7ac16bf7224cba284a318695d8093355Steve Block 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (++mRefCount == 1) { 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataBase.startCacheTransaction(); 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3622036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebViewWorkerThread 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // make sure to call enableTransaction/disableTransaction in pair 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static boolean disableTransaction() { 365808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 366808751fe7ac16bf7224cba284a318695d8093355Steve Block 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (--mRefCount == 0) { 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataBase.endCacheTransaction(); 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3742036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebViewWorkerThread 3752036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // make sure to call startTransaction/endTransaction in pair 3762036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba static boolean startTransaction() { 377808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 378808751fe7ac16bf7224cba284a318695d8093355Steve Block 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDataBase.startCacheTransaction(); 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3822036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebViewWorkerThread 3832036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // make sure to call startTransaction/endTransaction in pair 3842036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba static boolean endTransaction() { 385808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 386808751fe7ac16bf7224cba284a318695d8093355Steve Block 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean ret = mDataBase.endCacheTransaction(); 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (++mTrimCacheCount >= TRIM_CACHE_INTERVAL) { 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrimCacheCount = 0; 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trimCacheIfNeeded(); 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3952036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba /** 396303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Starts a cache transaction. Returns true if this is the only running 397303bc083c5a158ff240be658ac30d201cad56a18Steve Block * transaction. Otherwise, this transaction is nested inside currently 398303bc083c5a158ff240be658ac30d201cad56a18Steve Block * running transactions and false is returned. 399303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return True if this is the only running transaction 400303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @deprecated This method no longer has any effect and always returns false 4012036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba */ 4022036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba @Deprecated 4032036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba public static boolean startCacheTransaction() { 4042036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba return false; 4052036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 4062036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba 4072036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba /** 408303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Ends the innermost cache transaction and returns whether this was the 409303bc083c5a158ff240be658ac30d201cad56a18Steve Block * only running transaction. 410303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @return True if this was the only running transaction 411303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @deprecated This method no longer has any effect and always returns false 4122036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba */ 4132036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba @Deprecated 4142036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba public static boolean endCacheTransaction() { 4152036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba return false; 4162036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 4172036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 419ffefba15e3a011836f037c185d4909a59995ff32Steve Block * Gets the cache entry for the specified URL, or null if none is found. 420ffefba15e3a011836f037c185d4909a59995ff32Steve Block * If a non-null value is provided for the HTTP headers map, and the cache 421ffefba15e3a011836f037c185d4909a59995ff32Steve Block * entry needs validation, appropriate headers will be added to the map. 422ffefba15e3a011836f037c185d4909a59995ff32Steve Block * The input stream of the CacheEntry object should be closed by the caller 423ffefba15e3a011836f037c185d4909a59995ff32Steve Block * when access to the underlying file is no longer required. 424ffefba15e3a011836f037c185d4909a59995ff32Steve Block * @param url The URL for which a cache entry is requested 425ffefba15e3a011836f037c185d4909a59995ff32Steve Block * @param headers A map from HTTP header name to value, to be populated 426ffefba15e3a011836f037c185d4909a59995ff32Steve Block * for the returned cache entry 427ffefba15e3a011836f037c185d4909a59995ff32Steve Block * @return The cache entry for the specified URL 428c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 430c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static CacheResult getCacheFile(String url, 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map<String, String> headers) { 4338c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba return getCacheFile(url, 0, headers); 4348c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba } 4358c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 436ffefba15e3a011836f037c185d4909a59995ff32Steve Block private static CacheResult getCacheFileChromiumHttpStack(String url) { 437ffefba15e3a011836f037c185d4909a59995ff32Steve Block assert JniUtil.useChromiumHttpStack(); 438ffefba15e3a011836f037c185d4909a59995ff32Steve Block 439ffefba15e3a011836f037c185d4909a59995ff32Steve Block CacheResult result = nativeGetCacheResult(url); 440ffefba15e3a011836f037c185d4909a59995ff32Steve Block if (result == null) { 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 443ffefba15e3a011836f037c185d4909a59995ff32Steve Block // A temporary local file will have been created native side and localPath set 444ffefba15e3a011836f037c185d4909a59995ff32Steve Block // appropriately. 445ffefba15e3a011836f037c185d4909a59995ff32Steve Block File src = new File(mBaseDir, result.localPath); 446ffefba15e3a011836f037c185d4909a59995ff32Steve Block try { 447ffefba15e3a011836f037c185d4909a59995ff32Steve Block // Open the file here so that even if it is deleted, the content 448ffefba15e3a011836f037c185d4909a59995ff32Steve Block // is still readable by the caller until close() is called. 449ffefba15e3a011836f037c185d4909a59995ff32Steve Block result.inStream = new FileInputStream(src); 450ffefba15e3a011836f037c185d4909a59995ff32Steve Block } catch (FileNotFoundException e) { 451ffefba15e3a011836f037c185d4909a59995ff32Steve Block Log.v(LOGTAG, "getCacheFile(): Failed to open file: " + e); 452ffefba15e3a011836f037c185d4909a59995ff32Steve Block // TODO: The files in the cache directory can be removed by the 453ffefba15e3a011836f037c185d4909a59995ff32Steve Block // system. If it is gone, what should we do? 454ffefba15e3a011836f037c185d4909a59995ff32Steve Block return null; 455808751fe7ac16bf7224cba284a318695d8093355Steve Block } 456ffefba15e3a011836f037c185d4909a59995ff32Steve Block return result; 457ffefba15e3a011836f037c185d4909a59995ff32Steve Block } 458ffefba15e3a011836f037c185d4909a59995ff32Steve Block 459ffefba15e3a011836f037c185d4909a59995ff32Steve Block private static CacheResult getCacheFileAndroidHttpStack(String url, 460ffefba15e3a011836f037c185d4909a59995ff32Steve Block long postIdentifier) { 461ffefba15e3a011836f037c185d4909a59995ff32Steve Block assert !JniUtil.useChromiumHttpStack(); 4628c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 463808751fe7ac16bf7224cba284a318695d8093355Steve Block String databaseKey = getDatabaseKey(url, postIdentifier); 4648c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba CacheResult result = mDataBase.getCache(databaseKey); 46567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block if (result == null) { 46667ba204aa23e7d5a96ad241a1623e44976b51741Steve Block return null; 46767ba204aa23e7d5a96ad241a1623e44976b51741Steve Block } 46867ba204aa23e7d5a96ad241a1623e44976b51741Steve Block if (result.contentLength == 0) { 46967ba204aa23e7d5a96ad241a1623e44976b51741Steve Block if (!isCachableRedirect(result.httpStatusCode)) { 47067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // This should not happen. If it does, remove it. 47167ba204aa23e7d5a96ad241a1623e44976b51741Steve Block mDataBase.removeCache(databaseKey); 47267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block return null; 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 47567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block File src = new File(mBaseDir, result.localPath); 47667ba204aa23e7d5a96ad241a1623e44976b51741Steve Block try { 47767ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // Open the file here so that even if it is deleted, the content 47867ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // is still readable by the caller until close() is called. 47967ba204aa23e7d5a96ad241a1623e44976b51741Steve Block result.inStream = new FileInputStream(src); 48067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block } catch (FileNotFoundException e) { 48167ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // The files in the cache directory can be removed by the 48267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // system. If it is gone, clean up the database. 48367ba204aa23e7d5a96ad241a1623e44976b51741Steve Block mDataBase.removeCache(databaseKey); 48467ba204aa23e7d5a96ad241a1623e44976b51741Steve Block return null; 48567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block } 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 487ffefba15e3a011836f037c185d4909a59995ff32Steve Block return result; 488ffefba15e3a011836f037c185d4909a59995ff32Steve Block } 489ffefba15e3a011836f037c185d4909a59995ff32Steve Block 490ffefba15e3a011836f037c185d4909a59995ff32Steve Block static CacheResult getCacheFile(String url, long postIdentifier, 491ffefba15e3a011836f037c185d4909a59995ff32Steve Block Map<String, String> headers) { 492ffefba15e3a011836f037c185d4909a59995ff32Steve Block if (mDisabled) { 493ffefba15e3a011836f037c185d4909a59995ff32Steve Block return null; 494ffefba15e3a011836f037c185d4909a59995ff32Steve Block } 495ffefba15e3a011836f037c185d4909a59995ff32Steve Block 496ffefba15e3a011836f037c185d4909a59995ff32Steve Block CacheResult result = JniUtil.useChromiumHttpStack() ? 497ffefba15e3a011836f037c185d4909a59995ff32Steve Block getCacheFileChromiumHttpStack(url) : 498ffefba15e3a011836f037c185d4909a59995ff32Steve Block getCacheFileAndroidHttpStack(url, postIdentifier); 499ffefba15e3a011836f037c185d4909a59995ff32Steve Block 500ffefba15e3a011836f037c185d4909a59995ff32Steve Block if (result == null) { 501ffefba15e3a011836f037c185d4909a59995ff32Steve Block return null; 502ffefba15e3a011836f037c185d4909a59995ff32Steve Block } 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 50467ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // A null value for headers is used by CACHE_MODE_CACHE_ONLY to imply 50567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // that we should provide the cache result even if it is expired. 50667ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // Note that a negative expires value means a time in the far future. 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (headers != null && result.expires >= 0 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && result.expires <= System.currentTimeMillis()) { 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result.lastModified == null && result.etag == null) { 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 51267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // Return HEADER_KEY_IFNONEMATCH or HEADER_KEY_IFMODIFIEDSINCE 51367ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // for requesting validation. 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result.etag != null) { 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project headers.put(HEADER_KEY_IFNONEMATCH, result.etag); 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result.lastModified != null) { 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project headers.put(HEADER_KEY_IFMODIFIEDSINCE, result.lastModified); 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5222e5c150e746647a1ce5c10e1708debbf06c45ea7Derek Sollenberger if (DebugFlags.CACHE_MANAGER) { 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(LOGTAG, "getCacheFile for url " + url); 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Given a url and its full headers, returns CacheResult if a local cache 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * can be stored. Otherwise returns null. The mimetype is passed in so that 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the function can use the mimetype that will be passed to WebCore which 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * could be different from the mimetype defined in the headers. 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * forceCache is for out-of-package callers to force creation of a 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * CacheResult, and is used to supply surrogate responses for URL 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * interception. 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return CacheResult for a given url 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 539303bc083c5a158ff240be658ac30d201cad56a18Steve Block static CacheResult createCacheFile(String url, int statusCode, 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Headers headers, String mimeType, boolean forceCache) { 541808751fe7ac16bf7224cba284a318695d8093355Steve Block if (JniUtil.useChromiumHttpStack()) { 542e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // This method is public but hidden. We break functionality. 543808751fe7ac16bf7224cba284a318695d8093355Steve Block return null; 544808751fe7ac16bf7224cba284a318695d8093355Steve Block } 545808751fe7ac16bf7224cba284a318695d8093355Steve Block 5468c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba return createCacheFile(url, statusCode, headers, mimeType, 0, 5478c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba forceCache); 5488c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba } 5498c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 5508c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba static CacheResult createCacheFile(String url, int statusCode, 5518c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba Headers headers, String mimeType, long postIdentifier, 5528c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba boolean forceCache) { 553808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 554808751fe7ac16bf7224cba284a318695d8093355Steve Block 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!forceCache && mDisabled) { 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5598c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba String databaseKey = getDatabaseKey(url, postIdentifier); 5608c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 561105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // according to the rfc 2616, the 303 response MUST NOT be cached. 562105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (statusCode == 303) { 5633afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba // remove the saved cache if there is any 5648c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba mDataBase.removeCache(databaseKey); 565105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return null; 566105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 567105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 568105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // like the other browsers, do not cache redirects containing a cookie 569105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // header. 57067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block if (isCachableRedirect(statusCode) && !headers.getSetCookie().isEmpty()) { 5713afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba // remove the saved cache if there is any 5728c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba mDataBase.removeCache(databaseKey); 573105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return null; 574105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 575105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CacheResult ret = parseHeaders(statusCode, headers, mimeType); 5773afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba if (ret == null) { 5783afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba // this should only happen if the headers has "no-store" in the 5793afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba // cache-control. remove the saved cache if there is any 5808c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba mDataBase.removeCache(databaseKey); 5813afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba } else { 5828c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba setupFiles(databaseKey, ret); 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.outStream = new FileOutputStream(ret.outFile); 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (FileNotFoundException e) { 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This can happen with the system did a purge and our 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // subdirectory has gone, so lets try to create it again 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (createCacheDirectory()) { 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.outStream = new FileOutputStream(ret.outFile); 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (FileNotFoundException e2) { 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We failed to create the file again, so there 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // is something else wrong. Return null. 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Failed to create cache directory 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.mimeType = mimeType; 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 608303bc083c5a158ff240be658ac30d201cad56a18Steve Block * Adds a cache entry to the HTTP cache for the specicifed URL. Also closes 609303bc083c5a158ff240be658ac30d201cad56a18Steve Block * the cache entry's output stream. 610303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @param url The URL for which the cache entry should be added 611303bc083c5a158ff240be658ac30d201cad56a18Steve Block * @param cacheResult The cache entry to add 612c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 614c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 615303bc083c5a158ff240be658ac30d201cad56a18Steve Block public static void saveCacheFile(String url, CacheResult cacheResult) { 616303bc083c5a158ff240be658ac30d201cad56a18Steve Block saveCacheFile(url, 0, cacheResult); 6178c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba } 6188c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 6198c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba static void saveCacheFile(String url, long postIdentifier, 6208c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba CacheResult cacheRet) { 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.outStream.close(); 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 627808751fe7ac16bf7224cba284a318695d8093355Steve Block if (JniUtil.useChromiumHttpStack()) { 628303bc083c5a158ff240be658ac30d201cad56a18Steve Block // This method is exposed in the public API but the API provides no 629303bc083c5a158ff240be658ac30d201cad56a18Steve Block // way to obtain a new CacheResult object with a non-null output 630303bc083c5a158ff240be658ac30d201cad56a18Steve Block // stream ... 631303bc083c5a158ff240be658ac30d201cad56a18Steve Block // - CacheResult objects returned by getCacheFile() have a null 632303bc083c5a158ff240be658ac30d201cad56a18Steve Block // output stream. 633303bc083c5a158ff240be658ac30d201cad56a18Steve Block // - new CacheResult objects have a null output stream and no 634303bc083c5a158ff240be658ac30d201cad56a18Steve Block // setter is provided. 635303bc083c5a158ff240be658ac30d201cad56a18Steve Block // Since this method throws a null pointer exception in this case, 636303bc083c5a158ff240be658ac30d201cad56a18Steve Block // it is effectively useless from the point of view of the public 637303bc083c5a158ff240be658ac30d201cad56a18Steve Block // API. 638303bc083c5a158ff240be658ac30d201cad56a18Steve Block // 639303bc083c5a158ff240be658ac30d201cad56a18Steve Block // With the Chromium HTTP stack we continue to throw the same 640303bc083c5a158ff240be658ac30d201cad56a18Steve Block // exception for 'backwards compatibility' with the Android HTTP 641303bc083c5a158ff240be658ac30d201cad56a18Steve Block // stack. 642303bc083c5a158ff240be658ac30d201cad56a18Steve Block // 643303bc083c5a158ff240be658ac30d201cad56a18Steve Block // This method is not used from within this package with the 644303bc083c5a158ff240be658ac30d201cad56a18Steve Block // Chromium HTTP stack, and for public API use, we should already 645303bc083c5a158ff240be658ac30d201cad56a18Steve Block // have thrown an exception above. 646e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block assert false; 647303bc083c5a158ff240be658ac30d201cad56a18Steve Block return; 648808751fe7ac16bf7224cba284a318695d8093355Steve Block } 649808751fe7ac16bf7224cba284a318695d8093355Steve Block 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!cacheRet.outFile.exists()) { 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the file in the cache directory can be removed by the system 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 65567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block boolean redirect = isCachableRedirect(cacheRet.httpStatusCode); 656543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if (redirect) { 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // location is in database, no need to keep the file 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.contentLength = 0; 659686cf75d5cf447d34961f6217f2ea3ce3e484ac2Cary Clark cacheRet.localPath = ""; 660543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark } 661543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if ((redirect || cacheRet.contentLength == 0) 662543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark && !cacheRet.outFile.delete()) { 663543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark Log.e(LOGTAG, cacheRet.outFile.getPath() + " delete failed."); 664543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark } 665543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if (cacheRet.contentLength == 0) { 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6698c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba mDataBase.addCache(getDatabaseKey(url, postIdentifier), cacheRet); 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6712e5c150e746647a1ce5c10e1708debbf06c45ea7Derek Sollenberger if (DebugFlags.CACHE_MANAGER) { 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(LOGTAG, "saveCacheFile for url " + url); 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 676998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba static boolean cleanupCacheFile(CacheResult cacheRet) { 677808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 678808751fe7ac16bf7224cba284a318695d8093355Steve Block 679998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba try { 680998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba cacheRet.outStream.close(); 681998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba } catch (IOException e) { 682998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba return false; 683998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba } 684998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba return cacheRet.outFile.delete(); 685998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba } 686998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 68867ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * Remove all cache files. 68967ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * 69067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * @return Whether the removal succeeded. 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static boolean removeAllCacheFiles() { 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Note, this is called before init() when the database is 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // created or upgraded. 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mBaseDir == null) { 6968beb86c0430a7125bb1617172f34187308b178c0Kristian Monsen // This method should not be called before init() when using the 6978beb86c0430a7125bb1617172f34187308b178c0Kristian Monsen // chrome http stack 6988beb86c0430a7125bb1617172f34187308b178c0Kristian Monsen assert !JniUtil.useChromiumHttpStack(); 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Init() has not been called yet, so just flag that 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we need to clear the cache when init() is called. 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mClearCacheOnInit = true; 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7042036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // delete rows in the cache database 705cedb3a7e5849fd16e939add1ac6f5586467b8c68Kristian Monsen if (!JniUtil.useChromiumHttpStack()) 706cedb3a7e5849fd16e939add1ac6f5586467b8c68Kristian Monsen WebViewWorker.getHandler().sendEmptyMessage(WebViewWorker.MSG_CLEAR_CACHE); 707cedb3a7e5849fd16e939add1ac6f5586467b8c68Kristian Monsen 7082036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // delete cache files in a separate thread to not block UI. 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Runnable clearCache = new Runnable() { 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // delete all cache files 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] files = mBaseDir.list(); 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if mBaseDir doesn't exist, files can be null. 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (files != null) { 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < files.length; i++) { 717543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark File f = new File(mBaseDir, files[i]); 718543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if (!f.delete()) { 719543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark Log.e(LOGTAG, f.getPath() + " delete failed."); 720543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark } 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SecurityException e) { 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Ignore SecurityExceptions. 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new Thread(clearCache).start(); 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void trimCacheIfNeeded() { 733808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 734808751fe7ac16bf7224cba284a318695d8093355Steve Block 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDataBase.getCacheTotalSize() > CACHE_THRESHOLD) { 7362036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba List<String> pathList = mDataBase.trimCache(CACHE_TRIM_AMOUNT); 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = pathList.size(); 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 739543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark File f = new File(mBaseDir, pathList.get(i)); 740543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if (!f.delete()) { 741543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark Log.e(LOGTAG, f.getPath() + " delete failed."); 742543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark } 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7442036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // remove the unreferenced files in the cache directory 7452036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba final List<String> fileList = mDataBase.getAllCacheFileNames(); 7462036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba if (fileList == null) return; 7472036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba String[] toDelete = mBaseDir.list(new FilenameFilter() { 7482036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba public boolean accept(File dir, String filename) { 7492036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba if (fileList.contains(filename)) { 7502036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba return false; 7512036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } else { 7522036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba return true; 7532036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 7542036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 7552036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba }); 7562036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba if (toDelete == null) return; 7572036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba size = toDelete.length; 7582036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba for (int i = 0; i < size; i++) { 7592036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba File f = new File(mBaseDir, toDelete[i]); 7602036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba if (!f.delete()) { 7612036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba Log.e(LOGTAG, f.getPath() + " delete failed."); 7622036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 7632036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7672036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba static void clearCache() { 768808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 769808751fe7ac16bf7224cba284a318695d8093355Steve Block 7702036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // delete database 7712036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba mDataBase.clearCache(); 7722036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 7732036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba 77467ba204aa23e7d5a96ad241a1623e44976b51741Steve Block private static boolean isCachableRedirect(int statusCode) { 775105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (statusCode == 301 || statusCode == 302 || statusCode == 307) { 776105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // as 303 can't be cached, we do not return true 777105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 778105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } else { 779105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return false; 780105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 781105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 782105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 7838c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba private static String getDatabaseKey(String url, long postIdentifier) { 784808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 785808751fe7ac16bf7224cba284a318695d8093355Steve Block 7868c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba if (postIdentifier == 0) return url; 7878c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba return postIdentifier + url; 7888c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba } 7898c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("deprecation") 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void setupFiles(String url, CacheResult cacheRet) { 792808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 793808751fe7ac16bf7224cba284a318695d8093355Steve Block 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (true) { 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Note: SHA1 is much stronger hash. But the cost of setupFiles() is 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // 3.2% cpu time for a fresh load of nytimes.com. While a simple 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // String.hashCode() is only 0.6%. If adding the collision resolving 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to String.hashCode(), it makes the cpu time to be 1.6% for a 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // fresh load, but 5.3% for the worst case where all the files 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // already exist in the file system, but database is gone. So it 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // needs to resolve collision for every file at least once. 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int hashCode = url.hashCode(); 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuffer ret = new StringBuffer(8); 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project appendAsHex(hashCode, ret); 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String path = ret.toString(); 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File file = new File(mBaseDir, path); 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (true) { 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean checkOldPath = true; 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check hash collision. If the hash file doesn't exist, just 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // continue. There is a chance that the old cache file is not 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // same as the hash file. As mDataBase.getCache() is more 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // expansive than "leak" a file until clear cache, don't bother. 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the hash file exists, make sure that it is same as the 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // cache file. If it is not, resolve the collision. 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (file.exists()) { 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (checkOldPath) { 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CacheResult oldResult = mDataBase.getCache(url); 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldResult != null && oldResult.contentLength > 0) { 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path.equals(oldResult.localPath)) { 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = oldResult.localPath; 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = oldResult.localPath; 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project file = new File(mBaseDir, path); 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkOldPath = false; 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret = new StringBuffer(8); 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project appendAsHex(++hashCode, ret); 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = ret.toString(); 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project file = new File(mBaseDir, path); 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.localPath = path; 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.outFile = file; 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // get hash in byte[] 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Digest digest = new SHA1Digest(); 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int digestLen = digest.getDigestSize(); 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] hash = new byte[digestLen]; 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int urlLen = url.length(); 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] data = new byte[urlLen]; 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project url.getBytes(0, urlLen, data, 0); 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project digest.update(data, 0, urlLen); 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project digest.doFinal(hash, 0); 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // convert byte[] to hex String 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuffer result = new StringBuffer(2 * digestLen); 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < digestLen; i = i + 4) { 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int h = (0x00ff & hash[i]) << 24 | (0x00ff & hash[i + 1]) << 16 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project | (0x00ff & hash[i + 2]) << 8 | (0x00ff & hash[i + 3]); 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project appendAsHex(h, result); 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.localPath = result.toString(); 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.outFile = new File(mBaseDir, cacheRet.localPath); 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void appendAsHex(int i, StringBuffer ret) { 860808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 861808751fe7ac16bf7224cba284a318695d8093355Steve Block 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String hex = Integer.toHexString(i); 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (hex.length()) { 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 1: 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("0000000"); 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 2: 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("000000"); 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 3: 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("00000"); 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 4: 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("0000"); 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 5: 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("000"); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 6: 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("00"); 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 7: 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("0"); 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append(hex); 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static CacheResult parseHeaders(int statusCode, Headers headers, 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String mimeType) { 891808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 892808751fe7ac16bf7224cba284a318695d8093355Steve Block 893998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba // if the contentLength is already larger than CACHE_MAX_SIZE, skip it 894998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba if (headers.getContentLength() > CACHE_MAX_SIZE) return null; 895998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba 896a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // The HTML 5 spec, section 6.9.4, step 7.3 of the application cache 897a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // process states that HTTP caching rules are ignored for the 898a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // purposes of the application cache download process. 899a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // At this point we can't tell that if a file is part of this process, 900a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // except for the manifest, which has its own mimeType. 901a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // TODO: work out a way to distinguish all responses that are part of 902a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // the application download process and skip them. 903a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu if (MANIFEST_MIME.equals(mimeType)) return null; 904a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: if authenticated or secure, return null 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CacheResult ret = new CacheResult(); 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.httpStatusCode = statusCode; 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9097a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block ret.location = headers.getLocation(); 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = -1; 912e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba ret.expiresString = headers.getExpires(); 913e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba if (ret.expiresString != null) { 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9157cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson ret.expires = AndroidHttpClient.parseDate(ret.expiresString); 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalArgumentException ex) { 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Take care of the special "-1" and "0" cases 918e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba if ("-1".equals(ret.expiresString) 919e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba || "0".equals(ret.expiresString)) { 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // make it expired, but can be used for history navigation 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 923e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba Log.e(LOGTAG, "illegal expires: " + ret.expiresString); 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9287a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block ret.contentdisposition = headers.getContentDisposition(); 9290b956e1353a691674cb22c899c5a444b92532b60Grace Kloba 9307a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block ret.crossDomain = headers.getXPermittedCrossDomainPolicies(); 93160708a75120c4469dc2683485301ff9ee3b022e0Leon Clarke 9327865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba // lastModified and etag may be set back to http header. So they can't 9337865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba // be empty string. 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String lastModified = headers.getLastModified(); 9357865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba if (lastModified != null && lastModified.length() > 0) { 9367865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba ret.lastModified = lastModified; 9377865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba } 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String etag = headers.getEtag(); 9407a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block if (etag != null && etag.length() > 0) { 9417a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block ret.etag = etag; 9427a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block } 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String cacheControl = headers.getCacheControl(); 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cacheControl != null) { 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] controls = cacheControl.toLowerCase().split("[ ,;]"); 947eb0ced7a094df2c73e052a066535f4359b11a92dHenrik Baard boolean noCache = false; 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < controls.length; i++) { 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NO_STORE.equals(controls[i])) { 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // According to the spec, 'no-cache' means that the content 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // must be re-validated on every load. It does not mean that 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the content can not be cached. set to expire 0 means it 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // can only be used in CACHE_MODE_CACHE_ONLY case 95652cf58a2a47e4dc975314fab44783c7e4654ca6dGrace Kloba if (NO_CACHE.equals(controls[i])) { 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 958eb0ced7a094df2c73e052a066535f4359b11a92dHenrik Baard noCache = true; 959eb0ced7a094df2c73e052a066535f4359b11a92dHenrik Baard // if cache control = no-cache has been received, ignore max-age 960eb0ced7a094df2c73e052a066535f4359b11a92dHenrik Baard // header, according to http spec: 961eb0ced7a094df2c73e052a066535f4359b11a92dHenrik Baard // If a request includes the no-cache directive, it SHOULD NOT 962eb0ced7a094df2c73e052a066535f4359b11a92dHenrik Baard // include min-fresh, max-stale, or max-age. 963eb0ced7a094df2c73e052a066535f4359b11a92dHenrik Baard } else if (controls[i].startsWith(MAX_AGE) && !noCache) { 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int separator = controls[i].indexOf('='); 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (separator < 0) { 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project separator = controls[i].indexOf(':'); 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (separator > 0) { 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String s = controls[i].substring(separator + 1); 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long sec = Long.parseLong(s); 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sec >= 0) { 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = System.currentTimeMillis() + 1000 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sec; 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException ex) { 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ("1d".equals(s)) { 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Take care of the special "1d" case 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = System.currentTimeMillis() + 86400000; // 24*60*60*1000 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(LOGTAG, "exception in parseHeaders for " 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "max-age:" 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + controls[i].substring(separator + 1)); 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // According to RFC 2616 section 14.32: 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // client had sent "Cache-Control: no-cache" 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NO_CACHE.equals(headers.getPragma())) { 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // According to RFC 2616 section 13.2.4, if an expiration has not been 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // explicitly defined a heuristic to set an expiration may be used. 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ret.expires == -1) { 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ret.httpStatusCode == 301) { 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If it is a permanent redirect, and it did not have an 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // explicit cache directive, then it never expires 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = Long.MAX_VALUE; 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (ret.httpStatusCode == 302 || ret.httpStatusCode == 307) { 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If it is temporary redirect, expires 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (ret.lastModified == null) { 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // When we have no last-modified, then expire the content with 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in 24hrs as, according to the RFC, longer time requires a 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // warning 113 to be added to the response. 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Only add the default expiration for non-html markup. Some 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // sites like news.google.com have no cache directives. 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mimeType.startsWith("text/html")) { 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = System.currentTimeMillis() + 86400000; // 24*60*60*1000 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Setting a expires as zero will cache the result for 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // forward/back nav. 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If we have a last-modified value, we could use it to set the 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // expiration. Suggestion from RFC is 10% of time since 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // last-modified. As we are on mobile, loads are expensive, 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // increasing this to 20%. 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // 24 * 60 * 60 * 1000 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long lastmod = System.currentTimeMillis() + 86400000; 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10327cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson lastmod = AndroidHttpClient.parseDate(ret.lastModified); 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalArgumentException ex) { 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(LOGTAG, "illegal lastModified: " + ret.lastModified); 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long difference = System.currentTimeMillis() - lastmod; 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (difference > 0) { 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = System.currentTimeMillis() + difference / 5; 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // last modified is in the future, expire the content 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // on the last modified 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = lastmod; 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1049e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block 1050e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block private static native CacheResult nativeGetCacheResult(String url); 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1052