diff options
53 files changed, 1478 insertions, 1665 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 8024ab9..4b65965 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -225,6 +225,8 @@ 'renderer/pepper/pepper_truetype_font_linux.cc', 'renderer/pepper/pepper_truetype_font_mac.mm', 'renderer/pepper/pepper_truetype_font_win.cc', + 'renderer/pepper/pepper_url_loader_host.cc', + 'renderer/pepper/pepper_url_loader_host.h', 'renderer/pepper/pepper_video_capture_host.cc', 'renderer/pepper/pepper_video_capture_host.h', 'renderer/pepper/pepper_websocket_host.cc', diff --git a/content/public/renderer/renderer_ppapi_host.h b/content/public/renderer/renderer_ppapi_host.h index e5eaa4b..4d81c50 100644 --- a/content/public/renderer/renderer_ppapi_host.h +++ b/content/public/renderer/renderer_ppapi_host.h @@ -94,6 +94,10 @@ class RendererPpapiHost { virtual WebKit::WebPluginContainer* GetContainerForInstance( PP_Instance instance) const = 0; + // Returns the PID of the child process containing the plugin. If running + // in-process, this returns base::kNullProcessId. + virtual base::ProcessId GetPluginPID() const = 0; + // Returns the PlatformGraphics2D for the given plugin resource, or NULL if // the resource is invalid. virtual webkit::ppapi::PluginDelegate::PlatformGraphics2D* diff --git a/content/renderer/pepper/content_renderer_pepper_host_factory.cc b/content/renderer/pepper/content_renderer_pepper_host_factory.cc index 715725b..79b7c4f 100644 --- a/content/renderer/pepper/content_renderer_pepper_host_factory.cc +++ b/content/renderer/pepper/content_renderer_pepper_host_factory.cc @@ -12,6 +12,7 @@ #include "content/renderer/pepper/pepper_file_system_host.h" #include "content/renderer/pepper/pepper_graphics_2d_host.h" #include "content/renderer/pepper/pepper_truetype_font_host.h" +#include "content/renderer/pepper/pepper_url_loader_host.h" #include "content/renderer/pepper/pepper_video_capture_host.h" #include "content/renderer/pepper/pepper_video_destination_host.h" #include "content/renderer/pepper/pepper_video_source_host.h" @@ -74,6 +75,9 @@ scoped_ptr<ResourceHost> ContentRendererPepperHostFactory::CreateResourceHost( PepperGraphics2DHost::Create(host_, instance, params.pp_resource(), size, is_always_opaque)); } + case PpapiHostMsg_URLLoader_Create::ID: + return scoped_ptr<ResourceHost>(new PepperURLLoaderHost( + host_, false, instance, params.pp_resource())); case PpapiHostMsg_WebSocket_Create::ID: return scoped_ptr<ResourceHost>(new PepperWebSocketHost( host_, instance, params.pp_resource())); diff --git a/content/renderer/pepper/mock_renderer_ppapi_host.cc b/content/renderer/pepper/mock_renderer_ppapi_host.cc index 68aa8c8..8c61ccd 100644 --- a/content/renderer/pepper/mock_renderer_ppapi_host.cc +++ b/content/renderer/pepper/mock_renderer_ppapi_host.cc @@ -53,6 +53,11 @@ MockRendererPpapiHost::GetPlatformGraphics2D(PP_Resource resource) { return NULL; } +base::ProcessId MockRendererPpapiHost::GetPluginPID() const { + NOTIMPLEMENTED(); + return base::kNullProcessId; +} + bool MockRendererPpapiHost::HasUserGesture(PP_Instance instance) const { return has_user_gesture_; } diff --git a/content/renderer/pepper/mock_renderer_ppapi_host.h b/content/renderer/pepper/mock_renderer_ppapi_host.h index 47f5861..4476760 100644 --- a/content/renderer/pepper/mock_renderer_ppapi_host.h +++ b/content/renderer/pepper/mock_renderer_ppapi_host.h @@ -47,6 +47,7 @@ class MockRendererPpapiHost : public RendererPpapiHost { PP_Instance instance) const OVERRIDE; virtual webkit::ppapi::PluginDelegate::PlatformGraphics2D* GetPlatformGraphics2D(PP_Resource resource) OVERRIDE; + virtual base::ProcessId GetPluginPID() const OVERRIDE; virtual bool HasUserGesture(PP_Instance instance) const OVERRIDE; virtual int GetRoutingIDForWidget(PP_Instance instance) const OVERRIDE; virtual gfx::Point PluginPointToRenderView( diff --git a/content/renderer/pepper/pepper_in_process_resource_creation.cc b/content/renderer/pepper/pepper_in_process_resource_creation.cc index d695697..0738056 100644 --- a/content/renderer/pepper/pepper_in_process_resource_creation.cc +++ b/content/renderer/pepper/pepper_in_process_resource_creation.cc @@ -22,6 +22,7 @@ #include "ppapi/proxy/graphics_2d_resource.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/printing_resource.h" +#include "ppapi/proxy/url_loader_resource.h" #include "ppapi/proxy/url_request_info_resource.h" #include "ppapi/proxy/url_response_info_resource.h" #include "ppapi/proxy/websocket_resource.h" @@ -114,6 +115,13 @@ PP_Resource PepperInProcessResourceCreation::CreateTrueTypeFont( return 0; } +PP_Resource PepperInProcessResourceCreation::CreateURLLoader( + PP_Instance instance) { + return (new ppapi::proxy::URLLoaderResource( + host_impl_->in_process_router()->GetPluginConnection(), + instance))->GetReference(); +} + PP_Resource PepperInProcessResourceCreation::CreateURLRequestInfo( PP_Instance instance) { return (new ppapi::proxy::URLRequestInfoResource( diff --git a/content/renderer/pepper/pepper_in_process_resource_creation.h b/content/renderer/pepper/pepper_in_process_resource_creation.h index 847320b..8903afd 100644 --- a/content/renderer/pepper/pepper_in_process_resource_creation.h +++ b/content/renderer/pepper/pepper_in_process_resource_creation.h @@ -61,6 +61,8 @@ class PepperInProcessResourceCreation virtual PP_Resource CreateTrueTypeFont( PP_Instance instance, const struct PP_TrueTypeFontDesc_Dev* desc) OVERRIDE; + virtual PP_Resource CreateURLLoader( + PP_Instance instance) OVERRIDE; virtual PP_Resource CreateURLRequestInfo( PP_Instance instance) OVERRIDE; virtual PP_Resource CreateURLResponseInfo( diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.cc b/content/renderer/pepper/pepper_plugin_delegate_impl.cc index 110e1bc..a3625b8 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.cc @@ -46,12 +46,14 @@ #include "content/renderer/pepper/pepper_file_system_host.h" #include "content/renderer/pepper/pepper_hung_plugin_filter.h" #include "content/renderer/pepper/pepper_in_process_resource_creation.h" +#include "content/renderer/pepper/pepper_in_process_router.h" #include "content/renderer/pepper/pepper_platform_audio_input_impl.h" #include "content/renderer/pepper/pepper_platform_audio_output_impl.h" #include "content/renderer/pepper/pepper_platform_context_3d_impl.h" #include "content/renderer/pepper/pepper_platform_image_2d_impl.h" #include "content/renderer/pepper/pepper_platform_video_capture_impl.h" #include "content/renderer/pepper/pepper_proxy_channel_delegate_impl.h" +#include "content/renderer/pepper/pepper_url_loader_host.h" #include "content/renderer/pepper/renderer_ppapi_host_impl.h" #include "content/renderer/render_thread_impl.h" #include "content/renderer/render_view_impl.h" @@ -67,11 +69,16 @@ #include "ppapi/host/ppapi_host.h" #include "ppapi/proxy/host_dispatcher.h" #include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/url_loader_resource.h" +#include "ppapi/shared_impl/api_id.h" #include "ppapi/shared_impl/file_path.h" #include "ppapi/shared_impl/platform_file.h" +#include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/ppapi_permissions.h" #include "ppapi/shared_impl/ppapi_preferences.h" #include "ppapi/shared_impl/ppb_device_ref_shared.h" +#include "ppapi/shared_impl/ppp_instance_combined.h" +#include "ppapi/shared_impl/resource_tracker.h" #include "ppapi/thunk/enter.h" #include "ppapi/thunk/ppb_tcp_server_socket_private_api.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" @@ -91,6 +98,7 @@ #include "webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h" #include "webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h" #include "webkit/plugins/ppapi/resource_helper.h" +#include "webkit/plugins/ppapi/url_response_info_util.h" #include "webkit/plugins/webplugininfo.h" using WebKit::WebView; @@ -1335,6 +1343,64 @@ void PepperPluginDelegateImpl::SaveURLAs(const GURL& url) { render_view_->routing_id(), url, referrer)); } +void PepperPluginDelegateImpl::HandleDocumentLoad( + webkit::ppapi::PluginInstance* instance, + const WebKit::WebURLResponse& response) { + DCHECK(!instance->document_loader()); + + PP_Instance pp_instance = instance->pp_instance(); + RendererPpapiHostImpl* host_impl = static_cast<RendererPpapiHostImpl*>( + instance->module()->GetEmbedderState()); + + // Create a loader resource host for this load. Note that we have to set + // the document_loader before issuing the in-process + // PPP_Instance.HandleDocumentLoad call below, since this may reentrantly + // call into the instance and expect it to be valid. + PepperURLLoaderHost* loader_host = + new PepperURLLoaderHost(host_impl, true, pp_instance, 0); + instance->set_document_loader(loader_host); + loader_host->didReceiveResponse(NULL, response); + + // This host will be pending until the resource object attaches to it. + int pending_host_id = host_impl->GetPpapiHost()->AddPendingResourceHost( + scoped_ptr<ppapi::host::ResourceHost>(loader_host)); + DCHECK(pending_host_id); + ppapi::URLResponseInfoData data = + webkit::ppapi::DataFromWebURLResponse(pp_instance, response); + + if (host_impl->in_process_router()) { + // Running in-process, we can just create the resource and call the + // PPP_Instance function directly. + scoped_refptr<ppapi::proxy::URLLoaderResource> loader_resource( + new ppapi::proxy::URLLoaderResource( + host_impl->in_process_router()->GetPluginConnection(), + pp_instance, pending_host_id, data)); + + PP_Resource loader_pp_resource = loader_resource->GetReference(); + if (!instance->instance_interface()->HandleDocumentLoad( + instance->pp_instance(), loader_pp_resource)) + loader_resource->Close(); + // We don't pass a ref into the plugin, if it wants one, it will have taken + // an additional one. + ppapi::PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource( + loader_pp_resource); + + // Danger! If the plugin doesn't take a ref in HandleDocumentLoad, the + // resource host will be destroyed as soon as our scoped_refptr for the + // resource goes out of scope. + // + // Null it out so people don't accidentally add code below that uses it. + loader_host = NULL; + } else { + // Running out-of-process. Initiate an IPC call to notify the plugin + // process. + ppapi::proxy::HostDispatcher* dispatcher = + ppapi::proxy::HostDispatcher::GetForInstance(pp_instance); + dispatcher->Send(new PpapiMsg_PPPInstance_HandleDocumentLoad( + ppapi::API_ID_PPP_INSTANCE, pp_instance, pending_host_id, data)); + } +} + base::SharedMemory* PepperPluginDelegateImpl::CreateAnonymousSharedMemory( size_t size) { return RenderThread::Get()->HostAllocateSharedMemoryBuffer(size).release(); diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.h b/content/renderer/pepper/pepper_plugin_delegate_impl.h index 2f178ef..c694d54 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.h +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.h @@ -321,6 +321,9 @@ class PepperPluginDelegateImpl PP_DeviceType_Dev type, const EnumerateDevicesCallback& callback) OVERRIDE; virtual void StopEnumerateDevices(int request_id) OVERRIDE; + virtual void HandleDocumentLoad( + webkit::ppapi::PluginInstance* instance, + const WebKit::WebURLResponse& response) OVERRIDE; // RenderViewObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; diff --git a/content/renderer/pepper/pepper_url_loader_host.cc b/content/renderer/pepper/pepper_url_loader_host.cc new file mode 100644 index 0000000..b88ccdf --- /dev/null +++ b/content/renderer/pepper/pepper_url_loader_host.cc @@ -0,0 +1,380 @@ +// Copyright (c) 2013 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 "content/renderer/pepper/pepper_url_loader_host.h" + +#include "content/public/renderer/renderer_ppapi_host.h" +#include "net/base/net_errors.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebURLError.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebURLLoader.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebURLResponse.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderOptions.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/url_request_info_util.h" +#include "webkit/plugins/ppapi/url_response_info_util.h" + +using WebKit::WebFrame; +using WebKit::WebString; +using WebKit::WebURL; +using WebKit::WebURLError; +using WebKit::WebURLLoader; +using WebKit::WebURLLoaderOptions; +using WebKit::WebURLRequest; +using WebKit::WebURLResponse; + +#ifdef _MSC_VER +// Do not warn about use of std::copy with raw pointers. +#pragma warning(disable : 4996) +#endif + +namespace content { + +PepperURLLoaderHost::PepperURLLoaderHost(RendererPpapiHost* host, + bool main_document_loader, + PP_Instance instance, + PP_Resource resource) + : ResourceHost(host->GetPpapiHost(), instance, resource), + renderer_ppapi_host_(host), + main_document_loader_(main_document_loader), + has_universal_access_(false), + bytes_sent_(0), + total_bytes_to_be_sent_(-1), + bytes_received_(0), + total_bytes_to_be_received_(-1) { + DCHECK((main_document_loader && !resource) || + (!main_document_loader && resource)); +} + +PepperURLLoaderHost::~PepperURLLoaderHost() { + // Normally deleting this object will delete the loader which will implicitly + // cancel the load. But this won't happen for the main document loader. So it + // would be nice to issue a Close() here. + // + // However, the PDF plugin will cancel the document load and then close the + // resource (which is reasonable). It then makes a second request to load the + // document so it can set the "want progress" flags (which is unreasonable -- + // we should probably provide download progress on document loads). + // + // But a Close() on the main document (even if the request is already + // canceled) will cancel all pending subresources, of which the second + // request is one, and the load will fail. Even if we fixed the PDF reader to + // change the timing or to send progress events to avoid the second request, + // we don't want to cancel other loads when the main one is closed. + // + // "Leaking" the main document load here by not closing it will only affect + // plugins handling main document loads (which are very few, mostly only PDF) + // that dereference without explicitly closing the main document load (which + // PDF doesn't do -- it explicitly closes it before issuing the second + // request). And the worst thing that will happen is that any remaining data + // will get queued inside WebKit. + if (main_document_loader_) { + // The PluginInstance has a non-owning pointer to us. + webkit::ppapi::PluginInstance* instance_object = + renderer_ppapi_host_->GetPluginInstance(pp_instance()); + if (instance_object) { + DCHECK(instance_object->document_loader() == this); + instance_object->set_document_loader(NULL); + } + } + + // There is a path whereby the destructor for the loader_ member can + // invoke InstanceWasDeleted() upon this URLLoaderResource, thereby + // re-entering the scoped_ptr destructor with the same scoped_ptr object + // via loader_.reset(). Be sure that loader_ is first NULL then destroy + // the scoped_ptr. See http://crbug.com/159429. + scoped_ptr<WebKit::WebURLLoader> for_destruction_only(loader_.release()); + + for (size_t i = 0; i < pending_replies_.size(); i++) + delete pending_replies_[i]; +} + +int32_t PepperURLLoaderHost::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + IPC_BEGIN_MESSAGE_MAP(PepperURLLoaderHost, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_URLLoader_Open, + OnHostMsgOpen) + PPAPI_DISPATCH_HOST_RESOURCE_CALL( + PpapiHostMsg_URLLoader_SetDeferLoading, + OnHostMsgSetDeferLoading) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( + PpapiHostMsg_URLLoader_Close, + OnHostMsgClose); + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( + PpapiHostMsg_URLLoader_GrantUniversalAccess, + OnHostMsgGrantUniversalAccess) + IPC_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +void PepperURLLoaderHost::willSendRequest( + WebURLLoader* loader, + WebURLRequest& new_request, + const WebURLResponse& redirect_response) { + if (!request_data_.follow_redirects) { + SaveResponse(redirect_response); + SetDefersLoading(true); + } +} + +void PepperURLLoaderHost::didSendData( + WebURLLoader* loader, + unsigned long long bytes_sent, + unsigned long long total_bytes_to_be_sent) { + // TODO(darin): Bounds check input? + bytes_sent_ = static_cast<int64_t>(bytes_sent); + total_bytes_to_be_sent_ = static_cast<int64_t>(total_bytes_to_be_sent); + UpdateProgress(); +} + +void PepperURLLoaderHost::didReceiveResponse(WebURLLoader* loader, + const WebURLResponse& response) { + // Sets -1 if the content length is unknown. Send before issuing callback. + total_bytes_to_be_received_ = response.expectedContentLength(); + UpdateProgress(); + + SaveResponse(response); +} + +void PepperURLLoaderHost::didDownloadData(WebURLLoader* loader, + int data_length) { + bytes_received_ += data_length; + UpdateProgress(); +} + +void PepperURLLoaderHost::didReceiveData(WebURLLoader* loader, + const char* data, + int data_length, + int encoded_data_length) { + // Note that |loader| will be NULL for document loads. + bytes_received_ += data_length; + UpdateProgress(); + + PpapiPluginMsg_URLLoader_SendData* message = + new PpapiPluginMsg_URLLoader_SendData; + message->WriteData(data, data_length); + SendUpdateToPlugin(message); +} + +void PepperURLLoaderHost::didFinishLoading(WebURLLoader* loader, + double finish_time) { + // Note that |loader| will be NULL for document loads. + SendUpdateToPlugin(new PpapiPluginMsg_URLLoader_FinishedLoading(PP_OK)); +} + +void PepperURLLoaderHost::didFail(WebURLLoader* loader, + const WebURLError& error) { + // Note that |loader| will be NULL for document loads. + int32_t pp_error = PP_ERROR_FAILED; + if (error.domain.equals(WebString::fromUTF8(net::kErrorDomain))) { + // TODO(bbudge): Extend pp_errors.h to cover interesting network errors + // from the net error domain. + switch (error.reason) { + case net::ERR_ACCESS_DENIED: + case net::ERR_NETWORK_ACCESS_DENIED: + pp_error = PP_ERROR_NOACCESS; + break; + } + } else { + // It's a WebKit error. + pp_error = PP_ERROR_NOACCESS; + } + + SendUpdateToPlugin(new PpapiPluginMsg_URLLoader_FinishedLoading(pp_error)); +} + +void PepperURLLoaderHost::DidConnectPendingHostToResource() { + for (size_t i = 0; i < pending_replies_.size(); i++) { + host()->SendUnsolicitedReply(pp_resource(), *pending_replies_[i]); + delete pending_replies_[i]; + } + pending_replies_.clear(); +} + +int32_t PepperURLLoaderHost::OnHostMsgOpen( + ppapi::host::HostMessageContext* context, + const ppapi::URLRequestInfoData& request_data) { + // An "Open" isn't a resource Call so has no reply, but failure to open + // implies a load failure. To make it harder to forget to send the load + // failed reply from the open handler, we instead catch errors and convert + // them to load failed messages. + int32_t ret = InternalOnHostMsgOpen(context, request_data); + DCHECK(ret != PP_OK_COMPLETIONPENDING); + + if (ret != PP_OK) + SendUpdateToPlugin(new PpapiPluginMsg_URLLoader_FinishedLoading(ret)); + return PP_OK; +} + +// Since this is wrapped by OnHostMsgOpen, we can return errors here and they +// will be translated into a FinishedLoading call automatically. +int32_t PepperURLLoaderHost::InternalOnHostMsgOpen( + ppapi::host::HostMessageContext* context, + const ppapi::URLRequestInfoData& request_data) { + // Main document loads are already open, so don't allow people to open them + // again. + if (main_document_loader_) + return PP_ERROR_INPROGRESS; + + // Create a copy of the request data since CreateWebURLRequest will populate + // the file refs. + ppapi::URLRequestInfoData filled_in_request_data = request_data; + + if (webkit::ppapi::URLRequestRequiresUniversalAccess( + filled_in_request_data) && + !has_universal_access_) { + ppapi::PpapiGlobals::Get()->LogWithSource( + pp_instance(), PP_LOGLEVEL_ERROR, std::string(), + "PPB_URLLoader.Open: The URL you're requesting is " + " on a different security origin than your plugin. To request " + " cross-origin resources, see " + " PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS."); + return PP_ERROR_NOACCESS; + } + + if (loader_.get()) + return PP_ERROR_INPROGRESS; + + WebFrame* frame = GetFrame(); + if (!frame) + return PP_ERROR_FAILED; + WebURLRequest web_request; + if (!webkit::ppapi::CreateWebURLRequest(&filled_in_request_data, frame, + &web_request)) + return PP_ERROR_FAILED; + web_request.setRequestorProcessID(renderer_ppapi_host_->GetPluginPID()); + + WebURLLoaderOptions options; + if (has_universal_access_) { + options.allowCredentials = true; + options.crossOriginRequestPolicy = + WebURLLoaderOptions::CrossOriginRequestPolicyAllow; + } else { + // All other HTTP requests are untrusted. + options.untrustedHTTP = true; + if (filled_in_request_data.allow_cross_origin_requests) { + // Allow cross-origin requests with access control. The request specifies + // if credentials are to be sent. + options.allowCredentials = filled_in_request_data.allow_credentials; + options.crossOriginRequestPolicy = + WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; + } else { + // Same-origin requests can always send credentials. + options.allowCredentials = true; + } + } + + loader_.reset(frame->createAssociatedURLLoader(options)); + if (!loader_.get()) + return PP_ERROR_FAILED; + + // Don't actually save the request until we know we're going to load. + request_data_ = filled_in_request_data; + loader_->loadAsynchronously(web_request, this); + + // Although the request is technically pending, this is not a "Call" message + // so we don't return COMPLETIONPENDING. + return PP_OK; +} + +int32_t PepperURLLoaderHost::OnHostMsgSetDeferLoading( + ppapi::host::HostMessageContext* context, + bool defers_loading) { + SetDefersLoading(defers_loading); + return PP_OK; +} + +int32_t PepperURLLoaderHost::OnHostMsgClose( + ppapi::host::HostMessageContext* context) { + Close(); + return PP_OK; +} + +int32_t PepperURLLoaderHost::OnHostMsgGrantUniversalAccess( + ppapi::host::HostMessageContext* context) { + // Only plugins with private permission can bypass same origin. + if (!host()->permissions().HasPermission(ppapi::PERMISSION_PRIVATE)) + return PP_ERROR_FAILED; + has_universal_access_ = true; + return PP_OK; +} + +void PepperURLLoaderHost::SendUpdateToPlugin(IPC::Message* msg) { + if (pp_resource()) { + host()->SendUnsolicitedReply(pp_resource(), *msg); + delete msg; + } else { + pending_replies_.push_back(msg); + } +} + +void PepperURLLoaderHost::Close() { + if (loader_.get()) + loader_->cancel(); + else if (main_document_loader_) + GetFrame()->stopLoading(); +} + +WebKit::WebFrame* PepperURLLoaderHost::GetFrame() { + webkit::ppapi::PluginInstance* instance_object = + renderer_ppapi_host_->GetPluginInstance(pp_instance()); + if (!instance_object) + return NULL; + return instance_object->container()->element().document().frame(); +} + +void PepperURLLoaderHost::SetDefersLoading(bool defers_loading) { + if (loader_.get()) + loader_->setDefersLoading(defers_loading); + + // TODO(brettw) bug 96770: We need a way to set the defers loading flag on + // main document loads (when the loader_ is null). +} + +void PepperURLLoaderHost::SaveResponse(const WebURLResponse& response) { + if (!main_document_loader_) { + // When we're the main document loader, we send the response data up front, + // so we don't want to trigger any callbacks in the plugin which aren't + // expected. We should not be getting redirects so the response sent + // up-front should be valid (plugin document loads happen after all + // redirects are processed since WebKit has to know the MIME type). + SendUpdateToPlugin( + new PpapiPluginMsg_URLLoader_ReceivedResponse( + webkit::ppapi::DataFromWebURLResponse(pp_instance(), response))); + } +} + +void PepperURLLoaderHost::UpdateProgress() { + bool record_download = request_data_.record_download_progress; + bool record_upload = request_data_.record_upload_progress; + if (record_download || record_upload) { + // Here we go through some effort to only send the exact information that + // the requestor wanted in the request flags. It would be just as + // efficient to send all of it, but we don't want people to rely on + // getting download progress when they happen to set the upload progress + // flag. + ppapi::proxy::ResourceMessageReplyParams params; + SendUpdateToPlugin(new PpapiPluginMsg_URLLoader_UpdateProgress( + record_upload ? bytes_sent_ : -1, + record_upload ? total_bytes_to_be_sent_ : -1, + record_download ? bytes_received_ : -1, + record_download ? total_bytes_to_be_received_ : -1)); + } +} + +} // namespace content
\ No newline at end of file diff --git a/content/renderer/pepper/pepper_url_loader_host.h b/content/renderer/pepper/pepper_url_loader_host.h new file mode 100644 index 0000000..111194a --- /dev/null +++ b/content/renderer/pepper/pepper_url_loader_host.h @@ -0,0 +1,138 @@ +// Copyright (c) 2013 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. + +#ifndef CONTENT_RENDERER_PEPPER_PEPPER_URL_LOADER_HOST_H_ +#define CONTENT_RENDERER_PEPPER_PEPPER_URL_LOADER_HOST_H_ + +#include <vector> + +#include "content/common/content_export.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/proxy/resource_message_params.h" +#include "ppapi/shared_impl/url_request_info_data.h" +#include "ppapi/shared_impl/url_response_info_data.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebURLLoaderClient.h" + +namespace WebKit { +class WebFrame; +class WebURLLoader; +} + +namespace content { + +class RendererPpapiHost; + +class PepperURLLoaderHost + : public ppapi::host::ResourceHost, + public WebKit::WebURLLoaderClient { + public: + // If main_document_loader is true, PP_Resource must be 0 since it will be + // pending until the plugin resource attaches to it. + PepperURLLoaderHost(RendererPpapiHost* host, + bool main_document_loader, + PP_Instance instance, + PP_Resource resource); + virtual ~PepperURLLoaderHost(); + + // ResourceHost implementation. + virtual int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) OVERRIDE; + + // WebKit::WebURLLoaderClient implementation. + virtual void willSendRequest(WebKit::WebURLLoader* loader, + WebKit::WebURLRequest& new_request, + const WebKit::WebURLResponse& redir_response); + virtual void didSendData(WebKit::WebURLLoader* loader, + unsigned long long bytes_sent, + unsigned long long total_bytes_to_be_sent); + virtual void didReceiveResponse(WebKit::WebURLLoader* loader, + const WebKit::WebURLResponse& response); + virtual void didDownloadData(WebKit::WebURLLoader* loader, + int data_length); + virtual void didReceiveData(WebKit::WebURLLoader* loader, + const char* data, + int data_length, + int encoded_data_length); + virtual void didFinishLoading(WebKit::WebURLLoader* loader, + double finish_time); + virtual void didFail(WebKit::WebURLLoader* loader, + const WebKit::WebURLError& error); + + private: + // ResourceHost protected overrides. + virtual void DidConnectPendingHostToResource() OVERRIDE; + + // IPC messages + int32_t OnHostMsgOpen(ppapi::host::HostMessageContext* context, + const ppapi::URLRequestInfoData& request_data); + int32_t InternalOnHostMsgOpen(ppapi::host::HostMessageContext* context, + const ppapi::URLRequestInfoData& request_data); + int32_t OnHostMsgSetDeferLoading(ppapi::host::HostMessageContext* context, + bool defers_loading); + int32_t OnHostMsgClose(ppapi::host::HostMessageContext* context); + int32_t OnHostMsgGrantUniversalAccess( + ppapi::host::HostMessageContext* context); + + // Sends or queues an unsolicited message to the plugin resource. This + // handles the case where we have created a pending host resource and the + // plugin has not connected to us yet. Such messages will be queued until the + // plugin resource connects. + // + // Takes ownership of the given pointer. + void SendUpdateToPlugin(IPC::Message* msg); + + void Close(); + + // Returns the frame for the current request. + WebKit::WebFrame* GetFrame(); + + // Calls SetDefersLoading on the current load. This encapsulates the logic + // differences between document loads and regular ones. + void SetDefersLoading(bool defers_loading); + + // Converts a WebURLResponse to a URLResponseInfo and saves it. + void SaveResponse(const WebKit::WebURLResponse& response); + + // Sends the UpdateProgress message (if necessary) to the plugin. + void UpdateProgress(); + + // Non-owning pointer. + RendererPpapiHost* renderer_ppapi_host_; + + // If true, then the plugin instance is a full-frame plugin and we're just + // wrapping the main document's loader (i.e. loader_ is null). + bool main_document_loader_; + + // The data that generated the request. + ppapi::URLRequestInfoData request_data_; + + // Set to true when this loader can ignore same originl policy. + bool has_universal_access_; + + // The loader associated with this request. MAY BE NULL. + // + // This will be NULL if the load hasn't been opened yet, or if this is a main + // document loader (when registered as a mime type). Therefore, you should + // always NULL check this value before using it. In the case of a main + // document load, you would call the functions on the document to cancel the + // load, etc. since there is no loader. + scoped_ptr<WebKit::WebURLLoader> loader_; + + int64_t bytes_sent_; + int64_t total_bytes_to_be_sent_; + int64_t bytes_received_; + int64_t total_bytes_to_be_received_; + + // Messages sent while the resource host is pending. These will be forwarded + // to the plugin when the plugin side connects. The pointers are owned by + // this object and must be deleted. + std::vector<IPC::Message*> pending_replies_; + + DISALLOW_COPY_AND_ASSIGN(PepperURLLoaderHost); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_PEPPER_PEPPER_URL_LOADER_HOST_H_
\ No newline at end of file diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.cc b/content/renderer/pepper/renderer_ppapi_host_impl.cc index 32ce540..641d68e 100644 --- a/content/renderer/pepper/renderer_ppapi_host_impl.cc +++ b/content/renderer/pepper/renderer_ppapi_host_impl.cc @@ -201,6 +201,12 @@ WebKit::WebPluginContainer* RendererPpapiHostImpl::GetContainerForInstance( return instance_object->container(); } +base::ProcessId RendererPpapiHostImpl::GetPluginPID() const { + if (dispatcher_) + return dispatcher_->channel()->peer_pid(); + return base::kNullProcessId; +} + bool RendererPpapiHostImpl::HasUserGesture(PP_Instance instance) const { PluginInstance* instance_object = GetAndValidateInstance(instance); if (!instance_object) diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.h b/content/renderer/pepper/renderer_ppapi_host_impl.h index 4d3d0b4..d1256ac 100644 --- a/content/renderer/pepper/renderer_ppapi_host_impl.h +++ b/content/renderer/pepper/renderer_ppapi_host_impl.h @@ -82,7 +82,7 @@ class RendererPpapiHostImpl CreateInProcessResourceCreationAPI( webkit::ppapi::PluginInstance* instance); - // RendererPpapiHost. + // RendererPpapiHost implementation. virtual ppapi::host::PpapiHost* GetPpapiHost() OVERRIDE; virtual bool IsValidInstance(PP_Instance instance) const OVERRIDE; virtual webkit::ppapi::PluginInstance* GetPluginInstance( @@ -93,6 +93,7 @@ class RendererPpapiHostImpl PP_Instance instance) const OVERRIDE; virtual WebKit::WebPluginContainer* GetContainerForInstance( PP_Instance instance) const OVERRIDE; + virtual base::ProcessId GetPluginPID() const OVERRIDE; virtual bool HasUserGesture(PP_Instance instance) const OVERRIDE; virtual int GetRoutingIDForWidget(PP_Instance instance) const OVERRIDE; virtual gfx::Point PluginPointToRenderView( @@ -121,7 +122,9 @@ class RendererPpapiHostImpl webkit::ppapi::PluginModule* module_; // Non-owning pointer. - ppapi::proxy::HostDispatcher* dispatcher_; // Non-owning pointer. + // The dispatcher we use to send messagse when the plugin is out-of-process. + // Will be null when running in-process. Non-owning pointer. + ppapi::proxy::HostDispatcher* dispatcher_; scoped_ptr<ppapi::host::PpapiHost> ppapi_host_; diff --git a/ppapi/api/ppp_instance.idl b/ppapi/api/ppp_instance.idl index a5026ae..f178b7a 100644 --- a/ppapi/api/ppp_instance.idl +++ b/ppapi/api/ppp_instance.idl @@ -207,7 +207,7 @@ interface PPP_Instance { /** * HandleDocumentLoad() is called after initialize for a full-frame - * module that was instantiated based on the MIME type of a DOMWindow + * instance that was instantiated based on the MIME type of a DOMWindow * navigation. This situation only applies to modules that are pre-registered * to handle certain MIME types. If you haven't specifically registered to * handle a MIME type or aren't positive this applies to you, your @@ -230,7 +230,8 @@ interface PPP_Instance { * @param[in] url_loader An open <code>PPB_URLLoader</code> instance. * * @return <code>PP_TRUE</code> if the data was handled, - * <code>PP_FALSE</code> otherwise. + * <code>PP_FALSE</code> otherwise. If you return false, the load will be + * canceled for you. */ PP_Bool HandleDocumentLoad( /* A PP_Instance identifying one instance of a module. */ diff --git a/ppapi/c/ppp_instance.h b/ppapi/c/ppp_instance.h index bdc2883..d2641f9 100644 --- a/ppapi/c/ppp_instance.h +++ b/ppapi/c/ppp_instance.h @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* From ppp_instance.idl modified Thu Jun 28 15:08:39 2012. */ +/* From ppp_instance.idl modified Thu Apr 25 13:07:47 2013. */ #ifndef PPAPI_C_PPP_INSTANCE_H_ #define PPAPI_C_PPP_INSTANCE_H_ @@ -146,7 +146,7 @@ struct PPP_Instance_1_1 { void (*DidChangeFocus)(PP_Instance instance, PP_Bool has_focus); /** * HandleDocumentLoad() is called after initialize for a full-frame - * module that was instantiated based on the MIME type of a DOMWindow + * instance that was instantiated based on the MIME type of a DOMWindow * navigation. This situation only applies to modules that are pre-registered * to handle certain MIME types. If you haven't specifically registered to * handle a MIME type or aren't positive this applies to you, your @@ -169,7 +169,8 @@ struct PPP_Instance_1_1 { * @param[in] url_loader An open <code>PPB_URLLoader</code> instance. * * @return <code>PP_TRUE</code> if the data was handled, - * <code>PP_FALSE</code> otherwise. + * <code>PP_FALSE</code> otherwise. If you return false, the load will be + * canceled for you. */ PP_Bool (*HandleDocumentLoad)(PP_Instance instance, PP_Resource url_loader); }; diff --git a/ppapi/c/private/ppb_proxy_private.h b/ppapi/c/private/ppb_proxy_private.h index eac3f57..b185c2c 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;5" +#define PPB_PROXY_PRIVATE_INTERFACE "PPB_Proxy_Private;6" // Exposes functions needed by the out-of-process proxy to call into the // renderer PPAPI implementation. @@ -34,11 +34,6 @@ struct PPB_Proxy_Private { 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); - // Allows adding additional refcounts to the PluginModule that owns the // proxy dispatcher (and all interface proxies). For every AddRef call // there must be a corresponding release call. diff --git a/ppapi/ppapi_proxy.gypi b/ppapi/ppapi_proxy.gypi index 242f899..82e3c5a5 100644 --- a/ppapi/ppapi_proxy.gypi +++ b/ppapi/ppapi_proxy.gypi @@ -125,8 +125,6 @@ 'proxy/ppb_tcp_socket_private_proxy.h', 'proxy/ppb_testing_proxy.cc', 'proxy/ppb_testing_proxy.h', - 'proxy/ppb_url_loader_proxy.cc', - 'proxy/ppb_url_loader_proxy.h', 'proxy/ppb_var_deprecated_proxy.cc', 'proxy/ppb_var_deprecated_proxy.h', 'proxy/ppb_video_decoder_proxy.cc', @@ -176,6 +174,8 @@ 'proxy/truetype_font_singleton_resource.h', 'proxy/udp_socket_private_resource.cc', 'proxy/udp_socket_private_resource.h', + 'proxy/url_loader_resource.cc', + 'proxy/url_loader_resource.h', 'proxy/url_request_info_resource.cc', 'proxy/url_request_info_resource.h', 'proxy/url_response_info_resource.cc', diff --git a/ppapi/proxy/interface_list.cc b/ppapi/proxy/interface_list.cc index 4bd8b40..963daf3 100644 --- a/ppapi/proxy/interface_list.cc +++ b/ppapi/proxy/interface_list.cc @@ -104,7 +104,6 @@ #include "ppapi/proxy/ppb_tcp_server_socket_private_proxy.h" #include "ppapi/proxy/ppb_tcp_socket_private_proxy.h" #include "ppapi/proxy/ppb_testing_proxy.h" -#include "ppapi/proxy/ppb_url_loader_proxy.h" #include "ppapi/proxy/ppb_var_deprecated_proxy.h" #include "ppapi/proxy/ppb_video_decoder_proxy.h" #include "ppapi/proxy/ppb_x509_certificate_private_proxy.h" @@ -244,7 +243,6 @@ InterfaceList::InterfaceList() { // Do not add more stuff here, they should be added to interface_list*.h // TODO(brettw) remove these. AddPPB(PPB_Instance_Proxy::GetInfoPrivate(), PERMISSION_PRIVATE); - AddPPB(PPB_URLLoader_Proxy::GetTrustedInfo(), PERMISSION_PRIVATE); AddPPB(PPB_Var_Deprecated_Proxy::GetInfo(), PERMISSION_DEV); // TODO(tomfinegan): Figure out where to put these once we refactor things diff --git a/ppapi/proxy/plugin_resource.h b/ppapi/proxy/plugin_resource.h index 1535278..9448326 100644 --- a/ppapi/proxy/plugin_resource.h +++ b/ppapi/proxy/plugin_resource.h @@ -131,6 +131,8 @@ class PPAPI_PROXY_EXPORT PluginResource : public Resource { IPC::Message* reply_msg, ResourceMessageReplyParams* reply_params); + const Connection& connection() { return connection_; } + private: IPC::Sender* GetSender(Destination dest) { return dest == RENDERER ? connection_.renderer_sender : diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index 622cfb3..b7169d3 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -589,10 +589,10 @@ IPC_MESSAGE_ROUTED3(PpapiMsg_PPPInstance_DidChangeView, IPC_MESSAGE_ROUTED2(PpapiMsg_PPPInstance_DidChangeFocus, PP_Instance /* instance */, PP_Bool /* has_focus */) -IPC_SYNC_MESSAGE_ROUTED2_1(PpapiMsg_PPPInstance_HandleDocumentLoad, - PP_Instance /* instance */, - ppapi::HostResource /* url_loader */, - PP_Bool /* result */) +IPC_MESSAGE_ROUTED3(PpapiMsg_PPPInstance_HandleDocumentLoad, + PP_Instance /* instance */, + int /* pending_loader_host_id */, + ppapi::URLResponseInfoData /* response */) // PPP_Messaging. IPC_MESSAGE_ROUTED2(PpapiMsg_PPPMessaging_HandleMessage, @@ -631,19 +631,6 @@ IPC_MESSAGE_ROUTED2(PpapiMsg_PPPTextInput_RequestSurroundingText, PP_Instance /* instance */, uint32_t /* desired_number_of_characters */) -// PPB_URLLoader -// (Messages from browser to plugin to notify it of changes in state.) -// -// NOTE: The ReadResponseBody_Ack message is a custom generated message -// with the following fields appended: -// ppapi::HostResource -// response data (array of bytes stored via WriteData) -// int result -// -IPC_MESSAGE_ROUTED0(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack) -IPC_MESSAGE_ROUTED2(PpapiMsg_PPBURLLoader_CallbackComplete, - ppapi::HostResource /* loader */, - int32_t /* result */) #if !defined(OS_NACL) && !defined(NACL_WIN64) // PPB_Broker. IPC_MESSAGE_ROUTED3( @@ -722,11 +709,6 @@ IPC_MESSAGE_ROUTED3(PpapiMsg_PPBTCPSocket_SetBoolOptionACK, uint32 /* socket_id */, bool /* succeeded */) -// PPB_URLLoader_Trusted -IPC_MESSAGE_ROUTED1( - PpapiMsg_PPBURLLoader_UpdateProgress, - ppapi::proxy::PPBURLLoader_UpdateProgress_Params /* params */) - // PPB_TCPServerSocket_Private. // |socket_resource| should not be used as Resource in browser. The @@ -1002,30 +984,6 @@ IPC_MESSAGE_ROUTED4(PpapiHostMsg_PPBInstance_UpdateSurroundingText, uint32_t /* caret */, uint32_t /* anchor */) -// PPB_URLLoader. -IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBURLLoader_Create, - PP_Instance /* instance */, - ppapi::HostResource /* result */) -IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLLoader_Open, - ppapi::HostResource /* loader */, - ppapi::URLRequestInfoData /* request_data */) -IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_FollowRedirect, - ppapi::HostResource /* loader */) -IPC_SYNC_MESSAGE_ROUTED1_2( - PpapiHostMsg_PPBURLLoader_GetResponseInfo, - ppapi::HostResource /* loader */, - bool /* success */, - ppapi::URLResponseInfoData /* result */) -IPC_MESSAGE_ROUTED2(PpapiHostMsg_PPBURLLoader_ReadResponseBody, - ppapi::HostResource /* loader */, - int32_t /* bytes_to_read */) -IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_FinishStreamingToFile, - ppapi::HostResource /* loader */) -IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_Close, - ppapi::HostResource /* loader */) -IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBURLLoader_GrantUniversalAccess, - ppapi::HostResource /* loader */) - // PPB_Var. IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBVar_AddRefObject, int64 /* object_id */, @@ -1511,7 +1469,63 @@ IPC_MESSAGE_CONTROL0(PpapiHostMsg_Printing_GetDefaultPrintSettings) IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Printing_GetDefaultPrintSettingsReply, PP_PrintSettings_Dev /* print_settings */) +// URLLoader ------------------------------------------------------------------ + +IPC_MESSAGE_CONTROL0(PpapiHostMsg_URLLoader_Create) + +// These messages correspond to PPAPI calls and all should get a +// CallbackComplete message. +IPC_MESSAGE_CONTROL1(PpapiHostMsg_URLLoader_Open, + ppapi::URLRequestInfoData /* request_data */) + +// The plugin can tell the host to defer a load to hold off on sending more +// data because the buffer in the plugin is full. When defers_loading is set to +// false, data streaming will resume. +// +// When auditing redirects (no auto follow) the load will be automatically +// deferred each time we get a redirect. The plugin will reset this to false +// by sending this message when it wants to continue following the redirect. +// +// When streaming data, the host may still send more data after this call (for +// example, it could already be in-flight at the time of this request). +IPC_MESSAGE_CONTROL1(PpapiHostMsg_URLLoader_SetDeferLoading, + bool /* defers_loading */) + +// Closes the URLLoader. There is no reply. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_URLLoader_Close) + +// Requests that cross-site restrictions be ignored. The plugin must have +// the private permission set. Otherwise this message will be ignored by the +// renderer. There is no reply. +IPC_MESSAGE_CONTROL0(PpapiHostMsg_URLLoader_GrantUniversalAccess) + +// Push notification that a response is available. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_URLLoader_ReceivedResponse, + ppapi::URLResponseInfoData /* response */) + +// Push notification with load data from the renderer. It is a custom generated +// message with the response data (array of bytes stored via WriteData) +// appended. +IPC_MESSAGE_CONTROL0(PpapiPluginMsg_URLLoader_SendData) + +// Push notification indicating that all data has been sent, either via +// SendData or by streaming it to a file. Note that since this is a push +// notification, we don't use the result field of the ResourceMessageReply. +IPC_MESSAGE_CONTROL1(PpapiPluginMsg_URLLoader_FinishedLoading, + int32_t /* result */) + +// Push notification from the renderer to the plugin to tell it about download +// and upload progress. This will only be sent if the plugin has requested +// progress updates, and only the fields requested by the plugin will be +// valid. +IPC_MESSAGE_CONTROL4(PpapiPluginMsg_URLLoader_UpdateProgress, + int64_t /* bytes_sent */, + int64_t /* total_bytes_to_be_sent */, + int64_t /* bytes_received */, + int64_t /* total_bytes_to_be_received */) + // Shared memory --------------------------------------------------------------- + // Creates shared memory on the host side, returning a handle to the shared // memory on the plugin and keeping the memory mapped in on the host. // We return a "host handle_id" that can be mapped back to the @@ -1522,7 +1536,8 @@ IPC_SYNC_MESSAGE_CONTROL2_2(PpapiHostMsg_SharedMemory_CreateSharedMemory, int /* host_handle_id */, ppapi::proxy::SerializedHandle /* plugin_handle */) -// WebSocket ------------------------------------------------------------------ +// WebSocket ------------------------------------------------------------------- + IPC_MESSAGE_CONTROL0(PpapiHostMsg_WebSocket_Create) // Establishes the connection to a server. This message requires diff --git a/ppapi/proxy/ppapi_proxy_test.cc b/ppapi/proxy/ppapi_proxy_test.cc index 19f41bb..2df72cc 100644 --- a/ppapi/proxy/ppapi_proxy_test.cc +++ b/ppapi/proxy/ppapi_proxy_test.cc @@ -41,11 +41,6 @@ void SetReserveInstanceIDCallback(PP_Module module, // worry about Instance uniqueness in tests, so we can ignore the call. } -int32_t GetURLLoaderBufferedBytes(PP_Resource url_loader) { - NOTREACHED(); - return 0; -} - void AddRefModule(PP_Module module) {} void ReleaseModule(PP_Module module) {} PP_Bool IsInModuleDestructor(PP_Module module) { return PP_FALSE; } @@ -54,7 +49,6 @@ PPB_Proxy_Private ppb_proxy_private = { &PluginCrashed, &GetInstanceForResource, &SetReserveInstanceIDCallback, - &GetURLLoaderBufferedBytes, &AddRefModule, &ReleaseModule, &IsInModuleDestructor diff --git a/ppapi/proxy/ppb_url_loader_proxy.cc b/ppapi/proxy/ppb_url_loader_proxy.cc deleted file mode 100644 index 425b61f..0000000 --- a/ppapi/proxy/ppb_url_loader_proxy.cc +++ /dev/null @@ -1,652 +0,0 @@ -// Copyright (c) 2012 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 <algorithm> -#include <deque> -#include <vector> - -#include "base/bind.h" -#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/ppb_url_loader.h" -#include "ppapi/c/private/ppb_proxy_private.h" -#include "ppapi/c/trusted/ppb_url_loader_trusted.h" -#include "ppapi/proxy/enter_proxy.h" -#include "ppapi/proxy/host_dispatcher.h" -#include "ppapi/proxy/plugin_dispatcher.h" -#include "ppapi/proxy/plugin_resource_tracker.h" -#include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/proxy/ppb_file_ref_proxy.h" -#include "ppapi/shared_impl/scoped_pp_resource.h" -#include "ppapi/shared_impl/tracked_callback.h" -#include "ppapi/thunk/enter.h" -#include "ppapi/thunk/ppb_url_loader_api.h" -#include "ppapi/thunk/ppb_url_request_info_api.h" -#include "ppapi/thunk/resource_creation_api.h" -#include "ppapi/thunk/thunk.h" - -#if defined(OS_LINUX) -#include <sys/shm.h> -#endif - -using ppapi::thunk::EnterResourceNoLock; -using ppapi::thunk::PPB_URLLoader_API; -using ppapi::thunk::ResourceCreationAPI; - -namespace ppapi { -namespace proxy { - -namespace { - -// The maximum size we'll read into the plugin without being explicitly -// asked for a larger buffer. -const int32_t kMaxReadBufferSize = 16777216; // 16MB - -#if !defined(OS_NACL) -// 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); - if (!dispatcher) - return; - - PPBURLLoader_UpdateProgress_Params params; - params.instance = pp_instance; - params.resource.SetHostResource(pp_instance, pp_resource); - params.bytes_sent = bytes_sent; - params.total_bytes_to_be_sent = total_bytes_to_be_sent; - params.bytes_received = bytes_received; - params.total_bytes_to_be_received = total_bytes_to_be_received; - dispatcher->Send(new PpapiMsg_PPBURLLoader_UpdateProgress( - API_ID_PPB_URL_LOADER, params)); -} -#endif // !defined(OS_NACL) - -InterfaceProxy* CreateURLLoaderProxy(Dispatcher* dispatcher) { - return new PPB_URLLoader_Proxy(dispatcher); -} - -} // namespace - -// URLLoader ------------------------------------------------------------------- - -class URLLoader : public Resource, public PPB_URLLoader_API { - public: - URLLoader(const HostResource& resource); - virtual ~URLLoader(); - - // Resource overrides. - virtual PPB_URLLoader_API* AsPPB_URLLoader_API() OVERRIDE; - - // PPB_URLLoader_API implementation. - virtual int32_t Open(PP_Resource request_id, - scoped_refptr<TrackedCallback> callback) OVERRIDE; - virtual int32_t Open(const URLRequestInfoData& data, - int requestor_pid, - scoped_refptr<TrackedCallback> callback) OVERRIDE; - virtual int32_t FollowRedirect( - scoped_refptr<TrackedCallback> callback) OVERRIDE; - virtual PP_Bool GetUploadProgress(int64_t* bytes_sent, - int64_t* total_bytes_to_be_sent) OVERRIDE; - virtual PP_Bool GetDownloadProgress( - int64_t* bytes_received, - int64_t* total_bytes_to_be_received) OVERRIDE; - virtual PP_Resource GetResponseInfo() OVERRIDE; - virtual int32_t ReadResponseBody( - void* buffer, - int32_t bytes_to_read, - scoped_refptr<TrackedCallback> callback) OVERRIDE; - virtual int32_t FinishStreamingToFile( - scoped_refptr<TrackedCallback> callback) OVERRIDE; - virtual void Close() OVERRIDE; - virtual void GrantUniversalAccess() OVERRIDE; - virtual void RegisterStatusCallback( - PP_URLLoaderTrusted_StatusCallback cb) OVERRIDE; - virtual bool GetResponseInfoData(URLResponseInfoData* data) OVERRIDE; - - // Called when the browser has new up/download progress to report. - void UpdateProgress(const PPBURLLoader_UpdateProgress_Params& params); - - // Called when the browser responds to our ReadResponseBody request. - void ReadResponseBodyAck(int32_t result, const char* data); - - // Called when any callback other than the read callback has been executed. - void CallbackComplete(int32_t result); - - private: - // 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); - - PluginDispatcher* GetDispatcher() const { - return PluginDispatcher::GetForResource(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_; - - // Current completion callback for the current phase of loading. We have only - // one thing (open, follow redirect, read, etc.) outstanding at once. - scoped_refptr<TrackedCallback> current_callback_; - - // When an asynchronous read is pending, this will contain the buffer to put - // the data. The current_callback_ will identify the 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. - PP_Resource response_info_; - - private: - DISALLOW_COPY_AND_ASSIGN(URLLoader); -}; - -URLLoader::URLLoader(const HostResource& resource) - : Resource(OBJECT_IS_PROXY, resource), - bytes_sent_(-1), - total_bytes_to_be_sent_(-1), - bytes_received_(-1), - total_bytes_to_be_received_(-1), - current_read_buffer_(NULL), - current_read_buffer_size_(0), - response_info_(0) { -} - -URLLoader::~URLLoader() { - if (response_info_) - PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(response_info_); -} - -PPB_URLLoader_API* URLLoader::AsPPB_URLLoader_API() { - return this; -} - -int32_t URLLoader::Open(PP_Resource request_id, - scoped_refptr<TrackedCallback> callback) { - EnterResourceNoLock<thunk::PPB_URLRequestInfo_API> enter(request_id, true); - if (enter.failed()) { - Log(PP_LOGLEVEL_ERROR, "PPB_URLLoader.Open: The URL you're requesting is " - " on a different security origin than your plugin. To request " - " cross-origin resources, see " - " PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS."); - return PP_ERROR_BADRESOURCE; - } - return Open(enter.object()->GetData(), 0, callback); -} - -int32_t URLLoader::Open(const URLRequestInfoData& data, - int requestor_pid, - scoped_refptr<TrackedCallback> callback) { - DCHECK_EQ(0, requestor_pid); // Used in-process only. - - if (TrackedCallback::IsPending(current_callback_)) - return PP_ERROR_INPROGRESS; - - current_callback_ = callback; - - GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Open( - API_ID_PPB_URL_LOADER, host_resource(), data)); - return PP_OK_COMPLETIONPENDING; -} - -int32_t URLLoader::FollowRedirect(scoped_refptr<TrackedCallback> callback) { - if (TrackedCallback::IsPending(current_callback_)) - return PP_ERROR_INPROGRESS; - - current_callback_ = callback; - - GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FollowRedirect( - API_ID_PPB_URL_LOADER, host_resource())); - return PP_OK_COMPLETIONPENDING; -} - -PP_Bool URLLoader::GetUploadProgress(int64_t* bytes_sent, - int64_t* total_bytes_to_be_sent) { - if (bytes_sent_ == -1) { - *bytes_sent = 0; - *total_bytes_to_be_sent = 0; - return PP_FALSE; - } - *bytes_sent = bytes_sent_; - *total_bytes_to_be_sent = total_bytes_to_be_sent_; - return PP_TRUE; -} - -PP_Bool URLLoader::GetDownloadProgress( - int64_t* bytes_received, - int64_t* total_bytes_to_be_received) { - if (bytes_received_ == -1) { - *bytes_received = 0; - *total_bytes_to_be_received = 0; - return PP_FALSE; - } - *bytes_received = bytes_received_; - *total_bytes_to_be_received = total_bytes_to_be_received_; - return PP_TRUE; -} - -PP_Resource URLLoader::GetResponseInfo() { - if (!response_info_) { - bool success = false; - URLResponseInfoData data; - GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_GetResponseInfo( - API_ID_PPB_URL_LOADER, host_resource(), &success, &data)); - if (!success) - return 0; - - // Create a proxy resource for the the file ref host resource if needed. - PP_Resource body_as_file_ref = 0; - if (!data.body_as_file_ref.resource.is_null()) { - body_as_file_ref = - PPB_FileRef_Proxy::DeserializeFileRef(data.body_as_file_ref); - } - - // Assumes ownership of body_as_file_ref. - thunk::EnterResourceCreationNoLock enter(pp_instance()); - response_info_ = enter.functions()->CreateURLResponseInfo( - pp_instance(), data, body_as_file_ref); - } - - // The caller expects to get a ref, and we want to keep holding ours. - PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(response_info_); - return response_info_; -} - -int32_t URLLoader::ReadResponseBody(void* buffer, - int32_t bytes_to_read, - scoped_refptr<TrackedCallback> callback) { - if (!buffer || bytes_to_read <= 0) - return PP_ERROR_BADARGUMENT; // Must specify an output buffer. - if (TrackedCallback::IsPending(current_callback_)) - return PP_ERROR_INPROGRESS; // Can only have one request pending. - - if (buffer_.size()) { - // Special case: we've already buffered some data that we can synchronously - // return to the caller. Do so without making IPCs. - int32_t bytes_to_return = - std::min(bytes_to_read, static_cast<int32_t>(buffer_.size())); - PopBuffer(buffer, bytes_to_return); - return bytes_to_return; - } - - current_callback_ = callback; - current_read_buffer_ = buffer; - current_read_buffer_size_ = bytes_to_read; - - GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_ReadResponseBody( - API_ID_PPB_URL_LOADER, host_resource(), bytes_to_read)); - return PP_OK_COMPLETIONPENDING; -} - -int32_t URLLoader::FinishStreamingToFile( - scoped_refptr<TrackedCallback> callback) { - if (TrackedCallback::IsPending(current_callback_)) - return PP_ERROR_INPROGRESS; - - current_callback_ = callback; - - GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_FinishStreamingToFile( - API_ID_PPB_URL_LOADER, host_resource())); - return PP_OK_COMPLETIONPENDING; -} - -void URLLoader::Close() { - GetDispatcher()->Send(new PpapiHostMsg_PPBURLLoader_Close( - API_ID_PPB_URL_LOADER, host_resource())); -} - -void URLLoader::GrantUniversalAccess() { - GetDispatcher()->Send( - new PpapiHostMsg_PPBURLLoader_GrantUniversalAccess( - API_ID_PPB_URL_LOADER, host_resource())); -} - -void URLLoader::RegisterStatusCallback( - PP_URLLoaderTrusted_StatusCallback cb) { - // Not implemented in the proxied version, this is for implementing the - // proxy itself in the host. -} - -bool URLLoader::GetResponseInfoData(URLResponseInfoData* data) { - // Not implemented in the proxied version, this is for implementing the - // proxy itself in the host. - return false; -} - -void URLLoader::UpdateProgress( - const PPBURLLoader_UpdateProgress_Params& params) { - bytes_sent_ = params.bytes_sent; - total_bytes_to_be_sent_ = params.total_bytes_to_be_sent; - bytes_received_ = params.bytes_received; - total_bytes_to_be_received_ = params.total_bytes_to_be_received; -} - -void URLLoader::ReadResponseBodyAck(int32 result, const char* data) { - if (!TrackedCallback::IsPending(current_callback_) || !current_read_buffer_) { - NOTREACHED(); - return; - } - - if (result >= 0) { - DCHECK_EQ(0U, buffer_.size()); - - int32_t bytes_to_return = std::min(current_read_buffer_size_, result); - std::copy(data, - data + bytes_to_return, - static_cast<char*>(current_read_buffer_)); - - if (result > bytes_to_return) { - // Save what remains to be copied when ReadResponseBody is called again. - buffer_.insert(buffer_.end(), - data + bytes_to_return, - data + result); - } - - result = bytes_to_return; - } - - current_callback_->Run(result); -} - -void URLLoader::CallbackComplete(int32_t result) { - current_callback_->Run(result); -} - -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); -} - -// PPB_URLLoader_Proxy --------------------------------------------------------- - -PPB_URLLoader_Proxy::PPB_URLLoader_Proxy(Dispatcher* dispatcher) - : InterfaceProxy(dispatcher), - callback_factory_(this) { -} - -PPB_URLLoader_Proxy::~PPB_URLLoader_Proxy() { -} - -// static -PP_Resource PPB_URLLoader_Proxy::TrackPluginResource( - const HostResource& url_loader_resource) { - return (new URLLoader(url_loader_resource))->GetReference(); -} - -// static -const InterfaceProxy::Info* PPB_URLLoader_Proxy::GetTrustedInfo() { - static const Info info = { - thunk::GetPPB_URLLoaderTrusted_0_3_Thunk(), - PPB_URLLOADERTRUSTED_INTERFACE_0_3, - API_ID_NONE, // URL_LOADER is the canonical one. - false, - &CreateURLLoaderProxy - }; - return &info; -} - -// static -PP_Resource PPB_URLLoader_Proxy::CreateProxyResource(PP_Instance pp_instance) { - PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(pp_instance); - if (!dispatcher) - return 0; - - HostResource result; - dispatcher->Send(new PpapiHostMsg_PPBURLLoader_Create( - API_ID_PPB_URL_LOADER, pp_instance, &result)); - if (result.is_null()) - return 0; - return PPB_URLLoader_Proxy::TrackPluginResource(result); -} - -bool PPB_URLLoader_Proxy::OnMessageReceived(const IPC::Message& msg) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PPB_URLLoader_Proxy, msg) -#if !defined(OS_NACL) - 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(PpapiHostMsg_PPBURLLoader_GrantUniversalAccess, - OnMsgGrantUniversalAccess) -#endif // !defined(OS_NACL) - - IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_UpdateProgress, - OnMsgUpdateProgress) - IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_ReadResponseBody_Ack, - OnMsgReadResponseBodyAck) - IPC_MESSAGE_HANDLER(PpapiMsg_PPBURLLoader_CallbackComplete, - OnMsgCallbackComplete) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - // TODO(brettw) handle bad messages! - return handled; -} - -#if !defined(OS_NACL) -void PPB_URLLoader_Proxy::PrepareURLLoaderForSendingToPlugin( - PP_Resource resource) { - // So the plugin can query load status, we need to register our status - // callback before sending any URLLoader to the plugin. - EnterResourceNoLock<PPB_URLLoader_API> enter(resource, false); - if (enter.succeeded()) - enter.object()->RegisterStatusCallback(&UpdateResourceLoadStatus); - else - NOTREACHED(); // Only called internally, resource should be valid. -} - -void PPB_URLLoader_Proxy::OnMsgCreate(PP_Instance instance, - HostResource* result) { - thunk::EnterResourceCreation enter(instance); - if (enter.succeeded()) { - result->SetHostResource(instance, - enter.functions()->CreateURLLoader(instance)); - PrepareURLLoaderForSendingToPlugin(result->host_resource()); - } -} - -void PPB_URLLoader_Proxy::OnMsgOpen(const HostResource& loader, - const URLRequestInfoData& data) { - int peer_pid = dispatcher()->channel()->peer_pid(); - - EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter( - loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader); - enter.SetResult(enter.object()->Open(data, peer_pid, enter.callback())); - // TODO(brettw) bug 73236 register for the status callbacks. -} - -void PPB_URLLoader_Proxy::OnMsgFollowRedirect( - const HostResource& loader) { - EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter( - loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader); - if (enter.succeeded()) - enter.SetResult(enter.object()->FollowRedirect(enter.callback())); -} - -void PPB_URLLoader_Proxy::OnMsgGetResponseInfo(const HostResource& loader, - bool* success, - URLResponseInfoData* result) { - EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); - if (enter.succeeded()) - *success = enter.object()->GetResponseInfoData(result); - else - *success = false; -} - -void PPB_URLLoader_Proxy::OnMsgReadResponseBody( - const HostResource& 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; - } - - // 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 - // destroyed. Depending on the cleanup ordering, we may not need the weak - // pointer here.) - IPC::Message* message = - new PpapiMsg_PPBURLLoader_ReadResponseBody_Ack(API_ID_PPB_URL_LOADER); - IPC::ParamTraits<HostResource>::Write(message, loader); - - char* ptr = message->BeginWriteData(bytes_to_read); - if (!ptr) { - // TODO(brettw) have a way to check for out-of-memory. - } - - EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter( - loader, callback_factory_, &PPB_URLLoader_Proxy::OnReadCallback, message); - if (enter.succeeded()) { - enter.SetResult(enter.object()->ReadResponseBody(ptr, bytes_to_read, - enter.callback())); - } -} - -void PPB_URLLoader_Proxy::OnMsgFinishStreamingToFile( - const HostResource& loader) { - EnterHostFromHostResourceForceCallback<PPB_URLLoader_API> enter( - loader, callback_factory_, &PPB_URLLoader_Proxy::OnCallback, loader); - if (enter.succeeded()) - enter.SetResult(enter.object()->FinishStreamingToFile(enter.callback()));; -} - -void PPB_URLLoader_Proxy::OnMsgClose(const HostResource& loader) { - EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); - if (enter.succeeded()) - enter.object()->Close(); -} - -void PPB_URLLoader_Proxy::OnMsgGrantUniversalAccess( - const HostResource& loader) { - EnterHostFromHostResource<PPB_URLLoader_API> enter(loader); - if (enter.succeeded()) - enter.object()->GrantUniversalAccess(); -} -#endif // !defined(OS_NACL) - -// Called in the Plugin. -void PPB_URLLoader_Proxy::OnMsgUpdateProgress( - const PPBURLLoader_UpdateProgress_Params& params) { - EnterPluginFromHostResource<PPB_URLLoader_API> enter(params.resource); - if (enter.succeeded()) - static_cast<URLLoader*>(enter.object())->UpdateProgress(params); -} - -// Called in the Plugin. -void PPB_URLLoader_Proxy::OnMsgReadResponseBodyAck( - const IPC::Message& message) { - PickleIterator iter(message); - - HostResource host_resource; - if (!IPC::ParamTraits<HostResource>::Read(&message, &iter, &host_resource)) { - NOTREACHED() << "Expecting HostResource"; - return; - } - - const char* data; - int data_len; - if (!iter.ReadData(&data, &data_len)) { - NOTREACHED() << "Expecting data"; - return; - } - - int result; - if (!iter.ReadInt(&result)) { - NOTREACHED() << "Expecting result"; - return; - } - - if (result >= 0 && result != data_len) { - NOTREACHED() << "Data size mismatch"; - return; - } - - EnterPluginFromHostResource<PPB_URLLoader_API> enter(host_resource); - if (enter.succeeded()) - static_cast<URLLoader*>(enter.object())->ReadResponseBodyAck(result, data); -} - -// Called in the plugin. -void PPB_URLLoader_Proxy::OnMsgCallbackComplete( - const HostResource& host_resource, - int32_t result) { - EnterPluginFromHostResource<PPB_URLLoader_API> enter(host_resource); - if (enter.succeeded()) - static_cast<URLLoader*>(enter.object())->CallbackComplete(result); -} - -#if !defined(OS_NACL) -void PPB_URLLoader_Proxy::OnReadCallback(int32_t result, - IPC::Message* message) { - int32_t bytes_read = 0; - if (result > 0) - bytes_read = result; // Positive results indicate bytes read. - - message->TrimWriteData(bytes_read); - message->WriteInt(result); - - dispatcher()->Send(message); -} - -void PPB_URLLoader_Proxy::OnCallback(int32_t result, - const HostResource& resource) { - dispatcher()->Send(new PpapiMsg_PPBURLLoader_CallbackComplete( - API_ID_PPB_URL_LOADER, resource, result)); -} -#endif // !defined(OS_NACL) - -} // namespace proxy -} // namespace ppapi diff --git a/ppapi/proxy/ppb_url_loader_proxy.h b/ppapi/proxy/ppb_url_loader_proxy.h deleted file mode 100644 index f4c5bc5..0000000 --- a/ppapi/proxy/ppb_url_loader_proxy.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2012 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. - -#ifndef PPAPI_PPB_URL_LOADER_PROXY_H_ -#define PPAPI_PPB_URL_LOADER_PROXY_H_ - -#include "ppapi/c/pp_completion_callback.h" -#include "ppapi/c/pp_instance.h" -#include "ppapi/c/pp_module.h" -#include "ppapi/c/pp_resource.h" -#include "ppapi/c/pp_size.h" -#include "ppapi/c/pp_var.h" -#include "ppapi/c/ppb_url_loader.h" -#include "ppapi/c/trusted/ppb_url_loader_trusted.h" -#include "ppapi/proxy/interface_proxy.h" -#include "ppapi/proxy/proxy_completion_callback_factory.h" -#include "ppapi/shared_impl/host_resource.h" -#include "ppapi/utility/completion_callback_factory.h" - -namespace ppapi { - -struct URLRequestInfoData; -struct URLResponseInfoData; - -namespace proxy { - -struct PPBURLLoader_UpdateProgress_Params; - -class PPB_URLLoader_Proxy : public InterfaceProxy { - public: - PPB_URLLoader_Proxy(Dispatcher* dispatcher); - virtual ~PPB_URLLoader_Proxy(); - - static const Info* GetTrustedInfo(); - - static PP_Resource CreateProxyResource(PP_Instance instance); - - // URLLoader objects are normally allocated by the Create function, but - // they are also provided to PPP_Instance.OnMsgHandleDocumentLoad. This - // function allows the proxy for DocumentLoad to create the correct plugin - // proxied info for the given browser-supplied URLLoader resource ID. - static PP_Resource TrackPluginResource( - const HostResource& url_loader_resource); - - // InterfaceProxy implementation. - virtual bool OnMessageReceived(const IPC::Message& msg); - - // URLLoader objects are sent from places other than just URLLoader.Create, - // in particular when doing a full-frame plugin. This function does the - // necessary setup in the host before the resource is sent. Call this any - // time you're sending a new URLLoader that the plugin hasn't seen yet. - void PrepareURLLoaderForSendingToPlugin(PP_Resource resource); - - static const ApiID kApiID = API_ID_PPB_URL_LOADER; - - private: - // Plugin->renderer message handlers. - void OnMsgCreate(PP_Instance instance, - HostResource* result); - void OnMsgOpen(const HostResource& loader, - const URLRequestInfoData& data); - void OnMsgFollowRedirect(const HostResource& loader); - void OnMsgGetResponseInfo(const HostResource& loader, - bool* success, - URLResponseInfoData* result); - void OnMsgReadResponseBody(const HostResource& loader, - int32_t bytes_to_read); - void OnMsgFinishStreamingToFile(const HostResource& loader); - void OnMsgClose(const HostResource& loader); - void OnMsgGrantUniversalAccess(const HostResource& loader); - - // Renderer->plugin message handlers. - void OnMsgUpdateProgress( - const PPBURLLoader_UpdateProgress_Params& params); - void OnMsgReadResponseBodyAck(const IPC::Message& message); - void OnMsgCallbackComplete(const HostResource& host_resource, int32_t result); - - // Handles callbacks for read complete messages. Takes ownership of the - // message pointer. - void OnReadCallback(int32_t result, IPC::Message* message); - - // Handles callback for everything but reads. - void OnCallback(int32_t result, const HostResource& resource); - - ProxyCompletionCallbackFactory<PPB_URLLoader_Proxy> callback_factory_; -}; - -} // namespace proxy -} // namespace ppapi - -#endif // PPAPI_PPB_URL_LOADER_PROXY_H_ diff --git a/ppapi/proxy/ppp_instance_proxy.cc b/ppapi/proxy/ppp_instance_proxy.cc index eb1d4e4..a7a0699 100644 --- a/ppapi/proxy/ppp_instance_proxy.cc +++ b/ppapi/proxy/ppp_instance_proxy.cc @@ -13,11 +13,14 @@ #include "ppapi/c/ppp_instance.h" #include "ppapi/proxy/host_dispatcher.h" #include "ppapi/proxy/plugin_dispatcher.h" +#include "ppapi/proxy/plugin_globals.h" +#include "ppapi/proxy/plugin_proxy_delegate.h" #include "ppapi/proxy/plugin_resource_tracker.h" #include "ppapi/proxy/ppapi_messages.h" -#include "ppapi/proxy/ppb_url_loader_proxy.h" +#include "ppapi/proxy/url_loader_resource.h" #include "ppapi/shared_impl/ppapi_globals.h" #include "ppapi/shared_impl/ppb_view_shared.h" +#include "ppapi/shared_impl/resource_tracker.h" #include "ppapi/shared_impl/scoped_pp_resource.h" #include "ppapi/thunk/enter.h" #include "ppapi/thunk/ppb_flash_fullscreen_api.h" @@ -83,36 +86,11 @@ void DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { instance, has_focus)); } -PP_Bool HandleDocumentLoad(PP_Instance instance, - PP_Resource url_loader) { - PP_Bool result = PP_FALSE; - HostDispatcher* dispatcher = HostDispatcher::GetForInstance(instance); - - // Set up the URLLoader for proxying. - - PPB_URLLoader_Proxy* url_loader_proxy = static_cast<PPB_URLLoader_Proxy*>( - dispatcher->GetInterfaceProxy(API_ID_PPB_URL_LOADER)); - url_loader_proxy->PrepareURLLoaderForSendingToPlugin(url_loader); - - // PluginResourceTracker in the plugin process assumes that resources that it - // tracks have been addrefed on behalf of the plugin at the renderer side. So - // we explicitly do it for |url_loader| here. - // - // Please also see comments in PPP_Instance_Proxy::OnMsgHandleDocumentLoad() - // about releasing of this extra reference. - const PPB_Core* core = reinterpret_cast<const PPB_Core*>( - dispatcher->local_get_interface()(PPB_CORE_INTERFACE)); - if (!core) { - NOTREACHED(); - return PP_FALSE; - } - core->AddRefResource(url_loader); - - HostResource serialized_loader; - serialized_loader.SetHostResource(instance, url_loader); - dispatcher->Send(new PpapiMsg_PPPInstance_HandleDocumentLoad( - API_ID_PPP_INSTANCE, instance, serialized_loader, &result)); - return result; +PP_Bool HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader) { + // This should never get called. Out-of-process document loads are handled + // specially. + NOTREACHED(); + return PP_FALSE; } static const PPP_Instance_1_1 instance_interface = { @@ -253,19 +231,25 @@ void PPP_Instance_Proxy::OnPluginMsgDidChangeFocus(PP_Instance instance, void PPP_Instance_Proxy::OnPluginMsgHandleDocumentLoad( PP_Instance instance, - const HostResource& url_loader, - PP_Bool* result) { - PP_Resource plugin_loader = - PPB_URLLoader_Proxy::TrackPluginResource(url_loader); - *result = combined_interface_->HandleDocumentLoad(instance, plugin_loader); - - // This balances the one reference that TrackPluginResource() initialized it - // with. The plugin will normally take an additional reference which will keep - // the resource alive in the plugin (and the one reference in the renderer - // representing all plugin references). - // Once all references at the plugin side are released, the renderer side will - // be notified and release the reference added in HandleDocumentLoad() above. - PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource(plugin_loader); + int pending_loader_host_id, + const URLResponseInfoData& data) { + PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance); + if (!dispatcher) + return; + Connection connection(PluginGlobals::Get()->GetBrowserSender(), + dispatcher); + + scoped_refptr<URLLoaderResource> loader_resource( + new URLLoaderResource(connection, instance, + pending_loader_host_id, data)); + + PP_Resource loader_pp_resource = loader_resource->GetReference(); + if (!combined_interface_->HandleDocumentLoad(instance, loader_pp_resource)) + loader_resource->Close(); + // We don't pass a ref into the plugin, if it wants one, it will have taken + // an additional one. + PpapiGlobals::Get()->GetResourceTracker()->ReleaseResource( + loader_pp_resource); } } // namespace proxy diff --git a/ppapi/proxy/ppp_instance_proxy.h b/ppapi/proxy/ppp_instance_proxy.h index 1b599d0..85ae55c 100644 --- a/ppapi/proxy/ppp_instance_proxy.h +++ b/ppapi/proxy/ppp_instance_proxy.h @@ -20,6 +20,7 @@ struct PP_Rect; namespace ppapi { +struct URLResponseInfoData; struct ViewData; namespace proxy { @@ -50,8 +51,9 @@ class PPP_Instance_Proxy : public InterfaceProxy { PP_Bool flash_fullscreen); void OnPluginMsgDidChangeFocus(PP_Instance instance, PP_Bool has_focus); void OnPluginMsgHandleDocumentLoad(PP_Instance instance, - const HostResource& url_loader, - PP_Bool* result); + int pending_loader_host_id, + const URLResponseInfoData& data); + scoped_ptr<PPP_Instance_Combined> combined_interface_; }; diff --git a/ppapi/proxy/resource_creation_proxy.cc b/ppapi/proxy/resource_creation_proxy.cc index 8bbe862..50c7d6f 100644 --- a/ppapi/proxy/resource_creation_proxy.cc +++ b/ppapi/proxy/resource_creation_proxy.cc @@ -33,13 +33,13 @@ #include "ppapi/proxy/ppb_network_monitor_private_proxy.h" #include "ppapi/proxy/ppb_tcp_server_socket_private_proxy.h" #include "ppapi/proxy/ppb_tcp_socket_private_proxy.h" -#include "ppapi/proxy/ppb_url_loader_proxy.h" #include "ppapi/proxy/ppb_video_decoder_proxy.h" #include "ppapi/proxy/ppb_x509_certificate_private_proxy.h" #include "ppapi/proxy/printing_resource.h" #include "ppapi/proxy/talk_resource.h" #include "ppapi/proxy/truetype_font_resource.h" #include "ppapi/proxy/udp_socket_private_resource.h" +#include "ppapi/proxy/url_loader_resource.h" #include "ppapi/proxy/url_request_info_resource.h" #include "ppapi/proxy/url_response_info_resource.h" #include "ppapi/proxy/video_capture_resource.h" @@ -82,6 +82,11 @@ PP_Resource ResourceCreationProxy::CreateFileRef(PP_Instance instance, return PPB_FileRef_Proxy::CreateProxyResource(instance, file_system, path); } +PP_Resource ResourceCreationProxy::CreateFileRef( + const PPB_FileRef_CreateInfo& create_info) { + return PPB_FileRef_Proxy::DeserializeFileRef(create_info); +} + PP_Resource ResourceCreationProxy::CreateFileSystem( PP_Instance instance, PP_FileSystemType type) { @@ -166,7 +171,7 @@ PP_Resource ResourceCreationProxy::CreateTrueTypeFont( } PP_Resource ResourceCreationProxy::CreateURLLoader(PP_Instance instance) { - return PPB_URLLoader_Proxy::CreateProxyResource(instance); + return (new URLLoaderResource(GetConnection(), instance))->GetReference(); } PP_Resource ResourceCreationProxy::CreateURLRequestInfo( diff --git a/ppapi/proxy/resource_creation_proxy.h b/ppapi/proxy/resource_creation_proxy.h index 0597c11..74a0888 100644 --- a/ppapi/proxy/resource_creation_proxy.h +++ b/ppapi/proxy/resource_creation_proxy.h @@ -41,6 +41,8 @@ class ResourceCreationProxy : public InterfaceProxy, virtual PP_Resource CreateFileRef(PP_Instance instance, PP_Resource file_system, const char* path) OVERRIDE; + virtual PP_Resource CreateFileRef( + const PPB_FileRef_CreateInfo& create_info) OVERRIDE; virtual PP_Resource CreateFileSystem(PP_Instance instance, PP_FileSystemType type) OVERRIDE; virtual PP_Resource CreateIsolatedFileSystem( diff --git a/ppapi/proxy/url_loader_resource.cc b/ppapi/proxy/url_loader_resource.cc new file mode 100644 index 0000000..5ee8d95 --- /dev/null +++ b/ppapi/proxy/url_loader_resource.cc @@ -0,0 +1,392 @@ +// Copyright (c) 2013 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/url_loader_resource.h" + +#include "base/logging.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_url_loader.h" +#include "ppapi/proxy/dispatch_reply_message.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/proxy/ppb_file_ref_proxy.h" +#include "ppapi/proxy/url_request_info_resource.h" +#include "ppapi/proxy/url_response_info_resource.h" +#include "ppapi/shared_impl/ppapi_globals.h" +#include "ppapi/shared_impl/url_response_info_data.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/resource_creation_api.h" + +using ppapi::thunk::EnterResourceNoLock; +using ppapi::thunk::PPB_URLLoader_API; +using ppapi::thunk::PPB_URLRequestInfo_API; + +#ifdef _MSC_VER +// Do not warn about use of std::copy with raw pointers. +#pragma warning(disable : 4996) +#endif + +namespace ppapi { +namespace proxy { + +URLLoaderResource::URLLoaderResource(Connection connection, + PP_Instance instance) + : PluginResource(connection, instance), + mode_(MODE_WAITING_TO_OPEN), + status_callback_(NULL), + bytes_sent_(0), + total_bytes_to_be_sent_(-1), + bytes_received_(0), + total_bytes_to_be_received_(-1), + user_buffer_(NULL), + user_buffer_size_(0), + done_status_(PP_OK_COMPLETIONPENDING), + is_streaming_to_file_(false), + is_asynchronous_load_suspended_(false) { + SendCreate(RENDERER, PpapiHostMsg_URLLoader_Create()); +} + +URLLoaderResource::URLLoaderResource(Connection connection, + PP_Instance instance, + int pending_main_document_loader_id, + const ppapi::URLResponseInfoData& data) + : PluginResource(connection, instance), + mode_(MODE_OPENING), + status_callback_(NULL), + bytes_sent_(0), + total_bytes_to_be_sent_(-1), + bytes_received_(0), + total_bytes_to_be_received_(-1), + user_buffer_(NULL), + user_buffer_size_(0), + done_status_(PP_OK_COMPLETIONPENDING), + is_streaming_to_file_(false), + is_asynchronous_load_suspended_(false) { + AttachToPendingHost(RENDERER, pending_main_document_loader_id); + SaveResponseInfo(data); +} + +URLLoaderResource::~URLLoaderResource() { +} + +PPB_URLLoader_API* URLLoaderResource::AsPPB_URLLoader_API() { + return this; +} + +int32_t URLLoaderResource::Open(PP_Resource request_id, + scoped_refptr<TrackedCallback> callback) { + EnterResourceNoLock<PPB_URLRequestInfo_API> enter_request(request_id, true); + if (enter_request.failed()) { + Log(PP_LOGLEVEL_ERROR, + "PPB_URLLoader.Open: invalid request resource ID. (Hint to C++ wrapper" + " users: use the ResourceRequest constructor that takes an instance or" + " else the request will be null.)"); + return PP_ERROR_BADARGUMENT; + } + return Open(enter_request.object()->GetData(), 0, callback); +} + +int32_t URLLoaderResource::Open( + const ::ppapi::URLRequestInfoData& request_data, + int requestor_pid, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = ValidateCallback(callback); + if (rv != PP_OK) + return rv; + if (mode_ != MODE_WAITING_TO_OPEN) + return PP_ERROR_INPROGRESS; + + request_data_ = request_data; + + mode_ = MODE_OPENING; + is_asynchronous_load_suspended_ = false; + + RegisterCallback(callback); + Post(RENDERER, PpapiHostMsg_URLLoader_Open(request_data)); + return PP_OK_COMPLETIONPENDING; +} + +int32_t URLLoaderResource::FollowRedirect( + scoped_refptr<TrackedCallback> callback) { + int32_t rv = ValidateCallback(callback); + if (rv != PP_OK) + return rv; + if (mode_ != MODE_OPENING) + return PP_ERROR_INPROGRESS; + + SetDefersLoading(false); // Allow the redirect to continue. + RegisterCallback(callback); + return PP_OK_COMPLETIONPENDING; +} + +PP_Bool URLLoaderResource::GetUploadProgress(int64_t* bytes_sent, + int64_t* total_bytes_to_be_sent) { + if (!request_data_.record_upload_progress) { + *bytes_sent = 0; + *total_bytes_to_be_sent = 0; + return PP_FALSE; + } + *bytes_sent = bytes_sent_; + *total_bytes_to_be_sent = total_bytes_to_be_sent_; + return PP_TRUE; +} + +PP_Bool URLLoaderResource::GetDownloadProgress( + int64_t* bytes_received, + int64_t* total_bytes_to_be_received) { + if (!request_data_.record_download_progress) { + *bytes_received = 0; + *total_bytes_to_be_received = 0; + return PP_FALSE; + } + *bytes_received = bytes_received_; + *total_bytes_to_be_received = total_bytes_to_be_received_; + return PP_TRUE; +} + +PP_Resource URLLoaderResource::GetResponseInfo() { + if (response_info_.get()) + return response_info_->GetReference(); + return 0; +} + +int32_t URLLoaderResource::ReadResponseBody( + void* buffer, + int32_t bytes_to_read, + scoped_refptr<TrackedCallback> callback) { + int32_t rv = ValidateCallback(callback); + if (rv != PP_OK) + return rv; + if (!response_info_.get() || + !response_info_->data().body_as_file_ref.resource.is_null()) + return PP_ERROR_FAILED; + if (bytes_to_read <= 0 || !buffer) + return PP_ERROR_BADARGUMENT; + + user_buffer_ = static_cast<char*>(buffer); + user_buffer_size_ = bytes_to_read; + + if (!buffer_.empty()) + return FillUserBuffer(); + + // We may have already reached EOF. + if (done_status_ != PP_OK_COMPLETIONPENDING) { + user_buffer_ = NULL; + user_buffer_size_ = 0; + return done_status_; + } + + RegisterCallback(callback); + return PP_OK_COMPLETIONPENDING; +} + +int32_t URLLoaderResource::FinishStreamingToFile( + scoped_refptr<TrackedCallback> callback) { + int32_t rv = ValidateCallback(callback); + if (rv != PP_OK) + return rv; + if (!response_info_.get() || + response_info_->data().body_as_file_ref.resource.is_null()) + return PP_ERROR_FAILED; + + // We may have already reached EOF. + if (done_status_ != PP_OK_COMPLETIONPENDING) + return done_status_; + + is_streaming_to_file_ = true; + if (is_asynchronous_load_suspended_) + SetDefersLoading(false); + + // Wait for didFinishLoading / didFail. + RegisterCallback(callback); + return PP_OK_COMPLETIONPENDING; +} + +void URLLoaderResource::Close() { + mode_ = MODE_LOAD_COMPLETE; + done_status_ = PP_ERROR_ABORTED; + + Post(RENDERER, PpapiHostMsg_URLLoader_Close()); + + // Abort the callbacks, the plugin doesn't want to be called back after this. + // TODO(brettw) this should fix bug 69457, mark it fixed. ============ + if (TrackedCallback::IsPending(pending_callback_)) + pending_callback_->PostAbort(); +} + +void URLLoaderResource::GrantUniversalAccess() { + Post(RENDERER, PpapiHostMsg_URLLoader_GrantUniversalAccess()); +} + +void URLLoaderResource::RegisterStatusCallback( + PP_URLLoaderTrusted_StatusCallback callback) { + status_callback_ = callback; +} + +void URLLoaderResource::OnReplyReceived( + const ResourceMessageReplyParams& params, + const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(URLLoaderResource, msg) + case PpapiPluginMsg_URLLoader_SendData::ID: + // Special message, manually dispatch since we don't want the automatic + // unpickling. + OnPluginMsgSendData(params, msg); + break; + + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_URLLoader_ReceivedResponse, + OnPluginMsgReceivedResponse) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_URLLoader_FinishedLoading, + OnPluginMsgFinishedLoading) + PPAPI_DISPATCH_PLUGIN_RESOURCE_CALL( + PpapiPluginMsg_URLLoader_UpdateProgress, + OnPluginMsgUpdateProgress) + IPC_END_MESSAGE_MAP() +} + +void URLLoaderResource::OnPluginMsgReceivedResponse( + const ResourceMessageReplyParams& params, + const URLResponseInfoData& data) { + SaveResponseInfo(data); + RunCallback(PP_OK); +} + +void URLLoaderResource::OnPluginMsgSendData( + const ResourceMessageReplyParams& params, + const IPC::Message& message) { + PickleIterator iter(message); + const char* data; + int data_length; + if (!iter.ReadData(&data, &data_length)) { + NOTREACHED() << "Expecting data"; + return; + } + + mode_ = MODE_STREAMING_DATA; + buffer_.insert(buffer_.end(), data, data + data_length); + + // To avoid letting the network stack download an entire stream all at once, + // defer loading when we have enough buffer. + // Check for this before we run the callback, even though that could move + // data out of the buffer. Doing anything after the callback is unsafe. + DCHECK(request_data_.prefetch_buffer_lower_threshold < + request_data_.prefetch_buffer_upper_threshold); + if (!is_streaming_to_file_ && + !is_asynchronous_load_suspended_ && + (buffer_.size() >= static_cast<size_t>( + request_data_.prefetch_buffer_upper_threshold))) { + DVLOG(1) << "Suspending async load - buffer size: " << buffer_.size(); + SetDefersLoading(true); + } + + if (user_buffer_) + RunCallback(FillUserBuffer()); + else + DCHECK(!TrackedCallback::IsPending(pending_callback_)); +} + +void URLLoaderResource::OnPluginMsgFinishedLoading( + const ResourceMessageReplyParams& params, + int32_t result) { + mode_ = MODE_LOAD_COMPLETE; + done_status_ = result; + user_buffer_ = NULL; + user_buffer_size_ = 0; + + // If the client hasn't called any function that takes a callback since + // the initial call to Open, or called ReadResponseBody and got a + // synchronous return, then the callback will be NULL. + if (TrackedCallback::IsPending(pending_callback_)) + RunCallback(done_status_); +} + +void URLLoaderResource::OnPluginMsgUpdateProgress( + const ResourceMessageReplyParams& params, + int64_t bytes_sent, + int64_t total_bytes_to_be_sent, + int64_t bytes_received, + int64_t total_bytes_to_be_received) { + bytes_sent_ = bytes_sent; + total_bytes_to_be_sent_ = total_bytes_to_be_sent; + bytes_received_ = bytes_received; + total_bytes_to_be_received_ = total_bytes_to_be_received; + + if (status_callback_) + status_callback_(pp_instance(), pp_resource(), + bytes_sent_, total_bytes_to_be_sent_, + bytes_received_, total_bytes_to_be_received_); +} + +void URLLoaderResource::SetDefersLoading(bool defers_loading) { + Post(RENDERER, PpapiHostMsg_URLLoader_SetDeferLoading(defers_loading)); +} + +int32_t URLLoaderResource::ValidateCallback( + scoped_refptr<TrackedCallback> callback) { + DCHECK(callback); + if (TrackedCallback::IsPending(pending_callback_)) + return PP_ERROR_INPROGRESS; + return PP_OK; +} + +void URLLoaderResource::RegisterCallback( + scoped_refptr<TrackedCallback> callback) { + DCHECK(!TrackedCallback::IsPending(pending_callback_)); + pending_callback_ = callback; +} + +void URLLoaderResource::RunCallback(int32_t result) { + // This may be null when this is a main document loader. + if (!pending_callback_.get()) + return; + + // If |user_buffer_| was set as part of registering a callback, the paths + // which trigger that callack must have cleared it since the callback is now + // free to delete it. + DCHECK(!user_buffer_); + + // As a second line of defense, clear the |user_buffer_| in case the + // callbacks get called in an unexpected order. + user_buffer_ = NULL; + user_buffer_size_ = 0; + pending_callback_->Run(result); +} + +void URLLoaderResource::SaveResponseInfo(const URLResponseInfoData& data) { + // Create a proxy resource for the the file ref host resource if needed. + PP_Resource body_as_file_ref = 0; + if (!data.body_as_file_ref.resource.is_null()) { + thunk::EnterResourceCreationNoLock enter(pp_instance()); + body_as_file_ref = + enter.functions()->CreateFileRef(data.body_as_file_ref); + } + response_info_ = new URLResponseInfoResource( + connection(), pp_instance(), data, body_as_file_ref); +} + +size_t URLLoaderResource::FillUserBuffer() { + DCHECK(user_buffer_); + DCHECK(user_buffer_size_); + + size_t bytes_to_copy = std::min(buffer_.size(), user_buffer_size_); + std::copy(buffer_.begin(), buffer_.begin() + bytes_to_copy, user_buffer_); + buffer_.erase(buffer_.begin(), buffer_.begin() + bytes_to_copy); + + // If the buffer is getting too empty, resume asynchronous loading. + if (is_asynchronous_load_suspended_ && + buffer_.size() <= static_cast<size_t>( + request_data_.prefetch_buffer_lower_threshold)) { + DVLOG(1) << "Resuming async load - buffer size: " << buffer_.size(); + SetDefersLoading(false); + } + + // Reset for next time. + user_buffer_ = NULL; + user_buffer_size_ = 0; + return bytes_to_copy; +} + +} // namespace proxy +} // namespace ppapi
\ No newline at end of file diff --git a/ppapi/proxy/url_loader_resource.h b/ppapi/proxy/url_loader_resource.h new file mode 100644 index 0000000..685ccfe --- /dev/null +++ b/ppapi/proxy/url_loader_resource.h @@ -0,0 +1,146 @@ +// Copyright (c) 2013 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. + +#ifndef PPAPI_PROXY_URL_LOADER_RESOURCE_H_ +#define PPAPI_PROXY_URL_LOADER_RESOURCE_H_ + +#include <deque> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ppapi/c/trusted/ppb_url_loader_trusted.h" +#include "ppapi/proxy/plugin_resource.h" +#include "ppapi/proxy/ppapi_proxy_export.h" +#include "ppapi/shared_impl/url_request_info_data.h" +#include "ppapi/thunk/ppb_url_loader_api.h" + +namespace ppapi { +namespace proxy { + +class URLResponseInfoResource; + +class PPAPI_PROXY_EXPORT URLLoaderResource + : public PluginResource, + public NON_EXPORTED_BASE(thunk::PPB_URLLoader_API) { + public: + // Constructor for plugin-initiated loads. + URLLoaderResource(Connection connection, + PP_Instance instance); + + // Constructor for renderer-initiated (document) loads. The loader ID is the + // pending host ID for the already-created host in the renderer, and the + // response data is the response for the already-opened connection. + URLLoaderResource(Connection connection, + PP_Instance instance, + int pending_main_document_loader_id, + const URLResponseInfoData& data); + + virtual ~URLLoaderResource(); + + // Resource override. + thunk::PPB_URLLoader_API* AsPPB_URLLoader_API() OVERRIDE; + + // PPB_URLLoader_API implementation. + virtual int32_t Open(PP_Resource request_id, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t Open(const URLRequestInfoData& data, + int requestor_pid, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t FollowRedirect( + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual PP_Bool GetUploadProgress(int64_t* bytes_sent, + int64_t* total_bytes_to_be_sent) OVERRIDE; + virtual PP_Bool GetDownloadProgress( + int64_t* bytes_received, + int64_t* total_bytes_to_be_received) OVERRIDE; + virtual PP_Resource GetResponseInfo() OVERRIDE; + virtual int32_t ReadResponseBody( + void* buffer, + int32_t bytes_to_read, + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual int32_t FinishStreamingToFile( + scoped_refptr<TrackedCallback> callback) OVERRIDE; + virtual void Close() OVERRIDE; + virtual void GrantUniversalAccess() OVERRIDE; + virtual void RegisterStatusCallback( + PP_URLLoaderTrusted_StatusCallback callback) OVERRIDE; + + // PluginResource implementation. + virtual void OnReplyReceived(const ResourceMessageReplyParams& params, + const IPC::Message& msg) OVERRIDE; + + private: + enum Mode { + // The plugin has not called Open() yet. + MODE_WAITING_TO_OPEN, + + // The plugin is waiting for the Open() or FollowRedirect callback. + MODE_OPENING, + + // We've started to receive data and may receive more. + MODE_STREAMING_DATA, + + // All data has been streamed or there was an error. + MODE_LOAD_COMPLETE + }; + + // IPC message handlers. + void OnPluginMsgReceivedResponse(const ResourceMessageReplyParams& params, + const URLResponseInfoData& data); + void OnPluginMsgSendData(const ResourceMessageReplyParams& params, + const IPC::Message& message); + void OnPluginMsgFinishedLoading(const ResourceMessageReplyParams& params, + int32_t result); + void OnPluginMsgUpdateProgress(const ResourceMessageReplyParams& params, + int64_t bytes_sent, + int64_t total_bytes_to_be_sent, + int64_t bytes_received, + int64_t total_bytes_to_be_received); + + // Sends the defers loading message to the renderer to block or unblock the + // load. + void SetDefersLoading(bool defers_loading); + + int32_t ValidateCallback(scoped_refptr<TrackedCallback> callback); + + // Sets up |callback| as the pending callback. This should only be called once + // it is certain that |PP_OK_COMPLETIONPENDING| will be returned. + void RegisterCallback(scoped_refptr<TrackedCallback> callback); + + void RunCallback(int32_t result); + + // Saves the given response info to response_info_, handling file refs if + // necessary. This does not issue any callbacks. + void SaveResponseInfo(const URLResponseInfoData& data); + + size_t FillUserBuffer(); + + Mode mode_; + URLRequestInfoData request_data_; + + scoped_refptr<TrackedCallback> pending_callback_; + + PP_URLLoaderTrusted_StatusCallback status_callback_; + + std::deque<char> buffer_; + int64_t bytes_sent_; + int64_t total_bytes_to_be_sent_; + int64_t bytes_received_; + int64_t total_bytes_to_be_received_; + char* user_buffer_; + size_t user_buffer_size_; + int32_t done_status_; + bool is_streaming_to_file_; + bool is_asynchronous_load_suspended_; + + // The response info if we've received it. + scoped_refptr<URLResponseInfoResource> response_info_; + + DISALLOW_COPY_AND_ASSIGN(URLLoaderResource); +}; + +} // namespace proxy +} // namespace ppapi + +#endif // PPAPI_PROXY_URL_LOADER_RESOURCE_H_
\ No newline at end of file diff --git a/ppapi/proxy/url_response_info_resource.h b/ppapi/proxy/url_response_info_resource.h index f05b32c..dfb1f8f 100644 --- a/ppapi/proxy/url_response_info_resource.h +++ b/ppapi/proxy/url_response_info_resource.h @@ -37,6 +37,8 @@ class PPAPI_PROXY_EXPORT URLResponseInfoResource virtual PP_Var GetProperty(PP_URLResponseProperty property) OVERRIDE; virtual PP_Resource GetBodyAsFileRef() OVERRIDE; + const URLResponseInfoData& data() const { return data_; } + private: URLResponseInfoData data_; diff --git a/ppapi/shared_impl/api_id.h b/ppapi/shared_impl/api_id.h index 00706bf..16955aa 100644 --- a/ppapi/shared_impl/api_id.h +++ b/ppapi/shared_impl/api_id.h @@ -45,7 +45,6 @@ enum ApiID { API_ID_PPB_TESTING, API_ID_PPB_TEXT_INPUT, API_ID_PPB_UDPSOCKET_PRIVATE, - API_ID_PPB_URL_LOADER, API_ID_PPB_URL_RESPONSE_INFO, API_ID_PPB_VAR_ARRAY_BUFFER, API_ID_PPB_VAR_DEPRECATED, diff --git a/ppapi/shared_impl/resource.cc b/ppapi/shared_impl/resource.cc index 2c40961..4fb9a47 100644 --- a/ppapi/shared_impl/resource.cc +++ b/ppapi/shared_impl/resource.cc @@ -75,6 +75,7 @@ void Resource::OnReplyReceived(const proxy::ResourceMessageReplyParams& params, } void Resource::Log(PP_LogLevel level, const std::string& message) { +printf("Log:%s\n", message.c_str()); PpapiGlobals::Get()->LogWithSource(pp_instance(), level, std::string(), message); } diff --git a/ppapi/tests/test_url_loader.cc b/ppapi/tests/test_url_loader.cc index 0978f0e..d3602d3 100644 --- a/ppapi/tests/test_url_loader.cc +++ b/ppapi/tests/test_url_loader.cc @@ -800,7 +800,6 @@ std::string TestURLLoader::TestUntendedLoad() { event.Wait(); } } - // The loader should now have the data and have finished successfully. std::string body; std::string error = ReadEntireResponseBody(&loader, &body); diff --git a/ppapi/thunk/interfaces_ppb_private.h b/ppapi/thunk/interfaces_ppb_private.h index 94dd53f..6bc431d 100644 --- a/ppapi/thunk/interfaces_ppb_private.h +++ b/ppapi/thunk/interfaces_ppb_private.h @@ -47,6 +47,9 @@ PROXIED_IFACE(NoAPIName, PPB_TALK_PRIVATE_INTERFACE_1_0, // This uses the FileIO API which is declared in the public stable file. PROXIED_IFACE(NoAPIName, PPB_FILEIOTRUSTED_INTERFACE_0_4, PPB_FileIOTrusted_0_4) +PROXIED_IFACE(NoAPIName, PPB_URLLOADERTRUSTED_INTERFACE_0_3, + PPB_URLLoaderTrusted_0_3) + PROXIED_IFACE(NoAPIName, PPB_VIDEODESTINATION_PRIVATE_INTERFACE_0_1, PPB_VideoDestination_Private_0_1) PROXIED_IFACE(NoAPIName, PPB_VIDEOSOURCE_PRIVATE_INTERFACE_0_1, diff --git a/ppapi/thunk/interfaces_ppb_public_stable.h b/ppapi/thunk/interfaces_ppb_public_stable.h index 14b539f..ddfe2ca 100644 --- a/ppapi/thunk/interfaces_ppb_public_stable.h +++ b/ppapi/thunk/interfaces_ppb_public_stable.h @@ -23,7 +23,6 @@ PROXIED_API(PPB_FileRef) PROXIED_API(PPB_Graphics3D) PROXIED_API(PPB_ImageData) PROXIED_API(PPB_Instance) -PROXIED_API(PPB_URLLoader) // AudioConfig isn't proxied in the normal way, we have only local classes and // serialize it to a struct when we need it on the host side. @@ -73,7 +72,7 @@ PROXIED_IFACE(PPB_Instance, PPB_FULLSCREEN_INTERFACE_1_0, PPB_Fullscreen_1_0) PROXIED_IFACE(PPB_Instance, PPB_MESSAGING_INTERFACE_1_0, PPB_Messaging_1_0) PROXIED_IFACE(PPB_Instance, PPB_MOUSECURSOR_INTERFACE_1_0, PPB_MouseCursor_1_0) PROXIED_IFACE(PPB_Instance, PPB_MOUSELOCK_INTERFACE_1_0, PPB_MouseLock_1_0) -PROXIED_IFACE(PPB_URLLoader, PPB_URLLOADER_INTERFACE_1_0, PPB_URLLoader_1_0) +PROXIED_IFACE(NoAPIName, PPB_URLLOADER_INTERFACE_1_0, PPB_URLLoader_1_0) PROXIED_IFACE(NoAPIName, PPB_URLREQUESTINFO_INTERFACE_1_0, PPB_URLRequestInfo_1_0) PROXIED_IFACE(NoAPIName, PPB_URLRESPONSEINFO_INTERFACE_1_0, diff --git a/ppapi/thunk/ppb_url_loader_api.h b/ppapi/thunk/ppb_url_loader_api.h index 00d4690..df9b6aa 100644 --- a/ppapi/thunk/ppb_url_loader_api.h +++ b/ppapi/thunk/ppb_url_loader_api.h @@ -49,14 +49,6 @@ class PPB_URLLoader_API { virtual void GrantUniversalAccess() = 0; virtual void RegisterStatusCallback( PP_URLLoaderTrusted_StatusCallback cb) = 0; - - // Internal function. This will fill in the given response info data and - // return true on sucesss. If the dowbload was to a file, there will be one - // plugin reference transferred to the caller. On failure, returns false. - // - // If body_as_file_ref is non-zero, this will transfer one plugin reference - // to that object to the caller. - virtual bool GetResponseInfoData(URLResponseInfoData* data) = 0; }; } // namespace thunk diff --git a/ppapi/thunk/resource_creation_api.h b/ppapi/thunk/resource_creation_api.h index cd7e348..ec512ea 100644 --- a/ppapi/thunk/resource_creation_api.h +++ b/ppapi/thunk/resource_creation_api.h @@ -29,6 +29,7 @@ struct PP_Size; namespace ppapi { +struct PPB_FileRef_CreateInfo; struct URLRequestInfoData; struct URLResponseInfoData; @@ -47,6 +48,12 @@ class ResourceCreationAPI { virtual PP_Resource CreateFileRef(PP_Instance instance, PP_Resource file_system, const char* path) = 0; + // Like the above version but takes a serialized file ref. The resource + // in the serialized file ref is passed into this, which takes ownership of + // the reference. In the proxy, the return value will be a plugin resource. + // In the impl, the return value will be the same resource ID. + virtual PP_Resource CreateFileRef( + const PPB_FileRef_CreateInfo& serialized) = 0; virtual PP_Resource CreateFileSystem(PP_Instance instance, PP_FileSystemType type) = 0; virtual PP_Resource CreateIsolatedFileSystem(PP_Instance instance, diff --git a/ppapi/thunk/thunk.h b/ppapi/thunk/thunk.h index 2b074ff..2e31d2a 100644 --- a/ppapi/thunk/thunk.h +++ b/ppapi/thunk/thunk.h @@ -10,7 +10,6 @@ #include "ppapi/c/trusted/ppb_buffer_trusted.h" #include "ppapi/c/trusted/ppb_graphics_3d_trusted.h" #include "ppapi/c/trusted/ppb_image_data_trusted.h" -#include "ppapi/c/trusted/ppb_url_loader_trusted.h" #include "ppapi/thunk/ppapi_thunk_export.h" // Declares a getter for the interface thunk of the form: @@ -50,8 +49,6 @@ PPAPI_THUNK_EXPORT const PPB_ImageDataTrusted_0_4* GetPPB_ImageDataTrusted_0_4_Thunk(); PPAPI_THUNK_EXPORT const PPB_Instance_Private_0_1* GetPPB_Instance_Private_0_1_Thunk(); -PPAPI_THUNK_EXPORT const PPB_URLLoaderTrusted_0_3* - GetPPB_URLLoaderTrusted_0_3_Thunk(); } // namespace thunk } // namespace ppapi diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.cc b/webkit/plugins/ppapi/mock_plugin_delegate.cc index 80cf90b..feccd2f 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.cc +++ b/webkit/plugins/ppapi/mock_plugin_delegate.cc @@ -418,5 +418,10 @@ bool MockPluginDelegate::IsRunningInProcess(PP_Instance instance) const { return false; } +void MockPluginDelegate::HandleDocumentLoad( + PluginInstance* instance, + const WebKit::WebURLResponse& response) { +} + } // namespace ppapi } // namespace webkit diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.h b/webkit/plugins/ppapi/mock_plugin_delegate.h index a059aa1..d343c2a 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.h +++ b/webkit/plugins/ppapi/mock_plugin_delegate.h @@ -181,6 +181,8 @@ class MockPluginDelegate : public PluginDelegate { base::ProcessId target_process_id, bool should_close_source) const; virtual bool IsRunningInProcess(PP_Instance instance) const; + virtual void HandleDocumentLoad(PluginInstance* instance, + const WebKit::WebURLResponse& response); }; } // namespace ppapi diff --git a/webkit/plugins/ppapi/plugin_delegate.h b/webkit/plugins/ppapi/plugin_delegate.h index ec0c922..f48e94e 100644 --- a/webkit/plugins/ppapi/plugin_delegate.h +++ b/webkit/plugins/ppapi/plugin_delegate.h @@ -84,6 +84,9 @@ class WebGamepads; class WebPlugin; struct WebCompositionUnderline; struct WebCursorInfo; +struct WebURLError; +class WebURLLoaderClient; +class WebURLResponse; } namespace webkit_glue { @@ -675,6 +678,14 @@ class PluginDelegate { // Returns true if running in process. virtual bool IsRunningInProcess(PP_Instance instance) const = 0; + + // Notifies the plugin of the document load. This should initiate the call to + // PPP_Instance.HandleDocumentLoad. + // + // The loader object should set itself on the PluginInstance as the document + // loader using set_document_loader. + virtual void HandleDocumentLoad(PluginInstance* instance, + const WebKit::WebURLResponse& response) = 0; }; } // namespace ppapi diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc index 82d853e..75cead2 100644 --- a/webkit/plugins/ppapi/plugin_module.cc +++ b/webkit/plugins/ppapi/plugin_module.cc @@ -346,8 +346,6 @@ const void* InternalGetInterface(const char* name) { return PPB_Proxy_Impl::GetInterface(); if (strcmp(name, PPB_UMA_PRIVATE_INTERFACE) == 0) return PPB_UMA_Private_Impl::GetInterface(); - if (strcmp(name, PPB_URLLOADERTRUSTED_INTERFACE_0_3) == 0) - return ::ppapi::thunk::GetPPB_URLLoaderTrusted_0_3_Thunk(); if (strcmp(name, PPB_VAR_DEPRECATED_INTERFACE) == 0) return PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface(); if (strcmp(name, PPB_VAR_INTERFACE_1_0) == 0) diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.cc b/webkit/plugins/ppapi/ppapi_plugin_instance.cc index 565478c..0bd76f4 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.cc +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.cc @@ -40,6 +40,7 @@ #include "ppapi/shared_impl/resource.h" #include "ppapi/shared_impl/scoped_pp_resource.h" #include "ppapi/shared_impl/time_conversion.h" +#include "ppapi/shared_impl/url_request_info_data.h" #include "ppapi/shared_impl/var.h" #include "ppapi/thunk/enter.h" #include "ppapi/thunk/ppb_buffer_api.h" @@ -50,6 +51,7 @@ #include "third_party/WebKit/Source/Platform/chromium/public/WebGamepads.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebURL.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebURLError.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h" @@ -84,7 +86,6 @@ #include "webkit/plugins/ppapi/ppb_buffer_impl.h" #include "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" #include "webkit/plugins/ppapi/ppb_image_data_impl.h" -#include "webkit/plugins/ppapi/ppb_url_loader_impl.h" #include "webkit/plugins/ppapi/ppp_pdf.h" #include "webkit/plugins/ppapi/url_request_info_util.h" #include "webkit/plugins/sad_plugin.h" @@ -134,7 +135,11 @@ using WebKit::WebPrintParams; using WebKit::WebPrintScalingOption; using WebKit::WebScopedUserGesture; using WebKit::WebString; +using WebKit::WebURLError; +using WebKit::WebURLLoader; +using WebKit::WebURLLoaderClient; using WebKit::WebURLRequest; +using WebKit::WebURLResponse; using WebKit::WebUserGestureIndicator; using WebKit::WebUserGestureToken; using WebKit::WebView; @@ -319,6 +324,51 @@ PluginInstance* PluginInstance::Create(PluginDelegate* delegate, plugin_url); } +PluginInstance::NaClDocumentLoader::NaClDocumentLoader() + : finished_loading_(false) { +} + +PluginInstance::NaClDocumentLoader::~NaClDocumentLoader(){ +} + +void PluginInstance::NaClDocumentLoader::ReplayReceivedData( + WebURLLoaderClient* document_loader) { + for (std::list<std::string>::iterator it = data_.begin(); + it != data_.end(); ++it) { + document_loader->didReceiveData(NULL, it->c_str(), it->length(), + 0 /* encoded_data_length */); + } + if (finished_loading_) { + document_loader->didFinishLoading(NULL, + 0 /* finish_time */); + } + if (error_.get()) { + document_loader->didFail(NULL, *error_); + } +} + +void PluginInstance::NaClDocumentLoader::didReceiveData( + WebURLLoader* loader, + const char* data, + int data_length, + int encoded_data_length) { + data_.push_back(std::string(data, data_length)); +} + +void PluginInstance::NaClDocumentLoader::didFinishLoading( + WebURLLoader* loader, + double finish_time) { + DCHECK(!finished_loading_); + finished_loading_ = true; +} + +void PluginInstance::NaClDocumentLoader::didFail( + WebURLLoader* loader, + const WebURLError& error) { + DCHECK(!error_.get()); + error_.reset(new WebURLError(error)); +} + PluginInstance::GamepadImpl::GamepadImpl(PluginDelegate* delegate) : Resource(::ppapi::Resource::Untracked()), delegate_(delegate) { @@ -385,7 +435,9 @@ PluginInstance::PluginInstance( text_input_caret_set_(false), selection_caret_(0), selection_anchor_(0), - pending_user_gesture_(0.0) { + pending_user_gesture_(0.0), + document_loader_(NULL), + nacl_document_load_(false) { pp_instance_ = HostGlobals::Get()->AddInstance(this); memset(¤t_print_settings_, 0, sizeof(current_print_settings_)); @@ -397,6 +449,12 @@ PluginInstance::PluginInstance( view_data_.is_page_visible = delegate->IsPageVisible(); resource_creation_ = delegate_->CreateResourceCreationAPI(this); + + // TODO(bbudge) remove this when the trusted NaCl plugin has been removed. + // We must defer certain plugin events for NaCl instances since we switch + // from the in-process to the out-of-process proxy after instantiating them. + if (module->name() == "Native Client") + nacl_document_load_ = true; } PluginInstance::~PluginInstance() { @@ -596,13 +654,27 @@ bool PluginInstance::Initialize(const std::vector<std::string>& arg_names, return success; } -bool PluginInstance::HandleDocumentLoad(PPB_URLLoader_Impl* loader) { - if (!document_loader_) - document_loader_ = loader; - DCHECK(loader == document_loader_.get()); - - return PP_ToBool(instance_interface_->HandleDocumentLoad( - pp_instance(), loader->pp_resource())); +bool PluginInstance::HandleDocumentLoad( + const WebKit::WebURLResponse& response) { + DCHECK(!document_loader_); + if (!nacl_document_load_) { + if (module()->is_crashed()) { + // Don't create a resource for a crashed plugin. + container()->element().document().frame()->stopLoading(); + return false; + } + delegate()->HandleDocumentLoad(this, response); + // If the load was not abandoned, document_loader_ will now be set. It's + // possible that the load was canceled by now and document_loader_ was + // already nulled out. + } else { + // The NaCl proxy isn't available, so save the response and record document + // load notifications for later replay. + nacl_document_response_ = response; + nacl_document_loader_.reset(new NaClDocumentLoader()); + document_loader_ = nacl_document_loader_.get(); + } + return true; } bool PluginInstance::SendCompositionEventToPlugin(PP_InputEvent_Type type, @@ -2452,9 +2524,18 @@ PP_NaClResult PluginInstance::ResetAsProxied( view_change_weak_ptr_factory_.InvalidateWeakPtrs(); SendDidChangeView(); - // If we received HandleDocumentLoad, re-send it now via the proxy. - if (document_loader_) - HandleDocumentLoad(document_loader_.get()); + DCHECK(nacl_document_load_); + nacl_document_load_ = false; + if (!nacl_document_response_.isNull()) { + document_loader_ = NULL; + // Pass the response to the new proxy. + HandleDocumentLoad(nacl_document_response_); + nacl_document_response_ = WebKit::WebURLResponse(); + // Replay any document load events we've received to the real loader. + nacl_document_loader_->ReplayReceivedData(document_loader_); + nacl_document_loader_.reset(NULL); + } + return PP_NACL_OK; } diff --git a/webkit/plugins/ppapi/ppapi_plugin_instance.h b/webkit/plugins/ppapi/ppapi_plugin_instance.h index 281b8d4..ae1da17 100644 --- a/webkit/plugins/ppapi/ppapi_plugin_instance.h +++ b/webkit/plugins/ppapi/ppapi_plugin_instance.h @@ -46,6 +46,8 @@ #include "ppapi/thunk/resource_creation_api.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebCanvas.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebString.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebURLLoaderClient.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebURLResponse.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebPlugin.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebUserGestureToken.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -65,8 +67,11 @@ class WebInputEvent; class WebLayer; class WebMouseEvent; class WebPluginContainer; +class WebURLLoader; +class WebURLResponse; struct WebCompositionUnderline; struct WebCursorInfo; +struct WebURLError; struct WebPrintParams; } @@ -131,6 +136,10 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : // nonzero. PP_Instance pp_instance() const { return pp_instance_; } + ::ppapi::PPP_Instance_Combined* instance_interface() const { + return instance_interface_.get(); + } + ::ppapi::thunk::ResourceCreationAPI& resource_creation() { return *resource_creation_.get(); } @@ -173,11 +182,11 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : bool full_frame() const { return full_frame_; } const ::ppapi::ViewData& view_data() const { return view_data_; } - // PPP_Instance and PPP_Instance_Private pass-through. + // PPP_Instance and PPP_Instance_Private. bool Initialize(const std::vector<std::string>& arg_names, const std::vector<std::string>& arg_values, bool full_frame); - bool HandleDocumentLoad(PPB_URLLoader_Impl* loader); + bool HandleDocumentLoad(const WebKit::WebURLResponse& response); bool HandleInputEvent(const WebKit::WebInputEvent& event, WebKit::WebCursorInfo* cursor_info); PP_Var GetInstanceObject(); @@ -352,6 +361,17 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : void SimulateImeSetCompositionEvent( const ::ppapi::InputEventData& input_event); + // The document loader is valid when the plugin is "full-frame" and in this + // case is non-NULL as long as the corresponding loader resource is alive. + // This pointer is non-owning, so the loader must use set_document_loader to + // clear itself when it is destroyed. + WebKit::WebURLLoaderClient* document_loader() const { + return document_loader_; + } + void set_document_loader(WebKit::WebURLLoaderClient* loader) { + document_loader_ = loader; + } + ContentDecryptorDelegate* GetContentDecryptorDelegate(); // PPB_Instance_API implementation. @@ -485,6 +505,31 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : private: friend class PpapiUnittest; + // Class to record document load notifications and play them back once the + // real document loader becomes available. Used only by NaCl instances. + class NaClDocumentLoader : public WebKit::WebURLLoaderClient { + public: + NaClDocumentLoader(); + virtual ~NaClDocumentLoader(); + + void ReplayReceivedData(WebURLLoaderClient* document_loader); + + // WebKit::WebURLLoaderClient implementation. + virtual void didReceiveData(WebKit::WebURLLoader* loader, + const char* data, + int data_length, + int encoded_data_length); + virtual void didFinishLoading(WebKit::WebURLLoader* loader, + double finish_time); + virtual void didFail(WebKit::WebURLLoader* loader, + const WebKit::WebURLError& error); + + private: + std::list<std::string> data_; + bool finished_loading_; + scoped_ptr<WebKit::WebURLError> error_; + }; + // Implements PPB_Gamepad_API. This is just to avoid having an excessive // number of interfaces implemented by PluginInstance. class GamepadImpl : public ::ppapi::thunk::PPB_Gamepad_API, @@ -778,9 +823,12 @@ class WEBKIT_PLUGINS_EXPORT PluginInstance : std::vector<std::string> argn_; std::vector<std::string> argv_; - // This is NULL unless HandleDocumentLoad has called. In that case, we store - // the pointer so we can re-send it later if we are reset to talk to NaCl. - scoped_refptr<PPB_URLLoader_Impl> document_loader_; + // Non-owning pointer to the document loader, if any. + WebKit::WebURLLoaderClient* document_loader_; + // State for deferring document loads. Used only by NaCl instances. + WebKit::WebURLResponse nacl_document_response_; + scoped_ptr<NaClDocumentLoader> nacl_document_loader_; + bool nacl_document_load_; // The ContentDecryptorDelegate forwards PPP_ContentDecryptor_Private // calls and handles PPB_ContentDecryptor_Private calls. diff --git a/webkit/plugins/ppapi/ppapi_webplugin_impl.cc b/webkit/plugins/ppapi/ppapi_webplugin_impl.cc index 7257f2e..30820fb 100644 --- a/webkit/plugins/ppapi/ppapi_webplugin_impl.cc +++ b/webkit/plugins/ppapi/ppapi_webplugin_impl.cc @@ -14,6 +14,7 @@ #include "third_party/WebKit/Source/Platform/chromium/public/WebPoint.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebRect.h" #include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h" +#include "third_party/WebKit/Source/Platform/chromium/public/WebURLLoaderClient.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" @@ -27,7 +28,6 @@ #include "webkit/plugins/ppapi/npobject_var.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" using ppapi::NPObjectVar; using WebKit::WebCanvas; @@ -191,38 +191,26 @@ bool WebPluginImpl::handleInputEvent(const WebKit::WebInputEvent& event, void WebPluginImpl::didReceiveResponse( const WebKit::WebURLResponse& response) { - DCHECK(!document_loader_); - - if (instance_->module()->is_crashed()) { - // Don't create a resource for a crashed plugin. - instance_->container()->element().document().frame()->stopLoading(); - return; - } - - document_loader_ = new PPB_URLLoader_Impl(instance_->pp_instance(), true); - document_loader_->didReceiveResponse(NULL, response); - - if (!instance_->HandleDocumentLoad(document_loader_)) - document_loader_ = NULL; + DCHECK(!instance_->document_loader()); + instance_->HandleDocumentLoad(response); } void WebPluginImpl::didReceiveData(const char* data, int data_length) { - if (document_loader_) - document_loader_->didReceiveData(NULL, data, data_length, data_length); + WebKit::WebURLLoaderClient* document_loader = instance_->document_loader(); + if (document_loader) + document_loader->didReceiveData(NULL, data, data_length, 0); } void WebPluginImpl::didFinishLoading() { - if (document_loader_) { - document_loader_->didFinishLoading(NULL, 0); - document_loader_ = NULL; - } + WebKit::WebURLLoaderClient* document_loader = instance_->document_loader(); + if (document_loader) + document_loader->didFinishLoading(NULL, 0.0); } void WebPluginImpl::didFailLoading(const WebKit::WebURLError& error) { - if (document_loader_) { - document_loader_->didFail(NULL, error); - document_loader_ = NULL; - } + WebKit::WebURLLoaderClient* document_loader = instance_->document_loader(); + if (document_loader) + document_loader->didFail(NULL, error); } void WebPluginImpl::didFinishLoadingFrameRequest(const WebKit::WebURL& url, diff --git a/webkit/plugins/ppapi/ppapi_webplugin_impl.h b/webkit/plugins/ppapi/ppapi_webplugin_impl.h index 0ea0080..11bcf89 100644 --- a/webkit/plugins/ppapi/ppapi_webplugin_impl.h +++ b/webkit/plugins/ppapi/ppapi_webplugin_impl.h @@ -96,7 +96,6 @@ class WebPluginImpl : public WebKit::WebPlugin { // being an embedded resource. bool full_frame_; scoped_refptr<PluginInstance> instance_; - scoped_refptr<PPB_URLLoader_Impl> document_loader_; gfx::Rect plugin_rect_; PP_Var instance_object_; WebKit::WebPluginContainer* container_; diff --git a/webkit/plugins/ppapi/ppb_proxy_impl.cc b/webkit/plugins/ppapi/ppb_proxy_impl.cc index 070aa7a..2910045 100644 --- a/webkit/plugins/ppapi/ppb_proxy_impl.cc +++ b/webkit/plugins/ppapi/ppb_proxy_impl.cc @@ -10,7 +10,6 @@ #include "webkit/plugins/ppapi/host_globals.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" using ppapi::PpapiGlobals; using ppapi::thunk::EnterResource; @@ -42,13 +41,6 @@ void SetReserveInstanceIDCallback(PP_Module module, plugin_module->SetReserveInstanceIDCallback(reserve); } -int32_t GetURLLoaderBufferedBytes(PP_Resource url_loader) { - EnterResource<PPB_URLLoader_API> enter(url_loader, true); - if (enter.succeeded()) - return static_cast<PPB_URLLoader_Impl*>(enter.object())->buffer_size(); - return 0; -} - void AddRefModule(PP_Module module) { PluginModule* plugin_module = HostGlobals::Get()->GetModule(module); if (plugin_module) @@ -72,7 +64,6 @@ const PPB_Proxy_Private ppb_proxy = { &PluginCrashed, &GetInstanceForResource, &SetReserveInstanceIDCallback, - &GetURLLoaderBufferedBytes, &AddRefModule, &ReleaseModule, &IsInModuleDestructor diff --git a/webkit/plugins/ppapi/ppb_url_loader_impl.cc b/webkit/plugins/ppapi/ppb_url_loader_impl.cc deleted file mode 100644 index 0b0869d..0000000 --- a/webkit/plugins/ppapi/ppb_url_loader_impl.cc +++ /dev/null @@ -1,550 +0,0 @@ -// Copyright (c) 2012 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 "webkit/plugins/ppapi/ppb_url_loader_impl.h" - -#include "base/logging.h" -#include "net/base/net_errors.h" -#include "ppapi/c/pp_completion_callback.h" -#include "ppapi/c/pp_errors.h" -#include "ppapi/c/ppb_url_loader.h" -#include "ppapi/c/trusted/ppb_url_loader_trusted.h" -#include "ppapi/shared_impl/ppapi_globals.h" -#include "ppapi/shared_impl/url_response_info_data.h" -#include "ppapi/thunk/enter.h" -#include "ppapi/thunk/ppb_url_request_info_api.h" -#include "third_party/WebKit/Source/Platform/chromium/public/WebURLError.h" -#include "third_party/WebKit/Source/Platform/chromium/public/WebURLLoader.h" -#include "third_party/WebKit/Source/Platform/chromium/public/WebURLRequest.h" -#include "third_party/WebKit/Source/Platform/chromium/public/WebURLResponse.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebPluginContainer.h" -#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderOptions.h" -#include "webkit/appcache/web_application_cache_host_impl.h" -#include "webkit/plugins/ppapi/common.h" -#include "webkit/plugins/ppapi/plugin_module.h" -#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" -#include "webkit/plugins/ppapi/resource_helper.h" -#include "webkit/plugins/ppapi/url_request_info_util.h" -#include "webkit/plugins/ppapi/url_response_info_util.h" - -using appcache::WebApplicationCacheHostImpl; -using ppapi::Resource; -using ppapi::thunk::EnterResourceNoLock; -using ppapi::thunk::PPB_URLLoader_API; -using ppapi::thunk::PPB_URLRequestInfo_API; -using ppapi::TrackedCallback; -using WebKit::WebFrame; -using WebKit::WebString; -using WebKit::WebURL; -using WebKit::WebURLError; -using WebKit::WebURLLoader; -using WebKit::WebURLLoaderOptions; -using WebKit::WebURLRequest; -using WebKit::WebURLResponse; - -#ifdef _MSC_VER -// Do not warn about use of std::copy with raw pointers. -#pragma warning(disable : 4996) -#endif - -namespace webkit { -namespace ppapi { - -namespace { - -WebFrame* GetFrameForResource(const Resource* resource) { - PluginInstance* plugin_instance = ResourceHelper::GetPluginInstance(resource); - if (!plugin_instance) - return NULL; - return plugin_instance->container()->element().document().frame(); -} - -} // namespace - -PPB_URLLoader_Impl::PPB_URLLoader_Impl(PP_Instance instance, - bool main_document_loader) - : Resource(::ppapi::OBJECT_IS_IMPL, instance), - main_document_loader_(main_document_loader), - pending_callback_(), - bytes_sent_(0), - total_bytes_to_be_sent_(-1), - bytes_received_(0), - total_bytes_to_be_received_(-1), - user_buffer_(NULL), - user_buffer_size_(0), - done_status_(PP_OK_COMPLETIONPENDING), - is_streaming_to_file_(false), - is_asynchronous_load_suspended_(false), - has_universal_access_(false), - status_callback_(NULL) { -} - -PPB_URLLoader_Impl::~PPB_URLLoader_Impl() { - // Removes the resource from the ResourceTracker's tables. This normally - // happens as part of Resource destruction, but if a subclass destructor - // has a risk of re-entering destruction via the ResourceTracker, it can - // call this explicitly to get rid of the table entry before continuing - // with the destruction. If the resource is not in the ResourceTracker's - // tables, silently does nothing. See http://crbug.com/159429. - RemoveFromResourceTracker(); -} - -PPB_URLLoader_API* PPB_URLLoader_Impl::AsPPB_URLLoader_API() { - return this; -} - -void PPB_URLLoader_Impl::InstanceWasDeleted() { - loader_.reset(); -} - -int32_t PPB_URLLoader_Impl::Open(PP_Resource request_id, - scoped_refptr<TrackedCallback> callback) { - EnterResourceNoLock<PPB_URLRequestInfo_API> enter_request(request_id, true); - if (enter_request.failed()) { - Log(PP_LOGLEVEL_ERROR, - "PPB_URLLoader.Open: invalid request resource ID. (Hint to C++ wrapper" - " users: use the ResourceRequest constructor that takes an instance or" - " else the request will be null.)"); - return PP_ERROR_BADARGUMENT; - } - return Open(enter_request.object()->GetData(), 0, callback); -} - -int32_t PPB_URLLoader_Impl::Open( - const ::ppapi::URLRequestInfoData& request_data, - int requestor_pid, - scoped_refptr<TrackedCallback> callback) { - // Main document loads are already open, so don't allow people to open them - // again. - if (main_document_loader_) - return PP_ERROR_INPROGRESS; - - int32_t rv = ValidateCallback(callback); - if (rv != PP_OK) - return rv; - - // Create a copy of the request data since CreateWebURLRequest will populate - // the file refs. - ::ppapi::URLRequestInfoData filled_in_request_data = request_data; - - if (URLRequestRequiresUniversalAccess(filled_in_request_data) && - !has_universal_access_) { - Log(PP_LOGLEVEL_ERROR, "PPB_URLLoader.Open: The URL you're requesting is " - " on a different security origin than your plugin. To request " - " cross-origin resources, see " - " PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS."); - return PP_ERROR_NOACCESS; - } - - if (loader_) - return PP_ERROR_INPROGRESS; - - WebFrame* frame = GetFrameForResource(this); - if (!frame) - return PP_ERROR_FAILED; - WebURLRequest web_request; - if (!CreateWebURLRequest(&filled_in_request_data, frame, &web_request)) - return PP_ERROR_FAILED; - web_request.setRequestorProcessID(requestor_pid); - - // Save a copy of the request info so the plugin can continue to use and - // change it while we're doing the request without affecting us. We must do - // this after CreateWebURLRequest since that fills out the file refs. - request_data_ = filled_in_request_data; - - WebURLLoaderOptions options; - if (has_universal_access_) { - options.allowCredentials = true; - options.crossOriginRequestPolicy = - WebURLLoaderOptions::CrossOriginRequestPolicyAllow; - } else { - // All other HTTP requests are untrusted. - options.untrustedHTTP = true; - if (request_data_.allow_cross_origin_requests) { - // Allow cross-origin requests with access control. The request specifies - // if credentials are to be sent. - options.allowCredentials = request_data_.allow_credentials; - options.crossOriginRequestPolicy = - WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl; - } else { - // Same-origin requests can always send credentials. - options.allowCredentials = true; - } - } - - is_asynchronous_load_suspended_ = false; - loader_.reset(frame->createAssociatedURLLoader(options)); - if (!loader_) - return PP_ERROR_FAILED; - - loader_->loadAsynchronously(web_request, this); - - // Notify completion when we receive a redirect or response headers. - RegisterCallback(callback); - return PP_OK_COMPLETIONPENDING; -} - -int32_t PPB_URLLoader_Impl::FollowRedirect( - scoped_refptr<TrackedCallback> callback) { - int32_t rv = ValidateCallback(callback); - if (rv != PP_OK) - return rv; - - SetDefersLoading(false); // Allow the redirect to continue. - RegisterCallback(callback); - return PP_OK_COMPLETIONPENDING; -} - -PP_Bool PPB_URLLoader_Impl::GetUploadProgress(int64_t* bytes_sent, - int64_t* total_bytes_to_be_sent) { - if (!RecordUploadProgress()) { - *bytes_sent = 0; - *total_bytes_to_be_sent = 0; - return PP_FALSE; - } - *bytes_sent = bytes_sent_; - *total_bytes_to_be_sent = total_bytes_to_be_sent_; - return PP_TRUE; -} - -PP_Bool PPB_URLLoader_Impl::GetDownloadProgress( - int64_t* bytes_received, - int64_t* total_bytes_to_be_received) { - if (!RecordDownloadProgress()) { - *bytes_received = 0; - *total_bytes_to_be_received = 0; - return PP_FALSE; - } - *bytes_received = bytes_received_; - *total_bytes_to_be_received = total_bytes_to_be_received_; - return PP_TRUE; -} - -PP_Resource PPB_URLLoader_Impl::GetResponseInfo() { - ::ppapi::thunk::EnterResourceCreationNoLock enter(pp_instance()); - if (enter.failed() || !response_info_) - return 0; - - // Since we're the "host" the process-local resource for the file ref is - // the same as the host resource. We pass a ref to the file ref. - if (!response_info_->body_as_file_ref.resource.is_null()) { - ::ppapi::PpapiGlobals::Get()->GetResourceTracker()->AddRefResource( - response_info_->body_as_file_ref.resource.host_resource()); - } - return enter.functions()->CreateURLResponseInfo( - pp_instance(), - *response_info_, - response_info_->body_as_file_ref.resource.host_resource()); -} - -int32_t PPB_URLLoader_Impl::ReadResponseBody( - void* buffer, - int32_t bytes_to_read, - scoped_refptr<TrackedCallback> callback) { - int32_t rv = ValidateCallback(callback); - if (rv != PP_OK) - return rv; - if (!response_info_.get() || - !response_info_->body_as_file_ref.resource.is_null()) - return PP_ERROR_FAILED; - if (bytes_to_read <= 0 || !buffer) - return PP_ERROR_BADARGUMENT; - - user_buffer_ = static_cast<char*>(buffer); - user_buffer_size_ = bytes_to_read; - - if (!buffer_.empty()) - return FillUserBuffer(); - - // We may have already reached EOF. - if (done_status_ != PP_OK_COMPLETIONPENDING) { - user_buffer_ = NULL; - user_buffer_size_ = 0; - return done_status_; - } - - RegisterCallback(callback); - return PP_OK_COMPLETIONPENDING; -} - -int32_t PPB_URLLoader_Impl::FinishStreamingToFile( - scoped_refptr<TrackedCallback> callback) { - int32_t rv = ValidateCallback(callback); - if (rv != PP_OK) - return rv; - if (!response_info_.get() || - response_info_->body_as_file_ref.resource.is_null()) - return PP_ERROR_FAILED; - - // We may have already reached EOF. - if (done_status_ != PP_OK_COMPLETIONPENDING) - return done_status_; - - is_streaming_to_file_ = true; - if (is_asynchronous_load_suspended_) - SetDefersLoading(false); - - // Wait for didFinishLoading / didFail. - RegisterCallback(callback); - return PP_OK_COMPLETIONPENDING; -} - -void PPB_URLLoader_Impl::Close() { - if (loader_) - loader_->cancel(); - else if (main_document_loader_) - GetFrameForResource(this)->stopLoading(); - - // We must not access the buffer provided by the caller from this point on. - user_buffer_ = NULL; - user_buffer_size_ = 0; - if (TrackedCallback::IsPending(pending_callback_)) - pending_callback_->PostAbort(); -} - -void PPB_URLLoader_Impl::GrantUniversalAccess() { - has_universal_access_ = true; -} - -void PPB_URLLoader_Impl::RegisterStatusCallback( - PP_URLLoaderTrusted_StatusCallback cb) { - status_callback_ = cb; -} - -bool PPB_URLLoader_Impl::GetResponseInfoData( - ::ppapi::URLResponseInfoData* data) { - if (!response_info_) - return false; - - *data = *response_info_; - - // We transfer one plugin reference to the FileRef to the caller. - if (!response_info_->body_as_file_ref.resource.is_null()) { - ::ppapi::PpapiGlobals::Get()->GetResourceTracker()->AddRefResource( - response_info_->body_as_file_ref.resource.host_resource()); - } - return true; -} - -void PPB_URLLoader_Impl::willSendRequest( - WebURLLoader* loader, - WebURLRequest& new_request, - const WebURLResponse& redirect_response) { - if (!request_data_.follow_redirects) { - SaveResponse(redirect_response); - SetDefersLoading(true); - RunCallback(PP_OK); - } -} - -void PPB_URLLoader_Impl::didSendData( - WebURLLoader* loader, - unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent) { - // TODO(darin): Bounds check input? - bytes_sent_ = static_cast<int64_t>(bytes_sent); - total_bytes_to_be_sent_ = static_cast<int64_t>(total_bytes_to_be_sent); - UpdateStatus(); -} - -void PPB_URLLoader_Impl::didReceiveResponse(WebURLLoader* loader, - const WebURLResponse& response) { - SaveResponse(response); - - // Sets -1 if the content length is unknown. - total_bytes_to_be_received_ = response.expectedContentLength(); - UpdateStatus(); - - RunCallback(PP_OK); -} - -void PPB_URLLoader_Impl::didDownloadData(WebURLLoader* loader, - int data_length) { - bytes_received_ += data_length; - UpdateStatus(); -} - -void PPB_URLLoader_Impl::didReceiveData(WebURLLoader* loader, - const char* data, - int data_length, - int encoded_data_length) { - // Note that |loader| will be NULL for document loads. - bytes_received_ += data_length; - UpdateStatus(); - - buffer_.insert(buffer_.end(), data, data + data_length); - - // To avoid letting the network stack download an entire stream all at once, - // defer loading when we have enough buffer. - // Check for this before we run the callback, even though that could move - // data out of the buffer. Doing anything after the callback is unsafe. - DCHECK(request_data_.prefetch_buffer_lower_threshold < - request_data_.prefetch_buffer_upper_threshold); - if (!is_streaming_to_file_ && - !is_asynchronous_load_suspended_ && - (buffer_.size() >= static_cast<size_t>( - request_data_.prefetch_buffer_upper_threshold))) { - DVLOG(1) << "Suspending async load - buffer size: " << buffer_.size(); - SetDefersLoading(true); - } - - if (user_buffer_) { - RunCallback(FillUserBuffer()); - } else { - DCHECK(!TrackedCallback::IsPending(pending_callback_)); - } -} - -void PPB_URLLoader_Impl::didFinishLoading(WebURLLoader* loader, - double finish_time) { - FinishLoading(PP_OK); -} - -void PPB_URLLoader_Impl::didFail(WebURLLoader* loader, - const WebURLError& error) { - int32_t pp_error = PP_ERROR_FAILED; - if (error.domain.equals(WebString::fromUTF8(net::kErrorDomain))) { - // TODO(bbudge): Extend pp_errors.h to cover interesting network errors - // from the net error domain. - switch (error.reason) { - case net::ERR_ABORTED: - pp_error = PP_ERROR_ABORTED; - break; - case net::ERR_ACCESS_DENIED: - case net::ERR_NETWORK_ACCESS_DENIED: - pp_error = PP_ERROR_NOACCESS; - break; - } - } else { - // It's a WebKit error. - pp_error = PP_ERROR_NOACCESS; - } - - FinishLoading(pp_error); -} - -void PPB_URLLoader_Impl::SetDefersLoading(bool defers_loading) { - if (loader_) { - loader_->setDefersLoading(defers_loading); - is_asynchronous_load_suspended_ = defers_loading; - } - - // TODO(brettw) bug 96770: We need a way to set the defers loading flag on - // main document loads (when the loader_ is null). -} - -void PPB_URLLoader_Impl::FinishLoading(int32_t done_status) { - done_status_ = done_status; - user_buffer_ = NULL; - user_buffer_size_ = 0; - // If the client hasn't called any function that takes a callback since - // the initial call to Open, or called ReadResponseBody and got a - // synchronous return, then the callback will be NULL. - if (TrackedCallback::IsPending(pending_callback_)) - RunCallback(done_status_); -} - -int32_t PPB_URLLoader_Impl::ValidateCallback( - scoped_refptr<TrackedCallback> callback) { - DCHECK(callback); - - if (TrackedCallback::IsPending(pending_callback_)) - return PP_ERROR_INPROGRESS; - - return PP_OK; -} - -void PPB_URLLoader_Impl::RegisterCallback( - scoped_refptr<TrackedCallback> callback) { - DCHECK(!TrackedCallback::IsPending(pending_callback_)); - - PluginModule* plugin_module = ResourceHelper::GetPluginModule(this); - if (!plugin_module) - return; - - pending_callback_ = callback; -} - -void PPB_URLLoader_Impl::RunCallback(int32_t result) { - // This may be null only when this is a main document loader. - if (!pending_callback_) { - CHECK(main_document_loader_); - return; - } - - // If |user_buffer_| was set as part of registering a callback, the paths - // which trigger that callack must have cleared it since the callback is now - // free to delete it. - DCHECK(!user_buffer_); - - // As a second line of defense, clear the |user_buffer_| in case the - // callbacks get called in an unexpected order. - user_buffer_ = NULL; - user_buffer_size_ = 0; - pending_callback_->Run(result); -} - -size_t PPB_URLLoader_Impl::FillUserBuffer() { - DCHECK(user_buffer_); - DCHECK(user_buffer_size_); - - size_t bytes_to_copy = std::min(buffer_.size(), user_buffer_size_); - std::copy(buffer_.begin(), buffer_.begin() + bytes_to_copy, user_buffer_); - buffer_.erase(buffer_.begin(), buffer_.begin() + bytes_to_copy); - - // If the buffer is getting too empty, resume asynchronous loading. - if (is_asynchronous_load_suspended_ && - buffer_.size() <= static_cast<size_t>( - request_data_.prefetch_buffer_lower_threshold)) { - DVLOG(1) << "Resuming async load - buffer size: " << buffer_.size(); - SetDefersLoading(false); - } - - // Reset for next time. - user_buffer_ = NULL; - user_buffer_size_ = 0; - return bytes_to_copy; -} - -void PPB_URLLoader_Impl::SaveResponse(const WebURLResponse& response) { - // DataFromWebURLResponse returns a file ref with one reference to it, which - // we take over via our ScopedPPResource. - response_info_.reset(new ::ppapi::URLResponseInfoData( - DataFromWebURLResponse(pp_instance(), response))); - response_info_file_ref_ = ::ppapi::ScopedPPResource( - ::ppapi::ScopedPPResource::PassRef(), - response_info_->body_as_file_ref.resource.host_resource()); -} - -void PPB_URLLoader_Impl::UpdateStatus() { - if (status_callback_ && - (RecordDownloadProgress() || RecordUploadProgress())) { - // Here we go through some effort to only send the exact information that - // the requestor wanted in the request flags. It would be just as - // efficient to send all of it, but we don't want people to rely on - // getting download progress when they happen to set the upload progress - // flag. - status_callback_( - pp_instance(), pp_resource(), - RecordUploadProgress() ? bytes_sent_ : -1, - RecordUploadProgress() ? total_bytes_to_be_sent_ : -1, - RecordDownloadProgress() ? bytes_received_ : -1, - RecordDownloadProgress() ? total_bytes_to_be_received_ : -1); - } -} - -bool PPB_URLLoader_Impl::RecordDownloadProgress() const { - return request_data_.record_download_progress; -} - -bool PPB_URLLoader_Impl::RecordUploadProgress() const { - return request_data_.record_upload_progress; -} - -} // namespace ppapi -} // namespace webkit diff --git a/webkit/plugins/ppapi/ppb_url_loader_impl.h b/webkit/plugins/ppapi/ppb_url_loader_impl.h deleted file mode 100644 index bb4ea3a..0000000 --- a/webkit/plugins/ppapi/ppb_url_loader_impl.h +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2012 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. - -#ifndef WEBKIT_PLUGINS_PPAPI_PPB_URL_LOADER_IMPL_H_ -#define WEBKIT_PLUGINS_PPAPI_PPB_URL_LOADER_IMPL_H_ - -#include <deque> - -#include "base/memory/ref_counted.h" -#include "base/memory/scoped_ptr.h" -#include "ppapi/c/pp_completion_callback.h" -#include "ppapi/c/trusted/ppb_url_loader_trusted.h" -#include "ppapi/shared_impl/resource.h" -#include "ppapi/shared_impl/scoped_pp_resource.h" -#include "ppapi/shared_impl/tracked_callback.h" -#include "ppapi/shared_impl/url_request_info_data.h" -#include "ppapi/thunk/ppb_url_loader_api.h" -#include "third_party/WebKit/Source/Platform/chromium/public/WebURLLoaderClient.h" -#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" - -namespace WebKit { -class WebURL; -} - -namespace webkit { -namespace ppapi { - -class PPB_URLLoader_Impl : public ::ppapi::Resource, - public ::ppapi::thunk::PPB_URLLoader_API, - public WebKit::WebURLLoaderClient { - public: - PPB_URLLoader_Impl(PP_Instance instance, bool main_document_loader); - virtual ~PPB_URLLoader_Impl(); - - // Resource overrides. - virtual ::ppapi::thunk::PPB_URLLoader_API* AsPPB_URLLoader_API() OVERRIDE; - virtual void InstanceWasDeleted() OVERRIDE; - - // PPB_URLLoader_API implementation. - virtual int32_t Open( - PP_Resource request_id, - scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE; - virtual int32_t Open( - const ::ppapi::URLRequestInfoData& data, - int requestor_pid, - scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE; - virtual int32_t FollowRedirect( - scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE; - virtual PP_Bool GetUploadProgress(int64_t* bytes_sent, - int64_t* total_bytes_to_be_sent) OVERRIDE; - virtual PP_Bool GetDownloadProgress( - int64_t* bytes_received, - int64_t* total_bytes_to_be_received) OVERRIDE; - virtual PP_Resource GetResponseInfo() OVERRIDE; - virtual int32_t ReadResponseBody( - void* buffer, - int32_t bytes_to_read, - scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE; - virtual int32_t FinishStreamingToFile( - scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE; - virtual void Close() OVERRIDE; - virtual void GrantUniversalAccess() OVERRIDE; - virtual void RegisterStatusCallback( - PP_URLLoaderTrusted_StatusCallback cb) OVERRIDE; - virtual bool GetResponseInfoData( - ::ppapi::URLResponseInfoData* data) OVERRIDE; - - // WebKit::WebURLLoaderClient implementation. - virtual void willSendRequest(WebKit::WebURLLoader* loader, - WebKit::WebURLRequest& new_request, - const WebKit::WebURLResponse& redir_response); - virtual void didSendData(WebKit::WebURLLoader* loader, - unsigned long long bytes_sent, - unsigned long long total_bytes_to_be_sent); - virtual void didReceiveResponse(WebKit::WebURLLoader* loader, - const WebKit::WebURLResponse& response); - virtual void didDownloadData(WebKit::WebURLLoader* loader, - int data_length); - - virtual void didReceiveData(WebKit::WebURLLoader* loader, - const char* data, - int data_length, - int encoded_data_length); - virtual void didFinishLoading(WebKit::WebURLLoader* loader, - double finish_time); - virtual void didFail(WebKit::WebURLLoader* loader, - const WebKit::WebURLError& error); - - // 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 - // |PP_ERROR_...| to be returned to the plugin. - int32_t ValidateCallback(scoped_refptr< ::ppapi::TrackedCallback> callback); - - // Sets up |callback| as the pending callback. This should only be called once - // it is certain that |PP_OK_COMPLETIONPENDING| will be returned. - void RegisterCallback(scoped_refptr< ::ppapi::TrackedCallback> callback); - - void RunCallback(int32_t result); - - size_t FillUserBuffer(); - - // Converts a WebURLResponse to a URLResponseInfo and saves it. - void SaveResponse(const WebKit::WebURLResponse& response); - - // Calls the status_callback_ (if any) with the current upload and download - // progress. Call this function if you update any of these values to - // synchronize an out-of-process plugin's state. - void UpdateStatus(); - - // Returns true if the plugin has requested we record download or upload - // progress. When false, we don't need to update the counters. We go out of - // our way not to allow access to this information unless it's requested, - // even when it would be easier just to return it and not check, so that - // plugins don't depend on access without setting the flag. - bool RecordDownloadProgress() const; - bool RecordUploadProgress() const; - - // Calls SetDefersLoading on the current load. This encapsulates the logic - // differences between document loads and regular ones. - void SetDefersLoading(bool defers_loading); - - void FinishLoading(int32_t done_status); - - // If true, then the plugin instance is a full-frame plugin and we're just - // wrapping the main document's loader (i.e. loader_ is null). - bool main_document_loader_; - - // Keep a copy of the request data. We specifically do this instead of - // keeping a reference to the request resource, because the plugin might - // change the request info resource out from under us. - ::ppapi::URLRequestInfoData request_data_; - - // The loader associated with this request. MAY BE NULL. - // - // This will be NULL if the load hasn't been opened yet, or if this is a main - // document loader (when registered as a mime type). Therefore, you should - // always NULL check this value before using it. In the case of a main - // document load, you would call the functions on the document to cancel the - // load, etc. since there is no loader. - scoped_ptr<WebKit::WebURLLoader> loader_; - - scoped_refptr< ::ppapi::TrackedCallback> pending_callback_; - std::deque<char> buffer_; - int64_t bytes_sent_; - int64_t total_bytes_to_be_sent_; - int64_t bytes_received_; - int64_t total_bytes_to_be_received_; - char* user_buffer_; - size_t user_buffer_size_; - int32_t done_status_; - bool is_streaming_to_file_; - bool is_asynchronous_load_suspended_; - - bool has_universal_access_; - - PP_URLLoaderTrusted_StatusCallback status_callback_; - - // When the response info is received, this stores the data. The - // ScopedResource maintains the reference to the file ref (if any) in the - // data object so we don't forget to dereference it. - scoped_ptr< ::ppapi::URLResponseInfoData > response_info_; - ::ppapi::ScopedPPResource response_info_file_ref_; - - DISALLOW_COPY_AND_ASSIGN(PPB_URLLoader_Impl); -}; - -} // namespace ppapi -} // namespace webkit - -#endif // WEBKIT_PLUGINS_PPAPI_PPB_URL_LOADER_IMPL_H_ diff --git a/webkit/plugins/ppapi/resource_creation_impl.cc b/webkit/plugins/ppapi/resource_creation_impl.cc index f091a38..94e6e83 100644 --- a/webkit/plugins/ppapi/resource_creation_impl.cc +++ b/webkit/plugins/ppapi/resource_creation_impl.cc @@ -21,7 +21,6 @@ #include "webkit/plugins/ppapi/ppb_scrollbar_impl.h" #include "webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h" #include "webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h" -#include "webkit/plugins/ppapi/ppb_url_loader_impl.h" #include "webkit/plugins/ppapi/ppb_video_decoder_impl.h" #include "webkit/plugins/ppapi/ppb_x509_certificate_private_impl.h" #include "webkit/plugins/ppapi/resource_helper.h" @@ -84,6 +83,13 @@ PP_Resource ResourceCreationImpl::CreateFileRef( return res ? res->GetReference() : 0; } +PP_Resource ResourceCreationImpl::CreateFileRef( + const ::ppapi::PPB_FileRef_CreateInfo& serialized) { + // When we're in-process, the host resource in the create info *is* the + // resource, so we don't need to do anything. + return serialized.resource.host_resource(); +} + PP_Resource ResourceCreationImpl::CreateFlashDeviceID(PP_Instance instance) { return 0; // Not supported in-process. } @@ -233,10 +239,6 @@ PP_Resource ResourceCreationImpl::CreateUDPSocketPrivate(PP_Instance instance) { return 0; // Not supported in-process. } -PP_Resource ResourceCreationImpl::CreateURLLoader(PP_Instance instance) { - return (new PPB_URLLoader_Impl(instance, false))->GetReference(); -} - PP_Resource ResourceCreationImpl::CreateVideoCapture(PP_Instance instance) { return 0; // VideoCapture is not supported in process now. } diff --git a/webkit/plugins/ppapi/resource_creation_impl.h b/webkit/plugins/ppapi/resource_creation_impl.h index da48bc8..9ccc4be 100644 --- a/webkit/plugins/ppapi/resource_creation_impl.h +++ b/webkit/plugins/ppapi/resource_creation_impl.h @@ -41,6 +41,8 @@ class WEBKIT_PLUGINS_EXPORT ResourceCreationImpl virtual PP_Resource CreateFileRef(PP_Instance instance, PP_Resource file_system, const char* path) OVERRIDE; + virtual PP_Resource CreateFileRef( + const ::ppapi::PPB_FileRef_CreateInfo& serialized) OVERRIDE; virtual PP_Resource CreateFlashDeviceID(PP_Instance instance) OVERRIDE; virtual PP_Resource CreateFlashFontFile( PP_Instance instance, @@ -110,7 +112,6 @@ class WEBKIT_PLUGINS_EXPORT ResourceCreationImpl PP_Instance instance) OVERRIDE; virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instance) OVERRIDE; virtual PP_Resource CreateUDPSocketPrivate(PP_Instance instance) OVERRIDE; - virtual PP_Resource CreateURLLoader(PP_Instance instance) OVERRIDE; virtual PP_Resource CreateVideoCapture(PP_Instance instance) OVERRIDE; virtual PP_Resource CreateVideoDecoder( PP_Instance instance, diff --git a/webkit/plugins/ppapi/url_response_info_util.h b/webkit/plugins/ppapi/url_response_info_util.h index ff805db..346ede6 100644 --- a/webkit/plugins/ppapi/url_response_info_util.h +++ b/webkit/plugins/ppapi/url_response_info_util.h @@ -7,6 +7,7 @@ #include "ppapi/c/pp_instance.h" #include "ppapi/shared_impl/url_response_info_data.h" +#include "webkit/plugins/webkit_plugins_export.h" namespace WebKit { class WebURLResponse; @@ -18,7 +19,7 @@ namespace ppapi { // The returned object will have one plugin reference to the "body_as_file_ref" // if it's non-null. It's expected that the result of this function will be // passed to the plugin. -::ppapi::URLResponseInfoData DataFromWebURLResponse( +WEBKIT_PLUGINS_EXPORT ::ppapi::URLResponseInfoData DataFromWebURLResponse( PP_Instance pp_instance, const WebKit::WebURLResponse& response); diff --git a/webkit/plugins/webkit_plugins.gypi b/webkit/plugins/webkit_plugins.gypi index 69a52b7..f14a1f5 100644 --- a/webkit/plugins/webkit_plugins.gypi +++ b/webkit/plugins/webkit_plugins.gypi @@ -181,8 +181,6 @@ '../plugins/ppapi/ppb_tcp_socket_private_impl.h', '../plugins/ppapi/ppb_uma_private_impl.cc', '../plugins/ppapi/ppb_uma_private_impl.h', - '../plugins/ppapi/ppb_url_loader_impl.cc', - '../plugins/ppapi/ppb_url_loader_impl.h', '../plugins/ppapi/ppb_var_deprecated_impl.cc', '../plugins/ppapi/ppb_var_deprecated_impl.h', '../plugins/ppapi/ppb_video_decoder_impl.cc', |