|
@@ -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"
|
|
@@ -62,7 +64,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";
|
|
@@ -150,29 +152,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<network::SimpleURLLoader> 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<network::mojom::URLLoaderFactory>&& ptr) {
|
|
|
+ ptr_ = std::move(ptr);
|
|
|
+ }
|
|
|
+ void operator=(scoped_refptr<network::SharedURLLoaderFactory>&& refptr) {
|
|
|
+ refptr_ = std::move(refptr);
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ std::unique_ptr<network::mojom::URLLoaderFactory> ptr_;
|
|
|
+ scoped_refptr<network::SharedURLLoaderFactory> 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<InspectableWebContentsImpl::NetworkResourceLoader>(
|
|
|
+ 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<network::ResourceRequest>(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::mojom::URLResponseHead& response_head) {
|
|
|
response_headers_ = response_head.headers;
|
|
@@ -199,21 +259,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<base::DictionaryValue>();
|
|
|
- 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<base::DictionaryValue>();
|
|
|
+ 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));
|
|
|
}
|
|
@@ -222,9 +295,14 @@ class InspectableWebContentsImpl::NetworkResourceLoader
|
|
|
|
|
|
const int stream_id_;
|
|
|
InspectableWebContentsImpl* const bindings_;
|
|
|
+ const network::ResourceRequest resource_request_;
|
|
|
+ const net::NetworkTrafficAnnotationTag traffic_annotation_;
|
|
|
std::unique_ptr<network::SimpleURLLoader> loader_;
|
|
|
+ URLLoaderFactoryHolder url_loader_factory_;
|
|
|
DispatchCallback callback_;
|
|
|
scoped_refptr<net::HttpResponseHeaders> response_headers_;
|
|
|
+ base::OneShotTimer timer_;
|
|
|
+ base::TimeDelta retry_delay_;
|
|
|
};
|
|
|
|
|
|
// Implemented separately on each platform.
|
|
@@ -528,19 +606,45 @@ void InspectableWebContentsImpl::LoadNetworkResource(
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- auto resource_request = std::make_unique<network::ResourceRequest>();
|
|
|
- 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<NetworkResourceLoader>(
|
|
|
- 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,
|