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 <utils/Log.h> 34 35 namespace android { 36 37 class JavaInputStreamWrapper { 38 public: 39 JavaInputStreamWrapper(JNIEnv* env, jobject inputStream) 40 : m_inputStream(env->NewGlobalRef(inputStream)) 41 , m_buffer(0) { 42 LOG_ALWAYS_FATAL_IF(!inputStream); 43 jclass inputStreamClass = env->FindClass("java/io/InputStream"); 44 LOG_ALWAYS_FATAL_IF(!inputStreamClass); 45 m_read = env->GetMethodID(inputStreamClass, "read", "([B)I"); 46 LOG_ALWAYS_FATAL_IF(!m_read); 47 m_close = env->GetMethodID(inputStreamClass, "close", "()V"); 48 LOG_ALWAYS_FATAL_IF(!m_close); 49 env->DeleteLocalRef(inputStreamClass); 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 m_buffer = env->NewByteArray(out->capacity()); 67 m_buffer = (jbyteArray) env->NewGlobalRef(m_buffer); 68 } 69 int size = (int) 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 jclass javaResponse = env->FindClass("android/webkit/WebResourceResponse"); 86 LOG_ALWAYS_FATAL_IF(!javaResponse); 87 jfieldID mimeType = env->GetFieldID(javaResponse, "mMimeType", 88 "Ljava/lang/String;"); 89 LOG_ALWAYS_FATAL_IF(!mimeType); 90 jfieldID encoding = env->GetFieldID(javaResponse, "mEncoding", 91 "Ljava/lang/String;"); 92 LOG_ALWAYS_FATAL_IF(!encoding); 93 jfieldID inputStream = env->GetFieldID(javaResponse, "mInputStream", 94 "Ljava/io/InputStream;"); 95 LOG_ALWAYS_FATAL_IF(!inputStream); 96 97 jobject stream = env->GetObjectField(response, inputStream); 98 if (stream) 99 m_inputStream.set(new JavaInputStreamWrapper(env, stream)); 100 101 jstring mimeStr = (jstring) env->GetObjectField(response, mimeType); 102 jstring encodingStr = (jstring) env->GetObjectField(response, encoding); 103 104 if (mimeStr) { 105 const char* s = env->GetStringUTFChars(mimeStr, NULL); 106 m_mimeType.assign(s, env->GetStringUTFLength(mimeStr)); 107 env->ReleaseStringUTFChars(mimeStr, s); 108 } 109 if (encodingStr) { 110 const char* s = env->GetStringUTFChars(encodingStr, NULL); 111 m_encoding.assign(s, env->GetStringUTFLength(encodingStr)); 112 env->ReleaseStringUTFChars(encodingStr, s); 113 } 114 115 env->DeleteLocalRef(javaResponse); 116 env->DeleteLocalRef(stream); 117 env->DeleteLocalRef(mimeStr); 118 env->DeleteLocalRef(encodingStr); 119 } 120 121 UrlInterceptResponse::~UrlInterceptResponse() { 122 // Cannot be inlined because of JavaInputStreamWrapper visibility. 123 } 124 125 bool UrlInterceptResponse::readStream(std::vector<char>* out) const { 126 if (!m_inputStream) 127 return false; 128 m_inputStream->read(out); 129 return true; 130 } 131 132 } // namespace android 133