Compare commits

..

22 Commits

Author SHA1 Message Date
Keeley Hammond
e3bd73cbd7 chore: update patch with additional diffs
5029221: [RWS] Remove SameParty state from CanonicalCookie and ParsedCookie | https://chromium-review.googlesource.com/c/chromium/src/+/5029221
5030081: [RWS] Remove unused same_party ctor parameter | https://chromium-review.googlesource.com/c/chromium/src/+/5030081
5034217: [RWS] Remove CanonicalCookie::IsSameParty method | https://chromium-review.googlesource.com/c/chromium/src/+/5034217
2024-02-27 20:11:19 -08:00
Keeley Hammond
4f3391d92a feat: initial patch 2024-02-27 20:10:18 -08:00
Keeley Hammond
5cbaf97e31 fix: revert SameParty cookie attribute removal 2024-02-27 16:31:08 -08:00
electron-roller[bot]
2d9c5a62c6 chore: bump chromium to 122.0.6261.70 (29-x-y) (#41446)
chore: bump chromium in DEPS to 122.0.6261.70

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-02-27 15:12:14 -05:00
electron-roller[bot]
23f690ffd0 chore: bump chromium to 122.0.6261.69 (29-x-y) (#41425)
* chore: bump chromium in DEPS to 122.0.6261.69

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-02-26 11:35:30 +01:00
trop[bot]
8f4e94694e chore: fix import from patches.py in script/lib/git.py (#41437)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2024-02-26 10:05:30 +01:00
trop[bot]
af47434dc8 feat: add support for configuring system network context proxies (#41416)
* feat: add support for configuring system network context proxies

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* chore: add specs

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* chore: fix lint

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* fix: address review feedback

Co-authored-by: deepak1556 <hop2deep@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2024-02-23 14:56:30 -06:00
trop[bot]
8ab99e2d8e refactor: prefer using base::NoDestructor to base::{Singleton,LazyInstance} (#41423)
refactor: prefer using base::NoDestructor to base::{Singleton,LazyInstance}

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-02-23 09:02:58 -06:00
trop[bot]
ffcccdcf37 perf: omit unnecessary work from ElectronRenderFrameObserver::ShouldNotifyClient() (#41381)
perf: omit unnecessary work from ElectronRenderFrameObserver::ShouldNotifyClient()

- (perf) GetBlinkPreferences() returns a const&, so we can use that
  reference instead of making a temporary copy

- (perf) Don't create url object unless it's needed.

- (refactor) Move is_main_world() and is_isolated_world() from the
  header into an anonymous namespace in the .cc file so they can
  be inlined and made constexpr

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-02-22 11:51:37 -05:00
trop[bot]
ce2ac1c0c2 fix: use ScreenCaptureKit exclusively on macOS 14.4 and higher (#41403)
This fixes a nasty warning / permission dialog that pops up to end-users
when consuming legacy APIs.  Chrome has flipped these flags via field trials
as have other Electron apps. It should just be the default.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
2024-02-22 14:31:53 +01:00
trop[bot]
1c3feddef8 docs: update breaking changes language (#41398)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2024-02-21 14:17:57 -08:00
electron-roller[bot]
c779f19ee5 chore: bump chromium to 122.0.6261.57 (29-x-y) (#41390)
* chore: bump chromium in DEPS to 122.0.6261.57

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-02-21 11:26:48 -05:00
Keeley Hammond
09fbee9998 fix: check for draggable regions outside of main frame (#41388)
* fix: check for draggable regions outside of main frame

* fix: add nut-js to optional spec deps

Co-authored-by: samuelmaddock <samuelmaddock@electronjs.org>

---------

Co-authored-by: samuelmaddock <samuelmaddock@electronjs.org>
2024-02-21 10:52:02 -05:00
trop[bot]
69d371fc41 fix: revert to legacyMainResolve in JavaScript for asar compatibility (#41371)
* fix: revert to legacyMainResolve in JavaScript for asar compatibility

Co-authored-by: VerteDinde <vertedinde@electronjs.org>

* chore: update patch harder

* fix: export legacyMainResolve

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: VerteDinde <vertedinde@electronjs.org>
Co-authored-by: Keeley Hammond <khammond@slack-corp.com>
2024-02-19 15:56:16 -08:00
trop[bot]
b6db80c1c4 fix: properly stream uploadData in protocol.handle() (#41359)
* refactor(protocol): extract file stream factory

Increase readability by moving the file stream creation logic out of the
`uploadData` to request body conversion function.

Co-authored-by: Henrik S. Gaßmann <BurningEnlightenment@users.noreply.github.com>

* fix: properly flatten streams in `protocol.handle()`

Refs: electron/electron#39658

Co-authored-by: Henrik S. Gaßmann <BurningEnlightenment@users.noreply.github.com>

* fix: `protocol.handle()` filter null origin header

Refs: electron/electron#40754

Co-authored-by: Henrik S. Gaßmann <BurningEnlightenment@users.noreply.github.com>

* fix: remove obsolete TODO comment

Refs: electron/electron#38929

Co-authored-by: Henrik S. Gaßmann <BurningEnlightenment@users.noreply.github.com>

* fix: forward `Blob` parts in `protocol.handle()`

Refs: electron/electron#40826

Co-authored-by: Henrik S. Gaßmann <BurningEnlightenment@users.noreply.github.com>

* fix: explicitly error out on unknown chunk parts

Co-authored-by: Henrik S. Gaßmann <BurningEnlightenment@users.noreply.github.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Henrik S. Gaßmann <BurningEnlightenment@users.noreply.github.com>
2024-02-19 12:23:14 -08:00
trop[bot]
b87cf56b09 ci: fix helperPath calls in ci configs (#41365)
* ci: fix helperPath calls in ci configs

Co-authored-by: codebytere <codebytere@electronjs.org>

Co-authored-by: Keeley Hammond <khammond@slack-corp.com>

* ci: fix helperPaths harder

Co-authored-by: Keeley Hammond <khammond@slack-corp.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <khammond@slack-corp.com>
2024-02-17 20:32:12 -05:00
electron-roller[bot]
bc40a1aa0c chore: bump chromium to 122.0.6261.39 (29-x-y) (#41349)
* chore: bump chromium in DEPS to 122.0.6261.39

* chore: update patches

* fix: restore MessagePort close event

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2024-02-16 10:31:11 -06:00
trop[bot]
d8606efe94 fix: Ignore -webkit-app-region: drag; when window is in full screen mode. (#41332)
fix: Ignore `-webkit-app-region: drag;` when window is in full screen mode. (#41307)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Mikhail Leliakin <leliakin@canva.com>
2024-02-15 14:41:46 -05:00
Charles Kerr
523e0d4574 refactor: inline simple getters, pt . 2 (#41254) (#41341)
* refactor: inline AutofillPopup::line_count()

refactor: inline AutofillPopup::value_at()

refactor: inline AutofillPopup::label_at()

* refactor: inline NativeWindow::aspect_ratio()

refactor: inline NativeWindow::aspect_ratio_extra_size()

* refactor: inline BrowserProcessImpl::linux_storage_backend()

* refactor: inline ElectronMenuModel::sharing_item()

* refactor: inline Browser::badge_count()

* refactor: inline WebContents::is_guest()

refactor: inline InspectableWebContents::is_guest()

* refactor: inline InspectableWebContents::dev_tool_bounds()

* refactor: inline WebContents::type()
2024-02-15 11:00:32 -05:00
electron-roller[bot]
3b23911121 chore: bump chromium to 122.0.6261.29 (29-x-y) (#41279)
* chore: bump chromium in DEPS to 122.0.6261.29

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-02-15 08:32:44 +09:00
trop[bot]
516cbfa29a fix: skip the first two invalid updates when SCK is enabled (#41344)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
2024-02-14 13:30:24 -08:00
trop[bot]
5c71377f40 fix: add capability to use ScreenCaptureKit for thumbnail generation (#41329)
This aligns us with Chromiums flags / capabilities in regards to using SCK for
everything. Currently on 14.4 Electron apps will pop warnings for usage of
deprecated APIs.  With this change and a few "enable-features" toggles.

`--enable-features="ScreenCaptureKitMac,ScreenCaptureKitStreamPickerSonoma,ThumbnailCapturerMac:capture_mode/sc_screenshot_manager"`

As Chromium enables these by default Electron will inherit those changes, apps wishing to skip ahead can apply these flags early.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
2024-02-14 01:11:29 -08:00
78 changed files with 7126 additions and 347 deletions

View File

@@ -353,10 +353,10 @@ step-setup-rbe-for-build: &step-setup-rbe-for-build
mkdir third_party
# Pull down credential helper and print status
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
HELPER=$(node -p "require('./src/utils/reclient.js').helperPath")
HELPER=$(node -p "require('./src/utils/reclient.js').helperPath({})")
$HELPER login
echo 'export RBE_service='`node -e "console.log(require('./src/utils/reclient.js').serviceAddress)"` >> $BASH_ENV
echo 'export RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath)"` >> $BASH_ENV
echo 'export RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath({}))"` >> $BASH_ENV
echo 'export RBE_experimental_credentials_helper_args="print"' >> $BASH_ENV
step-restore-brew-cache: &step-restore-brew-cache

2
DEPS
View File

@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'122.0.6261.18',
'122.0.6261.70',
'node_version':
'v20.9.0',
'nan_version':

View File

@@ -106,7 +106,7 @@ for:
- mkdir third_party
- ps: >-
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath"
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath({})"
- ps: >-
& $env:RECLIENT_HELPER login
- ps: >-

View File

@@ -104,7 +104,7 @@ for:
- mkdir third_party
- ps: >-
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath"
- ps: $env:RECLIENT_HELPER = node -p "require('./src/utils/reclient.js').helperPath({})"
- ps: >-
& $env:RECLIENT_HELPER login
- ps: >-

View File

@@ -1468,6 +1468,24 @@ details.
**Note:** Enable `Secure Keyboard Entry` only when it is needed and disable it when it is no longer needed.
### `app.setProxy(config)`
* `config` [ProxyConfig](structures/proxy-config.md)
Returns `Promise<void>` - Resolves when the proxy setting process is complete.
Sets the proxy settings for networks requests made without an associated [Session](session.md).
Currently this will affect requests made with [Net](net.md) in the [utility process](../glossary.md#utility-process)
and internal requests made by the runtime (ex: geolocation queries).
This method can only be called after app is ready.
#### `app.resolveProxy(url)`
* `url` URL
Returns `Promise<string>` - Resolves with the proxy information for `url` that will be used when attempting to make requests using [Net](net.md) in the [utility process](../glossary.md#utility-process).
## Properties
### `app.accessibilitySupportEnabled` _macOS_ _Windows_

View File

@@ -589,105 +589,15 @@ Writes any unwritten DOMStorage data to disk.
#### `ses.setProxy(config)`
* `config` Object
* `mode` string (optional) - The proxy mode. Should be one of `direct`,
`auto_detect`, `pac_script`, `fixed_servers` or `system`. If it's
unspecified, it will be automatically determined based on other specified
options.
* `direct`
In direct mode all connections are created directly, without any proxy involved.
* `auto_detect`
In auto_detect mode the proxy configuration is determined by a PAC script that can
be downloaded at http://wpad/wpad.dat.
* `pac_script`
In pac_script mode the proxy configuration is determined by a PAC script that is
retrieved from the URL specified in the `pacScript`. This is the default mode
if `pacScript` is specified.
* `fixed_servers`
In fixed_servers mode the proxy configuration is specified in `proxyRules`.
This is the default mode if `proxyRules` is specified.
* `system`
In system mode the proxy configuration is taken from the operating system.
Note that the system mode is different from setting no proxy configuration.
In the latter case, Electron falls back to the system settings
only if no command-line options influence the proxy configuration.
* `pacScript` string (optional) - The URL associated with the PAC file.
* `proxyRules` string (optional) - Rules indicating which proxies to use.
* `proxyBypassRules` string (optional) - Rules indicating which URLs should
bypass the proxy settings.
* `config` [ProxyConfig](structures/proxy-config.md)
Returns `Promise<void>` - Resolves when the proxy setting process is complete.
Sets the proxy settings.
When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, the `proxyRules`
option is ignored and `pacScript` configuration is applied.
You may need `ses.closeAllConnections` to close currently in flight connections to prevent
pooled sockets using previous proxy from being reused by future requests.
The `proxyRules` has to follow the rules below:
```sh
proxyRules = schemeProxies[";"<schemeProxies>]
schemeProxies = [<urlScheme>"="]<proxyURIList>
urlScheme = "http" | "https" | "ftp" | "socks"
proxyURIList = <proxyURL>[","<proxyURIList>]
proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>]
```
For example:
* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and
HTTP proxy `foopy2:80` for `ftp://` URLs.
* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs.
* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing
over to `bar` if `foopy:80` is unavailable, and after that using no proxy.
* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs.
* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail
over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable.
* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no
proxy if `foopy` is unavailable.
* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use
`socks4://foopy2` for all other URLs.
The `proxyBypassRules` is a comma separated list of rules described below:
* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]`
Match all hostnames that match the pattern HOSTNAME_PATTERN.
Examples:
"foobar.com", "\*foobar.com", "\*.foobar.com", "\*foobar.com:99",
"https://x.\*.y.com:99"
* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]`
Match a particular domain suffix.
Examples:
".google.com", ".com", "http://.google.com"
* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]`
Match URLs which are IP address literals.
Examples:
"127.0.1", "\[0:0::1]", "\[::1]", "http://\[::1]:99"
* `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS`
Match any URL that is to an IP literal that falls between the
given range. IP range is specified using CIDR notation.
Examples:
"192.168.1.1/16", "fefe:13::abc/33".
* `<local>`
Match local addresses. The meaning of `<local>` is whether the
host matches one of: "127.0.0.1", "::1", "localhost".
#### `ses.resolveHost(host, [options])`
* `host` string - Hostname to resolve.

View File

@@ -0,0 +1,86 @@
# ProxyConfig Object
* `mode` string (optional) - The proxy mode. Should be one of `direct`,
`auto_detect`, `pac_script`, `fixed_servers` or `system`.
Defaults to `pac_script` proxy mode if `pacScript` option is specified
otherwise defaults to `fixed_servers`.
* `direct` - In direct mode all connections are created directly, without any proxy involved.
* `auto_detect` - In auto_detect mode the proxy configuration is determined by a PAC script that can
be downloaded at http://wpad/wpad.dat.
* `pac_script` - In pac_script mode the proxy configuration is determined by a PAC script that is
retrieved from the URL specified in the `pacScript`. This is the default mode if `pacScript` is specified.
* `fixed_servers` - In fixed_servers mode the proxy configuration is specified in `proxyRules`.
This is the default mode if `proxyRules` is specified.
* `system` - In system mode the proxy configuration is taken from the operating system.
Note that the system mode is different from setting no proxy configuration.
In the latter case, Electron falls back to the system settings only if no
command-line options influence the proxy configuration.
* `pacScript` string (optional) - The URL associated with the PAC file.
* `proxyRules` string (optional) - Rules indicating which proxies to use.
* `proxyBypassRules` string (optional) - Rules indicating which URLs should
bypass the proxy settings.
When `mode` is unspecified, `pacScript` and `proxyRules` are provided together, the `proxyRules`
option is ignored and `pacScript` configuration is applied.
The `proxyRules` has to follow the rules below:
```sh
proxyRules = schemeProxies[";"<schemeProxies>]
schemeProxies = [<urlScheme>"="]<proxyURIList>
urlScheme = "http" | "https" | "ftp" | "socks"
proxyURIList = <proxyURL>[","<proxyURIList>]
proxyURL = [<proxyScheme>"://"]<proxyHost>[":"<proxyPort>]
```
For example:
* `http=foopy:80;ftp=foopy2` - Use HTTP proxy `foopy:80` for `http://` URLs, and
HTTP proxy `foopy2:80` for `ftp://` URLs.
* `foopy:80` - Use HTTP proxy `foopy:80` for all URLs.
* `foopy:80,bar,direct://` - Use HTTP proxy `foopy:80` for all URLs, failing
over to `bar` if `foopy:80` is unavailable, and after that using no proxy.
* `socks4://foopy` - Use SOCKS v4 proxy `foopy:1080` for all URLs.
* `http=foopy,socks5://bar.com` - Use HTTP proxy `foopy` for http URLs, and fail
over to the SOCKS5 proxy `bar.com` if `foopy` is unavailable.
* `http=foopy,direct://` - Use HTTP proxy `foopy` for http URLs, and use no
proxy if `foopy` is unavailable.
* `http=foopy;socks=foopy2` - Use HTTP proxy `foopy` for http URLs, and use
`socks4://foopy2` for all other URLs.
The `proxyBypassRules` is a comma separated list of rules described below:
* `[ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ]`
Match all hostnames that match the pattern HOSTNAME_PATTERN.
Examples:
"foobar.com", "\*foobar.com", "\*.foobar.com", "\*foobar.com:99",
"https://x.\*.y.com:99"
* `"." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ]`
Match a particular domain suffix.
Examples:
".google.com", ".com", "http://.google.com"
* `[ SCHEME "://" ] IP_LITERAL [ ":" PORT ]`
Match URLs which are IP address literals.
Examples:
"127.0.1", "\[0:0::1]", "\[::1]", "http://\[::1]:99"
* `IP_LITERAL "/" PREFIX_LENGTH_IN_BITS`
Match any URL that is to an IP literal that falls between the
given range. IP range is specified using CIDR notation.
Examples:
"192.168.1.1/16", "fefe:13::abc/33".
* `<local>`
Match local addresses. The meaning of `<local>` is whether the
host matches one of: "127.0.0.1", "::1", "localhost".

View File

@@ -30,10 +30,10 @@ This switch was never formally documented but it's removal is being noted here r
### Behavior Changed: `ipcRenderer` can no longer be sent over the `contextBridge`
Attempting to send `ipcRenderer` as an object over the `contextBridge` will now result in
Attempting to send the entire `ipcRenderer` module as an object over the `contextBridge` will now result in
an empty object on the receiving side of the bridge. This change was made to remove / mitigate
a security footgun, you should not directly expose ipcRenderer or it's methods over the bridge.
Instead provide a safe wrapper like below:
a security footgun. You should not directly expose ipcRenderer or its methods over the bridge.
Instead, provide a safe wrapper like below:
```js
contextBridge.exposeInMainWorld('app', {

View File

@@ -114,6 +114,7 @@ auto_filenames = {
"docs/api/structures/protocol-request.md",
"docs/api/structures/protocol-response-upload-data.md",
"docs/api/structures/protocol-response.md",
"docs/api/structures/proxy-config.md",
"docs/api/structures/rectangle.md",
"docs/api/structures/referrer.md",
"docs/api/structures/render-process-gone-details.md",

View File

@@ -385,6 +385,7 @@ filenames = {
"shell/browser/extended_web_contents_observer.h",
"shell/browser/feature_list.cc",
"shell/browser/feature_list.h",
"shell/browser/feature_list_mac.mm",
"shell/browser/file_select_helper.cc",
"shell/browser/file_select_helper.h",
"shell/browser/file_select_helper_mac.mm",

View File

@@ -29,6 +29,21 @@ function makeStreamFromPipe (pipe: any): ReadableStream {
});
}
function makeStreamFromFileInfo ({
filePath,
offset = 0,
length = -1
}: {
filePath: string;
offset?: number;
length?: number;
}): ReadableStream {
return Readable.toWeb(createReadStream(filePath, {
start: offset,
end: length >= 0 ? offset + length : undefined
}));
}
function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): RequestInit['body'] {
if (!uploadData) return null;
// Optimization: skip creating a stream if the request is just a single buffer.
@@ -37,30 +52,42 @@ function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): Reque
const chunks = [...uploadData] as any[]; // TODO: types are wrong
let current: ReadableStreamDefaultReader | null = null;
return new ReadableStream({
pull (controller) {
async pull (controller) {
if (current) {
current.read().then(({ done, value }) => {
const { done, value } = await current.read();
// (done => value === undefined) as per WHATWG spec
if (done) {
current = null;
return this.pull!(controller);
} else {
controller.enqueue(value);
if (done) current = null;
}, (err) => {
controller.error(err);
});
}
} else {
if (!chunks.length) { return controller.close(); }
const chunk = chunks.shift()!;
if (chunk.type === 'rawData') { controller.enqueue(chunk.bytes); } else if (chunk.type === 'file') {
current = Readable.toWeb(createReadStream(chunk.filePath, { start: chunk.offset ?? 0, end: chunk.length >= 0 ? chunk.offset + chunk.length : undefined })).getReader();
this.pull!(controller);
if (chunk.type === 'rawData') {
controller.enqueue(chunk.bytes);
} else if (chunk.type === 'file') {
current = makeStreamFromFileInfo(chunk).getReader();
return this.pull!(controller);
} else if (chunk.type === 'stream') {
current = makeStreamFromPipe(chunk.body).getReader();
this.pull!(controller);
return this.pull!(controller);
} else if (chunk.type === 'blob') {
// Note that even though `getBlobData()` is a `Session` API, it doesn't
// actually use the `Session` context. Its implementation solely relies
// on global variables which allows us to implement this feature without
// knowledge of the `Session` associated with the current request by
// always pulling `Blob` data out of the default `Session`.
controller.enqueue(await session.defaultSession.getBlobData(chunk.blobUUID));
} else {
throw new Error(`Unknown upload data chunk type: ${chunk.type}`);
}
}
}
}) as RequestInit['body'];
}
// TODO(codebytere): Use Object.hasOwn() once we update to ECMAScript 2022.
function validateResponse (res: Response) {
if (!res || typeof res !== 'object') return false;
@@ -85,8 +112,12 @@ Protocol.prototype.handle = function (this: Electron.Protocol, scheme: string, h
const success = register.call(this, scheme, async (preq: ProtocolRequest, cb: any) => {
try {
const body = convertToRequestBody(preq.uploadData);
const headers = new Headers(preq.headers);
if (headers.get('origin') === 'null') {
headers.delete('origin');
}
const req = new Request(preq.url, {
headers: preq.headers,
headers,
method: preq.method,
referrer: preq.referrer,
body,

View File

@@ -130,4 +130,5 @@ build_run_reclient_cfg_generator_after_chrome.patch
fix_suppress_clang_-wimplicit-const-int-float-conversion_in.patch
cherry-pick-e7ffe20ebfac.patch
fix_getcursorscreenpoint_wrongly_returns_0_0.patch
fix_add_support_for_skipping_first_no-op_refresh_in_thumb_cap.patch
fix_add_support_for_skipping_first_2_no-op_refreshes_in_thumb_cap.patch
revert_same_party_cookie_attribute_removal.patch

View File

@@ -92,10 +92,10 @@ index 2709519d0bbf33548704c14a99324b504d27ccbf..aa3c2d3c1ea73da128616fe676ac09e2
int32_t world_id) = 0;
virtual bool AllowScriptExtensions() = 0;
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index 6139aed9ebbb459d4d7027312c0f15b669fedfb6..db566ba272b1eff5e67547c5d82bf7420def7285 100644
index 070f61ef364eec98080f29d089d39f74222e9759..a6d2f3bbe61486187d23d20fecb01749e1d897b7 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -289,6 +289,13 @@ void LocalFrameClientImpl::DidCreateScriptContext(
@@ -290,6 +290,13 @@ void LocalFrameClientImpl::DidCreateScriptContext(
web_frame_->Client()->DidCreateScriptContext(context, world_id);
}

View File

@@ -151,7 +151,7 @@ index 794efdb773422ddc12ccbe013a13aadeb980b487..a60bbd76141f06202343c68e78688a95
// In GTK4, there's no way to obtain the frame thickness from CSS values
// directly, so we must determine it experimentally based on the drawn
diff --git a/ui/gtk/window_frame_provider_gtk.h b/ui/gtk/window_frame_provider_gtk.h
index 91236ec07c01ca14248b997577ae887c0c396cd2..d70639d2ba40e325bbbbf6117741c13354984ed5 100644
index bed28192daffe032fde3a74ca70f1298fb12b1b7..268acade8bd1075f3ce756cdf29bf50905ccb433 100644
--- a/ui/gtk/window_frame_provider_gtk.h
+++ b/ui/gtk/window_frame_provider_gtk.h
@@ -18,7 +18,7 @@ namespace gtk {

View File

@@ -33,10 +33,10 @@ index d09e7aeb788550e7ecefb4b9c177dd26ecc5ad4c..c894dc421f55a94e541d00e05e2f05bf
"//base",
"//build:branding_buildflags",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 81dceec0b449c6fa90984f0bede8d3b94a93910a..32e5194b60f7db1d076e2ba3a884cce4e3133b02 100644
index 0811d62fd215de0231021c88c6083493b0a6b1ca..502275e7adf9388afeeaeca692784f9e9a060f8c 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4755,7 +4755,7 @@ static_library("browser") {
@@ -4763,7 +4763,7 @@ static_library("browser") {
# On Windows, the hashes are embedded in //chrome:chrome_initial rather
# than here in :chrome_dll.
@@ -46,10 +46,10 @@ index 81dceec0b449c6fa90984f0bede8d3b94a93910a..32e5194b60f7db1d076e2ba3a884cce4
sources += [ "certificate_viewer_stub.cc" ]
}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 005e321b191e69422c892c2001ffc98f9e198d14..e02717f068247e0c971e19374b8c2d2d0809fc5b 100644
index 84ea91c781a2f777461a4e99d1c8c2cdf138dc22..0d8a1ed6cebd86de4efc36a93e20cb6034a16c10 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -7220,7 +7220,6 @@ if (!is_fuchsia) {
@@ -7221,7 +7221,6 @@ if (!is_fuchsia) {
deps += [
"//chrome:other_version",
@@ -57,7 +57,7 @@ index 005e321b191e69422c892c2001ffc98f9e198d14..e02717f068247e0c971e19374b8c2d2d
"//chrome//services/util_win:unit_tests",
"//chrome/app:chrome_dll_resources",
"//chrome/app:win_unit_tests",
@@ -7241,6 +7240,10 @@ if (!is_fuchsia) {
@@ -7242,6 +7241,10 @@ if (!is_fuchsia) {
"//ui/resources",
]
@@ -68,7 +68,7 @@ index 005e321b191e69422c892c2001ffc98f9e198d14..e02717f068247e0c971e19374b8c2d2d
ldflags = [
"/DELAYLOAD:api-ms-win-core-winrt-error-l1-1-0.dll",
"/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll",
@@ -8259,7 +8262,6 @@ if (!is_fuchsia) {
@@ -8260,7 +8263,6 @@ if (!is_fuchsia) {
}
deps += [
@@ -76,7 +76,7 @@ index 005e321b191e69422c892c2001ffc98f9e198d14..e02717f068247e0c971e19374b8c2d2d
"//chrome/browser/apps:icon_standardizer",
"//chrome/browser/apps/app_service",
"//chrome/browser/apps/app_service:app_registry_cache_waiter",
@@ -8352,6 +8354,10 @@ if (!is_fuchsia) {
@@ -8353,6 +8355,10 @@ if (!is_fuchsia) {
"//ui/webui/resources/js/browser_command:mojo_bindings",
]

View File

@@ -13,10 +13,10 @@ uses internally for things like menus and devtools.
We can remove this patch once it has in some shape been upstreamed.
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc
index fbbc35818cfa1709b30520e2336eeab2d96693d0..814230e423a44bfc71b6e028fb870f2a1d15e15f 100644
index 17c3b9f659a3b3e7f61463e5900ed53276454a7b..93848cea0c62b5457c9033c477a3fb81120f33cb 100644
--- a/ui/native_theme/native_theme.cc
+++ b/ui/native_theme/native_theme.cc
@@ -198,6 +198,8 @@ NativeTheme::NativeTheme(bool should_use_dark_colors,
@@ -191,6 +191,8 @@ NativeTheme::NativeTheme(bool should_use_dark_colors,
NativeTheme::~NativeTheme() = default;
bool NativeTheme::ShouldUseDarkColors() const {
@@ -26,10 +26,10 @@ index fbbc35818cfa1709b30520e2336eeab2d96693d0..814230e423a44bfc71b6e028fb870f2a
}
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index 772c7a34a97588dd20c040be5ca482696990c880..fe1c04d6f9c9e9ca6a3aeacbaf897f1df5783248 100644
index 14f3667521de110e6b9cd884ef9311878bb8bc8a..c88da6b43b9caefa50e8606e5a641c7c3dd6287e 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -442,6 +442,23 @@ class NATIVE_THEME_EXPORT NativeTheme {
@@ -441,6 +441,23 @@ class NATIVE_THEME_EXPORT NativeTheme {
scoped_refptr<ColorProviderKey::ThemeInitializerSupplier> custom_theme,
bool use_custom_frame = true) const;
@@ -53,7 +53,7 @@ index 772c7a34a97588dd20c040be5ca482696990c880..fe1c04d6f9c9e9ca6a3aeacbaf897f1d
// Returns a shared instance of the native theme that should be used for web
// rendering. Do not use it in a normal application context (i.e. browser).
// The returned object should not be deleted by the caller. This function is
@@ -658,6 +675,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
@@ -655,6 +672,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
bool inverted_colors_ = false;
PreferredColorScheme preferred_color_scheme_ = PreferredColorScheme::kLight;
PreferredContrast preferred_contrast_ = PreferredContrast::kNoPreference;
@@ -62,10 +62,10 @@ index 772c7a34a97588dd20c040be5ca482696990c880..fe1c04d6f9c9e9ca6a3aeacbaf897f1d
SEQUENCE_CHECKER(sequence_checker_);
};
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index 6af4df92820d5a9d247a927244522f4c4acd164d..92af8c4a933b8462dce2524b0623a6843abd2600 100644
index 50647269ec84f1a543132b3d102152a40e1e65e1..41a7df7e873a7d3300fd48db0ffa5f1fc8e43198 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -655,6 +655,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const {
@@ -664,6 +664,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const {
// ...unless --force-dark-mode was specified in which case caveat emptor.
if (InForcedColorsMode() && !IsForcedDarkMode())
return false;

View File

@@ -1,13 +1,20 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <marshallofsound@electronjs.org>
Date: Tue, 13 Feb 2024 17:40:15 -0800
Subject: fix: add support for skipping first no-op refresh in thumb cap
Subject: fix: add support for skipping first 2 no-op refreshes in thumb cap
Fixes a bug in the SCK thumbnail capturer, will be reported upstream for a hopefully
less hacky fix.
The first refresh is "no windows yet, no thumbnails".
The second refresh is "we have windows, we queued the thumbnail requests"
The third refresh (the one we want) is "we have windows, and have thumbnail requests"
This really isn't ideal at all, we need to refactor desktopCapturer (read completely re-implement it)
to use StartUpdating and handle the events instead of using the "get the list once" method.
diff --git a/chrome/browser/media/webrtc/desktop_media_list.h b/chrome/browser/media/webrtc/desktop_media_list.h
index 0c6fccf16a11bbaff10115308e4b489490e5d3e6..3b541e6830ca902cf45483a3193376c0e559185e 100644
index 0c6fccf16a11bbaff10115308e4b489490e5d3e6..e5ec31054a43989e630115605de435399d36559b 100644
--- a/chrome/browser/media/webrtc/desktop_media_list.h
+++ b/chrome/browser/media/webrtc/desktop_media_list.h
@@ -143,6 +143,8 @@ class DesktopMediaList {
@@ -15,12 +22,12 @@ index 0c6fccf16a11bbaff10115308e4b489490e5d3e6..3b541e6830ca902cf45483a3193376c0
// delegated source list when it should be hidden.
virtual void HideList() = 0;
+
+ bool skip_next_refresh_ = false;
+ int skip_next_refresh_ = 0;
};
#endif // CHROME_BROWSER_MEDIA_WEBRTC_DESKTOP_MEDIA_LIST_H_
diff --git a/chrome/browser/media/webrtc/desktop_media_list_base.cc b/chrome/browser/media/webrtc/desktop_media_list_base.cc
index 780927301744ea7312f230cec76a24a33d71f767..321d3ff46cbb67e880d5414d83a199fb16457038 100644
index 780927301744ea7312f230cec76a24a33d71f767..d19b1cc9dedf839f12f4113db64293e5c8150f51 100644
--- a/chrome/browser/media/webrtc/desktop_media_list_base.cc
+++ b/chrome/browser/media/webrtc/desktop_media_list_base.cc
@@ -230,7 +230,11 @@ uint32_t DesktopMediaListBase::GetImageHash(const gfx::Image& image) {
@@ -28,8 +35,8 @@ index 780927301744ea7312f230cec76a24a33d71f767..321d3ff46cbb67e880d5414d83a199fb
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(refresh_callback_);
- std::move(refresh_callback_).Run();
+ if (skip_next_refresh_) {
+ skip_next_refresh_ = false;
+ if (skip_next_refresh_ > 0) {
+ skip_next_refresh_--;
+ } else {
+ std::move(refresh_callback_).Run();
+ }

View File

@@ -13,13 +13,13 @@ messages in the legacy window handle layer.
These conditions are regularly hit with WCO-enabled windows on Windows.
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.cc b/content/browser/renderer_host/legacy_render_widget_host_win.cc
index 2635d8967c42c85fb6830036e6de694b5736a97b..17bb1932f3a01c5027113061276f7050bb61f80e 100644
index 70c19054022dd8ebc28657bb9ec94c0ee3e7ad87..ed9bea21b4ee6d6b9a7b979fc63ccc43d1926184 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.cc
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.cc
@@ -322,12 +322,12 @@ LRESULT LegacyRenderWidgetHostHWND::OnKeyboardRange(UINT message,
LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
@@ -320,12 +320,12 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
WPARAM w_param,
LPARAM l_param) {
LPARAM l_param,
BOOL& handled) {
- if (message == WM_MOUSEMOVE) {
+ if (message == WM_MOUSEMOVE || message == WM_NCMOUSEMOVE) {
if (!mouse_tracking_enabled_) {
@@ -31,27 +31,27 @@ index 2635d8967c42c85fb6830036e6de694b5736a97b..17bb1932f3a01c5027113061276f7050
tme.hwndTrack = hwnd();
tme.dwHoverTime = 0;
TrackMouseEvent(&tme);
@@ -359,7 +359,10 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
@@ -356,7 +356,10 @@ LRESULT LegacyRenderWidgetHostHWND::OnMouseRange(UINT message,
// out of the picture.
if (!msg_handled_ &&
if (!handled &&
(message >= WM_NCMOUSEMOVE && message <= WM_NCXBUTTONDBLCLK)) {
- ret = ::DefWindowProc(GetParent(), message, w_param, l_param);
+ // Send WM_NCMOUSEMOVE messages using the LegacyRenderWidgetHostHWND's
+ // handle so mouse tracking on non-client areas doesn't break.
+ HWND target = message == WM_NCMOUSEMOVE ? hwnd() : GetParent();
+ ret = ::DefWindowProc(target, message, w_param, l_param);
msg_handled_ = TRUE;
handled = TRUE;
}
}
diff --git a/content/browser/renderer_host/legacy_render_widget_host_win.h b/content/browser/renderer_host/legacy_render_widget_host_win.h
index c478d6351ba160c76871ad657ede69b05b4e09ca..77631423937f7df7c52b4d3d309aa9335ab05bbb 100644
index f22af1f3e24033688a4f59666346075831df2243..50c66051efb0bfcb3c13e4ccb37dddfade9abb82 100644
--- a/content/browser/renderer_host/legacy_render_widget_host_win.h
+++ b/content/browser/renderer_host/legacy_render_widget_host_win.h
@@ -91,6 +91,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
CR_MESSAGE_HANDLER_EX(WM_NCHITTEST, OnNCHitTest)
CR_MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK,
OnMouseRange)
+ CR_MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseLeave)
CR_MESSAGE_HANDLER_EX(WM_NCCALCSIZE, OnNCCalcSize)
CR_MESSAGE_HANDLER_EX(WM_SIZE, OnSize)
CR_MESSAGE_HANDLER_EX(WM_DESTROY, OnDestroy)
@@ -102,6 +102,7 @@ class CONTENT_EXPORT LegacyRenderWidgetHostHWND
MESSAGE_HANDLER_EX(WM_VSCROLL, OnScroll)
MESSAGE_HANDLER_EX(WM_NCHITTEST, OnNCHitTest)
MESSAGE_RANGE_HANDLER(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange)
+ MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseLeave)
MESSAGE_HANDLER_EX(WM_NCCALCSIZE, OnNCCalcSize)
MESSAGE_HANDLER_EX(WM_SIZE, OnSize)
MESSAGE_HANDLER_EX(WM_DESTROY, OnDestroy)

View File

@@ -1278,7 +1278,7 @@ index eb81a70e4d5d5cd3e6ae9b45f8cd1c795ea76c51..dc30306f2c5d20503399fc3a8860773a
} // namespace sandbox
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index b39c4b213855c1028e0d8149a9f3d46080023d2f..5b844fca5705299df8c91c5e3fb9060d714782e9 100644
index d6a3fe5c93ab4dec202fa5bf83c55896b1bd6423..e046eb1b3e60fb8ef99922a6dff6c3701677bc22 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -312,6 +312,7 @@ component("core") {

File diff suppressed because it is too large Load Diff

View File

@@ -10,10 +10,10 @@ to handle this without patching, but this is fairly clean for now and no longer
patching legacy devtools code.
diff --git a/front_end/entrypoints/main/MainImpl.ts b/front_end/entrypoints/main/MainImpl.ts
index e5beed66e2c81c918b23287a190a628b416b5f6a..1d9b58c2ac3429e704df3b5f6d3dd3af405e8cb4 100644
index df915df956604163a9a7dda5dacb628899fe1015..1e449b06d96341ac8d1411b2760a7e2aeb087dca 100644
--- a/front_end/entrypoints/main/MainImpl.ts
+++ b/front_end/entrypoints/main/MainImpl.ts
@@ -729,6 +729,8 @@ export class MainImpl {
@@ -734,6 +734,8 @@ export class MainImpl {
globalThis.Main = globalThis.Main || {};
// @ts-ignore Exported for Tests.js
globalThis.Main.Main = MainImpl;

View File

@@ -51,3 +51,4 @@ fix_capture_embedder_exceptions_before_entering_v8.patch
spec_add_iterator_to_global_intrinsics.patch
fix_undici_incorrectly_copies_headers_onto_fetches.patch
src_preload_function_for_environment.patch
fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch

View File

@@ -0,0 +1,572 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Keeley Hammond <khammond@slack-corp.com>
Date: Mon, 19 Feb 2024 12:05:42 -0800
Subject: fix: revert "src,lb: reducing C++ calls of esm legacy main resolve"
This switch to native legacyMainResolve doesn't take asar into account, and can
cause errors when a project using ESM and asar tries to load a dependency which
uses commonJS. This will need to be fixed forward, but revert for Electron 29's
stable release to avoid potentially breaking apps with a riskier fix.
This patch can be removed when node's
native implementation has been patched
to recognize asar files.
This reverts commit 9cf2e1f55b8446a7cde23699d00a3be73aa0c8f1.
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
index ce8092b96aee8d09ff382110db4be62dcd760cce..fe0b6591e4c86b5fcbda4a1aac9c116e17920f05 100644
--- a/lib/internal/modules/esm/resolve.js
+++ b/lib/internal/modules/esm/resolve.js
@@ -36,10 +36,9 @@ const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
const experimentalNetworkImports =
getOptionValue('--experimental-network-imports');
const typeFlag = getOptionValue('--input-type');
-const { URL, pathToFileURL, fileURLToPath, isURL } = require('internal/url');
+const { URL, pathToFileURL, fileURLToPath, isURL, toPathIfFileURL } = require('internal/url');
const { getCWDURL } = require('internal/util');
const { canParse: URLCanParse } = internalBinding('url');
-const { legacyMainResolve: FSLegacyMainResolve } = internalBinding('fs');
const {
ERR_INPUT_TYPE_NOT_ALLOWED,
ERR_INVALID_ARG_TYPE,
@@ -136,34 +135,13 @@ function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
const realpathCache = new SafeMap();
-const legacyMainResolveExtensions = [
- '',
- '.js',
- '.json',
- '.node',
- '/index.js',
- '/index.json',
- '/index.node',
- './index.js',
- './index.json',
- './index.node',
-];
-
-const legacyMainResolveExtensionsIndexes = {
- // 0-6: when packageConfig.main is defined
- kResolvedByMain: 0,
- kResolvedByMainJs: 1,
- kResolvedByMainJson: 2,
- kResolvedByMainNode: 3,
- kResolvedByMainIndexJs: 4,
- kResolvedByMainIndexJson: 5,
- kResolvedByMainIndexNode: 6,
- // 7-9: when packageConfig.main is NOT defined,
- // or when the previous case didn't found the file
- kResolvedByPackageAndJs: 7,
- kResolvedByPackageAndJson: 8,
- kResolvedByPackageAndNode: 9,
-};
+/**
+ * @param {string | URL} url
+ * @returns {boolean}
+ */
+function fileExists(url) {
+ return internalModuleStat(toNamespacedPath(toPathIfFileURL(url))) === 0;
+}
/**
* Legacy CommonJS main resolution:
@@ -178,22 +156,44 @@ const legacyMainResolveExtensionsIndexes = {
* @returns {URL}
*/
function legacyMainResolve(packageJSONUrl, packageConfig, base) {
- const packageJsonUrlString = packageJSONUrl.href;
-
- if (typeof packageJsonUrlString !== 'string') {
- throw new ERR_INVALID_ARG_TYPE('packageJSONUrl', ['URL'], packageJSONUrl);
+ let guess;
+ if (packageConfig.main !== undefined) {
+ // Note: fs check redundances will be handled by Descriptor cache here.
+ if (fileExists(guess = new URL(`./${packageConfig.main}`,
+ packageJSONUrl))) {
+ return guess;
+ } else if (fileExists(guess = new URL(`./${packageConfig.main}.js`,
+ packageJSONUrl)));
+ else if (fileExists(guess = new URL(`./${packageConfig.main}.json`,
+ packageJSONUrl)));
+ else if (fileExists(guess = new URL(`./${packageConfig.main}.node`,
+ packageJSONUrl)));
+ else if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`,
+ packageJSONUrl)));
+ else if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`,
+ packageJSONUrl)));
+ else if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`,
+ packageJSONUrl)));
+ else guess = undefined;
+ if (guess) {
+ emitLegacyIndexDeprecation(guess, packageJSONUrl, base,
+ packageConfig.main);
+ return guess;
+ }
+ // Fallthrough.
}
-
- const baseStringified = isURL(base) ? base.href : base;
-
- const resolvedOption = FSLegacyMainResolve(packageJsonUrlString, packageConfig.main, baseStringified);
-
- const baseUrl = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ? `./${packageConfig.main}` : '';
- const resolvedUrl = new URL(baseUrl + legacyMainResolveExtensions[resolvedOption], packageJSONUrl);
-
- emitLegacyIndexDeprecation(resolvedUrl, packageJSONUrl, base, packageConfig.main);
-
- return resolvedUrl;
+ if (fileExists(guess = new URL('./index.js', packageJSONUrl)));
+ // So fs.
+ else if (fileExists(guess = new URL('./index.json', packageJSONUrl)));
+ else if (fileExists(guess = new URL('./index.node', packageJSONUrl)));
+ else guess = undefined;
+ if (guess) {
+ emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main);
+ return guess;
+ }
+ // Not found.
+ throw new ERR_MODULE_NOT_FOUND(
+ fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
}
const encodedSepRegEx = /%2F|%5C/i;
diff --git a/src/node_file.cc b/src/node_file.cc
index 59780dec1c4b6d157d2b04fea8c57cacce73ec3a..8f8629ed0b8cbc08a544211b63675ea0dcca1828 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -19,14 +19,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node_file.h" // NOLINT(build/include_inline)
-#include "ada.h"
#include "aliased_buffer-inl.h"
#include "memory_tracker-inl.h"
#include "node_buffer.h"
-#include "node_errors.h"
#include "node_external_reference.h"
#include "node_file-inl.h"
-#include "node_metadata.h"
#include "node_process-inl.h"
#include "node_stat_watcher.h"
#include "permission/permission.h"
@@ -3013,293 +3010,6 @@ static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
}
}
-static bool FileURLToPath(
- Environment* env,
- const ada::url_aggregator& file_url,
- /* The linter can't detect the assign for result_file_path
- So we need to ignore since it suggest to put const */
- // NOLINTNEXTLINE(runtime/references)
- std::string& result_file_path) {
- if (file_url.type != ada::scheme::FILE) {
- env->isolate()->ThrowException(ERR_INVALID_URL_SCHEME(env->isolate()));
-
- return false;
- }
-
- std::string_view pathname = file_url.get_pathname();
-#ifdef _WIN32
- size_t first_percent = std::string::npos;
- size_t pathname_size = pathname.size();
- std::string pathname_escaped_slash;
-
- for (size_t i = 0; i < pathname_size; i++) {
- if (pathname[i] == '/') {
- pathname_escaped_slash += '\\';
- } else {
- pathname_escaped_slash += pathname[i];
- }
-
- if (pathname[i] != '%') continue;
-
- if (first_percent == std::string::npos) {
- first_percent = i;
- }
-
- // just safe-guard against access the pathname
- // outside the bounds
- if ((i + 2) >= pathname_size) continue;
-
- char third = pathname[i + 2] | 0x20;
-
- bool is_slash = pathname[i + 1] == '2' && third == 102;
- bool is_forward_slash = pathname[i + 1] == '5' && third == 99;
-
- if (!is_slash && !is_forward_slash) continue;
-
- env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
- env->isolate(),
- "File URL path must not include encoded \\ or / characters"));
-
- return false;
- }
-
- std::string_view hostname = file_url.get_hostname();
- std::string decoded_pathname = ada::unicode::percent_decode(
- std::string_view(pathname_escaped_slash), first_percent);
-
- if (hostname.size() > 0) {
- // If hostname is set, then we have a UNC path
- // Pass the hostname through domainToUnicode just in case
- // it is an IDN using punycode encoding. We do not need to worry
- // about percent encoding because the URL parser will have
- // already taken care of that for us. Note that this only
- // causes IDNs with an appropriate `xn--` prefix to be decoded.
- result_file_path =
- "\\\\" + ada::unicode::to_unicode(hostname) + decoded_pathname;
-
- return true;
- }
-
- char letter = decoded_pathname[1] | 0x20;
- char sep = decoded_pathname[2];
-
- // a..z A..Z
- if (letter < 'a' || letter > 'z' || sep != ':') {
- env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
- env->isolate(), "File URL path must be absolute"));
-
- return false;
- }
-
- result_file_path = decoded_pathname.substr(1);
-
- return true;
-#else // _WIN32
- std::string_view hostname = file_url.get_hostname();
-
- if (hostname.size() > 0) {
- std::string error_message =
- std::string("File URL host must be \"localhost\" or empty on ") +
- std::string(per_process::metadata.platform);
- env->isolate()->ThrowException(
- ERR_INVALID_FILE_URL_HOST(env->isolate(), error_message.c_str()));
-
- return false;
- }
-
- size_t first_percent = std::string::npos;
- for (size_t i = 0; (i + 2) < pathname.size(); i++) {
- if (pathname[i] != '%') continue;
-
- if (first_percent == std::string::npos) {
- first_percent = i;
- }
-
- if (pathname[i + 1] == '2' && (pathname[i + 2] | 0x20) == 102) {
- env->isolate()->ThrowException(ERR_INVALID_FILE_URL_PATH(
- env->isolate(),
- "File URL path must not include encoded / characters"));
-
- return false;
- }
- }
-
- result_file_path = ada::unicode::percent_decode(pathname, first_percent);
-
- return true;
-#endif // _WIN32
-}
-
-BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
- Environment* env, const std::string& file_path) {
- THROW_IF_INSUFFICIENT_PERMISSIONS(
- env,
- permission::PermissionScope::kFileSystemRead,
- file_path,
- BindingData::FilePathIsFileReturnType::kThrowInsufficientPermissions);
-
- uv_fs_t req;
-
- int rc = uv_fs_stat(env->event_loop(), &req, file_path.c_str(), nullptr);
-
- if (rc == 0) {
- const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
- rc = !!(s->st_mode & S_IFDIR);
- }
-
- uv_fs_req_cleanup(&req);
-
- // rc is 0 if the path refers to a file
- if (rc == 0) return BindingData::FilePathIsFileReturnType::kIsFile;
-
- return BindingData::FilePathIsFileReturnType::kIsNotFile;
-}
-
-// the possible file extensions that should be tested
-// 0-6: when packageConfig.main is defined
-// 7-9: when packageConfig.main is NOT defined,
-// or when the previous case didn't found the file
-const std::array<std::string, 10> BindingData::legacy_main_extensions = {
- "",
- ".js",
- ".json",
- ".node",
- "/index.js",
- "/index.json",
- "/index.node",
- ".js",
- ".json",
- ".node"};
-
-void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
- CHECK_GE(args.Length(), 1);
- CHECK(args[0]->IsString());
-
- Environment* env = Environment::GetCurrent(args);
-
- Utf8Value utf8_package_json_url(env->isolate(), args[0].As<String>());
- auto package_json_url =
- ada::parse<ada::url_aggregator>(utf8_package_json_url.ToStringView());
-
- if (!package_json_url) {
- env->isolate()->ThrowException(
- ERR_INVALID_URL(env->isolate(), "Invalid URL"));
-
- return;
- }
-
- ada::result<ada::url_aggregator> file_path_url;
- std::string initial_file_path;
- std::string file_path;
-
- if (args.Length() >= 2 && !args[1]->IsNullOrUndefined() &&
- args[1]->IsString()) {
- std::string package_config_main =
- Utf8Value(env->isolate(), args[1].As<String>()).ToString();
-
- file_path_url = ada::parse<ada::url_aggregator>(
- std::string("./") + package_config_main, &package_json_url.value());
-
- if (!file_path_url) {
- env->isolate()->ThrowException(
- ERR_INVALID_URL(env->isolate(), "Invalid URL"));
-
- return;
- }
-
- if (!FileURLToPath(env, file_path_url.value(), initial_file_path)) return;
-
- FromNamespacedPath(&initial_file_path);
-
- for (int i = 0; i < BindingData::legacy_main_extensions_with_main_end;
- i++) {
- file_path = initial_file_path + BindingData::legacy_main_extensions[i];
-
- switch (FilePathIsFile(env, file_path)) {
- case BindingData::FilePathIsFileReturnType::kIsFile:
- return args.GetReturnValue().Set(i);
- case BindingData::FilePathIsFileReturnType::kIsNotFile:
- continue;
- case BindingData::FilePathIsFileReturnType::
- kThrowInsufficientPermissions:
- // the default behavior when do not have permission is to return
- // and exit the execution of the method as soon as possible
- // the internal function will throw the exception
- return;
- default:
- UNREACHABLE();
- }
- }
- }
-
- file_path_url =
- ada::parse<ada::url_aggregator>("./index", &package_json_url.value());
-
- if (!file_path_url) {
- env->isolate()->ThrowException(
- ERR_INVALID_URL(env->isolate(), "Invalid URL"));
-
- return;
- }
-
- if (!FileURLToPath(env, file_path_url.value(), initial_file_path)) return;
-
- FromNamespacedPath(&initial_file_path);
-
- for (int i = BindingData::legacy_main_extensions_with_main_end;
- i < BindingData::legacy_main_extensions_package_fallback_end;
- i++) {
- file_path = initial_file_path + BindingData::legacy_main_extensions[i];
-
- switch (FilePathIsFile(env, file_path)) {
- case BindingData::FilePathIsFileReturnType::kIsFile:
- return args.GetReturnValue().Set(i);
- case BindingData::FilePathIsFileReturnType::kIsNotFile:
- continue;
- case BindingData::FilePathIsFileReturnType::kThrowInsufficientPermissions:
- // the default behavior when do not have permission is to return
- // and exit the execution of the method as soon as possible
- // the internal function will throw the exception
- return;
- default:
- UNREACHABLE();
- }
- }
-
- std::string module_path;
- std::string module_base;
-
- if (!FileURLToPath(env, package_json_url.value(), module_path)) return;
-
- if (args.Length() >= 3 && !args[2]->IsNullOrUndefined() &&
- args[2]->IsString()) {
- Utf8Value utf8_base_path(env->isolate(), args[2].As<String>());
- auto base_url =
- ada::parse<ada::url_aggregator>(utf8_base_path.ToStringView());
-
- if (!base_url) {
- env->isolate()->ThrowException(
- ERR_INVALID_URL(env->isolate(), "Invalid URL"));
-
- return;
- }
-
- if (!FileURLToPath(env, base_url.value(), module_base)) return;
- } else {
- std::string err_arg_message =
- "The \"base\" argument must be of type string or an instance of URL.";
- env->isolate()->ThrowException(
- ERR_INVALID_ARG_TYPE(env->isolate(), err_arg_message.c_str()));
- return;
- }
-
- env->isolate()->ThrowException(
- ERR_MODULE_NOT_FOUND(env->isolate(),
- "Cannot find package '%s' imported from %s",
- module_path,
- module_base));
-}
-
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackField("stats_field_array", stats_field_array);
tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array);
@@ -3399,19 +3109,6 @@ InternalFieldInfoBase* BindingData::Serialize(int index) {
return info;
}
-void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
- Local<ObjectTemplate> target) {
- Isolate* isolate = isolate_data->isolate();
-
- SetMethod(
- isolate, target, "legacyMainResolve", BindingData::LegacyMainResolve);
-}
-
-void BindingData::RegisterExternalReferences(
- ExternalReferenceRegistry* registry) {
- registry->Register(BindingData::LegacyMainResolve);
-}
-
static void CreatePerIsolateProperties(IsolateData* isolate_data,
Local<ObjectTemplate> target) {
Isolate* isolate = isolate_data->isolate();
@@ -3468,7 +3165,6 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
SetMethod(isolate, target, "mkdtemp", Mkdtemp);
StatWatcher::CreatePerIsolateProperties(isolate_data, target);
- BindingData::CreatePerIsolateProperties(isolate_data, target);
target->Set(
FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
@@ -3542,7 +3238,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(Access);
registry->Register(AccessSync);
StatWatcher::RegisterExternalReferences(registry);
- BindingData::RegisterExternalReferences(registry);
registry->Register(Close);
registry->Register(CloseSync);
diff --git a/src/node_file.h b/src/node_file.h
index 4599546c5245300346557b68070c60292daaed23..7b43d027a2e6524f3ec6b7bccdb6e49a3c8790ea 100644
--- a/src/node_file.h
+++ b/src/node_file.h
@@ -63,13 +63,6 @@ class BindingData : public SnapshotableObject {
AliasedBufferIndex statfs_field_array;
AliasedBufferIndex statfs_field_bigint_array;
};
-
- enum class FilePathIsFileReturnType {
- kIsFile = 0,
- kIsNotFile,
- kThrowInsufficientPermissions
- };
-
explicit BindingData(Realm* realm,
v8::Local<v8::Object> wrap,
InternalFieldInfo* info = nullptr);
@@ -86,30 +79,12 @@ class BindingData : public SnapshotableObject {
SERIALIZABLE_OBJECT_METHODS()
SET_BINDING_ID(fs_binding_data)
- static void LegacyMainResolve(
- const v8::FunctionCallbackInfo<v8::Value>& args);
-
- static void CreatePerIsolateProperties(IsolateData* isolate_data,
- v8::Local<v8::ObjectTemplate> ctor);
- static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
-
void MemoryInfo(MemoryTracker* tracker) const override;
SET_SELF_SIZE(BindingData)
SET_MEMORY_INFO_NAME(BindingData)
private:
InternalFieldInfo* internal_field_info_ = nullptr;
-
- static FilePathIsFileReturnType FilePathIsFile(Environment* env,
- const std::string& file_path);
-
- static const std::array<std::string, 10> legacy_main_extensions;
- // define the final index of the algorithm resolution
- // when packageConfig.main is defined.
- static const uint8_t legacy_main_extensions_with_main_end = 7;
- // define the final index of the algorithm resolution
- // when packageConfig.main is NOT defined
- static const uint8_t legacy_main_extensions_package_fallback_end = 10;
};
// structure used to store state during a complex operation, e.g., mkdirp.
diff --git a/test/es-module/test-cjs-legacyMainResolve.js b/test/es-module/test-cjs-legacyMainResolve.js
index 1dc7d8faafe6eb5cea7e43e9783041f2a994be0d..d86d501689b2b72f2b964d6e2a91c5d36b6b62f5 100644
--- a/test/es-module/test-cjs-legacyMainResolve.js
+++ b/test/es-module/test-cjs-legacyMainResolve.js
@@ -82,7 +82,7 @@ describe('legacyMainResolve', () => {
{},
''
),
- { message: /instance of URL/, code: 'ERR_INVALID_ARG_TYPE' },
+ { message: 'Invalid URL', code: 'ERR_INVALID_URL' },
);
});
@@ -129,7 +129,7 @@ describe('legacyMainResolve', () => {
);
assert.throws(
() => legacyMainResolve(packageJsonUrl, { main: null }, packageJsonUrl),
- { code: 'ERR_MODULE_NOT_FOUND' },
+ { code: 'ERR_INTERNAL_ASSERTION' },
);
});
@@ -137,7 +137,7 @@ describe('legacyMainResolve', () => {
const packageJsonUrl = pathToFileURL('/c/file%20with%20percents/package.json');
assert.throws(
() => legacyMainResolve(packageJsonUrl, { main: null }, packageJsonUrl),
- { code: 'ERR_MODULE_NOT_FOUND' },
+ { code: 'ERR_INTERNAL_ASSERTION' },
);
});
@@ -150,7 +150,7 @@ describe('legacyMainResolve', () => {
);
assert.throws(
() => legacyMainResolve(packageJsonUrl, { main: null }, undefined),
- { message: /"base" argument must be/, code: 'ERR_INVALID_ARG_TYPE' },
+ { message: 'The "path" argument must be of type string or an instance of URL. Received undefined', code: 'ERR_INVALID_ARG_TYPE' },
);
});
});

View File

@@ -13,7 +13,10 @@ import re
import subprocess
import sys
from .patches import PATCH_FILENAME_PREFIX, is_patch_location_line
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(SCRIPT_DIR)
from patches import PATCH_FILENAME_PREFIX, is_patch_location_line
UPSTREAM_HEAD='refs/patches/upstream-head'

View File

@@ -26,6 +26,9 @@
#include "chrome/browser/icon_manager.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_paths.h"
#include "components/proxy_config/proxy_config_dictionary.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "components/proxy_config/proxy_prefs.h"
#include "content/browser/gpu/compositor_util.h" // nogncheck
#include "content/browser/gpu/gpu_data_manager_impl.h" // nogncheck
#include "content/public/browser/browser_accessibility_state.h"
@@ -1472,6 +1475,98 @@ void App::EnableSandbox(gin_helper::ErrorThrower thrower) {
command_line->AppendSwitch(switches::kEnableSandbox);
}
v8::Local<v8::Promise> App::SetProxy(gin::Arguments* args) {
v8::Isolate* isolate = args->isolate();
gin_helper::Promise<void> promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
gin_helper::Dictionary options;
args->GetNext(&options);
if (!Browser::Get()->is_ready()) {
promise.RejectWithErrorMessage(
"app.setProxy() can only be called after app is ready.");
return handle;
}
if (!g_browser_process->local_state()) {
promise.RejectWithErrorMessage(
"app.setProxy() failed due to internal error.");
return handle;
}
std::string mode, proxy_rules, bypass_list, pac_url;
options.Get("pacScript", &pac_url);
options.Get("proxyRules", &proxy_rules);
options.Get("proxyBypassRules", &bypass_list);
ProxyPrefs::ProxyMode proxy_mode = ProxyPrefs::MODE_FIXED_SERVERS;
if (!options.Get("mode", &mode)) {
// pacScript takes precedence over proxyRules.
if (!pac_url.empty()) {
proxy_mode = ProxyPrefs::MODE_PAC_SCRIPT;
}
} else if (!ProxyPrefs::StringToProxyMode(mode, &proxy_mode)) {
promise.RejectWithErrorMessage(
"Invalid mode, must be one of direct, auto_detect, pac_script, "
"fixed_servers or system");
return handle;
}
base::Value::Dict proxy_config;
switch (proxy_mode) {
case ProxyPrefs::MODE_DIRECT:
proxy_config = ProxyConfigDictionary::CreateDirect();
break;
case ProxyPrefs::MODE_SYSTEM:
proxy_config = ProxyConfigDictionary::CreateSystem();
break;
case ProxyPrefs::MODE_AUTO_DETECT:
proxy_config = ProxyConfigDictionary::CreateAutoDetect();
break;
case ProxyPrefs::MODE_PAC_SCRIPT:
proxy_config = ProxyConfigDictionary::CreatePacScript(pac_url, true);
break;
case ProxyPrefs::MODE_FIXED_SERVERS:
proxy_config =
ProxyConfigDictionary::CreateFixedServers(proxy_rules, bypass_list);
break;
default:
NOTIMPLEMENTED();
}
static_cast<BrowserProcessImpl*>(g_browser_process)
->in_memory_pref_store()
->SetValue(proxy_config::prefs::kProxy,
base::Value{std::move(proxy_config)},
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
g_browser_process->system_network_context_manager()
->GetContext()
->ForceReloadProxyConfig(base::BindOnce(
gin_helper::Promise<void>::ResolvePromise, std::move(promise)));
return handle;
}
v8::Local<v8::Promise> App::ResolveProxy(gin::Arguments* args) {
v8::Isolate* isolate = args->isolate();
gin_helper::Promise<std::string> promise(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
GURL url;
args->GetNext(&url);
static_cast<BrowserProcessImpl*>(g_browser_process)
->GetResolveProxyHelper()
->ResolveProxy(
url, base::BindOnce(gin_helper::Promise<std::string>::ResolvePromise,
std::move(promise)));
return handle;
}
void App::SetUserAgentFallback(const std::string& user_agent) {
ElectronBrowserClient::Get()->SetUserAgent(user_agent);
}
@@ -1681,7 +1776,7 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) {
.SetMethod("setBadgeCount",
base::BindRepeating(&Browser::SetBadgeCount, browser))
.SetMethod("getBadgeCount",
base::BindRepeating(&Browser::GetBadgeCount, browser))
base::BindRepeating(&Browser::badge_count, browser))
.SetMethod("getLoginItemSettings", &App::GetLoginItemSettings)
.SetMethod("setLoginItemSettings",
base::BindRepeating(&Browser::SetLoginItemSettings, browser))
@@ -1776,7 +1871,9 @@ gin::ObjectTemplateBuilder App::GetObjectTemplateBuilder(v8::Isolate* isolate) {
.SetProperty("userAgentFallback", &App::GetUserAgentFallback,
&App::SetUserAgentFallback)
.SetMethod("configureHostResolver", &ConfigureHostResolver)
.SetMethod("enableSandbox", &App::EnableSandbox);
.SetMethod("enableSandbox", &App::EnableSandbox)
.SetMethod("setProxy", &App::SetProxy)
.SetMethod("resolveProxy", &App::ResolveProxy);
}
const char* App::GetTypeName() {

View File

@@ -222,6 +222,8 @@ class App : public ElectronBrowserClient::Delegate,
void EnableSandbox(gin_helper::ErrorThrower thrower);
void SetUserAgentFallback(const std::string& user_agent);
std::string GetUserAgentFallback();
v8::Local<v8::Promise> SetProxy(gin::Arguments* args);
v8::Local<v8::Promise> ResolveProxy(gin::Arguments* args);
#if BUILDFLAG(IS_MAC)
void SetActivationPolicy(gin_helper::ErrorThrower thrower,

View File

@@ -299,6 +299,7 @@ v8::Local<v8::Promise> Cookies::Set(v8::Isolate* isolate,
const std::string* domain = details.FindString("domain");
const std::string* path = details.FindString("path");
bool http_only = details.FindBool("httpOnly").value_or(false);
bool same_party = details.FindBool("sameParty").value_or(false);
const std::string* same_site_string = details.FindString("sameSite");
net::CookieSameSite same_site;
std::string error = StringToCookieSameSite(same_site_string, &same_site);
@@ -323,8 +324,8 @@ v8::Local<v8::Promise> Cookies::Set(v8::Isolate* isolate,
path ? *path : "", ParseTimeProperty(details.FindDouble("creationDate")),
ParseTimeProperty(details.FindDouble("expirationDate")),
ParseTimeProperty(details.FindDouble("lastAccessDate")), secure,
http_only, same_site, net::COOKIE_PRIORITY_DEFAULT, std::nullopt,
&status);
http_only, same_site, net::COOKIE_PRIORITY_DEFAULT, same_party,
std::nullopt, &status);
if (!canonical_cookie || !canonical_cookie->IsCanonical()) {
promise.RejectWithErrorMessage(InclusionStatusToString(

View File

@@ -305,7 +305,8 @@ void DesktopCapturer::StartHandling(bool capture_window,
window_capturer_->SetThumbnailSize(thumbnail_size);
#if BUILDFLAG(IS_MAC)
window_capturer_->skip_next_refresh_ =
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kWindow);
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kWindow) ? 2
: 0;
#endif
OnceCallback update_callback = base::BindOnce(
@@ -334,7 +335,8 @@ void DesktopCapturer::StartHandling(bool capture_window,
screen_capturer_->SetThumbnailSize(thumbnail_size);
#if BUILDFLAG(IS_MAC)
screen_capturer_->skip_next_refresh_ =
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kScreen);
ShouldUseThumbnailCapturerMac(DesktopMediaList::Type::kScreen) ? 2
: 0;
#endif
OnceCallback update_callback = base::BindOnce(

View File

@@ -31,7 +31,7 @@ bool IsEncryptionAvailable() {
return OSCrypt::IsEncryptionAvailable() ||
(use_password_v10 &&
static_cast<BrowserProcessImpl*>(g_browser_process)
->GetLinuxStorageBackend() == "basic_text");
->linux_storage_backend() == "basic_text");
#else
return OSCrypt::IsEncryptionAvailable();
#endif
@@ -46,7 +46,7 @@ std::string GetSelectedLinuxBackend() {
if (!Browser::Get()->is_ready())
return "unknown";
return static_cast<BrowserProcessImpl*>(g_browser_process)
->GetLinuxStorageBackend();
->linux_storage_backend();
}
#endif

View File

@@ -859,7 +859,7 @@ WebContents::WebContents(v8::Isolate* isolate,
session_.Reset(isolate, session.ToV8());
std::unique_ptr<content::WebContents> web_contents;
if (IsGuest()) {
if (is_guest()) {
scoped_refptr<content::SiteInstance> site_instance =
content::SiteInstance::CreateForURL(session->browser_context(),
GURL("chrome-guest://fake-host"));
@@ -929,7 +929,7 @@ void WebContents::InitWithSessionAndOptions(
const gin_helper::Dictionary& options) {
Observe(owned_web_contents.get());
InitWithWebContents(std::move(owned_web_contents), session->browser_context(),
IsGuest());
is_guest());
inspectable_web_contents_->GetView()->SetDelegate(this);
@@ -989,7 +989,7 @@ void WebContents::InitWithSessionAndOptions(
SetUserAgent(GetBrowserContext()->GetUserAgent());
if (IsGuest()) {
if (is_guest()) {
NativeWindow* owner_window = nullptr;
if (embedder_) {
// New WebContents's owner_window is the embedder's owner_window.
@@ -1024,7 +1024,7 @@ void WebContents::InitWithExtensionView(v8::Isolate* isolate,
// Allow toggling DevTools for background pages
Observe(web_contents);
InitWithWebContents(std::unique_ptr<content::WebContents>(web_contents),
GetBrowserContext(), IsGuest());
GetBrowserContext(), is_guest());
inspectable_web_contents_->GetView()->SetDelegate(this);
}
#endif
@@ -1073,7 +1073,7 @@ WebContents::~WebContents() {
// For guest view based on OOPIF, the WebContents is released by the embedder
// frame, and we need to clear the reference to the memory.
bool not_owned_by_this = IsGuest() && attached_;
bool not_owned_by_this = is_guest() && attached_;
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// And background pages are owned by extensions::ExtensionHost.
if (type_ == Type::kBackgroundPage)
@@ -1103,7 +1103,7 @@ void WebContents::DeleteThisIfAlive() {
void WebContents::Destroy() {
// The content::WebContents should be destroyed asynchronously when possible
// as user may choose to destroy WebContents during an event of it.
if (Browser::Get()->is_shutting_down() || IsGuest()) {
if (Browser::Get()->is_shutting_down() || is_guest()) {
DeleteThisIfAlive();
} else {
content::GetUIThreadTaskRunner({})->PostTask(
@@ -1317,7 +1317,7 @@ void WebContents::CloseContents(content::WebContents* source) {
observer.OnCloseContents();
// This is handled by the embedder frame.
if (!IsGuest())
if (!is_guest())
Destroy();
}
@@ -1631,7 +1631,7 @@ void WebContents::HandleNewRenderFrame(
auto* web_preferences = WebContentsPreferences::From(web_contents());
if (web_preferences) {
auto maybe_color = web_preferences->GetBackgroundColor();
bool guest = IsGuest() || type_ == Type::kBrowserView;
bool guest = is_guest() || type_ == Type::kBrowserView;
// If webPreferences has no color stored we need to explicitly set guest
// webContents background color to transparent.
@@ -2134,7 +2134,7 @@ void WebContents::DidFinishNavigation(
Emit("did-navigate", url, http_response_code, http_status_text);
}
}
if (IsGuest())
if (is_guest())
Emit("load-commit", url, is_main_frame);
} else {
auto url = navigation_handle->GetURL();
@@ -2348,10 +2348,6 @@ base::ProcessId WebContents::GetOSProcessID() const {
return base::GetProcId(process_handle);
}
WebContents::Type WebContents::GetType() const {
return type_;
}
bool WebContents::Equal(const WebContents* web_contents) const {
return ID() == web_contents->ID();
}
@@ -3345,7 +3341,7 @@ bool WebContents::IsFocused() const {
if (!view)
return false;
if (GetType() != Type::kBackgroundPage) {
if (type() != Type::kBackgroundPage) {
auto* window = web_contents()->GetNativeView()->GetToplevelWindow();
if (window && !window->IsVisible())
return false;
@@ -3541,10 +3537,6 @@ void WebContents::OnCursorChanged(const ui::Cursor& cursor) {
}
}
bool WebContents::IsGuest() const {
return type_ == Type::kWebView;
}
void WebContents::AttachToIframe(content::WebContents* embedder_web_contents,
int embedder_frame_id) {
attached_ = true;
@@ -4260,7 +4252,7 @@ void WebContents::UpdateHtmlApiFullscreen(bool fullscreen) {
}
// Make sure all child webviews quit html fullscreen.
if (!fullscreen && !IsGuest()) {
if (!fullscreen && !is_guest()) {
auto* manager = WebViewManager::GetWebViewManager(web_contents());
manager->ForEachGuest(web_contents(), [&](content::WebContents* guest) {
WebContents* api_web_contents = WebContents::From(guest);
@@ -4372,7 +4364,7 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate,
.SetMethod("getZoomLevel", &WebContents::GetZoomLevel)
.SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
.SetMethod("getZoomFactor", &WebContents::GetZoomFactor)
.SetMethod("getType", &WebContents::GetType)
.SetMethod("getType", &WebContents::type)
.SetMethod("_getPreloadPaths", &WebContents::GetPreloadPaths)
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)

View File

@@ -169,7 +169,7 @@ class WebContents : public ExclusiveAccessContext,
void SetBackgroundThrottling(bool allowed);
int GetProcessID() const;
base::ProcessId GetOSProcessID() const;
Type GetType() const;
[[nodiscard]] Type type() const { return type_; }
bool Equal(const WebContents* web_contents) const;
void LoadURL(const GURL& url, const gin_helper::Dictionary& options);
void Reload();
@@ -288,7 +288,7 @@ class WebContents : public ExclusiveAccessContext,
v8::Local<v8::Promise> CapturePage(gin::Arguments* args);
// Methods for creating <webview>.
bool IsGuest() const;
[[nodiscard]] bool is_guest() const { return type_ == Type::kWebView; }
void AttachToIframe(content::WebContents* embedder_web_contents,
int embedder_frame_id);
void DetachFromOuterFrame();

View File

@@ -24,7 +24,7 @@ bool WebContents::IsFocused() const {
if (!view)
return false;
if (GetType() != Type::kBackgroundPage) {
if (type() != Type::kBackgroundPage) {
auto window = [web_contents()->GetNativeView().GetNativeNSView() window];
// On Mac the render widget host view does not lose focus when the window
// loses focus so check if the top level window is the key window.

View File

@@ -21,7 +21,8 @@ BadgeManager* BadgeManagerFactory::GetForBrowserContext(
// static
BadgeManagerFactory* BadgeManagerFactory::GetInstance() {
return base::Singleton<BadgeManagerFactory>::get();
static base::NoDestructor<BadgeManagerFactory> instance;
return instance.get();
}
BadgeManagerFactory::BadgeManagerFactory()

View File

@@ -9,7 +9,7 @@
namespace base {
template <typename T>
struct DefaultSingletonTraits;
class NoDestructor;
}
namespace badging {
@@ -30,7 +30,7 @@ class BadgeManagerFactory : public BrowserContextKeyedServiceFactory {
BadgeManagerFactory& operator=(const BadgeManagerFactory&) = delete;
private:
friend struct base::DefaultSingletonTraits<BadgeManagerFactory>;
friend base::NoDestructor<BadgeManagerFactory>;
BadgeManagerFactory();
~BadgeManagerFactory() override;

View File

@@ -159,10 +159,6 @@ void Browser::SetName(const std::string& name) {
OverriddenApplicationName() = name;
}
int Browser::GetBadgeCount() {
return badge_count_;
}
bool Browser::OpenFile(const std::string& file_path) {
bool prevent_default = false;
for (BrowserObserver& observer : observers_)

View File

@@ -110,7 +110,7 @@ class Browser : public WindowListObserver {
// Set/Get the badge count.
bool SetBadgeCount(std::optional<int> count);
int GetBadgeCount();
[[nodiscard]] int badge_count() const { return badge_count_; }
#if BUILDFLAG(IS_WIN)
struct LaunchItem {

View File

@@ -37,6 +37,7 @@
#include "net/proxy_resolution/proxy_config_with_annotation.h"
#include "services/device/public/cpp/geolocation/geolocation_manager.h"
#include "services/network/public/cpp/network_switches.h"
#include "shell/browser/net/resolve_proxy_helper.h"
#include "shell/common/electron_paths.h"
#include "shell/common/thread_restrictions.h"
@@ -100,9 +101,9 @@ void BrowserProcessImpl::PostEarlyInitialization() {
OSCrypt::RegisterLocalPrefs(pref_registry.get());
#endif
auto pref_store = base::MakeRefCounted<ValueMapPrefStore>();
ApplyProxyModeFromCommandLine(pref_store.get());
prefs_factory.set_command_line_prefs(std::move(pref_store));
in_memory_pref_store_ = base::MakeRefCounted<ValueMapPrefStore>();
ApplyProxyModeFromCommandLine(in_memory_pref_store());
prefs_factory.set_command_line_prefs(in_memory_pref_store());
// Only use a persistent prefs store when cookie encryption is enabled as that
// is the only key that needs it
@@ -316,6 +317,14 @@ const std::string& BrowserProcessImpl::GetSystemLocale() const {
return system_locale_;
}
electron::ResolveProxyHelper* BrowserProcessImpl::GetResolveProxyHelper() {
if (!resolve_proxy_helper_) {
resolve_proxy_helper_ = base::MakeRefCounted<electron::ResolveProxyHelper>(
system_network_context_manager()->GetContext());
}
return resolve_proxy_helper_.get();
}
#if BUILDFLAG(IS_LINUX)
void BrowserProcessImpl::SetLinuxStorageBackend(
os_crypt::SelectedLinuxBackend selected_backend) {
@@ -340,10 +349,6 @@ void BrowserProcessImpl::SetLinuxStorageBackend(
break;
}
}
const std::string& BrowserProcessImpl::GetLinuxStorageBackend() const {
return selected_linux_storage_backend_;
}
#endif // BUILDFLAG(IS_LINUX)
void BrowserProcessImpl::SetApplicationLocale(const std::string& locale) {

View File

@@ -31,6 +31,10 @@ namespace printing {
class PrintJobManager;
}
namespace electron {
class ResolveProxyHelper;
}
// Empty definition for std::unique_ptr, rather than a forward declaration
class BackgroundModeManager {};
@@ -53,13 +57,15 @@ class BrowserProcessImpl : public BrowserProcess {
void PreMainMessageLoopRun();
void PostDestroyThreads() {}
void PostMainMessageLoopRun();
void SetSystemLocale(const std::string& locale);
const std::string& GetSystemLocale() const;
electron::ResolveProxyHelper* GetResolveProxyHelper();
#if BUILDFLAG(IS_LINUX)
void SetLinuxStorageBackend(os_crypt::SelectedLinuxBackend selected_backend);
const std::string& GetLinuxStorageBackend() const;
[[nodiscard]] const std::string& linux_storage_backend() const {
return selected_linux_storage_backend_;
}
#endif
void EndSession() override {}
@@ -121,6 +127,10 @@ class BrowserProcessImpl : public BrowserProcess {
printing::PrintJobManager* print_job_manager() override;
StartupData* startup_data() override;
ValueMapPrefStore* in_memory_pref_store() const {
return in_memory_pref_store_.get();
}
private:
void CreateNetworkQualityObserver();
void CreateOSCryptAsync();
@@ -137,6 +147,8 @@ class BrowserProcessImpl : public BrowserProcess {
#endif
embedder_support::OriginTrialsSettingsStorage origin_trials_settings_storage_;
scoped_refptr<ValueMapPrefStore> in_memory_pref_store_;
scoped_refptr<electron::ResolveProxyHelper> resolve_proxy_helper_;
std::unique_ptr<network::NetworkQualityTracker> network_quality_tracker_;
std::unique_ptr<
network::NetworkQualityTracker::RTTAndThroughputEstimatesObserver>

View File

@@ -527,7 +527,8 @@ ElectronBrowserContext::GetReduceAcceptLanguageControllerDelegate() {
ResolveProxyHelper* ElectronBrowserContext::GetResolveProxyHelper() {
if (!resolve_proxy_helper_) {
resolve_proxy_helper_ = base::MakeRefCounted<ResolveProxyHelper>(this);
resolve_proxy_helper_ = base::MakeRefCounted<ResolveProxyHelper>(
GetDefaultStoragePartition()->GetNetworkContext());
}
return resolve_proxy_helper_.get();
}

View File

@@ -4,6 +4,7 @@
#include "shell/browser/extensions/electron_extension_system_factory.h"
#include "base/no_destructor.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "extensions/browser/extension_prefs_factory.h"
#include "extensions/browser/extension_registry_factory.h"
@@ -21,7 +22,8 @@ ExtensionSystem* ElectronExtensionSystemFactory::GetForBrowserContext(
// static
ElectronExtensionSystemFactory* ElectronExtensionSystemFactory::GetInstance() {
return base::Singleton<ElectronExtensionSystemFactory>::get();
static base::NoDestructor<ElectronExtensionSystemFactory> instance;
return instance.get();
}
ElectronExtensionSystemFactory::ElectronExtensionSystemFactory()

View File

@@ -5,9 +5,13 @@
#ifndef ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_EXTENSION_SYSTEM_FACTORY_H_
#define ELECTRON_SHELL_BROWSER_EXTENSIONS_ELECTRON_EXTENSION_SYSTEM_FACTORY_H_
#include "base/memory/singleton.h"
#include "extensions/browser/extension_system_provider.h"
namespace base {
template <typename T>
class NoDestructor;
} // namespace base
namespace extensions {
// A factory that provides ElectronExtensionSystem.
@@ -26,7 +30,7 @@ class ElectronExtensionSystemFactory : public ExtensionSystemProvider {
const ElectronExtensionSystemFactory&) = delete;
private:
friend struct base::DefaultSingletonTraits<ElectronExtensionSystemFactory>;
friend base::NoDestructor<ElectronExtensionSystemFactory>;
ElectronExtensionSystemFactory();
~ElectronExtensionSystemFactory() override;

View File

@@ -49,6 +49,11 @@ void InitializeFeatureList() {
// 'custom dictionary word list API' spec to crash.
std::string(",") + spellcheck::kWinDelaySpellcheckServiceInit.name;
#endif
std::string platform_specific_enable_features =
EnablePlatformSpecificFeatures();
if (platform_specific_enable_features.size() > 0) {
enable_features += std::string(",") + platform_specific_enable_features;
}
base::FeatureList::InitInstance(enable_features, disable_features);
}
@@ -60,4 +65,10 @@ void InitializeFieldTrials() {
base::FieldTrialList::CreateTrialsFromString(force_fieldtrials);
}
#if !BUILDFLAG(IS_MAC)
std::string EnablePlatformSpecificFeatures() {
return "";
}
#endif
} // namespace electron

View File

@@ -5,9 +5,12 @@
#ifndef ELECTRON_SHELL_BROWSER_FEATURE_LIST_H_
#define ELECTRON_SHELL_BROWSER_FEATURE_LIST_H_
#include <string>
namespace electron {
void InitializeFeatureList();
void InitializeFieldTrials();
std::string EnablePlatformSpecificFeatures();
} // namespace electron
#endif // ELECTRON_SHELL_BROWSER_FEATURE_LIST_H_

View File

@@ -0,0 +1,28 @@
// Copyright (c) 2024 Salesforce, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "electron/shell/browser/feature_list.h"
#include <string>
namespace electron {
std::string EnablePlatformSpecificFeatures() {
if (@available(macOS 14.4, *)) {
// These flags aren't exported so reference them by name directly, they are
// used to ensure that screen and window capture exclusive use
// ScreenCaptureKit APIs to avoid warning dialogs on macOS 14.4 and higher.
// kScreenCaptureKitPickerScreen,
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
// kScreenCaptureKitStreamPickerSonoma,
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
// kThumbnailCapturerMac,
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
return "ScreenCaptureKitPickerScreen,ScreenCaptureKitStreamPickerSonoma,"
"ThumbnailCapturerMac:capture_mode/sc_screenshot_manager";
}
return "";
}
} // namespace electron

View File

@@ -3,7 +3,7 @@
// found in the LICENSE-CHROMIUM file.
#include "shell/browser/media/media_capture_devices_dispatcher.h"
// #include "base/no_destructor.h"
#include "base/logging.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/media_capture_devices.h"
@@ -13,7 +13,8 @@ using content::BrowserThread;
namespace electron {
MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() {
return base::Singleton<MediaCaptureDevicesDispatcher>::get();
static base::NoDestructor<MediaCaptureDevicesDispatcher> instance;
return instance.get();
}
MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher() {

View File

@@ -5,7 +5,6 @@
#ifndef ELECTRON_SHELL_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
#define ELECTRON_SHELL_BROWSER_MEDIA_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
#include "base/memory/singleton.h"
#include "components/webrtc/media_stream_device_enumerator_impl.h"
#include "content/public/browser/media_observer.h"
#include "content/public/browser/media_stream_request.h"
@@ -45,7 +44,7 @@ class MediaCaptureDevicesDispatcher
const MediaCaptureDevicesDispatcher&) = delete;
private:
friend struct base::DefaultSingletonTraits<MediaCaptureDevicesDispatcher>;
friend base::NoDestructor<MediaCaptureDevicesDispatcher>;
MediaCaptureDevicesDispatcher();
~MediaCaptureDevicesDispatcher() override;

View File

@@ -518,14 +518,6 @@ bool NativeWindow::IsMenuBarVisible() const {
return true;
}
double NativeWindow::GetAspectRatio() const {
return aspect_ratio_;
}
gfx::Size NativeWindow::GetAspectRatioExtraSize() const {
return aspect_ratio_extraSize_;
}
void NativeWindow::SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) {
aspect_ratio_ = aspect_ratio;
@@ -763,6 +755,11 @@ int NativeWindow::NonClientHitTest(const gfx::Point& point) {
}
#endif
// This is to disable dragging in HTML5 full screen mode.
// Details: https://github.com/electron/electron/issues/41002
if (GetWidget()->IsFullscreen())
return HTNOWHERE;
for (auto* provider : draggable_region_providers_) {
int hit = provider->NonClientHitTest(point);
if (hit != HTNOWHERE)

View File

@@ -265,8 +265,10 @@ class NativeWindow : public base::SupportsUserData,
virtual bool IsMenuBarVisible() const;
// Set the aspect ratio when resizing window.
double GetAspectRatio() const;
gfx::Size GetAspectRatioExtraSize() const;
[[nodiscard]] double aspect_ratio() const { return aspect_ratio_; }
[[nodiscard]] gfx::Size aspect_ratio_extra_size() const {
return aspect_ratio_extraSize_;
}
virtual void SetAspectRatio(double aspect_ratio, const gfx::Size& extra_size);
// File preview APIs.

View File

@@ -649,7 +649,7 @@ bool NativeWindowMac::IsMaximized() const {
if (HasStyleMask(NSWindowStyleMaskResizable) != 0)
return [window_ isZoomed];
NSRect rectScreen = GetAspectRatio() > 0.0
NSRect rectScreen = aspect_ratio() > 0.0
? default_frame_for_zoom()
: [[NSScreen mainScreen] visibleFrame];

View File

@@ -4,6 +4,7 @@
#include "shell/browser/net/network_context_service_factory.h"
#include "base/no_destructor.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "shell/browser/net/network_context_service.h"
@@ -16,7 +17,8 @@ NetworkContextService* NetworkContextServiceFactory::GetForContext(
}
NetworkContextServiceFactory* NetworkContextServiceFactory::GetInstance() {
return base::Singleton<NetworkContextServiceFactory>::get();
static base::NoDestructor<NetworkContextServiceFactory> instance;
return instance.get();
}
NetworkContextServiceFactory::NetworkContextServiceFactory()

View File

@@ -14,6 +14,11 @@ namespace content {
class BrowserContext;
}
namespace base {
template <typename T>
class NoDestructor;
}
namespace electron {
class NetworkContextService;
@@ -33,7 +38,7 @@ class NetworkContextServiceFactory : public BrowserContextKeyedServiceFactory {
delete;
private:
friend struct base::DefaultSingletonTraits<NetworkContextServiceFactory>;
friend base::NoDestructor<NetworkContextServiceFactory>;
NetworkContextServiceFactory();
~NetworkContextServiceFactory() override;

View File

@@ -8,19 +8,17 @@
#include "base/functional/bind.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "net/base/network_anonymization_key.h"
#include "net/proxy_resolution/proxy_info.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "shell/browser/electron_browser_context.h"
using content::BrowserThread;
namespace electron {
ResolveProxyHelper::ResolveProxyHelper(ElectronBrowserContext* browser_context)
: browser_context_(browser_context) {}
ResolveProxyHelper::ResolveProxyHelper(
network::mojom::NetworkContext* network_context)
: network_context_(network_context) {}
ResolveProxyHelper::~ResolveProxyHelper() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -54,11 +52,9 @@ void ResolveProxyHelper::StartPendingRequest() {
receiver_.set_disconnect_handler(
base::BindOnce(&ResolveProxyHelper::OnProxyLookupComplete,
base::Unretained(this), net::ERR_ABORTED, std::nullopt));
browser_context_->GetDefaultStoragePartition()
->GetNetworkContext()
->LookUpProxyForURL(pending_requests_.front().url,
net::NetworkAnonymizationKey(),
std::move(proxy_lookup_client));
network_context_->LookUpProxyForURL(pending_requests_.front().url,
net::NetworkAnonymizationKey(),
std::move(proxy_lookup_client));
}
void ResolveProxyHelper::OnProxyLookupComplete(

View File

@@ -12,20 +12,19 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/proxy_lookup_client.mojom.h"
#include "url/gurl.h"
namespace electron {
class ElectronBrowserContext;
class ResolveProxyHelper
: public base::RefCountedThreadSafe<ResolveProxyHelper>,
network::mojom::ProxyLookupClient {
public:
using ResolveProxyCallback = base::OnceCallback<void(std::string)>;
explicit ResolveProxyHelper(ElectronBrowserContext* browser_context);
explicit ResolveProxyHelper(network::mojom::NetworkContext* network_context);
void ResolveProxy(const GURL& url, ResolveProxyCallback callback);
@@ -71,7 +70,7 @@ class ResolveProxyHelper
mojo::Receiver<network::mojom::ProxyLookupClient> receiver_{this};
// Weak Ref
raw_ptr<ElectronBrowserContext> browser_context_;
raw_ptr<network::mojom::NetworkContext> network_context_ = nullptr;
};
} // namespace electron

View File

@@ -4,6 +4,7 @@
#include "shell/browser/serial/serial_chooser_context_factory.h"
#include "base/no_destructor.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "shell/browser/electron_browser_context.h"
#include "shell/browser/serial/serial_chooser_context.h"
@@ -26,7 +27,8 @@ KeyedService* SerialChooserContextFactory::BuildServiceInstanceFor(
// static
SerialChooserContextFactory* SerialChooserContextFactory::GetInstance() {
return base::Singleton<SerialChooserContextFactory>::get();
static base::NoDestructor<SerialChooserContextFactory> instance;
return instance.get();
}
// static

View File

@@ -5,10 +5,14 @@
#ifndef ELECTRON_SHELL_BROWSER_SERIAL_SERIAL_CHOOSER_CONTEXT_FACTORY_H_
#define ELECTRON_SHELL_BROWSER_SERIAL_SERIAL_CHOOSER_CONTEXT_FACTORY_H_
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "shell/browser/serial/serial_chooser_context.h"
namespace base {
template <typename T>
class NoDestructor;
} // namespace base
namespace electron {
class SerialChooserContext;
@@ -20,7 +24,7 @@ class SerialChooserContextFactory : public BrowserContextKeyedServiceFactory {
static SerialChooserContextFactory* GetInstance();
private:
friend struct base::DefaultSingletonTraits<SerialChooserContextFactory>;
friend base::NoDestructor<SerialChooserContextFactory>;
SerialChooserContextFactory();
~SerialChooserContextFactory() override;

View File

@@ -231,7 +231,7 @@ void AutofillPopup::SetItems(const std::vector<std::u16string>& values,
void AutofillPopup::AcceptSuggestion(int index) {
mojo::AssociatedRemote<mojom::ElectronAutofillAgent> autofill_agent;
frame_host_->GetRemoteAssociatedInterfaces()->GetInterface(&autofill_agent);
autofill_agent->AcceptDataListSuggestion(GetValueAt(index));
autofill_agent->AcceptDataListSuggestion(value_at(index));
}
void AutofillPopup::UpdatePopupBounds() {
@@ -272,11 +272,10 @@ int AutofillPopup::GetDesiredPopupWidth() {
int popup_width = element_bounds_.width();
for (size_t i = 0; i < values_.size(); ++i) {
int row_size =
kEndPadding + 2 * kPopupBorderThickness +
gfx::GetStringWidth(GetValueAt(i), GetValueFontListForRow(i)) +
gfx::GetStringWidth(GetLabelAt(i), GetLabelFontListForRow(i));
if (!GetLabelAt(i).empty())
int row_size = kEndPadding + 2 * kPopupBorderThickness +
gfx::GetStringWidth(value_at(i), GetValueFontListForRow(i)) +
gfx::GetStringWidth(label_at(i), GetLabelFontListForRow(i));
if (!label_at(i).empty())
row_size += kNamePadding + kEndPadding;
popup_width = std::max(popup_width, row_size);
@@ -307,18 +306,6 @@ ui::ColorId AutofillPopup::GetBackgroundColorIDForRow(int index) const {
: ui::kColorResultsTableNormalBackground;
}
int AutofillPopup::GetLineCount() {
return values_.size();
}
std::u16string AutofillPopup::GetValueAt(int i) {
return values_.at(i);
}
std::u16string AutofillPopup::GetLabelAt(int i) {
return labels_.at(i);
}
int AutofillPopup::LineFromY(int y) const {
int current_height = kPopupBorderThickness;

View File

@@ -57,9 +57,9 @@ class AutofillPopup : public views::ViewObserver {
const gfx::FontList& GetLabelFontListForRow(int index) const;
ui::ColorId GetBackgroundColorIDForRow(int index) const;
int GetLineCount();
std::u16string GetValueAt(int i);
std::u16string GetLabelAt(int i);
int line_count() const { return values_.size(); }
const std::u16string& value_at(int i) const { return values_.at(i); }
const std::u16string& label_at(int i) const { return labels_.at(i); }
int LineFromY(int y) const;
int selected_index_;

View File

@@ -27,7 +27,7 @@
devtools_is_first_responder_ = NO;
attached_to_window_ = NO;
if (inspectableWebContentsView_->inspectable_web_contents()->IsGuest()) {
if (inspectableWebContentsView_->inspectable_web_contents()->is_guest()) {
fake_view_ = [[NSView alloc] init];
[fake_view_ setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self addSubview:fake_view_];

View File

@@ -493,8 +493,8 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
if (menu_)
return menu_;
if (model_ && model_->GetSharingItem()) {
NSMenu* menu = [self createShareMenuForItem:*model_->GetSharingItem()];
if (model_ && model_->sharing_item()) {
NSMenu* menu = [self createShareMenuForItem:*model_->sharing_item()];
menu_ = menu;
} else {
menu_ = [[NSMenu alloc] initWithTitle:@""];

View File

@@ -76,7 +76,7 @@ using FullScreenTransitionState =
- (NSRect)windowWillUseStandardFrame:(NSWindow*)window
defaultFrame:(NSRect)frame {
if (!shell_->zoom_to_page_width()) {
if (shell_->GetAspectRatio() > 0.0)
if (shell_->aspect_ratio() > 0.0)
shell_->set_default_frame_for_zoom(frame);
return frame;
}
@@ -104,7 +104,7 @@ using FullScreenTransitionState =
// Set the width. Don't touch y or height.
frame.size.width = zoomed_width;
if (shell_->GetAspectRatio() > 0.0)
if (shell_->aspect_ratio() > 0.0)
shell_->set_default_frame_for_zoom(frame);
return frame;
@@ -139,13 +139,12 @@ using FullScreenTransitionState =
- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
NSSize newSize = frameSize;
double aspectRatio = shell_->GetAspectRatio();
NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow();
if (aspectRatio > 0.0) {
gfx::Size windowSize = shell_->GetSize();
gfx::Size contentSize = shell_->GetContentSize();
gfx::Size extraSize = shell_->GetAspectRatioExtraSize();
if (const double aspectRatio = shell_->aspect_ratio(); aspectRatio > 0.0) {
const gfx::Size windowSize = shell_->GetSize();
const gfx::Size contentSize = shell_->GetContentSize();
const gfx::Size extraSize = shell_->aspect_ratio_extra_size();
double titleBarHeight = windowSize.height() - contentSize.height();
double extraWidthPlusFrame =

View File

@@ -99,11 +99,6 @@ bool ElectronMenuModel::GetSharingItemAt(size_t index,
void ElectronMenuModel::SetSharingItem(SharingItem item) {
sharing_item_.emplace(std::move(item));
}
const std::optional<ElectronMenuModel::SharingItem>&
ElectronMenuModel::GetSharingItem() const {
return sharing_item_;
}
#endif
void ElectronMenuModel::MenuWillClose() {

View File

@@ -98,7 +98,10 @@ class ElectronMenuModel : public ui::SimpleMenuModel {
bool GetSharingItemAt(size_t index, SharingItem* item) const;
// Set/Get the SharingItem of this menu.
void SetSharingItem(SharingItem item);
const std::optional<SharingItem>& GetSharingItem() const;
[[nodiscard]] const std::optional<SharingItem>& sharing_item() const {
return sharing_item_;
}
#endif
// ui::SimpleMenuModel:

View File

@@ -385,10 +385,6 @@ InspectableWebContentsDelegate* InspectableWebContents::GetDelegate() const {
return delegate_;
}
bool InspectableWebContents::IsGuest() const {
return is_guest_;
}
void InspectableWebContents::ReleaseWebContents() {
web_contents_.release();
WebContentsDestroyed();
@@ -455,7 +451,7 @@ void InspectableWebContents::CloseDevTools() {
managed_devtools_web_contents_.reset();
}
embedder_message_dispatcher_.reset();
if (!IsGuest())
if (!is_guest())
web_contents_->Focus();
}
}
@@ -517,10 +513,6 @@ void InspectableWebContents::CallClientFunction(
std::move(arguments), std::move(cb));
}
gfx::Rect InspectableWebContents::GetDevToolsBounds() const {
return devtools_bounds_;
}
void InspectableWebContents::SaveDevToolsBounds(const gfx::Rect& bounds) {
pref_service_->Set(kDevToolsBoundsPref,
base::Value{RectToDictionary(bounds)});

View File

@@ -55,7 +55,7 @@ class InspectableWebContents
void SetDelegate(InspectableWebContentsDelegate* delegate);
InspectableWebContentsDelegate* GetDelegate() const;
bool IsGuest() const;
[[nodiscard]] bool is_guest() const { return is_guest_; }
void ReleaseWebContents();
void SetDevToolsWebContents(content::WebContents* devtools);
void SetDockState(const std::string& state);
@@ -76,7 +76,9 @@ class InspectableWebContents
void InspectElement(int x, int y);
// Return the last position and size of devtools window.
gfx::Rect GetDevToolsBounds() const;
[[nodiscard]] const gfx::Rect& dev_tools_bounds() const {
return devtools_bounds_;
}
void SaveDevToolsBounds(const gfx::Rect& bounds);
// Return the last set zoom level of devtools window.

View File

@@ -124,7 +124,7 @@ void AutofillPopupView::OnSuggestionsChanged() {
return;
CreateChildViews();
if (popup_->GetLineCount() == 0) {
if (popup_->line_count() == 0) {
popup_->Hide();
return;
}
@@ -177,28 +177,28 @@ void AutofillPopupView::DrawAutofillEntry(gfx::Canvas* canvas,
int x_align_left = value_rect.x();
const int value_width = gfx::GetStringWidth(
popup_->GetValueAt(index), popup_->GetValueFontListForRow(index));
popup_->value_at(index), popup_->GetValueFontListForRow(index));
int value_x_align_left = x_align_left;
value_x_align_left =
is_rtl ? value_rect.right() - value_width : value_rect.x();
canvas->DrawStringRectWithFlags(
popup_->GetValueAt(index), popup_->GetValueFontListForRow(index),
popup_->value_at(index), popup_->GetValueFontListForRow(index),
GetColorProvider()->GetColor(ui::kColorResultsTableNormalText),
gfx::Rect(value_x_align_left, value_rect.y(), value_width,
value_rect.height()),
text_align);
// Draw the label text, if one exists.
if (!popup_->GetLabelAt(index).empty()) {
const int label_width = gfx::GetStringWidth(
popup_->GetLabelAt(index), popup_->GetLabelFontListForRow(index));
if (auto const& label = popup_->label_at(index); !label.empty()) {
const int label_width =
gfx::GetStringWidth(label, popup_->GetLabelFontListForRow(index));
int label_x_align_left = x_align_left;
label_x_align_left =
is_rtl ? value_rect.x() : value_rect.right() - label_width;
canvas->DrawStringRectWithFlags(
popup_->GetLabelAt(index), popup_->GetLabelFontListForRow(index),
label, popup_->GetLabelFontListForRow(index),
GetColorProvider()->GetColor(ui::kColorResultsTableDimmedText),
gfx::Rect(label_x_align_left, entry_rect.y(), label_width,
entry_rect.height()),
@@ -212,8 +212,8 @@ void AutofillPopupView::CreateChildViews() {
RemoveAllChildViews();
for (int i = 0; i < popup_->GetLineCount(); ++i) {
auto* child_view = new AutofillPopupChildView(popup_->GetValueAt(i));
for (int i = 0; i < popup_->line_count(); ++i) {
auto* child_view = new AutofillPopupChildView(popup_->value_at(i));
child_view->set_drag_controller(this);
AddChildView(child_view);
}
@@ -234,8 +234,7 @@ void AutofillPopupView::DoUpdateBoundsAndRedrawPopup() {
}
void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
if (!popup_ ||
static_cast<size_t>(popup_->GetLineCount()) != children().size())
if (!popup_ || static_cast<size_t>(popup_->line_count()) != children().size())
return;
gfx::Canvas* draw_canvas = canvas;
SkBitmap bitmap;
@@ -252,7 +251,7 @@ void AutofillPopupView::OnPaint(gfx::Canvas* canvas) {
GetColorProvider()->GetColor(ui::kColorResultsTableNormalBackground));
OnPaintBorder(draw_canvas);
for (int i = 0; i < popup_->GetLineCount(); ++i) {
for (int i = 0; i < popup_->line_count(); ++i) {
gfx::Rect line_rect = popup_->GetRowBounds(i);
DrawAutofillEntry(draw_canvas, i, line_rect);
@@ -381,7 +380,7 @@ bool AutofillPopupView::HandleKeyPressEvent(
SetSelectedLine(0);
return true;
case ui::VKEY_NEXT: // Page down.
SetSelectedLine(popup_->GetLineCount() - 1);
SetSelectedLine(popup_->line_count() - 1);
return true;
case ui::VKEY_ESCAPE:
popup_->Hide();
@@ -421,7 +420,7 @@ void AutofillPopupView::AcceptSuggestion(int index) {
}
bool AutofillPopupView::AcceptSelectedLine() {
if (!selected_line_ || selected_line_.value() >= popup_->GetLineCount())
if (!selected_line_ || selected_line_.value() >= popup_->line_count())
return false;
AcceptSuggestion(selected_line_.value());
@@ -441,7 +440,7 @@ void AutofillPopupView::SetSelectedLine(std::optional<int> selected_line) {
return;
if (selected_line_ == selected_line)
return;
if (selected_line && selected_line.value() >= popup_->GetLineCount())
if (selected_line && selected_line.value() >= popup_->line_count())
return;
auto previous_selected_line(selected_line_);
@@ -461,7 +460,7 @@ void AutofillPopupView::SelectNextLine() {
return;
int new_selected_line = selected_line_ ? *selected_line_ + 1 : 0;
if (new_selected_line >= popup_->GetLineCount())
if (new_selected_line >= popup_->line_count())
new_selected_line = 0;
SetSelectedLine(new_selected_line);
@@ -473,7 +472,7 @@ void AutofillPopupView::SelectPreviousLine() {
int new_selected_line = selected_line_.value_or(0) - 1;
if (new_selected_line < 0)
new_selected_line = popup_->GetLineCount() - 1;
new_selected_line = popup_->line_count() - 1;
SetSelectedLine(new_selected_line);
}

View File

@@ -83,7 +83,7 @@ InspectableWebContentsViewViews::InspectableWebContentsViewViews(
: InspectableWebContentsView(inspectable_web_contents),
devtools_web_view_(new views::WebView(nullptr)),
title_(u"Developer Tools") {
if (!inspectable_web_contents_->IsGuest() &&
if (!inspectable_web_contents_->is_guest() &&
inspectable_web_contents_->GetWebContents()->GetNativeView()) {
auto* contents_web_view = new views::WebView(nullptr);
contents_web_view->SetWebContents(
@@ -116,8 +116,7 @@ void InspectableWebContentsViewViews::ShowDevTools(bool activate) {
if (devtools_window_) {
devtools_window_web_view_->SetWebContents(
inspectable_web_contents_->GetDevToolsWebContents());
devtools_window_->SetBounds(
inspectable_web_contents()->GetDevToolsBounds());
devtools_window_->SetBounds(inspectable_web_contents()->dev_tools_bounds());
if (activate) {
devtools_window_->Show();
} else {
@@ -182,7 +181,7 @@ void InspectableWebContentsViewViews::SetIsDocked(bool docked, bool activate) {
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.delegate = devtools_window_delegate_;
params.bounds = inspectable_web_contents()->GetDevToolsBounds();
params.bounds = inspectable_web_contents()->dev_tools_bounds();
#if BUILDFLAG(IS_LINUX)
params.wm_role_name = "devtools";

View File

@@ -4,6 +4,7 @@
#include "shell/browser/usb/usb_chooser_context_factory.h"
#include "base/no_destructor.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "shell/browser/electron_browser_context.h"
#include "shell/browser/usb/usb_chooser_context.h"
@@ -26,7 +27,8 @@ KeyedService* UsbChooserContextFactory::BuildServiceInstanceFor(
// static
UsbChooserContextFactory* UsbChooserContextFactory::GetInstance() {
return base::Singleton<UsbChooserContextFactory>::get();
static base::NoDestructor<UsbChooserContextFactory> instance;
return instance.get();
}
// static

View File

@@ -5,9 +5,13 @@
#ifndef ELECTRON_SHELL_BROWSER_USB_USB_CHOOSER_CONTEXT_FACTORY_H_
#define ELECTRON_SHELL_BROWSER_USB_USB_CHOOSER_CONTEXT_FACTORY_H_
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
namespace base {
template <typename T>
class NoDestructor;
} // namespace base
namespace electron {
class UsbChooserContext;
@@ -24,7 +28,7 @@ class UsbChooserContextFactory : public BrowserContextKeyedServiceFactory {
UsbChooserContextFactory& operator=(const UsbChooserContextFactory&) = delete;
private:
friend struct base::DefaultSingletonTraits<UsbChooserContextFactory>;
friend base::NoDestructor<UsbChooserContextFactory>;
UsbChooserContextFactory();
~UsbChooserContextFactory() override;

View File

@@ -46,6 +46,14 @@ scoped_refptr<base::RefCountedMemory> NetResourceProvider(int key) {
return nullptr;
}
[[nodiscard]] constexpr bool is_main_world(int world_id) {
return world_id == WorldIDs::MAIN_WORLD_ID;
}
[[nodiscard]] constexpr bool is_isolated_world(int world_id) {
return world_id == WorldIDs::ISOLATED_WORLD_ID;
}
} // namespace
ElectronRenderFrameObserver::ElectronRenderFrameObserver(
@@ -57,10 +65,10 @@ ElectronRenderFrameObserver::ElectronRenderFrameObserver(
// Initialise resource for directory listing.
net::NetModule::SetResourceProvider(NetResourceProvider);
// App regions are only supported in the main frame.
auto* main_frame = frame->GetMainRenderFrame();
if (main_frame && main_frame == frame)
render_frame_->GetWebView()->SetSupportsAppRegion(true);
// In Chrome, app regions are only supported in the main frame.
// However, we need to support draggable regions on other
// local frames/windows, so extend support beyond the main frame.
render_frame_->GetWebView()->SetSupportsAppRegion(true);
}
void ElectronRenderFrameObserver::DidClearWindowObject() {
@@ -129,7 +137,7 @@ void ElectronRenderFrameObserver::DidInstallConditionalFeatures(
// This logic matches the EXPLAINED logic in electron_renderer_client.cc
// to avoid explaining it twice go check that implementation in
// DidCreateScriptContext();
bool is_main_world = IsMainWorld(world_id);
bool is_main_world = electron::is_main_world(world_id);
bool is_main_frame = render_frame_->IsMainFrame();
bool allow_node_in_sub_frames = prefs.node_integration_in_sub_frames;
@@ -203,16 +211,8 @@ void ElectronRenderFrameObserver::CreateIsolatedWorldContext() {
blink::BackForwardCacheAware::kPossiblyDisallow);
}
bool ElectronRenderFrameObserver::IsMainWorld(int world_id) {
return world_id == WorldIDs::MAIN_WORLD_ID;
}
bool ElectronRenderFrameObserver::IsIsolatedWorld(int world_id) {
return world_id == WorldIDs::ISOLATED_WORLD_ID;
}
bool ElectronRenderFrameObserver::ShouldNotifyClient(int world_id) {
auto prefs = render_frame_->GetBlinkPreferences();
bool ElectronRenderFrameObserver::ShouldNotifyClient(int world_id) const {
const auto& prefs = render_frame_->GetBlinkPreferences();
// This is necessary because if an iframe is created and a source is not
// set, the iframe loads about:blank and creates a script context for the
@@ -220,17 +220,17 @@ bool ElectronRenderFrameObserver::ShouldNotifyClient(int world_id) {
// is later set, the JS necessary to do that triggers illegal access errors
// when the initial about:blank Node.js environment is cleaned up. See:
// https://source.chromium.org/chromium/chromium/src/+/main:content/renderer/render_frame_impl.h;l=870-892;drc=4b6001440a18740b76a1c63fa2a002cc941db394
GURL url = render_frame_->GetWebFrame()->GetDocument().Url();
bool allow_node_in_sub_frames = prefs.node_integration_in_sub_frames;
if (allow_node_in_sub_frames && url.IsAboutBlank() &&
!render_frame_->IsMainFrame())
return false;
const bool allow_node_in_sub_frames = prefs.node_integration_in_sub_frames;
if (allow_node_in_sub_frames && !render_frame_->IsMainFrame()) {
if (GURL{render_frame_->GetWebFrame()->GetDocument().Url()}.IsAboutBlank())
return false;
}
if (prefs.context_isolation &&
(render_frame_->IsMainFrame() || allow_node_in_sub_frames))
return IsIsolatedWorld(world_id);
return is_isolated_world(world_id);
return IsMainWorld(world_id);
return is_main_world(world_id);
}
} // namespace electron

View File

@@ -37,10 +37,9 @@ class ElectronRenderFrameObserver : public content::RenderFrameObserver {
void DidMeaningfulLayout(blink::WebMeaningfulLayout layout_type) override;
private:
bool ShouldNotifyClient(int world_id);
[[nodiscard]] bool ShouldNotifyClient(int world_id) const;
void CreateIsolatedWorldContext();
bool IsMainWorld(int world_id);
bool IsIsolatedWorld(int world_id);
void OnTakeHeapSnapshot(IPC::PlatformFileForTransit file_handle,
const std::string& channel);

View File

@@ -37,6 +37,7 @@
#include "shell/renderer/electron_autofill_agent.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
#include "third_party/blink/public/platform/web_runtime_features.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_custom_element.h" // NOLINT(build/include_alpha)
#include "third_party/blink/public/web/web_frame_widget.h"
@@ -225,6 +226,14 @@ bool RendererClientBase::ShouldLoadPreload(
void RendererClientBase::RenderThreadStarted() {
auto* command_line = base::CommandLine::ForCurrentProcess();
// Enable MessagePort close event by default.
// The feature got reverted from stable to test in
// https://chromium-review.googlesource.com/c/chromium/src/+/5276821
// We had the event supported through patch before upstream support,
// this is an alternative option than restoring our patch.
blink::WebRuntimeFeatures::EnableFeatureFromString("MessagePortCloseEvent",
true);
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
auto* thread = content::RenderThread::Get();

View File

@@ -6,9 +6,10 @@ import * as net from 'node:net';
import * as fs from 'fs-extra';
import * as path from 'node:path';
import { promisify } from 'node:util';
import { app, BrowserWindow, Menu, session, net as electronNet, WebContents } from 'electron/main';
import { app, BrowserWindow, Menu, session, net as electronNet, WebContents, utilityProcess } from 'electron/main';
import { closeWindow, closeAllWindows } from './lib/window-helpers';
import { ifdescribe, ifit, listen, waitUntil } from './lib/spec-helpers';
import { collectStreamBody, getResponse } from './lib/net-helpers';
import { once } from 'node:events';
import split = require('split')
import * as semver from 'semver';
@@ -1895,6 +1896,154 @@ describe('app module', () => {
app.showAboutPanel();
});
});
describe('app.setProxy(options)', () => {
let server: http.Server;
afterEach(async () => {
if (server) {
server.close();
}
await app.setProxy({ mode: 'direct' as const });
});
it('allows configuring proxy settings', async () => {
const config = { proxyRules: 'http=myproxy:80' };
await app.setProxy(config);
const proxy = await app.resolveProxy('http://example.com/');
expect(proxy).to.equal('PROXY myproxy:80');
});
it('allows removing the implicit bypass rules for localhost', async () => {
const config = {
proxyRules: 'http=myproxy:80',
proxyBypassRules: '<-loopback>'
};
await app.setProxy(config);
const proxy = await app.resolveProxy('http://localhost');
expect(proxy).to.equal('PROXY myproxy:80');
});
it('allows configuring proxy settings with pacScript', async () => {
server = http.createServer((req, res) => {
const pac = `
function FindProxyForURL(url, host) {
return "PROXY myproxy:8132";
}
`;
res.writeHead(200, {
'Content-Type': 'application/x-ns-proxy-autoconfig'
});
res.end(pac);
});
const { url } = await listen(server);
{
const config = { pacScript: url };
await app.setProxy(config);
const proxy = await app.resolveProxy('https://google.com');
expect(proxy).to.equal('PROXY myproxy:8132');
}
{
const config = { mode: 'pac_script' as any, pacScript: url };
await app.setProxy(config);
const proxy = await app.resolveProxy('https://google.com');
expect(proxy).to.equal('PROXY myproxy:8132');
}
});
it('allows bypassing proxy settings', async () => {
const config = {
proxyRules: 'http=myproxy:80',
proxyBypassRules: '<local>'
};
await app.setProxy(config);
const proxy = await app.resolveProxy('http://example/');
expect(proxy).to.equal('DIRECT');
});
it('allows configuring proxy settings with mode `direct`', async () => {
const config = { mode: 'direct' as const, proxyRules: 'http=myproxy:80' };
await app.setProxy(config);
const proxy = await app.resolveProxy('http://example.com/');
expect(proxy).to.equal('DIRECT');
});
it('allows configuring proxy settings with mode `auto_detect`', async () => {
const config = { mode: 'auto_detect' as const };
await app.setProxy(config);
});
it('allows configuring proxy settings with mode `pac_script`', async () => {
const config = { mode: 'pac_script' as const };
await app.setProxy(config);
const proxy = await app.resolveProxy('http://example.com/');
expect(proxy).to.equal('DIRECT');
});
it('allows configuring proxy settings with mode `fixed_servers`', async () => {
const config = { mode: 'fixed_servers' as const, proxyRules: 'http=myproxy:80' };
await app.setProxy(config);
const proxy = await app.resolveProxy('http://example.com/');
expect(proxy).to.equal('PROXY myproxy:80');
});
it('allows configuring proxy settings with mode `system`', async () => {
const config = { mode: 'system' as const };
await app.setProxy(config);
});
it('disallows configuring proxy settings with mode `invalid`', async () => {
const config = { mode: 'invalid' as any };
await expect(app.setProxy(config)).to.eventually.be.rejectedWith(/Invalid mode/);
});
it('impacts proxy for requests made from utility process', async () => {
const utilityFixturePath = path.resolve(__dirname, 'fixtures', 'api', 'utility-process', 'api-net-spec.js');
const fn = async () => {
const urlRequest = electronNet.request('http://example.com/');
const response = await getResponse(urlRequest);
expect(response.statusCode).to.equal(200);
const message = await collectStreamBody(response);
expect(message).to.equal('ok from proxy\n');
};
server = http.createServer((req, res) => {
res.writeHead(200);
res.end('ok from proxy\n');
});
const { port, hostname } = await listen(server);
const config = { mode: 'fixed_servers' as const, proxyRules: `http=${hostname}:${port}` };
await app.setProxy(config);
const proxy = await app.resolveProxy('http://example.com/');
expect(proxy).to.equal(`PROXY ${hostname}:${port}`);
const child = utilityProcess.fork(utilityFixturePath, [], {
execArgv: ['--expose-gc']
});
child.postMessage({ fn: `(${fn})()` });
const [data] = await once(child, 'message');
expect(data.ok).to.be.true(data.message);
// Cleanup.
const [code] = await once(child, 'exit');
expect(code).to.equal(0);
});
it('does not impact proxy for requests made from main process', async () => {
server = http.createServer((req, res) => {
res.writeHead(200);
res.end('ok from server\n');
});
const { url } = await listen(server);
const config = { mode: 'fixed_servers' as const, proxyRules: 'http=myproxy:80' };
await app.setProxy(config);
const proxy = await app.resolveProxy('http://example.com/');
expect(proxy).to.equal('PROXY myproxy:80');
const urlRequest = electronNet.request(url);
const response = await getResponse(urlRequest);
expect(response.statusCode).to.equal(200);
const message = await collectStreamBody(response);
expect(message).to.equal('ok from server\n');
});
});
});
describe('default behavior', () => {

View File

@@ -11,7 +11,7 @@ import { app, BrowserWindow, BrowserView, dialog, ipcMain, OnBeforeSendHeadersLi
import { emittedUntil, emittedNTimes } from './lib/events-helpers';
import { ifit, ifdescribe, defer, listen } from './lib/spec-helpers';
import { closeWindow, closeAllWindows } from './lib/window-helpers';
import { areColorsSimilar, captureScreen, HexColors, getPixelColor } from './lib/screen-helpers';
import { areColorsSimilar, captureScreen, HexColors, getPixelColor, hasCapturableScreen } from './lib/screen-helpers';
import { once } from 'node:events';
import { setTimeout } from 'node:timers/promises';
import { setTimeout as syncSetTimeout } from 'node:timers';
@@ -6599,4 +6599,117 @@ describe('BrowserWindow module', () => {
expect(areColorsSimilar(centerColor, HexColors.BLUE)).to.be.true();
});
});
describe('draggable regions', () => {
afterEach(closeAllWindows);
ifit(hasCapturableScreen())('should allow the window to be dragged when enabled', async () => {
// WOA fails to load libnut so we're using require to defer loading only
// on supported platforms.
// "@nut-tree\libnut-win32\build\Release\libnut.node is not a valid Win32 application."
// @ts-ignore: nut-js is an optional dependency so it may not be installed
const { mouse, straightTo, centerOf, Region, Button } = require('@nut-tree/nut-js') as typeof import('@nut-tree/nut-js');
const display = screen.getPrimaryDisplay();
const w = new BrowserWindow({
x: 0,
y: 0,
width: display.bounds.width / 2,
height: display.bounds.height / 2,
frame: false,
titleBarStyle: 'hidden'
});
const overlayHTML = path.join(__dirname, 'fixtures', 'pages', 'overlay.html');
w.loadFile(overlayHTML);
await once(w, 'ready-to-show');
const winBounds = w.getBounds();
const titleBarHeight = 30;
const titleBarRegion = new Region(winBounds.x, winBounds.y, winBounds.width, titleBarHeight);
const screenRegion = new Region(display.bounds.x, display.bounds.y, display.bounds.width, display.bounds.height);
const startPos = w.getPosition();
await mouse.setPosition(await centerOf(titleBarRegion));
await mouse.pressButton(Button.LEFT);
await mouse.drag(straightTo(centerOf(screenRegion)));
// Wait for move to complete
await Promise.race([
once(w, 'move'),
setTimeout(100) // fallback for possible race condition
]);
const endPos = w.getPosition();
expect(startPos).to.not.deep.equal(endPos);
});
ifit(hasCapturableScreen())('should allow the window to be dragged when no WCO and --webkit-app-region: drag enabled', async () => {
// @ts-ignore: nut-js is an optional dependency so it may not be installed
const { mouse, straightTo, centerOf, Region, Button } = require('@nut-tree/nut-js') as typeof import('@nut-tree/nut-js');
const display = screen.getPrimaryDisplay();
const w = new BrowserWindow({
x: 0,
y: 0,
width: display.bounds.width / 2,
height: display.bounds.height / 2,
frame: false
});
const basePageHTML = path.join(__dirname, 'fixtures', 'pages', 'base-page.html');
w.loadFile(basePageHTML);
await once(w, 'ready-to-show');
await w.webContents.executeJavaScript(`
const style = document.createElement('style');
style.innerHTML = \`
#titlebar {
background-color: red;
height: 30px;
width: 100%;
-webkit-user-select: none;
-webkit-app-region: drag;
position: fixed;
top: 0;
left: 0;
z-index: 1000000000000;
}
\`;
const titleBar = document.createElement('title-bar');
titleBar.id = 'titlebar';
titleBar.textContent = 'test-titlebar';
document.body.append(style);
document.body.append(titleBar);
`);
// allow time for titlebar to finish loading
await setTimeout(2000);
const winBounds = w.getBounds();
const titleBarHeight = 30;
const titleBarRegion = new Region(winBounds.x, winBounds.y, winBounds.width, titleBarHeight);
const screenRegion = new Region(display.bounds.x, display.bounds.y, display.bounds.width, display.bounds.height);
const startPos = w.getPosition();
await mouse.setPosition(await centerOf(titleBarRegion));
await mouse.pressButton(Button.LEFT);
await mouse.drag(straightTo(centerOf(screenRegion)));
// Wait for move to complete
await Promise.race([
once(w, 'move'),
setTimeout(1000) // fallback for possible race condition
]);
const endPos = w.getPosition();
expect(startPos).to.not.deep.equal(endPos);
});
});
});

View File

@@ -8,6 +8,8 @@ import * as http from 'node:http';
import * as fs from 'node:fs';
import * as qs from 'node:querystring';
import * as stream from 'node:stream';
import * as streamConsumers from 'node:stream/consumers';
import * as webStream from 'node:stream/web';
import { EventEmitter, once } from 'node:events';
import { closeAllWindows, closeWindow } from './lib/window-helpers';
import { WebmGenerator } from './lib/video-helpers';
@@ -1548,6 +1550,122 @@ describe('protocol module', () => {
}
});
it('does not emit undefined chunks into the request body stream when uploading a stream', async () => {
protocol.handle('cors', async (request) => {
expect(request.body).to.be.an.instanceOf(webStream.ReadableStream);
for await (const value of request.body as webStream.ReadableStream<Uint8Array>) {
expect(value).to.not.be.undefined();
}
return new Response(undefined, { status: 200 });
});
defer(() => { protocol.unhandle('cors'); });
await contents.loadFile(path.resolve(fixturesPath, 'pages', 'base-page.html'));
contents.on('console-message', (e, level, message) => console.log(message));
const ok = await contents.executeJavaScript(`(async () => {
function wait(milliseconds) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}
const stream = new ReadableStream({
async start(controller) {
await wait(4);
controller.enqueue('This ');
await wait(4);
controller.enqueue('is ');
await wait(4);
controller.enqueue('a ');
await wait(4);
controller.enqueue('slow ');
await wait(4);
controller.enqueue('request.');
controller.close();
}
}).pipeThrough(new TextEncoderStream());
return (await fetch('cors://url.invalid', { method: 'POST', body: stream, duplex: 'half' })).ok;
})()`);
expect(ok).to.be.true();
});
it('does not emit undefined chunks into the request body stream when uploading a file', async () => {
protocol.handle('cors', async (request) => {
expect(request.body).to.be.an.instanceOf(webStream.ReadableStream);
for await (const value of request.body as webStream.ReadableStream<Uint8Array>) {
expect(value).to.not.be.undefined();
}
return new Response(undefined, { status: 200 });
});
defer(() => { protocol.unhandle('cors'); });
await contents.loadFile(path.resolve(fixturesPath, 'pages', 'file-input.html'));
const { debugger: debug } = contents;
debug.attach();
try {
const { root: { nodeId } } = await debug.sendCommand('DOM.getDocument');
const { nodeId: inputNodeId } = await debug.sendCommand('DOM.querySelector', { nodeId, selector: 'input' });
await debug.sendCommand('DOM.setFileInputFiles', {
files: [path.join(fixturesPath, 'cat-spin.mp4')],
nodeId: inputNodeId
});
const ok = await contents.executeJavaScript(`(async () => {
const formData = new FormData();
formData.append("data", document.getElementById("file").files[0]);
return (await fetch('cors://url.invalid', { method: 'POST', body: formData })).ok;
})()`);
expect(ok).to.be.true();
} finally {
debug.detach();
}
});
it('filters an illegal "origin: null" header', async () => {
protocol.handle('http', (req) => {
expect(new Headers(req.headers).get('origin')).to.not.equal('null');
return new Response();
});
defer(() => { protocol.unhandle('http'); });
const filePath = path.join(fixturesPath, 'pages', 'form-with-data.html');
await contents.loadFile(filePath);
const loadPromise = new Promise((resolve, reject) => {
contents.once('did-finish-load', resolve);
contents.once('did-fail-load', (_, errorCode, errorDescription) =>
reject(new Error(`did-fail-load: ${errorCode} ${errorDescription}. See AssertionError for details.`))
);
});
await contents.executeJavaScript(`
const form = document.querySelector('form');
form.action = 'http://cors.invalid';
form.method = 'POST';
form.submit();
`);
await loadPromise;
});
it('does forward Blob chunks', async () => {
// we register the protocol on a separate session to validate the assumption
// that `getBlobData()` indeed returns the blob data from a global variable
const s = session.fromPartition('protocol-handle-forwards-blob-chunks');
s.protocol.handle('cors', async (request) => {
expect(request.body).to.be.an.instanceOf(webStream.ReadableStream);
return new Response(
`hello to ${await streamConsumers.text(request.body as webStream.ReadableStream<Uint8Array>)}`,
{ status: 200 }
);
});
defer(() => { s.protocol.unhandle('cors'); });
const w = new BrowserWindow({ show: false, webPreferences: { session: s } });
await w.webContents.loadFile(path.resolve(fixturesPath, 'pages', 'base-page.html'));
const response = await w.webContents.executeJavaScript(`(async () => {
const body = new Blob(["it's-a ", 'me! ', 'Mario!'], { type: 'text/plain' });
return await (await fetch('cors://url.invalid', { method: 'POST', body })).text();
})()`);
expect(response).to.be.string('hello to it\'s-a me! Mario!');
});
// TODO(nornagon): this test doesn't pass on Linux currently, investigate.
ifit(process.platform !== 'linux')('is fast', async () => {
// 128 MB of spaces.

View File

@@ -91,3 +91,16 @@ export const areColorsSimilar = (
const distance = colorDistance(hexColorA, hexColorB);
return distance <= distanceThreshold;
};
/**
* Whether the current VM has a valid screen which can be used to capture.
*
* This is specific to Electron's CI test runners.
* - Linux: virtual screen display is 0x0
* - Win32 arm64 (WOA): virtual screen display is 0x0
* - Win32 ia32: skipped
*/
export const hasCapturableScreen = () => {
return process.platform === 'darwin' ||
(process.platform === 'win32' && process.arch === 'x64');
};

View File

@@ -200,5 +200,5 @@ export async function listen (server: http.Server | https.Server | http2.Http2Se
await new Promise<void>(resolve => server.listen(0, hostname, () => resolve()));
const { port } = server.address() as net.AddressInfo;
const protocol = (server instanceof http.Server) ? 'http' : 'https';
return { port, url: url.format({ protocol, hostname, port }) };
return { port, hostname, url: url.format({ protocol, hostname, port }) };
}

View File

@@ -38,6 +38,9 @@
"ws": "^7.4.6",
"yargs": "^16.0.3"
},
"optionalDependencies": {
"@nut-tree/nut-js": "^3.1.2"
},
"resolutions": {
"nan": "file:../../third_party/nan",
"dbus-native/optimist/minimist": "1.2.7",

File diff suppressed because it is too large Load Diff