Home | History | Annotate | Download | only in pepper
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/renderer_host/pepper/pepper_network_proxy_host.h"
      6 
      7 #include "base/bind.h"
      8 #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
      9 #include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
     10 #include "content/public/browser/browser_context.h"
     11 #include "content/public/browser/browser_thread.h"
     12 #include "content/public/browser/render_process_host.h"
     13 #include "content/public/common/socket_permission_request.h"
     14 #include "net/base/load_flags.h"
     15 #include "net/base/net_errors.h"
     16 #include "net/proxy/proxy_info.h"
     17 #include "net/url_request/url_request_context.h"
     18 #include "net/url_request/url_request_context_getter.h"
     19 #include "ppapi/c/pp_errors.h"
     20 #include "ppapi/host/dispatch_host_message.h"
     21 #include "ppapi/host/ppapi_host.h"
     22 #include "ppapi/proxy/ppapi_messages.h"
     23 
     24 namespace content {
     25 
     26 PepperNetworkProxyHost::PepperNetworkProxyHost(BrowserPpapiHostImpl* host,
     27                                                PP_Instance instance,
     28                                                PP_Resource resource)
     29     : ResourceHost(host->GetPpapiHost(), instance, resource),
     30       proxy_service_(NULL),
     31       is_allowed_(false),
     32       waiting_for_ui_thread_data_(true),
     33       weak_factory_(this) {
     34   int render_process_id(0), render_frame_id(0);
     35   host->GetRenderFrameIDsForInstance(
     36       instance, &render_process_id, &render_frame_id);
     37   BrowserThread::PostTaskAndReplyWithResult(
     38       BrowserThread::UI,
     39       FROM_HERE,
     40       base::Bind(&GetUIThreadDataOnUIThread,
     41                  render_process_id,
     42                  render_frame_id,
     43                  host->external_plugin()),
     44       base::Bind(&PepperNetworkProxyHost::DidGetUIThreadData,
     45                  weak_factory_.GetWeakPtr()));
     46 }
     47 
     48 PepperNetworkProxyHost::~PepperNetworkProxyHost() {
     49   while (!pending_requests_.empty()) {
     50     // If the proxy_service_ is NULL, we shouldn't have any outstanding
     51     // requests.
     52     DCHECK(proxy_service_);
     53     net::ProxyService::PacRequest* request = pending_requests_.front();
     54     proxy_service_->CancelPacRequest(request);
     55     pending_requests_.pop();
     56   }
     57 }
     58 
     59 PepperNetworkProxyHost::UIThreadData::UIThreadData() : is_allowed(false) {}
     60 
     61 PepperNetworkProxyHost::UIThreadData::~UIThreadData() {}
     62 
     63 // static
     64 PepperNetworkProxyHost::UIThreadData
     65 PepperNetworkProxyHost::GetUIThreadDataOnUIThread(int render_process_id,
     66                                                   int render_frame_id,
     67                                                   bool is_external_plugin) {
     68   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     69   PepperNetworkProxyHost::UIThreadData result;
     70   RenderProcessHost* render_process_host =
     71       RenderProcessHost::FromID(render_process_id);
     72   if (render_process_host && render_process_host->GetBrowserContext()) {
     73     result.context_getter =
     74         render_process_host->GetBrowserContext()
     75             ->GetRequestContextForRenderProcess(render_process_id);
     76   }
     77 
     78   SocketPermissionRequest request(
     79       content::SocketPermissionRequest::RESOLVE_PROXY, std::string(), 0);
     80   result.is_allowed =
     81       pepper_socket_utils::CanUseSocketAPIs(is_external_plugin,
     82                                             false /* is_private_api */,
     83                                             &request,
     84                                             render_process_id,
     85                                             render_frame_id);
     86   return result;
     87 }
     88 
     89 void PepperNetworkProxyHost::DidGetUIThreadData(
     90     const UIThreadData& ui_thread_data) {
     91   is_allowed_ = ui_thread_data.is_allowed;
     92   if (ui_thread_data.context_getter.get() &&
     93       ui_thread_data.context_getter->GetURLRequestContext()) {
     94     proxy_service_ =
     95         ui_thread_data.context_getter->GetURLRequestContext()->proxy_service();
     96   }
     97   waiting_for_ui_thread_data_ = false;
     98   if (!proxy_service_) {
     99     DLOG_IF(WARNING, proxy_service_)
    100         << "Failed to find a ProxyService for Pepper plugin.";
    101   }
    102   TryToSendUnsentRequests();
    103 }
    104 
    105 int32_t PepperNetworkProxyHost::OnResourceMessageReceived(
    106     const IPC::Message& msg,
    107     ppapi::host::HostMessageContext* context) {
    108   PPAPI_BEGIN_MESSAGE_MAP(PepperNetworkProxyHost, msg)
    109     PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_NetworkProxy_GetProxyForURL,
    110                                       OnMsgGetProxyForURL)
    111   PPAPI_END_MESSAGE_MAP()
    112   return PP_ERROR_FAILED;
    113 }
    114 
    115 int32_t PepperNetworkProxyHost::OnMsgGetProxyForURL(
    116     ppapi::host::HostMessageContext* context,
    117     const std::string& url) {
    118   GURL gurl(url);
    119   if (gurl.is_valid()) {
    120     UnsentRequest request = {gurl, context->MakeReplyMessageContext()};
    121     unsent_requests_.push(request);
    122     TryToSendUnsentRequests();
    123   } else {
    124     SendFailureReply(PP_ERROR_BADARGUMENT, context->MakeReplyMessageContext());
    125   }
    126   return PP_OK_COMPLETIONPENDING;
    127 }
    128 
    129 void PepperNetworkProxyHost::TryToSendUnsentRequests() {
    130   if (waiting_for_ui_thread_data_)
    131     return;
    132 
    133   while (!unsent_requests_.empty()) {
    134     const UnsentRequest& request = unsent_requests_.front();
    135     if (!proxy_service_) {
    136       SendFailureReply(PP_ERROR_FAILED, request.reply_context);
    137     } else if (!is_allowed_) {
    138       SendFailureReply(PP_ERROR_NOACCESS, request.reply_context);
    139     } else {
    140       // Everything looks valid, so try to resolve the proxy.
    141       net::ProxyInfo* proxy_info = new net::ProxyInfo;
    142       net::ProxyService::PacRequest* pending_request = NULL;
    143       base::Callback<void(int)> callback =
    144           base::Bind(&PepperNetworkProxyHost::OnResolveProxyCompleted,
    145                      weak_factory_.GetWeakPtr(),
    146                      request.reply_context,
    147                      base::Owned(proxy_info));
    148       int result = proxy_service_->ResolveProxy(request.url,
    149                                                 net::LOAD_NORMAL,
    150                                                 proxy_info,
    151                                                 callback,
    152                                                 &pending_request,
    153                                                 NULL,
    154                                                 net::BoundNetLog());
    155       pending_requests_.push(pending_request);
    156       // If it was handled synchronously, we must run the callback now;
    157       // proxy_service_ won't run it for us in this case.
    158       if (result != net::ERR_IO_PENDING)
    159         callback.Run(result);
    160     }
    161     unsent_requests_.pop();
    162   }
    163 }
    164 
    165 void PepperNetworkProxyHost::OnResolveProxyCompleted(
    166     ppapi::host::ReplyMessageContext context,
    167     net::ProxyInfo* proxy_info,
    168     int result) {
    169   pending_requests_.pop();
    170 
    171   if (result != net::OK) {
    172     // Currently, the only proxy-specific error we could get is
    173     // MANDATORY_PROXY_CONFIGURATION_FAILED. There's really no action a plugin
    174     // can take in this case, so there's no need to distinguish it from other
    175     // failures.
    176     context.params.set_result(PP_ERROR_FAILED);
    177   }
    178   host()->SendReply(context,
    179                     PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(
    180                         proxy_info->ToPacString()));
    181 }
    182 
    183 void PepperNetworkProxyHost::SendFailureReply(
    184     int32_t error,
    185     ppapi::host::ReplyMessageContext context) {
    186   context.params.set_result(error);
    187   host()->SendReply(
    188       context, PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(std::string()));
    189 }
    190 
    191 }  // namespace content
    192