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