| /* |
| * Copyright 2011, The Android Open Source Project |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| |
| #include "ChromiumIncludes.h" |
| #include "WebCache.h" |
| #include "WebCoreJni.h" |
| |
| #include <JNIHelp.h> |
| #include <platform/FileSystem.h> |
| #include <platform/text/Base64.h> |
| #include <wtf/text/CString.h> |
| #include <wtf/text/WTFString.h> |
| |
| using namespace WebCore; |
| using namespace base; |
| using namespace disk_cache; |
| using namespace net; |
| using namespace std; |
| |
| namespace android { |
| |
| // JNI for android.webkit.CacheManager |
| static const char* javaCacheManagerClass = "android/webkit/CacheManager"; |
| |
| static void setStringField(JNIEnv* env, const jobject& object, const jfieldID& field, const String& str) |
| { |
| jstring jstr = wtfStringToJstring(env, str); |
| env->SetObjectField(object, field, jstr); |
| env->DeleteLocalRef(jstr); |
| } |
| |
| static void setFieldFromHeaderIfPresent(CacheResult* result, const char* header, JNIEnv* env, const jobject& object, const jfieldID& field, bool allowEmptyString) |
| { |
| String value; |
| if (result->firstResponseHeader(header, &value, allowEmptyString)) |
| setStringField(env, object, field, value); |
| } |
| |
| static String getCacheFileBaseDir(JNIEnv* env) |
| { |
| static String baseDir; |
| if (baseDir.isEmpty()) { |
| jclass cacheManagerClass = env->FindClass("android/webkit/CacheManager"); |
| jmethodID getCacheFileBaseDirMethod = env->GetStaticMethodID(cacheManagerClass, "getCacheFileBaseDir", "()Ljava/io/File;"); |
| jclass fileClass = env->FindClass("java/io/File"); |
| jmethodID getPathMethod = env->GetMethodID(fileClass, "getPath", "()Ljava/lang/String;"); |
| jobject fileObject = env->CallStaticObjectMethod(cacheManagerClass, getCacheFileBaseDirMethod); |
| baseDir = jstringToWtfString(env, static_cast<jstring>(env->CallObjectMethod(fileObject, getPathMethod))); |
| } |
| return baseDir; |
| } |
| |
| static jobject getCacheResult(JNIEnv* env, jobject, jstring url) |
| { |
| // This is called on the UI thread. |
| scoped_refptr<CacheResult> result = WebCache::get(false /*privateBrowsing*/)->getCacheResult(jstringToWtfString(env, url)); |
| if (!result) |
| return 0; |
| |
| // We create and populate a file with the cache entry. This allows us to |
| // replicate the behaviour of the Android HTTP stack in the Java |
| // CacheManager, which opens the cache file and provides an input stream to |
| // the file as part of the Java CacheResult object! |
| String urlWtfString = jstringToWtfString(env, url); |
| Vector<char> encodedUrl; |
| base64Encode(urlWtfString.utf8().data(), urlWtfString.length(), encodedUrl, false /*insertLFs*/); |
| encodedUrl.append('\0'); |
| String filePath = pathByAppendingComponent(getCacheFileBaseDir(env), encodedUrl.data()); |
| if (!result->writeToFile(filePath)) |
| return 0; |
| |
| jclass cacheResultClass = env->FindClass("android/webkit/CacheManager$CacheResult"); |
| jmethodID constructor = env->GetMethodID(cacheResultClass, "<init>", "()V"); |
| // We only bother with the fields that are made accessible through the public API. |
| jfieldID contentdispositionField = env->GetFieldID(cacheResultClass, "contentdisposition", "Ljava/lang/String;"); |
| jfieldID contentLengthField = env->GetFieldID(cacheResultClass, "contentLength", "J"); |
| jfieldID etagField = env->GetFieldID(cacheResultClass, "etag", "Ljava/lang/String;"); |
| jfieldID encodingField = env->GetFieldID(cacheResultClass, "encoding", "Ljava/lang/String;"); |
| jfieldID expiresField = env->GetFieldID(cacheResultClass, "expires", "J"); |
| jfieldID expiresStringField = env->GetFieldID(cacheResultClass, "expiresString", "Ljava/lang/String;"); |
| jfieldID httpStatusCodeField = env->GetFieldID(cacheResultClass, "httpStatusCode", "I"); |
| jfieldID lastModifiedField = env->GetFieldID(cacheResultClass, "lastModified", "Ljava/lang/String;"); |
| jfieldID localPathField = env->GetFieldID(cacheResultClass, "localPath", "Ljava/lang/String;"); |
| jfieldID locationField = env->GetFieldID(cacheResultClass, "location", "Ljava/lang/String;"); |
| jfieldID mimeTypeField = env->GetFieldID(cacheResultClass, "mimeType", "Ljava/lang/String;"); |
| |
| jobject javaResult = env->NewObject(cacheResultClass, constructor); |
| setFieldFromHeaderIfPresent(result.get(), "content-disposition", env, javaResult, contentdispositionField, true); |
| env->SetLongField(javaResult, contentLengthField, result->contentSize()); |
| setFieldFromHeaderIfPresent(result.get(), "etag", env, javaResult, etagField, false); |
| setStringField(env, javaResult, encodingField, "TODO"); // TODO: Where does the Android stack set this? |
| env->SetLongField(javaResult, expiresField, result->expires()); |
| env->SetIntField(javaResult, httpStatusCodeField, result->responseCode()); |
| setFieldFromHeaderIfPresent(result.get(), "last-modified", env, javaResult, lastModifiedField, false); |
| setStringField(env, javaResult, localPathField, encodedUrl.data()); |
| setFieldFromHeaderIfPresent(result.get(), "location", env, javaResult, locationField, false); |
| setStringField(env, javaResult, mimeTypeField, result->mimeType()); |
| |
| return javaResult; |
| } |
| |
| static JNINativeMethod gCacheManagerMethods[] = { |
| { "nativeGetCacheResult", "(Ljava/lang/String;)Landroid/webkit/CacheManager$CacheResult;", (void*) getCacheResult }, |
| }; |
| |
| int registerCacheManager(JNIEnv* env) |
| { |
| #ifndef NDEBUG |
| jclass cacheManager = env->FindClass(javaCacheManagerClass); |
| ALOG_ASSERT(cacheManager, "Unable to find class"); |
| env->DeleteLocalRef(cacheManager); |
| #endif |
| return jniRegisterNativeMethods(env, javaCacheManagerClass, gCacheManagerMethods, NELEM(gCacheManagerMethods)); |
| } |
| |
| } // namespace android |