| Index: ppapi/proxy/ppb_url_loader_proxy.cc
|
| ===================================================================
|
| --- ppapi/proxy/ppb_url_loader_proxy.cc (revision 0)
|
| +++ ppapi/proxy/ppb_url_loader_proxy.cc (revision 0)
|
| @@ -0,0 +1,419 @@
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "ppapi/proxy/ppb_url_loader_proxy.h"
|
| +
|
| +#include <vector>
|
| +
|
| +#include "base/logging.h"
|
| +#include "build/build_config.h"
|
| +#include "ppapi/c/pp_completion_callback.h"
|
| +#include "ppapi/c/pp_errors.h"
|
| +#include "ppapi/c/pp_resource.h"
|
| +#include "ppapi/c/dev/ppb_url_loader_dev.h"
|
| +#include "ppapi/proxy/host_dispatcher.h"
|
| +#include "ppapi/proxy/plugin_dispatcher.h"
|
| +#include "ppapi/proxy/plugin_resource.h"
|
| +#include "ppapi/proxy/ppapi_messages.h"
|
| +#include "ppapi/proxy/ppb_url_response_info_proxy.h"
|
| +
|
| +#if defined(OS_LINUX)
|
| +#include <sys/shm.h>
|
| +#endif
|
| +
|
| +namespace pp {
|
| +namespace proxy {
|
| +
|
| +class URLLoader : public PluginResource {
|
| + public:
|
| + URLLoader();
|
| + virtual ~URLLoader();
|
| +
|
| + // Resource overrides.
|
| + virtual URLLoader* AsURLLoader() { return this; }
|
| +
|
| + // Initialized to -1. Will be set to nonnegative values by the UpdateProgress
|
| + // message when the values are known.
|
| + int64_t bytes_sent_;
|
| + int64_t total_bytes_to_be_sent_;
|
| + int64_t bytes_received_;
|
| + int64_t total_bytes_to_be_received_;
|
| +
|
| + // When an asynchronous read is pending, this will contain the callback and
|
| + // the buffer to put the data.
|
| + PP_CompletionCallback current_read_callback_;
|
| + char* current_read_buffer_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(URLLoader);
|
| +};
|
| +
|
| +URLLoader::URLLoader()
|
| + : bytes_sent_(-1),
|
| + total_bytes_to_be_sent_(-1),
|
| + bytes_received_(-1),
|
| + total_bytes_to_be_received_(-1),
|
| + current_read_callback_(PP_MakeCompletionCallback(NULL, NULL)),
|
| + current_read_buffer_(NULL) {
|
| +}
|
| +
|
| +URLLoader::~URLLoader() {
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +// Plugin interface implmentation ----------------------------------------------
|
| +
|
| +PP_Resource Create(PP_Instance instance_id) {
|
| + PluginDispatcher* dispatcher = PluginDispatcher::Get();
|
| + PP_Resource result = 0;
|
| + dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Create(
|
| + INTERFACE_ID_PPB_URL_LOADER, instance_id, &result));
|
| + if (result)
|
| + PPB_URLLoader_Proxy::TrackPluginResource(result);
|
| + return result;
|
| +}
|
| +
|
| +bool IsURLLoader(PP_Resource resource) {
|
| + URLLoader* object = PluginResource::GetAs<URLLoader>(resource);
|
| + return !!object;
|
| +}
|
| +
|
| +int32_t Open(PP_Resource loader_id,
|
| + PP_Resource request_id,
|
| + PP_CompletionCallback callback) {
|
| + Dispatcher* dispatcher = PluginDispatcher::Get();
|
| + dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Open(
|
| + INTERFACE_ID_PPB_URL_LOADER, loader_id, request_id,
|
| + dispatcher->callback_tracker().SendCallback(callback)));
|
| + return PP_ERROR_WOULDBLOCK;
|
| +}
|
| +
|
| +int32_t FollowRedirect(PP_Resource loader_id,
|
| + PP_CompletionCallback callback) {
|
| + Dispatcher* dispatcher = PluginDispatcher::Get();
|
| + dispatcher->Send(new PpapiHostMsg_PPBURLLoader_FollowRedirect(
|
| + INTERFACE_ID_PPB_URL_LOADER, loader_id,
|
| + dispatcher->callback_tracker().SendCallback(callback)));
|
| + return PP_ERROR_WOULDBLOCK;
|
| +}
|
| +
|
| +bool GetUploadProgress(PP_Resource loader_id,
|
| + int64_t* bytes_sent,
|
| + int64_t* total_bytes_to_be_sent) {
|
| + URLLoader* object = PluginResource::GetAs<URLLoader>(loader_id);
|
| + if (!object || object->bytes_sent_ == -1) {
|
| + *bytes_sent = 0;
|
| + *total_bytes_to_be_sent = 0;
|
| + return false;
|
| + }
|
| + *bytes_sent = object->bytes_sent_;
|
| + *total_bytes_to_be_sent = object->total_bytes_to_be_sent_;
|
| + return true;
|
| +}
|
| +
|
| +bool GetDownloadProgress(PP_Resource loader_id,
|
| + int64_t* bytes_received,
|
| + int64_t* total_bytes_to_be_received) {
|
| + URLLoader* object = PluginResource::GetAs<URLLoader>(loader_id);
|
| + if (!object || object->bytes_received_ == -1) {
|
| + *bytes_received = 0;
|
| + *total_bytes_to_be_received = 0;
|
| + return false;
|
| + }
|
| + *bytes_received = object->bytes_received_;
|
| + *total_bytes_to_be_received = object->total_bytes_to_be_received_;
|
| + return true;
|
| +}
|
| +
|
| +PP_Resource GetResponseInfo(PP_Resource loader_id) {
|
| + // If we find that plugins are frequently requesting the response info, we
|
| + // can improve performance by caching the PP_Resource in the URLLoader
|
| + // object. This way we only have to do IPC for the first request. However,
|
| + // it seems that most plugins will only call this once so there's no use
|
| + // optimizing this case.
|
| +
|
| + PP_Resource result;
|
| + PluginDispatcher* dispatcher = PluginDispatcher::Get();
|
| + dispatcher->Send(new PpapiHostMsg_PPBURLLoader_GetResponseInfo(
|
| + INTERFACE_ID_PPB_URL_LOADER, loader_id, &result));
|
| + if (dispatcher->plugin_resource_tracker()->PreparePreviouslyTrackedResource(
|
| + result))
|
| + return result;
|
| +
|
| + // Tell the response info to create a tracking object and add it to the
|
| + // resource tracker.
|
| + PPB_URLResponseInfo_Proxy::TrackPluginResource(result);
|
| + return result;
|
| +}
|
| +
|
| +int32_t ReadResponseBody(PP_Resource loader_id,
|
| + char* buffer,
|
| + int32_t bytes_to_read,
|
| + PP_CompletionCallback callback) {
|
| + URLLoader* object = PluginResource::GetAs<URLLoader>(loader_id);
|
| + if (!object)
|
| + return PP_ERROR_BADRESOURCE;
|
| +
|
| + if (!buffer)
|
| + return PP_ERROR_BADARGUMENT; // Must specify an output buffer.
|
| + 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
|
| + // how this works when we allow blocking calls (from background threads).
|
| + if (!callback.func)
|
| + return PP_ERROR_BADARGUMENT;
|
| +
|
| + object->current_read_callback_ = callback;
|
| + object->current_read_buffer_ = buffer;
|
| +
|
| + PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBURLLoader_ReadResponseBody(
|
| + INTERFACE_ID_PPB_URL_LOADER, loader_id, bytes_to_read));
|
| + return PP_ERROR_WOULDBLOCK;
|
| +}
|
| +
|
| +int32_t FinishStreamingToFile(PP_Resource loader_id,
|
| + PP_CompletionCallback callback) {
|
| + Dispatcher* dispatcher = PluginDispatcher::Get();
|
| + dispatcher->Send(new PpapiHostMsg_PPBURLLoader_FinishStreamingToFile(
|
| + INTERFACE_ID_PPB_URL_LOADER, loader_id,
|
| + dispatcher->callback_tracker().SendCallback(callback)));
|
| + return PP_ERROR_WOULDBLOCK;
|
| +}
|
| +
|
| +void Close(PP_Resource loader_id) {
|
| + PluginDispatcher::Get()->Send(new PpapiHostMsg_PPBURLLoader_Close(
|
| + INTERFACE_ID_PPB_URL_LOADER, loader_id));
|
| +}
|
| +
|
| +const PPB_URLLoader_Dev ppb_urlloader = {
|
| + &Create,
|
| + &IsURLLoader,
|
| + &Open,
|
| + &FollowRedirect,
|
| + &GetUploadProgress,
|
| + &GetDownloadProgress,
|
| + &GetResponseInfo,
|
| + &ReadResponseBody,
|
| + &FinishStreamingToFile,
|
| + &Close
|
| +};
|
| +
|
| +// Renderer status updates -----------------------------------------------------
|
| +
|
| +// Called in the renderer when the byte counts have changed. We send a message
|
| +// to the plugin to synchronize its counts so it can respond to status polls
|
| +// from the plugin.
|
| +void UpdateResourceLoadStatus(PP_Instance pp_instance,
|
| + PP_Resource pp_resource,
|
| + int64 bytes_sent,
|
| + int64 total_bytes_to_be_sent,
|
| + int64 bytes_received,
|
| + int64 total_bytes_to_be_received) {
|
| + Dispatcher* dispatcher = HostDispatcher::GetForInstance(pp_instance);
|
| + dispatcher->Send(new PpapiMsg_PPBURLLoader_UpdateProgress(
|
| + INTERFACE_ID_PPB_URL_LOADER, pp_resource,
|
| + bytes_sent, total_bytes_to_be_sent,
|
| + bytes_received, total_bytes_to_be_received));
|
| +}
|
| +
|
| +// Data associated with callbacks for ReadResponseBody.
|
| +struct ReadCallbackInfo {
|
| + base::WeakPtr<PPB_URLLoader_Proxy> loader;
|
| + PP_Resource pp_resource;
|
| + std::string read_buffer;
|
| +};
|
| +
|
| +// Callback for renderer calls to ReadResponseBody. This function will forward
|
| +// the result to the plugin and clean up the callback info.
|
| +void ReadCallbackHandler(void* user_data, int32_t result) {
|
| + scoped_ptr<ReadCallbackInfo> info(static_cast<ReadCallbackInfo*>(user_data));
|
| + if (!info->loader)
|
| + return;
|
| +
|
| + int32_t bytes_read = 0;
|
| + if (result > 0)
|
| + bytes_read = result; // Positive results indicate bytes read.
|
| + info->read_buffer.resize(bytes_read);
|
| +
|
| + info->loader->dispatcher()->Send(
|
| + new PpapiMsg_PPBURLLoader_ReadResponseBody_Ack(
|
| + INTERFACE_ID_PPB_URL_LOADER, info->pp_resource,
|
| + result, info->read_buffer));
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +// PPB_URLLoader_Proxy ---------------------------------------------------------
|
| +
|
| +PPB_URLLoader_Proxy::PPB_URLLoader_Proxy(Dispatcher* dispatcher,
|
| + const void* target_interface)
|
| + : InterfaceProxy(dispatcher, target_interface) {
|
| +}
|
| +
|
| +PPB_URLLoader_Proxy::~PPB_URLLoader_Proxy() {
|
| +}
|
| +
|
| +// static
|
| +void PPB_URLLoader_Proxy::TrackPluginResource(PP_Resource url_loader_resource) {
|
| + linked_ptr<URLLoader> object(new URLLoader);
|
| + PluginDispatcher::Get()->plugin_resource_tracker()->AddResource(
|
| + url_loader_resource, object);
|
| +}
|
| +
|
| +const void* PPB_URLLoader_Proxy::GetSourceInterface() const {
|
| + return &ppb_urlloader;
|
| +}
|
| +
|
| +InterfaceID PPB_URLLoader_Proxy::GetInterfaceId() const {
|
| + return INTERFACE_ID_PPB_URL_LOADER;
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMessageReceived(const IPC::Message& msg) {
|
| + IPC_BEGIN_MESSAGE_MAP(PPB_URLLoader_Proxy, msg)
|
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Create,
|
| + OnMsgCreate)
|
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Open,
|
| + OnMsgOpen)
|
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FollowRedirect,
|
| + OnMsgFollowRedirect)
|
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_GetResponseInfo,
|
| + OnMsgGetResponseInfo)
|
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_ReadResponseBody,
|
| + OnMsgReadResponseBody)
|
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile,
|
| + OnMsgFinishStreamingToFile)
|
| + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBURLLoader_Close,
|
| + OnMsgClose)
|
| +
|
| + IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_UpdateProgress,
|
| + OnMsgUpdateProgress)
|
| + IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack,
|
| + OnMsgReadResponseBodyAck)
|
| + IPC_END_MESSAGE_MAP()
|
| + // TODO(brettw) handle bad messages!
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMsgCreate(PP_Instance instance,
|
| + PP_Resource* result) {
|
| + *result = ppb_url_loader_target()->Create(instance);
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMsgOpen(PP_Resource loader,
|
| + PP_Resource request_info,
|
| + uint32_t serialized_callback) {
|
| + PP_CompletionCallback callback = ReceiveCallback(serialized_callback);
|
| + int32_t result = ppb_url_loader_target()->Open(
|
| + loader, request_info, callback);
|
| + if (result != PP_ERROR_WOULDBLOCK)
|
| + PP_RunCompletionCallback(&callback, result);
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMsgFollowRedirect(
|
| + PP_Resource loader,
|
| + uint32_t serialized_callback) {
|
| + PP_CompletionCallback callback = ReceiveCallback(serialized_callback);
|
| + int32_t result = ppb_url_loader_target()->FollowRedirect(
|
| + loader, callback);
|
| + if (result != PP_ERROR_WOULDBLOCK)
|
| + PP_RunCompletionCallback(&callback, result);
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMsgGetResponseInfo(PP_Resource loader,
|
| + PP_Resource* result) {
|
| + *result = ppb_url_loader_target()->GetResponseInfo(loader);
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMsgReadResponseBody(
|
| + PP_Resource loader,
|
| + int32_t bytes_to_read) {
|
| + // The plugin could be sending us malicious messages, don't accept negative
|
| + // sizes.
|
| + if (bytes_to_read < 0) {
|
| + // TODO(brettw) kill plugin.
|
| + bytes_to_read = 0;
|
| + }
|
| +
|
| + // 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
|
| + // destroyed. Depending on the cleanup ordering, we may not need the weak
|
| + // pointer here.)
|
| + ReadCallbackInfo* info = new ReadCallbackInfo;
|
| + info->loader = AsWeakPtr();
|
| + info->pp_resource = loader;
|
| + info->read_buffer.resize(bytes_to_read);
|
| +
|
| + int32_t result = ppb_url_loader_target()->ReadResponseBody(
|
| + loader, const_cast<char*>(info->read_buffer.c_str()), bytes_to_read,
|
| + PP_MakeCompletionCallback(&ReadCallbackHandler, info));
|
| + if (result != PP_ERROR_WOULDBLOCK) {
|
| + // Send error (or perhaps success for synchronous reads) back to plugin.
|
| + // The callback function is already set up to do this and also delete the
|
| + // callback info.
|
| + ReadCallbackHandler(info, result);
|
| + }
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMsgFinishStreamingToFile(
|
| + PP_Resource loader,
|
| + uint32_t serialized_callback) {
|
| + PP_CompletionCallback callback = ReceiveCallback(serialized_callback);
|
| + int32_t result = ppb_url_loader_target()->FinishStreamingToFile(
|
| + loader, callback);
|
| + if (result != PP_ERROR_WOULDBLOCK)
|
| + PP_RunCompletionCallback(&callback, result);
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMsgClose(PP_Resource loader) {
|
| + ppb_url_loader_target()->Close(loader);
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMsgUpdateProgress(
|
| + PP_Resource resource,
|
| + int64_t bytes_sent,
|
| + int64_t total_bytes_to_be_sent,
|
| + int64_t bytes_received,
|
| + int64_t total_bytes_to_be_received) {
|
| + URLLoader* object = PluginResource::GetAs<URLLoader>(resource);
|
| + if (!object) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| +
|
| + object->bytes_sent_ = bytes_sent;
|
| + object->total_bytes_to_be_sent_ = total_bytes_to_be_sent;
|
| + object->bytes_received_ = bytes_received;
|
| + object->total_bytes_to_be_received_ = total_bytes_to_be_received;
|
| +}
|
| +
|
| +void PPB_URLLoader_Proxy::OnMsgReadResponseBodyAck(PP_Resource pp_resource,
|
| + int32 result,
|
| + const std::string& data) {
|
| + URLLoader* object = PluginResource::GetAs<URLLoader>(pp_resource);
|
| + if (!object) {
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| +
|
| + if (!object->current_read_callback_.func || !object->current_read_buffer_) {
|
| + NOTREACHED();
|
| + 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());
|
| +
|
| + // 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;
|
| + PP_RunCompletionCallback(&temp_callback, result);
|
| +}
|
| +
|
| +} // namespace proxy
|
| +} // namespace pp
|
|
|
| Property changes on: ppapi/proxy/ppb_url_loader_proxy.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|