CacheManager.java revision f2bfe2bc05322a754c5a5d4e16ca182303ca72aa
1/* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.webkit; 18 19import android.content.Context; 20import android.net.http.Headers; 21import android.util.Log; 22 23import java.io.File; 24import java.io.FileInputStream; 25import java.io.FileNotFoundException; 26import java.io.IOException; 27import java.io.InputStream; 28import java.io.OutputStream; 29import java.util.Map; 30 31 32/** 33 * Manages the HTTP cache used by an application's {@link WebView} instances. 34 * @deprecated Access to the HTTP cache will be removed in a future release. 35 */ 36// The class CacheManager provides the persistent cache of content that is 37// received over the network. The component handles parsing of HTTP headers and 38// utilizes the relevant cache headers to determine if the content should be 39// stored and if so, how long it is valid for. Network requests are provided to 40// this component and if they can not be resolved by the cache, the HTTP headers 41// are attached, as appropriate, to the request for revalidation of content. The 42// class also manages the cache size. 43// 44// CacheManager may only be used if your activity contains a WebView. 45@Deprecated 46public final class CacheManager { 47 48 private static final String LOGTAG = "cache"; 49 50 static final String HEADER_KEY_IFMODIFIEDSINCE = "if-modified-since"; 51 static final String HEADER_KEY_IFNONEMATCH = "if-none-match"; 52 53 private static File mBaseDir; 54 55 /** 56 * Represents a resource stored in the HTTP cache. Instances of this class 57 * can be obtained by calling 58 * {@link CacheManager#getCacheFile CacheManager.getCacheFile(String, Map<String, String>))}. 59 * @deprecated Access to the HTTP cache will be removed in a future release. 60 */ 61 @Deprecated 62 public static class CacheResult { 63 // these fields are saved to the database 64 int httpStatusCode; 65 long contentLength; 66 long expires; 67 String expiresString; 68 String localPath; 69 String lastModified; 70 String etag; 71 String mimeType; 72 String location; 73 String encoding; 74 String contentdisposition; 75 String crossDomain; 76 77 // these fields are NOT saved to the database 78 InputStream inStream; 79 OutputStream outStream; 80 File outFile; 81 82 /** 83 * Gets the status code of this cache entry. 84 * @return The status code of this cache entry 85 */ 86 public int getHttpStatusCode() { 87 return httpStatusCode; 88 } 89 90 /** 91 * Gets the content length of this cache entry. 92 * @return The content length of this cache entry 93 */ 94 public long getContentLength() { 95 return contentLength; 96 } 97 98 /** 99 * Gets the path of the file used to store the content of this cache 100 * entry, relative to the base directory of the cache. See 101 * {@link CacheManager#getCacheFileBaseDir CacheManager.getCacheFileBaseDir()}. 102 * @return The path of the file used to store this cache entry 103 */ 104 public String getLocalPath() { 105 return localPath; 106 } 107 108 /** 109 * Gets the expiry date of this cache entry, expressed in milliseconds 110 * since midnight, January 1, 1970 UTC. 111 * @return The expiry date of this cache entry 112 */ 113 public long getExpires() { 114 return expires; 115 } 116 117 /** 118 * Gets the expiry date of this cache entry, expressed as a string. 119 * @return The expiry date of this cache entry 120 * 121 */ 122 public String getExpiresString() { 123 return expiresString; 124 } 125 126 /** 127 * Gets the date at which this cache entry was last modified, expressed 128 * as a string. 129 * @return The date at which this cache entry was last modified 130 */ 131 public String getLastModified() { 132 return lastModified; 133 } 134 135 /** 136 * Gets the entity tag of this cache entry. 137 * @return The entity tag of this cache entry 138 */ 139 public String getETag() { 140 return etag; 141 } 142 143 /** 144 * Gets the MIME type of this cache entry. 145 * @return The MIME type of this cache entry 146 */ 147 public String getMimeType() { 148 return mimeType; 149 } 150 151 /** 152 * Gets the value of the HTTP 'Location' header with which this cache 153 * entry was received. 154 * @return The HTTP 'Location' header for this cache entry 155 */ 156 public String getLocation() { 157 return location; 158 } 159 160 /** 161 * Gets the encoding of this cache entry. 162 * @return The encoding of this cache entry 163 */ 164 public String getEncoding() { 165 return encoding; 166 } 167 168 /** 169 * Gets the value of the HTTP 'Content-Disposition' header with which 170 * this cache entry was received. 171 * @return The HTTP 'Content-Disposition' header for this cache entry 172 * 173 */ 174 public String getContentDisposition() { 175 return contentdisposition; 176 } 177 178 /** 179 * Gets the input stream to the content of this cache entry, to allow 180 * content to be read. See 181 * {@link CacheManager#getCacheFile CacheManager.getCacheFile(String, Map<String, String>)}. 182 * @return An input stream to the content of this cache entry 183 */ 184 public InputStream getInputStream() { 185 return inStream; 186 } 187 188 /** 189 * Gets an output stream to the content of this cache entry, to allow 190 * content to be written. See 191 * {@link CacheManager#saveCacheFile CacheManager.saveCacheFile(String, CacheResult)}. 192 * @return An output stream to the content of this cache entry 193 */ 194 // Note that this is always null for objects returned by getCacheFile()! 195 public OutputStream getOutputStream() { 196 return outStream; 197 } 198 199 200 /** 201 * Sets an input stream to the content of this cache entry. 202 * @param stream An input stream to the content of this cache entry 203 */ 204 public void setInputStream(InputStream stream) { 205 this.inStream = stream; 206 } 207 208 /** 209 * Sets the encoding of this cache entry. 210 * @param encoding The encoding of this cache entry 211 */ 212 public void setEncoding(String encoding) { 213 this.encoding = encoding; 214 } 215 216 /** 217 * @hide 218 */ 219 public void setContentLength(long contentLength) { 220 this.contentLength = contentLength; 221 } 222 } 223 224 /** 225 * Initializes the HTTP cache. This method must be called before any 226 * CacheManager methods are used. Note that this is called automatically 227 * when a {@link WebView} is created. 228 * @param context The application context 229 */ 230 static void init(Context context) { 231 // This isn't actually where the real cache lives, but where we put files for the 232 // purpose of getCacheFile(). 233 mBaseDir = new File(context.getCacheDir(), "webviewCacheChromiumStaging"); 234 if (!mBaseDir.exists()) { 235 mBaseDir.mkdirs(); 236 } 237 } 238 239 /** 240 * Gets the base directory in which the files used to store the contents of 241 * cache entries are placed. See 242 * {@link CacheManager.CacheResult#getLocalPath CacheManager.CacheResult.getLocalPath()}. 243 * @return The base directory of the cache 244 * @deprecated Access to the HTTP cache will be removed in a future release. 245 */ 246 @Deprecated 247 public static File getCacheFileBaseDir() { 248 return mBaseDir; 249 } 250 251 /** 252 * Gets whether the HTTP cache is disabled. 253 * @return True if the HTTP cache is disabled 254 * @deprecated Access to the HTTP cache will be removed in a future release. 255 */ 256 @Deprecated 257 public static boolean cacheDisabled() { 258 return false; 259 } 260 261 /** 262 * Starts a cache transaction. Returns true if this is the only running 263 * transaction. Otherwise, this transaction is nested inside currently 264 * running transactions and false is returned. 265 * @return True if this is the only running transaction 266 * @deprecated This method no longer has any effect and always returns false 267 */ 268 @Deprecated 269 public static boolean startCacheTransaction() { 270 return false; 271 } 272 273 /** 274 * Ends the innermost cache transaction and returns whether this was the 275 * only running transaction. 276 * @return True if this was the only running transaction 277 * @deprecated This method no longer has any effect and always returns false 278 */ 279 @Deprecated 280 public static boolean endCacheTransaction() { 281 return false; 282 } 283 284 /** 285 * Gets the cache entry for the specified URL, or null if none is found. 286 * If a non-null value is provided for the HTTP headers map, and the cache 287 * entry needs validation, appropriate headers will be added to the map. 288 * The input stream of the CacheEntry object should be closed by the caller 289 * when access to the underlying file is no longer required. 290 * @param url The URL for which a cache entry is requested 291 * @param headers A map from HTTP header name to value, to be populated 292 * for the returned cache entry 293 * @return The cache entry for the specified URL 294 * @deprecated Access to the HTTP cache will be removed in a future release. 295 */ 296 @Deprecated 297 public static CacheResult getCacheFile(String url, 298 Map<String, String> headers) { 299 return getCacheFile(url, 0, headers); 300 } 301 302 static CacheResult getCacheFile(String url, long postIdentifier, 303 Map<String, String> headers) { 304 CacheResult result = nativeGetCacheResult(url); 305 if (result == null) { 306 return null; 307 } 308 // A temporary local file will have been created native side and localPath set 309 // appropriately. 310 File src = new File(mBaseDir, result.localPath); 311 try { 312 // Open the file here so that even if it is deleted, the content 313 // is still readable by the caller until close() is called. 314 result.inStream = new FileInputStream(src); 315 } catch (FileNotFoundException e) { 316 Log.v(LOGTAG, "getCacheFile(): Failed to open file: " + e); 317 // TODO: The files in the cache directory can be removed by the 318 // system. If it is gone, what should we do? 319 return null; 320 } 321 322 // A null value for headers is used by CACHE_MODE_CACHE_ONLY to imply 323 // that we should provide the cache result even if it is expired. 324 // Note that a negative expires value means a time in the far future. 325 if (headers != null && result.expires >= 0 326 && result.expires <= System.currentTimeMillis()) { 327 if (result.lastModified == null && result.etag == null) { 328 return null; 329 } 330 // Return HEADER_KEY_IFNONEMATCH or HEADER_KEY_IFMODIFIEDSINCE 331 // for requesting validation. 332 if (result.etag != null) { 333 headers.put(HEADER_KEY_IFNONEMATCH, result.etag); 334 } 335 if (result.lastModified != null) { 336 headers.put(HEADER_KEY_IFMODIFIEDSINCE, result.lastModified); 337 } 338 } 339 340 if (DebugFlags.CACHE_MANAGER) { 341 Log.v(LOGTAG, "getCacheFile for url " + url); 342 } 343 344 return result; 345 } 346 347 /** 348 * Given a url and its full headers, returns CacheResult if a local cache 349 * can be stored. Otherwise returns null. The mimetype is passed in so that 350 * the function can use the mimetype that will be passed to WebCore which 351 * could be different from the mimetype defined in the headers. 352 * forceCache is for out-of-package callers to force creation of a 353 * CacheResult, and is used to supply surrogate responses for URL 354 * interception. 355 * @return CacheResult for a given url 356 */ 357 static CacheResult createCacheFile(String url, int statusCode, 358 Headers headers, String mimeType, boolean forceCache) { 359 // This method is public but hidden. We break functionality. 360 return null; 361 } 362 363 /** 364 * Adds a cache entry to the HTTP cache for the specicifed URL. Also closes 365 * the cache entry's output stream. 366 * @param url The URL for which the cache entry should be added 367 * @param cacheResult The cache entry to add 368 * @deprecated Access to the HTTP cache will be removed in a future release. 369 */ 370 @Deprecated 371 public static void saveCacheFile(String url, CacheResult cacheResult) { 372 saveCacheFile(url, 0, cacheResult); 373 } 374 375 static void saveCacheFile(String url, long postIdentifier, 376 CacheResult cacheRet) { 377 try { 378 cacheRet.outStream.close(); 379 } catch (IOException e) { 380 return; 381 } 382 383 // This method is exposed in the public API but the API provides no 384 // way to obtain a new CacheResult object with a non-null output 385 // stream ... 386 // - CacheResult objects returned by getCacheFile() have a null 387 // output stream. 388 // - new CacheResult objects have a null output stream and no 389 // setter is provided. 390 // Since this method throws a null pointer exception in this case, 391 // it is effectively useless from the point of view of the public 392 // API. 393 // 394 // With the Chromium HTTP stack we continue to throw the same 395 // exception for 'backwards compatibility' with the Android HTTP 396 // stack. 397 // 398 // This method is not used from within this package, and for public API 399 // use, we should already have thrown an exception above. 400 assert false; 401 } 402 403 /** 404 * Remove all cache files. 405 * 406 * @return Whether the removal succeeded. 407 */ 408 static boolean removeAllCacheFiles() { 409 // delete cache files in a separate thread to not block UI. 410 final Runnable clearCache = new Runnable() { 411 public void run() { 412 // delete all cache files 413 try { 414 String[] files = mBaseDir.list(); 415 // if mBaseDir doesn't exist, files can be null. 416 if (files != null) { 417 for (int i = 0; i < files.length; i++) { 418 File f = new File(mBaseDir, files[i]); 419 if (!f.delete()) { 420 Log.e(LOGTAG, f.getPath() + " delete failed."); 421 } 422 } 423 } 424 } catch (SecurityException e) { 425 // Ignore SecurityExceptions. 426 } 427 } 428 }; 429 new Thread(clearCache).start(); 430 return true; 431 } 432 433 private static native CacheResult nativeGetCacheResult(String url); 434} 435