blob: 6042badfc92dfaf56b384313565caf6477ab0772 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/pepper/pepper_network_proxy_host.h"
#include "base/bind.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/socket_permission_request.h"
#include "net/base/net_errors.h"
#include "net/proxy/proxy_info.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/ppapi_host.h"
#include "ppapi/proxy/ppapi_messages.h"
namespace content {
PepperNetworkProxyHost::PepperNetworkProxyHost(BrowserPpapiHostImpl* host,
PP_Instance instance,
PP_Resource resource)
: ResourceHost(host->GetPpapiHost(), instance, resource),
proxy_service_(NULL),
is_allowed_(false),
waiting_for_ui_thread_data_(true),
weak_factory_(this) {
int render_process_id(0), render_view_id(0);
host->GetRenderViewIDsForInstance(instance,
&render_process_id,
&render_view_id);
BrowserThread::PostTaskAndReplyWithResult(
BrowserThread::UI, FROM_HERE,
base::Bind(&GetUIThreadDataOnUIThread,
render_process_id,
render_view_id,
host->external_plugin()),
base::Bind(&PepperNetworkProxyHost::DidGetUIThreadData,
weak_factory_.GetWeakPtr()));
}
PepperNetworkProxyHost::~PepperNetworkProxyHost() {
while (!pending_requests_.empty()) {
// If the proxy_service_ is NULL, we shouldn't have any outstanding
// requests.
DCHECK(proxy_service_);
net::ProxyService::PacRequest* request = pending_requests_.front();
proxy_service_->CancelPacRequest(request);
pending_requests_.pop();
}
}
PepperNetworkProxyHost::UIThreadData::UIThreadData()
: is_allowed(false) {
}
PepperNetworkProxyHost::UIThreadData::~UIThreadData() {
}
// static
PepperNetworkProxyHost::UIThreadData
PepperNetworkProxyHost::GetUIThreadDataOnUIThread(int render_process_id,
int render_view_id,
bool is_external_plugin) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
PepperNetworkProxyHost::UIThreadData result;
RenderProcessHost* render_process_host =
RenderProcessHost::FromID(render_process_id);
if (render_process_host && render_process_host->GetBrowserContext()) {
result.context_getter = render_process_host->GetBrowserContext()->
GetRequestContextForRenderProcess(render_process_id);
}
RenderViewHost* render_view_host =
RenderViewHost::FromID(render_process_id, render_view_id);
if (render_view_host) {
SocketPermissionRequest request(
content::SocketPermissionRequest::RESOLVE_PROXY, std::string(), 0);
result.is_allowed = pepper_socket_utils::CanUseSocketAPIs(
is_external_plugin,
false /* is_private_api */,
request,
render_view_host);
}
return result;
}
void PepperNetworkProxyHost::DidGetUIThreadData(
const UIThreadData& ui_thread_data) {
is_allowed_ = ui_thread_data.is_allowed;
if (ui_thread_data.context_getter.get() &&
ui_thread_data.context_getter->GetURLRequestContext()) {
proxy_service_ =
ui_thread_data.context_getter->GetURLRequestContext()->proxy_service();
}
waiting_for_ui_thread_data_ = false;
if (!proxy_service_) {
DLOG_IF(WARNING, proxy_service_)
<< "Failed to find a ProxyService for Pepper plugin.";
}
TryToSendUnsentRequests();
}
int32_t PepperNetworkProxyHost::OnResourceMessageReceived(
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) {
IPC_BEGIN_MESSAGE_MAP(PepperNetworkProxyHost, msg)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(
PpapiHostMsg_NetworkProxy_GetProxyForURL, OnMsgGetProxyForURL)
IPC_END_MESSAGE_MAP()
return PP_ERROR_FAILED;
}
int32_t PepperNetworkProxyHost::OnMsgGetProxyForURL(
ppapi::host::HostMessageContext* context,
const std::string& url) {
GURL gurl(url);
if (gurl.is_valid()) {
UnsentRequest request = { gurl, context->MakeReplyMessageContext() };
unsent_requests_.push(request);
TryToSendUnsentRequests();
} else {
SendFailureReply(PP_ERROR_BADARGUMENT,
context->MakeReplyMessageContext());
}
return PP_OK_COMPLETIONPENDING;
}
void PepperNetworkProxyHost::TryToSendUnsentRequests() {
if (waiting_for_ui_thread_data_)
return;
while (!unsent_requests_.empty()) {
const UnsentRequest& request = unsent_requests_.front();
if (!proxy_service_) {
SendFailureReply(PP_ERROR_FAILED, request.reply_context);
} else if (!is_allowed_) {
SendFailureReply(PP_ERROR_NOACCESS, request.reply_context);
} else {
// Everything looks valid, so try to resolve the proxy.
net::ProxyInfo* proxy_info = new net::ProxyInfo;
net::ProxyService::PacRequest* pending_request = NULL;
base::Callback<void (int)> callback =
base::Bind(&PepperNetworkProxyHost::OnResolveProxyCompleted,
weak_factory_.GetWeakPtr(),
request.reply_context,
base::Owned(proxy_info));
int result = proxy_service_->ResolveProxy(request.url,
proxy_info,
callback,
&pending_request,
net::BoundNetLog());
pending_requests_.push(pending_request);
// If it was handled synchronously, we must run the callback now;
// proxy_service_ won't run it for us in this case.
if (result != net::ERR_IO_PENDING)
callback.Run(result);
}
unsent_requests_.pop();
}
}
void PepperNetworkProxyHost::OnResolveProxyCompleted(
ppapi::host::ReplyMessageContext context,
net::ProxyInfo* proxy_info,
int result) {
pending_requests_.pop();
if (result != net::OK) {
// Currently, the only proxy-specific error we could get is
// MANDATORY_PROXY_CONFIGURATION_FAILED. There's really no action a plugin
// can take in this case, so there's no need to distinguish it from other
// failures.
context.params.set_result(PP_ERROR_FAILED);
}
host()->SendReply(context,
PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(
proxy_info->ToPacString()));
}
void PepperNetworkProxyHost::SendFailureReply(
int32_t error,
ppapi::host::ReplyMessageContext context) {
context.params.set_result(error);
host()->SendReply(context,
PpapiPluginMsg_NetworkProxy_GetProxyForURLReply(
std::string()));
}
} // namespace content