1bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block/*
2bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * Copyright 2011, The Android Open Source Project
3bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block *
4bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * Redistribution and use in source and binary forms, with or without
5bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * modification, are permitted provided that the following conditions
6bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * are met:
7bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block *  * Redistributions of source code must retain the above copyright
8bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block *    notice, this list of conditions and the following disclaimer.
9bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block *  * Redistributions in binary form must reproduce the above copyright
10bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block *    notice, this list of conditions and the following disclaimer in the
11bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block *    documentation and/or other materials provided with the distribution.
12bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block *
13bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block */
25bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
26bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#include "config.h"
27bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
28bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#include "ChromiumIncludes.h"
29bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#include "WebCache.h"
30bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#include "WebCoreJni.h"
31bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
32bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#include <JNIHelp.h>
33bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#include <platform/FileSystem.h>
34bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#include <platform/text/Base64.h>
35bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#include <wtf/text/CString.h>
36bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#include <wtf/text/WTFString.h>
37bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
38bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockusing namespace WebCore;
39bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockusing namespace base;
40bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockusing namespace disk_cache;
41bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockusing namespace net;
42bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockusing namespace std;
43bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
44bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blocknamespace android {
45bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
46bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block// JNI for android.webkit.CacheManager
47bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockstatic const char* javaCacheManagerClass = "android/webkit/CacheManager";
48bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
49bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockstatic void setStringField(JNIEnv* env, const jobject& object, const jfieldID& field, const String& str)
50bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block{
51bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jstring jstr = wtfStringToJstring(env, str);
52bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    env->SetObjectField(object, field, jstr);
53bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    env->DeleteLocalRef(jstr);
54bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block}
55bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
56bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockstatic void setFieldFromHeaderIfPresent(CacheResult* result, const char* header, JNIEnv* env, const jobject& object, const jfieldID& field, bool allowEmptyString)
57bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block{
58bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block  String value;
59bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block  if (result->firstResponseHeader(header, &value, allowEmptyString))
60bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block      setStringField(env, object, field, value);
61bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block}
62bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
63bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockstatic String getCacheFileBaseDir(JNIEnv* env)
64bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block{
65bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    static String baseDir;
66bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    if (baseDir.isEmpty()) {
67bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block        jclass cacheManagerClass = env->FindClass("android/webkit/CacheManager");
68bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block        jmethodID getCacheFileBaseDirMethod = env->GetStaticMethodID(cacheManagerClass, "getCacheFileBaseDir", "()Ljava/io/File;");
69bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block        jclass fileClass = env->FindClass("java/io/File");
70bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block        jmethodID getPathMethod = env->GetMethodID(fileClass, "getPath", "()Ljava/lang/String;");
71bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block        jobject fileObject = env->CallStaticObjectMethod(cacheManagerClass, getCacheFileBaseDirMethod);
72bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block        baseDir = jstringToWtfString(env, static_cast<jstring>(env->CallObjectMethod(fileObject, getPathMethod)));
73bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    }
74bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    return baseDir;
75bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block}
76bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
77bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockstatic jobject getCacheResult(JNIEnv* env, jobject, jstring url)
78bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block{
79bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    // This is called on the UI thread.
80bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    scoped_refptr<CacheResult> result = WebCache::get(false /*privateBrowsing*/)->getCacheResult(jstringToWtfString(env, url));
81bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    if (!result)
82bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block        return 0;
83bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
84bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    // We create and populate a file with the cache entry. This allows us to
85bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    // replicate the behaviour of the Android HTTP stack in the Java
86bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    // CacheManager, which opens the cache file and provides an input stream to
87bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    // the file as part of the Java CacheResult object!
88bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    String urlWtfString = jstringToWtfString(env, url);
89bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    Vector<char> encodedUrl;
90bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    base64Encode(urlWtfString.utf8().data(), urlWtfString.length(), encodedUrl, false /*insertLFs*/);
918d55fa6a7b44dd646774f089c2b88697d9d56096Ben Murdoch    encodedUrl.append('\0');
92bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    String filePath = pathByAppendingComponent(getCacheFileBaseDir(env), encodedUrl.data());
93bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    if (!result->writeToFile(filePath))
94bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block        return 0;
95bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
96bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jclass cacheResultClass = env->FindClass("android/webkit/CacheManager$CacheResult");
97bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jmethodID constructor = env->GetMethodID(cacheResultClass, "<init>", "()V");
98bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    // We only bother with the fields that are made accessible through the public API.
99bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID contentdispositionField = env->GetFieldID(cacheResultClass, "contentdisposition", "Ljava/lang/String;");
100bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID contentLengthField = env->GetFieldID(cacheResultClass, "contentLength", "J");
101bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID etagField = env->GetFieldID(cacheResultClass, "etag", "Ljava/lang/String;");
102bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID encodingField = env->GetFieldID(cacheResultClass, "encoding", "Ljava/lang/String;");
103bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID expiresField = env->GetFieldID(cacheResultClass, "expires", "J");
104bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID expiresStringField = env->GetFieldID(cacheResultClass, "expiresString", "Ljava/lang/String;");
105bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID httpStatusCodeField = env->GetFieldID(cacheResultClass, "httpStatusCode", "I");
106bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID lastModifiedField = env->GetFieldID(cacheResultClass, "lastModified", "Ljava/lang/String;");
107bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID localPathField = env->GetFieldID(cacheResultClass, "localPath", "Ljava/lang/String;");
108bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID locationField = env->GetFieldID(cacheResultClass, "location", "Ljava/lang/String;");
109bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jfieldID mimeTypeField = env->GetFieldID(cacheResultClass, "mimeType", "Ljava/lang/String;");
110bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
111bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jobject javaResult = env->NewObject(cacheResultClass, constructor);
112bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    setFieldFromHeaderIfPresent(result.get(), "content-disposition", env, javaResult, contentdispositionField, true);
113bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    env->SetLongField(javaResult, contentLengthField, result->contentSize());
114bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    setFieldFromHeaderIfPresent(result.get(), "etag", env, javaResult, etagField, false);
115bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    setStringField(env, javaResult, encodingField, "TODO"); // TODO: Where does the Android stack set this?
116bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    env->SetLongField(javaResult, expiresField, result->expires());
117bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    env->SetIntField(javaResult, httpStatusCodeField, result->responseCode());
118bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    setFieldFromHeaderIfPresent(result.get(), "last-modified", env, javaResult, lastModifiedField, false);
119bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    setStringField(env, javaResult, localPathField, encodedUrl.data());
120bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    setFieldFromHeaderIfPresent(result.get(), "location", env, javaResult, locationField, false);
121bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    setStringField(env, javaResult, mimeTypeField, result->mimeType());
122bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
123bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    return javaResult;
124bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block}
125bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
126bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockstatic JNINativeMethod gCacheManagerMethods[] = {
127bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    { "nativeGetCacheResult", "(Ljava/lang/String;)Landroid/webkit/CacheManager$CacheResult;", (void*) getCacheResult },
128bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block};
129bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
130bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Blockint registerCacheManager(JNIEnv* env)
131bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block{
132bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#ifndef NDEBUG
133bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    jclass cacheManager = env->FindClass(javaCacheManagerClass);
1346dd76b804786ec760bb04b137a6bf017064226dcSteve Block    ALOG_ASSERT(cacheManager, "Unable to find class");
135bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    env->DeleteLocalRef(cacheManager);
136bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block#endif
137bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block    return jniRegisterNativeMethods(env, javaCacheManagerClass, gCacheManagerMethods, NELEM(gCacheManagerMethods));
138bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block}
139bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block
140bf16cf132cbd54cc70f003ec6f7500e3dd39dbbbSteve Block} // namespace android
141