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