| Index: android_webview/native/input_stream_impl.cc
|
| diff --git a/android_webview/native/input_stream_impl.cc b/android_webview/native/input_stream_impl.cc
|
| index 24d7be09930bc734cbd56a55b00686f98513db33..fca6a29cc8378aca2bb107f430abb0773f2b2458 100644
|
| --- a/android_webview/native/input_stream_impl.cc
|
| +++ b/android_webview/native/input_stream_impl.cc
|
| @@ -84,46 +84,48 @@ bool InputStreamImpl::Read(net::IOBuffer* dest, int length, int* bytes_read) {
|
| return false;
|
| }
|
|
|
| + int remaining_length = length;
|
| + char* dest_write_ptr = dest->data();
|
| jbyteArray buffer = buffer_.obj();
|
| *bytes_read = 0;
|
|
|
| - const int read_size = std::min(length, kBufferSize);
|
| - int32_t byte_count;
|
| - do {
|
| - // Unfortunately it is valid for the Java InputStream to read 0 bytes some
|
| - // number of times before returning any more data. Because this method
|
| - // signals EOF by setting |bytes_read| to 0 and returning true necessary to
|
| - // call the Java-side read method until it returns something other than 0.
|
| - byte_count = Java_InputStream_readI_AB_I_I(
|
| - env, jobject_.obj(), buffer, 0, read_size);
|
| + while (remaining_length > 0) {
|
| + const int max_transfer_length = std::min(remaining_length, kBufferSize);
|
| + const int transfer_length = Java_InputStream_readI_AB_I_I(
|
| + env, jobject_.obj(), buffer, 0, max_transfer_length);
|
| if (ClearException(env))
|
| return false;
|
| - } while (byte_count == 0);
|
| -
|
| - // We've reached the end of the stream.
|
| - if (byte_count < 0)
|
| - return true;
|
| -
|
| -#ifndef NDEBUG
|
| - int32_t buffer_length = env->GetArrayLength(buffer);
|
| - DCHECK_GE(read_size, byte_count);
|
| - DCHECK_GE(buffer_length, byte_count);
|
| -#endif // NDEBUG
|
| -
|
| - // The DCHECKs are in place to help Chromium developers in case of bugs,
|
| - // this check is to prevent a malicious InputStream implementation from
|
| - // overrunning the |dest| buffer.
|
| - if (byte_count > read_size)
|
| - return false;
|
|
|
| - // Copy the data over to the provided C++ side buffer.
|
| - DCHECK_GE(length, byte_count);
|
| - env->GetByteArrayRegion(buffer, 0, byte_count,
|
| - reinterpret_cast<jbyte*>(dest->data() + *bytes_read));
|
| - if (ClearException(env))
|
| - return false;
|
| + if (transfer_length < 0) // EOF
|
| + break;
|
|
|
| - *bytes_read = byte_count;
|
| + // Note: it is possible, yet unlikely, that the Java InputStream returns
|
| + // a transfer_length == 0 from time to time. In such cases we just continue
|
| + // the read until we get either valid data or reach EOF.
|
| + if (transfer_length == 0)
|
| + continue;
|
| +
|
| + DCHECK_GE(max_transfer_length, transfer_length);
|
| + DCHECK_GE(env->GetArrayLength(buffer), transfer_length);
|
| +
|
| + // This check is to prevent a malicious InputStream implementation from
|
| + // overrunning the |dest| buffer.
|
| + if (transfer_length > max_transfer_length)
|
| + return false;
|
| +
|
| + // Copy the data over to the provided C++ IOBuffer.
|
| + DCHECK_GE(remaining_length, transfer_length);
|
| + env->GetByteArrayRegion(buffer, 0, transfer_length,
|
| + reinterpret_cast<jbyte*>(dest_write_ptr));
|
| + if (ClearException(env))
|
| + return false;
|
| +
|
| + remaining_length -= transfer_length;
|
| + dest_write_ptr += transfer_length;
|
| + }
|
| + // bytes_read can be strictly less than the req. length if EOF is encountered.
|
| + DCHECK(remaining_length >= 0 && remaining_length <= length);
|
| + *bytes_read = length - remaining_length;
|
| return true;
|
| }
|
|
|
|
|