| // 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/browser/renderer_host/pepper/pepper_network_proxy_host.h" |
| |
| #include "base/bind.h" |
| #include "base/task/post_task.h" |
| #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h" |
| #include "content/browser/renderer_host/pepper/pepper_proxy_lookup_helper.h" |
| #include "content/browser/renderer_host/pepper/pepper_socket_utils.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/site_instance.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/public/common/socket_permission_request.h" |
| #include "net/proxy_resolution/proxy_info.h" |
| #include "ppapi/c/pp_errors.h" |
| #include "ppapi/host/dispatch_host_message.h" |
| #include "ppapi/host/ppapi_host.h" |
| #include "ppapi/proxy/ppapi_messages.h" |
| #include "services/network/public/mojom/network_context.mojom.h" |
| #include "services/network/public/mojom/proxy_lookup_client.mojom.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| bool LookUpProxyForURLCallback( |
| int render_process_host_id, |
| int render_frame_host_id, |
| const GURL& url, |
| network::mojom::ProxyLookupClientPtr proxy_lookup_client) { |
| RenderFrameHost* render_frame_host = |
| RenderFrameHost::FromID(render_process_host_id, render_frame_host_id); |
| if (!render_frame_host) |
| return false; |
| |
| SiteInstance* site_instance = render_frame_host->GetSiteInstance(); |
| StoragePartition* storage_partition = BrowserContext::GetStoragePartition( |
| site_instance->GetBrowserContext(), site_instance); |
| |
| storage_partition->GetNetworkContext()->LookUpProxyForURL( |
| url, std::move(proxy_lookup_client)); |
| return true; |
| } |
| |
| } // namespace |
| |
| PepperNetworkProxyHost::PepperNetworkProxyHost(BrowserPpapiHostImpl* host, |
| PP_Instance instance, |
| PP_Resource resource) |
| : ResourceHost(host->GetPpapiHost(), instance, resource), |
| render_process_id_(0), |
| render_frame_id_(0), |
| is_allowed_(false), |
| waiting_for_ui_thread_data_(true), |
| weak_factory_(this) { |
| host->GetRenderFrameIDsForInstance(instance, &render_process_id_, |
| &render_frame_id_); |
| base::PostTaskWithTraitsAndReplyWithResult( |
| FROM_HERE, {BrowserThread::UI}, |
| base::BindOnce(&GetUIThreadDataOnUIThread, render_process_id_, |
| render_frame_id_, host->external_plugin()), |
| base::BindOnce(&PepperNetworkProxyHost::DidGetUIThreadData, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| PepperNetworkProxyHost::~PepperNetworkProxyHost() = default; |
| |
| PepperNetworkProxyHost::UIThreadData::UIThreadData() : is_allowed(false) {} |
| |
| PepperNetworkProxyHost::UIThreadData::UIThreadData(const UIThreadData& other) = |
| default; |
| |
| PepperNetworkProxyHost::UIThreadData::~UIThreadData() {} |
| |
| // static |
| PepperNetworkProxyHost::UIThreadData |
| PepperNetworkProxyHost::GetUIThreadDataOnUIThread(int render_process_id, |
| int render_frame_id, |
| bool is_external_plugin) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| PepperNetworkProxyHost::UIThreadData result; |
| |
| SocketPermissionRequest request( |
| content::SocketPermissionRequest::RESOLVE_PROXY, std::string(), 0); |
| result.is_allowed = |
| pepper_socket_utils::CanUseSocketAPIs(is_external_plugin, |
| false /* is_private_api */, |
| &request, |
| render_process_id, |
| render_frame_id); |
| return result; |
| } |
| |
| void PepperNetworkProxyHost::DidGetUIThreadData( |
| const UIThreadData& ui_thread_data) { |
| is_allowed_ = ui_thread_data.is_allowed; |
| waiting_for_ui_thread_data_ = false; |
| TryToSendUnsentRequests(); |
| } |
| |
| int32_t PepperNetworkProxyHost::OnResourceMessageReceived( |
| const IPC::Message& msg, |
| ppapi::host::HostMessageContext* context) { |
| PPAPI_BEGIN_MESSAGE_MAP(PepperNetworkProxyHost, msg) |
| PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_NetworkProxy_GetProxyForURL, |
| OnMsgGetProxyForURL) |
| PPAPI_END_MESSAGE_MAP() |
| return PP_ERROR_FAILED; |
| } |
| |
| int32_t PepperNetworkProxyHost::OnMsgGetProxyForURL( |
| ppapi::host::HostMessageContext* context, |
| const std::string& url) { |
| GURL gurl(url); |
| if (gurl.is_valid()) { |
| UnsentRequest request = {gurl, context->MakeReplyMessageContext()}; |
| unsent_requests_.push(request); |
| TryToSendUnsentRequests(); |
| } else { |
| SendFailureReply(PP_ERROR_BADARGUMENT, context->MakeReplyMessageContext()); |
| } |
| return PP_OK_COMPLETIONPENDING; |
| } |
| |
| void PepperNetworkProxyHost::TryToSendUnsentRequests() { |
| if (waiting_for_ui_thread_data_) |
| return; |
| |
| while (!unsent_requests_.empty()) { |
| const UnsentRequest& request = unsent_requests_.front(); |
| if (!is_allowed_) { |
| SendFailureReply(PP_ERROR_NOACCESS, request.reply_context); |
| } else { |
| // Everything looks valid, so try to resolve the proxy. |
| auto lookup_helper = std::make_unique<PepperProxyLookupHelper>(); |
| PepperProxyLookupHelper::LookUpProxyForURLCallback |
| look_up_proxy_for_url_callback = base::BindOnce( |
| &LookUpProxyForURLCallback, render_process_id_, render_frame_id_); |
| PepperProxyLookupHelper::LookUpCompleteCallback |
| look_up_complete_callback = |
| base::BindOnce(&PepperNetworkProxyHost::OnResolveProxyCompleted, |
| weak_factory_.GetWeakPtr(), request.reply_context, |
| lookup_helper.get()); |
| lookup_helper->Start(request.url, |
| std::move(look_up_proxy_for_url_callback), |
| std::move(look_up_complete_callback)); |
| pending_requests_.insert(std::move(lookup_helper)); |
| } |
| unsent_requests_.pop(); |
| } |
| } |
| |
| void PepperNetworkProxyHost::OnResolveProxyCompleted( |
| ppapi::host::ReplyMessageContext context, |
| PepperProxyLookupHelper* pending_request, |
| base::Optional<net::ProxyInfo> proxy_info) { |
| auto it = pending_requests_.find(pending_request); |
| DCHECK(it != pending_requests_.end()); |
| pending_requests_.erase(it); |
| |
| std::string pac_string; |
| if (!proxy_info) { |
| // This can happen in cases of network service crash, shutdown, or when |
| // the request fails with ERR_MANDATORY_PROXY_CONFIGURATION_FAILED. There's |
| // really no action a plugin can take, so there's no need to distinguish |
| // which error occurred. |
| context.params.set_result(PP_ERROR_FAILED); |
| } else { |
| pac_string = proxy_info->ToPacString(); |
| } |
| host()->SendReply( |
| context, PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(pac_string)); |
| } |
| |
| void PepperNetworkProxyHost::SendFailureReply( |
| int32_t error, |
| ppapi::host::ReplyMessageContext context) { |
| context.params.set_result(error); |
| host()->SendReply( |
| context, PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(std::string())); |
| } |
| |
| } // namespace content |