blob: 8b9bef71eaddf41e455827502fb3b6291f401a86 [file] [log] [blame]
John Abd-El-Maleka4bb87f2017-11-27 21:32:191// Copyright 2017 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/public/test/url_loader_interceptor.h"
6
Lukasz Anforowicz98ccf1c2018-08-23 18:14:317#include <string>
8#include <utility>
9
Sebastien Marchandf8cbfab2019-01-25 16:02:3010#include "base/bind.h"
David Benjamine430b8a2019-03-21 20:46:2711#include "base/containers/unique_ptr_adapters.h"
John Abd-El-Malek30a86892018-05-26 00:14:1612#include "base/files/file_path.h"
13#include "base/files/file_util.h"
14#include "base/path_service.h"
Dan Harrington942019f2019-01-04 17:58:0315#include "base/synchronization/lock.h"
Eric Seckler8652dcd52018-09-20 10:42:2816#include "base/task/post_task.h"
John Abd-El-Malek63ff5f32017-12-18 22:14:5817#include "base/test/bind_test_util.h"
John Abd-El-Malek30a86892018-05-26 00:14:1618#include "base/threading/thread_restrictions.h"
John Abd-El-Malek1d1ff9182018-08-10 16:18:2319#include "build/build_config.h"
John Abd-El-Maleka4bb87f2017-11-27 21:32:1920#include "content/browser/frame_host/render_frame_host_impl.h"
arthursonzogni1fd60e62018-05-09 15:57:3221#include "content/browser/loader/navigation_url_loader_impl.h"
John Abd-El-Maleka4bb87f2017-11-27 21:32:1922#include "content/browser/loader/resource_message_filter.h"
23#include "content/browser/loader/url_loader_factory_impl.h"
Tsuyoshi Horo0fd453152018-10-16 01:45:2024#include "content/browser/service_worker/embedded_worker_instance.h"
John Abd-El-Malekd5f920342018-02-12 17:37:3625#include "content/browser/storage_partition_impl.h"
John Abd-El-Maleka4bb87f2017-11-27 21:32:1926#include "content/browser/url_loader_factory_getter.h"
Eric Seckler8652dcd52018-09-20 10:42:2827#include "content/public/browser/browser_task_traits.h"
John Abd-El-Maleka4bb87f2017-11-27 21:32:1928#include "content/public/browser/browser_thread.h"
Ken Rockot0cf16c32018-03-01 16:50:4929#include "mojo/public/cpp/bindings/binding_set.h"
John Abd-El-Maleka796fa52017-12-12 17:12:3230#include "net/http/http_util.h"
John Abd-El-Malek30a86892018-05-26 00:14:1631#include "net/test/embedded_test_server/request_handler_util.h"
Yutaka Hiranod8789f92018-01-30 09:59:5132#include "services/network/public/cpp/features.h"
Ken Rockot54311e62018-02-10 19:01:5233#include "services/network/public/mojom/url_loader.mojom.h"
John Abd-El-Maleka4bb87f2017-11-27 21:32:1934
35namespace content {
36
John Abd-El-Malek30a86892018-05-26 00:14:1637namespace {
38
39base::FilePath GetDataFilePath(const std::string& relative_path) {
40 base::FilePath root_path;
41 CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &root_path));
42 return root_path.AppendASCII(relative_path);
43}
44
John Abd-El-Malek1d1ff9182018-08-10 16:18:2345static std::string ReadFile(const base::FilePath& path) {
John Abd-El-Malek30a86892018-05-26 00:14:1646 std::string contents;
John Abd-El-Malek1d1ff9182018-08-10 16:18:2347 CHECK(base::ReadFileToString(path, &contents));
John Abd-El-Malek30a86892018-05-26 00:14:1648 return contents;
49}
50
51} // namespace
52
Dan Harrington942019f2019-01-04 17:58:0353// Part of URLLoaderInterceptor which lives on the IO thread. Outlives
54// URLLoaderInterceptor.
55class URLLoaderInterceptor::IOState
Lukasz Anforowicz2f985a42019-07-19 02:56:5256 : public base::RefCountedThreadSafe<URLLoaderInterceptor::IOState,
57 BrowserThread::DeleteOnIOThread> {
Dan Harrington942019f2019-01-04 17:58:0358 public:
59 explicit IOState(URLLoaderInterceptor* parent) : parent_(parent) {}
Yao Xiao43ae3bc2019-07-09 05:22:2360 void Initialize(
61 const URLLoaderCompletionStatusCallback& completion_status_callback,
62 base::OnceClosure closure);
63
Dan Harrington942019f2019-01-04 17:58:0364 // Called when a SubresourceWrapper's binding has an error.
65 void SubresourceWrapperBindingError(SubresourceWrapper* wrapper);
66
67 // Unsets the parent pointer. Prevents URLLoaderInterceptor::Intercept from
68 // being called.
69 void UnsetParent() {
70 base::AutoLock lock(intercept_lock_);
71 parent_ = nullptr;
72 }
73
74 void Shutdown(base::OnceClosure closure) {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
76 url_loader_factory_getter_wrappers_.clear();
77 subresource_wrappers_.clear();
Clark DuVall649c05f2019-02-05 23:58:4778 navigation_wrappers_.clear();
Dan Harrington942019f2019-01-04 17:58:0379
John Abd-El-Malek87301582019-07-27 04:50:5280 URLLoaderFactoryGetter::SetGetNetworkFactoryCallbackForTesting(
81 URLLoaderFactoryGetter::GetNetworkFactoryCallback());
82 if (!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
83 NavigationURLLoaderImpl::SetURLLoaderFactoryInterceptorForTesting(
84 NavigationURLLoaderImpl::URLLoaderFactoryInterceptor());
Dan Harrington942019f2019-01-04 17:58:0385 }
86
87 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
88 ResourceMessageFilter::SetNetworkFactoryForTesting(nullptr);
89 }
90
91 if (closure)
92 std::move(closure).Run();
93 }
94
95 // Callback on IO thread whenever a
96 // URLLoaderFactoryGetter::GetNetworkContext is called on an object that
97 // doesn't have a test factory set up.
98 void GetNetworkFactoryCallback(
99 URLLoaderFactoryGetter* url_loader_factory_getter);
100
101 void CreateURLLoaderFactoryForSubresources(
102 network::mojom::URLLoaderFactoryRequest request,
103 int process_id,
104 network::mojom::URLLoaderFactoryPtrInfo original_factory);
105
106 bool Intercept(RequestParams* params) {
107 // The lock ensures that |URLLoaderInterceptor| can't be deleted while it
108 // is processing an intercept. Before |URLLoaderInterceptor| is deleted,
109 // parent_ is set to null so that requests can't be intercepted after
110 // |URLLoaderInterceptor| is deleted.
111 base::AutoLock lock(intercept_lock_);
112 if (!parent_)
113 return false;
114 return parent_->Intercept(params);
115 }
116
117 bool BeginNavigationCallback(
118 network::mojom::URLLoaderRequest* request,
119 int32_t routing_id,
120 int32_t request_id,
121 uint32_t options,
122 const network::ResourceRequest& url_request,
123 network::mojom::URLLoaderClientPtr* client,
124 const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
125 RequestParams params;
126 params.process_id = 0;
127 params.request = std::move(*request);
128 params.routing_id = routing_id;
129 params.request_id = request_id;
130 params.options = options;
131 params.url_request = url_request;
132 params.client = std::move(*client);
133 params.traffic_annotation = traffic_annotation;
134
135 if (Intercept(&params))
136 return true;
137
138 *request = std::move(params.request);
139 *client = std::move(params.client);
140 return false;
141 }
142
Clark DuVall649c05f2019-02-05 23:58:47143 // Callback on IO thread whenever NavigationURLLoaderImpl needs a
John Abd-El-Malek08e99952019-04-12 22:46:22144 // URLLoaderFactory with a network::mojom::TrustedURLLoaderHeaderClient or
145 // for a non-network-service scheme.
Clark DuVall649c05f2019-02-05 23:58:47146 void InterceptNavigationRequestCallback(
147 network::mojom::URLLoaderFactoryRequest* request) {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
149
150 auto proxied_request = std::move(*request);
151 network::mojom::URLLoaderFactoryPtr target_factory;
152 *request = mojo::MakeRequest(&target_factory);
153
154 navigation_wrappers_.emplace(
155 std::make_unique<URLLoaderFactoryNavigationWrapper>(
156 std::move(proxied_request), std::move(target_factory), this));
157 }
158
Yao Xiao43ae3bc2019-07-09 05:22:23159 URLLoaderCompletionStatusCallback GetCompletionStatusCallback() {
160 return completion_status_callback_;
161 }
162
Dan Harrington942019f2019-01-04 17:58:03163 private:
Lukasz Anforowicz2f985a42019-07-19 02:56:52164 friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
165 friend class base::DeleteHelper<IOState>;
166
Dan Harrington942019f2019-01-04 17:58:03167 ~IOState() {}
168
169 // This lock guarantees that when URLLoaderInterceptor is destroyed,
170 // no intercept callbacks will be called.
171 base::Lock intercept_lock_;
172 URLLoaderInterceptor* parent_ GUARDED_BY(intercept_lock_);
173
Yao Xiao43ae3bc2019-07-09 05:22:23174 URLLoaderCompletionStatusCallback completion_status_callback_;
175
Dan Harrington942019f2019-01-04 17:58:03176 // For intercepting frame requests with network service. There is one per
177 // StoragePartition. Only accessed on IO thread.
178 std::set<std::unique_ptr<URLLoaderFactoryGetterWrapper>>
179 url_loader_factory_getter_wrappers_;
180 // For intercepting subresources without network service in
181 // ResourceMessageFilter.
182 std::unique_ptr<Interceptor> rmf_interceptor_;
183 // For intercepting subresources with network service. There is one per
184 // active render frame commit. Only accessed on IO thread.
David Benjamine430b8a2019-03-21 20:46:27185 std::set<std::unique_ptr<SubresourceWrapper>, base::UniquePtrComparator>
186 subresource_wrappers_;
Clark DuVall649c05f2019-02-05 23:58:47187 std::set<std::unique_ptr<URLLoaderFactoryNavigationWrapper>>
188 navigation_wrappers_;
Dan Harrington942019f2019-01-04 17:58:03189
190 DISALLOW_COPY_AND_ASSIGN(IOState);
191};
192
Yao Xiao43ae3bc2019-07-09 05:22:23193class URLLoaderClientInterceptor : public network::mojom::URLLoaderClient {
194 public:
195 explicit URLLoaderClientInterceptor(
196 const base::Callback<network::mojom::URLLoaderFactory*()>& factory_getter,
197 URLLoaderInterceptor::RequestParams params,
198 const URLLoaderInterceptor::URLLoaderCompletionStatusCallback&
199 completion_status_callback)
200 : original_client_(std::move(params.client)),
201 delegating_client_binding_(this),
202 completion_status_callback_(std::move(completion_status_callback)),
203 request_url_(params.url_request.url) {
204 network::mojom::URLLoaderClientPtr delegating_client;
205 delegating_client_binding_.Bind(mojo::MakeRequest(&delegating_client));
206 factory_getter.Run()->CreateLoaderAndStart(
207 std::move(params.request), params.routing_id, params.request_id,
208 params.options, std::move(params.url_request),
209 std::move(delegating_client), params.traffic_annotation);
210 }
211
212 void OnReceiveResponse(const network::ResourceResponseHead& head) override {
213 original_client_->OnReceiveResponse(head);
214 }
215
216 void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
217 const network::ResourceResponseHead& head) override {
218 original_client_->OnReceiveRedirect(redirect_info, head);
219 }
220
221 void OnUploadProgress(int64_t current_position,
222 int64_t total_size,
223 base::OnceCallback<void()> callback) override {
224 original_client_->OnUploadProgress(current_position, total_size,
225 std::move(callback));
226 }
227
228 void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override {
229 original_client_->OnReceiveCachedMetadata(std::move(data));
230 }
231
232 void OnTransferSizeUpdated(int32_t transfer_size_diff) override {
233 original_client_->OnTransferSizeUpdated(transfer_size_diff);
234 }
235
236 void OnStartLoadingResponseBody(
237 mojo::ScopedDataPipeConsumerHandle body) override {
238 original_client_->OnStartLoadingResponseBody(std::move(body));
239 }
240
241 void OnComplete(const network::URLLoaderCompletionStatus& status) override {
242 if (!completion_status_callback_.is_null())
243 completion_status_callback_.Run(request_url_, status);
244 original_client_->OnComplete(status);
245 }
246
247 private:
248 network::mojom::URLLoaderClientPtr original_client_;
249 mojo::Binding<network::mojom::URLLoaderClient> delegating_client_binding_;
250 URLLoaderInterceptor::URLLoaderCompletionStatusCallback
251 completion_status_callback_;
252 GURL request_url_;
253};
254
John Abd-El-Malekb165dc52018-01-18 17:12:18255class URLLoaderInterceptor::Interceptor
256 : public network::mojom::URLLoaderFactory {
John Abd-El-Maleka4bb87f2017-11-27 21:32:19257 public:
258 using ProcessIdGetter = base::Callback<int()>;
John Abd-El-Malekb165dc52018-01-18 17:12:18259 using OriginalFactoryGetter =
260 base::Callback<network::mojom::URLLoaderFactory*()>;
John Abd-El-Maleka4bb87f2017-11-27 21:32:19261
Dan Harrington942019f2019-01-04 17:58:03262 Interceptor(URLLoaderInterceptor::IOState* parent,
John Abd-El-Maleka4bb87f2017-11-27 21:32:19263 const ProcessIdGetter& process_id_getter,
264 const OriginalFactoryGetter& original_factory_getter)
265 : parent_(parent),
266 process_id_getter_(process_id_getter),
Ken Rockot0cf16c32018-03-01 16:50:49267 original_factory_getter_(original_factory_getter) {
268 bindings_.set_connection_error_handler(base::BindRepeating(
269 &Interceptor::OnConnectionError, base::Unretained(this)));
270 }
John Abd-El-Maleka4bb87f2017-11-27 21:32:19271
272 ~Interceptor() override {}
273
Ken Rockot0cf16c32018-03-01 16:50:49274 void BindRequest(network::mojom::URLLoaderFactoryRequest request) {
275 bindings_.AddBinding(this, std::move(request));
276 }
277
278 void SetConnectionErrorHandler(base::OnceClosure handler) {
279 error_handler_ = std::move(handler);
280 }
281
John Abd-El-Maleka4bb87f2017-11-27 21:32:19282 private:
John Abd-El-Malekb165dc52018-01-18 17:12:18283 // network::mojom::URLLoaderFactory implementation:
284 void CreateLoaderAndStart(network::mojom::URLLoaderRequest request,
John Abd-El-Maleka4bb87f2017-11-27 21:32:19285 int32_t routing_id,
286 int32_t request_id,
287 uint32_t options,
John Abd-El-Malek1df61792018-01-12 20:40:45288 const network::ResourceRequest& url_request,
John Abd-El-Malekb165dc52018-01-18 17:12:18289 network::mojom::URLLoaderClientPtr client,
John Abd-El-Maleka4bb87f2017-11-27 21:32:19290 const net::MutableNetworkTrafficAnnotationTag&
291 traffic_annotation) override {
292 RequestParams params;
293 params.process_id = process_id_getter_.Run();
294 params.request = std::move(request);
295 params.routing_id = routing_id;
296 params.request_id = request_id;
297 params.options = options;
298 params.url_request = std::move(url_request);
299 params.client = std::move(client);
300 params.traffic_annotation = traffic_annotation;
arthursonzognib8a02552018-04-24 23:03:42301
John Abd-El-Malekdb3a13b2018-05-01 17:52:02302 if (parent_->Intercept(&params))
John Abd-El-Maleka4bb87f2017-11-27 21:32:19303 return;
304
Yao Xiao43ae3bc2019-07-09 05:22:23305 url_loader_client_interceptors_.push_back(
306 std::make_unique<URLLoaderClientInterceptor>(
307 std::move(original_factory_getter_), std::move(params),
308 parent_->GetCompletionStatusCallback()));
John Abd-El-Maleka4bb87f2017-11-27 21:32:19309 }
310
John Abd-El-Malekb165dc52018-01-18 17:12:18311 void Clone(network::mojom::URLLoaderFactoryRequest request) override {
Ken Rockot0cf16c32018-03-01 16:50:49312 BindRequest(std::move(request));
313 }
314
315 void OnConnectionError() {
316 if (bindings_.empty() && error_handler_)
317 std::move(error_handler_).Run();
John Abd-El-Malekb165dc52018-01-18 17:12:18318 }
John Abd-El-Maleka4bb87f2017-11-27 21:32:19319
Dan Harrington942019f2019-01-04 17:58:03320 URLLoaderInterceptor::IOState* parent_;
John Abd-El-Maleka4bb87f2017-11-27 21:32:19321 ProcessIdGetter process_id_getter_;
322 OriginalFactoryGetter original_factory_getter_;
Ken Rockot0cf16c32018-03-01 16:50:49323 mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
324 base::OnceClosure error_handler_;
Yao Xiao43ae3bc2019-07-09 05:22:23325 std::vector<std::unique_ptr<URLLoaderClientInterceptor>>
326 url_loader_client_interceptors_;
John Abd-El-Maleka4bb87f2017-11-27 21:32:19327
328 DISALLOW_COPY_AND_ASSIGN(Interceptor);
329};
330
John Abd-El-Malek63ff5f32017-12-18 22:14:58331// This class intercepts calls to each StoragePartition's URLLoaderFactoryGetter
332// so that it can intercept frame requests.
333class URLLoaderInterceptor::URLLoaderFactoryGetterWrapper {
John Abd-El-Maleka4bb87f2017-11-27 21:32:19334 public:
John Abd-El-Malek63ff5f32017-12-18 22:14:58335 URLLoaderFactoryGetterWrapper(
336 URLLoaderFactoryGetter* url_loader_factory_getter,
Dan Harrington942019f2019-01-04 17:58:03337 URLLoaderInterceptor::IOState* parent)
John Abd-El-Malek63ff5f32017-12-18 22:14:58338 : url_loader_factory_getter_(url_loader_factory_getter) {
Dan Harrington942019f2019-01-04 17:58:03339 DCHECK_CURRENTLY_ON(BrowserThread::IO);
John Abd-El-Malek63ff5f32017-12-18 22:14:58340 frame_interceptor_ = std::make_unique<Interceptor>(
341 parent, base::BindRepeating([]() { return 0; }),
John Abd-El-Malekb165dc52018-01-18 17:12:18342 base::BindLambdaForTesting([=]() -> network::mojom::URLLoaderFactory* {
John Abd-El-Malek63ff5f32017-12-18 22:14:58343 return url_loader_factory_getter
344 ->original_network_factory_for_testing()
345 ->get();
346 }));
347 url_loader_factory_getter_->SetNetworkFactoryForTesting(
Lukasz Anforowicz288027b2019-01-17 01:51:27348 frame_interceptor_.get());
John Abd-El-Malek63ff5f32017-12-18 22:14:58349 }
350
351 ~URLLoaderFactoryGetterWrapper() {
Dan Harrington942019f2019-01-04 17:58:03352 DCHECK_CURRENTLY_ON(BrowserThread::IO);
Lukasz Anforowicz288027b2019-01-17 01:51:27353 url_loader_factory_getter_->SetNetworkFactoryForTesting(nullptr);
John Abd-El-Malek63ff5f32017-12-18 22:14:58354 }
355
356 private:
357 std::unique_ptr<Interceptor> frame_interceptor_;
John Abd-El-Malek63ff5f32017-12-18 22:14:58358 URLLoaderFactoryGetter* url_loader_factory_getter_;
359};
360
Clark DuValla5e25b752018-11-27 22:08:16361class URLLoaderInterceptor::URLLoaderFactoryNavigationWrapper {
362 public:
363 URLLoaderFactoryNavigationWrapper(
364 network::mojom::URLLoaderFactoryRequest request,
365 network::mojom::URLLoaderFactoryPtr target_factory,
Dan Harrington942019f2019-01-04 17:58:03366 URLLoaderInterceptor::IOState* parent)
Clark DuValla5e25b752018-11-27 22:08:16367 : target_factory_(std::move(target_factory)) {
368 interceptor_ = std::make_unique<Interceptor>(
369 parent, base::BindRepeating([]() { return 0; }),
370 base::BindLambdaForTesting([=]() -> network::mojom::URLLoaderFactory* {
371 return this->target_factory_.get();
372 }));
373 interceptor_->BindRequest(std::move(request));
374 }
375
376 private:
377 std::unique_ptr<Interceptor> interceptor_;
378 network::mojom::URLLoaderFactoryPtr target_factory_;
379};
380
John Abd-El-Malekd5f920342018-02-12 17:37:36381// This class intercepts calls to
382// StoragePartition::GetURLLoaderFactoryForBrowserProcess.
383class URLLoaderInterceptor::BrowserProcessWrapper {
384 public:
385 BrowserProcessWrapper(network::mojom::URLLoaderFactoryRequest factory_request,
Dan Harrington942019f2019-01-04 17:58:03386 URLLoaderInterceptor::IOState* parent,
John Abd-El-Malekd5f920342018-02-12 17:37:36387 network::mojom::URLLoaderFactoryPtr original_factory)
388 : interceptor_(
389 parent,
390 base::BindRepeating([]() { return 0; }),
391 base::BindRepeating(&BrowserProcessWrapper::GetOriginalFactory,
392 base::Unretained(this))),
Ken Rockot0cf16c32018-03-01 16:50:49393 original_factory_(std::move(original_factory)) {
394 interceptor_.BindRequest(std::move(factory_request));
395 }
John Abd-El-Malekd5f920342018-02-12 17:37:36396
397 ~BrowserProcessWrapper() {}
398
399 private:
400 network::mojom::URLLoaderFactory* GetOriginalFactory() {
401 return original_factory_.get();
402 }
403
404 Interceptor interceptor_;
John Abd-El-Malekd5f920342018-02-12 17:37:36405 network::mojom::URLLoaderFactoryPtr original_factory_;
406
407 DISALLOW_COPY_AND_ASSIGN(BrowserProcessWrapper);
408};
409
John Abd-El-Malek63ff5f32017-12-18 22:14:58410// This class is sent along a RenderFrame commit message as a subresource
411// loader so that it can intercept subresource requests.
412class URLLoaderInterceptor::SubresourceWrapper {
413 public:
John Abd-El-Malekb165dc52018-01-18 17:12:18414 SubresourceWrapper(network::mojom::URLLoaderFactoryRequest factory_request,
John Abd-El-Malek63ff5f32017-12-18 22:14:58415 int process_id,
Dan Harrington942019f2019-01-04 17:58:03416 URLLoaderInterceptor::IOState* parent,
John Abd-El-Malekb165dc52018-01-18 17:12:18417 network::mojom::URLLoaderFactoryPtrInfo original_factory)
John Abd-El-Maleka4bb87f2017-11-27 21:32:19418 : interceptor_(
419 parent,
John Abd-El-Malek63ff5f32017-12-18 22:14:58420 base::BindRepeating([](int process_id) { return process_id; },
421 process_id),
422 base::BindRepeating(&SubresourceWrapper::GetOriginalFactory,
423 base::Unretained(this))),
John Abd-El-Malek63ff5f32017-12-18 22:14:58424 original_factory_(std::move(original_factory)) {
Ken Rockot0cf16c32018-03-01 16:50:49425 interceptor_.BindRequest(std::move(factory_request));
Dan Harrington942019f2019-01-04 17:58:03426 interceptor_.SetConnectionErrorHandler(base::BindOnce(
427 &URLLoaderInterceptor::IOState::SubresourceWrapperBindingError,
428 base::Unretained(parent), this));
John Abd-El-Malek63ff5f32017-12-18 22:14:58429 }
John Abd-El-Maleka4bb87f2017-11-27 21:32:19430
John Abd-El-Malek63ff5f32017-12-18 22:14:58431 ~SubresourceWrapper() {}
John Abd-El-Maleka4bb87f2017-11-27 21:32:19432
433 private:
John Abd-El-Malekb165dc52018-01-18 17:12:18434 network::mojom::URLLoaderFactory* GetOriginalFactory() {
John Abd-El-Maleka4bb87f2017-11-27 21:32:19435 return original_factory_.get();
436 }
437
438 Interceptor interceptor_;
John Abd-El-Malekb165dc52018-01-18 17:12:18439 network::mojom::URLLoaderFactoryPtr original_factory_;
John Abd-El-Maleka4bb87f2017-11-27 21:32:19440
John Abd-El-Malek63ff5f32017-12-18 22:14:58441 DISALLOW_COPY_AND_ASSIGN(SubresourceWrapper);
John Abd-El-Maleka4bb87f2017-11-27 21:32:19442};
443
444URLLoaderInterceptor::RequestParams::RequestParams() = default;
445URLLoaderInterceptor::RequestParams::~RequestParams() = default;
John Abd-El-Malekdf84c4492018-02-23 02:32:44446URLLoaderInterceptor::RequestParams::RequestParams(RequestParams&& other) =
447 default;
448URLLoaderInterceptor::RequestParams& URLLoaderInterceptor::RequestParams::
449operator=(RequestParams&& other) = default;
John Abd-El-Maleka4bb87f2017-11-27 21:32:19450
Dan Harringtona11fc962019-01-07 22:15:17451URLLoaderInterceptor::URLLoaderInterceptor(const InterceptCallback& callback)
Yao Xiao43ae3bc2019-07-09 05:22:23452 : URLLoaderInterceptor(callback, {}, {}) {}
Dan Harringtona11fc962019-01-07 22:15:17453
Yao Xiao43ae3bc2019-07-09 05:22:23454URLLoaderInterceptor::URLLoaderInterceptor(
455 const InterceptCallback& callback,
456 const URLLoaderCompletionStatusCallback& completion_status_callback,
457 base::OnceClosure ready_callback)
Dan Harrington942019f2019-01-04 17:58:03458 : callback_(callback), io_thread_(base::MakeRefCounted<IOState>(this)) {
John Abd-El-Malek63ff5f32017-12-18 22:14:58459 DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::UI) ||
460 BrowserThread::CurrentlyOn(BrowserThread::UI));
Dan Harrington942019f2019-01-04 17:58:03461 use_runloop_ = !ready_callback;
Matt Falkenhagen4332b162019-03-04 08:58:52462 RenderFrameHostImpl::SetNetworkFactoryForTesting(base::BindRepeating(
463 &URLLoaderInterceptor::CreateURLLoaderFactoryForSubresources,
464 base::Unretained(this)));
465 SharedWorkerHost::SetNetworkFactoryForTesting(base::BindRepeating(
466 &URLLoaderInterceptor::CreateURLLoaderFactoryForSubresources,
467 base::Unretained(this)));
468 // Note: This URLLoaderFactory creation callback will be used not only for
469 // subresource loading from service workers (i.e., fetch()), but also for
470 // loading non-installed service worker scripts.
471 EmbeddedWorkerInstance::SetNetworkFactoryForTesting(base::BindRepeating(
472 &URLLoaderInterceptor::CreateURLLoaderFactoryForSubresources,
473 base::Unretained(this)));
John Abd-El-Maleka4bb87f2017-11-27 21:32:19474
John Abd-El-Malekd5f920342018-02-12 17:37:36475 StoragePartitionImpl::
476 SetGetURLLoaderFactoryForBrowserProcessCallbackForTesting(
477 base::BindRepeating(
478 &URLLoaderInterceptor::GetURLLoaderFactoryForBrowserProcess,
479 base::Unretained(this)));
480
Clark DuVall0d278b432019-06-25 18:24:57481 if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
482 NavigationURLLoaderImpl::SetURLLoaderFactoryInterceptorForTesting(
483 base::BindRepeating(
484 &URLLoaderInterceptor::InterceptNavigationRequestCallback,
485 base::Unretained(this)));
486 }
487
John Abd-El-Malek63ff5f32017-12-18 22:14:58488 if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) {
Dan Harrington942019f2019-01-04 17:58:03489 if (use_runloop_) {
490 base::RunLoop run_loop;
491 base::PostTaskWithTraits(
492 FROM_HERE, {BrowserThread::IO},
493 base::BindOnce(&URLLoaderInterceptor::IOState::Initialize, io_thread_,
Yao Xiao43ae3bc2019-07-09 05:22:23494 std::move(completion_status_callback),
Dan Harrington942019f2019-01-04 17:58:03495 run_loop.QuitClosure()));
496 run_loop.Run();
497 } else {
498 base::OnceClosure wrapped_callback = base::BindOnce(
499 [](base::OnceClosure callback) {
500 base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
501 std::move(callback));
502 },
503 std::move(ready_callback));
504
505 base::PostTaskWithTraits(
506 FROM_HERE, {BrowserThread::IO},
507 base::BindOnce(&URLLoaderInterceptor::IOState::Initialize, io_thread_,
Yao Xiao43ae3bc2019-07-09 05:22:23508 std::move(completion_status_callback),
Dan Harrington942019f2019-01-04 17:58:03509 std::move(wrapped_callback)));
510 }
John Abd-El-Malek63ff5f32017-12-18 22:14:58511 } else {
Yao Xiao43ae3bc2019-07-09 05:22:23512 io_thread_->Initialize(std::move(completion_status_callback),
513 std::move(ready_callback));
John Abd-El-Maleka4bb87f2017-11-27 21:32:19514 }
515}
516
517URLLoaderInterceptor::~URLLoaderInterceptor() {
518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
Dan Harrington942019f2019-01-04 17:58:03519 io_thread_->UnsetParent();
John Abd-El-Malek63ff5f32017-12-18 22:14:58520
Matt Falkenhagen4332b162019-03-04 08:58:52521 RenderFrameHostImpl::SetNetworkFactoryForTesting(
522 RenderFrameHostImpl::CreateNetworkFactoryCallback());
523 SharedWorkerHost::SetNetworkFactoryForTesting(
524 RenderFrameHostImpl::CreateNetworkFactoryCallback());
525 EmbeddedWorkerInstance::SetNetworkFactoryForTesting(
526 RenderFrameHostImpl::CreateNetworkFactoryCallback());
John Abd-El-Maleka4bb87f2017-11-27 21:32:19527
John Abd-El-Malekd5f920342018-02-12 17:37:36528 StoragePartitionImpl::
529 SetGetURLLoaderFactoryForBrowserProcessCallbackForTesting(
530 StoragePartitionImpl::CreateNetworkFactoryCallback());
531
Clark DuVall0d278b432019-06-25 18:24:57532 if (NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
533 NavigationURLLoaderImpl::SetURLLoaderFactoryInterceptorForTesting(
534 NavigationURLLoaderImpl::URLLoaderFactoryInterceptor());
535 }
536
Dan Harrington942019f2019-01-04 17:58:03537 if (use_runloop_) {
538 base::RunLoop run_loop;
539 base::PostTaskWithTraits(
540 FROM_HERE, {BrowserThread::IO},
541 base::BindOnce(&URLLoaderInterceptor::IOState::Shutdown, io_thread_,
542 run_loop.QuitClosure()));
543 run_loop.Run();
544 } else {
545 base::PostTaskWithTraits(
546 FROM_HERE, {BrowserThread::IO},
547 base::BindOnce(&URLLoaderInterceptor::IOState::Shutdown, io_thread_,
548 base::OnceClosure()));
549 }
John Abd-El-Maleka4bb87f2017-11-27 21:32:19550}
551
John Abd-El-Malekb165dc52018-01-18 17:12:18552void URLLoaderInterceptor::WriteResponse(
553 const std::string& headers,
554 const std::string& body,
Ovidio Henriquezf8e2d93a2018-08-01 15:28:42555 network::mojom::URLLoaderClient* client,
556 base::Optional<net::SSLInfo> ssl_info) {
John Abd-El-Maleka796fa52017-12-12 17:12:32557 net::HttpResponseInfo info;
David Benjamin1384c0402019-04-29 18:55:52558 info.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
559 net::HttpUtil::AssembleRawHeaders(headers));
John Abd-El-Malek46248032018-01-17 19:11:23560 network::ResourceResponseHead response;
John Abd-El-Maleka796fa52017-12-12 17:12:32561 response.headers = info.headers;
562 response.headers->GetMimeType(&response.mime_type);
Ovidio Henriquezf8e2d93a2018-08-01 15:28:42563 response.ssl_info = std::move(ssl_info);
Marijn Kruisselbrink9ebd7ba2018-06-11 23:18:04564 client->OnReceiveResponse(response);
John Abd-El-Maleka796fa52017-12-12 17:12:32565
566 uint32_t bytes_written = body.size();
Andrey Kosyakov8846844e2018-07-10 00:49:22567 mojo::DataPipe data_pipe(body.size());
John Abd-El-Malekd5f920342018-02-12 17:37:36568 CHECK_EQ(MOJO_RESULT_OK,
569 data_pipe.producer_handle->WriteData(
570 body.data(), &bytes_written, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
John Abd-El-Maleka796fa52017-12-12 17:12:32571 client->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
572
573 network::URLLoaderCompletionStatus status;
John Abd-El-Malekd5f920342018-02-12 17:37:36574 status.decoded_body_length = body.size();
John Abd-El-Maleka796fa52017-12-12 17:12:32575 status.error_code = net::OK;
576 client->OnComplete(status);
577}
578
John Abd-El-Malek30a86892018-05-26 00:14:16579void URLLoaderInterceptor::WriteResponse(
580 const std::string& relative_path,
581 network::mojom::URLLoaderClient* client,
Ovidio Henriquezf8e2d93a2018-08-01 15:28:42582 const std::string* headers,
583 base::Optional<net::SSLInfo> ssl_info) {
John Abd-El-Malek1d1ff9182018-08-10 16:18:23584 return WriteResponse(GetDataFilePath(relative_path), client, headers,
585 std::move(ssl_info));
586}
587
588void URLLoaderInterceptor::WriteResponse(
589 const base::FilePath& file_path,
590 network::mojom::URLLoaderClient* client,
591 const std::string* headers,
592 base::Optional<net::SSLInfo> ssl_info) {
John Abd-El-Malek30a86892018-05-26 00:14:16593 base::ScopedAllowBlockingForTesting allow_io;
594 std::string headers_str;
595 if (headers) {
596 headers_str = *headers;
597 } else {
John Abd-El-Malek1d1ff9182018-08-10 16:18:23598 base::FilePath::StringPieceType mock_headers_extension;
599#if defined(OS_WIN)
600 base::string16 temp =
601 base::ASCIIToUTF16(net::test_server::kMockHttpHeadersExtension);
602 mock_headers_extension = temp;
603#else
604 mock_headers_extension = net::test_server::kMockHttpHeadersExtension;
605#endif
606
607 base::FilePath headers_path(file_path.AddExtension(mock_headers_extension));
608 if (base::PathExists(headers_path)) {
John Abd-El-Malek30a86892018-05-26 00:14:16609 headers_str = ReadFile(headers_path);
610 } else {
611 headers_str = "HTTP/1.0 200 OK\nContent-type: " +
John Abd-El-Malek1d1ff9182018-08-10 16:18:23612 net::test_server::GetContentType(file_path) + "\n\n";
John Abd-El-Malek30a86892018-05-26 00:14:16613 }
614 }
John Abd-El-Malek1d1ff9182018-08-10 16:18:23615 WriteResponse(headers_str, ReadFile(file_path), client, std::move(ssl_info));
John Abd-El-Malek30a86892018-05-26 00:14:16616}
617
John Abd-El-Maleka4bb87f2017-11-27 21:32:19618void URLLoaderInterceptor::CreateURLLoaderFactoryForSubresources(
John Abd-El-Malekb165dc52018-01-18 17:12:18619 network::mojom::URLLoaderFactoryRequest request,
John Abd-El-Maleka4bb87f2017-11-27 21:32:19620 int process_id,
John Abd-El-Malekb165dc52018-01-18 17:12:18621 network::mojom::URLLoaderFactoryPtrInfo original_factory) {
John Abd-El-Malek63ff5f32017-12-18 22:14:58622 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
Eric Seckler8652dcd52018-09-20 10:42:28623 base::PostTaskWithTraits(
624 FROM_HERE, {BrowserThread::IO},
tzikff02d282018-02-22 06:11:08625 base::BindOnce(
626 &URLLoaderInterceptor::CreateURLLoaderFactoryForSubresources,
tzik983fb232018-04-06 15:47:50627 base::Unretained(this), std::move(request), process_id,
628 std::move(original_factory)));
John Abd-El-Maleka4bb87f2017-11-27 21:32:19629 return;
630 }
Dan Harrington942019f2019-01-04 17:58:03631 io_thread_->CreateURLLoaderFactoryForSubresources(
632 std::move(request), process_id, std::move(original_factory));
John Abd-El-Maleka4bb87f2017-11-27 21:32:19633}
634
John Abd-El-Malekd5f920342018-02-12 17:37:36635network::mojom::URLLoaderFactoryPtr
636URLLoaderInterceptor::GetURLLoaderFactoryForBrowserProcess(
637 network::mojom::URLLoaderFactoryPtr original_factory) {
638 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
639 network::mojom::URLLoaderFactoryPtr loader_factory;
640 browser_process_interceptors_.emplace(std::make_unique<BrowserProcessWrapper>(
Dan Harrington942019f2019-01-04 17:58:03641 mojo::MakeRequest(&loader_factory), io_thread_.get(),
642 std::move(original_factory)));
John Abd-El-Malekd5f920342018-02-12 17:37:36643 return loader_factory;
644}
645
Clark DuVall0d278b432019-06-25 18:24:57646void URLLoaderInterceptor::InterceptNavigationRequestCallback(
647 network::mojom::URLLoaderFactoryRequest* request) {
648 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
649
650 auto proxied_request = std::move(*request);
651 network::mojom::URLLoaderFactoryPtr target_factory;
652 *request = mojo::MakeRequest(&target_factory);
653
654 navigation_wrappers_.emplace(
655 std::make_unique<URLLoaderFactoryNavigationWrapper>(
656 std::move(proxied_request), std::move(target_factory),
657 io_thread_.get()));
658}
659
John Abd-El-Malekdb3a13b2018-05-01 17:52:02660bool URLLoaderInterceptor::Intercept(RequestParams* params) {
661 if (callback_.Run(params))
662 return true;
663
664 // mock.failed.request is a special request whereby the query indicates what
665 // error code to respond with.
666 if (params->url_request.url.DomainIs("mock.failed.request")) {
667 std::string query = params->url_request.url.query();
668 std::string error_code = query.substr(query.find("=") + 1);
669
670 int error = 0;
671 base::StringToInt(error_code, &error);
672 network::URLLoaderCompletionStatus status;
673 status.error_code = error;
674 params->client->OnComplete(status);
675 return true;
676 }
677
678 return false;
679}
680
Dan Harrington942019f2019-01-04 17:58:03681void URLLoaderInterceptor::IOState::SubresourceWrapperBindingError(
John Abd-El-Malek63ff5f32017-12-18 22:14:58682 SubresourceWrapper* wrapper) {
John Abd-El-Malekd5f920342018-02-12 17:37:36683 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
David Benjamine430b8a2019-03-21 20:46:27684 auto it = subresource_wrappers_.find(wrapper);
685 DCHECK(it != subresource_wrappers_.end());
686 subresource_wrappers_.erase(it);
John Abd-El-Malek63ff5f32017-12-18 22:14:58687}
688
Yao Xiao43ae3bc2019-07-09 05:22:23689void URLLoaderInterceptor::IOState::Initialize(
690 const URLLoaderCompletionStatusCallback& completion_status_callback,
691 base::OnceClosure closure) {
692 completion_status_callback_ = std::move(completion_status_callback);
John Abd-El-Malek87301582019-07-27 04:50:52693 URLLoaderFactoryGetter::SetGetNetworkFactoryCallbackForTesting(
694 base::BindRepeating(
695 &URLLoaderInterceptor::IOState::GetNetworkFactoryCallback,
696 base::Unretained(this)));
Clark DuVall649c05f2019-02-05 23:58:47697
John Abd-El-Malek87301582019-07-27 04:50:52698 if (!NavigationURLLoaderImpl::IsNavigationLoaderOnUIEnabled()) {
699 NavigationURLLoaderImpl::SetURLLoaderFactoryInterceptorForTesting(
Dan Harrington942019f2019-01-04 17:58:03700 base::BindRepeating(
John Abd-El-Malek87301582019-07-27 04:50:52701 &URLLoaderInterceptor::IOState::InterceptNavigationRequestCallback,
Dan Harrington942019f2019-01-04 17:58:03702 base::Unretained(this)));
John Abd-El-Malek63ff5f32017-12-18 22:14:58703 }
704
John Abd-El-Malekd5f920342018-02-12 17:37:36705 if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
John Abd-El-Malek63ff5f32017-12-18 22:14:58706 rmf_interceptor_ = std::make_unique<Interceptor>(
707 this, base::BindRepeating([]() {
708 return ResourceMessageFilter::GetCurrentForTesting()->child_id();
709 }),
710 base::BindRepeating([]() {
John Abd-El-Malekb165dc52018-01-18 17:12:18711 network::mojom::URLLoaderFactory* factory =
John Abd-El-Malek63ff5f32017-12-18 22:14:58712 ResourceMessageFilter::GetCurrentForTesting();
713 return factory;
714 }));
715 ResourceMessageFilter::SetNetworkFactoryForTesting(rmf_interceptor_.get());
716 }
John Abd-El-Malek63ff5f32017-12-18 22:14:58717 if (closure)
718 std::move(closure).Run();
719}
720
Dan Harrington942019f2019-01-04 17:58:03721void URLLoaderInterceptor::IOState::GetNetworkFactoryCallback(
722 URLLoaderFactoryGetter* url_loader_factory_getter) {
John Abd-El-Maleka4bb87f2017-11-27 21:32:19723 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
Dan Harrington942019f2019-01-04 17:58:03724 url_loader_factory_getter_wrappers_.emplace(
725 std::make_unique<URLLoaderFactoryGetterWrapper>(url_loader_factory_getter,
726 this));
727}
John Abd-El-Malek63ff5f32017-12-18 22:14:58728
Dan Harrington942019f2019-01-04 17:58:03729void URLLoaderInterceptor::IOState::CreateURLLoaderFactoryForSubresources(
730 network::mojom::URLLoaderFactoryRequest request,
731 int process_id,
732 network::mojom::URLLoaderFactoryPtrInfo original_factory) {
733 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
734 subresource_wrappers_.emplace(std::make_unique<SubresourceWrapper>(
735 std::move(request), process_id, this, std::move(original_factory)));
John Abd-El-Maleka4bb87f2017-11-27 21:32:19736}
737
Lukasz Anforowicz98ccf1c2018-08-23 18:14:31738// static
739std::unique_ptr<content::URLLoaderInterceptor>
740URLLoaderInterceptor::SetupRequestFailForURL(const GURL& url,
Dan Harrington942019f2019-01-04 17:58:03741 net::Error error,
742 base::OnceClosure ready_callback) {
743 return std::make_unique<content::URLLoaderInterceptor>(
744 base::BindRepeating(
745 [](const GURL& url, net::Error error,
746 content::URLLoaderInterceptor::RequestParams* params) {
747 if (params->url_request.url != url)
748 return false;
749 params->client->OnComplete(
750 network::URLLoaderCompletionStatus(error));
751 return true;
752 },
753 url, error),
Yao Xiao43ae3bc2019-07-09 05:22:23754 URLLoaderCompletionStatusCallback(), std::move(ready_callback));
Lukasz Anforowicz98ccf1c2018-08-23 18:14:31755}
756
John Abd-El-Maleka4bb87f2017-11-27 21:32:19757} // namespace content