mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
274 Commits
v15.1.1
...
v16.0.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
339eccfc42 | ||
|
|
65c8415bac | ||
|
|
30be3150ff | ||
|
|
7d9ce1379f | ||
|
|
27d1f6a360 | ||
|
|
be46387f22 | ||
|
|
fe160165b6 | ||
|
|
be1c18096b | ||
|
|
2e3b05bcad | ||
|
|
54657fb667 | ||
|
|
c83d65eab0 | ||
|
|
3daad4fd40 | ||
|
|
b4a79672cf | ||
|
|
a71c610747 | ||
|
|
b1366421d1 | ||
|
|
f2696fb431 | ||
|
|
25c536d355 | ||
|
|
6530067b85 | ||
|
|
8626aa29d1 | ||
|
|
9e0a182821 | ||
|
|
2d8fa4d225 | ||
|
|
5a7ba8ba8c | ||
|
|
ede6b45bc1 | ||
|
|
1000ddfcab | ||
|
|
63110a7159 | ||
|
|
308ef699e6 | ||
|
|
764b2a6041 | ||
|
|
5009694dc9 | ||
|
|
c07016e1d1 | ||
|
|
7c5a346464 | ||
|
|
4f54cc0d18 | ||
|
|
520e7077d4 | ||
|
|
eb41f5b70e | ||
|
|
23afedcea8 | ||
|
|
9bc6e1a584 | ||
|
|
89b08817a9 | ||
|
|
cb6a22a7a4 | ||
|
|
74c53ad0c3 | ||
|
|
88235cb2bc | ||
|
|
f8b4dc98b9 | ||
|
|
79108c7acd | ||
|
|
b0273b96c1 | ||
|
|
f7dd18466b | ||
|
|
80175c5828 | ||
|
|
2a36199b35 | ||
|
|
f5c2bab02b | ||
|
|
acca212814 | ||
|
|
ebbaa3b352 | ||
|
|
c42ed97535 | ||
|
|
cec707ce67 | ||
|
|
0080a61c1d | ||
|
|
2f543c3fd4 | ||
|
|
f6da3b43c2 | ||
|
|
6029315e1a | ||
|
|
f6748f9795 | ||
|
|
6500bcbb32 | ||
|
|
a75617bff1 | ||
|
|
3ef74abfe4 | ||
|
|
70c534fd14 | ||
|
|
52bacd38a9 | ||
|
|
dbd18d8562 | ||
|
|
4fcc0884f8 | ||
|
|
ee19e5ee48 | ||
|
|
629d8913f6 | ||
|
|
92bff00d43 | ||
|
|
e38a0a67c6 | ||
|
|
82da4b0090 | ||
|
|
6dd33b75b2 | ||
|
|
a96f42ce86 | ||
|
|
efa70131e2 | ||
|
|
6fdf350bea | ||
|
|
8d8fcd88f5 | ||
|
|
ad98f4707f | ||
|
|
4576d9d23e | ||
|
|
64c70c420f | ||
|
|
b491a4c82f | ||
|
|
c5b517d89f | ||
|
|
9c4e3b67fb | ||
|
|
93068cfab5 | ||
|
|
c8e4cc29c0 | ||
|
|
9eaa9de3b4 | ||
|
|
664a452fb6 | ||
|
|
54b44584fa | ||
|
|
1295ba0ffc | ||
|
|
02ac33c4cd | ||
|
|
87050d75b8 | ||
|
|
00d0265782 | ||
|
|
c74b9ff312 | ||
|
|
b6a12a53e3 | ||
|
|
06b3b49214 | ||
|
|
c556ccac08 | ||
|
|
fb539f15d0 | ||
|
|
57d088517c | ||
|
|
fcad531f2e | ||
|
|
eb955af459 | ||
|
|
9dee1183f9 | ||
|
|
9891ff14a7 | ||
|
|
22abbf76fb | ||
|
|
90a3e7f927 | ||
|
|
55c57808fb | ||
|
|
ee33374675 | ||
|
|
6a1726576d | ||
|
|
64e33002f8 | ||
|
|
fb40065c1e | ||
|
|
ce6a71e936 | ||
|
|
57e3c25378 | ||
|
|
1546cb6e6c | ||
|
|
f39ba9281c | ||
|
|
8b7631228f | ||
|
|
4a2f41ee58 | ||
|
|
7379e5eb36 | ||
|
|
26f981fa3e | ||
|
|
99c0a723fd | ||
|
|
94ca57e296 | ||
|
|
1dcb8a370e | ||
|
|
e6f781f403 | ||
|
|
b8372f20a0 | ||
|
|
92222c874f | ||
|
|
c30303207a | ||
|
|
873872a32b | ||
|
|
5554de0237 | ||
|
|
ee0e15a52e | ||
|
|
6d4995ec17 | ||
|
|
8d86d84ff5 | ||
|
|
fd8eb3de1b | ||
|
|
4d89174b41 | ||
|
|
49e62f1261 | ||
|
|
e6802bf935 | ||
|
|
ad776d6113 | ||
|
|
f533c44912 | ||
|
|
63b35403ef | ||
|
|
399032252f | ||
|
|
dd7aeda6fb | ||
|
|
3b2db5f168 | ||
|
|
c1075debf3 | ||
|
|
88ff3a6a9a | ||
|
|
8007d01874 | ||
|
|
c2da4ec2bc | ||
|
|
aa9da78edb | ||
|
|
352ac21413 | ||
|
|
96131af5d3 | ||
|
|
f9c6f9af83 | ||
|
|
00d65eb9ac | ||
|
|
a9983c1d06 | ||
|
|
c2c1b22a31 | ||
|
|
501ac15b1d | ||
|
|
be43996d35 | ||
|
|
32194f0f71 | ||
|
|
e43a25724c | ||
|
|
5513e66982 | ||
|
|
10c4931477 | ||
|
|
aad1c0d493 | ||
|
|
34f1bc0e82 | ||
|
|
fb990ba1eb | ||
|
|
517b174c3c | ||
|
|
c83de755c1 | ||
|
|
aab5ea5f9d | ||
|
|
7093cd75cb | ||
|
|
2a28ca226f | ||
|
|
4820dee980 | ||
|
|
cb7c16cb2d | ||
|
|
11de995d38 | ||
|
|
ea889b423d | ||
|
|
655b614ecd | ||
|
|
cbeae20438 | ||
|
|
8699124397 | ||
|
|
ec13a0b0e6 | ||
|
|
e92d92d7eb | ||
|
|
dd16d68e96 | ||
|
|
90b5ba3bed | ||
|
|
29749f3dc6 | ||
|
|
f797159fbe | ||
|
|
b62bbfda4e | ||
|
|
db8644ee7a | ||
|
|
04aafcc5ef | ||
|
|
ff128a32d9 | ||
|
|
a9a90fa1b6 | ||
|
|
7cdd132d18 | ||
|
|
93d7968d64 | ||
|
|
cd09a54365 | ||
|
|
eaa5d372fb | ||
|
|
6669abf38d | ||
|
|
740dcc5c16 | ||
|
|
fcce2b16d5 | ||
|
|
94111c9d5c | ||
|
|
8b9d0092cb | ||
|
|
0c1f762119 | ||
|
|
a11a234eac | ||
|
|
fc9a197f6c | ||
|
|
61117a11a1 | ||
|
|
7132f36ddd | ||
|
|
d1bd9afbbf | ||
|
|
1e983e2a6e | ||
|
|
c5db7a9013 | ||
|
|
a48968c1ce | ||
|
|
d313ddbd3d | ||
|
|
6ad47322fa | ||
|
|
93b1d2d932 | ||
|
|
17615654e8 | ||
|
|
c6267d9fb0 | ||
|
|
52890e9efd | ||
|
|
7668507c9d | ||
|
|
439e83de6c | ||
|
|
08ff1c2cbf | ||
|
|
81c143318b | ||
|
|
c8f3324610 | ||
|
|
60650abf09 | ||
|
|
e11953b0e6 | ||
|
|
41646d1168 | ||
|
|
42936b07fe | ||
|
|
985f1b5c04 | ||
|
|
ac49e6af4a | ||
|
|
69f1c1b083 | ||
|
|
f17e6ae318 | ||
|
|
4f739d7837 | ||
|
|
590858a38d | ||
|
|
edb7413bae | ||
|
|
e223b4db94 | ||
|
|
08e9aea940 | ||
|
|
66c458a353 | ||
|
|
6a9cada98c | ||
|
|
d783e944d3 | ||
|
|
641260bc32 | ||
|
|
bc508c6113 | ||
|
|
ec6cd0053e | ||
|
|
8e1160fde4 | ||
|
|
320bea4c28 | ||
|
|
59ab79417d | ||
|
|
423172775e | ||
|
|
4703dc0a1d | ||
|
|
481b774fd7 | ||
|
|
acbd643e2a | ||
|
|
97929eab5f | ||
|
|
1c29734c91 | ||
|
|
8179349625 | ||
|
|
a17e48061a | ||
|
|
40e76dca07 | ||
|
|
6e43b0bcbf | ||
|
|
4519bc3cd1 | ||
|
|
2b897c8ad8 | ||
|
|
0cabff0a21 | ||
|
|
888ac65c72 | ||
|
|
c0e72bd335 | ||
|
|
ced2e8779f | ||
|
|
9693fb9a37 | ||
|
|
9a63d96e83 | ||
|
|
7b5deb2f3a | ||
|
|
8651c5d02d | ||
|
|
639f03977f | ||
|
|
9cc1b55663 | ||
|
|
3ee6326b93 | ||
|
|
39c3ff5292 | ||
|
|
4aa9455613 | ||
|
|
c5ad7ed0cd | ||
|
|
c3abbdefdd | ||
|
|
bd85b1d028 | ||
|
|
fa464286ee | ||
|
|
d63980edeb | ||
|
|
1c95d30c0f | ||
|
|
fc7ea75009 | ||
|
|
ceebae170e | ||
|
|
cce27a0961 | ||
|
|
10424c0149 | ||
|
|
a545cd3790 | ||
|
|
461db8f1ab | ||
|
|
d2989de5d9 | ||
|
|
385d0f590f | ||
|
|
64ba8feb93 | ||
|
|
a6ab702ae4 | ||
|
|
62711e23ad | ||
|
|
3cb06457c4 | ||
|
|
e3fe80e0e8 | ||
|
|
b24cfe17bc | ||
|
|
eca1098b55 |
@@ -45,7 +45,7 @@ executors:
|
||||
type: enum
|
||||
enum: ["medium", "xlarge", "2xlarge+"]
|
||||
docker:
|
||||
- image: electron.azurecr.io/build:d818f06a9b1540c7fd38f75ad5a2c493dd6843b6
|
||||
- image: ghcr.io/electron/build:27db4a3e3512bfd2e47f58cea69922da0835f1d9
|
||||
resource_class: << parameters.size >>
|
||||
|
||||
macos:
|
||||
|
||||
59
.devcontainer/README.md
Normal file
59
.devcontainer/README.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Electron Dev on Codespaces
|
||||
|
||||
Welcome to the Codespaces Electron Developer Environment.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Upon creation of your codespace you should have [build tools](https://github.com/electron/build-tools) installed and an initialized gclient checkout of Electron. In order to build electron you'll need to run the following commands.
|
||||
|
||||
```bash
|
||||
e sync -vv
|
||||
e build
|
||||
```
|
||||
|
||||
The initial sync will take approximately ~30 minutes and the build will take ~8 minutes. Incremental syncs and incremental builds are substantially quicker.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
Codespaces doesn't lean very well into gclient based checkouts, the directory structure is slightly strange. There are two locations for the `electron` checkout that both map to the same files under the hood.
|
||||
|
||||
```graphql
|
||||
# Primary gclient checkout container
|
||||
/workspaces/gclient/*
|
||||
└─ src/* - # Chromium checkout
|
||||
└─ electron - # Electron checkout
|
||||
# Symlinked Electron checkout (identical to the above)
|
||||
/workspaces/electron
|
||||
```
|
||||
|
||||
## Goma
|
||||
|
||||
If you are a maintainer [with Goma access](../docs/development/goma.md) it should be automatically configured and authenticated when you spin up a new codespaces instance. You can validate this by checking `e d goma_auth info` or by checking that your build-tools configuration has a goma mode of `cluster`.
|
||||
|
||||
## Running Electron
|
||||
|
||||
You can run Electron in a few ways. If you just want to see if it launches:
|
||||
|
||||
```bash
|
||||
# Enter an interactive JS prompt headlessly
|
||||
xvfb-run e start -i
|
||||
```
|
||||
|
||||
But if you want to actually see Electron you will need to use the built-in VNC capability. If you click "Ports" in codespaces and then open the `VNC web client` forwarded port you should see a web based VNC portal in your browser. When you are asked for a password use `builduser`.
|
||||
|
||||
Once in the VNC UI you can open `Applications -> System -> XTerm` which will open a VNC based terminal app and then you can run `e start` like normal and Electron will open in your VNC session.
|
||||
|
||||
## Running Tests
|
||||
|
||||
You run tests via build-tools and `xvfb`.
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
xvfb-run e test
|
||||
|
||||
# Run the main process tests
|
||||
xvfb-run e test --runners=main
|
||||
|
||||
# Run the old remote tests
|
||||
xvfb-run e test --runners=remote
|
||||
```
|
||||
43
.devcontainer/devcontainer.json
Normal file
43
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "buildtools",
|
||||
"onCreateCommand": ".devcontainer/on-create-command.sh",
|
||||
"workspaceFolder": "/workspaces/gclient/src/electron",
|
||||
"extensions": [
|
||||
"joeleinbinder.mojom-language",
|
||||
"rafaelmaiolla.diff",
|
||||
"surajbarkale.ninja",
|
||||
"ms-vscode.cpptools",
|
||||
"mutantdino.resourcemonitor",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"shakram02.bash-beautify",
|
||||
"marshallofsound.gnls-electron"
|
||||
],
|
||||
"settings": {
|
||||
"[gn]": {
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"editor.tabSize": 2,
|
||||
"bashBeautify.tabSize": 2
|
||||
},
|
||||
"forwardPorts": [8088, 6080, 5901],
|
||||
"portsAttributes": {
|
||||
"8088": {
|
||||
"label": "Goma Control Panel",
|
||||
"onAutoForward": "silent"
|
||||
},
|
||||
"6080": {
|
||||
"label": "VNC web client (noVNC)",
|
||||
"onAutoForward": "silent"
|
||||
},
|
||||
"5901": {
|
||||
"label": "VNC TCP port",
|
||||
"onAutoForward": "silent"
|
||||
}
|
||||
},
|
||||
"hostRequirements": {
|
||||
"storage": "32gb",
|
||||
"cpus": 8
|
||||
},
|
||||
"remoteUser": "builduser"
|
||||
}
|
||||
19
.devcontainer/docker-compose.yml
Normal file
19
.devcontainer/docker-compose.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
buildtools:
|
||||
image: ghcr.io/electron/devcontainer:27db4a3e3512bfd2e47f58cea69922da0835f1d9
|
||||
|
||||
volumes:
|
||||
- ..:/workspaces/gclient/src/electron:cached
|
||||
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
|
||||
command: /bin/sh -c "while sleep 1000; do :; done"
|
||||
|
||||
user: builduser
|
||||
|
||||
cap_add:
|
||||
- SYS_PTRACE
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
74
.devcontainer/on-create-command.sh
Executable file
74
.devcontainer/on-create-command.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
buildtools=$HOME/.electron_build_tools
|
||||
gclient_root=/workspaces/gclient
|
||||
buildtools_configs=/workspaces/buildtools-configs
|
||||
|
||||
export PATH="$PATH:$buildtools/src"
|
||||
|
||||
# Create the persisted buildtools config folder
|
||||
mkdir -p $buildtools_configs
|
||||
rm -f $buildtools/configs
|
||||
ln -s $buildtools_configs $buildtools/configs
|
||||
|
||||
# Write the gclient config if it does not already exist
|
||||
if [ ! -f $gclient_root/.gclient ]; then
|
||||
echo "solutions = [
|
||||
{ \"name\" : \"src/electron\",
|
||||
\"url\" : \"https://github.com/electron/electron\",
|
||||
\"deps_file\" : \"DEPS\",
|
||||
\"managed\" : False,
|
||||
\"custom_deps\" : {
|
||||
},
|
||||
\"custom_vars\": {},
|
||||
},
|
||||
]
|
||||
" >$gclient_root/.gclient
|
||||
fi
|
||||
|
||||
# Write the default buildtools config file if it does
|
||||
# not already exist
|
||||
if [ ! -f $buildtools/configs/evm.testing.json ]; then
|
||||
write_config() {
|
||||
echo "
|
||||
{
|
||||
\"root\": \"/workspaces/gclient\",
|
||||
\"goma\": \"$1\",
|
||||
\"gen\": {
|
||||
\"args\": [
|
||||
\"import(\\\"//electron/build/args/testing.gn\\\")\",
|
||||
\"import(\\\"/home/builduser/.electron_build_tools/third_party/goma.gn\\\")\"
|
||||
],
|
||||
\"out\": \"Testing\"
|
||||
},
|
||||
\"env\": {
|
||||
\"CHROMIUM_BUILDTOOLS_PATH\": \"/workspaces/gclient/src/buildtools\",
|
||||
\"GIT_CACHE_PATH\": \"/workspaces/gclient/.git-cache\"
|
||||
},
|
||||
\"remotes\": {
|
||||
\"electron\": {
|
||||
\"origin\": \"https://github.com/electron/electron.git\"
|
||||
}
|
||||
}
|
||||
}
|
||||
" >$buildtools/configs/evm.testing.json
|
||||
}
|
||||
|
||||
# Start out as cache only
|
||||
write_config cache-only
|
||||
|
||||
e use testing
|
||||
|
||||
# Attempt to auth to the goma service via codespaces tokens
|
||||
# if it works we can use the goma cluster
|
||||
export NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN
|
||||
if e d goma_auth login; then
|
||||
write_config cluster
|
||||
fi
|
||||
else
|
||||
# Even if the config file existed we still need to re-auth with the goma
|
||||
# cluster
|
||||
NOTGOMA_CODESPACES_TOKEN=$GITHUB_TOKEN e d goma_auth login || true
|
||||
fi
|
||||
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -16,3 +16,4 @@ DEPS @electron/wg-upgrades
|
||||
/lib/browser/guest-view-manager.ts @electron/wg-security
|
||||
/lib/browser/guest-window-proxy.ts @electron/wg-security
|
||||
/lib/browser/rpc-server.ts @electron/wg-security
|
||||
/lib/renderer/security-warnings.ts @electron/wg-security
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -37,4 +37,4 @@ body:
|
||||
label: Additional Information
|
||||
description: Add any other context about the problem here.
|
||||
validations:
|
||||
required: true
|
||||
required: false
|
||||
|
||||
25
BUILD.gn
25
BUILD.gn
@@ -187,6 +187,12 @@ action("electron_js2c") {
|
||||
rebase_path(sources, root_build_dir)
|
||||
}
|
||||
|
||||
action("generate_config_gypi") {
|
||||
outputs = [ "$root_gen_dir/config.gypi" ]
|
||||
script = "script/generate-config-gypi.py"
|
||||
args = rebase_path(outputs) + [ target_cpu ]
|
||||
}
|
||||
|
||||
target_gen_default_app_js = "$target_gen_dir/js/default_app"
|
||||
|
||||
typescript_build("default_app_js") {
|
||||
@@ -307,6 +313,23 @@ action("electron_fuses") {
|
||||
args = rebase_path(outputs)
|
||||
}
|
||||
|
||||
action("electron_generate_node_defines") {
|
||||
script = "build/generate_node_defines.py"
|
||||
|
||||
inputs = [
|
||||
"//third_party/electron_node/src/tracing/trace_event_common.h",
|
||||
"//third_party/electron_node/src/tracing/trace_event.h",
|
||||
"//third_party/electron_node/src/util.h",
|
||||
]
|
||||
|
||||
outputs = [
|
||||
"$target_gen_dir/push_and_undef_node_defines.h",
|
||||
"$target_gen_dir/pop_node_defines.h",
|
||||
]
|
||||
|
||||
args = [ rebase_path(target_gen_dir) ] + rebase_path(inputs)
|
||||
}
|
||||
|
||||
source_set("electron_lib") {
|
||||
configs += [ "//v8:external_startup_data" ]
|
||||
configs += [ "//third_party/electron_node:node_internals" ]
|
||||
@@ -318,6 +341,7 @@ source_set("electron_lib") {
|
||||
|
||||
deps = [
|
||||
":electron_fuses",
|
||||
":electron_generate_node_defines",
|
||||
":electron_js2c",
|
||||
":electron_version_header",
|
||||
":resources",
|
||||
@@ -329,6 +353,7 @@ source_set("electron_lib") {
|
||||
"//base/allocator:buildflags",
|
||||
"//chrome/app:command_ids",
|
||||
"//chrome/app/resources:platform_locale_settings",
|
||||
"//components/autofill/core/common:features",
|
||||
"//components/certificate_transparency",
|
||||
"//components/language/core/browser",
|
||||
"//components/net_log",
|
||||
|
||||
4
DEPS
4
DEPS
@@ -15,9 +15,9 @@ gclient_gn_args = [
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'94.0.4606.61',
|
||||
'96.0.4647.0',
|
||||
'node_version':
|
||||
'v16.5.0',
|
||||
'v16.9.1',
|
||||
'nan_version':
|
||||
# The following commit hash of NAN is v2.14.2 with *only* changes to the
|
||||
# test suite. This should be updated to a specific tag when one becomes
|
||||
|
||||
@@ -1 +1 @@
|
||||
15.1.1
|
||||
16.0.0-beta.1
|
||||
@@ -60,7 +60,6 @@ npm start
|
||||
- [electronjs.org/community#boilerplates](https://electronjs.org/community#boilerplates) - Sample starter apps created by the community
|
||||
- [electron/simple-samples](https://github.com/electron/simple-samples) - Small applications with ideas for taking them further
|
||||
- [electron/electron-api-demos](https://github.com/electron/electron-api-demos) - An Electron app that teaches you how to use Electron
|
||||
- [hokein/electron-sample-apps](https://github.com/hokein/electron-sample-apps) - Small demo apps for the various Electron APIs
|
||||
|
||||
## Programmatic usage
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ build_script:
|
||||
}
|
||||
}
|
||||
}
|
||||
- if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync --with_branch_heads --with_tags --ignore_locks)
|
||||
- if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync )
|
||||
- ps: >-
|
||||
if ($env:SAVE_GCLIENT_SRC -eq 'true') {
|
||||
# archive current source for future use
|
||||
|
||||
@@ -2,7 +2,7 @@ is_electron_build = true
|
||||
root_extra_deps = [ "//electron" ]
|
||||
|
||||
# Registry of NMVs --> https://github.com/nodejs/node/blob/master/doc/abi_version_registry.json
|
||||
node_module_version = 98
|
||||
node_module_version = 99
|
||||
|
||||
v8_promise_internal_field_count = 1
|
||||
v8_typed_array_max_size_in_heap = 0
|
||||
|
||||
34
build/generate_node_defines.py
Executable file
34
build/generate_node_defines.py
Executable file
@@ -0,0 +1,34 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
DEFINE_EXTRACT_REGEX = re.compile('^ *# *define (\w*)', re.MULTILINE)
|
||||
|
||||
def main(outDir, headers):
|
||||
defines = []
|
||||
for filename in headers:
|
||||
with open(filename, 'r') as f:
|
||||
content = f.read()
|
||||
defines += read_defines(content)
|
||||
|
||||
push_and_undef = ''
|
||||
for define in defines:
|
||||
push_and_undef += '#pragma push_macro("%s")\n' % define
|
||||
push_and_undef += '#undef %s\n' % define
|
||||
with open(os.path.join(outDir, 'push_and_undef_node_defines.h'), 'w') as o:
|
||||
o.write(push_and_undef)
|
||||
|
||||
pop = ''
|
||||
for define in defines:
|
||||
pop += '#pragma pop_macro("%s")\n' % define
|
||||
with open(os.path.join(outDir, 'pop_node_defines.h'), 'w') as o:
|
||||
o.write(pop)
|
||||
|
||||
def read_defines(content):
|
||||
defines = []
|
||||
for match in DEFINE_EXTRACT_REGEX.finditer(content):
|
||||
defines.append(match.group(1))
|
||||
return defines
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1], sys.argv[2:])
|
||||
@@ -5,8 +5,8 @@ template("npm_action") {
|
||||
|
||||
action("npm_pre_flight_" + target_name) {
|
||||
inputs = [
|
||||
"package.json",
|
||||
"yarn.lock",
|
||||
"//electron/package.json",
|
||||
"//electron/yarn.lock",
|
||||
]
|
||||
script = "//electron/build/npm-run.py"
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ template("webpack_build") {
|
||||
rebase_path("$target_gen_dir/buildflags/buildflags.h"),
|
||||
"--env.mode=" + mode,
|
||||
]
|
||||
deps += [ "buildflags" ]
|
||||
deps += [ "//electron/buildflags" ]
|
||||
|
||||
outputs = [ invoker.out_file ]
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ static_library("chrome") {
|
||||
"//chrome/browser/predictors/proxy_lookup_client_impl.h",
|
||||
"//chrome/browser/predictors/resolve_host_client_impl.cc",
|
||||
"//chrome/browser/predictors/resolve_host_client_impl.h",
|
||||
"//chrome/browser/process_singleton.h",
|
||||
"//chrome/browser/ui/browser_dialogs.cc",
|
||||
"//chrome/browser/ui/browser_dialogs.h",
|
||||
"//chrome/browser/ui/views/autofill/autofill_popup_view_utils.cc",
|
||||
"//chrome/browser/ui/views/autofill/autofill_popup_view_utils.h",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper.cc",
|
||||
@@ -57,6 +60,10 @@ static_library("chrome") {
|
||||
"//extensions/browser/app_window/size_constraints.h",
|
||||
]
|
||||
|
||||
if (is_posix) {
|
||||
sources += [ "//chrome/browser/process_singleton_posix.cc" ]
|
||||
}
|
||||
|
||||
if (is_mac) {
|
||||
sources += [
|
||||
"//chrome/browser/extensions/global_shortcut_listener_mac.h",
|
||||
@@ -65,6 +72,7 @@ static_library("chrome") {
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.h",
|
||||
"//chrome/browser/media/webrtc/system_media_capture_permissions_mac.mm",
|
||||
"//chrome/browser/media/webrtc/window_icon_util_mac.mm",
|
||||
"//chrome/browser/process_singleton_mac.mm",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.h",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper_view_mac.mm",
|
||||
]
|
||||
@@ -76,6 +84,7 @@ static_library("chrome") {
|
||||
"//chrome/browser/extensions/global_shortcut_listener_win.h",
|
||||
"//chrome/browser/icon_loader_win.cc",
|
||||
"//chrome/browser/media/webrtc/window_icon_util_win.cc",
|
||||
"//chrome/browser/process_singleton_win.cc",
|
||||
"//chrome/browser/ui/frame/window_frame_util.h",
|
||||
"//chrome/browser/ui/view_ids.h",
|
||||
"//chrome/browser/win/chrome_process_finder.cc",
|
||||
@@ -203,6 +212,7 @@ static_library("chrome") {
|
||||
"//components/services/print_compositor",
|
||||
"//components/services/print_compositor/public/cpp",
|
||||
"//components/services/print_compositor/public/mojom",
|
||||
"//printing/backend",
|
||||
]
|
||||
|
||||
deps += [
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
#define CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/sequence_checker.h"
|
||||
#include "ui/gfx/native_widget_types.h"
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/message_window.h"
|
||||
#endif // defined(OS_WIN)
|
||||
|
||||
namespace base {
|
||||
class CommandLine;
|
||||
}
|
||||
|
||||
// ProcessSingleton ----------------------------------------------------------
|
||||
//
|
||||
// This class allows different browser processes to communicate with
|
||||
// each other. It is named according to the user data directory, so
|
||||
// we can be sure that no more than one copy of the application can be
|
||||
// running at once with a given data directory.
|
||||
//
|
||||
// Implementation notes:
|
||||
// - the Windows implementation uses an invisible global message window;
|
||||
// - the Linux implementation uses a Unix domain socket in the user data dir.
|
||||
|
||||
class ProcessSingleton {
|
||||
public:
|
||||
enum NotifyResult {
|
||||
PROCESS_NONE,
|
||||
PROCESS_NOTIFIED,
|
||||
PROFILE_IN_USE,
|
||||
LOCK_ERROR,
|
||||
};
|
||||
|
||||
// Implement this callback to handle notifications from other processes. The
|
||||
// callback will receive the command line and directory with which the other
|
||||
// Chrome process was launched. Return true if the command line will be
|
||||
// handled within the current browser instance or false if the remote process
|
||||
// should handle it (i.e., because the current process is shutting down).
|
||||
using NotificationCallback = base::RepeatingCallback<bool(
|
||||
const base::CommandLine::StringVector& command_line,
|
||||
const base::FilePath& current_directory)>;
|
||||
|
||||
ProcessSingleton(const base::FilePath& user_data_dir,
|
||||
const NotificationCallback& notification_callback);
|
||||
~ProcessSingleton();
|
||||
|
||||
// Notify another process, if available. Otherwise sets ourselves as the
|
||||
// singleton instance. Returns PROCESS_NONE if we became the singleton
|
||||
// instance. Callers are guaranteed to either have notified an existing
|
||||
// process or have grabbed the singleton (unless the profile is locked by an
|
||||
// unreachable process).
|
||||
// TODO(brettw): Make the implementation of this method non-platform-specific
|
||||
// by making Linux re-use the Windows implementation.
|
||||
NotifyResult NotifyOtherProcessOrCreate();
|
||||
void StartListeningOnSocket();
|
||||
void OnBrowserReady();
|
||||
|
||||
// Sets ourself up as the singleton instance. Returns true on success. If
|
||||
// false is returned, we are not the singleton instance and the caller must
|
||||
// exit.
|
||||
// NOTE: Most callers should generally prefer NotifyOtherProcessOrCreate() to
|
||||
// this method, only callers for whom failure is preferred to notifying
|
||||
// another process should call this directly.
|
||||
bool Create();
|
||||
|
||||
// Clear any lock state during shutdown.
|
||||
void Cleanup();
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
static void DisablePromptForTesting();
|
||||
#endif
|
||||
#if defined(OS_WIN)
|
||||
// Called to query whether to kill a hung browser process that has visible
|
||||
// windows. Return true to allow killing the hung process.
|
||||
using ShouldKillRemoteProcessCallback = base::RepeatingCallback<bool()>;
|
||||
void OverrideShouldKillRemoteProcessCallbackForTesting(
|
||||
const ShouldKillRemoteProcessCallback& display_dialog_callback);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Notify another process, if available.
|
||||
// Returns true if another process was found and notified, false if we should
|
||||
// continue with the current process.
|
||||
// On Windows, Create() has to be called before this.
|
||||
NotifyResult NotifyOtherProcess();
|
||||
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
// Exposed for testing. We use a timeout on Linux, and in tests we want
|
||||
// this timeout to be short.
|
||||
NotifyResult NotifyOtherProcessWithTimeout(
|
||||
const base::CommandLine& command_line,
|
||||
int retry_attempts,
|
||||
const base::TimeDelta& timeout,
|
||||
bool kill_unresponsive);
|
||||
NotifyResult NotifyOtherProcessWithTimeoutOrCreate(
|
||||
const base::CommandLine& command_line,
|
||||
int retry_attempts,
|
||||
const base::TimeDelta& timeout);
|
||||
void OverrideCurrentPidForTesting(base::ProcessId pid);
|
||||
void OverrideKillCallbackForTesting(
|
||||
const base::RepeatingCallback<void(int)>& callback);
|
||||
#endif
|
||||
|
||||
private:
|
||||
NotificationCallback notification_callback_; // Handler for notifications.
|
||||
|
||||
#if defined(OS_WIN)
|
||||
HWND remote_window_ = nullptr; // The HWND_MESSAGE of another browser.
|
||||
base::win::MessageWindow window_; // The message-only window.
|
||||
bool is_virtualized_ =
|
||||
false; // Stuck inside Microsoft Softricity VM environment.
|
||||
HANDLE lock_file_ = INVALID_HANDLE_VALUE;
|
||||
base::FilePath user_data_dir_;
|
||||
ShouldKillRemoteProcessCallback should_kill_remote_process_callback_;
|
||||
#elif defined(OS_POSIX) && !defined(OS_ANDROID)
|
||||
// Start listening to the socket.
|
||||
void StartListening(int sock);
|
||||
|
||||
// Return true if the given pid is one of our child processes.
|
||||
// Assumes that the current pid is the root of all pids of the current
|
||||
// instance.
|
||||
bool IsSameChromeInstance(pid_t pid);
|
||||
|
||||
// Extract the process's pid from a symbol link path and if it is on
|
||||
// the same host, kill the process, unlink the lock file and return true.
|
||||
// If the process is part of the same chrome instance, unlink the lock file
|
||||
// and return true without killing it.
|
||||
// If the process is on a different host, return false.
|
||||
bool KillProcessByLockPath();
|
||||
|
||||
// Default function to kill a process, overridable by tests.
|
||||
void KillProcess(int pid);
|
||||
|
||||
// Allow overriding for tests.
|
||||
base::ProcessId current_pid_;
|
||||
|
||||
// Function to call when the other process is hung and needs to be killed.
|
||||
// Allows overriding for tests.
|
||||
base::RepeatingCallback<void(int)> kill_callback_;
|
||||
|
||||
// Path in file system to the socket.
|
||||
base::FilePath socket_path_;
|
||||
|
||||
// Path in file system to the lock.
|
||||
base::FilePath lock_path_;
|
||||
|
||||
// Path in file system to the cookie file.
|
||||
base::FilePath cookie_path_;
|
||||
|
||||
// Temporary directory to hold the socket.
|
||||
base::ScopedTempDir socket_dir_;
|
||||
|
||||
// Helper class for linux specific messages. LinuxWatcher is ref counted
|
||||
// because it posts messages between threads.
|
||||
class LinuxWatcher;
|
||||
scoped_refptr<LinuxWatcher> watcher_;
|
||||
int sock_ = -1;
|
||||
bool listen_on_ready_ = false;
|
||||
#endif
|
||||
|
||||
SEQUENCE_CHECKER(sequence_checker_);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessSingleton);
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_PROCESS_SINGLETON_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,315 +0,0 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/process_singleton.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "base/base_paths.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/process/process.h"
|
||||
#include "base/process/process_info.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/win/registry.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "chrome/browser/win/chrome_process_finder.h"
|
||||
#include "content/public/common/result_codes.h"
|
||||
#include "net/base/escape.h"
|
||||
#include "ui/gfx/win/hwnd_util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const char kLockfile[] = "lockfile";
|
||||
|
||||
// A helper class that acquires the given |mutex| while the AutoLockMutex is in
|
||||
// scope.
|
||||
class AutoLockMutex {
|
||||
public:
|
||||
explicit AutoLockMutex(HANDLE mutex) : mutex_(mutex) {
|
||||
DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
|
||||
DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
|
||||
}
|
||||
|
||||
~AutoLockMutex() {
|
||||
BOOL released = ::ReleaseMutex(mutex_);
|
||||
DPCHECK(released);
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE mutex_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoLockMutex);
|
||||
};
|
||||
|
||||
// A helper class that releases the given |mutex| while the AutoUnlockMutex is
|
||||
// in scope and immediately re-acquires it when going out of scope.
|
||||
class AutoUnlockMutex {
|
||||
public:
|
||||
explicit AutoUnlockMutex(HANDLE mutex) : mutex_(mutex) {
|
||||
BOOL released = ::ReleaseMutex(mutex_);
|
||||
DPCHECK(released);
|
||||
}
|
||||
|
||||
~AutoUnlockMutex() {
|
||||
DWORD result = ::WaitForSingleObject(mutex_, INFINITE);
|
||||
DPCHECK(result == WAIT_OBJECT_0) << "Result = " << result;
|
||||
}
|
||||
|
||||
private:
|
||||
HANDLE mutex_;
|
||||
DISALLOW_COPY_AND_ASSIGN(AutoUnlockMutex);
|
||||
};
|
||||
|
||||
// Checks the visibility of the enumerated window and signals once a visible
|
||||
// window has been found.
|
||||
BOOL CALLBACK BrowserWindowEnumeration(HWND window, LPARAM param) {
|
||||
bool* result = reinterpret_cast<bool*>(param);
|
||||
*result = ::IsWindowVisible(window) != 0;
|
||||
// Stops enumeration if a visible window has been found.
|
||||
return !*result;
|
||||
}
|
||||
|
||||
bool ParseCommandLine(const COPYDATASTRUCT* cds,
|
||||
base::CommandLine::StringVector* parsed_command_line,
|
||||
base::FilePath* current_directory) {
|
||||
// We should have enough room for the shortest command (min_message_size)
|
||||
// and also be a multiple of wchar_t bytes. The shortest command
|
||||
// possible is L"START\0\0" (empty current directory and command line).
|
||||
static const int min_message_size = 7;
|
||||
if (cds->cbData < min_message_size * sizeof(wchar_t) ||
|
||||
cds->cbData % sizeof(wchar_t) != 0) {
|
||||
LOG(WARNING) << "Invalid WM_COPYDATA, length = " << cds->cbData;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We split the string into 4 parts on NULLs.
|
||||
DCHECK(cds->lpData);
|
||||
const std::wstring msg(static_cast<wchar_t*>(cds->lpData),
|
||||
cds->cbData / sizeof(wchar_t));
|
||||
const std::wstring::size_type first_null = msg.find_first_of(L'\0');
|
||||
if (first_null == 0 || first_null == std::wstring::npos) {
|
||||
// no NULL byte, don't know what to do
|
||||
LOG(WARNING) << "Invalid WM_COPYDATA, length = " << msg.length()
|
||||
<< ", first null = " << first_null;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decode the command, which is everything until the first NULL.
|
||||
if (msg.substr(0, first_null) == L"START") {
|
||||
// Another instance is starting parse the command line & do what it would
|
||||
// have done.
|
||||
VLOG(1) << "Handling STARTUP request from another process";
|
||||
const std::wstring::size_type second_null =
|
||||
msg.find_first_of(L'\0', first_null + 1);
|
||||
if (second_null == std::wstring::npos || first_null == msg.length() - 1 ||
|
||||
second_null == msg.length()) {
|
||||
LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
|
||||
"parts separated by NULLs";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get current directory.
|
||||
*current_directory =
|
||||
base::FilePath(msg.substr(first_null + 1, second_null - first_null));
|
||||
|
||||
const std::wstring::size_type third_null =
|
||||
msg.find_first_of(L'\0', second_null + 1);
|
||||
if (third_null == std::wstring::npos || third_null == msg.length()) {
|
||||
LOG(WARNING) << "Invalid format for start command, we need a string in 4 "
|
||||
"parts separated by NULLs";
|
||||
}
|
||||
|
||||
// Get command line.
|
||||
const std::wstring cmd_line =
|
||||
msg.substr(second_null + 1, third_null - second_null);
|
||||
*parsed_command_line = base::CommandLine::FromString(cmd_line).argv();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProcessLaunchNotification(
|
||||
const ProcessSingleton::NotificationCallback& notification_callback,
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam,
|
||||
LRESULT* result) {
|
||||
if (message != WM_COPYDATA)
|
||||
return false;
|
||||
|
||||
// Handle the WM_COPYDATA message from another process.
|
||||
const COPYDATASTRUCT* cds = reinterpret_cast<COPYDATASTRUCT*>(lparam);
|
||||
|
||||
base::CommandLine::StringVector parsed_command_line;
|
||||
base::FilePath current_directory;
|
||||
if (!ParseCommandLine(cds, &parsed_command_line, ¤t_directory)) {
|
||||
*result = TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
*result = notification_callback.Run(parsed_command_line, current_directory)
|
||||
? TRUE
|
||||
: FALSE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TerminateAppWithError() {
|
||||
// TODO: This is called when the secondary process can't ping the primary
|
||||
// process. Need to find out what to do here.
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ProcessSingleton::ProcessSingleton(
|
||||
const base::FilePath& user_data_dir,
|
||||
const NotificationCallback& notification_callback)
|
||||
: notification_callback_(notification_callback),
|
||||
user_data_dir_(user_data_dir),
|
||||
should_kill_remote_process_callback_(
|
||||
base::BindRepeating(&TerminateAppWithError)) {
|
||||
// The user_data_dir may have not been created yet.
|
||||
base::CreateDirectoryAndGetError(user_data_dir, nullptr);
|
||||
}
|
||||
|
||||
ProcessSingleton::~ProcessSingleton() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
if (lock_file_ != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(lock_file_);
|
||||
}
|
||||
|
||||
// Code roughly based on Mozilla.
|
||||
ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
|
||||
if (is_virtualized_)
|
||||
return PROCESS_NOTIFIED; // We already spawned the process in this case.
|
||||
if (lock_file_ == INVALID_HANDLE_VALUE && !remote_window_) {
|
||||
return LOCK_ERROR;
|
||||
} else if (!remote_window_) {
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
|
||||
switch (chrome::AttemptToNotifyRunningChrome(remote_window_)) {
|
||||
case chrome::NOTIFY_SUCCESS:
|
||||
return PROCESS_NOTIFIED;
|
||||
case chrome::NOTIFY_FAILED:
|
||||
remote_window_ = NULL;
|
||||
return PROCESS_NONE;
|
||||
case chrome::NOTIFY_WINDOW_HUNG:
|
||||
// Fall through and potentially terminate the hung browser.
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD process_id = 0;
|
||||
DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id);
|
||||
if (!thread_id || !process_id) {
|
||||
remote_window_ = NULL;
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
base::Process process = base::Process::Open(process_id);
|
||||
|
||||
// The window is hung. Scan for every window to find a visible one.
|
||||
bool visible_window = false;
|
||||
::EnumThreadWindows(thread_id, &BrowserWindowEnumeration,
|
||||
reinterpret_cast<LPARAM>(&visible_window));
|
||||
|
||||
// If there is a visible browser window, ask the user before killing it.
|
||||
if (visible_window && !should_kill_remote_process_callback_.Run()) {
|
||||
// The user denied. Quit silently.
|
||||
return PROCESS_NOTIFIED;
|
||||
}
|
||||
|
||||
// Time to take action. Kill the browser process.
|
||||
process.Terminate(content::RESULT_CODE_HUNG, true);
|
||||
remote_window_ = NULL;
|
||||
return PROCESS_NONE;
|
||||
}
|
||||
|
||||
ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessOrCreate() {
|
||||
ProcessSingleton::NotifyResult result = PROCESS_NONE;
|
||||
if (!Create()) {
|
||||
result = NotifyOtherProcess();
|
||||
if (result == PROCESS_NONE)
|
||||
result = PROFILE_IN_USE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProcessSingleton::StartListeningOnSocket() {}
|
||||
void ProcessSingleton::OnBrowserReady() {}
|
||||
|
||||
// Look for a Chrome instance that uses the same profile directory. If there
|
||||
// isn't one, create a message window with its title set to the profile
|
||||
// directory path.
|
||||
bool ProcessSingleton::Create() {
|
||||
static const wchar_t kMutexName[] = L"Local\\AtomProcessSingletonStartup!";
|
||||
|
||||
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
|
||||
if (!remote_window_) {
|
||||
// Make sure we will be the one and only process creating the window.
|
||||
// We use a named Mutex since we are protecting against multi-process
|
||||
// access. As documented, it's clearer to NOT request ownership on creation
|
||||
// since it isn't guaranteed we will get it. It is better to create it
|
||||
// without ownership and explicitly get the ownership afterward.
|
||||
base::win::ScopedHandle only_me(::CreateMutex(NULL, FALSE, kMutexName));
|
||||
if (!only_me.IsValid()) {
|
||||
DPLOG(FATAL) << "CreateMutex failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoLockMutex auto_lock_only_me(only_me.Get());
|
||||
|
||||
// We now own the mutex so we are the only process that can create the
|
||||
// window at this time, but we must still check if someone created it
|
||||
// between the time where we looked for it above and the time the mutex
|
||||
// was given to us.
|
||||
remote_window_ = chrome::FindRunningChromeWindow(user_data_dir_);
|
||||
if (!remote_window_) {
|
||||
// We have to make sure there is no Chrome instance running on another
|
||||
// machine that uses the same profile.
|
||||
base::FilePath lock_file_path = user_data_dir_.AppendASCII(kLockfile);
|
||||
lock_file_ =
|
||||
::CreateFile(lock_file_path.value().c_str(), GENERIC_WRITE,
|
||||
FILE_SHARE_READ, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
||||
DWORD error = ::GetLastError();
|
||||
LOG_IF(WARNING, lock_file_ != INVALID_HANDLE_VALUE &&
|
||||
error == ERROR_ALREADY_EXISTS)
|
||||
<< "Lock file exists but is writable.";
|
||||
LOG_IF(ERROR, lock_file_ == INVALID_HANDLE_VALUE)
|
||||
<< "Lock file can not be created! Error code: " << error;
|
||||
|
||||
if (lock_file_ != INVALID_HANDLE_VALUE) {
|
||||
// Set the window's title to the path of our user data directory so
|
||||
// other Chrome instances can decide if they should forward to us.
|
||||
bool result =
|
||||
window_.CreateNamed(base::BindRepeating(&ProcessLaunchNotification,
|
||||
notification_callback_),
|
||||
user_data_dir_.value());
|
||||
|
||||
// NB: Ensure that if the primary app gets started as elevated
|
||||
// admin inadvertently, secondary windows running not as elevated
|
||||
// will still be able to send messages
|
||||
::ChangeWindowMessageFilterEx(window_.hwnd(), WM_COPYDATA, MSGFLT_ALLOW,
|
||||
NULL);
|
||||
CHECK(result && window_.hwnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return window_.hwnd() != NULL;
|
||||
}
|
||||
|
||||
void ProcessSingleton::Cleanup() {}
|
||||
|
||||
void ProcessSingleton::OverrideShouldKillRemoteProcessCallbackForTesting(
|
||||
const ShouldKillRemoteProcessCallback& display_dialog_callback) {
|
||||
should_kill_remote_process_callback_ = display_dialog_callback;
|
||||
}
|
||||
@@ -131,15 +131,15 @@ Returns `Object`:
|
||||
|
||||
Returns an Object containing `title` and `url` keys representing the bookmark in
|
||||
the clipboard. The `title` and `url` values will be empty strings when the
|
||||
bookmark is unavailable.
|
||||
bookmark is unavailable. The `title` value will always be empty on Windows.
|
||||
|
||||
### `clipboard.writeBookmark(title, url[, type])` _macOS_ _Windows_
|
||||
|
||||
* `title` String
|
||||
* `title` String - Unused on Windows
|
||||
* `url` String
|
||||
* `type` String (optional) - Can be `selection` or `clipboard`; default is 'clipboard'. `selection` is only available on Linux.
|
||||
|
||||
Writes the `title` and `url` into the clipboard as a bookmark.
|
||||
Writes the `title` (macOS only) and `url` into the clipboard as a bookmark.
|
||||
|
||||
**Note:** Most apps on Windows don't support pasting bookmarks into them so
|
||||
you can use `clipboard.write` to write both a bookmark and fallback text to the
|
||||
|
||||
@@ -53,3 +53,12 @@ Returns `Boolean` - Whether the command-line switch is present.
|
||||
Returns `String` - The command-line switch value.
|
||||
|
||||
**Note:** When the switch is not present or has no value, it returns empty string.
|
||||
|
||||
#### `commandLine.removeSwitch(switch)`
|
||||
|
||||
* `switch` String - A command-line switch
|
||||
|
||||
Removes the specified switch from Chromium's command line.
|
||||
|
||||
**Note:** This will not affect `process.argv`. The intended usage of this function is to
|
||||
control Chromium's behavior.
|
||||
|
||||
@@ -19,6 +19,9 @@ following projects:
|
||||
* [socorro](https://github.com/mozilla/socorro)
|
||||
* [mini-breakpad-server](https://github.com/electron/mini-breakpad-server)
|
||||
|
||||
> **Note:** Electron uses Crashpad, not Breakpad, to collect and upload
|
||||
> crashes, but for the time being, the [upload protocol is the same](https://chromium.googlesource.com/crashpad/crashpad/+/HEAD/doc/overview_design.md#Upload-to-collection-server).
|
||||
|
||||
Or use a 3rd party hosted solution:
|
||||
|
||||
* [Backtrace](https://backtrace.io/electron/)
|
||||
@@ -26,49 +29,12 @@ Or use a 3rd party hosted solution:
|
||||
* [BugSplat](https://www.bugsplat.com/docs/platforms/electron)
|
||||
|
||||
Crash reports are stored temporarily before being uploaded in a directory
|
||||
underneath the app's user data directory (called 'Crashpad' on Windows and Mac,
|
||||
or 'Crash Reports' on Linux). You can override this directory by calling
|
||||
`app.setPath('crashDumps', '/path/to/crashes')` before starting the crash
|
||||
reporter.
|
||||
underneath the app's user data directory, called 'Crashpad'. You can override
|
||||
this directory by calling `app.setPath('crashDumps', '/path/to/crashes')`
|
||||
before starting the crash reporter.
|
||||
|
||||
On Windows and macOS, Electron uses
|
||||
[crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/master/README.md)
|
||||
to monitor and report crashes. On Linux, Electron uses
|
||||
[breakpad](https://chromium.googlesource.com/breakpad/breakpad/+/master/). This
|
||||
is an implementation detail driven by Chromium, and it may change in future. In
|
||||
particular, crashpad is newer and will likely eventually replace breakpad on
|
||||
all platforms.
|
||||
|
||||
### Note about Node child processes on Linux
|
||||
|
||||
If you are using the Node.js `child_process` module and want to report crashes
|
||||
from those processes on Linux, there is an extra step you will need to take to
|
||||
properly initialize the crash reporter in the child process. This is not
|
||||
necessary on Mac or Windows, as those platforms use Crashpad, which
|
||||
automatically monitors child processes.
|
||||
|
||||
Since `require('electron')` is not available in Node child processes, the
|
||||
following APIs are available on the `process` object in Node child processes.
|
||||
Note that, on Linux, each Node child process has its own separate instance of
|
||||
the breakpad crash reporter. This is dissimilar to renderer child processes,
|
||||
which have a "stub" breakpad reporter which returns information to the main
|
||||
process for reporting.
|
||||
|
||||
#### `process.crashReporter.start(options)`
|
||||
|
||||
See [`crashReporter.start()`](#crashreporterstartoptions).
|
||||
|
||||
#### `process.crashReporter.getParameters()`
|
||||
|
||||
See [`crashReporter.getParameters()`](#crashreportergetparameters).
|
||||
|
||||
#### `process.crashReporter.addExtraParameter(key, value)`
|
||||
|
||||
See [`crashReporter.addExtraParameter(key, value)`](#crashreporteraddextraparameterkey-value).
|
||||
|
||||
#### `process.crashReporter.removeExtraParameter(key)`
|
||||
|
||||
See [`crashReporter.removeExtraParameter(key)`](#crashreporterremoveextraparameterkey).
|
||||
Electron uses [crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/refs/heads/main/README.md)
|
||||
to monitor and report crashes.
|
||||
|
||||
## Methods
|
||||
|
||||
@@ -186,12 +152,6 @@ names must be no longer than 39 bytes, and values must be no longer than 20320
|
||||
bytes. Keys with names longer than the maximum will be silently ignored. Key
|
||||
values longer than the maximum length will be truncated.
|
||||
|
||||
**Note:** On linux values that are longer than 127 bytes will be chunked into
|
||||
multiple keys, each 127 bytes in length. E.g. `addExtraParameter('foo', 'a'.repeat(130))`
|
||||
will result in two chunked keys `foo__1` and `foo__2`, the first will contain
|
||||
the first 127 bytes and the second will contain the remaining 3 bytes. On
|
||||
your crash reporting backend you should stitch together keys in this format.
|
||||
|
||||
### `crashReporter.removeExtraParameter(key)`
|
||||
|
||||
* `key` String - Parameter key, must be no longer than 39 bytes.
|
||||
@@ -203,6 +163,32 @@ will not include this parameter.
|
||||
|
||||
Returns `Record<String, String>` - The current 'extra' parameters of the crash reporter.
|
||||
|
||||
## In Node child processes
|
||||
|
||||
Since `require('electron')` is not available in Node child processes, the
|
||||
following APIs are available on the `process` object in Node child processes.
|
||||
|
||||
#### `process.crashReporter.start(options)`
|
||||
|
||||
See [`crashReporter.start()`](#crashreporterstartoptions).
|
||||
|
||||
Note that if the crash reporter is started in the main process, it will
|
||||
automatically monitor child processes, so it should not be started in the child
|
||||
process. Only use this method if the main process does not initialize the crash
|
||||
reporter.
|
||||
|
||||
#### `process.crashReporter.getParameters()`
|
||||
|
||||
See [`crashReporter.getParameters()`](#crashreportergetparameters).
|
||||
|
||||
#### `process.crashReporter.addExtraParameter(key, value)`
|
||||
|
||||
See [`crashReporter.addExtraParameter(key, value)`](#crashreporteraddextraparameterkey-value).
|
||||
|
||||
#### `process.crashReporter.removeExtraParameter(key)`
|
||||
|
||||
See [`crashReporter.removeExtraParameter(key)`](#crashreporterremoveextraparameterkey).
|
||||
|
||||
## Crash Report Payload
|
||||
|
||||
The crash reporter will send the following data to the `submitURL` as
|
||||
|
||||
@@ -100,6 +100,8 @@ The following methods of `chrome.tabs` are supported:
|
||||
|
||||
- `chrome.tabs.sendMessage`
|
||||
- `chrome.tabs.executeScript`
|
||||
- `chrome.tabs.update` (partial support)
|
||||
- supported properties: `url`, `muted`.
|
||||
|
||||
> **Note:** In Chrome, passing `-1` as a tab ID signifies the "currently active
|
||||
> tab". Since Electron has no such concept, passing `-1` as a tab ID is not
|
||||
|
||||
@@ -297,6 +297,35 @@ app.whenReady().then(() => {
|
||||
width: 800,
|
||||
height: 600
|
||||
})
|
||||
|
||||
win.webContents.session.setPermissionCheckHandler((webContents, permission, requestingOrigin, details) => {
|
||||
if (permission === 'serial') {
|
||||
// Add logic here to determine if permission should be given to allow serial selection
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
// Optionally, retrieve previously persisted devices from a persistent store
|
||||
const grantedDevices = fetchGrantedDevices()
|
||||
|
||||
win.webContents.session.setDevicePermissionHandler((details) => {
|
||||
if (new URL(details.origin).hostname === 'some-host' && details.deviceType === 'serial') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.serial.requestPort` first)
|
||||
return true
|
||||
}
|
||||
|
||||
// Search through the list of devices that have previously been granted permission
|
||||
return grantedDevices.some((grantedDevice) => {
|
||||
return grantedDevice.vendorId === details.device.vendorId &&
|
||||
grantedDevice.productId === details.device.productId &&
|
||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||
})
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
win.webContents.session.on('select-serial-port', (event, portList, webContents, callback) => {
|
||||
event.preventDefault()
|
||||
const selectedPort = portList.find((device) => {
|
||||
@@ -533,7 +562,8 @@ the original network configuration.
|
||||
* `hostname` String
|
||||
* `certificate` [Certificate](structures/certificate.md)
|
||||
* `validatedCertificate` [Certificate](structures/certificate.md)
|
||||
* `verificationResult` String - Verification result from chromium.
|
||||
* `isIssuedByKnownRoot` Boolean - `true` if Chromium recognises the root CA as a standard root. If it isn't then it's probably the case that this certificate was generated by a MITM proxy whose root has been installed locally (for example, by a corporate proxy). This should not be trusted if the `verificationResult` is not `OK`.
|
||||
* `verificationResult` String - `OK` if the certificate is trusted, otherwise an error like `CERT_REVOKED`.
|
||||
* `errorCode` Integer - Error code.
|
||||
* `callback` Function
|
||||
* `verificationResult` Integer - Value can be one of certificate error codes
|
||||
@@ -588,6 +618,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `permissionGranted` Boolean - Allow or deny the permission.
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
* `externalURL` String (optional) - The url of the `openExternal` request.
|
||||
* `securityOrigin` String (optional) - The security origin of the `media` request.
|
||||
* `mediaTypes` String[] (optional) - The types of media access being requested, elements can be `video`
|
||||
or `audio`
|
||||
* `requestingUrl` String - The last URL the requesting frame loaded
|
||||
@@ -646,9 +677,9 @@ session.fromPartition('some-partition').setPermissionCheckHandler((webContents,
|
||||
|
||||
* `handler` Function\<Boolean> | null
|
||||
* `details` Object
|
||||
* `deviceType` String - The type of device that permission is being requested on, can be `hid`.
|
||||
* `deviceType` String - The type of device that permission is being requested on, can be `hid` or `serial`.
|
||||
* `origin` String - The origin URL of the device permission check.
|
||||
* `device` [HIDDevice](structures/hid-device.md) - the device that permission is being requested for.
|
||||
* `device` [HIDDevice](structures/hid-device.md) | [SerialPort](structures/serial-port.md)- the device that permission is being requested for.
|
||||
* `frame` [WebFrameMain](web-frame-main.md) - WebFrameMain checking the device permission.
|
||||
|
||||
Sets the handler which can be used to respond to device permission checks for the `session`.
|
||||
@@ -673,6 +704,8 @@ app.whenReady().then(() => {
|
||||
if (permission === 'hid') {
|
||||
// Add logic here to determine if permission should be given to allow HID selection
|
||||
return true
|
||||
} else if (permission === 'serial') {
|
||||
// Add logic here to determine if permission should be given to allow serial port selection
|
||||
}
|
||||
return false
|
||||
})
|
||||
@@ -693,6 +726,11 @@ app.whenReady().then(() => {
|
||||
grantedDevice.productId === details.device.productId &&
|
||||
grantedDevice.serialNumber && grantedDevice.serialNumber === details.device.serialNumber
|
||||
})
|
||||
} else if (details.deviceType === 'serial') {
|
||||
if (details.device.vendorId === 123 && details.device.productId === 345) {
|
||||
// Always allow this type of device (this allows skipping the call to `navigator.hid.requestDevice` first)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -1494,8 +1494,8 @@ win.loadURL('http://github.com')
|
||||
|
||||
win.webContents.on('did-finish-load', () => {
|
||||
// Use default printing options
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
win.webContents.printToPDF({}).then(data => {
|
||||
const pdfPath = path.join(os.homedir(), 'Desktop', 'temp.pdf')
|
||||
fs.writeFile(pdfPath, data, (error) => {
|
||||
if (error) throw error
|
||||
console.log(`Wrote PDF successfully to ${pdfPath}`)
|
||||
|
||||
@@ -1025,3 +1025,78 @@ Emitted when DevTools is focused / opened.
|
||||
|
||||
[runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70
|
||||
[chrome-webview]: https://developer.chrome.com/docs/extensions/reference/webviewTag/
|
||||
|
||||
### Event: 'context-menu'
|
||||
|
||||
Returns:
|
||||
|
||||
* `params` Object
|
||||
* `x` Integer - x coordinate.
|
||||
* `y` Integer - y coordinate.
|
||||
* `linkURL` String - URL of the link that encloses the node the context menu
|
||||
was invoked on.
|
||||
* `linkText` String - Text associated with the link. May be an empty
|
||||
string if the contents of the link are an image.
|
||||
* `pageURL` String - URL of the top level page that the context menu was
|
||||
invoked on.
|
||||
* `frameURL` String - URL of the subframe that the context menu was invoked
|
||||
on.
|
||||
* `srcURL` String - Source URL for the element that the context menu
|
||||
was invoked on. Elements with source URLs are images, audio and video.
|
||||
* `mediaType` String - Type of the node the context menu was invoked on. Can
|
||||
be `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`.
|
||||
* `hasImageContents` Boolean - Whether the context menu was invoked on an image
|
||||
which has non-empty contents.
|
||||
* `isEditable` Boolean - Whether the context is editable.
|
||||
* `selectionText` String - Text of the selection that the context menu was
|
||||
invoked on.
|
||||
* `titleText` String - Title text of the selection that the context menu was
|
||||
invoked on.
|
||||
* `altText` String - Alt text of the selection that the context menu was
|
||||
invoked on.
|
||||
* `suggestedFilename` String - Suggested filename to be used when saving file through 'Save
|
||||
Link As' option of context menu.
|
||||
* `selectionRect` [Rectangle](structures/rectangle.md) - Rect representing the coordinates in the document space of the selection.
|
||||
* `selectionStartOffset` Number - Start position of the selection text.
|
||||
* `referrerPolicy` [Referrer](structures/referrer.md) - The referrer policy of the frame on which the menu is invoked.
|
||||
* `misspelledWord` String - The misspelled word under the cursor, if any.
|
||||
* `dictionarySuggestions` String[] - An array of suggested words to show the
|
||||
user to replace the `misspelledWord`. Only available if there is a misspelled
|
||||
word and spellchecker is enabled.
|
||||
* `frameCharset` String - The character encoding of the frame on which the
|
||||
menu was invoked.
|
||||
* `inputFieldType` String - If the context menu was invoked on an input
|
||||
field, the type of that field. Possible values are `none`, `plainText`,
|
||||
`password`, `other`.
|
||||
* `spellcheckEnabled` Boolean - If the context is editable, whether or not spellchecking is enabled.
|
||||
* `menuSourceType` String - Input source that invoked the context menu.
|
||||
Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`.
|
||||
* `mediaFlags` Object - The flags for the media element the context menu was
|
||||
invoked on.
|
||||
* `inError` Boolean - Whether the media element has crashed.
|
||||
* `isPaused` Boolean - Whether the media element is paused.
|
||||
* `isMuted` Boolean - Whether the media element is muted.
|
||||
* `hasAudio` Boolean - Whether the media element has audio.
|
||||
* `isLooping` Boolean - Whether the media element is looping.
|
||||
* `isControlsVisible` Boolean - Whether the media element's controls are
|
||||
visible.
|
||||
* `canToggleControls` Boolean - Whether the media element's controls are
|
||||
toggleable.
|
||||
* `canPrint` Boolean - Whether the media element can be printed.
|
||||
* `canSave` Boolean - Whether or not the media element can be downloaded.
|
||||
* `canShowPictureInPicture` Boolean - Whether the media element can show picture-in-picture.
|
||||
* `isShowingPictureInPicture` Boolean - Whether the media element is currently showing picture-in-picture.
|
||||
* `canRotate` Boolean - Whether the media element can be rotated.
|
||||
* `canLoop` Boolean - Whether the media element can be looped.
|
||||
* `editFlags` Object - These flags indicate whether the renderer believes it
|
||||
is able to perform the corresponding action.
|
||||
* `canUndo` Boolean - Whether the renderer believes it can undo.
|
||||
* `canRedo` Boolean - Whether the renderer believes it can redo.
|
||||
* `canCut` Boolean - Whether the renderer believes it can cut.
|
||||
* `canCopy` Boolean - Whether the renderer believes it can copy.
|
||||
* `canPaste` Boolean - Whether the renderer believes it can paste.
|
||||
* `canDelete` Boolean - Whether the renderer believes it can delete.
|
||||
* `canSelectAll` Boolean - Whether the renderer believes it can select all.
|
||||
* `canEditRichly` Boolean - Whether the renderer believes it can edit text richly.
|
||||
|
||||
Emitted when there is a new context menu that needs to be handled.
|
||||
|
||||
@@ -12,6 +12,75 @@ This document uses the following convention to categorize breaking changes:
|
||||
* **Deprecated:** An API was marked as deprecated. The API will continue to function, but will emit a deprecation warning, and will be removed in a future release.
|
||||
* **Removed:** An API or feature was removed, and is no longer supported by Electron.
|
||||
|
||||
## Planned Breaking API Changes (17.0)
|
||||
|
||||
### Removed: `desktopCapturer.getSources` in the renderer
|
||||
|
||||
The `desktopCapturer.getSources` API is now only available in the main process.
|
||||
This has been changed in order to improve the default security of Electron
|
||||
apps.
|
||||
|
||||
If you need this functionality, it can be replaced as follows:
|
||||
|
||||
```js
|
||||
// Main process
|
||||
const { ipcMain, desktopCapturer } = require('electron')
|
||||
|
||||
ipcMain.handle(
|
||||
'DESKTOP_CAPTURER_GET_SOURCES',
|
||||
(event, opts) => desktopCapturer.getSources(opts)
|
||||
)
|
||||
```
|
||||
|
||||
```js
|
||||
// Renderer process
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const desktopCapturer = {
|
||||
getSources: (opts) => ipcRenderer.invoke('DESKTOP_CAPTURER_GET_SOURCES', opts)
|
||||
}
|
||||
```
|
||||
|
||||
However, you should consider further restricting the information returned to
|
||||
the renderer; for instance, displaying a source selector to the user and only
|
||||
returning the selected source.
|
||||
|
||||
## Planned Breaking API Changes (16.0)
|
||||
|
||||
### Behavior Changed: `crashReporter` implementation switched to Crashpad on Linux
|
||||
|
||||
The underlying implementation of the `crashReporter` API on Linux has changed
|
||||
from Breakpad to Crashpad, bringing it in line with Windows and Mac. As a
|
||||
result of this, child processes are now automatically monitored, and calling
|
||||
`process.crashReporter.start` in Node child processes is no longer needed (and
|
||||
is not advisable, as it will start a second instance of the Crashpad reporter).
|
||||
|
||||
There are also some subtle changes to how annotations will be reported on
|
||||
Linux, including that long values will no longer be split between annotations
|
||||
appended with `__1`, `__2` and so on, and instead will be truncated at the
|
||||
(new, longer) annotation value limit.
|
||||
|
||||
### Deprecated: `desktopCapturer.getSources` in the renderer
|
||||
|
||||
Usage of the `desktopCapturer.getSources` API in the renderer has been
|
||||
deprecated and will be removed. This change improves the default security of
|
||||
Electron apps.
|
||||
|
||||
See [here](#removed-desktopcapturergetsources-in-the-renderer) for details on
|
||||
how to replace this API in your app.
|
||||
|
||||
## Planned Breaking API Changes (15.0)
|
||||
|
||||
### Default Changed: `nativeWindowOpen` defaults to `true`
|
||||
|
||||
Prior to Electron 15, `window.open` was by default shimmed to use
|
||||
`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work
|
||||
to open synchronously scriptable child windows, among other incompatibilities.
|
||||
`nativeWindowOpen` is no longer experimental, and is now the default.
|
||||
|
||||
See the documentation for [window.open in Electron](api/window-open.md)
|
||||
for more details.
|
||||
|
||||
## Planned Breaking API Changes (14.0)
|
||||
|
||||
### Removed: `remote` module
|
||||
@@ -62,16 +131,6 @@ ensure your code works with this property enabled. It has been enabled by defau
|
||||
|
||||
You will be affected by this change if you use either `webFrame.executeJavaScript` or `webFrame.executeJavaScriptInIsolatedWorld`. You will need to ensure that values returned by either of those methods are supported by the [Context Bridge API](api/context-bridge.md#parameter--error--return-type-support) as these methods use the same value passing semantics.
|
||||
|
||||
### Default Changed: `nativeWindowOpen` defaults to `true`
|
||||
|
||||
Prior to Electron 14, `window.open` was by default shimmed to use
|
||||
`BrowserWindowProxy`. This meant that `window.open('about:blank')` did not work
|
||||
to open synchronously scriptable child windows, among other incompatibilities.
|
||||
`nativeWindowOpen` is no longer experimental, and is now the default.
|
||||
|
||||
See the documentation for [window.open in Electron](api/window-open.md)
|
||||
for more details.
|
||||
|
||||
### Removed: BrowserWindowConstructorOptions inheriting from parent windows
|
||||
|
||||
Prior to Electron 14, windows opened with `window.open` would inherit
|
||||
|
||||
171
docs/development/creating-api.md
Normal file
171
docs/development/creating-api.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Creating a New Electron Browser Module
|
||||
|
||||
Welcome to the Electron API guide! If you are unfamiliar with creating a new Electron API module within the [`browser`](https://github.com/electron/electron/tree/main/shell/browser) directory, this guide serves as a checklist for some of the necessary steps that you will need to implement.
|
||||
|
||||
This is not a comprehensive end-all guide to creating an Electron Browser API, rather an outline documenting some of the more unintuitive steps.
|
||||
|
||||
## Add your files to Electron's project configuration
|
||||
|
||||
Electron uses [GN](https://gn.googlesource.com/gn) as a meta build system to generate files for its compiler, [Ninja](https://ninja-build.org/). This means that in order to tell Electron to compile your code, we have to add your API's code and header file names into [`filenames.gni`](https://github.com/electron/electron/blob/main/filenames.gni).
|
||||
|
||||
You will need to append your API file names alphabetically into the appropriate files like so:
|
||||
|
||||
```cpp title='filenames.gni'
|
||||
lib_sources = [
|
||||
"path/to/api/api_name.cc",
|
||||
"path/to/api/api_name.h",
|
||||
]
|
||||
|
||||
lib_sources_mac = [
|
||||
"path/to/api/api_name_mac.h",
|
||||
"path/to/api/api_name_mac.mm",
|
||||
]
|
||||
|
||||
lib_sources_win = [
|
||||
"path/to/api/api_name_win.cc",
|
||||
"path/to/api/api_name_win.h",
|
||||
]
|
||||
|
||||
lib_sources_linux = [
|
||||
"path/to/api/api_name_linux.cc",
|
||||
"path/to/api/api_name_linux.h",
|
||||
]
|
||||
```
|
||||
|
||||
Note that the Windows, macOS and Linux array additions are optional and should only be added if your API has specific platform implementations.
|
||||
|
||||
## Create API documentation
|
||||
|
||||
Type definitions are generated by Electron using [`@electron/docs-parser`](https://github.com/electron/docs-parser) and [`@electron/typescript-definitions`](https://github.com/electron/typescript-definitions). This step is necessary to ensure consistency across Electron's API documentation. This means that for your API type definition to appear in the `electron.d.ts` file, we must create a `.md` file. Examples can be found in [this folder](https://github.com/electron/electron/tree/main/docs/api).
|
||||
|
||||
## Set up `ObjectTemplateBuilder` and `Wrappable`
|
||||
|
||||
Electron constructs its modules using [`object_template_builder`](https://www.electronjs.org/blog/from-native-to-js#mateobjecttemplatebuilder).
|
||||
|
||||
[`wrappable`](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/gin/wrappable.h) is a base class for C++ objects that have corresponding v8 wrapper objects.
|
||||
|
||||
Here is a basic example of code that you may need to add, in order to incorporate `object_template_builder` and `wrappable` into your API. For further reference, you can find more implementations [here](https://github.com/electron/electron/tree/main/shell/browser/api).
|
||||
|
||||
In your `api_name.h` file:
|
||||
|
||||
```cpp title='api_name.h'
|
||||
|
||||
#ifndef SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_
|
||||
#define SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_
|
||||
|
||||
#include "gin/handle.h"
|
||||
#include "gin/wrappable.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
class ApiName : public gin::Wrappable<ApiName> {
|
||||
public:
|
||||
static gin::Handle<ApiName> Create(v8::Isolate* isolate);
|
||||
|
||||
// gin::Wrappable
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
const char* GetTypeName() override;
|
||||
} // namespace api
|
||||
} // namespace electron
|
||||
```
|
||||
|
||||
In your `api_name.cc` file:
|
||||
|
||||
```cpp title='api_name.cc'
|
||||
#include "shell/browser/api/electron_api_safe_storage.h"
|
||||
|
||||
#include "shell/browser/browser.h"
|
||||
#include "shell/common/gin_converters/base_converter.h"
|
||||
#include "shell/common/gin_converters/callback_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/gin_helper/object_template_builder.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "shell/common/platform_util.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
gin::WrapperInfo ApiName::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
|
||||
gin::ObjectTemplateBuilder ApiName::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
return gin::ObjectTemplateBuilder(isolate)
|
||||
.SetMethod("methodName", &ApiName::methodName);
|
||||
}
|
||||
|
||||
const char* ApiName::GetTypeName() {
|
||||
return "ApiName";
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<ApiName> ApiName::Create(v8::Isolate* isolate) {
|
||||
return gin::CreateHandle(isolate, new ApiName());
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
||||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.Set("apiName", electron::api::ApiName::Create(isolate));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
```
|
||||
|
||||
## Link your Electron API with Node
|
||||
|
||||
In the [`typings/internal-ambient.d.ts`](https://github.com/electron/electron/blob/main/typings/internal-ambient.d.ts) file, we need to append a new property onto the `Process` interface like so:
|
||||
|
||||
```ts title='typings/internal-ambient.d.ts'
|
||||
interface Process {
|
||||
_linkedBinding(name: 'electron_browser_{api_name}', Electron.ApiName);
|
||||
}
|
||||
```
|
||||
|
||||
At the very bottom of your `api_name.cc` file:
|
||||
|
||||
```cpp title='api_name.cc'
|
||||
NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_{api_name},Initialize)
|
||||
```
|
||||
|
||||
In your [`shell/common/node_bindings.cc`](https://github.com/electron/electron/blob/main/shell/common/node_bindings.cc) file, add your node binding name to Electron's built-in modules.
|
||||
|
||||
```cpp title='shell/common/node_bindings.cc'
|
||||
#define ELECTRON_BUILTIN_MODULES(V) \
|
||||
V(electron_browser_{api_name})
|
||||
```
|
||||
|
||||
> Note: More technical details on how Node links with Electron can be found on [our blog](https://www.electronjs.org/blog/electron-internals-using-node-as-a-library#link-node-with-electron).
|
||||
|
||||
## Expose your API to TypeScript
|
||||
|
||||
### Export your API as a module
|
||||
|
||||
We will need to create a new TypeScript file in the path that follows:
|
||||
|
||||
`"lib/browser/api/{electron_browser_{api_name}}.ts"`
|
||||
|
||||
An example of the contents of this file can be found [here](https://github.com/electron/electron/blob/main/lib/browser/api/native-image.ts).
|
||||
|
||||
### Expose your module to TypeScript
|
||||
|
||||
Add your module to the module list found at `"lib/browser/api/module-list.ts"` like so:
|
||||
|
||||
```typescript title='lib/browser/api/module-list.ts'
|
||||
export const browserModuleList: ElectronInternal.ModuleEntry[] = [
|
||||
{ name: 'apiName', loader: () => require('./api-name') },
|
||||
];
|
||||
```
|
||||
BIN
docs/images/windows-progress-bar.png
Normal file
BIN
docs/images/windows-progress-bar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -21,7 +21,7 @@ In the testing framework Spectron, you can now audit each window and `<webview>`
|
||||
tag in your application. For example:
|
||||
|
||||
```javascript
|
||||
app.client.auditAccessibility().then(function (audit) {
|
||||
app.client.auditAccessibility().then((audit) => {
|
||||
if (audit.failed) {
|
||||
console.error(audit.message)
|
||||
}
|
||||
|
||||
@@ -84,11 +84,15 @@ class TestDriver {
|
||||
In the app, you'd need to write a simple handler for the RPC calls:
|
||||
|
||||
```js
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
}
|
||||
|
||||
async function onMessage ({ msgId, cmd, args }) {
|
||||
const onMessage = async ({ msgId, cmd, args }) => {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
@@ -104,12 +108,8 @@ async function onMessage ({ msgId, cmd, args }) {
|
||||
}
|
||||
}
|
||||
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ Finally, the `main.js` file represents the main process and contains the actual
|
||||
const { app, BrowserWindow, ipcMain, nativeTheme } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
|
||||
@@ -84,13 +84,22 @@ There are several additional APIs for working with the Web Serial API:
|
||||
and [`serial-port-removed`](../api/session.md#event-serial-port-removed) events
|
||||
on the Session can be used to handle devices being plugged in or unplugged during the
|
||||
`navigator.serial.requestPort` process.
|
||||
* [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
can be used to provide default permissioning to devices without first calling
|
||||
for permission to devices via `navigator.serial.requestPort`. Additionally,
|
||||
the default behavior of Electron is to store granted device permision through
|
||||
the lifetime of the corresponding WebContents. If longer term storage is
|
||||
needed, a developer can store granted device permissions (eg when handling
|
||||
the `select-serial-port` event) and then read from that storage with
|
||||
`setDevicePermissionHandler`.
|
||||
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
|
||||
can be used to disable serial access for specific origins.
|
||||
|
||||
### Example
|
||||
|
||||
This example demonstrates an Electron application that automatically selects
|
||||
the first available Arduino Uno serial device (if connected) through
|
||||
serial devices through [`ses.setDevicePermissionHandler(handler)`](../api/session.md#sessetdevicepermissionhandlerhandler)
|
||||
as well as demonstrating selecting the first available Arduino Uno serial device (if connected) through
|
||||
[`select-serial-port` event on the Session](../api/session.md#event-select-serial-port)
|
||||
when the `Test Web Serial` button is clicked.
|
||||
|
||||
|
||||
@@ -2,43 +2,31 @@
|
||||
|
||||
> A detailed look at our versioning policy and implementation.
|
||||
|
||||
As of version 2.0.0, Electron follows [SemVer](#semver). The following command will install the most recent stable build of Electron:
|
||||
As of version 2.0.0, Electron follows the [SemVer](#semver) spec. The following command will install the most recent stable build of Electron:
|
||||
|
||||
```sh
|
||||
```sh npm2yarn
|
||||
npm install --save-dev electron
|
||||
```
|
||||
|
||||
To update an existing project to use the latest stable version:
|
||||
|
||||
```sh
|
||||
```sh npm2yarn
|
||||
npm install --save-dev electron@latest
|
||||
```
|
||||
|
||||
## Version 1.x
|
||||
|
||||
Electron versions *< 2.0* did not conform to the [SemVer](https://semver.org) spec: major versions corresponded to end-user API changes, minor versions corresponded to Chromium major releases, and patch versions corresponded to new features and bug fixes. While convenient for developers merging features, it creates problems for developers of client-facing applications. The QA testing cycles of major apps like Slack, Stride, Teams, Skype, VS Code, Atom, and Desktop can be lengthy and stability is a highly desired outcome. There is a high risk in adopting new features while trying to absorb bug fixes.
|
||||
|
||||
Here is an example of the 1.x strategy:
|
||||
|
||||

|
||||
|
||||
An app developed with `1.8.1` cannot take the `1.8.3` bug fix without either absorbing the `1.8.2` feature, or by backporting the fix and maintaining a new release line.
|
||||
|
||||
## Version 2.0 and Beyond
|
||||
## Versioning scheme
|
||||
|
||||
There are several major changes from our 1.x strategy outlined below. Each change is intended to satisfy the needs and priorities of developers/maintainers and app developers.
|
||||
|
||||
1. Strict use of SemVer
|
||||
1. Strict use of the the [SemVer](#semver) spec
|
||||
2. Introduction of semver-compliant `-beta` tags
|
||||
3. Introduction of [conventional commit messages](https://conventionalcommits.org/)
|
||||
4. Well-defined stabilization branches
|
||||
5. The `master` branch is versionless; only stabilization branches contain version information
|
||||
5. The `main` branch is versionless; only stabilization branches contain version information
|
||||
|
||||
We will cover in detail how git branching works, how npm tagging works, what developers should expect to see, and how one can backport changes.
|
||||
|
||||
# SemVer
|
||||
|
||||
From 2.0 onward, Electron will follow SemVer.
|
||||
## SemVer
|
||||
|
||||
Below is a table explicitly mapping types of changes to their corresponding category of SemVer (e.g. Major, Minor, Patch).
|
||||
|
||||
@@ -48,22 +36,25 @@ Below is a table explicitly mapping types of changes to their corresponding cate
|
||||
| Node.js major version updates | Node.js minor version updates | Node.js patch version updates |
|
||||
| Chromium version updates | | fix-related chromium patches |
|
||||
|
||||
For more information, see the [Semantic Versioning 2.0.0](https://semver.org/) spec.
|
||||
|
||||
Note that most Chromium updates will be considered breaking. Fixes that can be backported will likely be cherry-picked as patches.
|
||||
|
||||
# Stabilization Branches
|
||||
## Stabilization branches
|
||||
|
||||
Stabilization branches are branches that run parallel to master, taking in only cherry-picked commits that are related to security or stability. These branches are never merged back to master.
|
||||
Stabilization branches are branches that run parallel to `main`, taking in only cherry-picked commits that are related to security or stability. These branches are never merged back to `main`.
|
||||
|
||||

|
||||
|
||||
Since Electron 8, stabilization branches are always **major** version lines, and named against the following template `$MAJOR-x-y` e.g. `8-x-y`. Prior to that we used **minor** version lines and named them as `$MAJOR-$MINOR-x` e.g. `2-0-x`
|
||||
Since Electron 8, stabilization branches are always **major** version lines, and named against the following template `$MAJOR-x-y` e.g. `8-x-y`. Prior to that we used **minor** version lines and named them as `$MAJOR-$MINOR-x` e.g. `2-0-x`.
|
||||
|
||||
We allow for multiple stabilization branches to exist simultaneously, one for each supported version. For more details on which versions are supported, see our [Electron Release Timelines](./electron-timelines.md) doc.
|
||||
|
||||
We allow for multiple stabilization branches to exist simultaneously, and intend to support at least two in parallel at all times, backporting security fixes as necessary.
|
||||

|
||||
|
||||
Older lines will not be supported by GitHub, but other groups can take ownership and backport stability and security fixes on their own. We discourage this, but recognize that it makes life easier for many app developers.
|
||||
Older lines will not be supported by the Electron project, but other groups can take ownership and backport stability and security fixes on their own. We discourage this, but recognize that it makes life easier for many app developers.
|
||||
|
||||
# Beta Releases and Bug Fixes
|
||||
## Beta releases and bug fixes
|
||||
|
||||
Developers want to know which releases are _safe_ to use. Even seemingly innocent features can introduce regressions in complex applications. At the same time, locking to a fixed version is dangerous because you’re ignoring security patches and bug fixes that may have come out since your version. Our goal is to allow the following standard semver ranges in `package.json` :
|
||||
|
||||
@@ -116,15 +107,7 @@ A few examples of how various SemVer ranges will pick up new releases:
|
||||
|
||||

|
||||
|
||||
# Missing Features: Alphas
|
||||
|
||||
Our strategy has a few tradeoffs, which for now we feel are appropriate. Most importantly that new features in master may take a while before reaching a stable release line. If you want to try a new feature immediately, you will have to build Electron yourself.
|
||||
|
||||
As a future consideration, we may introduce one or both of the following:
|
||||
|
||||
* alpha releases that have looser stability constraints to betas; for example it would be allowable to admit new features while a stability channel is in _alpha_
|
||||
|
||||
# Feature Flags
|
||||
## Feature flags
|
||||
|
||||
Feature flags are a common practice in Chromium, and are well-established in the web-development ecosystem. In the context of Electron, a feature flag or **soft branch** must have the following properties:
|
||||
|
||||
@@ -132,20 +115,29 @@ Feature flags are a common practice in Chromium, and are well-established in the
|
||||
* it completely segments new and old code paths; refactoring old code to support a new feature _violates_ the feature-flag contract
|
||||
* feature flags are eventually removed after the feature is released
|
||||
|
||||
# Semantic Commits
|
||||
## Semantic commits
|
||||
|
||||
We seek to increase clarity at all levels of the update and releases process. Starting with `2.0.0` we will require pull requests adhere to the [Conventional Commits](https://conventionalcommits.org/) spec, which can be summarized as follows:
|
||||
All pull requests must adhere to the [Conventional Commits](https://conventionalcommits.org/) spec, which can be summarized as follows:
|
||||
|
||||
* Commits that would result in a SemVer **major** bump must start their body with `BREAKING CHANGE:`.
|
||||
* Commits that would result in a SemVer **minor** bump must start with `feat:`.
|
||||
* Commits that would result in a SemVer **patch** bump must start with `fix:`.
|
||||
|
||||
* We allow squashing of commits, provided that the squashed message adheres to the above message format.
|
||||
* It is acceptable for some commits in a pull request to not include a semantic prefix, as long as the pull request title contains a meaningful encompassing semantic message.
|
||||
The `electron/electron` repository also enforces squash merging, so you only need to make sure that your pull request has the correct title prefix.
|
||||
|
||||
# Versioned `master`
|
||||
## Versioned `main` branch
|
||||
|
||||
* The `master` branch will always contain the next major version `X.0.0-nightly.DATE` in its `package.json`
|
||||
* Release branches are never merged back to master
|
||||
* Release branches _do_ contain the correct version in their `package.json`
|
||||
* As soon as a release branch is cut for a major, master must be bumped to the next major. I.e. `master` is always versioned as the next theoretical release branch
|
||||
* The `main` branch will always contain the next major version `X.0.0-nightly.DATE` in its `package.json`.
|
||||
* Release branches are never merged back to `main`.
|
||||
* Release branches _do_ contain the correct version in their `package.json`.
|
||||
* As soon as a release branch is cut for a major, `main` must be bumped to the next major (i.e. `main` is always versioned as the next theoretical release branch).
|
||||
|
||||
## Historical versioning (Electron 1.X)
|
||||
|
||||
Electron versions *< 2.0* did not conform to the [SemVer](https://semver.org) spec: major versions corresponded to end-user API changes, minor versions corresponded to Chromium major releases, and patch versions corresponded to new features and bug fixes. While convenient for developers merging features, it creates problems for developers of client-facing applications. The QA testing cycles of major apps like Slack, Teams, Skype, VS Code, and GitHub Desktop can be lengthy and stability is a highly desired outcome. There is a high risk in adopting new features while trying to absorb bug fixes.
|
||||
|
||||
Here is an example of the 1.x strategy:
|
||||
|
||||

|
||||
|
||||
An app developed with `1.8.1` cannot take the `1.8.3` bug fix without either absorbing the `1.8.2` feature, or by backporting the fix and maintaining a new release line.
|
||||
|
||||
@@ -12,7 +12,7 @@ Fuses are the solution to this problem, at a high level they are "magic bits" in
|
||||
|
||||
### The easy way
|
||||
|
||||
We've made a handy module `@electron/fuses` to make flipping these fuses easy. Check out the README of that module for more details on usage and potential error cases.
|
||||
We've made a handy module, [`@electron/fuses`](https://npmjs.com/package/@electron/fuses), to make flipping these fuses easy. Check out the README of that module for more details on usage and potential error cases.
|
||||
|
||||
```js
|
||||
require('@electron/fuses').flipFuses(
|
||||
|
||||
@@ -39,7 +39,7 @@ inAppPurchase.on('transactions-updated', (event, transactions) => {
|
||||
}
|
||||
|
||||
// Check each transaction.
|
||||
transactions.forEach(function (transaction) {
|
||||
transactions.forEach((transaction) => {
|
||||
const payment = transaction.payment
|
||||
|
||||
switch (transaction.transactionState) {
|
||||
|
||||
@@ -82,7 +82,7 @@ listen for the `keyup` and `keydown` [DOM events][dom-events] inside the
|
||||
renderer process using the [addEventListener() API][addEventListener-api].
|
||||
|
||||
```javascript fiddle='docs/fiddles/features/keyboard-shortcuts/web-apis|focus=renderer.js'
|
||||
function handleKeyPress(event) {
|
||||
const handleKeyPress = (event) => {
|
||||
// You can put code here to handle the keypress.
|
||||
document.getElementById("last-keypress").innerText = event.key;
|
||||
console.log(`You pressed ${event.key}`);
|
||||
|
||||
@@ -25,7 +25,7 @@ Starting with a working application from the
|
||||
```javascript fiddle='docs/fiddles/features/macos-dock-menu'
|
||||
const { app, BrowserWindow, Menu } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
|
||||
@@ -134,7 +134,7 @@ app.whenReady().then(async () => {
|
||||
<script>
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
function doWork(input) {
|
||||
const doWork = (input) => {
|
||||
// Something cpu-intensive.
|
||||
return input * 2
|
||||
}
|
||||
@@ -185,7 +185,7 @@ stream of data.
|
||||
```js
|
||||
// renderer.js ///////////////////////////////////////////////////////////////
|
||||
|
||||
function makeStreamingRequest (element, callback) {
|
||||
const makeStreamingRequest = (element, callback) => {
|
||||
// MessageChannels are lightweight--it's cheap to create a new one for each
|
||||
// request.
|
||||
const { port1, port2 } = new MessageChannel()
|
||||
|
||||
@@ -54,7 +54,7 @@ const { Notification } = require('electron')
|
||||
const NOTIFICATION_TITLE = 'Basic Notification'
|
||||
const NOTIFICATION_BODY = 'Notification from the Main process'
|
||||
|
||||
function showNotification () {
|
||||
const showNotification = () => {
|
||||
new Notification({ title: NOTIFICATION_TITLE, body: NOTIFICATION_BODY }).show()
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ Starting with an HTML file `index.html`, this example will demonstrate how the `
|
||||
In order to mutate the DOM, create a `renderer.js` file that adds event listeners to the `'online'` and `'offline'` `window` events. The event handler sets the content of the `<strong id='status'>` element depending on the result of `navigator.onLine`.
|
||||
|
||||
```js title='renderer.js'
|
||||
function updateOnlineStatus () {
|
||||
const updateOnlineStatus = () => {
|
||||
document.getElementById('status').innerHTML = navigator.onLine ? 'online' : 'offline'
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ Finally, create a `main.js` file for main process that creates the window.
|
||||
```js title='main.js'
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const onlineStatusWindow = new BrowserWindow({
|
||||
width: 400,
|
||||
height: 100
|
||||
|
||||
@@ -84,7 +84,7 @@ uses `app` APIs to create a more native application window experience.
|
||||
|
||||
```js title='main.js'
|
||||
// quitting the app when no windows are open on non-macOS platforms
|
||||
app.on('window-all-closed', function () {
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@ without the need of switching to the window itself.
|
||||
|
||||
On Windows, you can use a taskbar button to display a progress bar.
|
||||
|
||||
![Windows Progress Bar][https://cloud.githubusercontent.com/assets/639601/5081682/16691fda-6f0e-11e4-9676-49b6418f1264.png]
|
||||

|
||||
|
||||
On macOS, the progress bar will be displayed as a part of the dock icon.
|
||||
|
||||
@@ -48,7 +48,7 @@ const { app, BrowserWindow } = require('electron')
|
||||
|
||||
let progressInterval
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
|
||||
@@ -166,7 +166,7 @@ Then, add a `createWindow()` function that loads `index.html` into a new `Browse
|
||||
instance.
|
||||
|
||||
```js
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
@@ -216,7 +216,7 @@ To implement this, listen for the `app` module's [`'window-all-closed'`][window-
|
||||
event, and call [`app.quit()`][app-quit] if the user is not on macOS (`darwin`).
|
||||
|
||||
```js
|
||||
app.on('window-all-closed', function () {
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
```
|
||||
@@ -244,7 +244,7 @@ from within your existing `whenReady()` callback.
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
@@ -295,7 +295,7 @@ to the `webPreferences.preload` option in your existing `BrowserWindow` construc
|
||||
const path = require('path')
|
||||
|
||||
// modify your existing createWindow() function
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
@@ -360,7 +360,7 @@ The full code is available below:
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
@@ -383,7 +383,7 @@ function createWindow () {
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
app.on('activate', () => {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
@@ -393,7 +393,7 @@ app.whenReady().then(() => {
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', function () {
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ const { app, BrowserWindow } = require('electron')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
|
||||
@@ -24,7 +24,7 @@ To set the represented file of window, you can use the
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const os = require('os');
|
||||
|
||||
function createWindow () {
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600
|
||||
|
||||
@@ -216,7 +216,7 @@ access to a `window.readConfig()` method, but no Node.js features.
|
||||
```js
|
||||
const { readFileSync } = require('fs')
|
||||
|
||||
window.readConfig = function () {
|
||||
window.readConfig = () => {
|
||||
const data = readFileSync('./config.json')
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -70,10 +70,10 @@ until the maintainers feel the maintenance burden is too high to continue doing
|
||||
|
||||
### Currently supported versions
|
||||
|
||||
* 16.x.y
|
||||
* 15.x.y
|
||||
* 14.x.y
|
||||
* 13.x.y
|
||||
* 12
|
||||
* 13
|
||||
|
||||
### End-of-life
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<includes>
|
||||
<include name="IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE" file="${target_gen_dir}/shell_devtools_discovery_page.html" use_base_dir="false" type="BINDATA" />
|
||||
<include name="IDR_PDF_MANIFEST" file="../chrome/browser/resources/pdf/manifest.json" type="BINDATA" />
|
||||
<include name="IDR_CRYPTOTOKEN_MANIFEST" file="../chrome/browser/resources/cryptotoken/manifest.json" type="BINDATA" />
|
||||
</includes>
|
||||
</release>
|
||||
</grit>
|
||||
|
||||
@@ -136,16 +136,14 @@ auto_filenames = {
|
||||
|
||||
sandbox_bundle_deps = [
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-events.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.ts",
|
||||
"lib/renderer/api/desktop-capturer.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/native-image.ts",
|
||||
"lib/renderer/api/web-frame.ts",
|
||||
"lib/renderer/inspector.ts",
|
||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||
@@ -170,7 +168,6 @@ auto_filenames = {
|
||||
]
|
||||
|
||||
isolated_bundle_deps = [
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/isolated_renderer/init.ts",
|
||||
"lib/renderer/web-view/web-view-attributes.ts",
|
||||
@@ -207,7 +204,6 @@ auto_filenames = {
|
||||
"lib/browser/api/menu.ts",
|
||||
"lib/browser/api/message-channel.ts",
|
||||
"lib/browser/api/module-list.ts",
|
||||
"lib/browser/api/native-image.ts",
|
||||
"lib/browser/api/native-theme.ts",
|
||||
"lib/browser/api/net-log.ts",
|
||||
"lib/browser/api/net.ts",
|
||||
@@ -242,13 +238,13 @@ auto_filenames = {
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/parse-features-string.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-events.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-globals-provider.ts",
|
||||
@@ -265,13 +261,12 @@ auto_filenames = {
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/web-view-events.ts",
|
||||
"lib/common/web-view-methods.ts",
|
||||
"lib/common/webpack-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
@@ -280,7 +275,6 @@ auto_filenames = {
|
||||
"lib/renderer/api/exports/electron.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/module-list.ts",
|
||||
"lib/renderer/api/native-image.ts",
|
||||
"lib/renderer/api/web-frame.ts",
|
||||
"lib/renderer/init.ts",
|
||||
"lib/renderer/inspector.ts",
|
||||
@@ -306,12 +300,12 @@ auto_filenames = {
|
||||
"lib/common/api/clipboard.ts",
|
||||
"lib/common/api/deprecate.ts",
|
||||
"lib/common/api/module-list.ts",
|
||||
"lib/common/api/native-image.ts",
|
||||
"lib/common/api/shell.ts",
|
||||
"lib/common/define-properties.ts",
|
||||
"lib/common/init.ts",
|
||||
"lib/common/ipc-messages.ts",
|
||||
"lib/common/reset-search-paths.ts",
|
||||
"lib/common/type-utils.ts",
|
||||
"lib/common/webpack-provider.ts",
|
||||
"lib/renderer/api/context-bridge.ts",
|
||||
"lib/renderer/api/crash-reporter.ts",
|
||||
@@ -319,7 +313,6 @@ auto_filenames = {
|
||||
"lib/renderer/api/exports/electron.ts",
|
||||
"lib/renderer/api/ipc-renderer.ts",
|
||||
"lib/renderer/api/module-list.ts",
|
||||
"lib/renderer/api/native-image.ts",
|
||||
"lib/renderer/api/web-frame.ts",
|
||||
"lib/renderer/ipc-renderer-internal-utils.ts",
|
||||
"lib/renderer/ipc-renderer-internal.ts",
|
||||
|
||||
@@ -44,8 +44,8 @@ filenames = {
|
||||
]
|
||||
|
||||
lib_sources_linux_x11 = [
|
||||
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc",
|
||||
"chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h",
|
||||
"shell/browser/ui/views/global_menu_bar_registrar_x11.cc",
|
||||
"shell/browser/ui/views/global_menu_bar_registrar_x11.h",
|
||||
"shell/browser/ui/views/global_menu_bar_x11.cc",
|
||||
"shell/browser/ui/views/global_menu_bar_x11.h",
|
||||
"shell/browser/ui/x/event_disabler.cc",
|
||||
@@ -56,13 +56,9 @@ filenames = {
|
||||
"shell/browser/ui/x/x_window_utils.h",
|
||||
]
|
||||
|
||||
lib_sources_posix = [
|
||||
"chromium_src/chrome/browser/process_singleton_posix.cc",
|
||||
"shell/browser/electron_browser_main_parts_posix.cc",
|
||||
]
|
||||
lib_sources_posix = [ "shell/browser/electron_browser_main_parts_posix.cc" ]
|
||||
|
||||
lib_sources_win = [
|
||||
"chromium_src/chrome/browser/process_singleton_win.cc",
|
||||
"shell/browser/api/electron_api_power_monitor_win.cc",
|
||||
"shell/browser/api/electron_api_system_preferences_win.cc",
|
||||
"shell/browser/browser_win.cc",
|
||||
@@ -237,7 +233,6 @@ filenames = {
|
||||
]
|
||||
|
||||
lib_sources = [
|
||||
"chromium_src/chrome/browser/process_singleton.h",
|
||||
"shell/app/command_line_args.cc",
|
||||
"shell/app/command_line_args.h",
|
||||
"shell/app/electron_content_client.cc",
|
||||
@@ -509,8 +504,6 @@ filenames = {
|
||||
"shell/browser/web_contents_preferences.h",
|
||||
"shell/browser/web_contents_zoom_controller.cc",
|
||||
"shell/browser/web_contents_zoom_controller.h",
|
||||
"shell/browser/web_dialog_helper.cc",
|
||||
"shell/browser/web_dialog_helper.h",
|
||||
"shell/browser/web_view_guest_delegate.cc",
|
||||
"shell/browser/web_view_guest_delegate.h",
|
||||
"shell/browser/web_view_manager.cc",
|
||||
@@ -690,6 +683,8 @@ filenames = {
|
||||
lib_sources_extensions = [
|
||||
"shell/browser/extensions/api/i18n/i18n_api.cc",
|
||||
"shell/browser/extensions/api/i18n/i18n_api.h",
|
||||
"shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.cc",
|
||||
"shell/browser/extensions/api/cryptotoken_private/cryptotoken_private_api.h",
|
||||
"shell/browser/extensions/api/management/electron_management_api_delegate.cc",
|
||||
"shell/browser/extensions/api/management/electron_management_api_delegate.h",
|
||||
"shell/browser/extensions/api/resources_private/resources_private_api.cc",
|
||||
|
||||
@@ -39,7 +39,8 @@ Object.assign(app, {
|
||||
hasSwitch: (theSwitch: string) => commandLine.hasSwitch(String(theSwitch)),
|
||||
getSwitchValue: (theSwitch: string) => commandLine.getSwitchValue(String(theSwitch)),
|
||||
appendSwitch: (theSwitch: string, value?: string) => commandLine.appendSwitch(String(theSwitch), typeof value === 'undefined' ? value : String(value)),
|
||||
appendArgument: (arg: string) => commandLine.appendArgument(String(arg))
|
||||
appendArgument: (arg: string) => commandLine.appendArgument(String(arg)),
|
||||
removeSwitch: (theSwitch: string) => commandLine.removeSwitch(String(theSwitch))
|
||||
} as Electron.CommandLine
|
||||
});
|
||||
|
||||
|
||||
@@ -143,7 +143,10 @@ export const roleList: Record<RoleId, Role> = {
|
||||
label: 'Toggle Developer Tools',
|
||||
accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
||||
nonNativeMacOSRole: true,
|
||||
windowMethod: w => w.webContents.toggleDevTools()
|
||||
webContentsMethod: wc => {
|
||||
const bw = wc.getOwnerBrowserWindow();
|
||||
if (bw) bw.webContents.toggleDevTools();
|
||||
}
|
||||
},
|
||||
togglefullscreen: {
|
||||
label: 'Toggle Full Screen',
|
||||
|
||||
@@ -16,7 +16,6 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [
|
||||
{ name: 'Menu', loader: () => require('./menu') },
|
||||
{ name: 'MenuItem', loader: () => require('./menu-item') },
|
||||
{ name: 'MessageChannelMain', loader: () => require('./message-channel') },
|
||||
{ name: 'nativeImage', loader: () => require('./native-image') },
|
||||
{ name: 'nativeTheme', loader: () => require('./native-theme') },
|
||||
{ name: 'net', loader: () => require('./net') },
|
||||
{ name: 'netLog', loader: () => require('./net-log') },
|
||||
|
||||
@@ -7,7 +7,11 @@ WebFrameMain.prototype.send = function (channel, ...args) {
|
||||
throw new Error('Missing required channel argument');
|
||||
}
|
||||
|
||||
return this._send(false /* internal */, channel, args);
|
||||
try {
|
||||
return this._send(false /* internal */, channel, args);
|
||||
} catch (e) {
|
||||
console.error('Error sending from webFrameMain: ', e);
|
||||
}
|
||||
};
|
||||
|
||||
WebFrameMain.prototype._sendInternal = function (channel, ...args) {
|
||||
@@ -15,7 +19,11 @@ WebFrameMain.prototype._sendInternal = function (channel, ...args) {
|
||||
throw new Error('Missing required channel argument');
|
||||
}
|
||||
|
||||
return this._send(true /* internal */, channel, args);
|
||||
try {
|
||||
return this._send(true /* internal */, channel, args);
|
||||
} catch (e) {
|
||||
console.error('Error sending from webFrameMain: ', e);
|
||||
}
|
||||
};
|
||||
|
||||
WebFrameMain.prototype.postMessage = function (...args) {
|
||||
|
||||
@@ -67,7 +67,7 @@ ipcMainInternal.handle(IPC_MESSAGES.INSPECTOR_CONTEXT_MENU, function (event, ite
|
||||
|
||||
const template = isEditMenu ? getEditMenuItems() : convertToMenuTemplate(items, resolve);
|
||||
const menu = Menu.buildFromTemplate(template);
|
||||
const window = event.sender.getOwnerBrowserWindow();
|
||||
const window = event.sender.getOwnerBrowserWindow()!;
|
||||
|
||||
menu.popup({ window, callback: () => resolve() });
|
||||
});
|
||||
@@ -94,7 +94,7 @@ ipcMainUtils.handleSync(IPC_MESSAGES.INSPECTOR_CONFIRM, async function (event, m
|
||||
buttons: ['OK', 'Cancel'],
|
||||
cancelId: 1
|
||||
};
|
||||
const window = event.sender.getOwnerBrowserWindow();
|
||||
const window = event.sender.getOwnerBrowserWindow()!;
|
||||
const { response } = await dialog.showMessageBox(window, options);
|
||||
return response === 0;
|
||||
});
|
||||
|
||||
@@ -4,17 +4,17 @@ import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-util
|
||||
import { parseWebViewWebPreferences } from '@electron/internal/common/parse-features-string';
|
||||
import { syncMethods, asyncMethods, properties } from '@electron/internal/common/web-view-methods';
|
||||
import { webViewEvents } from '@electron/internal/common/web-view-events';
|
||||
import { serialize } from '@electron/internal/common/type-utils';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
interface GuestInstance {
|
||||
elementInstanceId?: number;
|
||||
elementInstanceId: number;
|
||||
visibilityState?: VisibilityState;
|
||||
embedder: Electron.WebContents;
|
||||
guest: Electron.WebContents;
|
||||
}
|
||||
|
||||
const webViewManager = process._linkedBinding('electron_browser_web_view_manager');
|
||||
const eventBinding = process._linkedBinding('electron_browser_event');
|
||||
|
||||
const supportedWebViewEvents = Object.keys(webViewEvents);
|
||||
|
||||
@@ -28,16 +28,73 @@ function sanitizeOptionsForGuest (options: Record<string, any>) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
function makeWebPreferences (embedder: Electron.WebContents, params: Record<string, any>) {
|
||||
// parse the 'webpreferences' attribute string, if set
|
||||
// this uses the same parsing rules as window.open uses for its features
|
||||
const parsedWebPreferences =
|
||||
typeof params.webpreferences === 'string'
|
||||
? parseWebViewWebPreferences(params.webpreferences)
|
||||
: null;
|
||||
|
||||
const webPreferences: Electron.WebPreferences = {
|
||||
nodeIntegration: params.nodeintegration != null ? params.nodeintegration : false,
|
||||
nodeIntegrationInSubFrames: params.nodeintegrationinsubframes != null ? params.nodeintegrationinsubframes : false,
|
||||
plugins: params.plugins,
|
||||
zoomFactor: embedder.zoomFactor,
|
||||
disablePopups: !params.allowpopups,
|
||||
webSecurity: !params.disablewebsecurity,
|
||||
enableBlinkFeatures: params.blinkfeatures,
|
||||
disableBlinkFeatures: params.disableblinkfeatures,
|
||||
partition: params.partition,
|
||||
...parsedWebPreferences
|
||||
};
|
||||
|
||||
if (params.preload) {
|
||||
webPreferences.preloadURL = params.preload;
|
||||
}
|
||||
|
||||
// Security options that guest will always inherit from embedder
|
||||
const inheritedWebPreferences = new Map([
|
||||
['contextIsolation', true],
|
||||
['javascript', false],
|
||||
['nativeWindowOpen', true],
|
||||
['nodeIntegration', false],
|
||||
['sandbox', true],
|
||||
['nodeIntegrationInSubFrames', false],
|
||||
['enableWebSQL', false]
|
||||
]);
|
||||
|
||||
// Inherit certain option values from embedder
|
||||
const lastWebPreferences = embedder.getLastWebPreferences()!;
|
||||
for (const [name, value] of inheritedWebPreferences) {
|
||||
if (lastWebPreferences[name as keyof Electron.WebPreferences] === value) {
|
||||
(webPreferences as any)[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return webPreferences;
|
||||
}
|
||||
|
||||
// Create a new guest instance.
|
||||
const createGuest = function (embedder: Electron.WebContents, params: Record<string, any>) {
|
||||
const createGuest = function (embedder: Electron.WebContents, embedderFrameId: number, elementInstanceId: number, params: Record<string, any>) {
|
||||
const webPreferences = makeWebPreferences(embedder, params);
|
||||
const event = eventBinding.createWithSender(embedder);
|
||||
|
||||
embedder.emit('will-attach-webview', event, webPreferences, params);
|
||||
if (event.defaultPrevented) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
const guest = (webContents as typeof ElectronInternal.WebContents).create({
|
||||
...webPreferences,
|
||||
type: 'webview',
|
||||
partition: params.partition,
|
||||
embedder
|
||||
});
|
||||
|
||||
const guestInstanceId = guest.id;
|
||||
guestInstances.set(guestInstanceId, {
|
||||
elementInstanceId,
|
||||
guest,
|
||||
embedder
|
||||
});
|
||||
@@ -51,9 +108,6 @@ const createGuest = function (embedder: Electron.WebContents, params: Record<str
|
||||
|
||||
// Init guest web view after attached.
|
||||
guest.once('did-attach' as any, function (this: Electron.WebContents, event: Electron.Event) {
|
||||
params = this.attachParams!;
|
||||
delete this.attachParams;
|
||||
|
||||
const previouslyAttached = this.viewInstanceId != null;
|
||||
this.viewInstanceId = params.instanceId;
|
||||
|
||||
@@ -81,27 +135,33 @@ const createGuest = function (embedder: Electron.WebContents, params: Record<str
|
||||
}
|
||||
};
|
||||
|
||||
// Dispatch events to embedder.
|
||||
const fn = function (event: string) {
|
||||
guest.on(event as any, function (_, ...args: any[]) {
|
||||
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, event, ...args);
|
||||
const makeProps = (eventKey: string, args: any[]) => {
|
||||
const props: Record<string, any> = {};
|
||||
webViewEvents[eventKey].forEach((prop, index) => {
|
||||
props[prop] = args[index];
|
||||
});
|
||||
return props;
|
||||
};
|
||||
|
||||
// Dispatch events to embedder.
|
||||
for (const event of supportedWebViewEvents) {
|
||||
if (event !== 'new-window') {
|
||||
fn(event);
|
||||
}
|
||||
guest.on(event as any, function (_, ...args: any[]) {
|
||||
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, event, makeProps(event, args));
|
||||
});
|
||||
}
|
||||
|
||||
guest.on('new-window', function (event, url, frameName, disposition, options, additionalFeatures, referrer) {
|
||||
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'new-window', url,
|
||||
frameName, disposition, sanitizeOptionsForGuest(options),
|
||||
additionalFeatures, referrer);
|
||||
guest.on('new-window', function (event, url, frameName, disposition, options) {
|
||||
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'new-window', {
|
||||
url,
|
||||
frameName,
|
||||
disposition,
|
||||
options: sanitizeOptionsForGuest(options)
|
||||
});
|
||||
});
|
||||
|
||||
// Dispatch guest's IPC messages to embedder.
|
||||
guest.on('ipc-message-host' as any, function (event: Electron.IpcMainEvent, channel: string, args: any[]) {
|
||||
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_IPC_MESSAGE, {
|
||||
sendToEmbedder(IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT, 'ipc-message', {
|
||||
frameId: [event.processId, event.frameId],
|
||||
channel,
|
||||
args
|
||||
@@ -117,111 +177,25 @@ const createGuest = function (embedder: Electron.WebContents, params: Record<str
|
||||
}
|
||||
});
|
||||
|
||||
return guestInstanceId;
|
||||
};
|
||||
|
||||
// Attach the guest to an element of embedder.
|
||||
const attachGuest = function (event: Electron.IpcMainInvokeEvent,
|
||||
embedderFrameId: number, elementInstanceId: number, guestInstanceId: number, params: Record<string, any>) {
|
||||
const embedder = event.sender;
|
||||
// Destroy the old guest when attaching.
|
||||
const key = `${embedder.id}-${elementInstanceId}`;
|
||||
const oldGuestInstanceId = embedderElementsMap.get(key);
|
||||
if (oldGuestInstanceId != null) {
|
||||
// Reattachment to the same guest is just a no-op.
|
||||
if (oldGuestInstanceId === guestInstanceId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldGuestInstance = guestInstances.get(oldGuestInstanceId);
|
||||
if (oldGuestInstance) {
|
||||
oldGuestInstance.guest.detachFromOuterFrame();
|
||||
}
|
||||
}
|
||||
|
||||
const guestInstance = guestInstances.get(guestInstanceId);
|
||||
// If this isn't a valid guest instance then do nothing.
|
||||
if (!guestInstance) {
|
||||
throw new Error(`Invalid guestInstanceId: ${guestInstanceId}`);
|
||||
}
|
||||
const { guest } = guestInstance;
|
||||
if (guest.hostWebContents !== embedder) {
|
||||
throw new Error(`Access denied to guestInstanceId: ${guestInstanceId}`);
|
||||
}
|
||||
|
||||
// If this guest is already attached to an element then remove it
|
||||
if (guestInstance.elementInstanceId) {
|
||||
const oldKey = `${guestInstance.embedder.id}-${guestInstance.elementInstanceId}`;
|
||||
embedderElementsMap.delete(oldKey);
|
||||
|
||||
// Remove guest from embedder if moving across web views
|
||||
if (guest.viewInstanceId !== params.instanceId) {
|
||||
webViewManager.removeGuest(guestInstance.embedder, guestInstanceId);
|
||||
guestInstance.embedder._sendInternal(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${guest.viewInstanceId}`);
|
||||
}
|
||||
}
|
||||
|
||||
// parse the 'webpreferences' attribute string, if set
|
||||
// this uses the same parsing rules as window.open uses for its features
|
||||
const parsedWebPreferences =
|
||||
typeof params.webpreferences === 'string'
|
||||
? parseWebViewWebPreferences(params.webpreferences)
|
||||
: null;
|
||||
|
||||
const webPreferences: Electron.WebPreferences = {
|
||||
guestInstanceId,
|
||||
nodeIntegration: params.nodeintegration != null ? params.nodeintegration : false,
|
||||
nodeIntegrationInSubFrames: params.nodeintegrationinsubframes != null ? params.nodeintegrationinsubframes : false,
|
||||
plugins: params.plugins,
|
||||
zoomFactor: embedder.zoomFactor,
|
||||
disablePopups: !params.allowpopups,
|
||||
webSecurity: !params.disablewebsecurity,
|
||||
enableBlinkFeatures: params.blinkfeatures,
|
||||
disableBlinkFeatures: params.disableblinkfeatures,
|
||||
...parsedWebPreferences
|
||||
};
|
||||
|
||||
if (params.preload) {
|
||||
webPreferences.preloadURL = params.preload;
|
||||
}
|
||||
|
||||
// Security options that guest will always inherit from embedder
|
||||
const inheritedWebPreferences = new Map([
|
||||
['contextIsolation', true],
|
||||
['javascript', false],
|
||||
['nativeWindowOpen', true],
|
||||
['nodeIntegration', false],
|
||||
['sandbox', true],
|
||||
['nodeIntegrationInSubFrames', false],
|
||||
['enableWebSQL', false]
|
||||
]);
|
||||
|
||||
// Inherit certain option values from embedder
|
||||
const lastWebPreferences = embedder.getLastWebPreferences();
|
||||
for (const [name, value] of inheritedWebPreferences) {
|
||||
if (lastWebPreferences[name as keyof Electron.WebPreferences] === value) {
|
||||
(webPreferences as any)[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
embedder.emit('will-attach-webview', event, webPreferences, params);
|
||||
if (event.defaultPrevented) {
|
||||
if (guest.viewInstanceId == null) guest.viewInstanceId = params.instanceId;
|
||||
guest.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
guest.attachParams = params;
|
||||
embedderElementsMap.set(key, guestInstanceId);
|
||||
|
||||
guest.setEmbedder(embedder);
|
||||
guestInstance.embedder = embedder;
|
||||
guestInstance.elementInstanceId = elementInstanceId;
|
||||
|
||||
watchEmbedder(embedder);
|
||||
|
||||
webViewManager.addGuest(guestInstanceId, embedder, guest, webPreferences);
|
||||
guest.attachToIframe(embedder, embedderFrameId);
|
||||
|
||||
return guestInstanceId;
|
||||
};
|
||||
|
||||
// Remove an guest-embedder relationship.
|
||||
@@ -306,16 +280,8 @@ const handleMessageSync = function (channel: string, handler: (event: ElectronIn
|
||||
ipcMainUtils.handleSync(channel, makeSafeHandler(channel, handler));
|
||||
};
|
||||
|
||||
handleMessage(IPC_MESSAGES.GUEST_VIEW_MANAGER_CREATE_GUEST, function (event, params) {
|
||||
return createGuest(event.sender, params);
|
||||
});
|
||||
|
||||
handleMessage(IPC_MESSAGES.GUEST_VIEW_MANAGER_ATTACH_GUEST, function (event, embedderFrameId: number, elementInstanceId: number, guestInstanceId: number, params) {
|
||||
try {
|
||||
attachGuest(event, embedderFrameId, elementInstanceId, guestInstanceId, params);
|
||||
} catch (error) {
|
||||
console.error(`Guest attach failed: ${error}`);
|
||||
}
|
||||
handleMessage(IPC_MESSAGES.GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST, function (event, embedderFrameId: number, elementInstanceId: number, params) {
|
||||
return createGuest(event.sender, embedderFrameId, elementInstanceId, params);
|
||||
});
|
||||
|
||||
handleMessageSync(IPC_MESSAGES.GUEST_VIEW_MANAGER_DETACH_GUEST, function (event, guestInstanceId: number) {
|
||||
@@ -363,12 +329,6 @@ handleMessageSync(IPC_MESSAGES.GUEST_VIEW_MANAGER_PROPERTY_SET, function (event,
|
||||
(guest as any)[property] = val;
|
||||
});
|
||||
|
||||
handleMessage(IPC_MESSAGES.GUEST_VIEW_MANAGER_CAPTURE_PAGE, async function (event, guestInstanceId: number, args: any[]) {
|
||||
const guest = getGuestForWebContents(guestInstanceId, event.sender);
|
||||
|
||||
return serialize(await guest.capturePage(...args));
|
||||
});
|
||||
|
||||
// Returns WebContents from its guest id hosted in given webContents.
|
||||
const getGuestForWebContents = function (guestInstanceId: number, contents: Electron.WebContents) {
|
||||
const guestInstance = guestInstances.get(guestInstanceId);
|
||||
|
||||
@@ -65,8 +65,13 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition
|
||||
// https://html.spec.whatwg.org/multipage/window-object.html#apis-for-creating-and-navigating-browsing-contexts-by-name
|
||||
const existingWindow = getGuestWindowByFrameName(frameName);
|
||||
if (existingWindow) {
|
||||
existingWindow.loadURL(url);
|
||||
return existingWindow;
|
||||
if (existingWindow.isDestroyed() || existingWindow.webContents.isDestroyed()) {
|
||||
// FIXME(t57ser): The webContents is destroyed for some reason, unregister the frame name
|
||||
unregisterFrameName(frameName);
|
||||
} else {
|
||||
existingWindow.loadURL(url);
|
||||
return existingWindow;
|
||||
}
|
||||
}
|
||||
|
||||
const window = new BrowserWindow({
|
||||
@@ -144,7 +149,7 @@ function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs,
|
||||
postData?: PostData,
|
||||
}): boolean {
|
||||
const { url, frameName } = windowOpenArgs;
|
||||
const isWebViewWithPopupsDisabled = embedder.getType() === 'webview' && embedder.getLastWebPreferences().disablePopups;
|
||||
const isWebViewWithPopupsDisabled = embedder.getType() === 'webview' && embedder.getLastWebPreferences()!.disablePopups;
|
||||
const postBody = postData ? {
|
||||
data: postData,
|
||||
...parseContentTypeFormat(postData)
|
||||
@@ -229,7 +234,7 @@ export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = {
|
||||
// have unvetted prefs, use parsedWebPreferences.
|
||||
secureOverrideWebPreferences?: BrowserWindowConstructorOptions['webPreferences'],
|
||||
}) {
|
||||
const parentWebPreferences = embedder.getLastWebPreferences();
|
||||
const parentWebPreferences = embedder.getLastWebPreferences()!;
|
||||
const securityWebPreferencesFromParent = (Object.keys(securityWebPreferences).reduce((map, key) => {
|
||||
if (securityWebPreferences[key] === parentWebPreferences[key as keyof Electron.WebPreferences]) {
|
||||
(map as any)[key] = parentWebPreferences[key as keyof Electron.WebPreferences];
|
||||
|
||||
@@ -28,7 +28,7 @@ const getGuestWindow = function (guestContents: WebContents) {
|
||||
};
|
||||
|
||||
const isChildWindow = function (sender: WebContents, target: WebContents) {
|
||||
return target.getLastWebPreferences().openerId === sender.id;
|
||||
return target.getLastWebPreferences()!.openerId === sender.id;
|
||||
};
|
||||
|
||||
const isRelatedWindow = function (sender: WebContents, target: WebContents) {
|
||||
@@ -43,7 +43,7 @@ const isScriptableWindow = function (sender: WebContents, target: WebContents) {
|
||||
};
|
||||
|
||||
const isNodeIntegrationEnabled = function (sender: WebContents) {
|
||||
return sender.getLastWebPreferences().nodeIntegration === true;
|
||||
return sender.getLastWebPreferences()!.nodeIntegration === true;
|
||||
};
|
||||
|
||||
// Checks whether |sender| can access the |target|:
|
||||
@@ -65,7 +65,7 @@ ipcMainInternal.on(
|
||||
features: string
|
||||
) => {
|
||||
// This should only be allowed for senders that have nativeWindowOpen: false
|
||||
const lastWebPreferences = event.sender.getLastWebPreferences();
|
||||
const lastWebPreferences = event.sender.getLastWebPreferences()!;
|
||||
if (lastWebPreferences.nativeWindowOpen || lastWebPreferences.sandbox) {
|
||||
event.returnValue = null;
|
||||
throw new Error(
|
||||
|
||||
@@ -4,7 +4,6 @@ import { clipboard } from 'electron/common';
|
||||
import * as fs from 'fs';
|
||||
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
|
||||
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
|
||||
import * as typeUtils from '@electron/internal/common/type-utils';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
import type * as desktopCapturerModule from '@electron/internal/browser/desktop-capturer';
|
||||
@@ -39,6 +38,10 @@ ipcMainInternal.handle(IPC_MESSAGES.BROWSER_GET_LAST_WEB_PREFERENCES, function (
|
||||
return event.sender.getLastWebPreferences();
|
||||
});
|
||||
|
||||
ipcMainInternal.handle(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO, function (event) {
|
||||
return event.sender._getProcessMemoryInfo();
|
||||
});
|
||||
|
||||
// Methods not listed in this set are called directly in the renderer process.
|
||||
const allowedClipboardMethods = (() => {
|
||||
switch (process.platform) {
|
||||
@@ -56,7 +59,7 @@ ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_CLIPBOARD_SYNC, function (event, me
|
||||
throw new Error(`Invalid method: ${method}`);
|
||||
}
|
||||
|
||||
return typeUtils.serialize((clipboard as any)[method](...typeUtils.deserialize(args)));
|
||||
return (clipboard as any)[method](...args);
|
||||
});
|
||||
|
||||
if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
|
||||
@@ -71,7 +74,7 @@ if (BUILDFLAG(ENABLE_DESKTOP_CAPTURER)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return typeUtils.serialize(await desktopCapturer.getSourcesImpl(event.sender, options));
|
||||
return await desktopCapturer.getSourcesImpl(event.sender, options);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
import type * as typeUtilsModule from '@electron/internal/common/type-utils';
|
||||
|
||||
const clipboard = process._linkedBinding('electron_common_clipboard');
|
||||
|
||||
if (process.type === 'renderer') {
|
||||
const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils') as typeof ipcRendererUtilsModule;
|
||||
const typeUtils = require('@electron/internal/common/type-utils') as typeof typeUtilsModule;
|
||||
|
||||
const makeRemoteMethod = function (method: keyof Electron.Clipboard) {
|
||||
return (...args: any[]) => {
|
||||
args = typeUtils.serialize(args);
|
||||
const result = ipcRendererUtils.invokeSync(IPC_MESSAGES.BROWSER_CLIPBOARD_SYNC, method, ...args);
|
||||
return typeUtils.deserialize(result);
|
||||
};
|
||||
const makeRemoteMethod = function (method: keyof Electron.Clipboard): any {
|
||||
return (...args: any[]) => ipcRendererUtils.invokeSync(IPC_MESSAGES.BROWSER_CLIPBOARD_SYNC, method, ...args);
|
||||
};
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Common modules, please sort alphabetically
|
||||
export const commonModuleList: ElectronInternal.ModuleEntry[] = [
|
||||
{ name: 'clipboard', loader: () => require('./clipboard') },
|
||||
{ name: 'nativeImage', loader: () => require('./native-image') },
|
||||
{ name: 'shell', loader: () => require('./shell') },
|
||||
// The internal modules, invisible unless you know their names.
|
||||
{ name: 'deprecate', loader: () => require('./deprecate'), private: true }
|
||||
|
||||
@@ -4,19 +4,16 @@ export const enum IPC_MESSAGES {
|
||||
BROWSER_PRELOAD_ERROR = 'BROWSER_PRELOAD_ERROR',
|
||||
BROWSER_SANDBOX_LOAD = 'BROWSER_SANDBOX_LOAD',
|
||||
BROWSER_WINDOW_CLOSE = 'BROWSER_WINDOW_CLOSE',
|
||||
BROWSER_GET_PROCESS_MEMORY_INFO = 'BROWSER_GET_PROCESS_MEMORY_INFO',
|
||||
|
||||
GUEST_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE',
|
||||
|
||||
GUEST_VIEW_INTERNAL_DESTROY_GUEST = 'GUEST_VIEW_INTERNAL_DESTROY_GUEST',
|
||||
GUEST_VIEW_INTERNAL_DISPATCH_EVENT = 'GUEST_VIEW_INTERNAL_DISPATCH_EVENT',
|
||||
GUEST_VIEW_INTERNAL_IPC_MESSAGE = 'GUEST_VIEW_INTERNAL_IPC_MESSAGE',
|
||||
|
||||
GUEST_VIEW_MANAGER_CREATE_GUEST = 'GUEST_VIEW_MANAGER_CREATE_GUEST',
|
||||
GUEST_VIEW_MANAGER_ATTACH_GUEST = 'GUEST_VIEW_MANAGER_ATTACH_GUEST',
|
||||
GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST = 'GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST',
|
||||
GUEST_VIEW_MANAGER_DETACH_GUEST = 'GUEST_VIEW_MANAGER_DETACH_GUEST',
|
||||
GUEST_VIEW_MANAGER_FOCUS_CHANGE = 'GUEST_VIEW_MANAGER_FOCUS_CHANGE',
|
||||
GUEST_VIEW_MANAGER_CALL = 'GUEST_VIEW_MANAGER_CALL',
|
||||
GUEST_VIEW_MANAGER_CAPTURE_PAGE = 'GUEST_VIEW_MANAGER_CAPTURE_PAGE',
|
||||
GUEST_VIEW_MANAGER_PROPERTY_GET = 'GUEST_VIEW_MANAGER_PROPERTY_GET',
|
||||
GUEST_VIEW_MANAGER_PROPERTY_SET = 'GUEST_VIEW_MANAGER_PROPERTY_SET',
|
||||
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
function getCreateNativeImage () {
|
||||
return process._linkedBinding('electron_common_native_image').nativeImage.createEmpty;
|
||||
}
|
||||
|
||||
export function isPromise (val: any) {
|
||||
return (
|
||||
val &&
|
||||
val.then &&
|
||||
val.then instanceof Function &&
|
||||
val.constructor &&
|
||||
val.constructor.reject &&
|
||||
val.constructor.reject instanceof Function &&
|
||||
val.constructor.resolve &&
|
||||
val.constructor.resolve instanceof Function
|
||||
);
|
||||
}
|
||||
|
||||
const serializableTypes = [
|
||||
Boolean,
|
||||
Number,
|
||||
String,
|
||||
Date,
|
||||
Error,
|
||||
RegExp,
|
||||
ArrayBuffer
|
||||
];
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#Supported_types
|
||||
export function isSerializableObject (value: any) {
|
||||
return value === null || ArrayBuffer.isView(value) || serializableTypes.some(type => value instanceof type);
|
||||
}
|
||||
|
||||
const objectMap = function (source: Object, mapper: (value: any) => any) {
|
||||
const sourceEntries = Object.entries(source);
|
||||
const targetEntries = sourceEntries.map(([key, val]) => [key, mapper(val)]);
|
||||
return Object.fromEntries(targetEntries);
|
||||
};
|
||||
|
||||
function serializeNativeImage (image: Electron.NativeImage) {
|
||||
const representations = [];
|
||||
const scaleFactors = image.getScaleFactors();
|
||||
|
||||
// Use Buffer when there's only one representation for better perf.
|
||||
// This avoids compressing to/from PNG where it's not necessary to
|
||||
// ensure uniqueness of dataURLs (since there's only one).
|
||||
if (scaleFactors.length === 1) {
|
||||
const scaleFactor = scaleFactors[0];
|
||||
const size = image.getSize(scaleFactor);
|
||||
const buffer = image.toBitmap({ scaleFactor });
|
||||
representations.push({ scaleFactor, size, buffer });
|
||||
} else {
|
||||
// Construct from dataURLs to ensure that they are not lost in creation.
|
||||
for (const scaleFactor of scaleFactors) {
|
||||
const size = image.getSize(scaleFactor);
|
||||
const dataURL = image.toDataURL({ scaleFactor });
|
||||
representations.push({ scaleFactor, size, dataURL });
|
||||
}
|
||||
}
|
||||
return { __ELECTRON_SERIALIZED_NativeImage__: true, representations };
|
||||
}
|
||||
|
||||
function deserializeNativeImage (value: any, createNativeImage: typeof Electron.nativeImage['createEmpty']) {
|
||||
const image = createNativeImage();
|
||||
|
||||
// Use Buffer when there's only one representation for better perf.
|
||||
// This avoids compressing to/from PNG where it's not necessary to
|
||||
// ensure uniqueness of dataURLs (since there's only one).
|
||||
if (value.representations.length === 1) {
|
||||
const { buffer, size, scaleFactor } = value.representations[0];
|
||||
const { width, height } = size;
|
||||
image.addRepresentation({ buffer, scaleFactor, width, height });
|
||||
} else {
|
||||
// Construct from dataURLs to ensure that they are not lost in creation.
|
||||
for (const rep of value.representations) {
|
||||
const { dataURL, size, scaleFactor } = rep;
|
||||
const { width, height } = size;
|
||||
image.addRepresentation({ dataURL, scaleFactor, width, height });
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
export function serialize (value: any): any {
|
||||
if (value && value.constructor && value.constructor.name === 'NativeImage') {
|
||||
return serializeNativeImage(value);
|
||||
} if (Array.isArray(value)) {
|
||||
return value.map(serialize);
|
||||
} else if (isSerializableObject(value)) {
|
||||
return value;
|
||||
} else if (value instanceof Object) {
|
||||
return objectMap(value, serialize);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
export function deserialize (value: any, createNativeImage: typeof Electron.nativeImage['createEmpty'] = getCreateNativeImage()): any {
|
||||
if (value && value.__ELECTRON_SERIALIZED_NativeImage__) {
|
||||
return deserializeNativeImage(value, createNativeImage);
|
||||
} else if (Array.isArray(value)) {
|
||||
return value.map(value => deserialize(value, createNativeImage));
|
||||
} else if (isSerializableObject(value)) {
|
||||
return value;
|
||||
} else if (value instanceof Object) {
|
||||
return objectMap(value, value => deserialize(value, createNativeImage));
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ export const webViewEvents: Record<string, readonly string[]> = {
|
||||
'devtools-opened': [],
|
||||
'devtools-closed': [],
|
||||
'devtools-focused': [],
|
||||
'new-window': ['url', 'frameName', 'disposition', 'options'],
|
||||
'will-navigate': ['url'],
|
||||
'did-start-navigation': ['url', 'isInPlace', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
||||
'did-redirect-navigation': ['url', 'isInPlace', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
||||
|
||||
@@ -59,6 +59,7 @@ export const properties = new Set([
|
||||
]);
|
||||
|
||||
export const asyncMethods = new Set([
|
||||
'capturePage',
|
||||
'loadURL',
|
||||
'executeJavaScript',
|
||||
'insertCSS',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
||||
import { deserialize } from '@electron/internal/common/type-utils';
|
||||
import deprecate from '@electron/internal/common/api/deprecate';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
|
||||
@@ -14,6 +14,11 @@ function getCurrentStack () {
|
||||
return (target as any).stack;
|
||||
}
|
||||
|
||||
let warned = process.noDeprecation;
|
||||
export async function getSources (options: Electron.SourcesOptions) {
|
||||
return deserialize(await ipcRendererInternal.invoke(IPC_MESSAGES.DESKTOP_CAPTURER_GET_SOURCES, options, getCurrentStack()));
|
||||
if (!warned) {
|
||||
deprecate.log('The use of \'desktopCapturer.getSources\' in the renderer process is deprecated and will be removed. See https://www.electronjs.org/docs/breaking-changes#removed-desktopcapturergetsources-in-the-renderer for more details.');
|
||||
warned = true;
|
||||
}
|
||||
return await ipcRendererInternal.invoke(IPC_MESSAGES.DESKTOP_CAPTURER_GET_SOURCES, options, getCurrentStack());
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ export const rendererModuleList: ElectronInternal.ModuleEntry[] = [
|
||||
{ name: 'contextBridge', loader: () => require('./context-bridge') },
|
||||
{ name: 'crashReporter', loader: () => require('./crash-reporter') },
|
||||
{ name: 'ipcRenderer', loader: () => require('./ipc-renderer') },
|
||||
{ name: 'nativeImage', loader: () => require('./native-image') },
|
||||
{ name: 'webFrame', loader: () => require('./web-frame') }
|
||||
];
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
const { nativeImage } = process._linkedBinding('electron_common_native_image');
|
||||
|
||||
export default nativeImage;
|
||||
@@ -59,6 +59,10 @@ v8Util.setHiddenValue(global, 'ipcNative', {
|
||||
}
|
||||
});
|
||||
|
||||
process.getProcessMemoryInfo = () => {
|
||||
return ipcRendererInternal.invoke<Electron.ProcessMemoryInfo>(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO);
|
||||
};
|
||||
|
||||
// Use electron module after everything is ready.
|
||||
const { webFrameInit } = require('@electron/internal/renderer/web-frame-init') as typeof webFrameInitModule;
|
||||
webFrameInit();
|
||||
@@ -74,7 +78,7 @@ const isHiddenPage = mainFrame.getWebPreference('hiddenPage');
|
||||
const usesNativeWindowOpen = mainFrame.getWebPreference('nativeWindowOpen');
|
||||
const preloadScript = mainFrame.getWebPreference('preload');
|
||||
const preloadScripts = mainFrame.getWebPreference('preloadScripts');
|
||||
const guestInstanceId = mainFrame.getWebPreference('guestInstanceId');
|
||||
const isWebView = mainFrame.getWebPreference('isWebView');
|
||||
const openerId = mainFrame.getWebPreference('openerId');
|
||||
const appPath = hasSwitch('app-path') ? getSwitchValue('app-path') : null;
|
||||
|
||||
@@ -98,14 +102,14 @@ switch (window.location.protocol) {
|
||||
default: {
|
||||
// Override default web functions.
|
||||
const { windowSetup } = require('@electron/internal/renderer/window-setup') as typeof windowSetupModule;
|
||||
windowSetup(guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen);
|
||||
windowSetup(isWebView, openerId, isHiddenPage, usesNativeWindowOpen);
|
||||
}
|
||||
}
|
||||
|
||||
// Load webview tag implementation.
|
||||
if (process.isMainFrame) {
|
||||
const { webViewInit } = require('@electron/internal/renderer/web-view/web-view-init') as typeof webViewInitModule;
|
||||
webViewInit(contextIsolation, webviewTag, guestInstanceId);
|
||||
webViewInit(contextIsolation, webviewTag, isWebView);
|
||||
}
|
||||
|
||||
if (nodeIntegration) {
|
||||
|
||||
@@ -1,58 +1,32 @@
|
||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
|
||||
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
|
||||
import { webViewEvents } from '@electron/internal/common/web-view-events';
|
||||
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
|
||||
|
||||
const { mainFrame: webFrame } = process._linkedBinding('electron_renderer_web_frame');
|
||||
|
||||
export interface GuestViewDelegate {
|
||||
dispatchEvent (eventName: string, props: Record<string, any>): void;
|
||||
reset(): void;
|
||||
}
|
||||
|
||||
const DEPRECATED_EVENTS: Record<string, string> = {
|
||||
'page-title-updated': 'page-title-set'
|
||||
} as const;
|
||||
|
||||
const dispatchEvent = function (delegate: GuestViewDelegate, eventName: string, eventKey: string, ...args: Array<any>) {
|
||||
if (DEPRECATED_EVENTS[eventName] != null) {
|
||||
dispatchEvent(delegate, DEPRECATED_EVENTS[eventName], eventKey, ...args);
|
||||
}
|
||||
|
||||
const props: Record<string, any> = {};
|
||||
webViewEvents[eventKey].forEach((prop, index) => {
|
||||
props[prop] = args[index];
|
||||
});
|
||||
|
||||
delegate.dispatchEvent(eventName, props);
|
||||
};
|
||||
|
||||
export function registerEvents (viewInstanceId: number, delegate: GuestViewDelegate) {
|
||||
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`, function () {
|
||||
delegate.reset();
|
||||
delegate.dispatchEvent('destroyed', {});
|
||||
});
|
||||
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`, function (event, eventName, props) {
|
||||
if (DEPRECATED_EVENTS[eventName] != null) {
|
||||
delegate.dispatchEvent(DEPRECATED_EVENTS[eventName], props);
|
||||
}
|
||||
|
||||
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`, function (event, eventName, ...args) {
|
||||
dispatchEvent(delegate, eventName, eventName, ...args);
|
||||
});
|
||||
|
||||
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_IPC_MESSAGE}-${viewInstanceId}`, function (event, data) {
|
||||
delegate.dispatchEvent('ipc-message', data);
|
||||
delegate.dispatchEvent(eventName, props);
|
||||
});
|
||||
}
|
||||
|
||||
export function deregisterEvents (viewInstanceId: number) {
|
||||
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`);
|
||||
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`);
|
||||
ipcRendererInternal.removeAllListeners(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_IPC_MESSAGE}-${viewInstanceId}`);
|
||||
}
|
||||
|
||||
export function createGuest (params: Record<string, any>): Promise<number> {
|
||||
return ipcRendererInternal.invoke(IPC_MESSAGES.GUEST_VIEW_MANAGER_CREATE_GUEST, params);
|
||||
}
|
||||
|
||||
export function attachGuest (iframe: HTMLIFrameElement, elementInstanceId: number, guestInstanceId: number, params: Record<string, any>) {
|
||||
export function createGuest (iframe: HTMLIFrameElement, elementInstanceId: number, params: Record<string, any>): Promise<number> {
|
||||
if (!(iframe instanceof HTMLIFrameElement)) {
|
||||
throw new Error('Invalid embedder frame');
|
||||
}
|
||||
@@ -62,17 +36,13 @@ export function attachGuest (iframe: HTMLIFrameElement, elementInstanceId: numbe
|
||||
throw new Error('Invalid embedder frame');
|
||||
}
|
||||
|
||||
return ipcRendererInternal.invoke(IPC_MESSAGES.GUEST_VIEW_MANAGER_ATTACH_GUEST, embedderFrameId, elementInstanceId, guestInstanceId, params);
|
||||
return ipcRendererInternal.invoke(IPC_MESSAGES.GUEST_VIEW_MANAGER_CREATE_AND_ATTACH_GUEST, embedderFrameId, elementInstanceId, params);
|
||||
}
|
||||
|
||||
export function detachGuest (guestInstanceId: number) {
|
||||
return ipcRendererUtils.invokeSync(IPC_MESSAGES.GUEST_VIEW_MANAGER_DETACH_GUEST, guestInstanceId);
|
||||
}
|
||||
|
||||
export function capturePage (guestInstanceId: number, args: any[]) {
|
||||
return ipcRendererInternal.invoke(IPC_MESSAGES.GUEST_VIEW_MANAGER_CAPTURE_PAGE, guestInstanceId, args);
|
||||
}
|
||||
|
||||
export function invoke (guestInstanceId: number, method: string, args: any[]) {
|
||||
return ipcRendererInternal.invoke(IPC_MESSAGES.GUEST_VIEW_MANAGER_CALL, guestInstanceId, method, args);
|
||||
}
|
||||
|
||||
@@ -55,8 +55,7 @@ const defineWebViewElement = (hooks: WebViewImplHooks) => {
|
||||
}
|
||||
if (!internal.elementAttached) {
|
||||
hooks.guestViewInternal.registerEvents(internal.viewInstanceId, {
|
||||
dispatchEvent: internal.dispatchEvent.bind(internal),
|
||||
reset: internal.reset.bind(internal)
|
||||
dispatchEvent: internal.dispatchEvent.bind(internal)
|
||||
});
|
||||
internal.elementAttached = true;
|
||||
(internal.attributes.get(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC) as SrcAttribute).parse();
|
||||
|
||||
@@ -3,7 +3,6 @@ import { WEB_VIEW_CONSTANTS } from '@electron/internal/renderer/web-view/web-vie
|
||||
import { syncMethods, asyncMethods, properties } from '@electron/internal/common/web-view-methods';
|
||||
import type { WebViewAttribute, PartitionAttribute } from '@electron/internal/renderer/web-view/web-view-attributes';
|
||||
import { setupWebViewAttributes } from '@electron/internal/renderer/web-view/web-view-attributes';
|
||||
import { deserialize } from '@electron/internal/common/type-utils';
|
||||
|
||||
// ID generator.
|
||||
let nextId = 0;
|
||||
@@ -16,7 +15,6 @@ export interface WebViewImplHooks {
|
||||
readonly guestViewInternal: typeof guestViewInternalModule;
|
||||
readonly allowGuestViewElementDefinition: NodeJS.InternalWebFrame['allowGuestViewElementDefinition'];
|
||||
readonly setIsWebView: (iframe: HTMLIFrameElement) => void;
|
||||
readonly createNativeImage?: typeof Electron.nativeImage['createEmpty'];
|
||||
}
|
||||
|
||||
// Represents the internal state of the WebView node.
|
||||
@@ -115,9 +113,11 @@ export class WebViewImpl {
|
||||
}
|
||||
|
||||
createGuest () {
|
||||
this.hooks.guestViewInternal.createGuest(this.buildParams()).then(guestInstanceId => {
|
||||
this.attachGuestInstance(guestInstanceId);
|
||||
});
|
||||
this.internalInstanceId = getNextId();
|
||||
this.hooks.guestViewInternal.createGuest(this.internalElement, this.internalInstanceId, this.buildParams())
|
||||
.then(guestInstanceId => {
|
||||
this.attachGuestInstance(guestInstanceId);
|
||||
});
|
||||
}
|
||||
|
||||
dispatchEvent (eventName: string, props: Record<string, any> = {}) {
|
||||
@@ -192,20 +192,19 @@ export class WebViewImpl {
|
||||
}
|
||||
|
||||
attachGuestInstance (guestInstanceId: number) {
|
||||
if (!this.elementAttached) {
|
||||
// The element could be detached before we got response from browser.
|
||||
if (guestInstanceId === -1) {
|
||||
this.dispatchEvent('destroyed');
|
||||
return;
|
||||
}
|
||||
this.internalInstanceId = getNextId();
|
||||
|
||||
if (!this.elementAttached) {
|
||||
// The element could be detached before we got response from browser.
|
||||
// Destroy the backing webContents to avoid any zombie nodes in the frame tree.
|
||||
this.hooks.guestViewInternal.detachGuest(guestInstanceId);
|
||||
return;
|
||||
}
|
||||
|
||||
this.guestInstanceId = guestInstanceId;
|
||||
|
||||
this.hooks.guestViewInternal.attachGuest(
|
||||
this.internalElement,
|
||||
this.internalInstanceId,
|
||||
this.guestInstanceId,
|
||||
this.buildParams()
|
||||
);
|
||||
|
||||
// TODO(zcbenz): Should we deprecate the "resize" event? Wait, it is not
|
||||
// even documented.
|
||||
this.resizeObserver = new ResizeObserver(this.onElementResize.bind(this));
|
||||
@@ -234,10 +233,6 @@ export const setupMethods = (WebViewElement: typeof ElectronInternal.WebViewElem
|
||||
};
|
||||
}
|
||||
|
||||
WebViewElement.prototype.capturePage = async function (...args) {
|
||||
return deserialize(await hooks.guestViewInternal.capturePage(this.getWebContentsId(), args), hooks.createNativeImage);
|
||||
};
|
||||
|
||||
const createPropertyGetter = function (property: string) {
|
||||
return function (this: ElectronInternal.WebViewElement) {
|
||||
return hooks.guestViewInternal.propertyGet(this.getWebContentsId(), property);
|
||||
|
||||
@@ -20,9 +20,9 @@ function handleFocusBlur () {
|
||||
});
|
||||
}
|
||||
|
||||
export function webViewInit (contextIsolation: boolean, webviewTag: boolean, guestInstanceId: number) {
|
||||
export function webViewInit (contextIsolation: boolean, webviewTag: boolean, isWebView: boolean) {
|
||||
// Don't allow recursive `<webview>`.
|
||||
if (webviewTag && !guestInstanceId) {
|
||||
if (webviewTag && !isWebView) {
|
||||
const guestViewInternal = require('@electron/internal/renderer/web-view/guest-view-internal') as typeof guestViewInternalModule;
|
||||
if (contextIsolation) {
|
||||
v8Util.setHiddenValue(window, 'guestViewInternal', guestViewInternal);
|
||||
@@ -36,7 +36,7 @@ export function webViewInit (contextIsolation: boolean, webviewTag: boolean, gue
|
||||
}
|
||||
}
|
||||
|
||||
if (guestInstanceId) {
|
||||
if (isWebView) {
|
||||
// Report focus/blur events of webview to browser.
|
||||
handleFocusBlur();
|
||||
}
|
||||
|
||||
@@ -243,8 +243,8 @@ class BrowserWindowProxy {
|
||||
}
|
||||
|
||||
export const windowSetup = (
|
||||
guestInstanceId: number, openerId: number, isHiddenPage: boolean, usesNativeWindowOpen: boolean) => {
|
||||
if (!process.sandboxed && !guestInstanceId) {
|
||||
isWebView: boolean, openerId: number, isHiddenPage: boolean, usesNativeWindowOpen: boolean) => {
|
||||
if (!process.sandboxed && !isWebView) {
|
||||
// Override default window.close.
|
||||
window.close = function () {
|
||||
ipcRendererInternal.send(IPC_MESSAGES.BROWSER_WINDOW_CLOSE);
|
||||
@@ -318,7 +318,7 @@ export const windowSetup = (
|
||||
});
|
||||
}
|
||||
|
||||
if (guestInstanceId) {
|
||||
if (isWebView) {
|
||||
// Webview `document.visibilityState` tracks window visibility (and ignores
|
||||
// the actual <webview> element visibility) for backwards compatibility.
|
||||
// See discussion in #9178.
|
||||
|
||||
@@ -13,7 +13,7 @@ export const moduleList: ElectronInternal.ModuleEntry[] = [
|
||||
},
|
||||
{
|
||||
name: 'nativeImage',
|
||||
loader: () => require('@electron/internal/renderer/api/native-image')
|
||||
loader: () => require('@electron/internal/common/api/native-image')
|
||||
},
|
||||
{
|
||||
name: 'webFrame',
|
||||
|
||||
@@ -86,6 +86,10 @@ Object.assign(preloadProcess, processProps);
|
||||
Object.assign(process, binding.process);
|
||||
Object.assign(process, processProps);
|
||||
|
||||
process.getProcessMemoryInfo = preloadProcess.getProcessMemoryInfo = () => {
|
||||
return ipcRendererInternal.invoke<Electron.ProcessMemoryInfo>(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO);
|
||||
};
|
||||
|
||||
Object.defineProperty(preloadProcess, 'noDeprecation', {
|
||||
get () {
|
||||
return process.noDeprecation;
|
||||
@@ -127,7 +131,7 @@ const contextIsolation = mainFrame.getWebPreference('contextIsolation');
|
||||
const webviewTag = mainFrame.getWebPreference('webviewTag');
|
||||
const isHiddenPage = mainFrame.getWebPreference('hiddenPage');
|
||||
const usesNativeWindowOpen = true;
|
||||
const guestInstanceId = mainFrame.getWebPreference('guestInstanceId');
|
||||
const isWebView = mainFrame.getWebPreference('isWebView');
|
||||
const openerId = mainFrame.getWebPreference('openerId');
|
||||
|
||||
switch (window.location.protocol) {
|
||||
@@ -145,14 +149,14 @@ switch (window.location.protocol) {
|
||||
default: {
|
||||
// Override default web functions.
|
||||
const { windowSetup } = require('@electron/internal/renderer/window-setup') as typeof windowSetupModule;
|
||||
windowSetup(guestInstanceId, openerId, isHiddenPage, usesNativeWindowOpen);
|
||||
windowSetup(isWebView, openerId, isHiddenPage, usesNativeWindowOpen);
|
||||
}
|
||||
}
|
||||
|
||||
// Load webview tag implementation.
|
||||
if (process.isMainFrame) {
|
||||
const { webViewInit } = require('@electron/internal/renderer/web-view/web-view-init') as typeof webViewInitModule;
|
||||
webViewInit(contextIsolation, webviewTag, guestInstanceId);
|
||||
webViewInit(contextIsolation, webviewTag, isWebView);
|
||||
}
|
||||
|
||||
// Wrap the script into a function executed in global scope. It won't have
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "15.1.1",
|
||||
"version": "16.0.0-beta.1",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
@@ -56,8 +56,8 @@
|
||||
"minimist": "^1.2.5",
|
||||
"null-loader": "^4.0.0",
|
||||
"pre-flight": "^1.1.0",
|
||||
"remark-cli": "^4.0.0",
|
||||
"remark-preset-lint-markdown-style-guide": "^2.1.1",
|
||||
"remark-cli": "^10.0.0",
|
||||
"remark-preset-lint-markdown-style-guide": "^4.0.0",
|
||||
"semver": "^5.6.0",
|
||||
"shx": "^0.3.2",
|
||||
"standard-markdown": "^6.0.0",
|
||||
|
||||
@@ -2,3 +2,4 @@ expose_ripemd160.patch
|
||||
expose_aes-cfb.patch
|
||||
expose_des-ede3.patch
|
||||
fix_sync_evp_get_cipherbynid_and_evp_get_cipherbyname.patch
|
||||
enable_x509_v_flag_trusted_first_flag.patch
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Juan Cruz Viotti <jv@jviotti.com>
|
||||
Date: Thu, 30 Sep 2021 13:39:23 -0400
|
||||
Subject: Enable X509_V_FLAG_TRUSTED_FIRST flag
|
||||
|
||||
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
|
||||
|
||||
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
|
||||
index 5a881d64c30076404cc800fff9e943bb0b30d2ac..29d5341efc8eb7ae6f90bdde5a8032e99f75c98e 100644
|
||||
--- a/crypto/x509/x509_vpm.c
|
||||
+++ b/crypto/x509/x509_vpm.c
|
||||
@@ -528,7 +528,7 @@ static const X509_VERIFY_PARAM default_table[] = {
|
||||
(char *)"default", /* X509 default parameters */
|
||||
0, /* Check time */
|
||||
0, /* internal flags */
|
||||
- 0, /* flags */
|
||||
+ X509_V_FLAG_TRUSTED_FIRST, /* flags */
|
||||
0, /* purpose */
|
||||
0, /* trust */
|
||||
100, /* depth */
|
||||
@@ -31,7 +31,7 @@ index 786a5d5fb13d7ceafc9b7d58c0aaccb88552506d..5ede89f9f0761d1da1baa899e9a02b77
|
||||
return EVP_aes_128_ctr();
|
||||
} else if (OPENSSL_strcasecmp(name, "aes-192-ctr") == 0) {
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index 5a41a7b7dc9afee65d9004c497da735073715bd3..c6c901eaff474eaa3f06128ea825b8203d064a52 100644
|
||||
index 852b76bea69988e0b3ac76a17b603128f239dde0..d443f4dc2daea0b7aa86ae75d31d995fae667ba9 100644
|
||||
--- a/decrepit/evp/evp_do_all.c
|
||||
+++ b/decrepit/evp/evp_do_all.c
|
||||
@@ -20,8 +20,10 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
|
||||
@@ -19,7 +19,7 @@ index 5ede89f9f0761d1da1baa899e9a02b77ffcffe93..8205e121c152fe4e2d8df34a1ac2fe04
|
||||
// This is not a name used by OpenSSL, but tcpdump registers it
|
||||
// with |EVP_add_cipher_alias|. Our |EVP_add_cipher_alias| is a
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index c6c901eaff474eaa3f06128ea825b8203d064a52..f577cd23bf72b94b2651fe5eeb757106f5adaea2 100644
|
||||
index d443f4dc2daea0b7aa86ae75d31d995fae667ba9..5e71420b765019edea82a33884ace539cd91bda5 100644
|
||||
--- a/decrepit/evp/evp_do_all.c
|
||||
+++ b/decrepit/evp/evp_do_all.c
|
||||
@@ -39,6 +39,7 @@ void EVP_CIPHER_do_all_sorted(void (*callback)(const EVP_CIPHER *cipher,
|
||||
|
||||
@@ -10,12 +10,12 @@ this patch is required to provide ripemd160 support in the nodejs crypto
|
||||
module.
|
||||
|
||||
diff --git a/crypto/digest_extra/digest_extra.c b/crypto/digest_extra/digest_extra.c
|
||||
index a93601c170dc407f7d6d628fb7e2d2f0788467f3..00911ee69bb99a34b938ea6a62cd10bc930ec95c 100644
|
||||
index 8cbb28e3afde3dbae3887b22e8b607fa7303e89f..32caba196eb9f0823f774dac9e91314035b3ff7f 100644
|
||||
--- a/crypto/digest_extra/digest_extra.c
|
||||
+++ b/crypto/digest_extra/digest_extra.c
|
||||
@@ -84,6 +84,7 @@ static const struct nid_to_digest nid_to_digest_mapping[] = {
|
||||
{NID_sha384, EVP_sha384, SN_sha384, LN_sha384},
|
||||
@@ -85,6 +85,7 @@ static const struct nid_to_digest nid_to_digest_mapping[] = {
|
||||
{NID_sha512, EVP_sha512, SN_sha512, LN_sha512},
|
||||
{NID_sha512_256, EVP_sha512_256, SN_sha512_256, LN_sha512_256},
|
||||
{NID_md5_sha1, EVP_md5_sha1, SN_md5_sha1, LN_md5_sha1},
|
||||
+ {NID_ripemd160, EVP_ripemd160, SN_ripemd160, LN_ripemd160},
|
||||
// As a remnant of signing |EVP_MD|s, OpenSSL returned the corresponding
|
||||
@@ -62,21 +62,21 @@ index f006ebbc53eea78ce0337a076a05285f22da7a18..7b9309f39a2e5dc6e61bb89e5d32b176
|
||||
+
|
||||
#undef CHECK
|
||||
diff --git a/decrepit/evp/evp_do_all.c b/decrepit/evp/evp_do_all.c
|
||||
index d8023e08f70a060aed083212fefd1de3ecc142e4..5a41a7b7dc9afee65d9004c497da735073715bd3 100644
|
||||
index a3fb077b9b9e66d1bc524fd7987622e73aa4776a..852b76bea69988e0b3ac76a17b603128f239dde0 100644
|
||||
--- a/decrepit/evp/evp_do_all.c
|
||||
+++ b/decrepit/evp/evp_do_all.c
|
||||
@@ -78,6 +78,7 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
|
||||
callback(EVP_sha256(), "SHA256", NULL, arg);
|
||||
@@ -79,6 +79,7 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
|
||||
callback(EVP_sha384(), "SHA384", NULL, arg);
|
||||
callback(EVP_sha512(), "SHA512", NULL, arg);
|
||||
+ callback(EVP_ripemd160(), "RIPEMD160", NULL, arg);
|
||||
callback(EVP_sha512_256(), "SHA512-256", NULL, arg);
|
||||
+ callback(EVP_ripemd160(), "ripemd160", NULL, arg);
|
||||
|
||||
callback(EVP_md4(), "md4", NULL, arg);
|
||||
callback(EVP_md5(), "md5", NULL, arg);
|
||||
@@ -86,6 +87,7 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
|
||||
callback(EVP_sha256(), "sha256", NULL, arg);
|
||||
@@ -88,6 +89,7 @@ void EVP_MD_do_all_sorted(void (*callback)(const EVP_MD *cipher,
|
||||
callback(EVP_sha384(), "sha384", NULL, arg);
|
||||
callback(EVP_sha512(), "sha512", NULL, arg);
|
||||
callback(EVP_sha512_256(), "sha512-256", NULL, arg);
|
||||
+ callback(EVP_ripemd160(), "ripemd160", NULL, arg);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ webview_fullscreen.patch
|
||||
disable_unload_metrics.patch
|
||||
fix_add_check_for_sandbox_then_result.patch
|
||||
extend_apply_webpreferences.patch
|
||||
fix_expose_decrementcapturercount_in_web_contents_impl.patch
|
||||
add_setter_for_browsermainloop_result_code.patch
|
||||
make_include_of_stack_trace_h_unconditional.patch
|
||||
build_libc_as_static_library.patch
|
||||
@@ -102,5 +101,12 @@ refactor_restore_base_adaptcallbackforrepeating.patch
|
||||
hack_to_allow_gclient_sync_with_host_os_mac_on_linux_in_ci.patch
|
||||
don_t_run_pcscan_notifythreadcreated_if_pcscan_is_disabled.patch
|
||||
logging_win32_only_create_a_console_if_logging_to_stderr.patch
|
||||
feat_expose_raw_response_headers_from_urlloader.patch
|
||||
fix_media_key_usage_with_globalshortcuts.patch
|
||||
feat_expose_raw_response_headers_from_urlloader.patch
|
||||
chore_do_not_use_chrome_windows_in_cryptotoken_webrequestsender.patch
|
||||
process_singleton.patch
|
||||
fix_expose_decrementcapturercount_in_web_contents_impl.patch
|
||||
cherry-pick-ec42dfd3545f.patch
|
||||
cherry-pick-39090918efac.patch
|
||||
roll_perfetto_trace_processor_linux_from_b852166f90d5_to_e90b9fb93385.patch
|
||||
mas_gate_private_enterprise_APIs
|
||||
|
||||
@@ -10,7 +10,7 @@ DidCreateScriptContext is called, not all JS APIs are available in the
|
||||
context, which can cause some preload scripts to trip.
|
||||
|
||||
diff --git a/content/public/renderer/render_frame_observer.h b/content/public/renderer/render_frame_observer.h
|
||||
index e24c169444c699f295de2c1f1f42683eeca73436..4675cdccb1876a318a9a0253cdf552bb65516310 100644
|
||||
index 808bbcb0a13bbf069b2354bf39aabcd6d316d514..20e4cbe56bdb8dca3883778b16b9c127aca34793 100644
|
||||
--- a/content/public/renderer/render_frame_observer.h
|
||||
+++ b/content/public/renderer/render_frame_observer.h
|
||||
@@ -127,6 +127,8 @@ class CONTENT_EXPORT RenderFrameObserver : public IPC::Listener,
|
||||
@@ -23,10 +23,10 @@ index e24c169444c699f295de2c1f1f42683eeca73436..4675cdccb1876a318a9a0253cdf552bb
|
||||
int32_t world_id) {}
|
||||
virtual void DidClearWindowObject() {}
|
||||
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
|
||||
index d88901876c14b375bfe2e65698d741e10882fd48..c3bed8fa670cb079bc182addd93f9507e5448dca 100644
|
||||
index 4560b2e363e7392467ff623691d3bd0302b5a502..ebf2d997f03c36e5242405002c7dce583aec31dc 100644
|
||||
--- a/content/renderer/render_frame_impl.cc
|
||||
+++ b/content/renderer/render_frame_impl.cc
|
||||
@@ -4449,6 +4449,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
|
||||
@@ -4460,6 +4460,12 @@ void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
|
||||
observer.DidCreateScriptContext(context, world_id);
|
||||
}
|
||||
|
||||
@@ -40,10 +40,10 @@ index d88901876c14b375bfe2e65698d741e10882fd48..c3bed8fa670cb079bc182addd93f9507
|
||||
int world_id) {
|
||||
for (auto& observer : observers_)
|
||||
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
|
||||
index 1714c5b0a43fa21e370136afd8572b98df805f0f..8d71e6b8dd6d0b229f040b6b97bbda2845bd0db3 100644
|
||||
index 100e382cc73c1f107cd1b7e618b93e009a1f6c65..afebce99ebbcb28aff27d2d7044bb080ce9fd40e 100644
|
||||
--- a/content/renderer/render_frame_impl.h
|
||||
+++ b/content/renderer/render_frame_impl.h
|
||||
@@ -589,6 +589,8 @@ class CONTENT_EXPORT RenderFrameImpl
|
||||
@@ -594,6 +594,8 @@ class CONTENT_EXPORT RenderFrameImpl
|
||||
blink::WebLocalFrameClient::LazyLoadBehavior lazy_load_behavior) override;
|
||||
void DidCreateScriptContext(v8::Local<v8::Context> context,
|
||||
int world_id) override;
|
||||
@@ -53,10 +53,10 @@ index 1714c5b0a43fa21e370136afd8572b98df805f0f..8d71e6b8dd6d0b229f040b6b97bbda28
|
||||
int world_id) override;
|
||||
void DidChangeScrollOffset() override;
|
||||
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
|
||||
index 99ddb8f449481647a499a5bb3fd7f5d5272ae414..00d7f0bbb8dc3afdc2303668481cf17fbdfbdcba 100644
|
||||
index 0ccf54bd50144bc890c96651978f54b0d33713b6..de26aa9f319bd0c762b96f729ccf25a72dd90eb3 100644
|
||||
--- a/third_party/blink/public/web/web_local_frame_client.h
|
||||
+++ b/third_party/blink/public/web/web_local_frame_client.h
|
||||
@@ -587,6 +587,9 @@ class BLINK_EXPORT WebLocalFrameClient {
|
||||
@@ -589,6 +589,9 @@ class BLINK_EXPORT WebLocalFrameClient {
|
||||
virtual void DidCreateScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) {}
|
||||
|
||||
@@ -67,10 +67,10 @@ index 99ddb8f449481647a499a5bb3fd7f5d5272ae414..00d7f0bbb8dc3afdc2303668481cf17f
|
||||
virtual void WillReleaseScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) {}
|
||||
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
|
||||
index fbef5207c921a5443f26083a860becc48eb497c1..5a25ce658f3115325e2213063ac502c855d878ca 100644
|
||||
index b0d5db60fbe57275dda835113b0fb21acb9a422f..b6c9c389943088004a419677a2a17be0c6ab6398 100644
|
||||
--- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
|
||||
+++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
|
||||
@@ -200,6 +200,7 @@ void LocalWindowProxy::Initialize() {
|
||||
@@ -201,6 +201,7 @@ void LocalWindowProxy::Initialize() {
|
||||
}
|
||||
|
||||
InstallConditionalFeatures();
|
||||
@@ -79,10 +79,10 @@ index fbef5207c921a5443f26083a860becc48eb497c1..5a25ce658f3115325e2213063ac502c8
|
||||
if (World().IsMainWorld()) {
|
||||
GetFrame()->Loader().DispatchDidClearWindowObjectInMainWorld();
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
|
||||
index fd9d33e9ee3214673757d2857f339fff70e139f2..ed2ccb72e394f177ec17d823fbf22d725ba43853 100644
|
||||
index 727b770b33f209288904cc10f486ab25f82b4cd6..b25c945378a01ac918ff6dc6caf69effde3685e6 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
|
||||
@@ -299,6 +299,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
|
||||
@@ -303,6 +303,8 @@ class CORE_EXPORT LocalFrameClient : public FrameClient {
|
||||
|
||||
virtual void DidCreateScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) = 0;
|
||||
@@ -92,7 +92,7 @@ index fd9d33e9ee3214673757d2857f339fff70e139f2..ed2ccb72e394f177ec17d823fbf22d72
|
||||
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 96aea6ae2dc5322699741701569e8a1ccd4b9728..92a957fc4971ed3d5b343e8db4db9d603f11b1e9 100644
|
||||
index ba855e42e395f1ba1838400f08827a5bdc19d90f..c74031e118ffb7ff6312c33f99a6ff9d67b5bf19 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
|
||||
@@ -273,6 +273,13 @@ void LocalFrameClientImpl::DidCreateScriptContext(
|
||||
@@ -110,7 +110,7 @@ index 96aea6ae2dc5322699741701569e8a1ccd4b9728..92a957fc4971ed3d5b343e8db4db9d60
|
||||
v8::Local<v8::Context> context,
|
||||
int32_t world_id) {
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
|
||||
index b66e501d692b75e37f50fa3be018df092fc35176..3135bdfa960e9e914ded8ee87f227d5897c9ed33 100644
|
||||
index 57c9b6b733ebf5b9483d31959fbdccad8b72031c..13c7e6924a19717473379045ae1c1f0e6f6d52cf 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
|
||||
@@ -77,6 +77,8 @@ class CORE_EXPORT LocalFrameClientImpl final : public LocalFrameClient {
|
||||
@@ -123,10 +123,10 @@ index b66e501d692b75e37f50fa3be018df092fc35176..3135bdfa960e9e914ded8ee87f227d58
|
||||
int32_t world_id) override;
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
|
||||
index e405538cf1f520c67bcb72e164c66f4a4859d588..054df6b7718cef2c891eb4d00c95792dde5abd4b 100644
|
||||
index 0a4a0b8a4dc871dc86887774a6c81282ea98cda6..ab6ada68a78aa22e723080925d20cf14e8fe822a 100644
|
||||
--- a/third_party/blink/renderer/core/loader/empty_clients.h
|
||||
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
|
||||
@@ -355,6 +355,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
|
||||
@@ -360,6 +360,8 @@ class CORE_EXPORT EmptyLocalFrameClient : public LocalFrameClient {
|
||||
|
||||
void DidCreateScriptContext(v8::Local<v8::Context>,
|
||||
int32_t world_id) override {}
|
||||
|
||||
@@ -6,10 +6,10 @@ Subject: allow disabling blink scheduler throttling per RenderView
|
||||
This allows us to disable throttling for hidden windows.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
|
||||
index 9786cb8ef66333dd6f45d393ac1b13ba72f8a6a1..11ff32590f1b02b0d2d18830bbb6191e532768f2 100644
|
||||
index af75828e89e8cb1cca20c8acd64c9f864c0ffab7..182a6ebdf1ccad6b6ef7a2d45791bc0f5dc456f2 100644
|
||||
--- a/content/browser/renderer_host/render_view_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_view_host_impl.cc
|
||||
@@ -615,6 +615,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) {
|
||||
@@ -627,6 +627,11 @@ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) {
|
||||
GetWidget()->GetAssociatedFrameWidget()->SetBackgroundOpaque(opaque);
|
||||
}
|
||||
|
||||
@@ -22,10 +22,10 @@ index 9786cb8ef66333dd6f45d393ac1b13ba72f8a6a1..11ff32590f1b02b0d2d18830bbb6191e
|
||||
return is_active();
|
||||
}
|
||||
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
|
||||
index 0e95eaa02ae027d322660ca28527db3540837638..2c0e44b9a306e3eedba21d0fbaf93a62a6aed90d 100644
|
||||
index b51bd8160bf63a75066d23514b727eb365a3918c..48413119621f6b118b80d681f777e74af8dc8ab7 100644
|
||||
--- a/content/browser/renderer_host/render_view_host_impl.h
|
||||
+++ b/content/browser/renderer_host/render_view_host_impl.h
|
||||
@@ -137,6 +137,7 @@ class CONTENT_EXPORT RenderViewHostImpl
|
||||
@@ -135,6 +135,7 @@ class CONTENT_EXPORT RenderViewHostImpl
|
||||
bool IsRenderViewLive() override;
|
||||
void WriteIntoTrace(perfetto::TracedValue context) override;
|
||||
|
||||
@@ -34,10 +34,10 @@ index 0e95eaa02ae027d322660ca28527db3540837638..2c0e44b9a306e3eedba21d0fbaf93a62
|
||||
void SendRendererPreferencesToRenderer(
|
||||
const blink::RendererPreferences& preferences);
|
||||
diff --git a/content/public/browser/render_view_host.h b/content/public/browser/render_view_host.h
|
||||
index 740d1c322b740d374dd0287d99daebc1fe39ceda..f6ed1402120c0d8b30356c87a52d88fe39ed08d9 100644
|
||||
index 8bb06dec16fbf205230a10e0e52daa787338bc23..9ebc42788391e838e78af75e2449dde4f1107f22 100644
|
||||
--- a/content/public/browser/render_view_host.h
|
||||
+++ b/content/public/browser/render_view_host.h
|
||||
@@ -90,6 +90,9 @@ class CONTENT_EXPORT RenderViewHost {
|
||||
@@ -84,6 +84,9 @@ class CONTENT_EXPORT RenderViewHost {
|
||||
// Write a representation of this object into a trace.
|
||||
virtual void WriteIntoTrace(perfetto::TracedValue context) = 0;
|
||||
|
||||
@@ -113,10 +113,10 @@ index 7995eb16a7cf6a824653736ca067baa5e688834f..c26e087f2f4d7a1446ce439e5a08a34a
|
||||
|
||||
mojom::blink::PageVisibilityState WebViewImpl::GetVisibilityState() {
|
||||
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h
|
||||
index e7b0409bd60df8c1476f0c9ce14380bfade9773d..3a955aa7fcf08a7d7222eca37222870c6ec8fe36 100644
|
||||
index 293e146acb0257a80d41eecf0794b7f08aa0ffc4..c1c88c9349d3882f3896fa1ed715433d9cf19429 100644
|
||||
--- a/third_party/blink/renderer/core/exported/web_view_impl.h
|
||||
+++ b/third_party/blink/renderer/core/exported/web_view_impl.h
|
||||
@@ -416,6 +416,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
|
||||
@@ -417,6 +417,7 @@ class CORE_EXPORT WebViewImpl final : public WebView,
|
||||
LocalDOMWindow* PagePopupWindow() const;
|
||||
|
||||
PageScheduler* Scheduler() const override;
|
||||
@@ -124,7 +124,7 @@ index e7b0409bd60df8c1476f0c9ce14380bfade9773d..3a955aa7fcf08a7d7222eca37222870c
|
||||
void SetVisibilityState(mojom::blink::PageVisibilityState visibility_state,
|
||||
bool is_initial_state) override;
|
||||
mojom::blink::PageVisibilityState GetVisibilityState() override;
|
||||
@@ -847,6 +848,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
|
||||
@@ -848,6 +849,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
|
||||
// If true, we send IPC messages when |preferred_size_| changes.
|
||||
bool send_preferred_size_changes_ = false;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ WebPreferences of in-process child windows, rather than relying on
|
||||
process-level command line switches, as before.
|
||||
|
||||
diff --git a/third_party/blink/common/web_preferences/web_preferences.cc b/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
index 8a1315f7f89588bb21c6d3c21a7de7c07fed9679..51cc790f7e1ba1440a6ffaa56c9e01687fc35c06 100644
|
||||
index 8a1315f7f89588bb21c6d3c21a7de7c07fed9679..c23443c7816e38836b2f4233ca3a742693888f39 100644
|
||||
--- a/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
+++ b/third_party/blink/common/web_preferences/web_preferences.cc
|
||||
@@ -148,6 +148,22 @@ WebPreferences::WebPreferences()
|
||||
@@ -18,7 +18,7 @@ index 8a1315f7f89588bb21c6d3c21a7de7c07fed9679..51cc790f7e1ba1440a6ffaa56c9e0168
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ opener_id(0),
|
||||
+ context_isolation(false),
|
||||
+ guest_instance_id(0),
|
||||
+ is_webview(false),
|
||||
+ hidden_page(false),
|
||||
+ offscreen(false),
|
||||
+ preload(base::FilePath::StringType()),
|
||||
@@ -35,7 +35,7 @@ index 8a1315f7f89588bb21c6d3c21a7de7c07fed9679..51cc790f7e1ba1440a6ffaa56c9e0168
|
||||
accelerated_video_decode_enabled(false),
|
||||
animation_policy(
|
||||
diff --git a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
index a264ef99beb81dd6b1f55c1b0f57f6055b4ab771..ff4d5c5245ba0641b4ef02cdaf5d50be537b709e 100644
|
||||
index a264ef99beb81dd6b1f55c1b0f57f6055b4ab771..16b734cb371d22dbe99b4ae397126f240b9f686c 100644
|
||||
--- a/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
+++ b/third_party/blink/common/web_preferences/web_preferences_mojom_traits.cc
|
||||
@@ -23,6 +23,10 @@ bool StructTraits<blink::mojom::WebPreferencesDataView,
|
||||
@@ -56,7 +56,7 @@ index a264ef99beb81dd6b1f55c1b0f57f6055b4ab771..ff4d5c5245ba0641b4ef02cdaf5d50be
|
||||
+ // Begin Electron-specific WebPreferences.
|
||||
+ out->opener_id = data.opener_id();
|
||||
+ out->context_isolation = data.context_isolation();
|
||||
+ out->guest_instance_id = data.guest_instance_id();
|
||||
+ out->is_webview = data.is_webview();
|
||||
+ out->hidden_page = data.hidden_page();
|
||||
+ out->offscreen = data.offscreen();
|
||||
+ out->native_window_open = data.native_window_open();
|
||||
@@ -72,7 +72,7 @@ index a264ef99beb81dd6b1f55c1b0f57f6055b4ab771..ff4d5c5245ba0641b4ef02cdaf5d50be
|
||||
out->accelerated_video_decode_enabled =
|
||||
data.accelerated_video_decode_enabled();
|
||||
diff --git a/third_party/blink/public/common/web_preferences/web_preferences.h b/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
index 4517bf43c1b80f1aa0f3ba8e67e78b8b91e19f8a..492f6c948af74bb925826a1075e6343f147f0eb2 100644
|
||||
index 4517bf43c1b80f1aa0f3ba8e67e78b8b91e19f8a..5dc73459f424ad0a01b4ea18e4de196e20d24ae5 100644
|
||||
--- a/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
+++ b/third_party/blink/public/common/web_preferences/web_preferences.h
|
||||
@@ -10,6 +10,7 @@
|
||||
@@ -91,7 +91,7 @@ index 4517bf43c1b80f1aa0f3ba8e67e78b8b91e19f8a..492f6c948af74bb925826a1075e6343f
|
||||
+ std::vector<base::FilePath> preloads;
|
||||
+ int opener_id;
|
||||
+ bool context_isolation;
|
||||
+ int guest_instance_id;
|
||||
+ bool is_webview;
|
||||
+ bool hidden_page;
|
||||
+ bool offscreen;
|
||||
+ base::FilePath preload;
|
||||
@@ -109,7 +109,7 @@ index 4517bf43c1b80f1aa0f3ba8e67e78b8b91e19f8a..492f6c948af74bb925826a1075e6343f
|
||||
// only controls whether or not the "document.cookie" field is properly
|
||||
// connected to the backing store, for instance if you wanted to be able to
|
||||
diff --git a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
index 9dbbb581a8876430c3e0a39df1ff655d3ddc6d2d..fd6cbcfa1992a75bf660fb9eb47a9099acb3834f 100644
|
||||
index 9dbbb581a8876430c3e0a39df1ff655d3ddc6d2d..98c5c4ac5ee3130581c8576e5ef810a78939f50e 100644
|
||||
--- a/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
+++ b/third_party/blink/public/common/web_preferences/web_preferences_mojom_traits.h
|
||||
@@ -6,6 +6,7 @@
|
||||
@@ -137,8 +137,8 @@ index 9dbbb581a8876430c3e0a39df1ff655d3ddc6d2d..fd6cbcfa1992a75bf660fb9eb47a9099
|
||||
+ return r.context_isolation;
|
||||
+ }
|
||||
+
|
||||
+ static int guest_instance_id(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.guest_instance_id;
|
||||
+ static int is_webview(const blink::web_pref::WebPreferences& r) {
|
||||
+ return r.is_webview;
|
||||
+ }
|
||||
+
|
||||
+ static bool hidden_page(const blink::web_pref::WebPreferences& r) {
|
||||
@@ -190,7 +190,7 @@ index 9dbbb581a8876430c3e0a39df1ff655d3ddc6d2d..fd6cbcfa1992a75bf660fb9eb47a9099
|
||||
return r.cookie_enabled;
|
||||
}
|
||||
diff --git a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
index eaecb8c2b7dadaf7650bc8ac85cbad4383035e67..7863c865df17fa95965b5a4e543579bac22af90b 100644
|
||||
index eaecb8c2b7dadaf7650bc8ac85cbad4383035e67..64d83af36d384d2eb7fdd89a3a0d3665a40354a1 100644
|
||||
--- a/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
+++ b/third_party/blink/public/mojom/webpreferences/web_preferences.mojom
|
||||
@@ -10,6 +10,7 @@ import "third_party/blink/public/mojom/v8_cache_options.mojom";
|
||||
@@ -209,7 +209,7 @@ index eaecb8c2b7dadaf7650bc8ac85cbad4383035e67..7863c865df17fa95965b5a4e543579ba
|
||||
+ array<mojo_base.mojom.FilePath> preloads;
|
||||
+ int32 opener_id;
|
||||
+ bool context_isolation;
|
||||
+ int32 guest_instance_id;
|
||||
+ bool is_webview;
|
||||
+ bool hidden_page;
|
||||
+ bool offscreen;
|
||||
+ mojo_base.mojom.FilePath preload;
|
||||
|
||||
@@ -49,7 +49,7 @@ index 8bf6b4bc077cc41da5e0e6b13302bc343537c68f..01bddc0bcb7476408023c4cfc042a088
|
||||
// its owning reference back to our owning LocalFrame.
|
||||
client_->Detached(type);
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
|
||||
index 1dd636810e0c153f66269132ff09433eaf6d90b2..6f730919d3831bb8287f4a819f8bd9ef7e7e6503 100644
|
||||
index be646cf80c0d3490979e3500821c5fc4351af2a7..dca161475f9e0cd86db8675faec3d375d94c490f 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_frame.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
|
||||
@@ -553,10 +553,6 @@ bool LocalFrame::DetachImpl(FrameDetachType type) {
|
||||
|
||||
@@ -8,7 +8,7 @@ categories in use are known / declared. This patch is required for us
|
||||
to introduce a new Electron category for Electron-specific tracing.
|
||||
|
||||
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h
|
||||
index 81dea0e4a02ae26b2b55e6839202d6864a120d45..5174db10126c9cb81dc422bdac9ba18e498debe8 100644
|
||||
index 702ac1a5464635acb1064ca31f7ef211cc0b4a66..6adcf56ca83237d93cd289744b4eb29d7f9e39d6 100644
|
||||
--- a/base/trace_event/builtin_categories.h
|
||||
+++ b/base/trace_event/builtin_categories.h
|
||||
@@ -77,6 +77,7 @@
|
||||
|
||||
@@ -11,7 +11,7 @@ if we ever align our .pak file generation with Chrome we can remove this
|
||||
patch.
|
||||
|
||||
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
|
||||
index d4436b93723cac8b33a6ffab1437b221446a1fb0..3aef47b5f85c11845962e48efd75a1d5064b7412 100644
|
||||
index abab9c8e8c60a6d1690acca5133b3c54d0ccc793..f4378acd7c92193c6e6ac2785cd8a670bd9c650c 100644
|
||||
--- a/chrome/BUILD.gn
|
||||
+++ b/chrome/BUILD.gn
|
||||
@@ -165,11 +165,16 @@ if (!is_android && !is_mac) {
|
||||
@@ -33,10 +33,10 @@ index d4436b93723cac8b33a6ffab1437b221446a1fb0..3aef47b5f85c11845962e48efd75a1d5
|
||||
"//base",
|
||||
"//build:branding_buildflags",
|
||||
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
|
||||
index 135ad9b24745f6d016806f3c95993efe65b370f3..c5e694cd56b9db940e8564c82e2773aa1a53d9dd 100644
|
||||
index 27f4f83da31dbd3a1e754279e760dddf00224e1b..5cdcad53c32d7f25fe041344cb7441bdd6c524a5 100644
|
||||
--- a/chrome/browser/BUILD.gn
|
||||
+++ b/chrome/browser/BUILD.gn
|
||||
@@ -4359,7 +4359,7 @@ static_library("browser") {
|
||||
@@ -4415,7 +4415,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 135ad9b24745f6d016806f3c95993efe65b370f3..c5e694cd56b9db940e8564c82e2773aa
|
||||
}
|
||||
|
||||
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
|
||||
index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de5288ebaa 100644
|
||||
index a7e09cea9b71e810e08790d109e805a8119c0825..52f9f2b0d4e3ee7d3221f04f122f41e1429f6016 100644
|
||||
--- a/chrome/test/BUILD.gn
|
||||
+++ b/chrome/test/BUILD.gn
|
||||
@@ -5325,7 +5325,6 @@ test("unit_tests") {
|
||||
@@ -5482,7 +5482,6 @@ test("unit_tests") {
|
||||
assert(toolkit_views)
|
||||
sources += [ "../browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc" ]
|
||||
deps += [
|
||||
@@ -57,7 +57,7 @@ index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de
|
||||
"//chrome/browser:chrome_process_finder",
|
||||
"//chrome/browser/safe_browsing/chrome_cleaner",
|
||||
"//chrome/browser/safe_browsing/chrome_cleaner:public",
|
||||
@@ -5338,6 +5337,12 @@ test("unit_tests") {
|
||||
@@ -5495,6 +5494,12 @@ test("unit_tests") {
|
||||
"//components/chrome_cleaner/public/proto",
|
||||
"//ui/events/devices:test_support",
|
||||
]
|
||||
@@ -70,17 +70,17 @@ index 0fcf061bf93b4b11603ef944cf8dd4d456cf5f45..c2a035289bcd7424f1a2645da86133de
|
||||
}
|
||||
|
||||
# TODO(crbug.com/931218): Ninja cannot handle certain characters appearing
|
||||
@@ -5930,7 +5935,6 @@ test("unit_tests") {
|
||||
@@ -6088,7 +6093,6 @@ test("unit_tests") {
|
||||
}
|
||||
|
||||
deps += [
|
||||
- "//chrome:packed_resources_integrity_hash",
|
||||
"//chrome/browser:cart_db_content_proto",
|
||||
"//chrome/browser/media/router:test_support",
|
||||
"//chrome/browser/promo_browser_command:mojo_bindings",
|
||||
@@ -5966,6 +5970,9 @@ test("unit_tests") {
|
||||
"//ui/color:test_support",
|
||||
"//chrome/browser/resource_coordinator:intervention_policy_database_proto",
|
||||
@@ -6124,6 +6128,9 @@ test("unit_tests") {
|
||||
"//ui/native_theme:test_support",
|
||||
"//ui/webui/resources/js/browser_command:mojo_bindings",
|
||||
]
|
||||
+ if (!is_electron_build) {
|
||||
+ deps += [ "//chrome:packed_resources_integrity_hash" ]
|
||||
|
||||
@@ -14,7 +14,7 @@ tradeoff is that switching from MAS_BUILD to !MAS_BUILD or vice-versa will
|
||||
rebuild the entire tree.
|
||||
|
||||
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
|
||||
index 725894d05274355be4ad5d6ac3388a489220a50c..e568780d699a9ac977e509165b2e9b0516cde779 100644
|
||||
index 62e7e4bcd3e6c1ef49e3c929af7ac4634a1e6e2b..4edb4b27d985f6cd836832cde49346089ebe579e 100644
|
||||
--- a/build/config/BUILDCONFIG.gn
|
||||
+++ b/build/config/BUILDCONFIG.gn
|
||||
@@ -123,6 +123,9 @@ if (current_os == "") {
|
||||
|
||||
@@ -9,10 +9,10 @@ potentially prevent a window from being created.
|
||||
TODO(loc): this patch is currently broken.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
index 3e7b18a7f9ba48b010c329a3f857122977a7e205..ec3a51fcd891841f945b4f3629968330f25dd1c0 100644
|
||||
index 78eb422f2ac9c56f7a601f2e82a759817be23f82..1a62a9669484980a69d658ca6729e7caf3db96fb 100644
|
||||
--- a/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
|
||||
@@ -6421,6 +6421,7 @@ void RenderFrameHostImpl::CreateNewWindow(
|
||||
@@ -6533,6 +6533,7 @@ void RenderFrameHostImpl::CreateNewWindow(
|
||||
last_committed_origin_, params->window_container_type,
|
||||
params->target_url, params->referrer.To<Referrer>(),
|
||||
params->frame_name, params->disposition, *params->features,
|
||||
@@ -21,10 +21,10 @@ index 3e7b18a7f9ba48b010c329a3f857122977a7e205..ec3a51fcd891841f945b4f3629968330
|
||||
&no_javascript_access);
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index aac8edf20fc6dbf4aeee6793a76ea1916d121c63..603edba3e661be67f55f8c2ee30dc27d0ca2db49 100644
|
||||
index b9aa5d69242727e1a01df7a0d00d592c58e3815a..5a86229bf1fc52e6cccbf609ed029fe88d35cd8f 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3727,6 +3727,14 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
@@ -3734,6 +3734,14 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
}
|
||||
auto* new_contents_impl = new_contents.get();
|
||||
|
||||
@@ -39,7 +39,7 @@ index aac8edf20fc6dbf4aeee6793a76ea1916d121c63..603edba3e661be67f55f8c2ee30dc27d
|
||||
new_contents_impl->GetController().SetSessionStorageNamespace(
|
||||
partition_id, session_storage_namespace);
|
||||
|
||||
@@ -3769,12 +3777,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
@@ -3776,12 +3784,6 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
AddWebContentsDestructionObserver(new_contents_impl);
|
||||
}
|
||||
|
||||
@@ -53,13 +53,13 @@ index aac8edf20fc6dbf4aeee6793a76ea1916d121c63..603edba3e661be67f55f8c2ee30dc27d
|
||||
new_contents_impl, opener, params.target_url,
|
||||
params.referrer.To<Referrer>(), params.disposition,
|
||||
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
|
||||
index 192a5084eac3e9426ac8ddc4984b572d55c7a88a..63f53ff39240ea59a03f1a6f9d032444b0e4214d 100644
|
||||
index 74ed9ae0eae10e77dace6905b5108a834b07f8b4..924d6b43d444ccb919d6985c975eb8862ca35b20 100644
|
||||
--- a/content/common/frame.mojom
|
||||
+++ b/content/common/frame.mojom
|
||||
@@ -523,6 +523,10 @@ struct CreateNewWindowParams {
|
||||
// The impression associated with the navigation in the new window, if
|
||||
// one is specified.
|
||||
blink.mojom.Impression? impression;
|
||||
@@ -533,6 +533,10 @@ struct CreateNewWindowParams {
|
||||
|
||||
// Governs how downloads are handled if `target_url` results in a download.
|
||||
blink.mojom.NavigationDownloadPolicy download_policy;
|
||||
+
|
||||
+ // Extra fields added by Electron.
|
||||
+ string raw_features;
|
||||
@@ -68,10 +68,10 @@ index 192a5084eac3e9426ac8ddc4984b572d55c7a88a..63f53ff39240ea59a03f1a6f9d032444
|
||||
|
||||
// Operation result when the renderer asks the browser to create a new window.
|
||||
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
|
||||
index 997125e855c0f6393251193fa86c90d179cd9eb9..e5cf4b0c818ba7dcc3b942cdc989285641d2348c 100644
|
||||
index 0cf1f777dc5ffbca606fff558ef6a41e8ed60a99..40bd443cb3c82d9671c4716900a1f19b3c26de69 100644
|
||||
--- a/content/public/browser/content_browser_client.cc
|
||||
+++ b/content/public/browser/content_browser_client.cc
|
||||
@@ -563,6 +563,8 @@ bool ContentBrowserClient::CanCreateWindow(
|
||||
@@ -555,6 +555,8 @@ bool ContentBrowserClient::CanCreateWindow(
|
||||
const std::string& frame_name,
|
||||
WindowOpenDisposition disposition,
|
||||
const blink::mojom::WindowFeatures& features,
|
||||
@@ -81,10 +81,10 @@ index 997125e855c0f6393251193fa86c90d179cd9eb9..e5cf4b0c818ba7dcc3b942cdc9892856
|
||||
bool opener_suppressed,
|
||||
bool* no_javascript_access) {
|
||||
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
|
||||
index 65638e207d6bffd24a1121eb32c86545ba884007..8c68f9f74414a027aa0f7a66238c05ea6054ddf1 100644
|
||||
index b6dae0082a297a6dbafd63bd56729b77ffb832fc..66ff9593b8f3d62c486ef83c4c682edf73081d88 100644
|
||||
--- a/content/public/browser/content_browser_client.h
|
||||
+++ b/content/public/browser/content_browser_client.h
|
||||
@@ -164,6 +164,7 @@ class NetworkService;
|
||||
@@ -167,6 +167,7 @@ class NetworkService;
|
||||
class TrustedURLLoaderHeaderClient;
|
||||
} // namespace mojom
|
||||
struct ResourceRequest;
|
||||
@@ -92,7 +92,7 @@ index 65638e207d6bffd24a1121eb32c86545ba884007..8c68f9f74414a027aa0f7a66238c05ea
|
||||
} // namespace network
|
||||
|
||||
namespace sandbox {
|
||||
@@ -927,6 +928,8 @@ class CONTENT_EXPORT ContentBrowserClient {
|
||||
@@ -922,6 +923,8 @@ class CONTENT_EXPORT ContentBrowserClient {
|
||||
const std::string& frame_name,
|
||||
WindowOpenDisposition disposition,
|
||||
const blink::mojom::WindowFeatures& features,
|
||||
@@ -150,7 +150,7 @@ index a0da74d5cbe4ab8be84d6f1a92f444e858320745..5936fa4bce09895595ccb294504f5b89
|
||||
// typically happens when popups are created.
|
||||
virtual void WebContentsCreated(WebContents* source_contents,
|
||||
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
|
||||
index afec7767d905488a51b2dbba031b8a85d6d0138a..57f970d15bf03f817680982fa8605c333485804b 100644
|
||||
index ea22a86dc1a6e5cdb3e3dfa31a929a3dd14b9e61..215b059bb2dfcead6c709c99b39578f8e2216d93 100644
|
||||
--- a/content/renderer/render_view_impl.cc
|
||||
+++ b/content/renderer/render_view_impl.cc
|
||||
@@ -31,6 +31,7 @@
|
||||
@@ -169,14 +169,14 @@ index afec7767d905488a51b2dbba031b8a85d6d0138a..57f970d15bf03f817680982fa8605c33
|
||||
+ WTF::UTF8ConversionMode::kStrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD);
|
||||
+ params->body = GetRequestBodyForWebURLRequest(request);
|
||||
+
|
||||
// We preserve this information before sending the message since |params| is
|
||||
// moved on send.
|
||||
bool is_background_tab =
|
||||
params->download_policy.ApplyDownloadFramePolicy(
|
||||
/*is_opener_navigation=*/false, request.HasUserGesture(),
|
||||
// `openee_can_access_opener_origin` only matters for opener navigations,
|
||||
diff --git a/content/web_test/browser/web_test_content_browser_client.cc b/content/web_test/browser/web_test_content_browser_client.cc
|
||||
index c6872573086e628a894f482877db2d417552c6a1..5e67b6a59c3e3d6881f738985ab947a2d7902f0a 100644
|
||||
index 520b6f8146361cf8c00079c1cc0f5394f747d405..77f58cc157229eb01ce9a35aa5814f64d6e8f2f2 100644
|
||||
--- a/content/web_test/browser/web_test_content_browser_client.cc
|
||||
+++ b/content/web_test/browser/web_test_content_browser_client.cc
|
||||
@@ -450,6 +450,8 @@ bool WebTestContentBrowserClient::CanCreateWindow(
|
||||
@@ -438,6 +438,8 @@ bool WebTestContentBrowserClient::CanCreateWindow(
|
||||
const std::string& frame_name,
|
||||
WindowOpenDisposition disposition,
|
||||
const blink::mojom::WindowFeatures& features,
|
||||
@@ -186,10 +186,10 @@ index c6872573086e628a894f482877db2d417552c6a1..5e67b6a59c3e3d6881f738985ab947a2
|
||||
bool opener_suppressed,
|
||||
bool* no_javascript_access) {
|
||||
diff --git a/content/web_test/browser/web_test_content_browser_client.h b/content/web_test/browser/web_test_content_browser_client.h
|
||||
index 427656a1a01a9305459a8f1d6616fd0666413b39..c8e296286cdd148348932d2bdfa4d064f8cbe36d 100644
|
||||
index 1580bd13ea123740dc7a8813680a8d2448d49969..5c0809733b366ecff02c5a4b77dac9530eb15fbf 100644
|
||||
--- a/content/web_test/browser/web_test_content_browser_client.h
|
||||
+++ b/content/web_test/browser/web_test_content_browser_client.h
|
||||
@@ -83,6 +83,8 @@ class WebTestContentBrowserClient : public ShellContentBrowserClient {
|
||||
@@ -80,6 +80,8 @@ class WebTestContentBrowserClient : public ShellContentBrowserClient {
|
||||
const std::string& frame_name,
|
||||
WindowOpenDisposition disposition,
|
||||
const blink::mojom::WindowFeatures& features,
|
||||
@@ -220,10 +220,10 @@ index 84d32491a56528a84b4395fba1d54cdbb38d522b..09998a83c449ef8cd9f360fbcdcf7edc
|
||||
|
||||
} // namespace blink
|
||||
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
|
||||
index 229eba91cdfe6cb9eea403cb1e8e6af2066ffcc9..f5cb3041c92246471258eb4b7a2a9164b516f717 100644
|
||||
index 3915f0df47d5a2ae1a5f2909d2aa59192c0cc44b..ada26f26f2ac0fab4a2dc02a5b64c72614c06965 100644
|
||||
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
|
||||
@@ -2002,6 +2002,7 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
|
||||
@@ -2027,6 +2027,7 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
|
||||
|
||||
WebWindowFeatures window_features =
|
||||
GetWindowFeaturesFromString(features, incumbent_window);
|
||||
|
||||
455
patches/chromium/cherry-pick-39090918efac.patch
Normal file
455
patches/chromium/cherry-pick-39090918efac.patch
Normal file
@@ -0,0 +1,455 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: cfredric <cfredric@chromium.org>
|
||||
Date: Mon, 27 Sep 2021 22:14:18 +0000
|
||||
Subject: Consider HTTPS and WSS schemes identically for FPS.
|
||||
|
||||
This modifies the FPS implementation to normalize wss:// URLs into
|
||||
https:// URLs when determining the same-partiness of a request.
|
||||
|
||||
This allows SameParty cookies to be sent on same-party WSS connection
|
||||
requests. A browsertest is included to verify this.
|
||||
|
||||
Bug: 1251688
|
||||
Change-Id: Id277288982805e0d29c6683e0c13d4b7c7cfe359
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3182786
|
||||
Reviewed-by: Maksim Orlovich <morlovich@chromium.org>
|
||||
Reviewed-by: Shuran Huang <shuuran@chromium.org>
|
||||
Commit-Queue: Chris Fredrickson <cfredric@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#925457}
|
||||
|
||||
diff --git a/chrome/browser/net/websocket_browsertest.cc b/chrome/browser/net/websocket_browsertest.cc
|
||||
index 8a9fe6db3b0030496d00cf57d96a90ee899babaf..de48b97b96c22eeae5fe680868c48381d9a13cc2 100644
|
||||
--- a/chrome/browser/net/websocket_browsertest.cc
|
||||
+++ b/chrome/browser/net/websocket_browsertest.cc
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "base/test/bind.h"
|
||||
#include "build/build_config.h"
|
||||
#include "chrome/browser/chrome_notification_types.h"
|
||||
+#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/ui/login/login_handler.h"
|
||||
#include "chrome/browser/ui/login/login_handler_test_utils.h"
|
||||
@@ -45,25 +46,31 @@
|
||||
#include "mojo/public/cpp/system/data_pipe.h"
|
||||
#include "net/base/network_isolation_key.h"
|
||||
#include "net/cookies/site_for_cookies.h"
|
||||
+#include "net/dns/mock_host_resolver.h"
|
||||
#include "net/test/embedded_test_server/embedded_test_server.h"
|
||||
#include "net/test/spawned_test_server/spawned_test_server.h"
|
||||
#include "net/test/test_data_directory.h"
|
||||
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
|
||||
+#include "services/network/public/cpp/network_switches.h"
|
||||
#include "services/network/public/mojom/network_context.mojom.h"
|
||||
#include "services/network/public/mojom/websocket.mojom.h"
|
||||
+#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "url/gurl.h"
|
||||
#include "url/origin.h"
|
||||
|
||||
namespace {
|
||||
|
||||
+using SSLOptions = net::SpawnedTestServer::SSLOptions;
|
||||
+
|
||||
class WebSocketBrowserTest : public InProcessBrowserTest {
|
||||
public:
|
||||
- WebSocketBrowserTest()
|
||||
+ explicit WebSocketBrowserTest(
|
||||
+ SSLOptions::ServerCertificate cert = SSLOptions::CERT_OK)
|
||||
: ws_server_(net::SpawnedTestServer::TYPE_WS,
|
||||
net::GetWebSocketTestDataDirectory()),
|
||||
wss_server_(net::SpawnedTestServer::TYPE_WSS,
|
||||
- SSLOptions(SSLOptions::CERT_OK),
|
||||
+ SSLOptions(cert),
|
||||
net::GetWebSocketTestDataDirectory()) {}
|
||||
|
||||
protected:
|
||||
@@ -145,7 +152,6 @@ class WebSocketBrowserTest : public InProcessBrowserTest {
|
||||
net::SpawnedTestServer wss_server_;
|
||||
|
||||
private:
|
||||
- typedef net::SpawnedTestServer::SSLOptions SSLOptions;
|
||||
std::unique_ptr<content::TitleWatcher> watcher_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WebSocketBrowserTest);
|
||||
@@ -162,37 +168,72 @@ class WebSocketBrowserTestWithAllowFileAccessFromFiles
|
||||
};
|
||||
|
||||
// Framework for tests using the connect_to.html page served by a separate HTTP
|
||||
-// server.
|
||||
+// or HTTPS server.
|
||||
class WebSocketBrowserConnectToTest : public WebSocketBrowserTest {
|
||||
protected:
|
||||
- WebSocketBrowserConnectToTest() {
|
||||
- http_server_.ServeFilesFromSourceDirectory(
|
||||
- net::GetWebSocketTestDataDirectory());
|
||||
- }
|
||||
+ explicit WebSocketBrowserConnectToTest(
|
||||
+ SSLOptions::ServerCertificate cert = SSLOptions::CERT_OK)
|
||||
+ : WebSocketBrowserTest(cert) {}
|
||||
|
||||
// The title watcher and HTTP server are set up automatically by the test
|
||||
// framework. Each test case still needs to configure and start the
|
||||
// WebSocket server(s) it needs.
|
||||
void SetUpOnMainThread() override {
|
||||
+ server().ServeFilesFromSourceDirectory(
|
||||
+ net::GetWebSocketTestDataDirectory());
|
||||
WebSocketBrowserTest::SetUpOnMainThread();
|
||||
- ASSERT_TRUE(http_server_.Start());
|
||||
+ ASSERT_TRUE(server().Start());
|
||||
}
|
||||
|
||||
- // Supply a ws: or wss: URL to connect to.
|
||||
- void ConnectTo(GURL url) {
|
||||
- ASSERT_TRUE(http_server_.Started());
|
||||
+ // Supply a ws: or wss: URL to connect to. Serves connect_to.html from the
|
||||
+ // server's default host.
|
||||
+ void ConnectTo(const GURL& url) {
|
||||
+ ConnectTo(server().base_url().host(), url);
|
||||
+ }
|
||||
+
|
||||
+ // Supply a ws: or wss: URL to connect to via loading `host`/connect_to.html.
|
||||
+ void ConnectTo(const std::string& host, const GURL& url) {
|
||||
+ ASSERT_TRUE(server().Started());
|
||||
std::string query("url=" + url.spec());
|
||||
GURL::Replacements replacements;
|
||||
replacements.SetQueryStr(query);
|
||||
ASSERT_TRUE(ui_test_utils::NavigateToURL(
|
||||
- browser(), http_server_.GetURL("/connect_to.html")
|
||||
+ browser(), server()
|
||||
+ .GetURL(host, "/connect_to.html")
|
||||
.ReplaceComponents(replacements)));
|
||||
}
|
||||
|
||||
- private:
|
||||
+ virtual net::EmbeddedTestServer& server() = 0;
|
||||
+};
|
||||
+
|
||||
+// Concrete impl for tests that use connect_to.html over HTTP.
|
||||
+class WebSocketBrowserHTTPConnectToTest : public WebSocketBrowserConnectToTest {
|
||||
+ protected:
|
||||
+ net::EmbeddedTestServer& server() override { return http_server_; }
|
||||
+
|
||||
net::EmbeddedTestServer http_server_;
|
||||
};
|
||||
|
||||
+// Concrete impl for tests that use connect_to.html over HTTPS.
|
||||
+class WebSocketBrowserHTTPSConnectToTest
|
||||
+ : public WebSocketBrowserConnectToTest {
|
||||
+ protected:
|
||||
+ explicit WebSocketBrowserHTTPSConnectToTest(
|
||||
+ SSLOptions::ServerCertificate cert = SSLOptions::CERT_OK)
|
||||
+ : WebSocketBrowserConnectToTest(cert),
|
||||
+ https_server_(net::test_server::EmbeddedTestServer::TYPE_HTTPS) {}
|
||||
+
|
||||
+ void SetUpOnMainThread() override {
|
||||
+ host_resolver()->AddRule("*", "127.0.0.1");
|
||||
+ server().SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
|
||||
+ WebSocketBrowserConnectToTest::SetUpOnMainThread();
|
||||
+ }
|
||||
+
|
||||
+ net::EmbeddedTestServer& server() override { return https_server_; }
|
||||
+
|
||||
+ net::EmbeddedTestServer https_server_;
|
||||
+};
|
||||
+
|
||||
// Automatically fill in any login prompts that appear with the supplied
|
||||
// credentials.
|
||||
class AutoLogin : public content::NotificationObserver {
|
||||
@@ -352,7 +393,7 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserTest,
|
||||
EXPECT_EQ("PASS", WaitAndGetTitle());
|
||||
}
|
||||
|
||||
-IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
|
||||
+IN_PROC_BROWSER_TEST_F(WebSocketBrowserHTTPConnectToTest,
|
||||
WebSocketBasicAuthInWSURL) {
|
||||
// Launch a basic-auth-protected WebSocket server.
|
||||
ws_server_.set_websocket_basic_auth(true);
|
||||
@@ -364,7 +405,7 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
|
||||
EXPECT_EQ("PASS", WaitAndGetTitle());
|
||||
}
|
||||
|
||||
-IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
|
||||
+IN_PROC_BROWSER_TEST_F(WebSocketBrowserHTTPConnectToTest,
|
||||
WebSocketBasicAuthInWSURLBadCreds) {
|
||||
// Launch a basic-auth-protected WebSocket server.
|
||||
ws_server_.set_websocket_basic_auth(true);
|
||||
@@ -376,7 +417,7 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
|
||||
EXPECT_EQ("FAIL", WaitAndGetTitle());
|
||||
}
|
||||
|
||||
-IN_PROC_BROWSER_TEST_F(WebSocketBrowserConnectToTest,
|
||||
+IN_PROC_BROWSER_TEST_F(WebSocketBrowserHTTPConnectToTest,
|
||||
WebSocketBasicAuthNoCreds) {
|
||||
// Launch a basic-auth-protected WebSocket server.
|
||||
ws_server_.set_websocket_basic_auth(true);
|
||||
@@ -420,8 +461,7 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserTest, MAYBE_WebSocketAppliesHSTS) {
|
||||
https_server.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
|
||||
net::SpawnedTestServer wss_server(
|
||||
net::SpawnedTestServer::TYPE_WSS,
|
||||
- net::SpawnedTestServer::SSLOptions(
|
||||
- net::SpawnedTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN),
|
||||
+ SSLOptions(SSLOptions::CERT_COMMON_NAME_IS_DOMAIN),
|
||||
net::GetWebSocketTestDataDirectory());
|
||||
// This test sets HSTS on localhost. To avoid being redirected to https, start
|
||||
// the http server on 127.0.0.1 instead.
|
||||
@@ -711,4 +751,43 @@ IN_PROC_BROWSER_TEST_F(WebSocketBrowserTestWithAllowFileAccessFromFiles,
|
||||
EXPECT_EQ("FILE", WaitAndGetTitle());
|
||||
}
|
||||
|
||||
+// A test fixture that enables First-Party Sets.
|
||||
+class FirstPartySetsWebSocketBrowserTest
|
||||
+ : public WebSocketBrowserHTTPSConnectToTest {
|
||||
+ public:
|
||||
+ FirstPartySetsWebSocketBrowserTest()
|
||||
+ : WebSocketBrowserHTTPSConnectToTest(SSLOptions::CERT_TEST_NAMES) {}
|
||||
+
|
||||
+ void SetUpCommandLine(base::CommandLine* command_line) override {
|
||||
+ WebSocketBrowserTest::SetUpCommandLine(command_line);
|
||||
+ command_line->AppendSwitchASCII(
|
||||
+ network::switches::kUseFirstPartySet,
|
||||
+ "https://a.test,https://b.test,https://c.test");
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+IN_PROC_BROWSER_TEST_F(FirstPartySetsWebSocketBrowserTest,
|
||||
+ SendsSamePartyCookies) {
|
||||
+ ASSERT_TRUE(wss_server_.Start());
|
||||
+
|
||||
+ ASSERT_TRUE(content::SetCookie(browser()->profile(),
|
||||
+ server().GetURL("a.test", "/"),
|
||||
+ "same-party-cookie=1; SameParty; Secure"));
|
||||
+ ASSERT_TRUE(content::SetCookie(browser()->profile(),
|
||||
+ server().GetURL("a.test", "/"),
|
||||
+ "same-site-cookie=1; SameSite=Lax; Secure"));
|
||||
+
|
||||
+ content::DOMMessageQueue message_queue;
|
||||
+ ConnectTo("b.test", wss_server_.GetURL("a.test", "echo-request-headers"));
|
||||
+
|
||||
+ std::string message;
|
||||
+ EXPECT_TRUE(message_queue.WaitForMessage(&message));
|
||||
+ // Only the SameParty cookie should have been sent, since it was a cross-site
|
||||
+ // but same-party connection.
|
||||
+ EXPECT_THAT(message, testing::HasSubstr("same-party-cookie=1"));
|
||||
+ EXPECT_THAT(message, testing::Not(testing::HasSubstr("same-site-cookie=1")));
|
||||
+
|
||||
+ EXPECT_EQ("PASS", WaitAndGetTitle());
|
||||
+}
|
||||
+
|
||||
} // namespace
|
||||
diff --git a/net/data/websocket/connect_to.html b/net/data/websocket/connect_to.html
|
||||
index 05c653fc5d2ab9a333efea5b4c5eee83a03bbe07..8a6d78214fe5974cbb0ec62b61f4d7fdcdf42c3b 100644
|
||||
--- a/net/data/websocket/connect_to.html
|
||||
+++ b/net/data/websocket/connect_to.html
|
||||
@@ -29,6 +29,17 @@ ws.onclose = function()
|
||||
document.title = 'FAIL';
|
||||
}
|
||||
|
||||
+ws.onmessage = function(evt)
|
||||
+{
|
||||
+ domAutomationController.send(evt.data);
|
||||
+}
|
||||
+
|
||||
+ws.onerror = function(evt)
|
||||
+{
|
||||
+ console.error(`WebSocket error: '${evt.message}'`);
|
||||
+}
|
||||
+
|
||||
+
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
|
||||
index 71199ca12a6b805f288349b0d702b834d4e51df7..90626857ea6452a04e872d13f4474c67a905353c 100644
|
||||
--- a/net/test/spawned_test_server/base_test_server.cc
|
||||
+++ b/net/test/spawned_test_server/base_test_server.cc
|
||||
@@ -137,6 +137,8 @@ base::FilePath BaseTestServer::SSLOptions::GetCertificateFile() const {
|
||||
case CERT_KEY_USAGE_RSA_DIGITAL_SIGNATURE:
|
||||
return base::FilePath(
|
||||
FILE_PATH_LITERAL("key_usage_rsa_digitalsignature.pem"));
|
||||
+ case CERT_TEST_NAMES:
|
||||
+ return base::FilePath(FILE_PATH_LITERAL("test_names.pem"));
|
||||
default:
|
||||
NOTREACHED();
|
||||
}
|
||||
@@ -228,6 +230,14 @@ GURL BaseTestServer::GetURL(const std::string& path) const {
|
||||
return GURL(GetScheme() + "://" + host_port_pair_.ToString() + "/" + path);
|
||||
}
|
||||
|
||||
+GURL BaseTestServer::GetURL(const std::string& hostname,
|
||||
+ const std::string& relative_url) const {
|
||||
+ GURL local_url = GetURL(relative_url);
|
||||
+ GURL::Replacements replace_host;
|
||||
+ replace_host.SetHostStr(hostname);
|
||||
+ return local_url.ReplaceComponents(replace_host);
|
||||
+}
|
||||
+
|
||||
GURL BaseTestServer::GetURLWithUser(const std::string& path,
|
||||
const std::string& user) const {
|
||||
return GURL(GetScheme() + "://" + user + "@" + host_port_pair_.ToString() +
|
||||
diff --git a/net/test/spawned_test_server/base_test_server.h b/net/test/spawned_test_server/base_test_server.h
|
||||
index e16c548686fd00517493a33ad390dfd2a4ead380..091c5b3ea3f910bfe188c82bc1be85f75dd7dc78 100644
|
||||
--- a/net/test/spawned_test_server/base_test_server.h
|
||||
+++ b/net/test/spawned_test_server/base_test_server.h
|
||||
@@ -77,6 +77,11 @@ class BaseTestServer {
|
||||
// A certificate with invalid notBefore and notAfter times. Windows'
|
||||
// certificate library will not parse this certificate.
|
||||
CERT_BAD_VALIDITY,
|
||||
+
|
||||
+ // A certificate that covers a number of test names. See [test_names] in
|
||||
+ // net/data/ssl/scripts/ee.cnf. More may be added by editing this list and
|
||||
+ // and rerunning net/data/ssl/scripts/generate-test-certs.sh.
|
||||
+ CERT_TEST_NAMES,
|
||||
};
|
||||
|
||||
// NOTE: the values of these enumerators are passed to the the Python test
|
||||
@@ -206,6 +211,8 @@ class BaseTestServer {
|
||||
bool GetAddressList(AddressList* address_list) const WARN_UNUSED_RESULT;
|
||||
|
||||
GURL GetURL(const std::string& path) const;
|
||||
+ GURL GetURL(const std::string& hostname,
|
||||
+ const std::string& relative_url) const;
|
||||
|
||||
GURL GetURLWithUser(const std::string& path,
|
||||
const std::string& user) const;
|
||||
diff --git a/services/network/first_party_sets/first_party_sets.cc b/services/network/first_party_sets/first_party_sets.cc
|
||||
index 1650c28d8b6c61b30531e1e2ef3e2869d8450360..826b403a2a9702c255ee9b7ea38dc74b9e18791d 100644
|
||||
--- a/services/network/first_party_sets/first_party_sets.cc
|
||||
+++ b/services/network/first_party_sets/first_party_sets.cc
|
||||
@@ -91,16 +91,17 @@ bool FirstPartySets::IsContextSamePartyWithSite(
|
||||
const net::SchemefulSite* top_frame_site,
|
||||
const std::set<net::SchemefulSite>& party_context,
|
||||
bool infer_singleton_sets) const {
|
||||
- const net::SchemefulSite* site_owner = FindOwner(site, infer_singleton_sets);
|
||||
- if (!site_owner)
|
||||
+ const absl::optional<net::SchemefulSite> site_owner =
|
||||
+ FindOwner(site, infer_singleton_sets);
|
||||
+ if (!site_owner.has_value())
|
||||
return false;
|
||||
|
||||
const auto is_owned_by_site_owner =
|
||||
- [this, site_owner,
|
||||
+ [this, &site_owner,
|
||||
infer_singleton_sets](const net::SchemefulSite& context_site) -> bool {
|
||||
- const net::SchemefulSite* context_owner =
|
||||
+ const absl::optional<net::SchemefulSite> context_owner =
|
||||
FindOwner(context_site, infer_singleton_sets);
|
||||
- return context_owner && *context_owner == *site_owner;
|
||||
+ return context_owner.has_value() && *context_owner == *site_owner;
|
||||
};
|
||||
|
||||
if (top_frame_site && !is_owned_by_site_owner(*top_frame_site))
|
||||
@@ -131,7 +132,8 @@ net::FirstPartySetsContextType FirstPartySets::ComputeContextType(
|
||||
const absl::optional<net::SchemefulSite>& top_frame_site,
|
||||
const std::set<net::SchemefulSite>& party_context) const {
|
||||
constexpr bool infer_singleton_sets = true;
|
||||
- const net::SchemefulSite* site_owner = FindOwner(site, infer_singleton_sets);
|
||||
+ const absl::optional<net::SchemefulSite> site_owner =
|
||||
+ FindOwner(site, infer_singleton_sets);
|
||||
// Note: the `party_context` consists of the intermediate frames (for frame
|
||||
// requests) or intermediate frames and current frame for subresource
|
||||
// requests.
|
||||
@@ -152,18 +154,22 @@ net::FirstPartySetsContextType FirstPartySets::ComputeContextType(
|
||||
: net::FirstPartySetsContextType::kTopResourceMatchMixed;
|
||||
}
|
||||
|
||||
-const net::SchemefulSite* FirstPartySets::FindOwner(
|
||||
+const absl::optional<net::SchemefulSite> FirstPartySets::FindOwner(
|
||||
const net::SchemefulSite& site,
|
||||
bool infer_singleton_sets) const {
|
||||
- const auto it = sets_.find(site);
|
||||
- if (it == sets_.end())
|
||||
- return infer_singleton_sets ? &site : nullptr;
|
||||
- return &it->second;
|
||||
+ net::SchemefulSite normalized_site = site;
|
||||
+ normalized_site.ConvertWebSocketToHttp();
|
||||
+ const auto it = sets_.find(normalized_site);
|
||||
+ if (it != sets_.end())
|
||||
+ return it->second;
|
||||
+ if (infer_singleton_sets)
|
||||
+ return normalized_site;
|
||||
+ return absl::nullopt;
|
||||
}
|
||||
|
||||
bool FirstPartySets::IsInNontrivialFirstPartySet(
|
||||
const net::SchemefulSite& site) const {
|
||||
- return base::Contains(sets_, site);
|
||||
+ return FindOwner(site, /*infer_singleton_sets=*/false).has_value();
|
||||
}
|
||||
|
||||
base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>>
|
||||
@@ -244,7 +250,8 @@ base::flat_set<net::SchemefulSite> FirstPartySets::ComputeSetsDiff(
|
||||
for (const auto& old_pair : old_sets) {
|
||||
const net::SchemefulSite& old_member = old_pair.first;
|
||||
const net::SchemefulSite& old_owner = old_pair.second;
|
||||
- const net::SchemefulSite* current_owner = FindOwner(old_member, false);
|
||||
+ const absl::optional<net::SchemefulSite> current_owner =
|
||||
+ FindOwner(old_member, false);
|
||||
// Look for the removed sites and the ones have owner changed.
|
||||
if (!current_owner || *current_owner != old_owner) {
|
||||
result.emplace(old_member);
|
||||
diff --git a/services/network/first_party_sets/first_party_sets.h b/services/network/first_party_sets/first_party_sets.h
|
||||
index 8158b555856526170051cba72a08312a5528de51..fc87e5155667befc5a94bbe539ca71dc47d5f7d1 100644
|
||||
--- a/services/network/first_party_sets/first_party_sets.h
|
||||
+++ b/services/network/first_party_sets/first_party_sets.h
|
||||
@@ -97,11 +97,12 @@ class FirstPartySets {
|
||||
base::OnceCallback<void(const std::string&)> callback);
|
||||
|
||||
private:
|
||||
- // Returns a pointer to `site`'s owner (optionally inferring a singleton set
|
||||
- // if necessary), or `nullptr` if `site` has no owner. Must not return
|
||||
- // `nullptr` if `infer_singleton_sets` is true.
|
||||
- const net::SchemefulSite* FindOwner(const net::SchemefulSite& site,
|
||||
- bool infer_singleton_sets) const;
|
||||
+ // Returns `site`'s owner (optionally inferring a singleton set if necessary),
|
||||
+ // or `nullopt` if `site` has no owner. Must not return `nullopt` if
|
||||
+ // `infer_singleton_sets` is true.
|
||||
+ const absl::optional<net::SchemefulSite> FindOwner(
|
||||
+ const net::SchemefulSite& site,
|
||||
+ bool infer_singleton_sets) const;
|
||||
|
||||
// We must ensure there's no intersection between the manually-specified set
|
||||
// and the sets that came from Component Updater. (When reconciling the
|
||||
diff --git a/services/network/first_party_sets/first_party_sets_unittest.cc b/services/network/first_party_sets/first_party_sets_unittest.cc
|
||||
index 2055619f4c999cbfd5a5ee4780e2eb5c1dad5816..52eb8e8a3d87172353c64bba972311db2889c693 100644
|
||||
--- a/services/network/first_party_sets/first_party_sets_unittest.cc
|
||||
+++ b/services/network/first_party_sets/first_party_sets_unittest.cc
|
||||
@@ -1167,6 +1167,8 @@ TEST_F(FirstPartySetsTest, ComputeContext) {
|
||||
net::SchemefulSite nonmember1(GURL("https://nonmember1.test"));
|
||||
net::SchemefulSite member(GURL("https://member1.test"));
|
||||
net::SchemefulSite owner(GURL("https://example.test"));
|
||||
+ net::SchemefulSite wss_member(GURL("wss://member1.test"));
|
||||
+ net::SchemefulSite wss_nonmember(GURL("wss://nonmember.test"));
|
||||
|
||||
// Works as usual for sites that are in First-Party sets.
|
||||
EXPECT_THAT(sets().ComputeContext(member, &member, {member}),
|
||||
@@ -1180,10 +1182,17 @@ TEST_F(FirstPartySetsTest, ComputeContext) {
|
||||
EXPECT_THAT(sets().ComputeContext(member, &member, {member, owner}),
|
||||
net::SamePartyContext(SamePartyContextType::kSameParty));
|
||||
|
||||
+ // Works if the site is provided with WSS scheme instead of HTTPS.
|
||||
+ EXPECT_THAT(sets().ComputeContext(wss_member, &member, {member, owner}),
|
||||
+ net::SamePartyContext(SamePartyContextType::kSameParty));
|
||||
+
|
||||
EXPECT_THAT(sets().ComputeContext(nonmember, &member, {member}),
|
||||
net::SamePartyContext(SamePartyContextType::kCrossParty));
|
||||
EXPECT_THAT(sets().ComputeContext(member, &nonmember, {member}),
|
||||
net::SamePartyContext(SamePartyContextType::kCrossParty));
|
||||
+ EXPECT_THAT(
|
||||
+ sets().ComputeContext(wss_nonmember, &wss_member, {member, owner}),
|
||||
+ net::SamePartyContext(SamePartyContextType::kCrossParty));
|
||||
|
||||
// Top&resource differs from Ancestors.
|
||||
EXPECT_THAT(sets().ComputeContext(member, &member, {nonmember}),
|
||||
@@ -1225,6 +1234,12 @@ TEST_F(FirstPartySetsTest, IsInNontrivialFirstPartySet) {
|
||||
EXPECT_TRUE(sets().IsInNontrivialFirstPartySet(
|
||||
net::SchemefulSite(GURL("https://member1.test"))));
|
||||
|
||||
+ EXPECT_TRUE(sets().IsInNontrivialFirstPartySet(
|
||||
+ net::SchemefulSite(GURL("wss://member1.test"))));
|
||||
+
|
||||
+ EXPECT_FALSE(sets().IsInNontrivialFirstPartySet(
|
||||
+ net::SchemefulSite(GURL("ws://member1.test"))));
|
||||
+
|
||||
EXPECT_FALSE(sets().IsInNontrivialFirstPartySet(
|
||||
net::SchemefulSite(GURL("https://nonmember.test"))));
|
||||
}
|
||||
626
patches/chromium/cherry-pick-ec42dfd3545f.patch
Normal file
626
patches/chromium/cherry-pick-ec42dfd3545f.patch
Normal file
@@ -0,0 +1,626 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shuran Huang <shuuran@chromium.org>
|
||||
Date: Fri, 24 Sep 2021 00:47:47 +0000
|
||||
Subject: Add functions to pass in persisted FPSs and compute diffs.
|
||||
|
||||
Pass the persisted FPSs and a callback that takes a FPSs into Network
|
||||
Service. The persisted FPSs is parsed and compared to the current FPSs
|
||||
in the FirstPartySets class, then call the callback with the current
|
||||
FPSs. The function that passes in the persisted FPSs and the callback
|
||||
has not been called anywhere yet.
|
||||
|
||||
Bug: 1219656
|
||||
Change-Id: I08c531aa08d3aeeb772c1eb9a3a453a07b0349d3
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3103693
|
||||
Commit-Queue: Shuran Huang <shuuran@chromium.org>
|
||||
Reviewed-by: Will Harris <wfh@chromium.org>
|
||||
Reviewed-by: Matt Menke <mmenke@chromium.org>
|
||||
Reviewed-by: Chris Fredrickson <cfredric@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#924570}
|
||||
|
||||
diff --git a/services/network/first_party_sets/first_party_sets.cc b/services/network/first_party_sets/first_party_sets.cc
|
||||
index f7e732e88d6e6ebc5daed9169d5eee336a9de8c1..1650c28d8b6c61b30531e1e2ef3e2869d8450360 100644
|
||||
--- a/services/network/first_party_sets/first_party_sets.cc
|
||||
+++ b/services/network/first_party_sets/first_party_sets.cc
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/ranges/algorithm.h"
|
||||
#include "base/strings/string_split.h"
|
||||
+#include "base/task/post_task.h"
|
||||
#include "net/base/schemeful_site.h"
|
||||
#include "net/cookies/cookie_constants.h"
|
||||
#include "net/cookies/same_party_context.h"
|
||||
@@ -72,12 +73,16 @@ void FirstPartySets::SetManuallySpecifiedSet(const std::string& flag_value) {
|
||||
flag_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY));
|
||||
|
||||
ApplyManuallySpecifiedSet();
|
||||
+ manual_sets_ready_ = true;
|
||||
+ ClearSiteDataOnChangedSetsIfReady();
|
||||
}
|
||||
|
||||
base::flat_map<net::SchemefulSite, net::SchemefulSite>*
|
||||
FirstPartySets::ParseAndSet(base::StringPiece raw_sets) {
|
||||
sets_ = FirstPartySetParser::ParseSetsFromComponentUpdater(raw_sets);
|
||||
ApplyManuallySpecifiedSet();
|
||||
+ component_sets_ready_ = true;
|
||||
+ ClearSiteDataOnChangedSetsIfReady();
|
||||
return &sets_;
|
||||
}
|
||||
|
||||
@@ -218,4 +223,48 @@ void FirstPartySets::ApplyManuallySpecifiedSet() {
|
||||
sets_.emplace(manual_owner, manual_owner);
|
||||
}
|
||||
|
||||
+void FirstPartySets::SetPersistedSets(base::StringPiece raw_sets) {
|
||||
+ raw_persisted_sets_ = std::string(raw_sets);
|
||||
+ persisted_sets_ready_ = true;
|
||||
+ ClearSiteDataOnChangedSetsIfReady();
|
||||
+}
|
||||
+
|
||||
+void FirstPartySets::SetOnSiteDataCleared(
|
||||
+ base::OnceCallback<void(const std::string&)> callback) {
|
||||
+ on_site_data_cleared_ = std::move(callback);
|
||||
+ ClearSiteDataOnChangedSetsIfReady();
|
||||
+}
|
||||
+
|
||||
+base::flat_set<net::SchemefulSite> FirstPartySets::ComputeSetsDiff(
|
||||
+ const base::flat_map<net::SchemefulSite, net::SchemefulSite>& old_sets) {
|
||||
+ if (old_sets.empty())
|
||||
+ return {};
|
||||
+
|
||||
+ base::flat_set<net::SchemefulSite> result;
|
||||
+ for (const auto& old_pair : old_sets) {
|
||||
+ const net::SchemefulSite& old_member = old_pair.first;
|
||||
+ const net::SchemefulSite& old_owner = old_pair.second;
|
||||
+ const net::SchemefulSite* current_owner = FindOwner(old_member, false);
|
||||
+ // Look for the removed sites and the ones have owner changed.
|
||||
+ if (!current_owner || *current_owner != old_owner) {
|
||||
+ result.emplace(old_member);
|
||||
+ }
|
||||
+ }
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+void FirstPartySets::ClearSiteDataOnChangedSetsIfReady() {
|
||||
+ if (!persisted_sets_ready_ || !component_sets_ready_ || !manual_sets_ready_ ||
|
||||
+ on_site_data_cleared_.is_null())
|
||||
+ return;
|
||||
+
|
||||
+ base::flat_set<net::SchemefulSite> diff = ComputeSetsDiff(
|
||||
+ FirstPartySetParser::DeserializeFirstPartySets(raw_persisted_sets_));
|
||||
+
|
||||
+ // TODO(shuuran@chromium.org): Implement site state clearing.
|
||||
+
|
||||
+ std::move(on_site_data_cleared_)
|
||||
+ .Run(FirstPartySetParser::SerializeFirstPartySets(sets_));
|
||||
+}
|
||||
+
|
||||
} // namespace network
|
||||
diff --git a/services/network/first_party_sets/first_party_sets.h b/services/network/first_party_sets/first_party_sets.h
|
||||
index 81e0e1080d965947a2ebc1635638c25ad75a1bf7..8158b555856526170051cba72a08312a5528de51 100644
|
||||
--- a/services/network/first_party_sets/first_party_sets.h
|
||||
+++ b/services/network/first_party_sets/first_party_sets.h
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
+#include "base/callback.h"
|
||||
#include "base/containers/flat_map.h"
|
||||
#include "base/containers/flat_set.h"
|
||||
#include "net/base/schemeful_site.h"
|
||||
@@ -87,6 +88,14 @@ class FirstPartySets {
|
||||
// the members of the set includes the owner.
|
||||
base::flat_map<net::SchemefulSite, std::set<net::SchemefulSite>> Sets() const;
|
||||
|
||||
+ // Sets the `raw_persisted_sets_`, which is a JSON-encoded
|
||||
+ // string representation of a map of site -> site.
|
||||
+ void SetPersistedSets(base::StringPiece persisted_sets);
|
||||
+ // Sets the `on_site_data_cleared_` callback, which takes input of a
|
||||
+ // JSON-encoded string representation of a map of site -> site.
|
||||
+ void SetOnSiteDataCleared(
|
||||
+ base::OnceCallback<void(const std::string&)> callback);
|
||||
+
|
||||
private:
|
||||
// Returns a pointer to `site`'s owner (optionally inferring a singleton set
|
||||
// if necessary), or `nullptr` if `site` has no owner. Must not return
|
||||
@@ -101,6 +110,19 @@ class FirstPartySets {
|
||||
// `manually_specified_set_`.
|
||||
void ApplyManuallySpecifiedSet();
|
||||
|
||||
+ // Compares the map `old_sets` to `sets_` and returns the set of sites that:
|
||||
+ // 1) were in `old_sets` but are no longer in `sets_`, i.e. leave the FPSs;
|
||||
+ // or, 2) mapped to a different owner site.
|
||||
+ base::flat_set<net::SchemefulSite> ComputeSetsDiff(
|
||||
+ const base::flat_map<net::SchemefulSite, net::SchemefulSite>& old_sets);
|
||||
+
|
||||
+ // Checks the required inputs have been received, and if so, computes the diff
|
||||
+ // between the `sets_` and the parsed `raw_persisted_sets_`, and clears the
|
||||
+ // site data of the set of sites based on the diff.
|
||||
+ //
|
||||
+ // TODO(shuuran@chromium.org): Implement the code to clear site state.
|
||||
+ void ClearSiteDataOnChangedSetsIfReady();
|
||||
+
|
||||
// Represents the mapping of site -> site, where keys are members of sets, and
|
||||
// values are owners of the sets. Owners are explicitly represented as members
|
||||
// of the set.
|
||||
@@ -108,6 +130,22 @@ class FirstPartySets {
|
||||
absl::optional<
|
||||
std::pair<net::SchemefulSite, base::flat_set<net::SchemefulSite>>>
|
||||
manually_specified_set_;
|
||||
+
|
||||
+ std::string raw_persisted_sets_;
|
||||
+
|
||||
+ bool persisted_sets_ready_ = false;
|
||||
+ bool component_sets_ready_ = false;
|
||||
+ bool manual_sets_ready_ = false;
|
||||
+
|
||||
+ // The callback runs after the site state clearing is completed.
|
||||
+ base::OnceCallback<void(const std::string&)> on_site_data_cleared_;
|
||||
+
|
||||
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_SitesJoined);
|
||||
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_SitesLeft);
|
||||
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_OwnerChanged);
|
||||
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_OwnerLeft);
|
||||
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_OwnerMemberRotate);
|
||||
+ FRIEND_TEST_ALL_PREFIXES(FirstPartySets, ComputeSetsDiff_EmptySets);
|
||||
};
|
||||
|
||||
} // namespace network
|
||||
diff --git a/services/network/first_party_sets/first_party_sets_unittest.cc b/services/network/first_party_sets/first_party_sets_unittest.cc
|
||||
index b929315d9b857e0f86d1d726f7cefefb7ad8e54c..2055619f4c999cbfd5a5ee4780e2eb5c1dad5816 100644
|
||||
--- a/services/network/first_party_sets/first_party_sets_unittest.cc
|
||||
+++ b/services/network/first_party_sets/first_party_sets_unittest.cc
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <initializer_list>
|
||||
|
||||
#include "base/json/json_reader.h"
|
||||
+#include "base/test/bind.h"
|
||||
#include "net/base/schemeful_site.h"
|
||||
#include "net/cookies/cookie_constants.h"
|
||||
#include "net/cookies/same_party_context.h"
|
||||
@@ -204,6 +205,30 @@ TEST(FirstPartySets, SetsManuallySpecified_Invalid_RegisteredDomain_Member) {
|
||||
EXPECT_THAT(sets.ParseAndSet("[]"), Pointee(IsEmpty()));
|
||||
}
|
||||
|
||||
+TEST(FirstPartySets, SetsManuallySpecified_Valid_EmptyValue) {
|
||||
+ FirstPartySets sets;
|
||||
+ sets.SetManuallySpecifiedSet("");
|
||||
+
|
||||
+ // Set non-empty existing sets to distinguish the failure case from the no-op
|
||||
+ // case when processing the manually-specified sets.
|
||||
+ const std::string existing_sets = R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member.test"]
|
||||
+ }
|
||||
+ ]
|
||||
+ )";
|
||||
+ ASSERT_TRUE(base::JSONReader::Read(existing_sets));
|
||||
+
|
||||
+ EXPECT_THAT(sets.ParseAndSet(existing_sets),
|
||||
+ Pointee(UnorderedElementsAre(
|
||||
+ Pair(SerializesTo("https://example.test"),
|
||||
+ SerializesTo("https://example.test")),
|
||||
+ Pair(SerializesTo("https://member.test"),
|
||||
+ SerializesTo("https://example.test")))));
|
||||
+}
|
||||
+
|
||||
TEST(FirstPartySets, SetsManuallySpecified_Valid_SingleMember) {
|
||||
FirstPartySets sets;
|
||||
sets.SetManuallySpecifiedSet("https://example.test,https://member.test");
|
||||
@@ -469,6 +494,311 @@ TEST(FirstPartySets, SetsManuallySpecified_PrunesInducedSingletons) {
|
||||
SerializesTo("https://example.test")))));
|
||||
}
|
||||
|
||||
+TEST(FirstPartySets, ComputeSetsDiff_SitesJoined) {
|
||||
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
|
||||
+ {net::SchemefulSite(GURL("https://example.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://member1.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://member3.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))}};
|
||||
+
|
||||
+ // Consistency check the reviewer-friendly JSON format matches the input.
|
||||
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member1.test", "https://member3.test"]
|
||||
+ }
|
||||
+ ]
|
||||
+ )"),
|
||||
+ Pointee(old_sets));
|
||||
+
|
||||
+ FirstPartySets sets;
|
||||
+ sets.ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member1.test", "https://member3.test"]
|
||||
+ },
|
||||
+ {
|
||||
+ "owner": "https://foo.test",
|
||||
+ "members": ["https://member2.test"]
|
||||
+ }
|
||||
+ ]
|
||||
+ )");
|
||||
+ // "https://foo.test" and "https://member2.test" joined FPSs. We don't clear
|
||||
+ // site data upon joining, so the computed diff should be empty set.
|
||||
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets), IsEmpty());
|
||||
+}
|
||||
+
|
||||
+TEST(FirstPartySets, ComputeSetsDiff_SitesLeft) {
|
||||
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
|
||||
+ {net::SchemefulSite(GURL("https://example.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://member1.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://member3.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://foo.test")),
|
||||
+ net::SchemefulSite(GURL("https://foo.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://member2.test")),
|
||||
+ net::SchemefulSite(GURL("https://foo.test"))}};
|
||||
+
|
||||
+ // Consistency check the reviewer-friendly JSON format matches the input.
|
||||
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member1.test", "https://member3.test"]
|
||||
+ },
|
||||
+ {
|
||||
+ "owner": "https://foo.test",
|
||||
+ "members": ["https://member2.test"]
|
||||
+ },
|
||||
+ ]
|
||||
+ )"),
|
||||
+ Pointee(old_sets));
|
||||
+
|
||||
+ FirstPartySets sets;
|
||||
+ sets.ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member1.test"]
|
||||
+ },
|
||||
+ ]
|
||||
+ )");
|
||||
+ // Expected diff: "https://foo.test", "https://member2.test" and
|
||||
+ // "https://member3.test" left FPSs.
|
||||
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets),
|
||||
+ UnorderedElementsAre(SerializesTo("https://foo.test"),
|
||||
+ SerializesTo("https://member2.test"),
|
||||
+ SerializesTo("https://member3.test")));
|
||||
+}
|
||||
+
|
||||
+TEST(FirstPartySets, ComputeSetsDiff_OwnerChanged) {
|
||||
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
|
||||
+ {net::SchemefulSite(GURL("https://example.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://member1.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://foo.test")),
|
||||
+ net::SchemefulSite(GURL("https://foo.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://member2.test")),
|
||||
+ net::SchemefulSite(GURL("https://foo.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://member3.test")),
|
||||
+ net::SchemefulSite(GURL("https://foo.test"))}};
|
||||
+
|
||||
+ // Consistency check the reviewer-friendly JSON format matches the input.
|
||||
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member1.test"]
|
||||
+ },
|
||||
+ {
|
||||
+ "owner": "https://foo.test",
|
||||
+ "members": ["https://member2.test", "https://member3.test"]
|
||||
+ },
|
||||
+ ]
|
||||
+ )"),
|
||||
+ Pointee(old_sets));
|
||||
+
|
||||
+ FirstPartySets sets;
|
||||
+ sets.ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member1.test", "https://member3.test"]
|
||||
+ },
|
||||
+ {
|
||||
+ "owner": "https://foo.test",
|
||||
+ "members": ["https://member2.test"]
|
||||
+ }
|
||||
+ ]
|
||||
+ )");
|
||||
+ // Expected diff: "https://member3.test" changed owner.
|
||||
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets),
|
||||
+ UnorderedElementsAre(SerializesTo("https://member3.test")));
|
||||
+}
|
||||
+
|
||||
+TEST(FirstPartySets, ComputeSetsDiff_OwnerLeft) {
|
||||
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
|
||||
+ {net::SchemefulSite(GURL("https://example.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://foo.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://bar.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))}};
|
||||
+
|
||||
+ // Consistency check the reviewer-friendly JSON format matches the input.
|
||||
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://foo.test", "https://bar.test"]
|
||||
+ }
|
||||
+ ]
|
||||
+ )"),
|
||||
+ Pointee(old_sets));
|
||||
+
|
||||
+ FirstPartySets sets;
|
||||
+ sets.ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://foo.test",
|
||||
+ "members": ["https://bar.test"]
|
||||
+ }
|
||||
+ ]
|
||||
+ )");
|
||||
+ // Expected diff: "https://example.test" left FPSs, "https://foo.test" and
|
||||
+ // "https://bar.test" changed owner.
|
||||
+ // It would be valid to only have example.test in the diff, but our logic
|
||||
+ // isn't sophisticated enough yet to know that foo.test and bar.test don't
|
||||
+ // need to be included in the result.
|
||||
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets),
|
||||
+ UnorderedElementsAre(SerializesTo("https://example.test"),
|
||||
+ SerializesTo("https://foo.test"),
|
||||
+ SerializesTo("https://bar.test")));
|
||||
+}
|
||||
+
|
||||
+TEST(FirstPartySets, ComputeSetsDiff_OwnerMemberRotate) {
|
||||
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
|
||||
+ {net::SchemefulSite(GURL("https://example.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://foo.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))}};
|
||||
+
|
||||
+ // Consistency check the reviewer-friendly JSON format matches the input.
|
||||
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://foo.test"]
|
||||
+ }
|
||||
+ ]
|
||||
+ )"),
|
||||
+ Pointee(old_sets));
|
||||
+
|
||||
+ FirstPartySets sets;
|
||||
+ sets.ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://foo.test",
|
||||
+ "members": ["https://example.test"]
|
||||
+ }
|
||||
+ ]
|
||||
+ )");
|
||||
+ // Expected diff: "https://example.test" and "https://foo.test" changed owner.
|
||||
+ // It would be valid to not include example.test and foo.test in the result,
|
||||
+ // but our logic isn't sophisticated enough yet to know that.ß
|
||||
+ EXPECT_THAT(sets.ComputeSetsDiff(old_sets),
|
||||
+ UnorderedElementsAre(SerializesTo("https://example.test"),
|
||||
+ SerializesTo("https://foo.test")));
|
||||
+}
|
||||
+
|
||||
+TEST(FirstPartySets, ComputeSetsDiff_EmptySets) {
|
||||
+ // Empty old_sets.
|
||||
+ FirstPartySets sets;
|
||||
+ sets.ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member1.test"]
|
||||
+ },
|
||||
+ ]
|
||||
+ )");
|
||||
+ EXPECT_THAT(sets.ComputeSetsDiff({}), IsEmpty());
|
||||
+
|
||||
+ // Empty current sets.
|
||||
+ auto old_sets = base::flat_map<net::SchemefulSite, net::SchemefulSite>{
|
||||
+ {net::SchemefulSite(GURL("https://example.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))},
|
||||
+ {net::SchemefulSite(GURL("https://member1.test")),
|
||||
+ net::SchemefulSite(GURL("https://example.test"))}};
|
||||
+ // Consistency check the reviewer-friendly JSON format matches the input.
|
||||
+ ASSERT_THAT(FirstPartySets().ParseAndSet(R"(
|
||||
+ [
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member1.test"]
|
||||
+ }
|
||||
+ ]
|
||||
+ )"),
|
||||
+ Pointee(old_sets));
|
||||
+ EXPECT_THAT(FirstPartySets().ComputeSetsDiff(old_sets),
|
||||
+ UnorderedElementsAre(SerializesTo("https://example.test"),
|
||||
+ SerializesTo("https://member1.test")));
|
||||
+}
|
||||
+
|
||||
+TEST(FirstPartySets, ClearSiteDataOnChangedSetsIfReady_NotReady) {
|
||||
+ int callback_calls = 0;
|
||||
+ auto callback = base::BindLambdaForTesting(
|
||||
+ [&](const std::string& got) { callback_calls++; });
|
||||
+ // component sets not ready.
|
||||
+ {
|
||||
+ FirstPartySets sets;
|
||||
+ callback_calls = 0;
|
||||
+ sets.SetPersistedSets("{}");
|
||||
+ sets.SetManuallySpecifiedSet("");
|
||||
+ sets.SetOnSiteDataCleared(callback);
|
||||
+ EXPECT_EQ(callback_calls, 0);
|
||||
+ }
|
||||
+ // manual sets not ready.
|
||||
+ {
|
||||
+ FirstPartySets sets;
|
||||
+ callback_calls = 0;
|
||||
+ sets.ParseAndSet("[]");
|
||||
+ sets.SetPersistedSets("{}");
|
||||
+ sets.SetOnSiteDataCleared(callback);
|
||||
+ EXPECT_EQ(callback_calls, 0);
|
||||
+ }
|
||||
+ // persisted sets not ready.
|
||||
+ {
|
||||
+ FirstPartySets sets;
|
||||
+ callback_calls = 0;
|
||||
+ sets.ParseAndSet("[]");
|
||||
+ sets.SetManuallySpecifiedSet("");
|
||||
+ sets.SetOnSiteDataCleared(callback);
|
||||
+ EXPECT_EQ(callback_calls, 0);
|
||||
+ }
|
||||
+ // callback not set.
|
||||
+ {
|
||||
+ FirstPartySets sets;
|
||||
+ callback_calls = 0;
|
||||
+ sets.ParseAndSet("[]");
|
||||
+ sets.SetManuallySpecifiedSet("");
|
||||
+ sets.SetPersistedSets("{}");
|
||||
+ EXPECT_EQ(callback_calls, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// The callback only runs when `old_sets` is generated and `sets` has merged the
|
||||
+// inputs from Component Updater and command line flag.
|
||||
+TEST(FirstPartySets, ClearSiteDataOnChangedSetsIfReady_Ready) {
|
||||
+ FirstPartySets sets;
|
||||
+ int callback_calls = 0;
|
||||
+ sets.ParseAndSet(R"([
|
||||
+ {
|
||||
+ "owner": "https://example.test",
|
||||
+ "members": ["https://member1.test"]
|
||||
+ }
|
||||
+ ])");
|
||||
+ sets.SetManuallySpecifiedSet("https://example2.test,https://member2.test");
|
||||
+ sets.SetPersistedSets(
|
||||
+ R"({"https://example.test":"https://example.test",
|
||||
+ "https://member1.test":"https://example.test"})");
|
||||
+ sets.SetOnSiteDataCleared(base::BindLambdaForTesting([&](const std::string&
|
||||
+ got) {
|
||||
+ EXPECT_EQ(
|
||||
+ got,
|
||||
+ R"({"https://member1.test":"https://example.test","https://member2.test":"https://example2.test"})");
|
||||
+ callback_calls++;
|
||||
+ }));
|
||||
+ EXPECT_EQ(callback_calls, 1);
|
||||
+}
|
||||
+
|
||||
class FirstPartySetsTest : public ::testing::Test {
|
||||
public:
|
||||
FirstPartySetsTest() {
|
||||
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
|
||||
index 5d598ff6c626510bf1da00d35bc9ba4179bac93e..c850d6950aa7777cdc5c2056d4b80c9dd44d3af9 100644
|
||||
--- a/services/network/network_service.cc
|
||||
+++ b/services/network/network_service.cc
|
||||
@@ -343,8 +343,7 @@ void NetworkService::Initialize(mojom::NetworkServiceParamsPtr params,
|
||||
}
|
||||
|
||||
first_party_sets_ = std::make_unique<FirstPartySets>();
|
||||
- if (net::cookie_util::IsFirstPartySetsEnabled() &&
|
||||
- command_line->HasSwitch(switches::kUseFirstPartySet)) {
|
||||
+ if (net::cookie_util::IsFirstPartySetsEnabled()) {
|
||||
first_party_sets_->SetManuallySpecifiedSet(
|
||||
command_line->GetSwitchValueASCII(switches::kUseFirstPartySet));
|
||||
}
|
||||
@@ -785,6 +784,14 @@ void NetworkService::SetFirstPartySets(const std::string& raw_sets) {
|
||||
first_party_sets_->ParseAndSet(raw_sets);
|
||||
}
|
||||
|
||||
+void NetworkService::SetPersistedFirstPartySetsAndGetCurrentSets(
|
||||
+ const std::string& persisted_sets,
|
||||
+ mojom::NetworkService::SetPersistedFirstPartySetsAndGetCurrentSetsCallback
|
||||
+ callback) {
|
||||
+ first_party_sets_->SetPersistedSets(persisted_sets);
|
||||
+ first_party_sets_->SetOnSiteDataCleared(std::move(callback));
|
||||
+}
|
||||
+
|
||||
void NetworkService::SetExplicitlyAllowedPorts(
|
||||
const std::vector<uint16_t>& ports) {
|
||||
net::SetExplicitlyAllowedPorts(ports);
|
||||
diff --git a/services/network/network_service.h b/services/network/network_service.h
|
||||
index 1da4505fc9fe478e00353cd55e615878ea875aa0..963e22f6d5e957684dc56dd6e3ae31fa430a355e 100644
|
||||
--- a/services/network/network_service.h
|
||||
+++ b/services/network/network_service.h
|
||||
@@ -204,6 +204,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
|
||||
void BindTestInterface(
|
||||
mojo::PendingReceiver<mojom::NetworkServiceTest> receiver) override;
|
||||
void SetFirstPartySets(const std::string& raw_sets) override;
|
||||
+ void SetPersistedFirstPartySetsAndGetCurrentSets(
|
||||
+ const std::string& persisted_sets,
|
||||
+ mojom::NetworkService::SetPersistedFirstPartySetsAndGetCurrentSetsCallback
|
||||
+ callback) override;
|
||||
void SetExplicitlyAllowedPorts(const std::vector<uint16_t>& ports) override;
|
||||
|
||||
// Returns an HttpAuthHandlerFactory for the given NetworkContext.
|
||||
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc
|
||||
index bd8ed7abe5870d23e3b0430f29f0448cf425fabc..dffa318ab85d6851c54d0f3c38ab6bb72f274f40 100644
|
||||
--- a/services/network/network_service_unittest.cc
|
||||
+++ b/services/network/network_service_unittest.cc
|
||||
@@ -925,6 +925,7 @@ class NetworkServiceTestWithService : public testing::Test {
|
||||
void SetUp() override {
|
||||
test_server_.AddDefaultHandlers(base::FilePath(kServicesTestData));
|
||||
ASSERT_TRUE(test_server_.Start());
|
||||
+ scoped_features_.InitAndEnableFeature(net::features::kFirstPartySets);
|
||||
service_ = NetworkService::CreateForTesting();
|
||||
service_->Bind(network_service_.BindNewPipeAndPassReceiver());
|
||||
}
|
||||
@@ -989,7 +990,7 @@ class NetworkServiceTestWithService : public testing::Test {
|
||||
mojo::Remote<mojom::NetworkContext> network_context_;
|
||||
mojo::Remote<mojom::URLLoader> loader_;
|
||||
|
||||
- DISALLOW_COPY_AND_ASSIGN(NetworkServiceTestWithService);
|
||||
+ base::test::ScopedFeatureList scoped_features_;
|
||||
};
|
||||
|
||||
// Verifies that loading a URL through the network service's mojo interface
|
||||
@@ -1169,6 +1170,18 @@ TEST_F(NetworkServiceTestWithService, GetNetworkList) {
|
||||
run_loop.Run();
|
||||
}
|
||||
|
||||
+TEST_F(NetworkServiceTestWithService,
|
||||
+ SetPersistedFirstPartySetsAndGetCurrentSets) {
|
||||
+ base::RunLoop run_loop;
|
||||
+ network_service_->SetPersistedFirstPartySetsAndGetCurrentSets(
|
||||
+ "", base::BindLambdaForTesting([&](const std::string& got) {
|
||||
+ EXPECT_EQ(got, "{}");
|
||||
+ run_loop.Quit();
|
||||
+ }));
|
||||
+ network_service_->SetFirstPartySets("");
|
||||
+ run_loop.Run();
|
||||
+}
|
||||
+
|
||||
class TestNetworkChangeManagerClient
|
||||
: public mojom::NetworkChangeManagerClient {
|
||||
public:
|
||||
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
|
||||
index fe5450b20b3c4a8490e853dd236bf6baefa90b81..59fbbde6ffc30d51304a72f402eee7c664ea111b 100644
|
||||
--- a/services/network/public/mojom/network_service.mojom
|
||||
+++ b/services/network/public/mojom/network_service.mojom
|
||||
@@ -373,6 +373,14 @@ interface NetworkService {
|
||||
// cleared (except for the manually-specified set, if one exists).
|
||||
SetFirstPartySets(string raw_sets);
|
||||
|
||||
+ // Sets the First-Party Sets data that was persisted to compare it with the
|
||||
+ // current First-Party Sets data set by `SetFirstPartySets()`, which is
|
||||
+ // considered more up-to-date, and returns a serialized version of the current
|
||||
+ // one. Both input and output are in format of the JSON-encoded string
|
||||
+ // representation of a map of site -> site.
|
||||
+ SetPersistedFirstPartySetsAndGetCurrentSets(string persisted_sets)
|
||||
+ => (string up_to_date_sets);
|
||||
+
|
||||
// Sets the list of ports which will be permitted even if they normally would
|
||||
// be restricted.
|
||||
SetExplicitlyAllowedPorts(array<uint16> ports);
|
||||
@@ -0,0 +1,48 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <samuel.r.attard@gmail.com>
|
||||
Date: Fri, 6 Aug 2021 03:36:57 -0700
|
||||
Subject: chore: do not use chrome.windows in cryptotoken webrequestsender
|
||||
|
||||
Electron does not support chrome.windows which this method depends on. It also does not need to, the method's goal is to determine if the webContents that triggered the cryptotoken request is still "active". In Chrome this means active tab in the tab strip === this tab + the window owning that tab strip is focused.
|
||||
|
||||
In Electron that can be simplified to webContents.isFocused() which maps to "is the webContents view focused and is the owning window the key window". We map tab.active to that IsFocused() value and we can remove the chrome.windows logic here.
|
||||
|
||||
This can't be upstreamed but the patch is minimal.
|
||||
|
||||
diff --git a/chrome/browser/resources/cryptotoken/webrequestsender.js b/chrome/browser/resources/cryptotoken/webrequestsender.js
|
||||
index 734abbbf3132d245c2c39bbe9b7780acbea196b0..adff416286eaa10a099be83aaf07e56ec323fe3d 100644
|
||||
--- a/chrome/browser/resources/cryptotoken/webrequestsender.js
|
||||
+++ b/chrome/browser/resources/cryptotoken/webrequestsender.js
|
||||
@@ -134,10 +134,11 @@ function tabInForeground(tabId) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
- if (!chrome.windows || !chrome.windows.get) {
|
||||
- reject();
|
||||
- return;
|
||||
- }
|
||||
+ // Electron does not support chrome.windows
|
||||
+ // if (!chrome.windows || !chrome.windows.get) {
|
||||
+ // reject();
|
||||
+ // return;
|
||||
+ // }
|
||||
chrome.tabs.get(tabId, function(tab) {
|
||||
if (chrome.runtime.lastError) {
|
||||
resolve(false);
|
||||
@@ -147,9 +148,13 @@ function tabInForeground(tabId) {
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
- chrome.windows.get(tab.windowId, function(aWindow) {
|
||||
- resolve(aWindow && aWindow.focused);
|
||||
- });
|
||||
+ // tab.active in Electron maps to the "focused" state of the view
|
||||
+ // which is only true when both the webContents and the window are
|
||||
+ // focused.
|
||||
+ resolve(true);
|
||||
+ // chrome.windows.get(tab.windowId, function(aWindow) {
|
||||
+ // resolve(aWindow && aWindow.focused);
|
||||
+ // });
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -35,10 +35,10 @@ index 5b4d70991e19edcdfee731c56251932bf43e535f..fe1977c5e6ce0f5b30e8be529b9efa51
|
||||
|
||||
#endif // CHROME_BROWSER_ANDROID_DOCUMENT_DOCUMENT_WEB_CONTENTS_DELEGATE_H_
|
||||
diff --git a/chrome/browser/media/offscreen_tab.cc b/chrome/browser/media/offscreen_tab.cc
|
||||
index d6295d809381f4f4a86a9948762079232ba6c93c..ad429250984cf367e1194bda67bc56a886f650ae 100644
|
||||
index c0823105ecc86ce2e60ede44be29a14889dad887..bb0f2672c6e565657500e617b4eb416c0575dac7 100644
|
||||
--- a/chrome/browser/media/offscreen_tab.cc
|
||||
+++ b/chrome/browser/media/offscreen_tab.cc
|
||||
@@ -283,8 +283,7 @@ bool OffscreenTab::IsWebContentsCreationOverridden(
|
||||
@@ -284,8 +284,7 @@ bool OffscreenTab::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
@@ -49,10 +49,10 @@ index d6295d809381f4f4a86a9948762079232ba6c93c..ad429250984cf367e1194bda67bc56a8
|
||||
// uses this to spawn new windows/tabs, which is also not allowed for
|
||||
// offscreen tabs.
|
||||
diff --git a/chrome/browser/media/offscreen_tab.h b/chrome/browser/media/offscreen_tab.h
|
||||
index 3fd38bcb861174f99369d0e53b9946c632baf21a..de1a4df623538cc2857f8bb85b05e17d411c45a0 100644
|
||||
index c80128b816cc77b95af215384fdc36b2150f95ea..3fe773e671d1c087eaf1303ca60883597c0c3907 100644
|
||||
--- a/chrome/browser/media/offscreen_tab.h
|
||||
+++ b/chrome/browser/media/offscreen_tab.h
|
||||
@@ -103,8 +103,7 @@ class OffscreenTab final : public ProfileObserver,
|
||||
@@ -107,8 +107,7 @@ class OffscreenTab final : public ProfileObserver,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
@@ -94,10 +94,10 @@ index 07014765f33bdddebcc5bc32a2713d6523faf394..f866f69f9c810d89f1a0e9e4952293f6
|
||||
content::WebContents* source,
|
||||
const content::OpenURLParams& params) override;
|
||||
diff --git a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
|
||||
index ef84e04d628fb5cdbaf8fbbf84af3bf23e00c522..f1ee0bee5bfd08227a29498f8410d5d3582e02c3 100644
|
||||
index ba376cca99e6b8b367c6a4cfc9925b940728b9fc..f1b831507d628d35cc65f697ffc832568fc28193 100644
|
||||
--- a/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
|
||||
+++ b/chrome/browser/ui/ash/keyboard/chrome_keyboard_web_contents.cc
|
||||
@@ -66,8 +66,7 @@ class ChromeKeyboardContentsDelegate : public content::WebContentsDelegate,
|
||||
@@ -72,8 +72,7 @@ class ChromeKeyboardContentsDelegate : public content::WebContentsDelegate,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
@@ -108,10 +108,10 @@ index ef84e04d628fb5cdbaf8fbbf84af3bf23e00c522..f1ee0bee5bfd08227a29498f8410d5d3
|
||||
}
|
||||
|
||||
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
|
||||
index 7e29403699d56081424643bd143d0f255c8e8e73..ad9f02f84ce5954d3a2ca9b7c26eab7f2c90c162 100644
|
||||
index c8d3c04475fe3ee60ec4671ee47c18aa78840dd1..e5d95132b4f20f17f328e41cf6d0cf839787222a 100644
|
||||
--- a/chrome/browser/ui/browser.cc
|
||||
+++ b/chrome/browser/ui/browser.cc
|
||||
@@ -1787,12 +1787,11 @@ bool Browser::IsWebContentsCreationOverridden(
|
||||
@@ -1790,12 +1790,11 @@ bool Browser::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
@@ -155,10 +155,10 @@ index ff97ac6e97c688d677053a5f01546a4c2d91ff1d..1da6a9c32b883a17975e61d603639182
|
||||
// uses this to spawn new windows/tabs, which is also not allowed for
|
||||
// local presentations.
|
||||
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_controller.h b/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
|
||||
index 058ec72442d59989c4d6df4a7c791ecfeff0ef99..f7c8c2139382cb2e290c561624291afe647383cf 100644
|
||||
index 45cd02ecf7b7acb107f95656b3fa07a5fca2ea95..b06ca2dbdd0c21554802ab3b99576b381d0e4ddb 100644
|
||||
--- a/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
|
||||
+++ b/chrome/browser/ui/media_router/presentation_receiver_window_controller.h
|
||||
@@ -99,8 +99,7 @@ class PresentationReceiverWindowController final
|
||||
@@ -104,8 +104,7 @@ class PresentationReceiverWindowController final
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
@@ -232,10 +232,10 @@ index c5c5a7b63b5b3b62a9517cbef3ae23ce57a3c89c..4f1b7e88d6d2ae89a60311c8aeb1fcee
|
||||
void AddNewContents(content::WebContents* source,
|
||||
std::unique_ptr<content::WebContents> new_contents,
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index a5aca663101e206156528adaf299d4d97a9ee59e..50bee6111f723932ad2164f42c71ad95c2a12771 100644
|
||||
index ad1b4abe0390215e007ad2db8d972661470e94ed..d3593a6f3e9f6cba5823169d36fd93a6f97608ae 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3675,8 +3675,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
@@ -3682,8 +3682,7 @@ FrameTree* WebContentsImpl::CreateNewWindow(
|
||||
|
||||
if (delegate_ && delegate_->IsWebContentsCreationOverridden(
|
||||
source_site_instance, params.window_container_type,
|
||||
@@ -302,10 +302,10 @@ index 9b293d0df6c634bf44a69d607c4eee839a74b4a1..7e5b9cbdcc232c5e20eae0130d800f50
|
||||
content::RenderFrameHost* opener,
|
||||
content::SiteInstance* source_site_instance,
|
||||
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
|
||||
index 2dc016e4be765413b4cef0f5471dcf9240f73ff5..224cd2be71670ac565d02ecb2838123154255dc6 100644
|
||||
index b794ee4204fb8eaf90084e762f80988af13609b4..ac4e00f2ef1d2a722851d88531c28e65dea0341e 100644
|
||||
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
|
||||
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
|
||||
@@ -386,8 +386,7 @@ bool MimeHandlerViewGuest::IsWebContentsCreationOverridden(
|
||||
@@ -385,8 +385,7 @@ bool MimeHandlerViewGuest::IsWebContentsCreationOverridden(
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
@@ -316,10 +316,10 @@ index 2dc016e4be765413b4cef0f5471dcf9240f73ff5..224cd2be71670ac565d02ecb28381231
|
||||
}
|
||||
|
||||
diff --git a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
|
||||
index bb90319f768ed2f3a3e530d64bf622de585ce163..d84de1d218267887f6b8624f913438ebc4aa7a79 100644
|
||||
index 647a9bdf39c60f61cf3c9520bc7e57e206678cd0..59860dc143467168e2ce596f26c84ed8a26be6ed 100644
|
||||
--- a/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
|
||||
+++ b/extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
|
||||
@@ -158,8 +158,7 @@ class MimeHandlerViewGuest
|
||||
@@ -167,8 +167,7 @@ class MimeHandlerViewGuest
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
@@ -344,10 +344,10 @@ index 2863abb239a77b96e638c83f47ae7219cf0ccec8..5675ad386efa99383067eb404b385cf2
|
||||
// can catch bad client behavior while not interfering with normal operation.
|
||||
constexpr size_t kMaxPendingWebContentsCount = 10;
|
||||
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h
|
||||
index e2736c5329d9516fdd417df4dff8039f991e800e..11081373e0d70e7ec366c6917c21db61c4e18cca 100644
|
||||
index 3e65c4e8faf63ab1d42e3f57457a071e322383dc..5f4d859f8f3ebb58336485a0a39837eec2c46294 100644
|
||||
--- a/fuchsia/engine/browser/frame_impl.h
|
||||
+++ b/fuchsia/engine/browser/frame_impl.h
|
||||
@@ -245,8 +245,7 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
@@ -246,8 +246,7 @@ class FrameImpl : public fuchsia::web::Frame,
|
||||
content::SiteInstance* source_site_instance,
|
||||
content::mojom::WindowContainerType window_container_type,
|
||||
const GURL& opener_url,
|
||||
@@ -358,7 +358,7 @@ index e2736c5329d9516fdd417df4dff8039f991e800e..11081373e0d70e7ec366c6917c21db61
|
||||
int opener_render_process_id,
|
||||
int opener_render_frame_id,
|
||||
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
|
||||
index dd1f6129173a0e19023f4ec9b66c44486b080456..d10468c06f84b59387af0a8fd5bc1c06108865eb 100644
|
||||
index 09bb4b3ef68aeb6dc2fa83ab574c46bebc68dcd1..e104fcba8c5c2e5530ae9a231c21fb1cd69ee303 100644
|
||||
--- a/headless/lib/browser/headless_web_contents_impl.cc
|
||||
+++ b/headless/lib/browser/headless_web_contents_impl.cc
|
||||
@@ -192,8 +192,7 @@ class HeadlessWebContentsImpl::Delegate : public content::WebContentsDelegate {
|
||||
|
||||
@@ -7,10 +7,10 @@ spellchecker uses a few IDS_ resources. We need to load these from
|
||||
Electrons grit header instead of Chromes
|
||||
|
||||
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
|
||||
index 913813f344ca1c6301710ed983c80a358fa68443..135ad9b24745f6d016806f3c95993efe65b370f3 100644
|
||||
index 7f050d074a057b9226444432625e3df856c5d1d8..27f4f83da31dbd3a1e754279e760dddf00224e1b 100644
|
||||
--- a/chrome/browser/BUILD.gn
|
||||
+++ b/chrome/browser/BUILD.gn
|
||||
@@ -6608,6 +6608,7 @@ static_library("browser") {
|
||||
@@ -6736,6 +6736,7 @@ static_library("browser") {
|
||||
deps += [
|
||||
"//components/spellcheck/browser",
|
||||
"//components/spellcheck/common",
|
||||
@@ -32,7 +32,7 @@ index 2b7aa1add57dccbcbf8202cead5b7d2d5a174270..2ba03fc045f2e4bb12f173aacb6581cc
|
||||
#include "components/pref_registry/pref_registry_syncable.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
diff --git a/components/language/core/browser/BUILD.gn b/components/language/core/browser/BUILD.gn
|
||||
index 1ece01a38683e81fdf07ec475c2bf1bf19fab891..668789ca5c0b3b6381313dbb4cccf119b80e9b66 100644
|
||||
index e2f54334ed199b0cb4658c1b1c956dd8bc8b2bf0..0241849170f6d589d011c28127abfd9bc830e5e5 100644
|
||||
--- a/components/language/core/browser/BUILD.gn
|
||||
+++ b/components/language/core/browser/BUILD.gn
|
||||
@@ -28,6 +28,7 @@ static_library("browser") {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user