- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / pepper / pepper_network_proxy_host.cc
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