mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
22 Commits
thumb-cap
...
same-party
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3bd73cbd7 | ||
|
|
4f3391d92a | ||
|
|
5cbaf97e31 | ||
|
|
2d9c5a62c6 | ||
|
|
23f690ffd0 | ||
|
|
8f4e94694e | ||
|
|
af47434dc8 | ||
|
|
8ab99e2d8e | ||
|
|
ffcccdcf37 | ||
|
|
ce2ac1c0c2 | ||
|
|
1c3feddef8 | ||
|
|
c779f19ee5 | ||
|
|
09fbee9998 | ||
|
|
69d371fc41 | ||
|
|
b6db80c1c4 | ||
|
|
b87cf56b09 | ||
|
|
bc40a1aa0c | ||
|
|
d8606efe94 | ||
|
|
523e0d4574 | ||
|
|
3b23911121 | ||
|
|
516cbfa29a | ||
|
|
5c71377f40 |
@@ -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
2
DEPS
@@ -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':
|
||||
|
||||
@@ -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: >-
|
||||
|
||||
@@ -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: >-
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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.
|
||||
|
||||
86
docs/api/structures/proxy-config.md
Normal file
86
docs/api/structures/proxy-config.md
Normal 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".
|
||||
@@ -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', {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
+ }
|
||||
@@ -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)
|
||||
|
||||
@@ -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") {
|
||||
|
||||
4832
patches/chromium/revert_same_party_cookie_attribute_removal.patch
Normal file
4832
patches/chromium/revert_same_party_cookie_attribute_removal.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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' },
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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_)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_
|
||||
|
||||
28
shell/browser/feature_list_mac.mm
Normal file
28
shell/browser/feature_list_mac.mm
Normal 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
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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_];
|
||||
|
||||
@@ -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:@""];
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)});
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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');
|
||||
};
|
||||
|
||||
@@ -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 }) };
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
778
spec/yarn.lock
778
spec/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user