| // Copyright 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_host_resolver_message_filter.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/logging.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_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_process_host.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/public/common/socket_permission_request.h" |
| #include "net/base/address_list.h" |
| #include "net/dns/public/dns_query_type.h" |
| #include "ppapi/c/pp_errors.h" |
| #include "ppapi/c/private/ppb_host_resolver_private.h" |
| #include "ppapi/c/private/ppb_net_address_private.h" |
| #include "ppapi/host/dispatch_host_message.h" |
| #include "ppapi/host/error_conversion.h" |
| #include "ppapi/host/host_message_context.h" |
| #include "ppapi/proxy/ppapi_messages.h" |
| #include "ppapi/shared_impl/private/net_address_private_impl.h" |
| #include "services/network/public/mojom/network_context.mojom.h" |
| |
| using ppapi::host::NetErrorToPepperError; |
| using ppapi::host::ReplyMessageContext; |
| |
| namespace content { |
| |
| namespace { |
| |
| void PrepareRequestInfo(const PP_HostResolver_Private_Hint& hint, |
| network::mojom::ResolveHostParameters* params) { |
| switch (hint.family) { |
| case PP_NETADDRESSFAMILY_PRIVATE_IPV4: |
| params->dns_query_type = net::DnsQueryType::A; |
| break; |
| case PP_NETADDRESSFAMILY_PRIVATE_IPV6: |
| params->dns_query_type = net::DnsQueryType::AAAA; |
| break; |
| default: |
| params->dns_query_type = net::DnsQueryType::UNSPECIFIED; |
| } |
| |
| if (hint.flags & PP_HOST_RESOLVER_PRIVATE_FLAGS_CANONNAME) |
| params->include_canonical_name = true; |
| if (hint.flags & PP_HOST_RESOLVER_PRIVATE_FLAGS_LOOPBACK_ONLY) |
| params->loopback_only = true; |
| } |
| |
| void CreateNetAddressListFromAddressList( |
| const net::AddressList& list, |
| std::vector<PP_NetAddress_Private>* net_address_list) { |
| DCHECK(net_address_list); |
| |
| net_address_list->clear(); |
| net_address_list->reserve(list.size()); |
| |
| PP_NetAddress_Private address; |
| for (size_t i = 0; i < list.size(); ++i) { |
| if (!ppapi::NetAddressPrivateImpl::IPEndPointToNetAddress( |
| list[i].address().bytes(), list[i].port(), &address)) { |
| net_address_list->clear(); |
| return; |
| } |
| net_address_list->push_back(address); |
| } |
| } |
| |
| } // namespace |
| |
| PepperHostResolverMessageFilter::PepperHostResolverMessageFilter( |
| BrowserPpapiHostImpl* host, |
| PP_Instance instance, |
| bool private_api) |
| : external_plugin_(host->external_plugin()), |
| private_api_(private_api), |
| render_process_id_(0), |
| render_frame_id_(0), |
| binding_(this) { |
| DCHECK(host); |
| |
| if (!host->GetRenderFrameIDsForInstance( |
| instance, &render_process_id_, &render_frame_id_)) { |
| NOTREACHED(); |
| } |
| } |
| |
| PepperHostResolverMessageFilter::~PepperHostResolverMessageFilter() {} |
| |
| scoped_refptr<base::TaskRunner> |
| PepperHostResolverMessageFilter::OverrideTaskRunnerForMessage( |
| const IPC::Message& message) { |
| if (message.type() == PpapiHostMsg_HostResolver_Resolve::ID) |
| return base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}); |
| return nullptr; |
| } |
| |
| int32_t PepperHostResolverMessageFilter::OnResourceMessageReceived( |
| const IPC::Message& msg, |
| ppapi::host::HostMessageContext* context) { |
| PPAPI_BEGIN_MESSAGE_MAP(PepperHostResolverMessageFilter, msg) |
| PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_HostResolver_Resolve, |
| OnMsgResolve) |
| PPAPI_END_MESSAGE_MAP() |
| return PP_ERROR_FAILED; |
| } |
| |
| int32_t PepperHostResolverMessageFilter::OnMsgResolve( |
| const ppapi::host::HostMessageContext* context, |
| const ppapi::HostPortPair& host_port, |
| const PP_HostResolver_Private_Hint& hint) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| |
| // Check plugin permissions. |
| SocketPermissionRequest request( |
| SocketPermissionRequest::RESOLVE_HOST, host_port.host, host_port.port); |
| if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, |
| private_api_, |
| &request, |
| render_process_id_, |
| render_frame_id_)) { |
| return PP_ERROR_NOACCESS; |
| } |
| |
| RenderProcessHost* render_process_host = |
| RenderProcessHost::FromID(render_process_id_); |
| if (!render_process_host) |
| return PP_ERROR_FAILED; |
| auto* storage_partition = render_process_host->GetStoragePartition(); |
| |
| // Grab a reference to this class to ensure that it's fully alive if a |
| // connection error occurs (i.e. ref count is higher than 0 and there's no |
| // task from ResourceMessageFilterDeleteTraits to delete this object on the IO |
| // thread pending). Balanced in OnComplete(); |
| AddRef(); |
| |
| network::mojom::ResolveHostClientPtr client_ptr; |
| binding_.Bind(mojo::MakeRequest(&client_ptr)); |
| binding_.set_connection_error_handler( |
| base::BindOnce(&PepperHostResolverMessageFilter::OnComplete, |
| base::Unretained(this), net::ERR_FAILED, base::nullopt)); |
| |
| network::mojom::ResolveHostParametersPtr parameters = |
| network::mojom::ResolveHostParameters::New(); |
| PrepareRequestInfo(hint, parameters.get()); |
| |
| storage_partition->GetNetworkContext()->ResolveHost( |
| net::HostPortPair(host_port.host, host_port.port), std::move(parameters), |
| std::move(client_ptr)); |
| host_resolve_context_ = context->MakeReplyMessageContext(); |
| |
| return PP_OK_COMPLETIONPENDING; |
| } |
| |
| void PepperHostResolverMessageFilter::OnComplete( |
| int result, |
| const base::Optional<net::AddressList>& resolved_addresses) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| binding_.Close(); |
| |
| base::PostTaskWithTraits( |
| FROM_HERE, {BrowserThread::IO}, |
| base::BindOnce(&PepperHostResolverMessageFilter::OnLookupFinished, this, |
| result, std::move(resolved_addresses), |
| host_resolve_context_)); |
| host_resolve_context_ = ppapi::host::ReplyMessageContext(); |
| |
| Release(); // Balances AddRef in OnMsgResolve. |
| } |
| |
| void PepperHostResolverMessageFilter::OnLookupFinished( |
| int net_result, |
| const base::Optional<net::AddressList>& addresses, |
| const ReplyMessageContext& context) { |
| if (net_result != net::OK) { |
| SendResolveError(NetErrorToPepperError(net_result), context); |
| } else { |
| const std::string& canonical_name = addresses.value().canonical_name(); |
| NetAddressList net_address_list; |
| CreateNetAddressListFromAddressList(addresses.value(), &net_address_list); |
| if (net_address_list.empty()) |
| SendResolveError(PP_ERROR_FAILED, context); |
| else |
| SendResolveReply(PP_OK, canonical_name, net_address_list, context); |
| } |
| } |
| |
| void PepperHostResolverMessageFilter::SendResolveReply( |
| int32_t result, |
| const std::string& canonical_name, |
| const NetAddressList& net_address_list, |
| const ReplyMessageContext& context) { |
| ReplyMessageContext reply_context = context; |
| reply_context.params.set_result(result); |
| SendReply(reply_context, |
| PpapiPluginMsg_HostResolver_ResolveReply(canonical_name, |
| net_address_list)); |
| } |
| |
| void PepperHostResolverMessageFilter::SendResolveError( |
| int32_t error, |
| const ReplyMessageContext& context) { |
| SendResolveReply(error, std::string(), NetAddressList(), context); |
| } |
| |
| } // namespace content |