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