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_view_id(0);
     34   host->GetRenderViewIDsForInstance(instance,
     35                                     &render_process_id,
     36                                     &render_view_id);
     37   BrowserThread::PostTaskAndReplyWithResult(
     38       BrowserThread::UI, FROM_HERE,
     39       base::Bind(&GetUIThreadDataOnUIThread,
     40                  render_process_id,
     41                  render_view_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()
     59     : is_allowed(false) {
     60 }
     61 
     62 PepperNetworkProxyHost::UIThreadData::~UIThreadData() {
     63 }
     64 
     65 // static
     66 PepperNetworkProxyHost::UIThreadData
     67 PepperNetworkProxyHost::GetUIThreadDataOnUIThread(int render_process_id,
     68                                                   int render_view_id,
     69                                                   bool is_external_plugin) {
     70   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     71   PepperNetworkProxyHost::UIThreadData result;
     72   RenderProcessHost* render_process_host =
     73       RenderProcessHost::FromID(render_process_id);
     74   if (render_process_host && render_process_host->GetBrowserContext()) {
     75     result.context_getter = render_process_host->GetBrowserContext()->
     76         GetRequestContextForRenderProcess(render_process_id);
     77   }
     78 
     79   RenderViewHost* render_view_host =
     80       RenderViewHost::FromID(render_process_id, render_view_id);
     81   if (render_view_host) {
     82     SocketPermissionRequest request(
     83         content::SocketPermissionRequest::RESOLVE_PROXY, std::string(), 0);
     84     result.is_allowed = pepper_socket_utils::CanUseSocketAPIs(
     85         is_external_plugin,
     86         false /* is_private_api */,
     87         request,
     88         render_view_host);
     89   }
     90   return result;
     91 }
     92 
     93 void PepperNetworkProxyHost::DidGetUIThreadData(
     94     const UIThreadData& ui_thread_data) {
     95   is_allowed_ = ui_thread_data.is_allowed;
     96   if (ui_thread_data.context_getter.get() &&
     97       ui_thread_data.context_getter->GetURLRequestContext()) {
     98     proxy_service_ =
     99         ui_thread_data.context_getter->GetURLRequestContext()->proxy_service();
    100   }
    101   waiting_for_ui_thread_data_ = false;
    102   if (!proxy_service_) {
    103     DLOG_IF(WARNING, proxy_service_)
    104         << "Failed to find a ProxyService for Pepper plugin.";
    105   }
    106   TryToSendUnsentRequests();
    107 }
    108 
    109 int32_t PepperNetworkProxyHost::OnResourceMessageReceived(
    110     const IPC::Message& msg,
    111     ppapi::host::HostMessageContext* context) {
    112   IPC_BEGIN_MESSAGE_MAP(PepperNetworkProxyHost, msg)
    113     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
    114         PpapiHostMsg_NetworkProxy_GetProxyForURL, OnMsgGetProxyForURL)
    115   IPC_END_MESSAGE_MAP()
    116   return PP_ERROR_FAILED;
    117 }
    118 
    119 int32_t PepperNetworkProxyHost::OnMsgGetProxyForURL(
    120     ppapi::host::HostMessageContext* context,
    121     const std::string& url) {
    122   GURL gurl(url);
    123   if (gurl.is_valid()) {
    124     UnsentRequest request = { gurl, context->MakeReplyMessageContext() };
    125     unsent_requests_.push(request);
    126     TryToSendUnsentRequests();
    127   } else {
    128     SendFailureReply(PP_ERROR_BADARGUMENT,
    129                      context->MakeReplyMessageContext());
    130   }
    131   return PP_OK_COMPLETIONPENDING;
    132 }
    133 
    134 void PepperNetworkProxyHost::TryToSendUnsentRequests() {
    135   if (waiting_for_ui_thread_data_)
    136     return;
    137 
    138   while (!unsent_requests_.empty()) {
    139     const UnsentRequest& request = unsent_requests_.front();
    140     if (!proxy_service_) {
    141       SendFailureReply(PP_ERROR_FAILED, request.reply_context);
    142     } else if (!is_allowed_) {
    143       SendFailureReply(PP_ERROR_NOACCESS, request.reply_context);
    144     } else {
    145       // Everything looks valid, so try to resolve the proxy.
    146       net::ProxyInfo* proxy_info = new net::ProxyInfo;
    147       net::ProxyService::PacRequest* pending_request = NULL;
    148       base::Callback<void (int)> callback =
    149           base::Bind(&PepperNetworkProxyHost::OnResolveProxyCompleted,
    150                      weak_factory_.GetWeakPtr(),
    151                      request.reply_context,
    152                      base::Owned(proxy_info));
    153       int result = proxy_service_->ResolveProxy(request.url,
    154                                                 proxy_info,
    155                                                 callback,
    156                                                 &pending_request,
    157                                                 net::BoundNetLog());
    158       pending_requests_.push(pending_request);
    159       // If it was handled synchronously, we must run the callback now;
    160       // proxy_service_ won't run it for us in this case.
    161       if (result != net::ERR_IO_PENDING)
    162         callback.Run(result);
    163     }
    164     unsent_requests_.pop();
    165   }
    166 }
    167 
    168 void PepperNetworkProxyHost::OnResolveProxyCompleted(
    169     ppapi::host::ReplyMessageContext context,
    170     net::ProxyInfo* proxy_info,
    171     int result) {
    172   pending_requests_.pop();
    173 
    174   if (result != net::OK) {
    175     // Currently, the only proxy-specific error we could get is
    176     // MANDATORY_PROXY_CONFIGURATION_FAILED. There's really no action a plugin
    177     // can take in this case, so there's no need to distinguish it from other
    178     // failures.
    179     context.params.set_result(PP_ERROR_FAILED);
    180   }
    181   host()->SendReply(context,
    182                     PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(
    183                         proxy_info->ToPacString()));
    184 }
    185 
    186 void PepperNetworkProxyHost::SendFailureReply(
    187     int32_t error,
    188     ppapi::host::ReplyMessageContext context) {
    189   context.params.set_result(error);
    190   host()->SendReply(context,
    191                     PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(
    192                         std::string()));
    193 }
    194 
    195 }  // namespace content
    196