12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "android_webview/native/input_stream_impl.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/android/jni_android.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Disable "Warnings treated as errors" for input_stream_jni as it's a Java 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// system class and we have to generate C++ hooks for all methods in the class 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// even if they're unused. 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#pragma GCC diagnostic push 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#pragma GCC diagnostic ignored "-Wunused-function" 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "jni/InputStreamUtil_jni.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#pragma GCC diagnostic pop 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/base/io_buffer.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::AttachCurrentThread; 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::ClearException; 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::android::JavaRef; 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace android_webview { 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace { 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// This should be the same as InputStramUtil.EXCEPTION_THROWN_STATUS. 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const int kExceptionThrownStatusCode = -2; 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool RegisterInputStream(JNIEnv* env) { 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return RegisterNativesImpl(env); 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Maximum number of bytes to be read in a single read. 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int InputStreamImpl::kBufferSize = 4096; 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//static 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const InputStreamImpl* InputStreamImpl::FromInputStream( 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const InputStream* input_stream) { 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return static_cast<const InputStreamImpl*>(input_stream); 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// TODO: Use unsafe version for all Java_InputStream methods in this file 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// once BUG 157880 is fixed and implement graceful exception handling. 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputStreamImpl::InputStreamImpl() { 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputStreamImpl::InputStreamImpl(const JavaRef<jobject>& stream) 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : jobject_(stream) { 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(!stream.is_null()); 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)InputStreamImpl::~InputStreamImpl() { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) JNIEnv* env = AttachCurrentThread(); 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Java_InputStreamUtil_close(env, jobject_.obj()); 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputStreamImpl::BytesAvailable(int* bytes_available) const { 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) JNIEnv* env = AttachCurrentThread(); 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int bytes = Java_InputStreamUtil_available(env, jobject_.obj()); 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (bytes == kExceptionThrownStatusCode) 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *bytes_available = bytes; 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputStreamImpl::Skip(int64_t n, int64_t* bytes_skipped) { 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) JNIEnv* env = AttachCurrentThread(); 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) int bytes = Java_InputStreamUtil_skip(env, jobject_.obj(), n); 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (bytes < 0) 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (bytes > n) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *bytes_skipped = bytes; 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool InputStreamImpl::Read(net::IOBuffer* dest, int length, int* bytes_read) { 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) JNIEnv* env = AttachCurrentThread(); 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!buffer_.obj()) { 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Allocate transfer buffer. 837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch base::android::ScopedJavaLocalRef<jbyteArray> temp( 847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch env, env->NewByteArray(kBufferSize)); 857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch buffer_.Reset(temp); 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (ClearException(env)) 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 90d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) int remaining_length = length; 91d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) char* dest_write_ptr = dest->data(); 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) jbyteArray buffer = buffer_.obj(); 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *bytes_read = 0; 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) while (remaining_length > 0) { 96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) const int max_transfer_length = std::min(remaining_length, kBufferSize); 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int transfer_length = Java_InputStreamUtil_read( 98d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) env, jobject_.obj(), buffer, 0, max_transfer_length); 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (transfer_length == kExceptionThrownStatusCode) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return false; 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (transfer_length < 0) // EOF 103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) break; 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Note: it is possible, yet unlikely, that the Java InputStream returns 106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // a transfer_length == 0 from time to time. In such cases we just continue 107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // the read until we get either valid data or reach EOF. 108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (transfer_length == 0) 109d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) continue; 110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 111d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK_GE(max_transfer_length, transfer_length); 112d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK_GE(env->GetArrayLength(buffer), transfer_length); 113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // This check is to prevent a malicious InputStream implementation from 115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // overrunning the |dest| buffer. 116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (transfer_length > max_transfer_length) 117d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return false; 118d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 119d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Copy the data over to the provided C++ IOBuffer. 120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK_GE(remaining_length, transfer_length); 121d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) env->GetByteArrayRegion(buffer, 0, transfer_length, 122d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) reinterpret_cast<jbyte*>(dest_write_ptr)); 123d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (ClearException(env)) 124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return false; 125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 126d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) remaining_length -= transfer_length; 127d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) dest_write_ptr += transfer_length; 128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // bytes_read can be strictly less than the req. length if EOF is encountered. 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_GE(remaining_length, 0); 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_LE(remaining_length, length); 132d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) *bytes_read = length - remaining_length; 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return true; 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace android_webview 137