mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
12 Commits
v9.0.0-nig
...
v9.0.0-nig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24d6743d57 | ||
|
|
fbc3bb872b | ||
|
|
46c12308cd | ||
|
|
26ecf63ab4 | ||
|
|
4f1536479e | ||
|
|
878ab916d2 | ||
|
|
b02a20e4dc | ||
|
|
af1e8a347e | ||
|
|
457b7bf24f | ||
|
|
97e2569f02 | ||
|
|
ba85d4c3bb | ||
|
|
98844c20a7 |
@@ -1 +1 @@
|
||||
9.0.0-nightly.20191113
|
||||
9.0.0-nightly.20191116
|
||||
@@ -32,6 +32,8 @@ static_library("chrome") {
|
||||
"//chrome/browser/icon_loader_win.cc",
|
||||
"//chrome/browser/icon_manager.cc",
|
||||
"//chrome/browser/icon_manager.h",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm",
|
||||
"//chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc",
|
||||
"//chrome/browser/net/chrome_mojo_proxy_resolver_factory.h",
|
||||
"//chrome/browser/net/proxy_config_monitor.cc",
|
||||
|
||||
@@ -323,8 +323,8 @@ Returns:
|
||||
* `port` Integer
|
||||
* `realm` String
|
||||
* `callback` Function
|
||||
* `username` String
|
||||
* `password` String
|
||||
* `username` String (optional)
|
||||
* `password` String (optional)
|
||||
|
||||
Emitted when `webContents` wants to do basic auth.
|
||||
|
||||
@@ -341,6 +341,10 @@ app.on('login', (event, webContents, details, authInfo, callback) => {
|
||||
})
|
||||
```
|
||||
|
||||
If `callback` is called without a username or password, the authentication
|
||||
request will be cancelled and the authentication error will be returned to the
|
||||
page.
|
||||
|
||||
### Event: 'gpu-info-update'
|
||||
|
||||
Emitted whenever there is a GPU info update.
|
||||
|
||||
@@ -158,7 +158,7 @@ const idleTime = getSystemIdleTime()
|
||||
### webFrame Isolated World APIs
|
||||
|
||||
```js
|
||||
// Removed in Elecron 7.0
|
||||
// Removed in Electron 7.0
|
||||
webFrame.setIsolatedWorldContentSecurityPolicy(worldId, csp)
|
||||
webFrame.setIsolatedWorldHumanReadableName(worldId, name)
|
||||
webFrame.setIsolatedWorldSecurityOrigin(worldId, securityOrigin)
|
||||
@@ -176,6 +176,39 @@ webFrame.setIsolatedWorldInfo(
|
||||
|
||||
This property was removed in Chromium 77, and as such is no longer available.
|
||||
|
||||
### `webkitdirectory` attribute for `<input type="file"/>`
|
||||
|
||||
The `webkitdirectory` property on HTML file inputs allows them to select folders.
|
||||
Previous versions of Electron had an incorrect implementation where the `event.target.files`
|
||||
of the input returned a `FileList` that returned one `File` corresponding to the selected folder.
|
||||
|
||||
As of Electron 7, that `FileList` is now list of all files contained within
|
||||
the folder, similarly to Chrome, Firefox, and Edge
|
||||
([link to MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory)).
|
||||
|
||||
As an illustration, take a folder with this structure:
|
||||
```console
|
||||
folder
|
||||
├── file1
|
||||
├── file2
|
||||
└── file3
|
||||
```
|
||||
|
||||
In Electron <=6, this would return a `FileList` with a `File` object for:
|
||||
```console
|
||||
path/to/folder
|
||||
```
|
||||
|
||||
In Electron 7, this now returns a `FileList` with a `File` object for:
|
||||
```console
|
||||
/path/to/folder/file3
|
||||
/path/to/folder/file2
|
||||
/path/to/folder/file1
|
||||
```
|
||||
|
||||
Note that `webkitdirectory` no longer exposes the path to the selected folder.
|
||||
If you require the path to the selected folder rather than the folder contents,
|
||||
see the `dialog.showOpenDialog` API ([link](https://github.com/electron/electron/blob/master/docs/api/dialog.md#dialogshowopendialogbrowserwindow-options)).
|
||||
## Planned Breaking API Changes (6.0)
|
||||
|
||||
### `win.setMenu(null)`
|
||||
|
||||
@@ -70,8 +70,8 @@ Returns:
|
||||
* `port` Integer
|
||||
* `realm` String
|
||||
* `callback` Function
|
||||
* `username` String
|
||||
* `password` String
|
||||
* `username` String (optional)
|
||||
* `password` String (optional)
|
||||
|
||||
Emitted when an authenticating proxy is asking for user credentials.
|
||||
|
||||
|
||||
@@ -91,7 +91,11 @@ The `desktopCapturer` module has the following methods:
|
||||
|
||||
Returns `Promise<DesktopCapturerSource[]>` - Resolves with an array of [`DesktopCapturerSource`](structures/desktop-capturer-source.md) objects, each `DesktopCapturerSource` represents a screen or an individual window that can be captured.
|
||||
|
||||
**Note** Capturing the screen contents requires user consent on macOS 10.15 Catalina or higher,
|
||||
which can detected by [`systemPreferences.getMediaAccessStatus`].
|
||||
|
||||
[`navigator.mediaDevices.getUserMedia`]: https://developer.mozilla.org/en/docs/Web/API/MediaDevices/getUserMedia
|
||||
[`systemPreferences.getMediaAccessStatus`]: system-preferences.md#systempreferencesgetmediaaccessstatusmediatype-macos
|
||||
|
||||
## Caveats
|
||||
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
## Promisification
|
||||
|
||||
The Electron team is currently undergoing an initiative to convert callback-based functions in Electron to return Promises. During this transition period, both the callback and Promise-based versions of these functions will work correctly, and will both be documented.
|
||||
|
||||
To enable deprecation warnings for these updated functions, use the [`process.enablePromiseAPIs` runtime flag](../process.md#processenablepromiseapis).
|
||||
|
||||
When a majority of affected functions are migrated, this flag will be enabled by default and all developers will be able to see these deprecation warnings. At that time, the callback-based versions will also be removed from documentation. This document will be continuously updated as more functions are converted.
|
||||
|
||||
### Candidate Functions
|
||||
|
||||
- [app.importCertificate(options, callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#importCertificate)
|
||||
- [contents.print([options], [callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#print)
|
||||
|
||||
### Converted Functions
|
||||
The Electron team recently underwent an initiative to convert callback-based APIs to Promise-based ones. See converted functions below:
|
||||
|
||||
- [app.getFileIcon(path[, options], callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#getFileIcon)
|
||||
- [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage)
|
||||
|
||||
@@ -82,12 +82,6 @@ A `Boolean` that controls whether or not deprecation warnings are printed to `st
|
||||
Setting this to `true` will silence deprecation warnings. This property is used
|
||||
instead of the `--no-deprecation` command line flag.
|
||||
|
||||
### `process.enablePromiseAPIs`
|
||||
|
||||
A `Boolean` that controls whether or not deprecation warnings are printed to `stderr` when
|
||||
formerly callback-based APIs converted to Promises are invoked using callbacks. Setting this to `true`
|
||||
will enable deprecation warnings.
|
||||
|
||||
### `process.resourcesPath` _Readonly_
|
||||
|
||||
A `String` representing the path to the resources directory.
|
||||
|
||||
@@ -434,11 +434,13 @@ Returns `Boolean` - `true` if the current process is a trusted accessibility cli
|
||||
|
||||
### `systemPreferences.getMediaAccessStatus(mediaType)` _macOS_
|
||||
|
||||
* `mediaType` String - `microphone` or `camera`.
|
||||
* `mediaType` String - Can be `microphone`, `camera` or `screen`.
|
||||
|
||||
Returns `String` - Can be `not-determined`, `granted`, `denied`, `restricted` or `unknown`.
|
||||
|
||||
This user consent was not required until macOS 10.14 Mojave, so this method will always return `granted` if your system is running 10.13 High Sierra or lower.
|
||||
This user consent was not required on macOS 10.13 High Sierra or lower so this method will always return `granted`.
|
||||
macOS 10.14 Mojave or higher requires consent for `microphone` and `camera` access.
|
||||
macOS 10.15 Catalina or higher requires consent for `screen` access.
|
||||
|
||||
### `systemPreferences.askForMediaAccess(mediaType)` _macOS_
|
||||
|
||||
|
||||
@@ -463,8 +463,8 @@ Returns:
|
||||
* `port` Integer
|
||||
* `realm` String
|
||||
* `callback` Function
|
||||
* `username` String
|
||||
* `password` String
|
||||
* `username` String (optional)
|
||||
* `password` String (optional)
|
||||
|
||||
Emitted when `webContents` wants to do basic auth.
|
||||
|
||||
|
||||
@@ -247,22 +247,11 @@ class ClientRequest extends EventEmitter {
|
||||
})
|
||||
|
||||
urlRequest.on('login', (event, authInfo, callback) => {
|
||||
this.emit('login', authInfo, (username, password) => {
|
||||
// If null or undefined username/password, force to empty string.
|
||||
if (username === null || username === undefined) {
|
||||
username = ''
|
||||
}
|
||||
if (typeof username !== 'string') {
|
||||
throw new Error('username must be a string')
|
||||
}
|
||||
if (password === null || password === undefined) {
|
||||
password = ''
|
||||
}
|
||||
if (typeof password !== 'string') {
|
||||
throw new Error('password must be a string')
|
||||
}
|
||||
callback(username, password)
|
||||
})
|
||||
const handled = this.emit('login', authInfo, callback)
|
||||
if (!handled) {
|
||||
// If there were no listeners, cancel the authentication request.
|
||||
callback()
|
||||
}
|
||||
})
|
||||
|
||||
if (callback) {
|
||||
|
||||
@@ -116,64 +116,6 @@ const deprecate: ElectronInternal.DeprecationUtil = {
|
||||
})
|
||||
},
|
||||
|
||||
// deprecate a callback-based function in favor of one returning a Promise
|
||||
promisify: <T extends (...args: any[]) => any>(fn: T): T => {
|
||||
const fnName = fn.name || 'function'
|
||||
const oldName = `${fnName} with callbacks`
|
||||
const newName = `${fnName} with Promises`
|
||||
const warn = warnOnce(oldName, newName)
|
||||
|
||||
return function (this: any, ...params: any[]) {
|
||||
let cb: Function | undefined
|
||||
if (params.length > 0 && typeof params[params.length - 1] === 'function') {
|
||||
cb = params.pop()
|
||||
}
|
||||
const promise = fn.apply(this, params)
|
||||
if (!cb) return promise
|
||||
if (process.enablePromiseAPIs) warn()
|
||||
return promise
|
||||
.then((res: any) => {
|
||||
process.nextTick(() => {
|
||||
cb!.length === 2 ? cb!(null, res) : cb!(res)
|
||||
})
|
||||
return res
|
||||
}, (err: Error) => {
|
||||
process.nextTick(() => {
|
||||
cb!.length === 2 ? cb!(err) : cb!()
|
||||
})
|
||||
throw err
|
||||
})
|
||||
} as T
|
||||
},
|
||||
|
||||
// convertPromiseValue: Temporarily disabled until it's used
|
||||
// deprecate a callback-based function in favor of one returning a Promise
|
||||
promisifyMultiArg: <T extends (...args: any[]) => any>(fn: T /* convertPromiseValue: (v: any) => any */): T => {
|
||||
const fnName = fn.name || 'function'
|
||||
const oldName = `${fnName} with callbacks`
|
||||
const newName = `${fnName} with Promises`
|
||||
const warn = warnOnce(oldName, newName)
|
||||
|
||||
return function (this: any, ...params) {
|
||||
let cb: Function | undefined
|
||||
if (params.length > 0 && typeof params[params.length - 1] === 'function') {
|
||||
cb = params.pop()
|
||||
}
|
||||
const promise = fn.apply(this, params)
|
||||
if (!cb) return promise
|
||||
if (process.enablePromiseAPIs) warn()
|
||||
return promise
|
||||
.then((res: any) => {
|
||||
process.nextTick(() => {
|
||||
// eslint-disable-next-line standard/no-callback-literal
|
||||
cb!.length > 2 ? cb!(null, ...res) : cb!(...res)
|
||||
})
|
||||
}, (err: Error) => {
|
||||
process.nextTick(() => cb!(err))
|
||||
})
|
||||
} as T
|
||||
},
|
||||
|
||||
// change the name of a property
|
||||
renameProperty: (o, oldName, newName) => {
|
||||
const warn = warnOnce(oldName, newName)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "9.0.0-nightly.20191113",
|
||||
"version": "9.0.0-nightly.20191116",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -85,3 +85,5 @@ feat_unset_window_aspect_ratio_on_linux.patch
|
||||
fix_ambiguous_reference_to_data.patch
|
||||
backport_fix_msstl_compat_in_ui_events.patch
|
||||
build_win_fix_msstl_compatibility_for_pdf.patch
|
||||
fix_missing_algorithm_include.patch
|
||||
add_trustedauthclient_to_urlloaderfactory.patch
|
||||
|
||||
158
patches/chromium/add_trustedauthclient_to_urlloaderfactory.patch
Normal file
158
patches/chromium/add_trustedauthclient_to_urlloaderfactory.patch
Normal file
@@ -0,0 +1,158 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jeremy Apthorp <nornagon@nornagon.net>
|
||||
Date: Tue, 12 Nov 2019 11:50:16 -0800
|
||||
Subject: add TrustedAuthClient to URLLoaderFactory
|
||||
|
||||
This allows intercepting authentication requests for the 'net' module.
|
||||
Without this, the 'login' event for electron.net.ClientRequest can't be
|
||||
implemented, because the existing path checks for the presence of a
|
||||
WebContents, and cancels the authentication if there's no WebContents
|
||||
available, which there isn't in the case of the 'net' module.
|
||||
|
||||
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
|
||||
index 6b14d8354375377526e141ee499a7583be3f22b0..eeb9e19c0ecdf4631e596e7c0927693f2239f293 100644
|
||||
--- a/services/network/public/mojom/network_context.mojom
|
||||
+++ b/services/network/public/mojom/network_context.mojom
|
||||
@@ -181,6 +181,25 @@ interface TrustedURLLoaderHeaderClient {
|
||||
pending_receiver<TrustedHeaderClient> header_client);
|
||||
};
|
||||
|
||||
+interface TrustedAuthClient {
|
||||
+ OnAuthRequired(
|
||||
+ mojo_base.mojom.UnguessableToken? window_id,
|
||||
+ uint32 process_id,
|
||||
+ uint32 routing_id,
|
||||
+ uint32 request_id,
|
||||
+ url.mojom.Url url,
|
||||
+ bool first_auth_attempt,
|
||||
+ AuthChallengeInfo auth_info,
|
||||
+ URLResponseHead? head,
|
||||
+ pending_remote<AuthChallengeResponder> auth_challenge_responder);
|
||||
+};
|
||||
+interface TrustedURLLoaderAuthClient {
|
||||
+ // When a new URLLoader is created, this will be called to pass a
|
||||
+ // corresponding |auth_client|.
|
||||
+ OnLoaderCreated(int32 request_id,
|
||||
+ pending_receiver<TrustedAuthClient> auth_client);
|
||||
+};
|
||||
+
|
||||
interface CertVerifierClient {
|
||||
Verify(
|
||||
int32 default_error,
|
||||
@@ -559,6 +578,8 @@ struct URLLoaderFactoryParams {
|
||||
// impact because of the extra process hops, so use should be minimized.
|
||||
pending_remote<TrustedURLLoaderHeaderClient>? header_client;
|
||||
|
||||
+ pending_remote<TrustedURLLoaderAuthClient>? auth_client;
|
||||
+
|
||||
// If non-empty array is given, |factory_bound_allow_patterns| is used for
|
||||
// CORS checks in addition to the per-context allow patterns that is managed
|
||||
// via NetworkContext interface. This still respects the per-context block
|
||||
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
|
||||
index d4e13ffaed76847b00cf98b248ba17ad70a9884c..33ab3ea9c60e097d8525f1066f3890a5bccd754a 100644
|
||||
--- a/services/network/url_loader.cc
|
||||
+++ b/services/network/url_loader.cc
|
||||
@@ -335,6 +335,7 @@ URLLoader::URLLoader(
|
||||
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder,
|
||||
base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator,
|
||||
mojom::TrustedURLLoaderHeaderClient* url_loader_header_client,
|
||||
+ mojom::TrustedURLLoaderAuthClient* url_loader_auth_client,
|
||||
mojom::OriginPolicyManager* origin_policy_manager)
|
||||
: url_request_context_(url_request_context),
|
||||
network_service_client_(network_service_client),
|
||||
@@ -391,6 +392,11 @@ URLLoader::URLLoader(
|
||||
header_client_.set_disconnect_handler(
|
||||
base::BindOnce(&URLLoader::OnConnectionError, base::Unretained(this)));
|
||||
}
|
||||
+ if (url_loader_auth_client) {
|
||||
+ url_loader_auth_client->OnLoaderCreated(request_id_, auth_client_.BindNewPipeAndPassReceiver());
|
||||
+ auth_client_.set_disconnect_handler(
|
||||
+ base::BindOnce(&URLLoader::OnConnectionError, base::Unretained(this)));
|
||||
+ }
|
||||
if (want_raw_headers_) {
|
||||
options_ |= mojom::kURLLoadOptionSendSSLInfoWithResponse |
|
||||
mojom::kURLLoadOptionSendSSLInfoForCertificateError;
|
||||
@@ -818,7 +824,7 @@ void URLLoader::OnReceivedRedirect(net::URLRequest* url_request,
|
||||
|
||||
void URLLoader::OnAuthRequired(net::URLRequest* url_request,
|
||||
const net::AuthChallengeInfo& auth_info) {
|
||||
- if (!network_context_client_) {
|
||||
+ if (!network_context_client_ && !auth_client_) {
|
||||
OnAuthCredentials(base::nullopt);
|
||||
return;
|
||||
}
|
||||
@@ -834,10 +840,18 @@ void URLLoader::OnAuthRequired(net::URLRequest* url_request,
|
||||
if (url_request->response_headers())
|
||||
head.headers = url_request->response_headers();
|
||||
head.auth_challenge_info = auth_info;
|
||||
- network_context_client_->OnAuthRequired(
|
||||
- fetch_window_id_, factory_params_->process_id, render_frame_id_,
|
||||
- request_id_, url_request_->url(), first_auth_attempt_, auth_info, head,
|
||||
- auth_challenge_responder_receiver_.BindNewPipeAndPassRemote());
|
||||
+
|
||||
+ if (auth_client_) {
|
||||
+ auth_client_->OnAuthRequired(
|
||||
+ fetch_window_id_, factory_params_->process_id, render_frame_id_,
|
||||
+ request_id_, url_request_->url(), first_auth_attempt_, auth_info, head,
|
||||
+ auth_challenge_responder_receiver_.BindNewPipeAndPassRemote());
|
||||
+ } else {
|
||||
+ network_context_client_->OnAuthRequired(
|
||||
+ fetch_window_id_, factory_params_->process_id, render_frame_id_,
|
||||
+ request_id_, url_request_->url(), first_auth_attempt_, auth_info, head,
|
||||
+ auth_challenge_responder_receiver_.BindNewPipeAndPassRemote());
|
||||
+ }
|
||||
|
||||
auth_challenge_responder_receiver_.set_disconnect_handler(
|
||||
base::BindOnce(&URLLoader::DeleteSelf, base::Unretained(this)));
|
||||
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
|
||||
index 0a47148a52a46f8a6f12f503731623f87e15b173..db8ca018c7e99a1a1acea156b4d49a755b93cc09 100644
|
||||
--- a/services/network/url_loader.h
|
||||
+++ b/services/network/url_loader.h
|
||||
@@ -85,6 +85,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
|
||||
base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder,
|
||||
base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator,
|
||||
mojom::TrustedURLLoaderHeaderClient* url_loader_header_client,
|
||||
+ mojom::TrustedURLLoaderAuthClient* url_loader_auth_client,
|
||||
mojom::OriginPolicyManager* origin_policy_manager);
|
||||
~URLLoader() override;
|
||||
|
||||
@@ -362,6 +363,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
|
||||
base::Optional<base::UnguessableToken> fetch_window_id_;
|
||||
|
||||
mojo::Remote<mojom::TrustedHeaderClient> header_client_;
|
||||
+ mojo::Remote<mojom::TrustedAuthClient> auth_client_;
|
||||
|
||||
std::unique_ptr<FileOpenerForUpload> file_opener_for_upload_;
|
||||
|
||||
diff --git a/services/network/url_loader_factory.cc b/services/network/url_loader_factory.cc
|
||||
index 7145e0e96550d554bb1df85bd79818ec9a45f7b1..53225eb1b0b7f1aa2498cecc8222f9f897ac364f 100644
|
||||
--- a/services/network/url_loader_factory.cc
|
||||
+++ b/services/network/url_loader_factory.cc
|
||||
@@ -65,6 +65,7 @@ URLLoaderFactory::URLLoaderFactory(
|
||||
params_(std::move(params)),
|
||||
resource_scheduler_client_(std::move(resource_scheduler_client)),
|
||||
header_client_(std::move(params_->header_client)),
|
||||
+ auth_client_(std::move(params_->auth_client)),
|
||||
cors_url_loader_factory_(cors_url_loader_factory) {
|
||||
DCHECK(context);
|
||||
DCHECK_NE(mojom::kInvalidProcessId, params_->process_id);
|
||||
@@ -209,6 +210,7 @@ void URLLoaderFactory::CreateLoaderAndStart(
|
||||
resource_scheduler_client_, std::move(keepalive_statistics_recorder),
|
||||
std::move(network_usage_accumulator),
|
||||
header_client_.is_bound() ? header_client_.get() : nullptr,
|
||||
+ auth_client_.is_bound() ? auth_client_.get() : nullptr,
|
||||
context_->origin_policy_manager());
|
||||
cors_url_loader_factory_->OnLoaderCreated(std::move(loader));
|
||||
}
|
||||
diff --git a/services/network/url_loader_factory.h b/services/network/url_loader_factory.h
|
||||
index 7b143aa49be833ddf05b7b99bea19ee0b674b79c..6d1fbca87e3827c953fdac2cfb96806114d8aea9 100644
|
||||
--- a/services/network/url_loader_factory.h
|
||||
+++ b/services/network/url_loader_factory.h
|
||||
@@ -71,6 +71,7 @@ class URLLoaderFactory : public mojom::URLLoaderFactory {
|
||||
mojom::URLLoaderFactoryParamsPtr params_;
|
||||
scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
|
||||
mojo::Remote<mojom::TrustedURLLoaderHeaderClient> header_client_;
|
||||
+ mojo::Remote<mojom::TrustedURLLoaderAuthClient> auth_client_;
|
||||
|
||||
// |cors_url_loader_factory_| owns this.
|
||||
cors::CorsURLLoaderFactory* cors_url_loader_factory_;
|
||||
@@ -7,7 +7,7 @@ Electron has exposed methods to allow setting the aspect ratio
|
||||
for a given window, and as a part of that needed to allow users to
|
||||
reset the aspect ratio. On macOS, we can do this with existing APIs,
|
||||
but on Linux this was not possible using currently exposed APIs without
|
||||
this patch.
|
||||
this patch.
|
||||
|
||||
Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/1895789.
|
||||
|
||||
|
||||
76
patches/chromium/fix_missing_algorithm_include.patch
Normal file
76
patches/chromium/fix_missing_algorithm_include.patch
Normal file
@@ -0,0 +1,76 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Thu, 7 Nov 2019 16:49:03 -0800
|
||||
Subject: fix: missing algorithm include
|
||||
|
||||
This file had an include-what-you-use issue leading to release build
|
||||
failures, as it was unable to find max in the std namespace.
|
||||
|
||||
Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/1904823.
|
||||
|
||||
diff --git a/media/base/byte_queue.cc b/media/base/byte_queue.cc
|
||||
index 245fafa668568fd308e5a2806dafc1c5f0bf3dbd..f9cd0c214ac6210d4332bad47b56ef8130be67a2 100644
|
||||
--- a/media/base/byte_queue.cc
|
||||
+++ b/media/base/byte_queue.cc
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "media/base/byte_queue.h"
|
||||
|
||||
+#include <algorithm>
|
||||
+
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/checked_math.h"
|
||||
|
||||
diff --git a/third_party/blink/public/platform/web_time_range.h b/third_party/blink/public/platform/web_time_range.h
|
||||
index 2c17f7c8ce58f1255994e9e6fd74f70fa1a22b1c..4b0a59bf3308b49d2c4ffd86120759417094cb21 100644
|
||||
--- a/third_party/blink/public/platform/web_time_range.h
|
||||
+++ b/third_party/blink/public/platform/web_time_range.h
|
||||
@@ -31,6 +31,8 @@
|
||||
#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_TIME_RANGE_H_
|
||||
#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_TIME_RANGE_H_
|
||||
|
||||
+#include <algorithm>
|
||||
+
|
||||
#include "third_party/blink/public/platform/web_vector.h"
|
||||
|
||||
namespace blink {
|
||||
diff --git a/third_party/blink/renderer/core/layout/min_max_size.h b/third_party/blink/renderer/core/layout/min_max_size.h
|
||||
index c3fdbde6e4bf585351b3fc8d0ce2bd2673a82b5e..4233e6c79a1d67dd6c1ca33929d0beedbf9a1116 100644
|
||||
--- a/third_party/blink/renderer/core/layout/min_max_size.h
|
||||
+++ b/third_party/blink/renderer/core/layout/min_max_size.h
|
||||
@@ -5,6 +5,8 @@
|
||||
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_MIN_MAX_SIZE_H_
|
||||
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_MIN_MAX_SIZE_H_
|
||||
|
||||
+#include <algorithm>
|
||||
+
|
||||
#include "third_party/blink/renderer/core/core_export.h"
|
||||
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h
|
||||
index 50f699428acf8251f14411dc30caa750cfac88bf..8236afa14ee99b5f61e6c785721abf62299cbaed 100644
|
||||
--- a/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h
|
||||
+++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h
|
||||
@@ -5,6 +5,8 @@
|
||||
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GEOMETRY_NG_MARGIN_STRUT_H_
|
||||
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_GEOMETRY_NG_MARGIN_STRUT_H_
|
||||
|
||||
+#include <algorithm>
|
||||
+
|
||||
#include "third_party/blink/renderer/core/core_export.h"
|
||||
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/style/style_difference.h b/third_party/blink/renderer/core/style/style_difference.h
|
||||
index 91292961f1f02e53c58653f72297ea05d78fc07b..517fbb8f5a7aa549373e3806aaec4b3d1f0ec13f 100644
|
||||
--- a/third_party/blink/renderer/core/style/style_difference.h
|
||||
+++ b/third_party/blink/renderer/core/style/style_difference.h
|
||||
@@ -5,7 +5,9 @@
|
||||
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_DIFFERENCE_H_
|
||||
#define THIRD_PARTY_BLINK_RENDERER_CORE_STYLE_STYLE_DIFFERENCE_H_
|
||||
|
||||
+#include <algorithm>
|
||||
#include <iosfwd>
|
||||
+
|
||||
#include "third_party/blink/renderer/core/core_export.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
|
||||
#include "third_party/blink/renderer/platform/wtf/assertions.h"
|
||||
@@ -1,7 +1,6 @@
|
||||
add_realloc.patch
|
||||
build_gn.patch
|
||||
expose_mksnapshot.patch
|
||||
deps_provide_more_v8_backwards_compatibility.patch
|
||||
dcheck.patch
|
||||
export_symbols_needed_for_windows_build.patch
|
||||
workaround_an_undefined_symbol_error.patch
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Anna Henningsen <anna@addaleax.net>
|
||||
Date: Fri, 28 Sep 2018 22:43:38 -0400
|
||||
Subject: deps: provide more V8 backwards compatibility
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add back a number deprecated APIs, using shims that
|
||||
should work well enough at least for the duration of Node 11
|
||||
and do not come with significant maintenance overhead.
|
||||
|
||||
Refs: https://github.com/nodejs/node/issues/23122
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/23158
|
||||
Reviewed-By: Rich Trott <rtrott@gmail.com>
|
||||
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
|
||||
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
|
||||
Reviewed-By: James M Snell <jasnell@gmail.com>
|
||||
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
|
||||
Reviewed-By: Yang Guo <yangguo@chromium.org>
|
||||
Reviewed-By: Michaël Zasso <targos@protonmail.com>
|
||||
|
||||
diff --git a/include/v8.h b/include/v8.h
|
||||
index fe86e1a17f2cad844ef92f45a8da6e7fee4eba49..3450677471b7276b631ea12a4cd39514c8105b46 100644
|
||||
--- a/include/v8.h
|
||||
+++ b/include/v8.h
|
||||
@@ -1330,6 +1330,10 @@ class V8_EXPORT PrimitiveArray {
|
||||
public:
|
||||
static Local<PrimitiveArray> New(Isolate* isolate, int length);
|
||||
int Length() const;
|
||||
+ V8_DEPRECATED("Use Isolate* version")
|
||||
+ void Set(int index, Local<Primitive> item);
|
||||
+ V8_DEPRECATED("Use Isolate* version")
|
||||
+ Local<Primitive> Get(int index);
|
||||
void Set(Isolate* isolate, int index, Local<Primitive> item);
|
||||
Local<Primitive> Get(Isolate* isolate, int index);
|
||||
};
|
||||
@@ -2078,6 +2082,8 @@ class V8_EXPORT StackTrace {
|
||||
/**
|
||||
* Returns a StackFrame at a particular index.
|
||||
*/
|
||||
+ V8_DEPRECATED("Use Isolate version")
|
||||
+ Local<StackFrame> GetFrame(uint32_t index) const;
|
||||
Local<StackFrame> GetFrame(Isolate* isolate, uint32_t index) const;
|
||||
|
||||
/**
|
||||
@@ -2774,6 +2780,15 @@ class V8_EXPORT Value : public Data {
|
||||
|
||||
Local<Boolean> ToBoolean(Isolate* isolate) const;
|
||||
|
||||
+ V8_DEPRECATED("Use maybe version")
|
||||
+ inline Local<Boolean> ToBoolean() const;
|
||||
+ V8_DEPRECATED("Use maybe version")
|
||||
+ inline Local<String> ToString() const;
|
||||
+ V8_DEPRECATED("Use maybe version")
|
||||
+ inline Local<Object> ToObject() const;
|
||||
+ V8_DEPRECATED("Use maybe version")
|
||||
+ inline Local<Integer> ToInteger() const;
|
||||
+
|
||||
/**
|
||||
* Attempts to convert a string to an array index.
|
||||
* Returns an empty handle if the conversion fails.
|
||||
@@ -2790,7 +2805,14 @@ class V8_EXPORT Value : public Data {
|
||||
Local<Context> context) const;
|
||||
V8_WARN_UNUSED_RESULT Maybe<int32_t> Int32Value(Local<Context> context) const;
|
||||
|
||||
+ V8_DEPRECATED("Use maybe version") bool BooleanValue() const;
|
||||
+ V8_DEPRECATED("Use maybe version") double NumberValue() const;
|
||||
+ V8_DEPRECATED("Use maybe version") int64_t IntegerValue() const;
|
||||
+ V8_DEPRECATED("Use maybe version") uint32_t Uint32Value() const;
|
||||
+ V8_DEPRECATED("Use maybe version") int32_t Int32Value() const;
|
||||
+
|
||||
/** JS == */
|
||||
+ V8_DEPRECATED("Use maybe version") bool Equals(Local<Value> that) const;
|
||||
V8_WARN_UNUSED_RESULT Maybe<bool> Equals(Local<Context> context,
|
||||
Local<Value> that) const;
|
||||
bool StrictEquals(Local<Value> that) const;
|
||||
@@ -2897,6 +2919,8 @@ class V8_EXPORT String : public Name {
|
||||
* Returns the number of bytes in the UTF-8 encoded
|
||||
* representation of this string.
|
||||
*/
|
||||
+ V8_DEPRECATED("Use Isolate version instead") int Utf8Length() const;
|
||||
+
|
||||
int Utf8Length(Isolate* isolate) const;
|
||||
|
||||
/**
|
||||
@@ -2953,12 +2977,22 @@ class V8_EXPORT String : public Name {
|
||||
// 16-bit character codes.
|
||||
int Write(Isolate* isolate, uint16_t* buffer, int start = 0, int length = -1,
|
||||
int options = NO_OPTIONS) const;
|
||||
+ V8_DEPRECATED("Use Isolate* version")
|
||||
+ int Write(uint16_t* buffer, int start = 0, int length = -1,
|
||||
+ int options = NO_OPTIONS) const;
|
||||
// One byte characters.
|
||||
int WriteOneByte(Isolate* isolate, uint8_t* buffer, int start = 0,
|
||||
int length = -1, int options = NO_OPTIONS) const;
|
||||
+ V8_DEPRECATED("Use Isolate* version")
|
||||
+ int WriteOneByte(uint8_t* buffer, int start = 0,
|
||||
+ int length = -1, int options = NO_OPTIONS) const;
|
||||
// UTF-8 encoded characters.
|
||||
int WriteUtf8(Isolate* isolate, char* buffer, int length = -1,
|
||||
int* nchars_ref = nullptr, int options = NO_OPTIONS) const;
|
||||
+ V8_DEPRECATED("Use Isolate* version")
|
||||
+ int WriteUtf8(char* buffer, int length = -1,
|
||||
+ int* nchars_ref = nullptr,
|
||||
+ int options = NO_OPTIONS) const;
|
||||
|
||||
/**
|
||||
* A zero length string.
|
||||
@@ -3126,6 +3160,8 @@ class V8_EXPORT String : public Name {
|
||||
*/
|
||||
static Local<String> Concat(Isolate* isolate, Local<String> left,
|
||||
Local<String> right);
|
||||
+ V8_DEPRECATED("Use Isolate* version")
|
||||
+ static Local<String> Concat(Local<String> left, Local<String> right);
|
||||
|
||||
/**
|
||||
* Creates a new external string using the data defined in the given
|
||||
@@ -3190,6 +3226,8 @@ class V8_EXPORT String : public Name {
|
||||
*/
|
||||
class V8_EXPORT Utf8Value {
|
||||
public:
|
||||
+ V8_DEPRECATED("Use Isolate version")
|
||||
+ explicit Utf8Value(Local<v8::Value> obj);
|
||||
Utf8Value(Isolate* isolate, Local<v8::Value> obj);
|
||||
~Utf8Value();
|
||||
char* operator*() { return str_; }
|
||||
@@ -3213,6 +3251,8 @@ class V8_EXPORT String : public Name {
|
||||
*/
|
||||
class V8_EXPORT Value {
|
||||
public:
|
||||
+ V8_DEPRECATED("Use Isolate version")
|
||||
+ explicit Value(Local<v8::Value> obj);
|
||||
Value(Isolate* isolate, Local<v8::Value> obj);
|
||||
~Value();
|
||||
uint16_t* operator*() { return str_; }
|
||||
@@ -5689,6 +5729,8 @@ class V8_EXPORT BooleanObject : public Object {
|
||||
class V8_EXPORT StringObject : public Object {
|
||||
public:
|
||||
static Local<Value> New(Isolate* isolate, Local<String> value);
|
||||
+ V8_DEPRECATED("Use Isolate* version")
|
||||
+ static Local<Value> New(Local<String> value);
|
||||
|
||||
Local<String> ValueOf() const;
|
||||
|
||||
@@ -11131,6 +11173,29 @@ template <class T> Value* Value::Cast(T* value) {
|
||||
}
|
||||
|
||||
|
||||
+Local<Boolean> Value::ToBoolean() const {
|
||||
+ return ToBoolean(Isolate::GetCurrent());
|
||||
+}
|
||||
+
|
||||
+
|
||||
+Local<String> Value::ToString() const {
|
||||
+ return ToString(Isolate::GetCurrent()->GetCurrentContext())
|
||||
+ .FromMaybe(Local<String>());
|
||||
+}
|
||||
+
|
||||
+
|
||||
+Local<Object> Value::ToObject() const {
|
||||
+ return ToObject(Isolate::GetCurrent()->GetCurrentContext())
|
||||
+ .FromMaybe(Local<Object>());
|
||||
+}
|
||||
+
|
||||
+
|
||||
+Local<Integer> Value::ToInteger() const {
|
||||
+ return ToInteger(Isolate::GetCurrent()->GetCurrentContext())
|
||||
+ .FromMaybe(Local<Integer>());
|
||||
+}
|
||||
+
|
||||
+
|
||||
Boolean* Boolean::Cast(v8::Value* value) {
|
||||
#ifdef V8_ENABLE_CHECKS
|
||||
CheckCast(value);
|
||||
diff --git a/src/api/api.cc b/src/api/api.cc
|
||||
index f6f2ba988d95660637f6733dafdd12db7acaa992..d753abd5d2d7e788b7dd96a200d5be0d85f87fe3 100644
|
||||
--- a/src/api/api.cc
|
||||
+++ b/src/api/api.cc
|
||||
@@ -2199,6 +2199,10 @@ int PrimitiveArray::Length() const {
|
||||
return array->length();
|
||||
}
|
||||
|
||||
+void PrimitiveArray::Set(int index, Local<Primitive> item) {
|
||||
+ return Set(Isolate::GetCurrent(), index, item);
|
||||
+}
|
||||
+
|
||||
void PrimitiveArray::Set(Isolate* v8_isolate, int index,
|
||||
Local<Primitive> item) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
|
||||
@@ -2212,6 +2216,10 @@ void PrimitiveArray::Set(Isolate* v8_isolate, int index,
|
||||
array->set(index, *i_item);
|
||||
}
|
||||
|
||||
+Local<Primitive> PrimitiveArray::Get(int index) {
|
||||
+ return Get(Isolate::GetCurrent(), index);
|
||||
+}
|
||||
+
|
||||
Local<Primitive> PrimitiveArray::Get(Isolate* v8_isolate, int index) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
|
||||
i::Handle<i::FixedArray> array = Utils::OpenHandle(this);
|
||||
@@ -2975,6 +2983,10 @@ void Message::PrintCurrentStackTrace(Isolate* isolate, FILE* out) {
|
||||
|
||||
// --- S t a c k T r a c e ---
|
||||
|
||||
+Local<StackFrame> StackTrace::GetFrame(uint32_t index) const {
|
||||
+ return GetFrame(Isolate::GetCurrent(), index);
|
||||
+}
|
||||
+
|
||||
Local<StackFrame> StackTrace::GetFrame(Isolate* v8_isolate,
|
||||
uint32_t index) const {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
|
||||
@@ -3562,6 +3574,34 @@ MaybeLocal<BigInt> Value::ToBigInt(Local<Context> context) const {
|
||||
RETURN_ESCAPED(result);
|
||||
}
|
||||
|
||||
+bool Value::BooleanValue() const {
|
||||
+ return BooleanValue(Isolate::GetCurrent());
|
||||
+}
|
||||
+
|
||||
+
|
||||
+double Value::NumberValue() const {
|
||||
+ return NumberValue(Isolate::GetCurrent()->GetCurrentContext())
|
||||
+ .FromMaybe(std::numeric_limits<double>::quiet_NaN());
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int64_t Value::IntegerValue() const {
|
||||
+ return NumberValue(Isolate::GetCurrent()->GetCurrentContext())
|
||||
+ .FromMaybe(0);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+uint32_t Value::Uint32Value() const {
|
||||
+ return Uint32Value(Isolate::GetCurrent()->GetCurrentContext())
|
||||
+ .FromMaybe(0);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int32_t Value::Int32Value() const {
|
||||
+ return Int32Value(Isolate::GetCurrent()->GetCurrentContext())
|
||||
+ .FromMaybe(0);
|
||||
+}
|
||||
+
|
||||
bool Value::BooleanValue(Isolate* v8_isolate) const {
|
||||
return Utils::OpenHandle(this)->BooleanValue(
|
||||
reinterpret_cast<i::Isolate*>(v8_isolate));
|
||||
@@ -3951,6 +3991,11 @@ MaybeLocal<Uint32> Value::ToArrayIndex(Local<Context> context) const {
|
||||
return Local<Uint32>();
|
||||
}
|
||||
|
||||
+bool Value::Equals(Local<Value> that) const {
|
||||
+ return Equals(Isolate::GetCurrent()->GetCurrentContext(), that)
|
||||
+ .FromMaybe(false);
|
||||
+}
|
||||
+
|
||||
Maybe<bool> Value::Equals(Local<Context> context, Local<Value> that) const {
|
||||
i::Isolate* isolate = Utils::OpenHandle(*context)->GetIsolate();
|
||||
auto self = Utils::OpenHandle(this);
|
||||
@@ -5168,6 +5213,10 @@ bool String::ContainsOnlyOneByte() const {
|
||||
return helper.Check(*str);
|
||||
}
|
||||
|
||||
+int String::Utf8Length() const {
|
||||
+ return Utf8Length(Isolate::GetCurrent());
|
||||
+}
|
||||
+
|
||||
int String::Utf8Length(Isolate* isolate) const {
|
||||
i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
str = i::String::Flatten(reinterpret_cast<i::Isolate*>(isolate), str);
|
||||
@@ -5320,6 +5369,14 @@ static int WriteUtf8Impl(i::Vector<const Char> string, char* write_start,
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
+
|
||||
+int String::WriteUtf8(char* buffer, int capacity,
|
||||
+ int* nchars_ref, int options) const {
|
||||
+ return WriteUtf8(Isolate::GetCurrent(),
|
||||
+ buffer, capacity, nchars_ref, options);
|
||||
+}
|
||||
+
|
||||
+
|
||||
int String::WriteUtf8(Isolate* v8_isolate, char* buffer, int capacity,
|
||||
int* nchars_ref, int options) const {
|
||||
i::Handle<i::String> str = Utils::OpenHandle(this);
|
||||
@@ -5358,6 +5415,17 @@ static inline int WriteHelper(i::Isolate* isolate, const String* string,
|
||||
return end - start;
|
||||
}
|
||||
|
||||
+int String::WriteOneByte(uint8_t* buffer, int start,
|
||||
+ int length, int options) const {
|
||||
+ return WriteOneByte(Isolate::GetCurrent(), buffer, start, length, options);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int String::Write(uint16_t* buffer, int start, int length,
|
||||
+ int options) const {
|
||||
+ return Write(Isolate::GetCurrent(), buffer, start, length, options);
|
||||
+}
|
||||
+
|
||||
int String::WriteOneByte(Isolate* isolate, uint8_t* buffer, int start,
|
||||
int length, int options) const {
|
||||
return WriteHelper(reinterpret_cast<i::Isolate*>(isolate), this, buffer,
|
||||
@@ -6269,6 +6337,11 @@ MaybeLocal<String> String::NewFromTwoByte(Isolate* isolate,
|
||||
return result;
|
||||
}
|
||||
|
||||
+Local<String> v8::String::Concat(Local<String> left,
|
||||
+ Local<String> right) {
|
||||
+ return Concat(Isolate::GetCurrent(), left, right);
|
||||
+}
|
||||
+
|
||||
Local<String> v8::String::Concat(Isolate* v8_isolate, Local<String> left,
|
||||
Local<String> right) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
|
||||
@@ -6539,6 +6612,10 @@ bool v8::BooleanObject::ValueOf() const {
|
||||
return js_primitive_wrapper->value().IsTrue(isolate);
|
||||
}
|
||||
|
||||
+Local<v8::Value> v8::StringObject::New(Local<String> value) {
|
||||
+ return New(Isolate::GetCurrent(), value);
|
||||
+}
|
||||
+
|
||||
Local<v8::Value> v8::StringObject::New(Isolate* v8_isolate,
|
||||
Local<String> value) {
|
||||
i::Handle<i::String> string = Utils::OpenHandle(*value);
|
||||
@@ -9078,6 +9155,9 @@ bool MicrotasksScope::IsRunningMicrotasks(Isolate* v8_isolate) {
|
||||
return microtask_queue->IsRunningMicrotasks();
|
||||
}
|
||||
|
||||
+String::Utf8Value::Utf8Value(v8::Local<v8::Value> obj)
|
||||
+ : Utf8Value(Isolate::GetCurrent(), obj) {}
|
||||
+
|
||||
String::Utf8Value::Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> obj)
|
||||
: str_(nullptr), length_(0) {
|
||||
if (obj.IsEmpty()) return;
|
||||
@@ -9095,6 +9175,9 @@ String::Utf8Value::Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> obj)
|
||||
|
||||
String::Utf8Value::~Utf8Value() { i::DeleteArray(str_); }
|
||||
|
||||
+String::Value::Value(v8::Local<v8::Value> obj)
|
||||
+ : Value(Isolate::GetCurrent(), obj) {}
|
||||
+
|
||||
String::Value::Value(v8::Isolate* isolate, v8::Local<v8::Value> obj)
|
||||
: str_(nullptr), length_(0) {
|
||||
if (obj.IsEmpty()) return;
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/threading/sequenced_task_runner_handle.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
|
||||
#include "net/base/mac/url_conversions.h"
|
||||
#include "shell/browser/mac/atom_application.h"
|
||||
#include "shell/browser/mac/dict_util.h"
|
||||
@@ -103,6 +104,23 @@ AVMediaType ParseMediaType(const std::string& media_type) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string ConvertSystemPermission(
|
||||
system_media_permissions::SystemPermission value) {
|
||||
using SystemPermission = system_media_permissions::SystemPermission;
|
||||
switch (value) {
|
||||
case SystemPermission::kNotDetermined:
|
||||
return "not-determined";
|
||||
case SystemPermission::kRestricted:
|
||||
return "restricted";
|
||||
case SystemPermission::kDenied:
|
||||
return "denied";
|
||||
case SystemPermission::kAllowed:
|
||||
return "granted";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void SystemPreferences::PostNotification(const std::string& name,
|
||||
@@ -574,24 +592,15 @@ std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower,
|
||||
std::string SystemPreferences::GetMediaAccessStatus(
|
||||
const std::string& media_type,
|
||||
gin_helper::Arguments* args) {
|
||||
if (auto type = ParseMediaType(media_type)) {
|
||||
if (@available(macOS 10.14, *)) {
|
||||
switch ([AVCaptureDevice authorizationStatusForMediaType:type]) {
|
||||
case AVAuthorizationStatusNotDetermined:
|
||||
return "not-determined";
|
||||
case AVAuthorizationStatusRestricted:
|
||||
return "restricted";
|
||||
case AVAuthorizationStatusDenied:
|
||||
return "denied";
|
||||
case AVAuthorizationStatusAuthorized:
|
||||
return "granted";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
} else {
|
||||
// access always allowed pre-10.14 Mojave
|
||||
return "granted";
|
||||
}
|
||||
if (media_type == "camera") {
|
||||
return ConvertSystemPermission(
|
||||
system_media_permissions::CheckSystemVideoCapturePermission());
|
||||
} else if (media_type == "microphone") {
|
||||
return ConvertSystemPermission(
|
||||
system_media_permissions::CheckSystemAudioCapturePermission());
|
||||
} else if (media_type == "screen") {
|
||||
return ConvertSystemPermission(
|
||||
system_media_permissions::CheckSystemScreenCapturePermission());
|
||||
} else {
|
||||
args->ThrowError("Invalid media type");
|
||||
return std::string();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/containers/id_map.h"
|
||||
#include "gin/handle.h"
|
||||
#include "mojo/public/cpp/bindings/receiver_set.h"
|
||||
#include "mojo/public/cpp/system/string_data_source.h"
|
||||
@@ -13,6 +14,7 @@
|
||||
#include "services/network/public/mojom/chunked_data_pipe_getter.mojom.h"
|
||||
#include "shell/browser/api/atom_api_session.h"
|
||||
#include "shell/browser/atom_browser_context.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_converters/gurl_converter.h"
|
||||
#include "shell/common/gin_converters/net_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
@@ -51,6 +53,11 @@ namespace api {
|
||||
|
||||
namespace {
|
||||
|
||||
base::IDMap<URLRequest*>& GetAllRequests() {
|
||||
static base::NoDestructor<base::IDMap<URLRequest*>> s_all_requests;
|
||||
return *s_all_requests;
|
||||
}
|
||||
|
||||
// Network state for request and response.
|
||||
enum State {
|
||||
STATE_STARTED = 1 << 0,
|
||||
@@ -166,7 +173,9 @@ class ChunkedDataPipeGetter : public UploadDataPipeGetter,
|
||||
mojo::ReceiverSet<network::mojom::ChunkedDataPipeGetter> receiver_set_;
|
||||
};
|
||||
|
||||
URLRequest::URLRequest(gin::Arguments* args) : weak_factory_(this) {
|
||||
URLRequest::URLRequest(gin::Arguments* args)
|
||||
: id_(GetAllRequests().Add(this)), weak_factory_(this) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
request_ = std::make_unique<network::ResourceRequest>();
|
||||
gin_helper::Dictionary dict;
|
||||
if (args->GetNext(&dict)) {
|
||||
@@ -176,6 +185,8 @@ URLRequest::URLRequest(gin::Arguments* args) : weak_factory_(this) {
|
||||
request_->redirect_mode = redirect_mode_;
|
||||
}
|
||||
|
||||
request_->render_frame_id = id_;
|
||||
|
||||
std::string partition;
|
||||
gin::Handle<api::Session> session;
|
||||
if (!dict.Get("session", &session)) {
|
||||
@@ -192,6 +203,38 @@ URLRequest::URLRequest(gin::Arguments* args) : weak_factory_(this) {
|
||||
|
||||
URLRequest::~URLRequest() = default;
|
||||
|
||||
URLRequest* URLRequest::FromID(uint32_t id) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
return GetAllRequests().Lookup(id);
|
||||
}
|
||||
|
||||
void URLRequest::OnAuthRequired(
|
||||
const GURL& url,
|
||||
bool first_auth_attempt,
|
||||
net::AuthChallengeInfo auth_info,
|
||||
network::mojom::URLResponseHeadPtr head,
|
||||
mojo::PendingRemote<network::mojom::AuthChallengeResponder>
|
||||
auth_challenge_responder) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
mojo::Remote<network::mojom::AuthChallengeResponder> auth_responder(
|
||||
std::move(auth_challenge_responder));
|
||||
auth_responder.set_disconnect_handler(
|
||||
base::BindOnce(&URLRequest::Cancel, weak_factory_.GetWeakPtr()));
|
||||
auto cb = base::BindOnce(
|
||||
[](mojo::Remote<network::mojom::AuthChallengeResponder> auth_responder,
|
||||
gin::Arguments* args) {
|
||||
base::string16 username_str, password_str;
|
||||
if (!args->GetNext(&username_str) || !args->GetNext(&password_str)) {
|
||||
auth_responder->OnAuthCredentials(base::nullopt);
|
||||
return;
|
||||
}
|
||||
auth_responder->OnAuthCredentials(
|
||||
net::AuthCredentials(username_str, password_str));
|
||||
},
|
||||
std::move(auth_responder));
|
||||
Emit("login", auth_info, base::AdaptCallbackForRepeating(std::move(cb)));
|
||||
}
|
||||
|
||||
bool URLRequest::NotStarted() const {
|
||||
return request_state_ == 0;
|
||||
}
|
||||
@@ -512,11 +555,12 @@ void URLRequest::EmitError(EventType type, base::StringPiece message) {
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void URLRequest::EmitEvent(EventType type, Args... args) {
|
||||
void URLRequest::EmitEvent(EventType type, Args&&... args) {
|
||||
const char* method =
|
||||
type == EventType::kRequest ? "_emitRequestEvent" : "_emitResponseEvent";
|
||||
v8::HandleScope handle_scope(isolate());
|
||||
gin_helper::CustomEmit(isolate(), GetWrapper(), method, args...);
|
||||
gin_helper::CustomEmit(isolate(), GetWrapper(), method,
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// static
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "services/network/public/cpp/simple_url_loader.h"
|
||||
#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
|
||||
#include "services/network/public/mojom/data_pipe_getter.mojom.h"
|
||||
#include "services/network/public/mojom/network_context.mojom.h"
|
||||
#include "shell/common/gin_helper/event_emitter.h"
|
||||
|
||||
namespace electron {
|
||||
@@ -32,6 +33,15 @@ class URLRequest : public gin_helper::EventEmitter<URLRequest>,
|
||||
|
||||
static void BuildPrototype(v8::Isolate* isolate,
|
||||
v8::Local<v8::FunctionTemplate> prototype);
|
||||
static URLRequest* FromID(uint32_t id);
|
||||
|
||||
void OnAuthRequired(
|
||||
const GURL& url,
|
||||
bool first_auth_attempt,
|
||||
net::AuthChallengeInfo auth_info,
|
||||
network::mojom::URLResponseHeadPtr head,
|
||||
mojo::PendingRemote<network::mojom::AuthChallengeResponder>
|
||||
auth_challenge_responder);
|
||||
|
||||
protected:
|
||||
explicit URLRequest(gin::Arguments* args);
|
||||
@@ -89,7 +99,7 @@ class URLRequest : public gin_helper::EventEmitter<URLRequest>,
|
||||
};
|
||||
void EmitError(EventType type, base::StringPiece error);
|
||||
template <typename... Args>
|
||||
void EmitEvent(EventType type, Args... args);
|
||||
void EmitEvent(EventType type, Args&&... args);
|
||||
|
||||
std::unique_ptr<network::ResourceRequest> request_;
|
||||
std::unique_ptr<network::SimpleURLLoader> loader_;
|
||||
@@ -132,6 +142,8 @@ class URLRequest : public gin_helper::EventEmitter<URLRequest>,
|
||||
// Used by pin/unpin to manage lifetime.
|
||||
v8::Global<v8::Object> wrapper_;
|
||||
|
||||
uint32_t id_;
|
||||
|
||||
base::WeakPtrFactory<URLRequest> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(URLRequest);
|
||||
|
||||
@@ -332,6 +332,10 @@ void WebRequest::OnCompleted(extensions::WebRequestInfo* info,
|
||||
HandleSimpleEvent(kOnCompleted, info, request, net_error);
|
||||
}
|
||||
|
||||
void WebRequest::OnRequestWillBeDestroyed(extensions::WebRequestInfo* info) {
|
||||
callbacks_.erase(info->id);
|
||||
}
|
||||
|
||||
template <WebRequest::SimpleEvent event>
|
||||
void WebRequest::SetSimpleListener(gin::Arguments* args) {
|
||||
SetListener<SimpleListener>(event, &simple_listeners_, args);
|
||||
|
||||
@@ -84,6 +84,7 @@ class WebRequest : public gin::Wrappable<WebRequest>, public WebRequestAPI {
|
||||
void OnCompleted(extensions::WebRequestInfo* info,
|
||||
const network::ResourceRequest& request,
|
||||
int net_error) override;
|
||||
void OnRequestWillBeDestroyed(extensions::WebRequestInfo* info) override;
|
||||
|
||||
enum SimpleEvent {
|
||||
kOnSendHeaders,
|
||||
|
||||
@@ -28,10 +28,12 @@
|
||||
#include "content/browser/blob_storage/chrome_blob_storage_context.h" // nogncheck
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/storage_partition.h"
|
||||
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "services/network/public/cpp/features.h"
|
||||
#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
|
||||
#include "services/network/public/mojom/network_context.mojom.h"
|
||||
#include "shell/browser/api/atom_api_url_request.h"
|
||||
#include "shell/browser/atom_browser_client.h"
|
||||
#include "shell/browser/atom_browser_main_parts.h"
|
||||
#include "shell/browser/atom_download_manager_delegate.h"
|
||||
@@ -325,6 +327,7 @@ AtomBrowserContext::GetURLLoaderFactory() {
|
||||
network::mojom::URLLoaderFactoryParamsPtr params =
|
||||
network::mojom::URLLoaderFactoryParams::New();
|
||||
params->header_client = std::move(header_client);
|
||||
params->auth_client = auth_client_.BindNewPipeAndPassRemote();
|
||||
params->process_id = network::mojom::kBrowserProcessId;
|
||||
params->is_trusted = true;
|
||||
params->is_corb_enabled = false;
|
||||
@@ -342,6 +345,39 @@ AtomBrowserContext::GetURLLoaderFactory() {
|
||||
return url_loader_factory_;
|
||||
}
|
||||
|
||||
class AuthResponder : public network::mojom::TrustedAuthClient {
|
||||
public:
|
||||
AuthResponder() {}
|
||||
~AuthResponder() override = default;
|
||||
|
||||
private:
|
||||
void OnAuthRequired(
|
||||
const base::Optional<::base::UnguessableToken>& window_id,
|
||||
uint32_t process_id,
|
||||
uint32_t routing_id,
|
||||
uint32_t request_id,
|
||||
const ::GURL& url,
|
||||
bool first_auth_attempt,
|
||||
const ::net::AuthChallengeInfo& auth_info,
|
||||
::network::mojom::URLResponseHeadPtr head,
|
||||
mojo::PendingRemote<network::mojom::AuthChallengeResponder>
|
||||
auth_challenge_responder) override {
|
||||
api::URLRequest* url_request = api::URLRequest::FromID(routing_id);
|
||||
if (url_request) {
|
||||
url_request->OnAuthRequired(url, first_auth_attempt, auth_info,
|
||||
std::move(head),
|
||||
std::move(auth_challenge_responder));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AtomBrowserContext::OnLoaderCreated(
|
||||
int32_t request_id,
|
||||
mojo::PendingReceiver<network::mojom::TrustedAuthClient> auth_client) {
|
||||
mojo::MakeSelfOwnedReceiver(std::make_unique<AuthResponder>(),
|
||||
std::move(auth_client));
|
||||
}
|
||||
|
||||
content::PushMessagingService* AtomBrowserContext::GetPushMessagingService() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "content/public/browser/browser_context.h"
|
||||
#include "content/public/browser/resource_context.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "services/network/public/mojom/network_context.mojom.h"
|
||||
#include "services/network/public/mojom/url_loader_factory.mojom.h"
|
||||
#include "shell/browser/media/media_device_id_salt.h"
|
||||
|
||||
@@ -50,7 +51,8 @@ class WebViewManager;
|
||||
|
||||
class AtomBrowserContext
|
||||
: public base::RefCountedDeleteOnSequence<AtomBrowserContext>,
|
||||
public content::BrowserContext {
|
||||
public content::BrowserContext,
|
||||
public network::mojom::TrustedURLLoaderAuthClient {
|
||||
public:
|
||||
// partition_id => browser_context
|
||||
struct PartitionKey {
|
||||
@@ -149,6 +151,10 @@ class AtomBrowserContext
|
||||
friend class base::RefCountedDeleteOnSequence<AtomBrowserContext>;
|
||||
friend class base::DeleteHelper<AtomBrowserContext>;
|
||||
|
||||
void OnLoaderCreated(int32_t request_id,
|
||||
mojo::PendingReceiver<network::mojom::TrustedAuthClient>
|
||||
header_client) override;
|
||||
|
||||
// Initialize pref registry.
|
||||
void InitPrefs();
|
||||
|
||||
@@ -185,6 +191,7 @@ class AtomBrowserContext
|
||||
|
||||
// Shared URLLoaderFactory.
|
||||
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
|
||||
mojo::Receiver<network::mojom::TrustedURLLoaderAuthClient> auth_client_{this};
|
||||
|
||||
base::WeakPtrFactory<AtomBrowserContext> weak_factory_;
|
||||
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "gin/arguments.h"
|
||||
#include "gin/dictionary.h"
|
||||
#include "shell/browser/api/atom_api_web_contents.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_converters/gurl_converter.h"
|
||||
#include "shell/common/gin_converters/net_converter.h"
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
|
||||
@@ -57,7 +60,7 @@ void LoginHandler::EmitEvent(
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
auto details = gin::Dictionary::CreateEmpty(isolate);
|
||||
details.Set("url", url.spec());
|
||||
details.Set("url", url);
|
||||
|
||||
// These parameters aren't documented, and I'm not sure that they're useful,
|
||||
// but we might as well stick 'em on the details object. If it turns out they
|
||||
@@ -70,17 +73,23 @@ void LoginHandler::EmitEvent(
|
||||
api_web_contents->Emit("login", std::move(details), auth_info,
|
||||
base::BindOnce(&LoginHandler::CallbackFromJS,
|
||||
weak_factory_.GetWeakPtr()));
|
||||
if (!default_prevented) {
|
||||
if (!default_prevented && auth_required_callback_) {
|
||||
std::move(auth_required_callback_).Run(base::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
LoginHandler::~LoginHandler() = default;
|
||||
|
||||
void LoginHandler::CallbackFromJS(base::string16 username,
|
||||
base::string16 password) {
|
||||
std::move(auth_required_callback_)
|
||||
.Run(net::AuthCredentials(username, password));
|
||||
void LoginHandler::CallbackFromJS(gin::Arguments* args) {
|
||||
if (auth_required_callback_) {
|
||||
base::string16 username, password;
|
||||
if (!args->GetNext(&username) || !args->GetNext(&password)) {
|
||||
std::move(auth_required_callback_).Run(base::nullopt);
|
||||
return;
|
||||
}
|
||||
std::move(auth_required_callback_)
|
||||
.Run(net::AuthCredentials(username, password));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#ifndef SHELL_BROWSER_LOGIN_HANDLER_H_
|
||||
#define SHELL_BROWSER_LOGIN_HANDLER_H_
|
||||
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/values.h"
|
||||
#include "content/public/browser/content_browser_client.h"
|
||||
#include "content/public/browser/login_delegate.h"
|
||||
@@ -15,6 +14,10 @@ namespace content {
|
||||
class WebContents;
|
||||
}
|
||||
|
||||
namespace gin {
|
||||
class Arguments;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
// Handles HTTP basic auth.
|
||||
@@ -36,7 +39,7 @@ class LoginHandler : public content::LoginDelegate,
|
||||
const GURL& url,
|
||||
scoped_refptr<net::HttpResponseHeaders> response_headers,
|
||||
bool first_auth_attempt);
|
||||
void CallbackFromJS(base::string16 username, base::string16 password);
|
||||
void CallbackFromJS(gin::Arguments* args);
|
||||
|
||||
LoginAuthRequiredCallback auth_required_callback_;
|
||||
|
||||
|
||||
@@ -345,39 +345,23 @@ bool NativeWindowViews::PreHandleMSG(UINT message,
|
||||
return false;
|
||||
}
|
||||
case WM_GETMINMAXINFO: {
|
||||
// We need to handle GETMINMAXINFO ourselves because chromium tries to
|
||||
// get the scale factor of the window during it's version of this handler
|
||||
// based on the window position, which is invalid at this point. The
|
||||
// previous method of calling SetWindowPlacement fixed the window
|
||||
// position for the scale factor calculation but broke other things.
|
||||
MINMAXINFO* info = reinterpret_cast<MINMAXINFO*>(l_param);
|
||||
WINDOWPLACEMENT wp;
|
||||
wp.length = sizeof(WINDOWPLACEMENT);
|
||||
|
||||
display::Display display =
|
||||
display::Screen::GetScreen()->GetDisplayNearestPoint(
|
||||
last_normal_placement_bounds_.origin());
|
||||
// We do this to work around a Windows bug, where the minimized Window
|
||||
// would report that the closest display to it is not the one that it was
|
||||
// previously on (but the leftmost one instead). We restore the position
|
||||
// of the window during the restore operation, this way chromium can
|
||||
// use the proper display to calculate the scale factor to use.
|
||||
if (!last_normal_placement_bounds_.IsEmpty() &&
|
||||
GetWindowPlacement(GetAcceleratedWidget(), &wp)) {
|
||||
wp.rcNormalPosition = last_normal_placement_bounds_.ToRECT();
|
||||
SetWindowPlacement(GetAcceleratedWidget(), &wp);
|
||||
|
||||
const gfx::Size widget_min_size = widget()->GetMinimumSize();
|
||||
const gfx::Size widget_max_size = widget()->GetMaximumSize();
|
||||
gfx::Size min_size = gfx::ScaleToCeiledSize(
|
||||
ContentBoundsToWindowBounds(gfx::Rect(widget_min_size)).size(),
|
||||
display.device_scale_factor());
|
||||
gfx::Size max_size = gfx::ScaleToCeiledSize(
|
||||
ContentBoundsToWindowBounds(gfx::Rect(widget_max_size)).size(),
|
||||
display.device_scale_factor());
|
||||
|
||||
info->ptMinTrackSize.x = min_size.width();
|
||||
info->ptMinTrackSize.y = min_size.height();
|
||||
if (widget_max_size.width() || widget_max_size.height()) {
|
||||
if (!max_size.width())
|
||||
max_size.set_width(GetSystemMetrics(SM_CXMAXTRACK));
|
||||
if (!max_size.height())
|
||||
max_size.set_height(GetSystemMetrics(SM_CYMAXTRACK));
|
||||
info->ptMaxTrackSize.x = max_size.width();
|
||||
info->ptMaxTrackSize.y = max_size.height();
|
||||
last_normal_placement_bounds_ = gfx::Rect();
|
||||
}
|
||||
|
||||
*result = 1;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
case WM_NCCALCSIZE: {
|
||||
if (!has_frame() && w_param == TRUE) {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/file_url_loader.h"
|
||||
#include "mojo/public/cpp/bindings/receiver.h"
|
||||
#include "mojo/public/cpp/bindings/strong_binding.h"
|
||||
#include "mojo/public/cpp/system/data_pipe_producer.h"
|
||||
#include "mojo/public/cpp/system/file_data_source.h"
|
||||
#include "net/base/filename_util.h"
|
||||
|
||||
@@ -49,9 +49,10 @@ ProxyingURLLoaderFactory::InProgressRequest::InProgressRequest(
|
||||
target_client_(std::move(client)),
|
||||
current_response_(network::mojom::URLResponseHead::New()),
|
||||
proxied_client_binding_(this),
|
||||
// TODO(zcbenz): We should always use "extraHeaders" mode to be compatible
|
||||
// with old APIs.
|
||||
has_any_extra_headers_listeners_(false) {
|
||||
// Always use "extraHeaders" mode to be compatible with old APIs, except
|
||||
// when the |request_id_| is zero, which is not supported in Chromium and
|
||||
// only happens in Electron when the request is started from net module.
|
||||
has_any_extra_headers_listeners_(network_service_request_id != 0) {
|
||||
// If there is a client error, clean up the request.
|
||||
target_client_.set_connection_error_handler(base::BindOnce(
|
||||
&ProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
|
||||
@@ -60,7 +61,19 @@ ProxyingURLLoaderFactory::InProgressRequest::InProgressRequest(
|
||||
}
|
||||
|
||||
ProxyingURLLoaderFactory::InProgressRequest::~InProgressRequest() {
|
||||
// TODO(zcbenz): Do cleanup here.
|
||||
// This is important to ensure that no outstanding blocking requests continue
|
||||
// to reference state owned by this object.
|
||||
if (info_) {
|
||||
factory_->web_request_api()->OnRequestWillBeDestroyed(&info_.value());
|
||||
}
|
||||
if (on_before_send_headers_callback_) {
|
||||
std::move(on_before_send_headers_callback_)
|
||||
.Run(net::ERR_ABORTED, base::nullopt);
|
||||
}
|
||||
if (on_headers_received_callback_) {
|
||||
std::move(on_headers_received_callback_)
|
||||
.Run(net::ERR_ABORTED, base::nullopt, base::nullopt);
|
||||
}
|
||||
}
|
||||
|
||||
void ProxyingURLLoaderFactory::InProgressRequest::Restart() {
|
||||
@@ -84,8 +97,7 @@ void ProxyingURLLoaderFactory::InProgressRequest::UpdateRequestInfo() {
|
||||
|
||||
current_request_uses_header_client_ =
|
||||
factory_->url_loader_header_client_receiver_.is_bound() &&
|
||||
network_service_request_id_ != 0 &&
|
||||
false /* TODO(zcbenz): HasExtraHeadersListenerForRequest */;
|
||||
network_service_request_id_ != 0 && has_any_extra_headers_listeners_;
|
||||
}
|
||||
|
||||
void ProxyingURLLoaderFactory::InProgressRequest::RestartInternal() {
|
||||
@@ -722,6 +734,10 @@ void ProxyingURLLoaderFactory::CreateLoaderAndStart(
|
||||
// don't use it for identity here.
|
||||
const uint64_t web_request_id = ++g_request_id;
|
||||
|
||||
// Notes: Chromium assumes that requests with zero-ID would never use the
|
||||
// "extraHeaders" code path, however in Electron requests started from
|
||||
// the net module would have zero-ID because they do not have renderer process
|
||||
// associated.
|
||||
if (request_id)
|
||||
network_request_id_to_web_request_id_.emplace(request_id, web_request_id);
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@ class WebRequestAPI {
|
||||
virtual void OnCompleted(extensions::WebRequestInfo* info,
|
||||
const network::ResourceRequest& request,
|
||||
int net_error) = 0;
|
||||
virtual void OnRequestWillBeDestroyed(extensions::WebRequestInfo* info) = 0;
|
||||
};
|
||||
|
||||
// This class is responsible for following tasks when NetworkService is enabled:
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 9,0,0,20191113
|
||||
PRODUCTVERSION 9,0,0,20191113
|
||||
FILEVERSION 9,0,0,20191116
|
||||
PRODUCTVERSION 9,0,0,20191116
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
||||
@@ -80,7 +80,12 @@ describe('BrowserWindow module', () => {
|
||||
})
|
||||
it('should emit beforeunload handler', async () => {
|
||||
await w.loadFile(path.join(fixtures, 'api', 'beforeunload-false.html'))
|
||||
const beforeunload = emittedOnce(w, 'onbeforeunload')
|
||||
const beforeunload = new Promise(resolve => {
|
||||
ipcMain.once('onbeforeunload', (e) => {
|
||||
e.returnValue = null
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
w.close()
|
||||
await beforeunload
|
||||
})
|
||||
@@ -164,8 +169,9 @@ describe('BrowserWindow module', () => {
|
||||
expect(content).to.equal('close')
|
||||
})
|
||||
it('should emit beforeunload event', async () => {
|
||||
w.loadFile(path.join(fixtures, 'api', 'close-beforeunload-false.html'))
|
||||
await emittedOnce(w, 'onbeforeunload')
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-false.html'))
|
||||
const [e] = await emittedOnce(ipcMain, 'onbeforeunload')
|
||||
e.returnValue = null
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1552,7 +1558,7 @@ describe('BrowserWindow module', () => {
|
||||
expect(test).to.eql('preload')
|
||||
})
|
||||
it('can successfully delete the Buffer global', async () => {
|
||||
const preload = path.join(fixtures, 'module', 'delete-buffer.js')
|
||||
const preload = path.join(__dirname, 'fixtures', 'module', 'delete-buffer.js')
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
@@ -1676,7 +1682,7 @@ describe('BrowserWindow module', () => {
|
||||
describe('"enableRemoteModule" option', () => {
|
||||
const generateSpecs = (description: string, sandbox: boolean) => {
|
||||
describe(description, () => {
|
||||
const preload = path.join(fixtures, 'module', 'preload-remote.js')
|
||||
const preload = path.join(__dirname, 'fixtures', 'module', 'preload-remote.js')
|
||||
|
||||
it('enables the remote module by default', async () => {
|
||||
const w = new BrowserWindow({
|
||||
@@ -1794,7 +1800,7 @@ describe('BrowserWindow module', () => {
|
||||
preload
|
||||
}
|
||||
})
|
||||
const htmlPath = path.join(fixtures, 'api', 'sandbox.html?exit-event')
|
||||
const htmlPath = path.join(__dirname, 'fixtures', 'api', 'sandbox.html?exit-event')
|
||||
const pageUrl = 'file://' + htmlPath
|
||||
w.loadURL(pageUrl)
|
||||
const [, url] = await emittedOnce(ipcMain, 'answer')
|
||||
@@ -1815,7 +1821,7 @@ describe('BrowserWindow module', () => {
|
||||
w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
|
||||
options.webPreferences!.preload = preload
|
||||
})
|
||||
const htmlPath = path.join(fixtures, 'api', 'sandbox.html?window-open')
|
||||
const htmlPath = path.join(__dirname, 'fixtures', 'api', 'sandbox.html?window-open')
|
||||
const pageUrl = 'file://' + htmlPath
|
||||
const answer = emittedOnce(ipcMain, 'answer')
|
||||
w.loadURL(pageUrl)
|
||||
@@ -1844,7 +1850,7 @@ describe('BrowserWindow module', () => {
|
||||
options.webPreferences!.preload = preload
|
||||
})
|
||||
w.loadFile(
|
||||
path.join(fixtures, 'api', 'sandbox.html'),
|
||||
path.join(__dirname, 'fixtures', 'api', 'sandbox.html'),
|
||||
{ search: 'window-open-external' }
|
||||
)
|
||||
|
||||
@@ -1921,7 +1927,11 @@ describe('BrowserWindow module', () => {
|
||||
prefs.foo = 'bar'
|
||||
})
|
||||
w.loadFile(path.join(fixtures, 'api', 'new-window.html'))
|
||||
const [, , webPreferences] = await emittedOnce(ipcMain, 'answer')
|
||||
const [[, childWebContents]] = await Promise.all([
|
||||
emittedOnce(app, 'web-contents-created'),
|
||||
emittedOnce(ipcMain, 'answer')
|
||||
])
|
||||
const webPreferences = (childWebContents as any).getLastWebPreferences()
|
||||
expect(webPreferences.foo).to.equal('bar')
|
||||
})
|
||||
|
||||
@@ -1952,7 +1962,7 @@ describe('BrowserWindow module', () => {
|
||||
'parent-answer',
|
||||
'child-answer'
|
||||
], done)
|
||||
w.loadFile(path.join(fixtures, 'api', 'sandbox.html'), { search: 'verify-ipc-sender' })
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'sandbox.html'), { search: 'verify-ipc-sender' })
|
||||
})
|
||||
|
||||
describe('event handling', () => {
|
||||
@@ -1988,7 +1998,7 @@ describe('BrowserWindow module', () => {
|
||||
'did-frame-finish-load',
|
||||
'dom-ready'
|
||||
], done)
|
||||
w.loadFile(path.join(fixtures, 'api', 'sandbox.html'), { search: 'webcontents-events' })
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'sandbox.html'), { search: 'webcontents-events' })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2021,7 +2031,7 @@ describe('BrowserWindow module', () => {
|
||||
sandbox: true
|
||||
}
|
||||
})
|
||||
w.loadFile(path.join(fixtures, 'api', 'sandbox.html'), { search: 'reload-remote' })
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'sandbox.html'), { search: 'reload-remote' })
|
||||
|
||||
ipcMain.on('get-remote-module-path', (event) => {
|
||||
event.returnValue = path.join(fixtures, 'module', 'hello.js')
|
||||
@@ -2057,7 +2067,7 @@ describe('BrowserWindow module', () => {
|
||||
options.webPreferences!.preload = preload
|
||||
})
|
||||
|
||||
w.loadFile(path.join(fixtures, 'api', 'sandbox.html'), { search: 'reload-remote-child' })
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'sandbox.html'), { search: 'reload-remote-child' })
|
||||
|
||||
ipcMain.on('get-remote-module-path', (event) => {
|
||||
event.returnValue = path.join(fixtures, 'module', 'hello-child.js')
|
||||
@@ -2233,7 +2243,11 @@ describe('BrowserWindow module', () => {
|
||||
prefs.foo = 'bar'
|
||||
})
|
||||
w.loadFile(path.join(fixtures, 'api', 'new-window.html'))
|
||||
const [, , webPreferences] = await emittedOnce(ipcMain, 'answer')
|
||||
const [[, childWebContents]] = await Promise.all([
|
||||
emittedOnce(app, 'web-contents-created'),
|
||||
emittedOnce(ipcMain, 'answer')
|
||||
])
|
||||
const webPreferences = (childWebContents as any).getLastWebPreferences()
|
||||
expect(webPreferences.foo).to.equal('bar')
|
||||
})
|
||||
it('should have nodeIntegration disabled in child windows', async () => {
|
||||
@@ -2359,22 +2373,27 @@ describe('BrowserWindow module', () => {
|
||||
beforeEach(() => {
|
||||
w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } })
|
||||
})
|
||||
afterEach(() => {
|
||||
ipcMain.removeAllListeners('onbeforeunload')
|
||||
})
|
||||
afterEach(closeAllWindows)
|
||||
it('returning undefined would not prevent close', (done) => {
|
||||
w.once('closed', () => { done() })
|
||||
w.loadFile(path.join(fixtures, 'api', 'close-beforeunload-undefined.html'))
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-undefined.html'))
|
||||
})
|
||||
it('returning false would prevent close', (done) => {
|
||||
w.once('onbeforeunload' as any, () => { done() })
|
||||
w.loadFile(path.join(fixtures, 'api', 'close-beforeunload-false.html'))
|
||||
it('returning false would prevent close', async () => {
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-false.html'))
|
||||
const [e] = await emittedOnce(ipcMain, 'onbeforeunload')
|
||||
e.returnValue = null
|
||||
})
|
||||
it('returning empty string would prevent close', (done) => {
|
||||
w.once('onbeforeunload' as any, () => { done() })
|
||||
w.loadFile(path.join(fixtures, 'api', 'close-beforeunload-empty-string.html'))
|
||||
ipcMain.once('onbeforeunload', (e) => { e.returnValue = null; done() })
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-empty-string.html'))
|
||||
})
|
||||
it('emits for each close attempt', (done) => {
|
||||
let beforeUnloadCount = 0
|
||||
w.on('onbeforeunload' as any, () => {
|
||||
ipcMain.on('onbeforeunload', (e) => {
|
||||
e.returnValue = null
|
||||
beforeUnloadCount += 1
|
||||
if (beforeUnloadCount < 3) {
|
||||
w.close()
|
||||
@@ -2382,12 +2401,13 @@ describe('BrowserWindow module', () => {
|
||||
done()
|
||||
}
|
||||
})
|
||||
w.webContents.once('did-finish-load', () => { w.close() })
|
||||
w.loadFile(path.join(fixtures, 'api', 'beforeunload-false-prevent3.html'))
|
||||
w.webContents.once('did-finish-load', () => { w.webContents.executeJavaScript('window.close()', true) })
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'beforeunload-false-prevent3.html'))
|
||||
})
|
||||
it('emits for each reload attempt', (done) => {
|
||||
let beforeUnloadCount = 0
|
||||
w.on('onbeforeunload' as any, () => {
|
||||
ipcMain.on('onbeforeunload', (e) => {
|
||||
e.returnValue = null
|
||||
beforeUnloadCount += 1
|
||||
if (beforeUnloadCount < 3) {
|
||||
w.reload()
|
||||
@@ -2401,11 +2421,12 @@ describe('BrowserWindow module', () => {
|
||||
})
|
||||
w.reload()
|
||||
})
|
||||
w.loadFile(path.join(fixtures, 'api', 'beforeunload-false-prevent3.html'))
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'beforeunload-false-prevent3.html'))
|
||||
})
|
||||
it('emits for each navigation attempt', (done) => {
|
||||
let beforeUnloadCount = 0
|
||||
w.on('onbeforeunload' as any, () => {
|
||||
ipcMain.on('onbeforeunload', (e) => {
|
||||
e.returnValue = null
|
||||
beforeUnloadCount += 1
|
||||
if (beforeUnloadCount < 3) {
|
||||
w.loadURL('about:blank')
|
||||
@@ -2419,7 +2440,7 @@ describe('BrowserWindow module', () => {
|
||||
})
|
||||
w.loadURL('about:blank')
|
||||
})
|
||||
w.loadFile(path.join(fixtures, 'api', 'beforeunload-false-prevent3.html'))
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'beforeunload-false-prevent3.html'))
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -192,79 +192,4 @@ describe('deprecate', () => {
|
||||
expect(warnings[0]).to.equal('\'old\' is deprecated and will be removed. Please use \'new\' instead.')
|
||||
})
|
||||
})
|
||||
|
||||
describe('promisify', () => {
|
||||
const expected = 'Hello, world!'
|
||||
let promiseFunc: (param: any) => Promise<any>
|
||||
let warnings: string[]
|
||||
|
||||
const enableCallbackWarnings = () => {
|
||||
warnings = []
|
||||
deprecate.setHandler(warning => warnings.push(warning))
|
||||
process.enablePromiseAPIs = true
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
deprecate.setHandler(null)
|
||||
process.throwDeprecation = true
|
||||
|
||||
promiseFunc = param => new Promise((resolve) => resolve(param))
|
||||
})
|
||||
|
||||
it('acts as a pass-through for promise-based invocations', async () => {
|
||||
enableCallbackWarnings()
|
||||
promiseFunc = deprecate.promisify(promiseFunc)
|
||||
|
||||
const actual = await promiseFunc(expected)
|
||||
expect(actual).to.equal(expected)
|
||||
expect(warnings).to.have.lengthOf(0)
|
||||
})
|
||||
|
||||
it('only calls back an error if the callback is called with (err, data)', async () => {
|
||||
enableCallbackWarnings()
|
||||
const erringPromiseFunc = deprecate.promisify(
|
||||
() => new Promise((resolve, reject) => {
|
||||
reject(new Error('fail'))
|
||||
})
|
||||
)
|
||||
|
||||
{
|
||||
const [err, data] = await new Promise(resolve => {
|
||||
(erringPromiseFunc as any)((err: Error | undefined, data: any) => {
|
||||
resolve([err, data])
|
||||
}).catch(() => { /* silence deprecation warning */ })
|
||||
})
|
||||
expect(data).to.be.undefined()
|
||||
expect(err).to.be.an.instanceOf(Error).with.property('message', 'fail')
|
||||
}
|
||||
{
|
||||
const data = await new Promise(resolve => {
|
||||
(erringPromiseFunc as any)((data: any) => { resolve(data) })
|
||||
.catch(() => { /* silence deprecation warning */ })
|
||||
})
|
||||
expect(data).to.be.undefined()
|
||||
}
|
||||
})
|
||||
|
||||
it('warns exactly once for callback-based invocations', (done) => {
|
||||
enableCallbackWarnings()
|
||||
promiseFunc = deprecate.promisify(promiseFunc)
|
||||
|
||||
let callbackCount = 0
|
||||
const invocationCount = 3
|
||||
const callback = (actual: number) => {
|
||||
expect(actual).to.equal(expected)
|
||||
expect(warnings).to.have.lengthOf(1)
|
||||
expect(warnings[0]).to.include('promiseFunc')
|
||||
callbackCount += 1
|
||||
if (callbackCount === invocationCount) {
|
||||
done()
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < invocationCount; i += 1) {
|
||||
(promiseFunc as any)(expected, callback)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -45,24 +45,6 @@ describe('ipc main module', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('remote objects registry', () => {
|
||||
it('does not dereference until the render view is deleted (regression)', (done) => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.once('error-message', (event, message) => {
|
||||
expect(message).to.match(/^Cannot call method 'getURL' on missing remote object/)
|
||||
done()
|
||||
})
|
||||
|
||||
w.loadFile(path.join(fixtures, 'api', 'render-view-deleted.html'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('ipcMain.on', () => {
|
||||
it('is not used for internals', async () => {
|
||||
const appPath = path.join(fixtures, 'api', 'ipc-main-listeners')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { expect } from 'chai'
|
||||
import { net as originalNet, session, ClientRequest } from 'electron'
|
||||
import { net as originalNet, session, ClientRequest, BrowserWindow } from 'electron'
|
||||
import * as http from 'http'
|
||||
import * as url from 'url'
|
||||
import { AddressInfo } from 'net'
|
||||
@@ -206,6 +206,135 @@ describe('net module', () => {
|
||||
urlRequest.end()
|
||||
})
|
||||
})
|
||||
|
||||
it('should emit the login event when 401', async () => {
|
||||
const [user, pass] = ['user', 'pass']
|
||||
const serverUrl = await respondOnce.toSingleURL((request, response) => {
|
||||
if (!request.headers.authorization) {
|
||||
return response.writeHead(401, { 'WWW-Authenticate': 'Basic realm="Foo"' }).end()
|
||||
}
|
||||
response.writeHead(200).end('ok')
|
||||
})
|
||||
let loginAuthInfo: any
|
||||
await new Promise((resolve, reject) => {
|
||||
const request = net.request({ method: 'GET', url: serverUrl })
|
||||
request.on('response', (response) => {
|
||||
response.on('error', reject)
|
||||
response.on('data', () => {})
|
||||
response.on('end', () => resolve())
|
||||
})
|
||||
request.on('login', (authInfo, cb) => {
|
||||
loginAuthInfo = authInfo
|
||||
cb(user, pass)
|
||||
})
|
||||
request.on('error', reject)
|
||||
request.end()
|
||||
})
|
||||
expect(loginAuthInfo.realm).to.equal('Foo')
|
||||
expect(loginAuthInfo.scheme).to.equal('basic')
|
||||
})
|
||||
|
||||
it('should produce an error on the response object when cancelling authentication', async () => {
|
||||
const serverUrl = await respondOnce.toSingleURL((request, response) => {
|
||||
if (!request.headers.authorization) {
|
||||
return response.writeHead(401, { 'WWW-Authenticate': 'Basic realm="Foo"' }).end()
|
||||
}
|
||||
response.writeHead(200).end('ok')
|
||||
})
|
||||
await expect(new Promise((resolve, reject) => {
|
||||
const request = net.request({ method: 'GET', url: serverUrl })
|
||||
request.on('response', (response) => {
|
||||
response.on('error', reject)
|
||||
response.on('data', () => {})
|
||||
response.on('end', () => resolve())
|
||||
})
|
||||
request.on('login', (authInfo, cb) => {
|
||||
cb()
|
||||
})
|
||||
request.on('error', reject)
|
||||
request.end()
|
||||
})).to.eventually.be.rejectedWith('net::ERR_HTTP_RESPONSE_CODE_FAILURE')
|
||||
})
|
||||
|
||||
it('should share credentials with WebContents', async () => {
|
||||
const [user, pass] = ['user', 'pass']
|
||||
const serverUrl = await new Promise<string>((resolve) => {
|
||||
const server = http.createServer((request, response) => {
|
||||
if (!request.headers.authorization) {
|
||||
return response.writeHead(401, { 'WWW-Authenticate': 'Basic realm="Foo"' }).end()
|
||||
}
|
||||
return response.writeHead(200).end('ok')
|
||||
})
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
resolve(`http://127.0.0.1:${(server.address() as AddressInfo).port}`)
|
||||
})
|
||||
after(() => { server.close() })
|
||||
})
|
||||
const bw = new BrowserWindow({ show: false })
|
||||
const loaded = bw.loadURL(serverUrl)
|
||||
bw.webContents.on('login', (event, details, authInfo, cb) => {
|
||||
event.preventDefault()
|
||||
cb(user, pass)
|
||||
})
|
||||
await loaded
|
||||
bw.close()
|
||||
await new Promise((resolve, reject) => {
|
||||
const request = net.request({ method: 'GET', url: serverUrl })
|
||||
request.on('response', (response) => {
|
||||
response.on('error', reject)
|
||||
response.on('data', () => {})
|
||||
response.on('end', () => resolve())
|
||||
})
|
||||
request.on('login', () => {
|
||||
// we shouldn't receive a login event, because the credentials should
|
||||
// be cached.
|
||||
reject(new Error('unexpected login event'))
|
||||
})
|
||||
request.on('error', reject)
|
||||
request.end()
|
||||
})
|
||||
})
|
||||
|
||||
it('should share proxy credentials with WebContents', async () => {
|
||||
const [user, pass] = ['user', 'pass']
|
||||
const proxyPort = await new Promise<number>((resolve) => {
|
||||
const server = http.createServer((request, response) => {
|
||||
if (!request.headers['proxy-authorization']) {
|
||||
return response.writeHead(407, { 'Proxy-Authenticate': 'Basic realm="Foo"' }).end()
|
||||
}
|
||||
return response.writeHead(200).end('ok')
|
||||
})
|
||||
server.listen(0, '127.0.0.1', () => {
|
||||
resolve((server.address() as AddressInfo).port)
|
||||
})
|
||||
after(() => { server.close() })
|
||||
})
|
||||
const customSession = session.fromPartition(`net-proxy-test-${Math.random()}`)
|
||||
await customSession.setProxy({ proxyRules: `127.0.0.1:${proxyPort}`, proxyBypassRules: '<-loopback>' })
|
||||
const bw = new BrowserWindow({ show: false, webPreferences: { session: customSession } })
|
||||
const loaded = bw.loadURL('http://127.0.0.1:9999')
|
||||
bw.webContents.on('login', (event, details, authInfo, cb) => {
|
||||
event.preventDefault()
|
||||
cb(user, pass)
|
||||
})
|
||||
await loaded
|
||||
bw.close()
|
||||
await new Promise((resolve, reject) => {
|
||||
const request = net.request({ method: 'GET', url: 'http://127.0.0.1:9999', session: customSession })
|
||||
request.on('response', (response) => {
|
||||
response.on('error', reject)
|
||||
response.on('data', () => {})
|
||||
response.on('end', () => resolve())
|
||||
})
|
||||
request.on('login', () => {
|
||||
// we shouldn't receive a login event, because the credentials should
|
||||
// be cached.
|
||||
reject(new Error('unexpected login event'))
|
||||
})
|
||||
request.on('error', reject)
|
||||
request.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('ClientRequest API', () => {
|
||||
|
||||
@@ -158,6 +158,24 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('remote objects registry', () => {
|
||||
it('does not dereference until the render view is deleted (regression)', (done) => {
|
||||
const w = new BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.once('error-message', (event, message) => {
|
||||
expect(message).to.match(/^Cannot call method 'getURL' on missing remote object/)
|
||||
done()
|
||||
})
|
||||
|
||||
w.loadFile(path.join(fixtures, 'api', 'render-view-deleted.html'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('remote listeners', () => {
|
||||
afterEach(closeAllWindows)
|
||||
|
||||
@@ -168,7 +186,7 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
await w.loadFile(path.join(__dirname, '..', 'spec', 'fixtures', 'api', 'remote-event-handler.html'))
|
||||
await w.loadFile(path.join(fixtures, 'api', 'remote-event-handler.html'))
|
||||
w.webContents.reload()
|
||||
await emittedOnce(w.webContents, 'did-finish-load')
|
||||
|
||||
|
||||
@@ -520,6 +520,7 @@ describe('session module', () => {
|
||||
})
|
||||
response.on('error', (error: any) => { reject(new Error(error)) })
|
||||
})
|
||||
request.on('error', (error: any) => { reject(new Error(error)) })
|
||||
request.end()
|
||||
})
|
||||
// the first time should throw due to unauthenticated
|
||||
|
||||
@@ -246,6 +246,11 @@ describe('systemPreferences module', () => {
|
||||
const microphoneStatus = systemPreferences.getMediaAccessStatus('microphone')
|
||||
expect(statuses).to.include(microphoneStatus)
|
||||
})
|
||||
|
||||
it('returns an access status for a screen access request', () => {
|
||||
const screenStatus = systemPreferences.getMediaAccessStatus('screen')
|
||||
expect(statuses).to.include(screenStatus)
|
||||
})
|
||||
})
|
||||
|
||||
describe('systemPreferences.getAnimationSettings()', () => {
|
||||
|
||||
@@ -47,20 +47,20 @@ describe('webContents module', () => {
|
||||
w.webContents.once('will-prevent-unload', () => {
|
||||
expect.fail('should not have fired')
|
||||
})
|
||||
w.loadFile(path.join(fixturesPath, 'api', 'close-beforeunload-undefined.html'))
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-undefined.html'))
|
||||
})
|
||||
|
||||
it('emits if beforeunload returns false', (done) => {
|
||||
it('emits if beforeunload returns false', async () => {
|
||||
const w = new BrowserWindow({ show: false })
|
||||
w.webContents.once('will-prevent-unload', () => done())
|
||||
w.loadFile(path.join(fixturesPath, 'api', 'close-beforeunload-false.html'))
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-false.html'))
|
||||
await emittedOnce(w.webContents, 'will-prevent-unload')
|
||||
})
|
||||
|
||||
it('supports calling preventDefault on will-prevent-unload events', (done) => {
|
||||
it('supports calling preventDefault on will-prevent-unload events', async () => {
|
||||
const w = new BrowserWindow({ show: false })
|
||||
w.webContents.once('will-prevent-unload', event => event.preventDefault())
|
||||
w.once('closed', () => done())
|
||||
w.loadFile(path.join(fixturesPath, 'api', 'close-beforeunload-false.html'))
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'api', 'close-beforeunload-false.html'))
|
||||
await emittedOnce(w, 'closed')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -695,15 +695,19 @@ describe('webContents module', () => {
|
||||
describe('focus()', () => {
|
||||
describe('when the web contents is hidden', () => {
|
||||
afterEach(closeAllWindows)
|
||||
it('does not blur the focused window', (done) => {
|
||||
it('does not blur the focused window', async () => {
|
||||
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } })
|
||||
ipcMain.once('answer', (event, parentFocused, childFocused) => {
|
||||
expect(parentFocused).to.be.true()
|
||||
expect(childFocused).to.be.false()
|
||||
done()
|
||||
})
|
||||
w.show()
|
||||
w.loadFile(path.join(fixturesPath, 'pages', 'focus-web-contents.html'))
|
||||
await w.loadURL('about:blank')
|
||||
w.focus()
|
||||
const child = new BrowserWindow({ show: false })
|
||||
child.loadURL('about:blank')
|
||||
child.webContents.focus()
|
||||
const currentFocused = w.isFocused()
|
||||
const childFocused = child.isFocused()
|
||||
child.close()
|
||||
expect(currentFocused).to.be.true()
|
||||
expect(childFocused).to.be.false()
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1534,7 +1538,7 @@ describe('webContents module', () => {
|
||||
}
|
||||
response
|
||||
.writeHead(401, { 'WWW-Authenticate': 'Basic realm="Foo"' })
|
||||
.end()
|
||||
.end('401')
|
||||
}).listen(0, '127.0.0.1', () => {
|
||||
serverPort = (server.address() as AddressInfo).port
|
||||
serverUrl = `http://127.0.0.1:${serverPort}`
|
||||
@@ -1557,6 +1561,10 @@ describe('webContents module', () => {
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await session.defaultSession.clearAuthCache({ type: 'password' })
|
||||
})
|
||||
|
||||
after(() => {
|
||||
server.close()
|
||||
proxyServer.close()
|
||||
@@ -1607,5 +1615,16 @@ describe('webContents module', () => {
|
||||
expect(eventAuthInfo.port).to.equal(proxyServerPort)
|
||||
expect(eventAuthInfo.realm).to.equal('Foo')
|
||||
})
|
||||
|
||||
it('cancels authentication when callback is called with no arguments', async () => {
|
||||
const w = new BrowserWindow({ show: false })
|
||||
w.webContents.on('login', (event, request, authInfo, cb) => {
|
||||
event.preventDefault()
|
||||
cb()
|
||||
})
|
||||
await w.loadURL(serverUrl)
|
||||
const body = await w.webContents.executeJavaScript(`document.documentElement.textContent`)
|
||||
expect(body).to.equal('401')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -20,6 +20,9 @@ describe('webRequest module', () => {
|
||||
if (req.headers.accept === '*/*;test/header') {
|
||||
content += 'header/received'
|
||||
}
|
||||
if (req.headers.origin === 'http://new-origin') {
|
||||
content += 'new/origin'
|
||||
}
|
||||
res.end(content)
|
||||
}
|
||||
})
|
||||
@@ -145,6 +148,16 @@ describe('webRequest module', () => {
|
||||
expect(data).to.equal('/header/received')
|
||||
})
|
||||
|
||||
it('can change CORS headers', async () => {
|
||||
ses.webRequest.onBeforeSendHeaders((details, callback) => {
|
||||
const requestHeaders = details.requestHeaders
|
||||
requestHeaders.Origin = 'http://new-origin'
|
||||
callback({ requestHeaders: requestHeaders })
|
||||
})
|
||||
const { data } = await ajax(defaultURL)
|
||||
expect(data).to.equal('/new/origin')
|
||||
})
|
||||
|
||||
it('resets the whole headers', async () => {
|
||||
const requestHeaders = {
|
||||
Test: 'header'
|
||||
@@ -199,6 +212,16 @@ describe('webRequest module', () => {
|
||||
expect(headers).to.match(/^custom: Changed$/m)
|
||||
})
|
||||
|
||||
it('can change CORS headers', async () => {
|
||||
ses.webRequest.onHeadersReceived((details, callback) => {
|
||||
const responseHeaders = details.responseHeaders!
|
||||
responseHeaders['access-control-allow-origin'] = ['http://new-origin'] as any
|
||||
callback({ responseHeaders: responseHeaders })
|
||||
})
|
||||
const { headers } = await ajax(defaultURL)
|
||||
expect(headers).to.match(/^access-control-allow-origin: http:\/\/new-origin$/m)
|
||||
})
|
||||
|
||||
it('does not change header by default', async () => {
|
||||
ses.webRequest.onHeadersReceived((details, callback) => {
|
||||
callback({})
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
var unloadPreventedCount = 0;
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
require('electron').remote.getCurrentWindow().emit('onbeforeunload');
|
||||
require('electron').ipcRenderer.sendSync('onbeforeunload')
|
||||
}, 0);
|
||||
if (unloadPreventedCount < 3) {
|
||||
unloadPreventedCount++;
|
||||
@@ -5,7 +5,7 @@
|
||||
var unloadPrevented = false;
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
require('electron').remote.getCurrentWindow().emit('onbeforeunload');
|
||||
require('electron').ipcRenderer.sendSync('onbeforeunload');
|
||||
}, 0);
|
||||
|
||||
if (!unloadPrevented) {
|
||||
@@ -5,7 +5,7 @@
|
||||
var unloadPrevented = false;
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
require('electron').remote.getCurrentWindow().emit('onbeforeunload');
|
||||
require('electron').ipcRenderer.sendSync('onbeforeunload');
|
||||
}, 0);
|
||||
if (!unloadPrevented) {
|
||||
unloadPrevented = true;
|
||||
16
spec-main/fixtures/pages/webview-devtools.html
Normal file
16
spec-main/fixtures/pages/webview-devtools.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<webview nodeintegration src="./a.html"></webview>
|
||||
<script>
|
||||
var wv = document.querySelector('webview')
|
||||
wv.addEventListener('dom-ready', () => {
|
||||
wv.openDevTools()
|
||||
})
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -164,7 +164,21 @@ describe('<webview> tag', function () {
|
||||
const extensionPath = path.join(fixtures, 'devtools-extensions', 'foo')
|
||||
BrowserWindow.addDevToolsExtension(extensionPath)
|
||||
|
||||
w.loadFile(path.join(fixtures, 'pages', 'webview-devtools.html'))
|
||||
w.loadFile(path.join(__dirname, 'fixtures', 'pages', 'webview-devtools.html'))
|
||||
app.once('web-contents-created', (e, webContents) => {
|
||||
webContents.on('devtools-opened', function () {
|
||||
const showPanelIntervalId = setInterval(function () {
|
||||
if (!webContents.isDestroyed() && webContents.devToolsWebContents) {
|
||||
webContents.devToolsWebContents.executeJavaScript('(' + function () {
|
||||
const lastPanelId: any = (window as any).UI.inspectorView._tabbedPane._tabs.peekLast().id;
|
||||
(window as any).UI.inspectorView.showPanel(lastPanelId)
|
||||
}.toString() + ')()')
|
||||
} else {
|
||||
clearInterval(showPanelIntervalId)
|
||||
}
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
const [, { runtimeId, tabId }] = await emittedOnce(ipcMain, 'answer')
|
||||
expect(runtimeId).to.equal('foo')
|
||||
|
||||
@@ -233,7 +233,7 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => {
|
||||
})
|
||||
|
||||
describe('remote value in browser', () => {
|
||||
const print = path.join(fixtures, 'module', 'print_name.js')
|
||||
const print = path.join(__dirname, '..', 'spec-main', 'fixtures', 'module', 'print_name.js')
|
||||
const printName = remote.require(print)
|
||||
|
||||
it('preserves NaN', () => {
|
||||
|
||||
2
spec/fixtures/api/beforeunload-false.html
vendored
2
spec/fixtures/api/beforeunload-false.html
vendored
@@ -5,7 +5,7 @@
|
||||
var unloadPrevented = false;
|
||||
window.onbeforeunload = function() {
|
||||
setTimeout(function() {
|
||||
require('electron').remote.getCurrentWindow().emit('onbeforeunload');
|
||||
require('electron').ipcRenderer.sendSync('onbeforeunload');
|
||||
}, 0);
|
||||
if (!unloadPrevented) {
|
||||
unloadPrevented = true;
|
||||
|
||||
4
spec/fixtures/api/new-window-preload.js
vendored
4
spec/fixtures/api/new-window-preload.js
vendored
@@ -1,4 +1,4 @@
|
||||
const { ipcRenderer, remote } = require('electron')
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
ipcRenderer.send('answer', process.argv, remote.getCurrentWindow().webContents.getWebPreferences())
|
||||
ipcRenderer.send('answer', process.argv)
|
||||
window.close()
|
||||
|
||||
24
spec/fixtures/pages/focus-web-contents.html
vendored
24
spec/fixtures/pages/focus-web-contents.html
vendored
@@ -1,24 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<script>
|
||||
const {ipcRenderer, remote} = require('electron')
|
||||
|
||||
remote.getCurrentWindow().focus()
|
||||
|
||||
const child = new remote.BrowserWindow({show: false})
|
||||
child.loadURL('about:blank')
|
||||
child.webContents.focus()
|
||||
|
||||
const currentFocused = remote.getCurrentWindow().isFocused()
|
||||
const childFocused = child.isFocused()
|
||||
child.close()
|
||||
ipcRenderer.send('answer', currentFocused, childFocused)
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
31
spec/fixtures/pages/webview-devtools.html
vendored
31
spec/fixtures/pages/webview-devtools.html
vendored
@@ -1,31 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<webview nodeintegration src="./a.html"></webview>
|
||||
<script>
|
||||
var wv = document.querySelector('webview')
|
||||
wv.addEventListener('dom-ready', () => {
|
||||
const { remote } = require('electron')
|
||||
const webContents = remote.webContents.fromId(wv.getWebContentsId())
|
||||
webContents.on('devtools-opened', function () {
|
||||
var showPanelIntevalId = setInterval(function () {
|
||||
if (webContents.devToolsWebContents) {
|
||||
webContents.devToolsWebContents.executeJavaScript('(' + (function () {
|
||||
var lastPanelId = UI.inspectorView._tabbedPane._tabs.peekLast().id
|
||||
UI.inspectorView.showPanel(lastPanelId)
|
||||
}).toString() + ')()')
|
||||
} else {
|
||||
clearInterval(showPanelIntevalId)
|
||||
}
|
||||
}, 100)
|
||||
})
|
||||
|
||||
wv.openDevTools()
|
||||
})
|
||||
</script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
3
spec/fixtures/pages/window-open-size.html
vendored
3
spec/fixtures/pages/window-open-size.html
vendored
@@ -1,8 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
var size = require('electron').remote.getCurrentWindow().getSize();
|
||||
window.opener.postMessage('size: ' + size[0] + ' ' + size[1], '*')
|
||||
window.opener.postMessage('size: ' + outerWidth + ' ' + outerHeight, '*')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
5
typings/internal-electron.d.ts
vendored
5
typings/internal-electron.d.ts
vendored
@@ -90,11 +90,6 @@ declare namespace ElectronInternal {
|
||||
removeProperty<T, K extends (keyof T & string)>(object: T, propertyName: K): T;
|
||||
renameProperty<T, K extends (keyof T & string)>(object: T, oldName: string, newName: K): T;
|
||||
moveAPI(fn: Function, oldUsage: string, newUsage: string): Function;
|
||||
|
||||
promisify<T extends (...args: any[]) => any>(fn: T): T;
|
||||
|
||||
// convertPromiseValue: Temporarily disabled until it's used
|
||||
promisifyMultiArg<T extends (...args: any[]) => any>(fn: T, /*convertPromiseValue: (v: any) => any*/): T;
|
||||
}
|
||||
|
||||
interface DesktopCapturer {
|
||||
|
||||
Reference in New Issue
Block a user