1 // Copyright (c) 2012 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/resolve_proxy_msg_helper.h"
6
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "content/common/view_messages.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/render_process_host.h"
12 #include "content/public/browser/storage_partition.h"
13 #include "net/base/network_isolation_key.h"
14 #include "net/proxy_resolution/proxy_info.h"
15 #include "services/network/public/mojom/network_context.mojom.h"
16
17 namespace content {
18
ResolveProxyMsgHelper(int render_process_host_id)19 ResolveProxyMsgHelper::ResolveProxyMsgHelper(int render_process_host_id)
20 : BrowserMessageFilter(ViewMsgStart),
21 render_process_host_id_(render_process_host_id) {}
22
OverrideThreadForMessage(const IPC::Message & message,BrowserThread::ID * thread)23 void ResolveProxyMsgHelper::OverrideThreadForMessage(
24 const IPC::Message& message,
25 BrowserThread::ID* thread) {
26 if (message.type() == ViewHostMsg_ResolveProxy::ID)
27 *thread = BrowserThread::UI;
28 }
29
OnMessageReceived(const IPC::Message & message)30 bool ResolveProxyMsgHelper::OnMessageReceived(const IPC::Message& message) {
31 bool handled = true;
32 IPC_BEGIN_MESSAGE_MAP(ResolveProxyMsgHelper, message)
33 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_ResolveProxy, OnResolveProxy)
34 IPC_MESSAGE_UNHANDLED(handled = false)
35 IPC_END_MESSAGE_MAP()
36 return handled;
37 }
38
OnResolveProxy(const GURL & url,IPC::Message * reply_msg)39 void ResolveProxyMsgHelper::OnResolveProxy(const GURL& url,
40 IPC::Message* reply_msg) {
41 DCHECK_CURRENTLY_ON(BrowserThread::UI);
42
43 // Enqueue the pending request.
44 pending_requests_.push_back(PendingRequest(url, reply_msg));
45
46 // If nothing is in progress, start.
47 if (!receiver_.is_bound()) {
48 DCHECK_EQ(1u, pending_requests_.size());
49 StartPendingRequest();
50 }
51 }
52
~ResolveProxyMsgHelper()53 ResolveProxyMsgHelper::~ResolveProxyMsgHelper() {
54 DCHECK(!owned_self_);
55 DCHECK(!receiver_.is_bound());
56 }
57
StartPendingRequest()58 void ResolveProxyMsgHelper::StartPendingRequest() {
59 DCHECK_CURRENTLY_ON(BrowserThread::UI);
60 DCHECK(!receiver_.is_bound());
61 DCHECK(!pending_requests_.empty());
62
63 // Start the request.
64 mojo::PendingRemote<network::mojom::ProxyLookupClient> proxy_lookup_client =
65 receiver_.BindNewPipeAndPassRemote();
66 receiver_.set_disconnect_handler(
67 base::BindOnce(&ResolveProxyMsgHelper::OnProxyLookupComplete,
68 base::Unretained(this), net::ERR_ABORTED, base::nullopt));
69 owned_self_ = this;
70 if (!SendRequestToNetworkService(pending_requests_.front().url,
71 std::move(proxy_lookup_client))) {
72 OnProxyLookupComplete(net::ERR_FAILED, base::nullopt);
73 }
74 }
75
SendRequestToNetworkService(const GURL & url,mojo::PendingRemote<network::mojom::ProxyLookupClient> proxy_lookup_client)76 bool ResolveProxyMsgHelper::SendRequestToNetworkService(
77 const GURL& url,
78 mojo::PendingRemote<network::mojom::ProxyLookupClient>
79 proxy_lookup_client) {
80 DCHECK_CURRENTLY_ON(BrowserThread::UI);
81
82 RenderProcessHost* render_process_host =
83 RenderProcessHost::FromID(render_process_host_id_);
84 // Fail the request if there's no such RenderProcessHost;
85 if (!render_process_host)
86 return false;
87 // TODO(https://crbug.com/1021661): Pass in a non-empty NetworkIsolationKey.
88 render_process_host->GetStoragePartition()
89 ->GetNetworkContext()
90 ->LookUpProxyForURL(url, net::NetworkIsolationKey::Todo(),
91 std::move(proxy_lookup_client));
92 return true;
93 }
94
OnProxyLookupComplete(int32_t net_error,const base::Optional<net::ProxyInfo> & proxy_info)95 void ResolveProxyMsgHelper::OnProxyLookupComplete(
96 int32_t net_error,
97 const base::Optional<net::ProxyInfo>& proxy_info) {
98 DCHECK_CURRENTLY_ON(BrowserThread::UI);
99 DCHECK(!pending_requests_.empty());
100
101 receiver_.reset();
102
103 // Need to keep |this| alive until the end of this method, and then release
104 // this reference. StartPendingRequest(), if called, will grab other
105 // reference, and a reference may be owned by the IO thread or by other
106 // posted tasks, so |this| may or may not be deleted at the end of this
107 // method.
108 scoped_refptr<ResolveProxyMsgHelper> owned_self = std::move(owned_self_);
109
110 // If all references except |owned_self| have been released, then there's
111 // nothing waiting for pending requests to complete. So just exit this method,
112 // which will release the last reference, destroying |this|.
113 if (HasOneRef())
114 return;
115
116 // Clear the current (completed) request.
117 PendingRequest completed_req = std::move(pending_requests_.front());
118 pending_requests_.pop_front();
119
120 ViewHostMsg_ResolveProxy::WriteReplyParams(
121 completed_req.reply_msg.get(), !!proxy_info,
122 proxy_info ? proxy_info->ToPacString() : std::string());
123 Send(completed_req.reply_msg.release());
124
125 // Start the next request.
126 if (!pending_requests_.empty())
127 StartPendingRequest();
128 }
129
PendingRequest(const GURL & url,IPC::Message * reply_msg)130 ResolveProxyMsgHelper::PendingRequest::PendingRequest(const GURL& url,
131 IPC::Message* reply_msg)
132 : url(url), reply_msg(reply_msg) {}
133
134 ResolveProxyMsgHelper::PendingRequest::PendingRequest(
135 PendingRequest&& pending_request) noexcept = default;
136
137 ResolveProxyMsgHelper::PendingRequest::~PendingRequest() noexcept = default;
138
139 ResolveProxyMsgHelper::PendingRequest& ResolveProxyMsgHelper::PendingRequest::
140 operator=(PendingRequest&& pending_request) noexcept = default;
141
142 } // namespace content
143