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