Home | History | Annotate | Download | only in WebCoreSupport
      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