feat: migrate webRequest module to NetworkService (Part 5) (#19714)

* Pass WebRequest to ProxyingURLLoaderFactory

* Call WebRequestAPI in InProgressRequest

* Store the listeners

* Pass the request and response

* Add stub to handle the events

* Use extensions::WebRequestInfo

* Make sure webRequest is managed by Session

* chore: make creation of WebRequestNS more clear

* fix: check WebContents for service workers
This commit is contained in:
Cheng Zhao 2019-08-13 14:47:35 +09:00 committed by GitHub
parent 9713fa09e7
commit 69eac0d9d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 365 additions and 46 deletions

View file

@ -206,8 +206,10 @@ Session::Session(v8::Isolate* isolate, AtomBrowserContext* browser_context)
Session::~Session() { Session::~Session() {
content::BrowserContext::GetDownloadManager(browser_context()) content::BrowserContext::GetDownloadManager(browser_context())
->RemoveObserver(this); ->RemoveObserver(this);
// TODO(zcbenz): Now since URLRequestContextGetter is gone, is this still
// needed?
// Refs https://github.com/electron/electron/pull/12305.
DestroyGlobalHandle(isolate(), cookies_); DestroyGlobalHandle(isolate(), cookies_);
DestroyGlobalHandle(isolate(), web_request_);
DestroyGlobalHandle(isolate(), protocol_); DestroyGlobalHandle(isolate(), protocol_);
DestroyGlobalHandle(isolate(), net_log_); DestroyGlobalHandle(isolate(), net_log_);
g_sessions.erase(weak_map_id()); g_sessions.erase(weak_map_id());

View file

@ -100,12 +100,14 @@ class Session : public mate::TrackableObject<Session>,
download::DownloadItem* item) override; download::DownloadItem* item) override;
private: private:
// Cached object. // Cached mate::Wrappable objects.
v8::Global<v8::Value> cookies_; v8::Global<v8::Value> cookies_;
v8::Global<v8::Value> protocol_; v8::Global<v8::Value> protocol_;
v8::Global<v8::Value> web_request_;
v8::Global<v8::Value> net_log_; v8::Global<v8::Value> net_log_;
// Cached object.
v8::Global<v8::Value> web_request_;
// The client id to enable the network throttler. // The client id to enable the network throttler.
base::UnguessableToken network_emulation_token_; base::UnguessableToken network_emulation_token_;

View file

@ -4,13 +4,14 @@
#include "shell/browser/api/atom_api_web_request_ns.h" #include "shell/browser/api/atom_api_web_request_ns.h"
#include <set> #include <memory>
#include <string> #include <string>
#include <utility>
#include "extensions/common/url_pattern.h"
#include "gin/converter.h" #include "gin/converter.h"
#include "gin/dictionary.h" #include "gin/dictionary.h"
#include "gin/object_template_builder.h" #include "gin/object_template_builder.h"
#include "shell/browser/api/atom_api_session.h"
#include "shell/browser/atom_browser_context.h" #include "shell/browser/atom_browser_context.h"
#include "shell/common/gin_converters/callback_converter_gin_adapter.h" #include "shell/common/gin_converters/callback_converter_gin_adapter.h"
#include "shell/common/gin_converters/std_converter.h" #include "shell/common/gin_converters/std_converter.h"
@ -37,12 +38,56 @@ namespace electron {
namespace api { namespace api {
namespace {
const char* kUserDataKey = "WebRequestNS";
// BrowserContext <=> WebRequestNS relationship.
struct UserData : public base::SupportsUserData::Data {
explicit UserData(WebRequestNS* data) : data(data) {}
WebRequestNS* data;
};
// Test whether the URL of |request| matches |patterns|.
bool MatchesFilterCondition(extensions::WebRequestInfo* request,
const std::set<URLPattern>& patterns) {
if (patterns.empty())
return true;
for (const auto& pattern : patterns) {
if (pattern.MatchesURL(request->url))
return true;
}
return false;
}
} // namespace
gin::WrapperInfo WebRequestNS::kWrapperInfo = {gin::kEmbedderNativeGin}; gin::WrapperInfo WebRequestNS::kWrapperInfo = {gin::kEmbedderNativeGin};
WebRequestNS::WebRequestNS(v8::Isolate* isolate, WebRequestNS::SimpleListenerInfo::SimpleListenerInfo(
AtomBrowserContext* browser_context) {} std::set<URLPattern> patterns_,
SimpleListener listener_)
: url_patterns(std::move(patterns_)), listener(listener_) {}
WebRequestNS::SimpleListenerInfo::SimpleListenerInfo() = default;
WebRequestNS::SimpleListenerInfo::~SimpleListenerInfo() = default;
WebRequestNS::~WebRequestNS() = default; WebRequestNS::ResponseListenerInfo::ResponseListenerInfo(
std::set<URLPattern> patterns_,
ResponseListener listener_)
: url_patterns(std::move(patterns_)), listener(listener_) {}
WebRequestNS::ResponseListenerInfo::ResponseListenerInfo() = default;
WebRequestNS::ResponseListenerInfo::~ResponseListenerInfo() = default;
WebRequestNS::WebRequestNS(v8::Isolate* isolate,
content::BrowserContext* browser_context)
: browser_context_(browser_context) {
browser_context_->SetUserData(kUserDataKey, std::make_unique<UserData>(this));
}
WebRequestNS::~WebRequestNS() {
browser_context_->RemoveUserData(kUserDataKey);
}
gin::ObjectTemplateBuilder WebRequestNS::GetObjectTemplateBuilder( gin::ObjectTemplateBuilder WebRequestNS::GetObjectTemplateBuilder(
v8::Isolate* isolate) { v8::Isolate* isolate) {
@ -68,18 +113,70 @@ const char* WebRequestNS::GetTypeName() {
return "WebRequest"; return "WebRequest";
} }
int WebRequestNS::OnBeforeRequest(extensions::WebRequestInfo* request,
net::CompletionOnceCallback callback,
GURL* new_url) {
return HandleResponseEvent(kOnBeforeRequest, request, std::move(callback),
new_url);
}
int WebRequestNS::OnBeforeSendHeaders(extensions::WebRequestInfo* request,
BeforeSendHeadersCallback callback,
net::HttpRequestHeaders* headers) {
// TODO(zcbenz): Figure out how to handle this generally.
return net::OK;
}
int WebRequestNS::OnHeadersReceived(
extensions::WebRequestInfo* request,
net::CompletionOnceCallback callback,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url) {
return HandleResponseEvent(kOnHeadersReceived, request, std::move(callback),
original_response_headers,
override_response_headers,
allowed_unsafe_redirect_url);
}
void WebRequestNS::OnSendHeaders(extensions::WebRequestInfo* request,
const net::HttpRequestHeaders& headers) {
HandleSimpleEvent(kOnSendHeaders, request, headers);
}
void WebRequestNS::OnBeforeRedirect(extensions::WebRequestInfo* request,
const GURL& new_location) {
HandleSimpleEvent(kOnBeforeRedirect, request, new_location);
}
void WebRequestNS::OnResponseStarted(extensions::WebRequestInfo* request) {
HandleSimpleEvent(kOnResponseStarted, request);
}
void WebRequestNS::OnErrorOccurred(extensions::WebRequestInfo* request,
int net_error) {
HandleSimpleEvent(kOnErrorOccurred, request, net_error);
}
void WebRequestNS::OnCompleted(extensions::WebRequestInfo* request,
int net_error) {
HandleSimpleEvent(kOnCompleted, request, net_error);
}
template <WebRequestNS::SimpleEvent event> template <WebRequestNS::SimpleEvent event>
void WebRequestNS::SetSimpleListener(gin::Arguments* args) { void WebRequestNS::SetSimpleListener(gin::Arguments* args) {
SetListener<SimpleListener, SimpleEvent>(event, args); SetListener<SimpleListener>(event, &simple_listeners_, args);
} }
template <WebRequestNS::ResponseEvent event> template <WebRequestNS::ResponseEvent event>
void WebRequestNS::SetResponseListener(gin::Arguments* args) { void WebRequestNS::SetResponseListener(gin::Arguments* args) {
SetListener<ResponseListener, ResponseEvent>(event, args); SetListener<ResponseListener>(event, &response_listeners_, args);
} }
template <typename Listener, typename Event> template <typename Listener, typename Listeners, typename Event>
void WebRequestNS::SetListener(Event event, gin::Arguments* args) { void WebRequestNS::SetListener(Event event,
Listeners* listeners,
gin::Arguments* args) {
// { urls }. // { urls }.
std::set<URLPattern> patterns; std::set<URLPattern> patterns;
gin::Dictionary dict(args->isolate()); gin::Dictionary dict(args->isolate());
@ -94,17 +191,76 @@ void WebRequestNS::SetListener(Event event, gin::Arguments* args) {
return; return;
} }
// TODO(zcbenz): Actually set the listeners. if (listener.is_null())
args->ThrowTypeError("This API is not implemented yet"); listeners->erase(event);
else
(*listeners)[event] = {std::move(patterns), std::move(listener)};
}
template <typename... Args>
void WebRequestNS::HandleSimpleEvent(SimpleEvent event,
extensions::WebRequestInfo* request,
Args... args) {
const auto& info = simple_listeners_[event];
if (!MatchesFilterCondition(request, info.url_patterns))
return;
// TODO(zcbenz): Invoke the listener.
}
template <typename Out, typename... Args>
int WebRequestNS::HandleResponseEvent(ResponseEvent event,
extensions::WebRequestInfo* request,
net::CompletionOnceCallback callback,
Out out,
Args... args) {
const auto& info = response_listeners_[event];
if (!MatchesFilterCondition(request, info.url_patterns))
return net::OK;
// TODO(zcbenz): Invoke the listener.
return net::OK;
}
// static
gin::Handle<WebRequestNS> WebRequestNS::FromOrCreate(
v8::Isolate* isolate,
content::BrowserContext* browser_context) {
gin::Handle<WebRequestNS> handle = From(isolate, browser_context);
if (handle.IsEmpty()) {
// Make sure the |Session| object has the |webRequest| property created.
v8::Local<v8::Value> web_request =
Session::CreateFrom(isolate,
static_cast<AtomBrowserContext*>(browser_context))
->WebRequest(isolate);
gin::ConvertFromV8(isolate, web_request, &handle);
}
DCHECK(!handle.IsEmpty());
return handle;
} }
// static // static
gin::Handle<WebRequestNS> WebRequestNS::Create( gin::Handle<WebRequestNS> WebRequestNS::Create(
v8::Isolate* isolate, v8::Isolate* isolate,
AtomBrowserContext* browser_context) { content::BrowserContext* browser_context) {
DCHECK(From(isolate, browser_context).IsEmpty())
<< "WebRequestNS already created";
return gin::CreateHandle(isolate, new WebRequestNS(isolate, browser_context)); return gin::CreateHandle(isolate, new WebRequestNS(isolate, browser_context));
} }
// static
gin::Handle<WebRequestNS> WebRequestNS::From(
v8::Isolate* isolate,
content::BrowserContext* browser_context) {
if (!browser_context)
return gin::Handle<WebRequestNS>();
auto* user_data =
static_cast<UserData*>(browser_context->GetUserData(kUserDataKey));
if (!user_data)
return gin::Handle<WebRequestNS>();
return gin::CreateHandle(isolate, user_data->data);
}
} // namespace api } // namespace api
} // namespace electron } // namespace electron

View file

@ -5,25 +5,47 @@
#ifndef SHELL_BROWSER_API_ATOM_API_WEB_REQUEST_NS_H_ #ifndef SHELL_BROWSER_API_ATOM_API_WEB_REQUEST_NS_H_
#define SHELL_BROWSER_API_ATOM_API_WEB_REQUEST_NS_H_ #define SHELL_BROWSER_API_ATOM_API_WEB_REQUEST_NS_H_
#include <map>
#include <set>
#include "base/values.h" #include "base/values.h"
#include "extensions/common/url_pattern.h"
#include "gin/arguments.h" #include "gin/arguments.h"
#include "gin/handle.h" #include "gin/handle.h"
#include "gin/wrappable.h" #include "gin/wrappable.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#include "native_mate/handle.h" #include "native_mate/handle.h"
#include "shell/browser/net/proxying_url_loader_factory.h"
namespace content {
class BrowserContext;
}
namespace electron { namespace electron {
class AtomBrowserContext;
namespace api { namespace api {
class WebRequestNS : public gin::Wrappable<WebRequestNS> { class WebRequestNS : public gin::Wrappable<WebRequestNS>, public WebRequestAPI {
public: public:
static gin::WrapperInfo kWrapperInfo; static gin::WrapperInfo kWrapperInfo;
static gin::Handle<WebRequestNS> Create(v8::Isolate* isolate, // Return the WebRequest object attached to |browser_context|, create if there
AtomBrowserContext* browser_context); // is no one.
// Note that the lifetime of WebRequest object is managed by Session, instead
// of the caller.
static gin::Handle<WebRequestNS> FromOrCreate(
v8::Isolate* isolate,
content::BrowserContext* browser_context);
// Return a new WebRequest object, this should only be called by Session.
static gin::Handle<WebRequestNS> Create(
v8::Isolate* isolate,
content::BrowserContext* browser_context);
// Find the WebRequest object attached to |browser_context|.
static gin::Handle<WebRequestNS> From(
v8::Isolate* isolate,
content::BrowserContext* browser_context);
// gin::Wrappable: // gin::Wrappable:
gin::ObjectTemplateBuilder GetObjectTemplateBuilder( gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
@ -31,9 +53,31 @@ class WebRequestNS : public gin::Wrappable<WebRequestNS> {
const char* GetTypeName() override; const char* GetTypeName() override;
private: private:
WebRequestNS(v8::Isolate* isolate, AtomBrowserContext* browser_context); WebRequestNS(v8::Isolate* isolate, content::BrowserContext* browser_context);
~WebRequestNS() override; ~WebRequestNS() override;
// WebRequestAPI:
int OnBeforeRequest(extensions::WebRequestInfo* request,
net::CompletionOnceCallback callback,
GURL* new_url) override;
int OnBeforeSendHeaders(extensions::WebRequestInfo* request,
BeforeSendHeadersCallback callback,
net::HttpRequestHeaders* headers) override;
int OnHeadersReceived(
extensions::WebRequestInfo* request,
net::CompletionOnceCallback callback,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url) override;
void OnSendHeaders(extensions::WebRequestInfo* request,
const net::HttpRequestHeaders& headers) override;
void OnBeforeRedirect(extensions::WebRequestInfo* request,
const GURL& new_location) override;
void OnResponseStarted(extensions::WebRequestInfo* request) override;
void OnErrorOccurred(extensions::WebRequestInfo* request,
int net_error) override;
void OnCompleted(extensions::WebRequestInfo* request, int net_error) override;
enum SimpleEvent { enum SimpleEvent {
kOnSendHeaders, kOnSendHeaders,
kOnBeforeRedirect, kOnBeforeRedirect,
@ -56,8 +100,44 @@ class WebRequestNS : public gin::Wrappable<WebRequestNS> {
void SetSimpleListener(gin::Arguments* args); void SetSimpleListener(gin::Arguments* args);
template <ResponseEvent event> template <ResponseEvent event>
void SetResponseListener(gin::Arguments* args); void SetResponseListener(gin::Arguments* args);
template <typename Listener, typename Event> template <typename Listener, typename Listeners, typename Event>
void SetListener(Event event, gin::Arguments* args); void SetListener(Event event, Listeners* listeners, gin::Arguments* args);
template <typename... Args>
void HandleSimpleEvent(SimpleEvent event,
extensions::WebRequestInfo* request,
Args... args);
template <typename Out, typename... Args>
int HandleResponseEvent(ResponseEvent event,
extensions::WebRequestInfo* request,
net::CompletionOnceCallback callback,
Out out,
Args... args);
struct SimpleListenerInfo {
std::set<URLPattern> url_patterns;
SimpleListener listener;
SimpleListenerInfo(std::set<URLPattern>, SimpleListener);
SimpleListenerInfo();
~SimpleListenerInfo();
};
struct ResponseListenerInfo {
std::set<URLPattern> url_patterns;
ResponseListener listener;
ResponseListenerInfo(std::set<URLPattern>, ResponseListener);
ResponseListenerInfo();
~ResponseListenerInfo();
};
std::map<SimpleEvent, SimpleListenerInfo> simple_listeners_;
std::map<ResponseEvent, ResponseListenerInfo> response_listeners_;
std::map<uint64_t, net::CompletionOnceCallback> callbacks_;
// Weak-ref, it manages us.
content::BrowserContext* browser_context_;
}; };
} // namespace api } // namespace api

View file

@ -52,6 +52,7 @@
#include "shell/browser/api/atom_api_app.h" #include "shell/browser/api/atom_api_app.h"
#include "shell/browser/api/atom_api_protocol_ns.h" #include "shell/browser/api/atom_api_protocol_ns.h"
#include "shell/browser/api/atom_api_web_contents.h" #include "shell/browser/api/atom_api_web_contents.h"
#include "shell/browser/api/atom_api_web_request_ns.h"
#include "shell/browser/atom_browser_context.h" #include "shell/browser/atom_browser_context.h"
#include "shell/browser/atom_browser_main_parts.h" #include "shell/browser/atom_browser_main_parts.h"
#include "shell/browser/atom_navigation_throttle.h" #include "shell/browser/atom_navigation_throttle.h"
@ -979,13 +980,17 @@ bool AtomBrowserClient::WillCreateURLLoaderFactory(
bool* bypass_redirect_checks) { bool* bypass_redirect_checks) {
content::WebContents* web_contents = content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(frame_host); content::WebContents::FromRenderFrameHost(frame_host);
if (!web_contents) { // For service workers there might be no WebContents.
if (!web_contents)
return false; return false;
}
v8::Isolate* isolate = v8::Isolate::GetCurrent();
api::ProtocolNS* protocol = api::ProtocolNS::FromWrappedClass( api::ProtocolNS* protocol = api::ProtocolNS::FromWrappedClass(
v8::Isolate::GetCurrent(), web_contents->GetBrowserContext()); isolate, web_contents->GetBrowserContext());
if (!protocol) DCHECK(protocol);
return false; auto web_request = api::WebRequestNS::FromOrCreate(
isolate, web_contents->GetBrowserContext());
DCHECK(web_request.get());
auto proxied_receiver = std::move(*factory_receiver); auto proxied_receiver = std::move(*factory_receiver);
network::mojom::URLLoaderFactoryPtrInfo target_factory_info; network::mojom::URLLoaderFactoryPtrInfo target_factory_info;
@ -996,8 +1001,9 @@ bool AtomBrowserClient::WillCreateURLLoaderFactory(
header_client_request = mojo::MakeRequest(header_client); header_client_request = mojo::MakeRequest(header_client);
new ProxyingURLLoaderFactory( new ProxyingURLLoaderFactory(
protocol->intercept_handlers(), std::move(proxied_receiver), web_request.get(), protocol->intercept_handlers(), render_process_id,
std::move(target_factory_info), std::move(header_client_request)); std::move(proxied_receiver), std::move(target_factory_info),
std::move(header_client_request));
if (bypass_redirect_checks) if (bypass_redirect_checks)
*bypass_redirect_checks = true; *bypass_redirect_checks = true;

View file

@ -6,6 +6,7 @@
#include <utility> #include <utility>
#include "extensions/browser/extension_navigation_ui_data.h"
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
#include "net/base/completion_repeating_callback.h" #include "net/base/completion_repeating_callback.h"
#include "net/http/http_util.h" #include "net/http/http_util.h"
@ -57,7 +58,9 @@ ProxyingURLLoaderFactory::InProgressRequest::InProgressRequest(
network::URLLoaderCompletionStatus(net::ERR_ABORTED))); network::URLLoaderCompletionStatus(net::ERR_ABORTED)));
} }
ProxyingURLLoaderFactory::InProgressRequest::~InProgressRequest() {} ProxyingURLLoaderFactory::InProgressRequest::~InProgressRequest() {
// TODO(zcbenz): Do cleanup here.
}
void ProxyingURLLoaderFactory::InProgressRequest::Restart() { void ProxyingURLLoaderFactory::InProgressRequest::Restart() {
UpdateRequestInfo(); UpdateRequestInfo();
@ -65,13 +68,27 @@ void ProxyingURLLoaderFactory::InProgressRequest::Restart() {
} }
void ProxyingURLLoaderFactory::InProgressRequest::UpdateRequestInfo() { void ProxyingURLLoaderFactory::InProgressRequest::UpdateRequestInfo() {
// Derive a new WebRequestInfo value any time |Restart()| is called, because
// the details in |request_| may have changed e.g. if we've been redirected.
// |request_initiator| can be modified on redirects, but we keep the original
// for |initiator| in the event. See also
// https://developer.chrome.com/extensions/webRequest#event-onBeforeRequest.
network::ResourceRequest request_for_info = request_;
request_for_info.request_initiator = original_initiator_;
info_.emplace(extensions::WebRequestInfoInitParams(
request_id_, factory_->render_process_id_, request_.render_frame_id,
nullptr, routing_id_, request_for_info, false,
!(options_ & network::mojom::kURLLoadOptionSynchronous)));
current_request_uses_header_client_ = current_request_uses_header_client_ =
factory_->url_loader_header_client_binding_ && factory_->url_loader_header_client_binding_ &&
network_service_request_id_ != 0 && network_service_request_id_ != 0 &&
false /* HasExtraHeadersListenerForRequest */; false /* TODO(zcbenz): HasExtraHeadersListenerForRequest */;
} }
void ProxyingURLLoaderFactory::InProgressRequest::RestartInternal() { void ProxyingURLLoaderFactory::InProgressRequest::RestartInternal() {
DCHECK_EQ(info_->url, request_.url)
<< "UpdateRequestInfo must have been called first";
request_completed_ = false; request_completed_ = false;
// If the header client will be used, we start the request immediately, and // If the header client will be used, we start the request immediately, and
@ -87,8 +104,8 @@ void ProxyingURLLoaderFactory::InProgressRequest::RestartInternal() {
weak_factory_.GetWeakPtr()); weak_factory_.GetWeakPtr());
} }
redirect_url_ = GURL(); redirect_url_ = GURL();
// TODO(zcbenz): Call webRequest.onBeforeRequest. int result = factory_->web_request_api()->OnBeforeRequest(
int result = net::OK; &info_.value(), continuation, &redirect_url_);
if (result == net::ERR_BLOCKED_BY_CLIENT) { if (result == net::ERR_BLOCKED_BY_CLIENT) {
// The request was cancelled synchronously. Dispatch an error notification // The request was cancelled synchronously. Dispatch an error notification
// and terminate the request. // and terminate the request.
@ -242,7 +259,7 @@ void ProxyingURLLoaderFactory::InProgressRequest::OnComplete(
} }
target_client_->OnComplete(status); target_client_->OnComplete(status);
// TODO(zcbenz): Call webRequest.onCompleted. factory_->web_request_api()->OnCompleted(&info_.value(), status.error_code);
// Deletes |this|. // Deletes |this|.
factory_->RemoveRequest(network_service_request_id_, request_id_); factory_->RemoveRequest(network_service_request_id_, request_id_);
@ -300,8 +317,8 @@ void ProxyingURLLoaderFactory::InProgressRequest::ContinueToBeforeSendHeaders(
auto continuation = base::BindRepeating( auto continuation = base::BindRepeating(
&InProgressRequest::ContinueToSendHeaders, weak_factory_.GetWeakPtr()); &InProgressRequest::ContinueToSendHeaders, weak_factory_.GetWeakPtr());
// Note: In Electron onBeforeSendHeaders is called for all protocols. // Note: In Electron onBeforeSendHeaders is called for all protocols.
// TODO(zcbenz): Call webRequest.onBeforeSendHeaders. int result = factory_->web_request_api()->OnBeforeSendHeaders(
int result = net::OK; &info_.value(), continuation, &request_.headers);
if (result == net::ERR_BLOCKED_BY_CLIENT) { if (result == net::ERR_BLOCKED_BY_CLIENT) {
// The request was cancelled synchronously. Dispatch an error notification // The request was cancelled synchronously. Dispatch an error notification
@ -368,7 +385,7 @@ void ProxyingURLLoaderFactory::InProgressRequest::ContinueToSendHeaders(
proxied_client_binding_.ResumeIncomingMethodCallProcessing(); proxied_client_binding_.ResumeIncomingMethodCallProcessing();
// Note: In Electron onSendHeaders is called for all protocols. // Note: In Electron onSendHeaders is called for all protocols.
// TODO(zcbenz): Call webRequest.onSendHeaders. factory_->web_request_api()->OnSendHeaders(&info_.value(), request_.headers);
if (!current_request_uses_header_client_) if (!current_request_uses_header_client_)
ContinueToStartRequest(net::OK); ContinueToStartRequest(net::OK);
@ -477,9 +494,11 @@ void ProxyingURLLoaderFactory::InProgressRequest::ContinueToResponseStarted(
return; return;
} }
info_->AddResponseInfoFromResourceResponse(current_response_);
proxied_client_binding_.ResumeIncomingMethodCallProcessing(); proxied_client_binding_.ResumeIncomingMethodCallProcessing();
// TODO(zcbenz): Call webRequest.onResponseStarted. factory_->web_request_api()->OnResponseStarted(&info_.value());
target_client_->OnReceiveResponse(current_response_); target_client_->OnReceiveResponse(current_response_);
} }
@ -491,10 +510,13 @@ void ProxyingURLLoaderFactory::InProgressRequest::ContinueToBeforeRedirect(
return; return;
} }
info_->AddResponseInfoFromResourceResponse(current_response_);
if (proxied_client_binding_.is_bound()) if (proxied_client_binding_.is_bound())
proxied_client_binding_.ResumeIncomingMethodCallProcessing(); proxied_client_binding_.ResumeIncomingMethodCallProcessing();
// TODO(zcbenz): Call WebRequest.onBeforeRedirect. factory_->web_request_api()->OnBeforeRedirect(&info_.value(),
redirect_info.new_url);
target_client_->OnReceiveRedirect(redirect_info, current_response_); target_client_->OnReceiveRedirect(redirect_info, current_response_);
request_.url = redirect_info.new_url; request_.url = redirect_info.new_url;
request_.method = redirect_info.new_method; request_.method = redirect_info.new_method;
@ -586,8 +608,10 @@ void ProxyingURLLoaderFactory::InProgressRequest::
net::CompletionRepeatingCallback copyable_callback = net::CompletionRepeatingCallback copyable_callback =
base::AdaptCallbackForRepeating(std::move(continuation)); base::AdaptCallbackForRepeating(std::move(continuation));
// TODO(zcbenz): Call webRequest.onHeadersReceived. DCHECK(info_.has_value());
int result = net::OK; int result = factory_->web_request_api()->OnHeadersReceived(
&info_.value(), copyable_callback, current_response_.headers.get(),
&override_headers_, &redirect_url_);
if (result == net::ERR_BLOCKED_BY_CLIENT) { if (result == net::ERR_BLOCKED_BY_CLIENT) {
OnRequestError(network::URLLoaderCompletionStatus(result)); OnRequestError(network::URLLoaderCompletionStatus(result));
return; return;
@ -612,19 +636,24 @@ void ProxyingURLLoaderFactory::InProgressRequest::OnRequestError(
const network::URLLoaderCompletionStatus& status) { const network::URLLoaderCompletionStatus& status) {
if (!request_completed_) { if (!request_completed_) {
target_client_->OnComplete(status); target_client_->OnComplete(status);
// TODO(zcbenz): Call webRequest.onErrorOccurred. factory_->web_request_api()->OnErrorOccurred(&info_.value(),
status.error_code);
} }
// TODO(zcbenz): Disassociate from factory. // Deletes |this|.
delete this; factory_->RemoveRequest(network_service_request_id_, request_id_);
} }
ProxyingURLLoaderFactory::ProxyingURLLoaderFactory( ProxyingURLLoaderFactory::ProxyingURLLoaderFactory(
WebRequestAPI* web_request_api,
const HandlersMap& intercepted_handlers, const HandlersMap& intercepted_handlers,
int render_process_id,
network::mojom::URLLoaderFactoryRequest loader_request, network::mojom::URLLoaderFactoryRequest loader_request,
network::mojom::URLLoaderFactoryPtrInfo target_factory_info, network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
network::mojom::TrustedURLLoaderHeaderClientRequest header_client_request) network::mojom::TrustedURLLoaderHeaderClientRequest header_client_request)
: intercepted_handlers_(intercepted_handlers), : web_request_api_(web_request_api),
intercepted_handlers_(intercepted_handlers),
render_process_id_(render_process_id),
url_loader_header_client_binding_(this) { url_loader_header_client_binding_(this) {
target_factory_.Bind(std::move(target_factory_info)); target_factory_.Bind(std::move(target_factory_info));
target_factory_.set_connection_error_handler(base::BindOnce( target_factory_.set_connection_error_handler(base::BindOnce(

View file

@ -12,6 +12,7 @@
#include <vector> #include <vector>
#include "base/optional.h" #include "base/optional.h"
#include "extensions/browser/api/web_request/web_request_info.h"
#include "services/network/public/cpp/resource_request.h" #include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/resource_response.h" #include "services/network/public/cpp/resource_response.h"
#include "services/network/public/mojom/network_context.mojom.h" #include "services/network/public/mojom/network_context.mojom.h"
@ -20,6 +21,39 @@
namespace electron { namespace electron {
// Defines the interface for WebRequest API, implemented by api::WebRequestNS.
class WebRequestAPI {
public:
virtual ~WebRequestAPI() {}
using BeforeSendHeadersCallback =
base::OnceCallback<void(const std::set<std::string>& removed_headers,
const std::set<std::string>& set_headers,
int error_code)>;
virtual int OnBeforeRequest(extensions::WebRequestInfo* request,
net::CompletionOnceCallback callback,
GURL* new_url) = 0;
virtual int OnBeforeSendHeaders(extensions::WebRequestInfo* request,
BeforeSendHeadersCallback callback,
net::HttpRequestHeaders* headers) = 0;
virtual int OnHeadersReceived(
extensions::WebRequestInfo* request,
net::CompletionOnceCallback callback,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
GURL* allowed_unsafe_redirect_url) = 0;
virtual void OnSendHeaders(extensions::WebRequestInfo* request,
const net::HttpRequestHeaders& headers) = 0;
virtual void OnBeforeRedirect(extensions::WebRequestInfo* request,
const GURL& new_location) = 0;
virtual void OnResponseStarted(extensions::WebRequestInfo* request) = 0;
virtual void OnErrorOccurred(extensions::WebRequestInfo* request,
int net_error) = 0;
virtual void OnCompleted(extensions::WebRequestInfo* request,
int net_error) = 0;
};
// This class is responsible for following tasks when NetworkService is enabled: // This class is responsible for following tasks when NetworkService is enabled:
// 1. handling intercepted protocols; // 1. handling intercepted protocols;
// 2. implementing webRequest module; // 2. implementing webRequest module;
@ -108,6 +142,8 @@ class ProxyingURLLoaderFactory
mojo::Binding<network::mojom::URLLoader> proxied_loader_binding_; mojo::Binding<network::mojom::URLLoader> proxied_loader_binding_;
network::mojom::URLLoaderClientPtr target_client_; network::mojom::URLLoaderClientPtr target_client_;
base::Optional<extensions::WebRequestInfo> info_;
network::ResourceResponseHead current_response_; network::ResourceResponseHead current_response_;
scoped_refptr<net::HttpResponseHeaders> override_headers_; scoped_refptr<net::HttpResponseHeaders> override_headers_;
GURL redirect_url_; GURL redirect_url_;
@ -150,7 +186,9 @@ class ProxyingURLLoaderFactory
}; };
ProxyingURLLoaderFactory( ProxyingURLLoaderFactory(
WebRequestAPI* web_request_api,
const HandlersMap& intercepted_handlers, const HandlersMap& intercepted_handlers,
int render_process_id,
network::mojom::URLLoaderFactoryRequest loader_request, network::mojom::URLLoaderFactoryRequest loader_request,
network::mojom::URLLoaderFactoryPtrInfo target_factory_info, network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
network::mojom::TrustedURLLoaderHeaderClientRequest network::mojom::TrustedURLLoaderHeaderClientRequest
@ -173,12 +211,17 @@ class ProxyingURLLoaderFactory
int32_t request_id, int32_t request_id,
network::mojom::TrustedHeaderClientRequest request) override; network::mojom::TrustedHeaderClientRequest request) override;
WebRequestAPI* web_request_api() { return web_request_api_; }
private: private:
void OnTargetFactoryError(); void OnTargetFactoryError();
void OnProxyBindingError(); void OnProxyBindingError();
void RemoveRequest(int32_t network_service_request_id, uint64_t request_id); void RemoveRequest(int32_t network_service_request_id, uint64_t request_id);
void MaybeDeleteThis(); void MaybeDeleteThis();
// Passed from api::WebRequestNS.
WebRequestAPI* web_request_api_;
// This is passed from api::ProtocolNS. // This is passed from api::ProtocolNS.
// //
// The ProtocolNS instance lives through the lifetime of BrowserContenxt, // The ProtocolNS instance lives through the lifetime of BrowserContenxt,
@ -188,6 +231,7 @@ class ProxyingURLLoaderFactory
// In this way we can avoid using code from api namespace in this file. // In this way we can avoid using code from api namespace in this file.
const HandlersMap& intercepted_handlers_; const HandlersMap& intercepted_handlers_;
const int render_process_id_;
mojo::BindingSet<network::mojom::URLLoaderFactory> proxy_bindings_; mojo::BindingSet<network::mojom::URLLoaderFactory> proxy_bindings_;
network::mojom::URLLoaderFactoryPtr target_factory_; network::mojom::URLLoaderFactoryPtr target_factory_;
mojo::Binding<network::mojom::TrustedURLLoaderHeaderClient> mojo::Binding<network::mojom::TrustedURLLoaderHeaderClient>