blob: d846daf683ce62d09743c0fcc488cb09b1705bd7 [file] [log] [blame]
/*
* Copyright 2010, The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "UrlInterceptResponse"
#include "config.h"
#include "JNIUtility.h"
#include "UrlInterceptResponse.h"
#include "WebCoreJni.h"
#include <ScopedLocalRef.h>
#include <utils/Log.h>
namespace android {
class JavaInputStreamWrapper {
public:
JavaInputStreamWrapper(JNIEnv* env, jobject inputStream)
: m_inputStream(env->NewGlobalRef(inputStream))
, m_buffer(NULL) {
LOG_ALWAYS_FATAL_IF(!m_inputStream);
ScopedLocalRef<jclass> inputStreamClass(env, env->FindClass("java/io/InputStream"));
LOG_ALWAYS_FATAL_IF(!inputStreamClass.get());
m_read = env->GetMethodID(inputStreamClass.get(), "read", "([B)I");
LOG_ALWAYS_FATAL_IF(!m_read);
m_close = env->GetMethodID(inputStreamClass.get(), "close", "()V");
LOG_ALWAYS_FATAL_IF(!m_close);
}
~JavaInputStreamWrapper() {
JNIEnv* env = JSC::Bindings::getJNIEnv();
env->CallVoidMethod(m_inputStream, m_close);
checkException(env);
env->DeleteGlobalRef(m_inputStream);
// In case we never call read().
if (m_buffer)
env->DeleteGlobalRef(m_buffer);
}
void read(std::vector<char>* out) {
JNIEnv* env = JSC::Bindings::getJNIEnv();
// Initialize our read buffer to the capacity of out.
if (!m_buffer) {
ScopedLocalRef<jbyteArray> buffer_local(env, env->NewByteArray(out->capacity()));
m_buffer = static_cast<jbyteArray>(env->NewGlobalRef(buffer_local.get()));
}
int size = env->CallIntMethod(m_inputStream, m_read, m_buffer);
if (checkException(env) || size < 0)
return;
// Copy from m_buffer to out.
out->resize(size);
env->GetByteArrayRegion(m_buffer, 0, size, (jbyte*)&out->front());
}
private:
jobject m_inputStream;
jbyteArray m_buffer;
jmethodID m_read;
jmethodID m_close;
};
UrlInterceptResponse::UrlInterceptResponse(JNIEnv* env, jobject response) {
ScopedLocalRef<jclass> javaResponse(env, env->FindClass("android/webkit/WebResourceResponse"));
LOG_ALWAYS_FATAL_IF(!javaResponse.get());
jfieldID mimeType = env->GetFieldID(javaResponse.get(), "mMimeType", "Ljava/lang/String;");
LOG_ALWAYS_FATAL_IF(!mimeType);
jfieldID encoding = env->GetFieldID(javaResponse.get(), "mEncoding", "Ljava/lang/String;");
LOG_ALWAYS_FATAL_IF(!encoding);
jfieldID inputStream = env->GetFieldID(javaResponse.get(), "mInputStream", "Ljava/io/InputStream;");
LOG_ALWAYS_FATAL_IF(!inputStream);
ScopedLocalRef<jobject> stream(env, env->GetObjectField(response, inputStream));
if (stream.get())
m_inputStream.set(new JavaInputStreamWrapper(env, stream.get()));
ScopedLocalRef<jstring> mimeStr(env, static_cast<jstring>(env->GetObjectField(response, mimeType)));
ScopedLocalRef<jstring> encodingStr(env, static_cast<jstring>(env->GetObjectField(response, encoding)));
if (mimeStr.get()) {
const char* s = env->GetStringUTFChars(mimeStr.get(), NULL);
m_mimeType.assign(s, env->GetStringUTFLength(mimeStr.get()));
env->ReleaseStringUTFChars(mimeStr.get(), s);
}
if (encodingStr.get()) {
const char* s = env->GetStringUTFChars(encodingStr.get(), NULL);
m_encoding.assign(s, env->GetStringUTFLength(encodingStr.get()));
env->ReleaseStringUTFChars(encodingStr.get(), s);
}
}
UrlInterceptResponse::~UrlInterceptResponse() {
// Cannot be inlined because of JavaInputStreamWrapper visibility.
}
bool UrlInterceptResponse::readStream(std::vector<char>* out) const {
if (!m_inputStream)
return false;
m_inputStream->read(out);
return true;
}
} // namespace android