CacheManager.java revision cedb3a7e5849fd16e939add1ac6f5586467b8c68
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 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.bouncycastle.crypto.Digest; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.bouncycastle.crypto.digests.SHA1Digest; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The class CacheManager provides the persistent cache of content that is 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * received over the network. The component handles parsing of HTTP headers and 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * utilizes the relevant cache headers to determine if the content should be 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * stored and if so, how long it is valid for. Network requests are provided to 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this component and if they can not be resolved by the cache, the HTTP headers 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * are attached, as appropriate, to the request for revalidation of content. The 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * class also manages the cache size. 47c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * 48c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 50c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick@Deprecated 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic final class CacheManager { 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String LOGTAG = "cache"; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String HEADER_KEY_IFMODIFIEDSINCE = "if-modified-since"; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static final String HEADER_KEY_IFNONEMATCH = "if-none-match"; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String NO_STORE = "no-store"; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String NO_CACHE = "no-cache"; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String MAX_AGE = "max-age"; 61a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu private static final String MANIFEST_MIME = "text/cache-manifest"; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static long CACHE_THRESHOLD = 6 * 1024 * 1024; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static long CACHE_TRIM_AMOUNT = 2 * 1024 * 1024; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 66998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba // Limit the maximum cache file size to half of the normal capacity 67998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba static long CACHE_MAX_SIZE = (CACHE_THRESHOLD - CACHE_TRIM_AMOUNT) / 2; 68998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean mDisabled; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Reference count the enable/disable transaction 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int mRefCount; 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // trimCacheIfNeeded() is called when a page is fully loaded. But JavaScript 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // can load the content, e.g. in a slideshow, continuously, so we need to 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // trim the cache on a timer base too. endCacheTransaction() is called on a 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // timer base. We share the same timer with less frequent update. 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int mTrimCacheCount = 0; 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int TRIM_CACHE_INTERVAL = 5; 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static WebViewDatabase mDataBase; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static File mBaseDir; 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Flag to clear the cache when the CacheManager is initialized 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static boolean mClearCacheOnInit = false; 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 87f0c443deca49d597c8268ef3b0f7198976073241Ben Murdoch /** 88f0c443deca49d597c8268ef3b0f7198976073241Ben Murdoch * This class represents a resource retrieved from the HTTP cache. 89f0c443deca49d597c8268ef3b0f7198976073241Ben Murdoch * Instances of this class can be obtained by invoking the 90f0c443deca49d597c8268ef3b0f7198976073241Ben Murdoch * CacheManager.getCacheFile() method. 91c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * 92c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 93f0c443deca49d597c8268ef3b0f7198976073241Ben Murdoch */ 94c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static class CacheResult { 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // these fields are saved to the database 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int httpStatusCode; 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long contentLength; 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long expires; 100e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba String expiresString; 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String localPath; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String lastModified; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String etag; 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String mimeType; 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String location; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String encoding; 1070b956e1353a691674cb22c899c5a444b92532b60Grace Kloba String contentdisposition; 10860708a75120c4469dc2683485301ff9ee3b022e0Leon Clarke String crossDomain; 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // these fields are NOT saved to the database 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project InputStream inStream; 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project OutputStream outStream; 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File outFile; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getHttpStatusCode() { 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return httpStatusCode; 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getContentLength() { 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return contentLength; 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getLocalPath() { 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return localPath; 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getExpires() { 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return expires; 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 131e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba public String getExpiresString() { 132e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba return expiresString; 133e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba } 134e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getLastModified() { 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return lastModified; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getETag() { 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return etag; 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getMimeType() { 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mimeType; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getLocation() { 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return location; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String getEncoding() { 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return encoding; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1550b956e1353a691674cb22c899c5a444b92532b60Grace Kloba public String getContentDisposition() { 1560b956e1353a691674cb22c899c5a444b92532b60Grace Kloba return contentdisposition; 1570b956e1353a691674cb22c899c5a444b92532b60Grace Kloba } 1580b956e1353a691674cb22c899c5a444b92532b60Grace Kloba 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // For out-of-package access to the underlying streams. 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public InputStream getInputStream() { 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return inStream; 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public OutputStream getOutputStream() { 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return outStream; 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // These fields can be set manually. 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setInputStream(InputStream stream) { 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.inStream = stream; 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setEncoding(String encoding) { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.encoding = encoding; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 176b67529b905440e2ba550742773b927abad882c19Iain Merrick 177b67529b905440e2ba550742773b927abad882c19Iain Merrick /** 178b67529b905440e2ba550742773b927abad882c19Iain Merrick * @hide 179b67529b905440e2ba550742773b927abad882c19Iain Merrick */ 180b67529b905440e2ba550742773b927abad882c19Iain Merrick public void setContentLength(long contentLength) { 181b67529b905440e2ba550742773b927abad882c19Iain Merrick this.contentLength = contentLength; 182b67529b905440e2ba550742773b927abad882c19Iain Merrick } 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18667ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * Initialize the CacheManager. 18767ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * 18867ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * Note that this is called automatically when a {@link android.webkit.WebView} is created. 18967ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param context The application context. 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void init(Context context) { 193808751fe7ac16bf7224cba284a318695d8093355Steve Block if (JniUtil.useChromiumHttpStack()) { 194e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // This isn't actually where the real cache lives, but where we put files for the 195e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // purpose of getCacheFile(). 196e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block mBaseDir = new File(context.getCacheDir(), "webviewCacheChromiumStaging"); 197e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block if (!mBaseDir.exists()) { 198e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block mBaseDir.mkdirs(); 199e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block } else { 200e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // TODO: Should we clear out old files? 201e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block } 202808751fe7ac16bf7224cba284a318695d8093355Steve Block return; 203808751fe7ac16bf7224cba284a318695d8093355Steve Block } 204808751fe7ac16bf7224cba284a318695d8093355Steve Block 20501d0fbfa683012623f030ec75a63e1a9fabcb916Romain Guy mDataBase = WebViewDatabase.getInstance(context.getApplicationContext()); 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBaseDir = new File(context.getCacheDir(), "webviewCache"); 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (createCacheDirectory() && mClearCacheOnInit) { 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project removeAllCacheFiles(); 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mClearCacheOnInit = false; 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create the cache directory if it does not already exist. 21567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return true if the cache directory didn't exist and was created. 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static private boolean createCacheDirectory() { 219808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 220808751fe7ac16bf7224cba284a318695d8093355Steve Block 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mBaseDir.exists()) { 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if(!mBaseDir.mkdirs()) { 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(LOGTAG, "Unable to create webviewCache directory"); 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileUtils.setPermissions( 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBaseDir.toString(), 22811c1a0be5d8332e662ccc00f4cb66d821e79c8dfJohn Reck FileUtils.S_IRWXU | FileUtils.S_IRWXG, 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project -1, -1); 23067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // If we did create the directory, we need to flush 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the cache database. The directory could be recreated 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // because the system flushed all the data/cache directories 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to free up disk space. 2342036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // delete rows in the cache database 2352036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba WebViewWorker.getHandler().sendEmptyMessage( 2362036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba WebViewWorker.MSG_CLEAR_CACHE); 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 24367ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * Get the base directory of the cache. Together with the local path of the CacheResult, 24467ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * obtained from {@link android.webkit.CacheManager.CacheResult#getLocalPath}, this 24567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * identifies the cache file. 246c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * 247cedb3a7e5849fd16e939add1ac6f5586467b8c68Kristian Monsen * Cache files are not guaranteed to be in this directory before 248cedb3a7e5849fd16e939add1ac6f5586467b8c68Kristian Monsen * CacheManager#getCacheFile(String, Map<String, String>) is called. 249cedb3a7e5849fd16e939add1ac6f5586467b8c68Kristian Monsen * 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return File The base directory of the cache. 251c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * 252c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 254c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static File getCacheFileBaseDir() { 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mBaseDir; 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 26067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * Sets whether the cache is disabled. 26167ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * 26267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * @param disabled Whether the cache should be disabled 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void setCacheDisabled(boolean disabled) { 265808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 266808751fe7ac16bf7224cba284a318695d8093355Steve Block 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (disabled == mDisabled) { 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDisabled = disabled; 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDisabled) { 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project removeAllCacheFiles(); 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 27767ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * Whether the cache is disabled. 278c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * 27967ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * @return return Whether the cache is disabled 280c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * 281c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 283c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static boolean cacheDisabled() { 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDisabled; 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2882036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebViewWorkerThread 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // make sure to call enableTransaction/disableTransaction in pair 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static boolean enableTransaction() { 291808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 292808751fe7ac16bf7224cba284a318695d8093355Steve Block 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (++mRefCount == 1) { 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataBase.startCacheTransaction(); 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3002036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebViewWorkerThread 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // make sure to call enableTransaction/disableTransaction in pair 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static boolean disableTransaction() { 303808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 304808751fe7ac16bf7224cba284a318695d8093355Steve Block 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (--mRefCount == 0) { 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDataBase.endCacheTransaction(); 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 3122036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebViewWorkerThread 3132036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // make sure to call startTransaction/endTransaction in pair 3142036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba static boolean startTransaction() { 315808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 316808751fe7ac16bf7224cba284a318695d8093355Steve Block 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mDataBase.startCacheTransaction(); 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3202036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebViewWorkerThread 3212036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // make sure to call startTransaction/endTransaction in pair 3222036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba static boolean endTransaction() { 323808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 324808751fe7ac16bf7224cba284a318695d8093355Steve Block 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean ret = mDataBase.endCacheTransaction(); 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (++mTrimCacheCount >= TRIM_CACHE_INTERVAL) { 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrimCacheCount = 0; 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project trimCacheIfNeeded(); 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3332036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebCore Thread 3342036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // make sure to call startCacheTransaction/endCacheTransaction in pair 3352036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba /** 336201480c50e6f0ca7a0df7dfb14ba748c710969eaJoe Onorato * @deprecated Always returns false. 3372036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba */ 3382036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba @Deprecated 3392036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba public static boolean startCacheTransaction() { 3402036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba return false; 3412036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 3422036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba 3432036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // only called from WebCore Thread 3442036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // make sure to call startCacheTransaction/endCacheTransaction in pair 3452036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba /** 346201480c50e6f0ca7a0df7dfb14ba748c710969eaJoe Onorato * @deprecated Always returns false. 3472036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba */ 3482036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba @Deprecated 3492036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba public static boolean endCacheTransaction() { 3502036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba return false; 3512036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 3522036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 35467ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * Given a URL, returns the corresponding CacheResult if it exists, or null otherwise. 35567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * 356e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block * The input stream of the CacheEntry object is initialized and opened and should be closed by 357e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block * the caller when access to the underlying file is no longer required. 35867ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * If a non-zero value is provided for the headers map, and the cache entry needs validation, 35967ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * HEADER_KEY_IFNONEMATCH or HEADER_KEY_IFMODIFIEDSINCE will be set in headers. 36067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * 36167ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * @return The CacheResult for the given URL 362c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * 363c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 365c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static CacheResult getCacheFile(String url, 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Map<String, String> headers) { 3688c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba return getCacheFile(url, 0, headers); 3698c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba } 3708c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 3718c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba static CacheResult getCacheFile(String url, long postIdentifier, 3728c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba Map<String, String> headers) { 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDisabled) { 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 377808751fe7ac16bf7224cba284a318695d8093355Steve Block if (JniUtil.useChromiumHttpStack()) { 378e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block CacheResult result = nativeGetCacheResult(url); 379e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block if (result == null) { 380e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block return null; 381e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block } 382e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // A temporary local file will have been created native side and localPath set 383e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // appropriately. 384e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block File src = new File(mBaseDir, result.localPath); 385e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block try { 386e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // Open the file here so that even if it is deleted, the content 387e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // is still readable by the caller until close() is called. 388e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block result.inStream = new FileInputStream(src); 389e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block } catch (FileNotFoundException e) { 390e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block Log.v(LOGTAG, "getCacheFile(): Failed to open file: " + e); 391e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // TODO: The files in the cache directory can be removed by the 392e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // system. If it is gone, what should we do? 393e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block return null; 394e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block } 395e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block return result; 396808751fe7ac16bf7224cba284a318695d8093355Steve Block } 3978c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 398808751fe7ac16bf7224cba284a318695d8093355Steve Block String databaseKey = getDatabaseKey(url, postIdentifier); 3998c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba CacheResult result = mDataBase.getCache(databaseKey); 40067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block if (result == null) { 40167ba204aa23e7d5a96ad241a1623e44976b51741Steve Block return null; 40267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block } 40367ba204aa23e7d5a96ad241a1623e44976b51741Steve Block if (result.contentLength == 0) { 40467ba204aa23e7d5a96ad241a1623e44976b51741Steve Block if (!isCachableRedirect(result.httpStatusCode)) { 40567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // This should not happen. If it does, remove it. 40667ba204aa23e7d5a96ad241a1623e44976b51741Steve Block mDataBase.removeCache(databaseKey); 40767ba204aa23e7d5a96ad241a1623e44976b51741Steve Block return null; 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 41067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block File src = new File(mBaseDir, result.localPath); 41167ba204aa23e7d5a96ad241a1623e44976b51741Steve Block try { 41267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // Open the file here so that even if it is deleted, the content 41367ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // is still readable by the caller until close() is called. 41467ba204aa23e7d5a96ad241a1623e44976b51741Steve Block result.inStream = new FileInputStream(src); 41567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block } catch (FileNotFoundException e) { 41667ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // The files in the cache directory can be removed by the 41767ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // system. If it is gone, clean up the database. 41867ba204aa23e7d5a96ad241a1623e44976b51741Steve Block mDataBase.removeCache(databaseKey); 41967ba204aa23e7d5a96ad241a1623e44976b51741Steve Block return null; 42067ba204aa23e7d5a96ad241a1623e44976b51741Steve Block } 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 42367ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // A null value for headers is used by CACHE_MODE_CACHE_ONLY to imply 42467ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // that we should provide the cache result even if it is expired. 42567ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // Note that a negative expires value means a time in the far future. 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (headers != null && result.expires >= 0 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && result.expires <= System.currentTimeMillis()) { 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result.lastModified == null && result.etag == null) { 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 43167ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // Return HEADER_KEY_IFNONEMATCH or HEADER_KEY_IFMODIFIEDSINCE 43267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block // for requesting validation. 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result.etag != null) { 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project headers.put(HEADER_KEY_IFNONEMATCH, result.etag); 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result.lastModified != null) { 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project headers.put(HEADER_KEY_IFMODIFIEDSINCE, result.lastModified); 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4412e5c150e746647a1ce5c10e1708debbf06c45ea7Derek Sollenberger if (DebugFlags.CACHE_MANAGER) { 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(LOGTAG, "getCacheFile for url " + url); 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Given a url and its full headers, returns CacheResult if a local cache 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * can be stored. Otherwise returns null. The mimetype is passed in so that 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the function can use the mimetype that will be passed to WebCore which 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * could be different from the mimetype defined in the headers. 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * forceCache is for out-of-package callers to force creation of a 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * CacheResult, and is used to supply surrogate responses for URL 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * interception. 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return CacheResult for a given url 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide - hide createCacheFile since it has a parameter of type headers, which is 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in a hidden package. 459c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * 460c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 462c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static CacheResult createCacheFile(String url, int statusCode, 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Headers headers, String mimeType, boolean forceCache) { 465808751fe7ac16bf7224cba284a318695d8093355Steve Block if (JniUtil.useChromiumHttpStack()) { 466e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // This method is public but hidden. We break functionality. 467808751fe7ac16bf7224cba284a318695d8093355Steve Block return null; 468808751fe7ac16bf7224cba284a318695d8093355Steve Block } 469808751fe7ac16bf7224cba284a318695d8093355Steve Block 4708c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba return createCacheFile(url, statusCode, headers, mimeType, 0, 4718c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba forceCache); 4728c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba } 4738c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 4748c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba static CacheResult createCacheFile(String url, int statusCode, 4758c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba Headers headers, String mimeType, long postIdentifier, 4768c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba boolean forceCache) { 477808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 478808751fe7ac16bf7224cba284a318695d8093355Steve Block 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!forceCache && mDisabled) { 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4838c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba String databaseKey = getDatabaseKey(url, postIdentifier); 4848c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 485105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // according to the rfc 2616, the 303 response MUST NOT be cached. 486105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (statusCode == 303) { 4873afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba // remove the saved cache if there is any 4888c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba mDataBase.removeCache(databaseKey); 489105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return null; 490105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 491105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 492105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // like the other browsers, do not cache redirects containing a cookie 493105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // header. 49467ba204aa23e7d5a96ad241a1623e44976b51741Steve Block if (isCachableRedirect(statusCode) && !headers.getSetCookie().isEmpty()) { 4953afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba // remove the saved cache if there is any 4968c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba mDataBase.removeCache(databaseKey); 497105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return null; 498105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 499105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CacheResult ret = parseHeaders(statusCode, headers, mimeType); 5013afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba if (ret == null) { 5023afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba // this should only happen if the headers has "no-store" in the 5033afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba // cache-control. remove the saved cache if there is any 5048c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba mDataBase.removeCache(databaseKey); 5053afdd56470d6d4dcb20fe0f68ec9e54a167a9d74Grace Kloba } else { 5068c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba setupFiles(databaseKey, ret); 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.outStream = new FileOutputStream(ret.outFile); 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (FileNotFoundException e) { 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // This can happen with the system did a purge and our 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // subdirectory has gone, so lets try to create it again 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (createCacheDirectory()) { 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.outStream = new FileOutputStream(ret.outFile); 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (FileNotFoundException e2) { 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We failed to create the file again, so there 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // is something else wrong. Return null. 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Failed to create cache directory 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.mimeType = mimeType; 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Save the info of a cache file for a given url to the CacheMap so that it 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * can be reused later 534c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * 535c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick * @deprecated Access to the HTTP cache will be removed in a future release. 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 537c96235deb9f4d08285f3b1a2c28ea9f771b40f47Iain Merrick @Deprecated 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static void saveCacheFile(String url, CacheResult cacheRet) { 5398c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba saveCacheFile(url, 0, cacheRet); 5408c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba } 5418c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 5428c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba static void saveCacheFile(String url, long postIdentifier, 5438c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba CacheResult cacheRet) { 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.outStream.close(); 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 550808751fe7ac16bf7224cba284a318695d8093355Steve Block if (JniUtil.useChromiumHttpStack()) { 551e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // This method is exposed in the public API but the API provides no way to obtain a 552e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // new CacheResult object with a non-null output stream ... 553e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // - CacheResult objects returned by getCacheFile() have a null output stream. 554e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // - new CacheResult objects have a null output stream and no setter is provided. 555e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // Since for the Android HTTP stack this method throws a null pointer exception in this 556e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // case, this method is effectively useless from the point of view of the public API. 557e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block 558e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // We should already have thrown an exception above, to maintain 'backward 559e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block // compatibility' with the Android HTTP stack. 560e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block assert false; 561808751fe7ac16bf7224cba284a318695d8093355Steve Block } 562808751fe7ac16bf7224cba284a318695d8093355Steve Block 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!cacheRet.outFile.exists()) { 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the file in the cache directory can be removed by the system 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 56867ba204aa23e7d5a96ad241a1623e44976b51741Steve Block boolean redirect = isCachableRedirect(cacheRet.httpStatusCode); 569543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if (redirect) { 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // location is in database, no need to keep the file 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.contentLength = 0; 572686cf75d5cf447d34961f6217f2ea3ce3e484ac2Cary Clark cacheRet.localPath = ""; 573543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark } 574543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if ((redirect || cacheRet.contentLength == 0) 575543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark && !cacheRet.outFile.delete()) { 576543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark Log.e(LOGTAG, cacheRet.outFile.getPath() + " delete failed."); 577543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark } 578543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if (cacheRet.contentLength == 0) { 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5828c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba mDataBase.addCache(getDatabaseKey(url, postIdentifier), cacheRet); 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5842e5c150e746647a1ce5c10e1708debbf06c45ea7Derek Sollenberger if (DebugFlags.CACHE_MANAGER) { 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(LOGTAG, "saveCacheFile for url " + url); 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 589998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba static boolean cleanupCacheFile(CacheResult cacheRet) { 590808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 591808751fe7ac16bf7224cba284a318695d8093355Steve Block 592998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba try { 593998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba cacheRet.outStream.close(); 594998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba } catch (IOException e) { 595998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba return false; 596998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba } 597998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba return cacheRet.outFile.delete(); 598998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba } 599998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 60167ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * Remove all cache files. 60267ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * 60367ba204aa23e7d5a96ad241a1623e44976b51741Steve Block * @return Whether the removal succeeded. 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static boolean removeAllCacheFiles() { 606808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 607808751fe7ac16bf7224cba284a318695d8093355Steve Block 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Note, this is called before init() when the database is 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // created or upgraded. 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mBaseDir == null) { 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Init() has not been called yet, so just flag that 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we need to clear the cache when init() is called. 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mClearCacheOnInit = true; 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6162036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // delete rows in the cache database 617cedb3a7e5849fd16e939add1ac6f5586467b8c68Kristian Monsen if (!JniUtil.useChromiumHttpStack()) 618cedb3a7e5849fd16e939add1ac6f5586467b8c68Kristian Monsen WebViewWorker.getHandler().sendEmptyMessage(WebViewWorker.MSG_CLEAR_CACHE); 619cedb3a7e5849fd16e939add1ac6f5586467b8c68Kristian Monsen 6202036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // delete cache files in a separate thread to not block UI. 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final Runnable clearCache = new Runnable() { 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // delete all cache files 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] files = mBaseDir.list(); 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if mBaseDir doesn't exist, files can be null. 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (files != null) { 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < files.length; i++) { 629543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark File f = new File(mBaseDir, files[i]); 630543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if (!f.delete()) { 631543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark Log.e(LOGTAG, f.getPath() + " delete failed."); 632543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark } 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SecurityException e) { 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Ignore SecurityExceptions. 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new Thread(clearCache).start(); 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static void trimCacheIfNeeded() { 645808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 646808751fe7ac16bf7224cba284a318695d8093355Steve Block 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mDataBase.getCacheTotalSize() > CACHE_THRESHOLD) { 6482036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba List<String> pathList = mDataBase.trimCache(CACHE_TRIM_AMOUNT); 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = pathList.size(); 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 651543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark File f = new File(mBaseDir, pathList.get(i)); 652543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark if (!f.delete()) { 653543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark Log.e(LOGTAG, f.getPath() + " delete failed."); 654543221fc4b9dd16db2c687cd59f1eeea8d89c5a5Cary Clark } 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6562036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // remove the unreferenced files in the cache directory 6572036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba final List<String> fileList = mDataBase.getAllCacheFileNames(); 6582036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba if (fileList == null) return; 6592036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba String[] toDelete = mBaseDir.list(new FilenameFilter() { 6602036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba public boolean accept(File dir, String filename) { 6612036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba if (fileList.contains(filename)) { 6622036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba return false; 6632036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } else { 6642036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba return true; 6652036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 6662036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 6672036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba }); 6682036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba if (toDelete == null) return; 6692036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba size = toDelete.length; 6702036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba for (int i = 0; i < size; i++) { 6712036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba File f = new File(mBaseDir, toDelete[i]); 6722036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba if (!f.delete()) { 6732036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba Log.e(LOGTAG, f.getPath() + " delete failed."); 6742036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 6752036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6792036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba static void clearCache() { 680808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 681808751fe7ac16bf7224cba284a318695d8093355Steve Block 6822036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba // delete database 6832036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba mDataBase.clearCache(); 6842036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba } 6852036dbab1726c34953360a7a56d6b9ef1f2aa7ddGrace Kloba 68667ba204aa23e7d5a96ad241a1623e44976b51741Steve Block private static boolean isCachableRedirect(int statusCode) { 687105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project if (statusCode == 301 || statusCode == 302 || statusCode == 307) { 688105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project // as 303 can't be cached, we do not return true 689105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return true; 690105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } else { 691105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project return false; 692105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 693105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project } 694105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project 6958c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba private static String getDatabaseKey(String url, long postIdentifier) { 696808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 697808751fe7ac16bf7224cba284a318695d8093355Steve Block 6988c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba if (postIdentifier == 0) return url; 6998c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba return postIdentifier + url; 7008c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba } 7018c92c39b858ae73a1b08ed698887efa98ced987cGrace Kloba 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("deprecation") 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void setupFiles(String url, CacheResult cacheRet) { 704808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 705808751fe7ac16bf7224cba284a318695d8093355Steve Block 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (true) { 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Note: SHA1 is much stronger hash. But the cost of setupFiles() is 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // 3.2% cpu time for a fresh load of nytimes.com. While a simple 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // String.hashCode() is only 0.6%. If adding the collision resolving 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to String.hashCode(), it makes the cpu time to be 1.6% for a 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // fresh load, but 5.3% for the worst case where all the files 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // already exist in the file system, but database is gone. So it 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // needs to resolve collision for every file at least once. 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int hashCode = url.hashCode(); 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuffer ret = new StringBuffer(8); 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project appendAsHex(hashCode, ret); 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String path = ret.toString(); 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File file = new File(mBaseDir, path); 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (true) { 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean checkOldPath = true; 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check hash collision. If the hash file doesn't exist, just 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // continue. There is a chance that the old cache file is not 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // same as the hash file. As mDataBase.getCache() is more 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // expansive than "leak" a file until clear cache, don't bother. 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the hash file exists, make sure that it is same as the 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // cache file. If it is not, resolve the collision. 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (file.exists()) { 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (checkOldPath) { 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CacheResult oldResult = mDataBase.getCache(url); 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (oldResult != null && oldResult.contentLength > 0) { 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path.equals(oldResult.localPath)) { 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = oldResult.localPath; 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = oldResult.localPath; 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project file = new File(mBaseDir, path); 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project checkOldPath = false; 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret = new StringBuffer(8); 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project appendAsHex(++hashCode, ret); 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path = ret.toString(); 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project file = new File(mBaseDir, path); 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.localPath = path; 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.outFile = file; 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // get hash in byte[] 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Digest digest = new SHA1Digest(); 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int digestLen = digest.getDigestSize(); 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] hash = new byte[digestLen]; 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int urlLen = url.length(); 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project byte[] data = new byte[urlLen]; 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project url.getBytes(0, urlLen, data, 0); 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project digest.update(data, 0, urlLen); 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project digest.doFinal(hash, 0); 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // convert byte[] to hex String 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StringBuffer result = new StringBuffer(2 * digestLen); 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < digestLen; i = i + 4) { 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int h = (0x00ff & hash[i]) << 24 | (0x00ff & hash[i + 1]) << 16 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project | (0x00ff & hash[i + 2]) << 8 | (0x00ff & hash[i + 3]); 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project appendAsHex(h, result); 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.localPath = result.toString(); 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cacheRet.outFile = new File(mBaseDir, cacheRet.localPath); 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static void appendAsHex(int i, StringBuffer ret) { 772808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 773808751fe7ac16bf7224cba284a318695d8093355Steve Block 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String hex = Integer.toHexString(i); 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (hex.length()) { 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 1: 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("0000000"); 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 2: 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("000000"); 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 3: 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("00000"); 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 4: 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("0000"); 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 5: 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("000"); 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 6: 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("00"); 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 7: 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append("0"); 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.append(hex); 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static CacheResult parseHeaders(int statusCode, Headers headers, 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String mimeType) { 803808751fe7ac16bf7224cba284a318695d8093355Steve Block assert !JniUtil.useChromiumHttpStack(); 804808751fe7ac16bf7224cba284a318695d8093355Steve Block 805998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba // if the contentLength is already larger than CACHE_MAX_SIZE, skip it 806998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba if (headers.getContentLength() > CACHE_MAX_SIZE) return null; 807998c05b3b5db124a31da1ac38af0e97bca114122Grace Kloba 808a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // The HTML 5 spec, section 6.9.4, step 7.3 of the application cache 809a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // process states that HTTP caching rules are ignored for the 810a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // purposes of the application cache download process. 811a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // At this point we can't tell that if a file is part of this process, 812a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // except for the manifest, which has its own mimeType. 813a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // TODO: work out a way to distinguish all responses that are part of 814a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu // the application download process and skip them. 815a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu if (MANIFEST_MIME.equals(mimeType)) return null; 816a1ba11bd78f9540e58516dd742fe4cc8726e262fAndrei Popescu 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: if authenticated or secure, return null 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CacheResult ret = new CacheResult(); 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.httpStatusCode = statusCode; 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8217a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block ret.location = headers.getLocation(); 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = -1; 824e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba ret.expiresString = headers.getExpires(); 825e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba if (ret.expiresString != null) { 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 8277cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson ret.expires = AndroidHttpClient.parseDate(ret.expiresString); 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalArgumentException ex) { 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Take care of the special "-1" and "0" cases 830e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba if ("-1".equals(ret.expiresString) 831e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba || "0".equals(ret.expiresString)) { 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // make it expired, but can be used for history navigation 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 835e64c5567de20d06ac7ed1f5a01f018991cd40a52Grace Kloba Log.e(LOGTAG, "illegal expires: " + ret.expiresString); 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8407a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block ret.contentdisposition = headers.getContentDisposition(); 8410b956e1353a691674cb22c899c5a444b92532b60Grace Kloba 8427a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block ret.crossDomain = headers.getXPermittedCrossDomainPolicies(); 84360708a75120c4469dc2683485301ff9ee3b022e0Leon Clarke 8447865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba // lastModified and etag may be set back to http header. So they can't 8457865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba // be empty string. 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String lastModified = headers.getLastModified(); 8477865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba if (lastModified != null && lastModified.length() > 0) { 8487865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba ret.lastModified = lastModified; 8497865fa97244d2f33d2a9c9ec359b475d6597e994Grace Kloba } 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String etag = headers.getEtag(); 8527a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block if (etag != null && etag.length() > 0) { 8537a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block ret.etag = etag; 8547a1121511d8b587a3ab9fc971c0e85cef38f3f81Steve Block } 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String cacheControl = headers.getCacheControl(); 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cacheControl != null) { 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] controls = cacheControl.toLowerCase().split("[ ,;]"); 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < controls.length; i++) { 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NO_STORE.equals(controls[i])) { 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // According to the spec, 'no-cache' means that the content 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // must be re-validated on every load. It does not mean that 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the content can not be cached. set to expire 0 means it 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // can only be used in CACHE_MODE_CACHE_ONLY case 86752cf58a2a47e4dc975314fab44783c7e4654ca6dGrace Kloba if (NO_CACHE.equals(controls[i])) { 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (controls[i].startsWith(MAX_AGE)) { 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int separator = controls[i].indexOf('='); 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (separator < 0) { 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project separator = controls[i].indexOf(':'); 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (separator > 0) { 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String s = controls[i].substring(separator + 1); 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long sec = Long.parseLong(s); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sec >= 0) { 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = System.currentTimeMillis() + 1000 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sec; 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (NumberFormatException ex) { 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ("1d".equals(s)) { 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Take care of the special "1d" case 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = System.currentTimeMillis() + 86400000; // 24*60*60*1000 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(LOGTAG, "exception in parseHeaders for " 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "max-age:" 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + controls[i].substring(separator + 1)); 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // According to RFC 2616 section 14.32: 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // HTTP/1.1 caches SHOULD treat "Pragma: no-cache" as if the 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // client had sent "Cache-Control: no-cache" 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (NO_CACHE.equals(headers.getPragma())) { 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // According to RFC 2616 section 13.2.4, if an expiration has not been 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // explicitly defined a heuristic to set an expiration may be used. 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ret.expires == -1) { 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ret.httpStatusCode == 301) { 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If it is a permanent redirect, and it did not have an 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // explicit cache directive, then it never expires 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = Long.MAX_VALUE; 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (ret.httpStatusCode == 302 || ret.httpStatusCode == 307) { 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If it is temporary redirect, expires 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (ret.lastModified == null) { 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // When we have no last-modified, then expire the content with 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in 24hrs as, according to the RFC, longer time requires a 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // warning 113 to be added to the response. 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Only add the default expiration for non-html markup. Some 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // sites like news.google.com have no cache directives. 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mimeType.startsWith("text/html")) { 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = System.currentTimeMillis() + 86400000; // 24*60*60*1000 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Setting a expires as zero will cache the result for 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // forward/back nav. 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = 0; 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If we have a last-modified value, we could use it to set the 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // expiration. Suggestion from RFC is 10% of time since 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // last-modified. As we are on mobile, loads are expensive, 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // increasing this to 20%. 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // 24 * 60 * 60 * 1000 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long lastmod = System.currentTimeMillis() + 86400000; 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 9387cfa90fee54f44831ac492891d1c123601c2a262Jesse Wilson lastmod = AndroidHttpClient.parseDate(ret.lastModified); 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalArgumentException ex) { 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(LOGTAG, "illegal lastModified: " + ret.lastModified); 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long difference = System.currentTimeMillis() - lastmod; 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (difference > 0) { 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = System.currentTimeMillis() + difference / 5; 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // last modified is in the future, expire the content 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // on the last modified 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ret.expires = lastmod; 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ret; 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 955e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block 956e8492473a94e827b9a73f1fa4f5741e85c0e832cSteve Block private static native CacheResult nativeGetCacheResult(String url); 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 958