1 /* 2 * Copyright 2010, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #define LOG_TAG "UrlInterceptResponse" 27 #include "config.h" 28 29 #include "JNIUtility.h" 30 #include "UrlInterceptResponse.h" 31 #include "WebCoreJni.h" 32 33 #include <ScopedLocalRef.h> 34 #include <utils/Log.h> 35 36 namespace android { 37 38 class JavaInputStreamWrapper { 39 public: 40 JavaInputStreamWrapper(JNIEnv* env, jobject inputStream) 41 : m_inputStream(env->NewGlobalRef(inputStream)) 42 , m_buffer(NULL) { 43 LOG_ALWAYS_FATAL_IF(!m_inputStream); 44 ScopedLocalRef<jclass> inputStreamClass(env, env->FindClass("java/io/InputStream")); 45 LOG_ALWAYS_FATAL_IF(!inputStreamClass.get()); 46 m_read = env->GetMethodID(inputStreamClass.get(), "read", "([B)I"); 47 LOG_ALWAYS_FATAL_IF(!m_read); 48 m_close = env->GetMethodID(inputStreamClass.get(), "close", "()V"); 49 LOG_ALWAYS_FATAL_IF(!m_close); 50 } 51 52 ~JavaInputStreamWrapper() { 53 JNIEnv* env = JSC::Bindings::getJNIEnv(); 54 env->CallVoidMethod(m_inputStream, m_close); 55 checkException(env); 56 env->DeleteGlobalRef(m_inputStream); 57 // In case we never call read(). 58 if (m_buffer) 59 env->DeleteGlobalRef(m_buffer); 60 } 61 62 void read(std::vector<char>* out) { 63 JNIEnv* env = JSC::Bindings::getJNIEnv(); 64 // Initialize our read buffer to the capacity of out. 65 if (!m_buffer) { 66 ScopedLocalRef<jbyteArray> buffer_local(env, env->NewByteArray(out->capacity())); 67 m_buffer = static_cast<jbyteArray>(env->NewGlobalRef(buffer_local.get())); 68 } 69 int size = env->CallIntMethod(m_inputStream, m_read, m_buffer); 70 if (checkException(env) || size < 0) 71 return; 72 // Copy from m_buffer to out. 73 out->resize(size); 74 env->GetByteArrayRegion(m_buffer, 0, size, (jbyte*)&out->front()); 75 } 76 77 private: 78 jobject m_inputStream; 79 jbyteArray m_buffer; 80 jmethodID m_read; 81 jmethodID m_close; 82 }; 83 84 UrlInterceptResponse::UrlInterceptResponse(JNIEnv* env, jobject response) { 85 ScopedLocalRef<jclass> javaResponse(env, env->FindClass("android/webkit/WebResourceResponse")); 86 LOG_ALWAYS_FATAL_IF(!javaResponse.get()); 87 jfieldID mimeType = env->GetFieldID(javaResponse.get(), "mMimeType", "Ljava/lang/String;"); 88 LOG_ALWAYS_FATAL_IF(!mimeType); 89 jfieldID encoding = env->GetFieldID(javaResponse.get(), "mEncoding", "Ljava/lang/String;"); 90 LOG_ALWAYS_FATAL_IF(!encoding); 91 jfieldID inputStream = env->GetFieldID(javaResponse.get(), "mInputStream", "Ljava/io/InputStream;"); 92 LOG_ALWAYS_FATAL_IF(!inputStream); 93 94 ScopedLocalRef<jobject> stream(env, env->GetObjectField(response, inputStream)); 95 if (stream.get()) 96 m_inputStream.set(new JavaInputStreamWrapper(env, stream.get())); 97 98 ScopedLocalRef<jstring> mimeStr(env, static_cast<jstring>(env->GetObjectField(response, mimeType))); 99 ScopedLocalRef<jstring> encodingStr(env, static_cast<jstring>(env->GetObjectField(response, encoding))); 100 101 if (mimeStr.get()) { 102 const char* s = env->GetStringUTFChars(mimeStr.get(), NULL); 103 m_mimeType.assign(s, env->GetStringUTFLength(mimeStr.get())); 104 env->ReleaseStringUTFChars(mimeStr.get(), s); 105 } 106 if (encodingStr.get()) { 107 const char* s = env->GetStringUTFChars(encodingStr.get(), NULL); 108 m_encoding.assign(s, env->GetStringUTFLength(encodingStr.get())); 109 env->ReleaseStringUTFChars(encodingStr.get(), s); 110 } 111 } 112 113 UrlInterceptResponse::~UrlInterceptResponse() { 114 // Cannot be inlined because of JavaInputStreamWrapper visibility. 115 } 116 117 bool UrlInterceptResponse::readStream(std::vector<char>* out) const { 118 if (!m_inputStream) 119 return false; 120 m_inputStream->read(out); 121 return true; 122 } 123 124 } // namespace android 125