feat: add protocol.handle (#36674)
This commit is contained in:
parent
6a6908c4c8
commit
fda8ea9277
25 changed files with 1254 additions and 89 deletions
|
@ -273,9 +273,17 @@ gin::Handle<Protocol> Protocol::Create(
|
|||
isolate, new Protocol(isolate, browser_context->protocol_registry()));
|
||||
}
|
||||
|
||||
gin::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return gin::Wrappable<Protocol>::GetObjectTemplateBuilder(isolate)
|
||||
// static
|
||||
gin::Handle<Protocol> Protocol::New(gin_helper::ErrorThrower thrower) {
|
||||
thrower.ThrowError("Protocol cannot be created from JS");
|
||||
return gin::Handle<Protocol>();
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::ObjectTemplate> Protocol::FillObjectTemplate(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> tmpl) {
|
||||
return gin::ObjectTemplateBuilder(isolate, "Protocol", tmpl)
|
||||
.SetMethod("registerStringProtocol",
|
||||
&Protocol::RegisterProtocolFor<ProtocolType::kString>)
|
||||
.SetMethod("registerBufferProtocol",
|
||||
|
@ -304,7 +312,8 @@ gin::ObjectTemplateBuilder Protocol::GetObjectTemplateBuilder(
|
|||
.SetMethod("interceptProtocol",
|
||||
&Protocol::InterceptProtocolFor<ProtocolType::kFree>)
|
||||
.SetMethod("uninterceptProtocol", &Protocol::UninterceptProtocol)
|
||||
.SetMethod("isProtocolIntercepted", &Protocol::IsProtocolIntercepted);
|
||||
.SetMethod("isProtocolIntercepted", &Protocol::IsProtocolIntercepted)
|
||||
.Build();
|
||||
}
|
||||
|
||||
const char* Protocol::GetTypeName() {
|
||||
|
@ -333,6 +342,7 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||
void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.Set("Protocol", electron::api::Protocol::GetConstructor(context));
|
||||
dict.SetMethod("registerSchemesAsPrivileged", &RegisterSchemesAsPrivileged);
|
||||
dict.SetMethod("getStandardSchemes", &electron::api::GetStandardSchemes);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "gin/handle.h"
|
||||
#include "gin/wrappable.h"
|
||||
#include "shell/browser/net/electron_url_loader_factory.h"
|
||||
#include "shell/common/gin_helper/constructible.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
|
@ -37,15 +38,19 @@ enum class ProtocolError {
|
|||
};
|
||||
|
||||
// Protocol implementation based on network services.
|
||||
class Protocol : public gin::Wrappable<Protocol> {
|
||||
class Protocol : public gin::Wrappable<Protocol>,
|
||||
public gin_helper::Constructible<Protocol> {
|
||||
public:
|
||||
static gin::Handle<Protocol> Create(v8::Isolate* isolate,
|
||||
ElectronBrowserContext* browser_context);
|
||||
|
||||
static gin::Handle<Protocol> New(gin_helper::ErrorThrower thrower);
|
||||
|
||||
// gin::Wrappable
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
static v8::Local<v8::ObjectTemplate> FillObjectTemplate(
|
||||
v8::Isolate* isolate,
|
||||
v8::Local<v8::ObjectTemplate> tmpl);
|
||||
const char* GetTypeName() override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "shell/browser/electron_browser_context.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/browser/net/asar/asar_url_loader_factory.h"
|
||||
#include "shell/browser/net/proxying_url_loader_factory.h"
|
||||
#include "shell/browser/protocol_registry.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_converters/gurl_converter.h"
|
||||
|
@ -488,7 +489,10 @@ SimpleURLLoaderWrapper::GetURLLoaderFactoryForURL(const GURL& url) {
|
|||
// Explicitly handle intercepted protocols here, even though
|
||||
// ProxyingURLLoaderFactory would handle them later on, so that we can
|
||||
// correctly intercept file:// scheme URLs.
|
||||
if (protocol_registry->IsProtocolIntercepted(url.scheme())) {
|
||||
bool bypass_custom_protocol_handlers =
|
||||
request_options_ & kBypassCustomProtocolHandlers;
|
||||
if (!bypass_custom_protocol_handlers &&
|
||||
protocol_registry->IsProtocolIntercepted(url.scheme())) {
|
||||
auto& protocol_handler =
|
||||
protocol_registry->intercept_handlers().at(url.scheme());
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote =
|
||||
|
@ -497,7 +501,8 @@ SimpleURLLoaderWrapper::GetURLLoaderFactoryForURL(const GURL& url) {
|
|||
url_loader_factory = network::SharedURLLoaderFactory::Create(
|
||||
std::make_unique<network::WrapperPendingSharedURLLoaderFactory>(
|
||||
std::move(pending_remote)));
|
||||
} else if (protocol_registry->IsProtocolRegistered(url.scheme())) {
|
||||
} else if (!bypass_custom_protocol_handlers &&
|
||||
protocol_registry->IsProtocolRegistered(url.scheme())) {
|
||||
auto& protocol_handler = protocol_registry->handlers().at(url.scheme());
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote =
|
||||
ElectronURLLoaderFactory::Create(protocol_handler.first,
|
||||
|
@ -528,6 +533,10 @@ gin::Handle<SimpleURLLoaderWrapper> SimpleURLLoaderWrapper::Create(
|
|||
auto request = std::make_unique<network::ResourceRequest>();
|
||||
opts.Get("method", &request->method);
|
||||
opts.Get("url", &request->url);
|
||||
if (!request->url.is_valid()) {
|
||||
args->ThrowTypeError("Invalid URL");
|
||||
return gin::Handle<SimpleURLLoaderWrapper>();
|
||||
}
|
||||
request->site_for_cookies = net::SiteForCookies::FromUrl(request->url);
|
||||
opts.Get("referrer", &request->referrer);
|
||||
request->referrer_policy =
|
||||
|
@ -648,7 +657,7 @@ gin::Handle<SimpleURLLoaderWrapper> SimpleURLLoaderWrapper::Create(
|
|||
|
||||
bool use_session_cookies = false;
|
||||
opts.Get("useSessionCookies", &use_session_cookies);
|
||||
int options = 0;
|
||||
int options = network::mojom::kURLLoadOptionSniffMimeType;
|
||||
if (!credentials_specified && !use_session_cookies) {
|
||||
// This is the default case, as well as the case when credentials is not
|
||||
// specified and useSessionCookies is false. credentials_mode will be
|
||||
|
@ -657,6 +666,11 @@ gin::Handle<SimpleURLLoaderWrapper> SimpleURLLoaderWrapper::Create(
|
|||
options |= network::mojom::kURLLoadOptionBlockAllCookies;
|
||||
}
|
||||
|
||||
bool bypass_custom_protocol_handlers = false;
|
||||
opts.Get("bypassCustomProtocolHandlers", &bypass_custom_protocol_handlers);
|
||||
if (bypass_custom_protocol_handlers)
|
||||
options |= kBypassCustomProtocolHandlers;
|
||||
|
||||
v8::Local<v8::Value> body;
|
||||
v8::Local<v8::Value> chunk_pipe_getter;
|
||||
if (opts.Get("body", &body)) {
|
||||
|
@ -738,6 +752,7 @@ void SimpleURLLoaderWrapper::OnResponseStarted(
|
|||
dict.Set("httpVersion", response_head.headers->GetHttpVersion());
|
||||
dict.Set("headers", response_head.headers.get());
|
||||
dict.Set("rawHeaders", response_head.raw_response_headers);
|
||||
dict.Set("mimeType", response_head.mime_type);
|
||||
Emit("response-started", final_url, dict);
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,10 @@ void NodeStreamLoader::NotifyComplete(int result) {
|
|||
return;
|
||||
}
|
||||
|
||||
client_->OnComplete(network::URLLoaderCompletionStatus(result));
|
||||
network::URLLoaderCompletionStatus status(result);
|
||||
status.completion_time = base::TimeTicks::Now();
|
||||
status.decoded_body_length = bytes_written_;
|
||||
client_->OnComplete(status);
|
||||
delete this;
|
||||
}
|
||||
|
||||
|
@ -126,6 +129,8 @@ void NodeStreamLoader::ReadMore() {
|
|||
// Hold the buffer until the write is done.
|
||||
buffer_.Reset(isolate_, buffer);
|
||||
|
||||
bytes_written_ += node::Buffer::Length(buffer);
|
||||
|
||||
// Write buffer to mojo pipe asynchronously.
|
||||
is_reading_ = false;
|
||||
is_writing_ = true;
|
||||
|
|
|
@ -81,6 +81,8 @@ class NodeStreamLoader : public network::mojom::URLLoader {
|
|||
// Whether we are in the middle of a stream.read().
|
||||
bool is_reading_ = false;
|
||||
|
||||
size_t bytes_written_ = 0;
|
||||
|
||||
// When NotifyComplete is called while writing, we will save the result and
|
||||
// quit with it after the write is done.
|
||||
bool ended_ = false;
|
||||
|
|
|
@ -806,18 +806,23 @@ void ProxyingURLLoaderFactory::CreateLoaderAndStart(
|
|||
}
|
||||
|
||||
// Check if user has intercepted this scheme.
|
||||
auto it = intercepted_handlers_.find(request.url.scheme());
|
||||
if (it != intercepted_handlers_.end()) {
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> loader_remote;
|
||||
this->Clone(loader_remote.InitWithNewPipeAndPassReceiver());
|
||||
bool bypass_custom_protocol_handlers =
|
||||
options & kBypassCustomProtocolHandlers;
|
||||
if (!bypass_custom_protocol_handlers) {
|
||||
auto it = intercepted_handlers_.find(request.url.scheme());
|
||||
if (it != intercepted_handlers_.end()) {
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory> loader_remote;
|
||||
this->Clone(loader_remote.InitWithNewPipeAndPassReceiver());
|
||||
|
||||
// <scheme, <type, handler>>
|
||||
it->second.second.Run(
|
||||
request, base::BindOnce(&ElectronURLLoaderFactory::StartLoading,
|
||||
std::move(loader), request_id, options, request,
|
||||
std::move(client), traffic_annotation,
|
||||
std::move(loader_remote), it->second.first));
|
||||
return;
|
||||
// <scheme, <type, handler>>
|
||||
it->second.second.Run(
|
||||
request,
|
||||
base::BindOnce(&ElectronURLLoaderFactory::StartLoading,
|
||||
std::move(loader), request_id, options, request,
|
||||
std::move(client), traffic_annotation,
|
||||
std::move(loader_remote), it->second.first));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The loader of ServiceWorker forbids loading scripts from file:// URLs, and
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
namespace electron {
|
||||
|
||||
const uint32_t kBypassCustomProtocolHandlers = 1 << 30;
|
||||
|
||||
// This class is responsible for following tasks when NetworkService is enabled:
|
||||
// 1. handling intercepted protocols;
|
||||
// 2. implementing webRequest module;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue