/* * Copyright 2010, 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. */ #define LOG_TAG "UrlInterceptResponse" #include "config.h" #include "JNIUtility.h" #include "UrlInterceptResponse.h" #include "WebCoreJni.h" #include namespace android { class JavaInputStreamWrapper { public: JavaInputStreamWrapper(JNIEnv* env, jobject inputStream) : m_inputStream(env->NewGlobalRef(inputStream)) , m_buffer(0) { LOG_ALWAYS_FATAL_IF(!inputStream); m_inputStreamClass = env->FindClass("java/io/InputStream"); LOG_ALWAYS_FATAL_IF(!m_inputStreamClass); m_read = env->GetMethodID(m_inputStreamClass, "read", "([B)I"); LOG_ALWAYS_FATAL_IF(!m_read); m_close = env->GetMethodID(m_inputStreamClass, "close", "()V"); LOG_ALWAYS_FATAL_IF(!m_close); } ~JavaInputStreamWrapper() { JNIEnv* env = JSC::Bindings::getJNIEnv(); env->CallVoidMethod(m_inputStream, m_close); checkException(env); env->DeleteGlobalRef(m_inputStream); // In case we never call read(). if (m_buffer) env->DeleteGlobalRef(m_buffer); } void read(std::vector* out) { JNIEnv* env = JSC::Bindings::getJNIEnv(); // Initialize our read buffer to the capacity of out. if (!m_buffer) { m_buffer = env->NewByteArray(out->capacity()); m_buffer = (jbyteArray) env->NewGlobalRef(m_buffer); } int size = (int) env->CallIntMethod(m_inputStream, m_read, m_buffer); if (checkException(env) || size < 0) return; // Copy from m_buffer to out. out->resize(size); env->GetByteArrayRegion(m_buffer, 0, size, (jbyte*)&out->front()); } private: jobject m_inputStream; jbyteArray m_buffer; jclass m_inputStreamClass; jmethodID m_read; jmethodID m_close; }; UrlInterceptResponse::UrlInterceptResponse(JNIEnv* env, jobject response) { jclass javaResponse = env->FindClass("android/webkit/WebResourceResponse"); LOG_ALWAYS_FATAL_IF(!javaResponse); jfieldID mimeType = env->GetFieldID(javaResponse, "mMimeType", "Ljava/lang/String;"); LOG_ALWAYS_FATAL_IF(!mimeType); jfieldID encoding = env->GetFieldID(javaResponse, "mEncoding", "Ljava/lang/String;"); LOG_ALWAYS_FATAL_IF(!encoding); jfieldID inputStream = env->GetFieldID(javaResponse, "mInputStream", "Ljava/io/InputStream;"); LOG_ALWAYS_FATAL_IF(!inputStream); jobject stream = env->GetObjectField(response, inputStream); if (stream) m_inputStream.set(new JavaInputStreamWrapper(env, stream)); jstring mimeStr = (jstring) env->GetObjectField(response, mimeType); jstring encodingStr = (jstring) env->GetObjectField(response, encoding); if (mimeStr) { const char* s = env->GetStringUTFChars(mimeStr, NULL); m_mimeType.assign(s, env->GetStringUTFLength(mimeStr)); env->ReleaseStringUTFChars(mimeStr, s); } if (encodingStr) { const char* s = env->GetStringUTFChars(encodingStr, NULL); m_encoding.assign(s, env->GetStringUTFLength(encodingStr)); env->ReleaseStringUTFChars(encodingStr, s); } env->DeleteLocalRef(javaResponse); env->DeleteLocalRef(mimeStr); env->DeleteLocalRef(encodingStr); } UrlInterceptResponse::~UrlInterceptResponse() { // Cannot be inlined because of JavaInputStreamWrapper visibility. } bool UrlInterceptResponse::readStream(std::vector* out) const { if (!m_inputStream) return false; m_inputStream->read(out); return true; } } // namespace android