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 <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