From 96e7b443fc60334944edce1d69618cdfa8642237 Mon Sep 17 00:00:00 2001 From: "trop[bot]" <37223003+trop[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2019 17:29:49 -0800 Subject: [PATCH] fix: sourcemaps not loading with network service (#21494) Backports https://chromium-review.googlesource.com/c/chromium/src/+/1525270 Backports https://chromium-review.googlesource.com/c/chromium/src/+/1852212 --- .../ui/inspectable_web_contents_impl.cc | 176 ++++++++++++++---- 1 file changed, 140 insertions(+), 36 deletions(-) diff --git a/shell/browser/ui/inspectable_web_contents_impl.cc b/shell/browser/ui/inspectable_web_contents_impl.cc index 037921a817af4..562602d77dfb9 100644 --- a/shell/browser/ui/inspectable_web_contents_impl.cc +++ b/shell/browser/ui/inspectable_web_contents_impl.cc @@ -27,10 +27,12 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/file_select_listener.h" +#include "content/public/browser/file_url_loader.h" #include "content/public/browser/host_zoom_map.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/shared_cors_origin_access_list.h" #include "content/public/browser/storage_partition.h" #include "content/public/common/user_agent.h" #include "ipc/ipc_channel.h" @@ -61,7 +63,7 @@ const char kChromeUIDevToolsURL[] = "textColor=rgba(0,0,0,1)&" "experiments=true"; const char kChromeUIDevToolsRemoteFrontendBase[] = - "https://devtools-frontend.appspot.com/"; + "https://chrome-devtools-frontend.appspot.com/"; const char kChromeUIDevToolsRemoteFrontendPath[] = "serve_file"; const char kDevToolsBoundsPref[] = "electron.devtools.bounds"; @@ -149,29 +151,87 @@ GURL GetDevToolsURL(bool can_dock) { return GURL(url_string); } +constexpr base::TimeDelta kInitialBackoffDelay = + base::TimeDelta::FromMilliseconds(250); +constexpr base::TimeDelta kMaxBackoffDelay = base::TimeDelta::FromSeconds(10); + } // namespace class InspectableWebContentsImpl::NetworkResourceLoader : public network::SimpleURLLoaderStreamConsumer { public: - NetworkResourceLoader(int stream_id, - InspectableWebContentsImpl* bindings, - std::unique_ptr loader, - network::mojom::URLLoaderFactory* url_loader_factory, - const DispatchCallback& callback) + class URLLoaderFactoryHolder { + public: + network::mojom::URLLoaderFactory* get() { + return ptr_.get() ? ptr_.get() : refptr_.get(); + } + void operator=(std::unique_ptr&& ptr) { + ptr_ = std::move(ptr); + } + void operator=(scoped_refptr&& refptr) { + refptr_ = std::move(refptr); + } + + private: + std::unique_ptr ptr_; + scoped_refptr refptr_; + }; + + static void Create(int stream_id, + InspectableWebContentsImpl* bindings, + const network::ResourceRequest& resource_request, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + URLLoaderFactoryHolder url_loader_factory, + const DispatchCallback& callback, + base::TimeDelta retry_delay = base::TimeDelta()) { + auto resource_loader = + std::make_unique( + stream_id, bindings, resource_request, traffic_annotation, + std::move(url_loader_factory), callback, retry_delay); + bindings->loaders_.insert(std::move(resource_loader)); + } + + NetworkResourceLoader( + int stream_id, + InspectableWebContentsImpl* bindings, + const network::ResourceRequest& resource_request, + const net::NetworkTrafficAnnotationTag& traffic_annotation, + URLLoaderFactoryHolder url_loader_factory, + const DispatchCallback& callback, + base::TimeDelta delay) : stream_id_(stream_id), bindings_(bindings), - loader_(std::move(loader)), - callback_(callback) { + resource_request_(resource_request), + traffic_annotation_(traffic_annotation), + loader_(network::SimpleURLLoader::Create( + std::make_unique(resource_request), + traffic_annotation)), + url_loader_factory_(std::move(url_loader_factory)), + callback_(callback), + retry_delay_(delay) { loader_->SetOnResponseStartedCallback(base::BindOnce( &NetworkResourceLoader::OnResponseStarted, base::Unretained(this))); - loader_->DownloadAsStream(url_loader_factory, this); + timer_.Start(FROM_HERE, delay, + base::BindRepeating(&NetworkResourceLoader::DownloadAsStream, + base::Unretained(this))); } NetworkResourceLoader(const NetworkResourceLoader&) = delete; NetworkResourceLoader& operator=(const NetworkResourceLoader&) = delete; private: + void DownloadAsStream() { + loader_->DownloadAsStream(url_loader_factory_.get(), this); + } + + base::TimeDelta GetNextExponentialBackoffDelay(const base::TimeDelta& delta) { + if (delta.is_zero()) { + return kInitialBackoffDelay; + } else { + return delta * 1.3; + } + } + void OnResponseStarted(const GURL& final_url, const network::ResourceResponseHead& response_head) { response_headers_ = response_head.headers; @@ -198,21 +258,34 @@ class InspectableWebContentsImpl::NetworkResourceLoader } void OnComplete(bool success) override { - base::DictionaryValue response; - response.SetInteger("statusCode", response_headers_ - ? response_headers_->response_code() - : 200); - - auto headers = std::make_unique(); - size_t iterator = 0; - std::string name; - std::string value; - while (response_headers_ && - response_headers_->EnumerateHeaderLines(&iterator, &name, &value)) - headers->SetString(name, value); - - response.Set("headers", std::move(headers)); - callback_.Run(&response); + if (!success && loader_->NetError() == net::ERR_INSUFFICIENT_RESOURCES && + retry_delay_ < kMaxBackoffDelay) { + const base::TimeDelta delay = + GetNextExponentialBackoffDelay(retry_delay_); + LOG(WARNING) << "InspectableWebContentsImpl::NetworkResourceLoader id = " + << stream_id_ + << " failed with insufficient resources, retrying in " + << delay << "." << std::endl; + NetworkResourceLoader::Create( + stream_id_, bindings_, resource_request_, traffic_annotation_, + std::move(url_loader_factory_), callback_, delay); + } else { + base::DictionaryValue response; + response.SetInteger("statusCode", response_headers_ + ? response_headers_->response_code() + : 200); + + auto headers = std::make_unique(); + size_t iterator = 0; + std::string name; + std::string value; + while (response_headers_ && + response_headers_->EnumerateHeaderLines(&iterator, &name, &value)) + headers->SetString(name, value); + + response.Set("headers", std::move(headers)); + callback_.Run(&response); + } bindings_->loaders_.erase(bindings_->loaders_.find(this)); } @@ -221,9 +294,14 @@ class InspectableWebContentsImpl::NetworkResourceLoader const int stream_id_; InspectableWebContentsImpl* const bindings_; + const network::ResourceRequest resource_request_; + const net::NetworkTrafficAnnotationTag traffic_annotation_; std::unique_ptr loader_; + URLLoaderFactoryHolder url_loader_factory_; DispatchCallback callback_; scoped_refptr response_headers_; + base::OneShotTimer timer_; + base::TimeDelta retry_delay_; }; // Implemented separately on each platform. @@ -527,19 +605,45 @@ void InspectableWebContentsImpl::LoadNetworkResource( return; } - auto resource_request = std::make_unique(); - resource_request->url = gurl; - resource_request->headers.AddHeadersFromString(headers); - - auto* partition = content::BrowserContext::GetDefaultStoragePartition( - GetDevToolsWebContents()->GetBrowserContext()); - auto factory = partition->GetURLLoaderFactoryForBrowserProcess(); + // Create traffic annotation tag. + net::NetworkTrafficAnnotationTag traffic_annotation = + net::DefineNetworkTrafficAnnotation("devtools_network_resource", R"( + semantics { + sender: "Developer Tools" + description: + "When user opens Developer Tools, the browser may fetch additional " + "resources from the network to enrich the debugging experience " + "(e.g. source map resources)." + trigger: "User opens Developer Tools to debug a web page." + data: "Any resources requested by Developer Tools." + destination: WEBSITE + } + policy { + cookies_allowed: YES + cookies_store: "user" + setting: + "It's not possible to disable this feature from settings." + })"); + + network::ResourceRequest resource_request; + resource_request.url = gurl; + resource_request.site_for_cookies = gurl; + resource_request.headers.AddHeadersFromString(headers); + + NetworkResourceLoader::URLLoaderFactoryHolder url_loader_factory; + if (gurl.SchemeIsFile()) { + url_loader_factory = content::CreateFileURLLoaderFactory( + base::FilePath() /* profile_path */, + nullptr /* shared_cors_origin_access_list */); + } else { + auto* partition = content::BrowserContext::GetDefaultStoragePartition( + GetDevToolsWebContents()->GetBrowserContext()); + url_loader_factory = partition->GetURLLoaderFactoryForBrowserProcess(); + } - auto simple_url_loader = network::SimpleURLLoader::Create( - std::move(resource_request), MISSING_TRAFFIC_ANNOTATION); - auto resource_loader = std::make_unique( - stream_id, this, std::move(simple_url_loader), factory.get(), callback); - loaders_.insert(std::move(resource_loader)); + NetworkResourceLoader::Create(stream_id, this, resource_request, + traffic_annotation, + std::move(url_loader_factory), callback); } void InspectableWebContentsImpl::SetIsDocked(const DispatchCallback& callback,