cef/libcef/browser/net_service/url_loader_factory_getter.cc
Marshall Greenblatt ba0e1b5719 Add NetworkService support for CefURLRequest (see issue #2622).
Requests created using CefURLRequest::Create are not associated with a
browser/frame. When originating from the render process these requests cannot be
intercepted and consequently only http(s) and blob requests are supported. To
work around this limitation a new CefFrame::CreateURLRequest method has been
added that allows the request to be associated with that browser/frame for
interception purposes.

This change also fixes an issue with the NetworkService implementation where
redirected requests could result in two parallel requests being sent to the
target server.

To test: URLRequestTest.* tests pass with NetworkService enabled.
2019-05-17 21:42:25 +03:00

127 lines
4.9 KiB
C++

// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
// Copyright (c) 2018 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 "libcef/browser/net_service/url_loader_factory_getter.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/thread_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/devtools/devtools_instrumentation.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_client.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
namespace net_service {
// Based on CreateDownloadURLLoaderFactoryGetter from
// content/browser/download/download_manager_impl.cc.
// static
scoped_refptr<URLLoaderFactoryGetter> URLLoaderFactoryGetter::Create(
content::RenderFrameHost* render_frame_host,
content::BrowserContext* browser_context) {
CEF_REQUIRE_UIT();
DCHECK(browser_context);
// Call this early because newly created BrowserContexts may need to
// initialize additional state, and that should be done on the UI thread
// instead of potentially racing with the WillCreateURLLoaderFactory
// implementation.
auto loader_factory =
content::BrowserContext::GetDefaultStoragePartition(browser_context)
->GetURLLoaderFactoryForBrowserProcess();
network::mojom::URLLoaderFactoryPtrInfo proxy_factory_ptr_info;
network::mojom::URLLoaderFactoryRequest proxy_factory_request;
// Create an intermediate pipe that can be used to proxy the request's
// URLLoaderFactory.
network::mojom::URLLoaderFactoryPtrInfo maybe_proxy_factory_ptr_info;
network::mojom::URLLoaderFactoryRequest maybe_proxy_factory_request =
MakeRequest(&maybe_proxy_factory_ptr_info);
bool should_proxy = false;
int render_process_id = -1;
if (render_frame_host) {
render_process_id = render_frame_host->GetProcess()->GetID();
// Allow DevTools to potentially inject itself into the proxy pipe.
should_proxy =
content::devtools_instrumentation::WillCreateURLLoaderFactory(
static_cast<content::RenderFrameHostImpl*>(render_frame_host),
false /* is_navigation */, false /* is_download */,
&maybe_proxy_factory_request);
}
// Allow the Content embedder to inject itself if it wants to.
should_proxy |= CefContentBrowserClient::Get()->WillCreateURLLoaderFactory(
browser_context, render_frame_host, render_process_id,
false /* is_navigation */, false /* is_download */, url::Origin(),
&maybe_proxy_factory_request, nullptr /* header_client */,
nullptr /* bypass_redirect_checks */);
// If anyone above indicated that they care about proxying, pass the
// intermediate pipe along to the URLLoaderFactoryGetter.
if (should_proxy) {
proxy_factory_ptr_info = std::move(maybe_proxy_factory_ptr_info);
proxy_factory_request = std::move(maybe_proxy_factory_request);
}
return base::WrapRefCounted(new URLLoaderFactoryGetter(
loader_factory->Clone(), std::move(proxy_factory_ptr_info),
std::move(proxy_factory_request)));
}
// Based on NetworkDownloadURLLoaderFactoryGetter from
// content/browser/download/network_download_url_loader_factory_getter.cc.
scoped_refptr<network::SharedURLLoaderFactory>
URLLoaderFactoryGetter::GetURLLoaderFactory() {
// On first call we associate with the current thread.
if (!task_runner_) {
task_runner_ = base::ThreadTaskRunnerHandle::Get();
} else {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
}
if (lazy_factory_)
return lazy_factory_;
// Bind on the current thread.
auto loader_factory =
network::SharedURLLoaderFactory::Create(std::move(loader_factory_info_));
if (proxy_factory_request_.is_pending()) {
loader_factory->Clone(std::move(proxy_factory_request_));
lazy_factory_ =
base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
std::move(proxy_factory_ptr_info_));
} else {
lazy_factory_ = loader_factory;
}
return lazy_factory_;
}
URLLoaderFactoryGetter::URLLoaderFactoryGetter(
std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info,
network::mojom::URLLoaderFactoryPtrInfo proxy_factory_ptr_info,
network::mojom::URLLoaderFactoryRequest proxy_factory_request)
: loader_factory_info_(std::move(loader_factory_info)),
proxy_factory_ptr_info_(std::move(proxy_factory_ptr_info)),
proxy_factory_request_(std::move(proxy_factory_request)) {}
URLLoaderFactoryGetter::~URLLoaderFactoryGetter() = default;
void URLLoaderFactoryGetter::DeleteOnCorrectThread() const {
if (task_runner_ && !task_runner_->RunsTasksInCurrentSequence()) {
task_runner_->DeleteSoon(FROM_HERE, this);
return;
}
delete this;
}
} // namespace net_service