summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ppapi/c/private/ppb_proxy_private.h7
-rw-r--r--ppapi/proxy/ppb_url_loader_proxy.cc88
-rw-r--r--webkit/plugins/ppapi/ppb_proxy_impl.cc12
-rw-r--r--webkit/plugins/ppapi/ppb_url_loader_impl.h4
4 files changed, 99 insertions, 12 deletions
diff --git a/ppapi/c/private/ppb_proxy_private.h b/ppapi/c/private/ppb_proxy_private.h
index ae6a39e..e1e133e 100644
--- a/ppapi/c/private/ppb_proxy_private.h
+++ b/ppapi/c/private/ppb_proxy_private.h
@@ -10,7 +10,7 @@
#include "ppapi/c/pp_module.h"
#include "ppapi/c/pp_resource.h"
-#define PPB_PROXY_PRIVATE_INTERFACE "PPB_Proxy_Private;3"
+#define PPB_PROXY_PRIVATE_INTERFACE "PPB_Proxy_Private;4"
// Exposes functions needed by the out-of-process proxy to call into the
// renderer PPAPI implementation.
@@ -33,6 +33,11 @@ struct PPB_Proxy_Private {
void (*SetReserveInstanceIDCallback)(
PP_Module module,
PP_Bool (*is_seen)(PP_Module, PP_Instance));
+
+ // Returns the number of bytes synchronously readable out of the URLLoader's
+ // buffer. Returns 0 on failure or if the url loader doesn't have any data
+ // now.
+ int32_t (*GetURLLoaderBufferedBytes)(PP_Resource url_loader);
};
#endif // PPAPI_C_PRIVATE_PROXY_PRIVATE_H_
diff --git a/ppapi/proxy/ppb_url_loader_proxy.cc b/ppapi/proxy/ppb_url_loader_proxy.cc
index 1489923..bc17f15 100644
--- a/ppapi/proxy/ppb_url_loader_proxy.cc
+++ b/ppapi/proxy/ppb_url_loader_proxy.cc
@@ -4,6 +4,8 @@
#include "ppapi/proxy/ppb_url_loader_proxy.h"
+#include <algorithm>
+#include <deque>
#include <vector>
#include "base/logging.h"
@@ -12,6 +14,7 @@
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_resource.h"
#include "ppapi/c/ppb_url_loader.h"
+#include "ppapi/c/private/ppb_proxy_private.h"
#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
#include "ppapi/proxy/host_dispatcher.h"
#include "ppapi/proxy/plugin_dispatcher.h"
@@ -37,6 +40,15 @@ class URLLoader : public PluginResource {
PP_Resource GetResponseInfo();
+ // Appends the given data to the buffer_.
+ void PushBuffer(const char* data, size_t data_size);
+
+ // Reads the give bytes out of the buffer_, placing them in the given output
+ // buffer, and removes the bytes from the buffer.
+ //
+ // The size must be not more than the current size of the buffer.
+ void PopBuffer(void* output_buffer, int32_t output_size);
+
// Initialized to -1. Will be set to nonnegative values by the UpdateProgress
// message when the values are known.
int64_t bytes_sent_;
@@ -48,6 +60,11 @@ class URLLoader : public PluginResource {
// the buffer to put the data.
PP_CompletionCallback current_read_callback_;
void* current_read_buffer_;
+ int32_t current_read_buffer_size_;
+
+ // A buffer of all the data that's been sent to us from the host that we
+ // have yet to send out to the plugin.
+ std::deque<char> buffer_;
// Cached copy of the response info. When nonzero, we're holding a reference
// to this resource.
@@ -65,6 +82,7 @@ URLLoader::URLLoader(const HostResource& resource)
total_bytes_to_be_received_(-1),
current_read_callback_(PP_MakeCompletionCallback(NULL, NULL)),
current_read_buffer_(NULL),
+ current_read_buffer_size_(0),
response_info_(0) {
}
@@ -103,8 +121,25 @@ PP_Resource URLLoader::GetResponseInfo() {
return response_info_;
}
+void URLLoader::PushBuffer(const char* data, size_t data_size) {
+ buffer_.insert(buffer_.end(), data, data + data_size);
+}
+
+void URLLoader::PopBuffer(void* output_buffer, int32_t output_size) {
+ CHECK(output_size <= static_cast<int32_t>(buffer_.size()));
+ std::copy(buffer_.begin(),
+ buffer_.begin() + output_size,
+ static_cast<char*>(output_buffer));
+ buffer_.erase(buffer_.begin(),
+ buffer_.begin() + output_size);
+}
+
namespace {
+// The maximum size we'll read into the plugin without being explicitly
+// asked for a larger buffer.
+static const int32_t kMaxReadBufferSize = 16777216; // 16MB
+
// Converts the given loader ID to the dispatcher associated with it and the
// loader object. Returns true if the object was found.
bool RoutingDataFromURLLoader(PP_Resource loader_id,
@@ -208,14 +243,14 @@ int32_t ReadResponseBody(PP_Resource loader_id,
void* buffer,
int32_t bytes_to_read,
PP_CompletionCallback callback) {
- URLLoader* loader_object;
+ URLLoader* object;
PluginDispatcher* dispatcher;
- if (!RoutingDataFromURLLoader(loader_id, &loader_object, &dispatcher))
+ if (!RoutingDataFromURLLoader(loader_id, &object, &dispatcher))
return PP_ERROR_BADRESOURCE;
- if (!buffer)
+ if (!buffer || bytes_to_read <= 0)
return PP_ERROR_BADARGUMENT; // Must specify an output buffer.
- if (loader_object->current_read_callback_.func)
+ if (object->current_read_callback_.func)
return PP_ERROR_INPROGRESS; // Can only have one request pending.
// Currently we don't support sync calls to read. We'll need to revisit
@@ -223,12 +258,20 @@ int32_t ReadResponseBody(PP_Resource loader_id,
if (!callback.func)
return PP_ERROR_BADARGUMENT;
- loader_object->current_read_callback_ = callback;
- loader_object->current_read_buffer_ = buffer;
+ if (static_cast<size_t>(bytes_to_read) <= object->buffer_.size()) {
+ // Special case: we've buffered enough data to be able to synchronously
+ // return data to the caller. Do so without making IPCs.
+ object->PopBuffer(buffer, bytes_to_read);
+ return bytes_to_read;
+ }
+
+ object->current_read_callback_ = callback;
+ object->current_read_buffer_ = buffer;
+ object->current_read_buffer_size_ = bytes_to_read;
dispatcher->Send(new PpapiHostMsg_PPBURLLoader_ReadResponseBody(
INTERFACE_ID_PPB_URL_LOADER,
- loader_object->host_resource(), bytes_to_read));
+ object->host_resource(), bytes_to_read));
return PP_OK_COMPLETIONPENDING;
}
@@ -433,6 +476,19 @@ void PPB_URLLoader_Proxy::OnMsgReadResponseBody(
bytes_to_read = 0;
}
+ // Read more than requested if there are bytes available for synchronous
+ // reading. This prevents us from getting too far behind due to IPC message
+ // latency. Any extra data will get buffered in the plugin.
+ int32_t synchronously_available_bytes =
+ static_cast<HostDispatcher*>(dispatcher())->ppb_proxy()->
+ GetURLLoaderBufferedBytes(loader.host_resource());
+ if (bytes_to_read < kMaxReadBufferSize) {
+ // Grow the amount to read so we read ahead synchronously, if possible.
+ bytes_to_read =
+ std::max(bytes_to_read,
+ std::min(synchronously_available_bytes, kMaxReadBufferSize));
+ }
+
// This heap object will get deleted by the callback handler.
// TODO(brettw) this will be leaked if the plugin closes the resource!
// (Also including the plugin unloading and having the resource implicitly
@@ -508,15 +564,27 @@ void PPB_URLLoader_Proxy::OnMsgReadResponseBodyAck(
return;
}
- // In the error case, the string will be empty, so we can always just copy
- // out of it before issuing the callback.
- memcpy(object->current_read_buffer_, data.c_str(), data.length());
+ // Append the data we requested to the internal buffer.
+ // TODO(brettw) avoid double-copying data that's coming from IPC and going
+ // into the plugin buffer (we can skip the internal buffer in this case).
+ object->PushBuffer(data.data(), data.length());
+
+ if (result >= 0) {
+ // Fill the user buffer. We may get fewer bytes than requested in the
+ // case of stream end.
+ int32_t bytes_to_return =
+ std::min(object->current_read_buffer_size_,
+ static_cast<int32_t>(object->buffer_.size()));
+ object->PopBuffer(object->current_read_buffer_, bytes_to_return);
+ result = bytes_to_return;
+ }
// The plugin should be able to make a new request from their callback, so
// we have to clear our copy first.
PP_CompletionCallback temp_callback = object->current_read_callback_;
object->current_read_callback_ = PP_BlockUntilComplete();
object->current_read_buffer_ = NULL;
+ object->current_read_buffer_size_ = 0;
PP_RunCompletionCallback(&temp_callback, result);
}
diff --git a/webkit/plugins/ppapi/ppb_proxy_impl.cc b/webkit/plugins/ppapi/ppb_proxy_impl.cc
index f82ec46..9c69891 100644
--- a/webkit/plugins/ppapi/ppb_proxy_impl.cc
+++ b/webkit/plugins/ppapi/ppb_proxy_impl.cc
@@ -7,6 +7,7 @@
#include "ppapi/c/private/ppb_proxy_private.h"
#include "webkit/plugins/ppapi/plugin_module.h"
#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
+#include "webkit/plugins/ppapi/ppb_url_loader_impl.h"
#include "webkit/plugins/ppapi/resource.h"
#include "webkit/plugins/ppapi/resource_tracker.h"
@@ -35,10 +36,19 @@ void SetReserveInstanceIDCallback(PP_Module module,
plugin_module->SetReserveInstanceIDCallback(reserve);
}
+int32_t GetURLLoaderBufferedBytes(PP_Resource url_loader) {
+ scoped_refptr<PPB_URLLoader_Impl> loader(
+ Resource::GetAs<PPB_URLLoader_Impl>(url_loader));
+ if (!loader)
+ return 0;
+ return loader->buffer_size();
+}
+
const PPB_Proxy_Private ppb_proxy = {
&PluginCrashed,
&GetInstanceForResource,
- &SetReserveInstanceIDCallback
+ &SetReserveInstanceIDCallback,
+ &GetURLLoaderBufferedBytes
};
} // namespace
diff --git a/webkit/plugins/ppapi/ppb_url_loader_impl.h b/webkit/plugins/ppapi/ppb_url_loader_impl.h
index c46bbb6..fae3628 100644
--- a/webkit/plugins/ppapi/ppb_url_loader_impl.h
+++ b/webkit/plugins/ppapi/ppb_url_loader_impl.h
@@ -88,6 +88,10 @@ class PPB_URLLoader_Impl : public Resource, public WebKit::WebURLLoaderClient {
PPB_URLResponseInfo_Impl* response_info() const { return response_info_; }
+ // Returns the number of bytes currently available for synchronous reading
+ // in the loader.
+ int32_t buffer_size() const { return buffer_.size(); }
+
private:
// Check that |callback| is valid (only non-blocking operation is supported)
// and that no callback is already pending. Returns |PP_OK| if okay, else