Compare commits

..

27 Commits

Author SHA1 Message Date
Sam Maddock
cc6164fe27 feat: ServiceWorkerMain (#45341) 2025-01-31 12:40:19 -05:00
trop[bot]
59e4794ff5 build: fix slack-github-action for backports (#45403)
build: fix slack-github-action for backports

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-31 09:53:50 -05:00
trop[bot]
fa03b92f7e feat: contextBridge.executeInMainWorld (#45330)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>
2025-01-31 09:50:44 -05:00
trop[bot]
9d696ceffe feat: redesign preload APIs (#45329)
* feat: redesign preload APIs

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

* docs: remove service-worker mentions for now

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

* fix lint

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

* remove service-worker ipc code

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

* add filename

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

* fix: web preferences preload not included

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

* fix: missing common init

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

* fix: preload bundle script error

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>
2025-01-31 09:46:17 -05:00
trop[bot]
e9b3e4cc91 fix: multiple directory selection on Linux (#45394)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-31 09:38:44 +01:00
trop[bot]
895bc51272 build: fixup concurrent builds on protected branches (#45383)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-01-30 10:36:24 +01:00
Keeley Hammond
ef1ad85082 fix: crash in gin::wrappable::secondweakcallback (#45378)
fix: crash in gin::wrappable::secondweakcallback (#45368)
2025-01-29 15:04:08 -08:00
trop[bot]
e99328a45e docs: reference security guide in ipcRenderer.on docs (#45371)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Niklas Wenzel <dev@nikwen.de>
2025-01-29 15:44:07 -05:00
trop[bot]
04f5fe6a1c build: add NSPrefersDisplaySafeAreaCompatibilityMode = false to Info.plist (#45357)
build: add NSPrefersDisplaySafeAreaCompatibilityMode = false to Info.plist

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2025-01-29 19:55:03 +01:00
trop[bot]
08b6bb1712 build: use Python311 exe (#45364)
build: yse Python311 exe

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <khammond@slack-corp.com>
2025-01-28 20:43:17 -08:00
trop[bot]
813efbcdf7 docs: fix broken code in drag and drop example (#45336)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Niklas Wenzel <dev@nikwen.de>
2025-01-27 13:05:42 -05:00
trop[bot]
d34fa2e301 docs: Add note about directly exposing Electron APIs in preload (#45324)
* docs: Add note about directly exposing Electron APIs in preload

Co-authored-by: Felix Rieseberg <fr@makenotion.com>

* Implement feedback

Co-authored-by: Felix Rieseberg <fr@makenotion.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Felix Rieseberg <fr@makenotion.com>
2025-01-23 16:29:48 -08:00
trop[bot]
724744af16 chore: better logging if Node initialization fails (#45317)
feat: better logging if Node initialization fails

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2025-01-23 12:16:18 -06:00
trop[bot]
91bb748eaa refactor: remove InspectableWebContentsViewMac in favor of the Views version (#45238)
* refactor: remove InspectableWebContentsViewMac in favor of the Views version

* cherry-pick: refactor: remove InspectableWebContentsViewMac in favor of the Views version (#41326)

commit e67ab9a93d

Confilcts not resolved, except removal of the files removed
by the original commit.

* resolved conflicts and build issues after cherry-pick

* cherry-picked: fix: add method allowing to disable headless mode in native widget

https://github.com/electron/electron/pull/42996
fixing
https://github.com/electron/electron/issues/42995

* fix: displaying select popup in window created as fullscreen window

`constrainFrameRect:toScreen:` is not being call for windows created
with `fullscreen: true` therefore `headless` mode was not being removed
and `RenderWidgetHostNSViewBridge::DisplayPopupMenu` ignored displaying
popup.

Issue could be fixed by placing additional removal of `headless` mode
in the `toggleFullScreen:`, but `orderWindow:relativeTo:` is called
both for a regular and a fullscreen window, therefore there will be
a single place fixing both cases.

Because `electron::NativeWindowMac` lifetime may be shorter than
`ElectronNSWindow` on which macOS may execute `orderWindow:relativeTo:`
we need to clear `shell_` when `NativeWindow` is being closed.

Fixes #43010.

* fix: Content visibility when using `vibrancy`

We need to put `NSVisualEffectView` before `ViewsCompositorSuperview`
otherwise when using `vibrancy` in `BrowserWindow` `NSVisualEffectView`
will hide content displayed by the compositor.

Fixes #43003
Fixes #42336

In fact main issues reported in these tickets were not present after
cherry-picking original refactor switching to `views::WebView`, so
text could be selected and click event was properly generated. However
both issues testcases were using `vibrancy` and actual content was
invisible, because it was covered by the `NSVisualEffectView`.

* fix: EXCEPTION_ACCESS_VIOLATION crash on BrowserWindow.destroy()

Restored postponed deletion of the `NativeWindow`.

Restoration caused `DCHECK(new_parent_ui_layer->GetCompositor());` failure
in `BrowserCompositorMac::SetParentUiLayer` after the spec test:
`chrome extensions chrome.webRequest does not take precedence over Electron webRequest - http`
with stack:
```
7   Electron Framework 0x000000011fe07830 content::BrowserCompositorMac::SetParentUiLayer(ui::Layer*) + 628
8   Electron Framework 0x000000011fe0c154 content::RenderWidgetHostViewMac::SetParentUiLayer(ui::Layer*) + 220
9   Electron Framework 0x000000011fe226a8 content::WebContentsViewMac::CreateViewForWidget(content::RenderWidgetHost*) + 600
10  Electron Framework 0x000000011fd37e4c content::WebContentsImpl::CreateRenderWidgetHostViewForRenderManager(content::RenderViewHost*) + 164
11  Electron Framework 0x000000011fb32278 content::RenderFrameHostManager::CreateSpeculativeRenderFrame(content::SiteInstanceImpl*, bool, scoped_refptr<content::BrowsingContextState> const&) + 816
12  Electron Framework 0x000000011fb2ab8c content::RenderFrameHostManager::CreateSpeculativeRenderFrameHost(content::SiteInstanceImpl*, content::SiteInstanceImpl*, bool) + 1308
13  Electron Framework 0x000000011fb28598 content::RenderFrameHostManager::GetFrameHostForNavigation(content::NavigationRequest*, content::BrowsingContextGroupSwap*, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>*) + 1796
14  Electron Framework 0x000000011fa78660 content::NavigationRequest::SelectFrameHostForOnRequestFailedInternal(bool, bool, std::__Cr::optional<std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>> const&) + 280
15  Electron Framework 0x000000011fa6a994 content::NavigationRequest::OnRequestFailedInternal(network::URLLoaderCompletionStatus const&, bool, std::__Cr::optional<std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>> const&, bo
+ 1008
16  Electron Framework 0x000000011fa7772c content::NavigationRequest::OnRequestFailed(network::URLLoaderCompletionStatus const&) + 72
17  Electron Framework 0x000000011f8554ac content::NavigationURLLoaderImpl::NotifyRequestFailed(network::URLLoaderCompletionStatus const&) + 248
```
This was probably the reason of removing `NativeWindow` immediately
in order to cleanup `views_host_` in `WebContentsViewMac` to prevent
using layer without compositor in `WebContentsViewMac::CreateViewForWidget`.

`[ElectronNSWindowDelegate windowWillClose:]` is deleting window host
and the compositor used by the `NativeWindow` therefore detach `NativeWindow`
contents from parent. This will clear `views_host_` and prevent failing
mentioned `DCHECK`.

Fixes #42975

* chore: Applied review suggestions

Co-authored-by: Michał Pichliński <michal.pichlinski@here.io>

* refactor: directly cleanup shell

Co-authored-by: Samuel Maddock <smaddock@slack-corp.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Michał Pichliński <michal.pichlinski@here.io>
Co-authored-by: Samuel Maddock <smaddock@slack-corp.com>
2025-01-23 11:54:15 +01:00
trop[bot]
d77c2d75ed fix: potential crash in chrome.tabs.update() (#45302)
fix: potential crash in chrome.tabs.update()

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-23 11:53:40 +01:00
trop[bot]
f4c3eb4391 refactor: in StopTracing(), use string literals instead of optional<string> (#45292)
refactor: simplify StopTracing() a little by using a string_view instead of an optional<string>

We have compile-time string literals that we're passing to a method
that takes a string_view argument, so we don't need all this extra
optional<string> scaffolding

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2025-01-22 09:43:38 -06:00
trop[bot]
9aca9e9fb6 docs: add DocCardList component for index doc (#45296)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Erick Zhao <ezhao@slack-corp.com>
2025-01-22 10:53:19 +01:00
trop[bot]
e0fa647601 refactor: simplify ParseUserScript() (#45288)
refactor: simplify ParseUserScript()

local variable user_script no longer needed after #43205

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2025-01-22 10:11:16 +01:00
trop[bot]
6b0fd02c0a fix: webContents.print() with OOP printing (#45285)
* fix: webContents.print() with OOP printing

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* Update patches/chromium/printing.patch

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

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-21 15:13:29 -05:00
trop[bot]
1017ac821f chore: align clipboard blink::web_pref::WebPreferences with upstream (#45280)
chore: align clipboard blink::web_pref::WebPreferences with upstream

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-21 09:39:04 -08:00
trop[bot]
91b53b633a fix: getAsFileSystemHandle failure when drag-dropping two directories (#45256)
fix: drag-dropping two directories

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-20 14:01:15 -06:00
trop[bot]
8da9572592 fix: two possible FSA crashes (#45261)
* 5786874: Change Observer: Fix crash when navigating to new page

https://chromium-review.googlesource.com/c/chromium/src/+/5786874

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* 5794141: Change Observer: Fix Get*PermissionGrant crash

https://chromium-review.googlesource.com/c/chromium/src/+/5794141

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-20 18:20:55 +01:00
trop[bot]
291bbff5d8 build: fix clang-format duplicate message (#45265)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-20 18:20:47 +01:00
trop[bot]
d704a3fc5b fix: page scaling in silent mode printing (#45262)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-20 10:37:54 -06:00
trop[bot]
fb70b81ee6 fix: broken OOP window.print() on macOS/Linux (#45259)
fix: broken OOP printing on macOS/Linux

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-01-20 10:37:35 -06:00
trop[bot]
97fa059e1f docs: remove quickstart (#45209)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Anny Yang <yangannyx@gmail.com>
2025-01-17 10:36:58 +01:00
Felix Rieseberg
8a64cdc0b1 docs: Why Electron? (#45191) (#45222)
* docs: Why Electron?

* Apply suggestions from code review




* Update docs/why-electron.md

---------

Co-authored-by: Sam Maddock <samuel.maddock@gmail.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2025-01-16 14:06:57 -05:00
125 changed files with 3330 additions and 1388 deletions

View File

@@ -16,5 +16,5 @@ runs:
e auto-update disable
if [ "$(expr substr $(uname -s) 1 10)" == "MSYS_NT-10" ]; then
e d cipd.bat --version
cp "C:\Python37\python.exe" "C:\Python37\python3.exe"
cp "C:\Python311\python.exe" "C:\Python311\python3.exe"
fi

View File

@@ -41,7 +41,7 @@ jobs:
sha-file: .dig-old
filename: electron.old.d.ts
- name: Upload artifacts
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 #v4.6.0
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b #v4.5.0
with:
name: artifacts
path: electron/artifacts

View File

@@ -94,7 +94,7 @@ jobs:
}))
- name: Create Release Project Board
if: ${{ steps.check-major-version.outputs.MAJOR }}
uses: dsanders11/project-actions/copy-project@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/copy-project@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
id: create-release-board
with:
drafts: true
@@ -114,14 +114,14 @@ jobs:
GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }}
- name: Find Previous Release Project Board
if: ${{ steps.check-major-version.outputs.MAJOR }}
uses: dsanders11/project-actions/find-project@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/find-project@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
id: find-prev-release-board
with:
title: ${{ steps.generate-project-metadata.outputs.prev-prev-major }}-x-y
token: ${{ steps.generate-token.outputs.token }}
- name: Close Previous Release Project Board
if: ${{ steps.check-major-version.outputs.MAJOR }}
uses: dsanders11/project-actions/close-project@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/close-project@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
with:
project-number: ${{ steps.find-prev-release-board.outputs.number }}
token: ${{ steps.generate-token.outputs.token }}

View File

@@ -20,13 +20,12 @@ jobs:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron
- name: Set status
uses: dsanders11/project-actions/edit-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/edit-item@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
with:
token: ${{ steps.generate-token.outputs.token }}
project-number: 90
field: Status
field-value: ✅ Triaged
fail-if-item-not-found: false
issue-labeled-blocked:
name: blocked/* label added
if: startsWith(github.event.label.name, 'blocked/')
@@ -39,13 +38,12 @@ jobs:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron
- name: Set status
uses: dsanders11/project-actions/edit-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/edit-item@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
with:
token: ${{ steps.generate-token.outputs.token }}
project-number: 90
field: Status
field-value: 🛑 Blocked
fail-if-item-not-found: false
issue-labeled-blocked-need-repro:
name: blocked/need-repro label added
if: github.event.label.name == 'blocked/need-repro'

View File

@@ -19,7 +19,7 @@ jobs:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron
- name: Add to Issue Triage
uses: dsanders11/project-actions/add-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/add-item@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
with:
field: Reporter
field-value: ${{ github.event.issue.user.login }}

View File

@@ -10,7 +10,6 @@ jobs:
issue-transferred:
name: Issue Transferred
runs-on: ubuntu-latest
if: ${{ !github.event.changes.new_repository.private }}
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
@@ -19,9 +18,7 @@ jobs:
creds: ${{ secrets.ISSUE_TRIAGE_GH_APP_CREDS }}
org: electron
- name: Remove from issue triage
uses: dsanders11/project-actions/delete-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/delete-item@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
with:
token: ${{ steps.generate-token.outputs.token }}
project-number: 90
item: ${{ github.event.changes.new_issue.html_url }}
fail-if-item-not-found: false

View File

@@ -30,10 +30,9 @@ jobs:
org: electron
- name: Set status
if: ${{ steps.check-for-blocked-labels.outputs.NOT_BLOCKED }}
uses: dsanders11/project-actions/edit-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/edit-item@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
with:
token: ${{ steps.generate-token.outputs.token }}
project-number: 90
field: Status
field-value: 📥 Was Blocked
fail-if-item-not-found: false

View File

@@ -56,8 +56,8 @@ on:
default: false
concurrency:
group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
jobs:
build:

View File

@@ -56,8 +56,8 @@ on:
default: false
concurrency:
group: electron-build-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
group: electron-build-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
permissions:
contents: read

View File

@@ -9,8 +9,8 @@ on:
type: string
concurrency:
group: electron-lint-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
group: electron-lint-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
jobs:
lint:

View File

@@ -61,8 +61,8 @@ on:
concurrency:
group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.target-variant }}-${{ inputs.is-asan }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.target-variant }}-${{ inputs.is-asan }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
env:
ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }}

View File

@@ -27,8 +27,8 @@ on:
default: false
concurrency:
group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
permissions:
contents: read
@@ -239,7 +239,7 @@ jobs:
if: always() && !cancelled()
- name: Upload Test Artifacts
if: always() && !cancelled()
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b
with:
name: test_artifacts_${{ env.ARTIFACT_KEY }}_${{ matrix.shard }}
path: src/electron/spec/artifacts

View File

@@ -27,8 +27,8 @@ on:
default: testing
concurrency:
group: electron-node-nan-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
group: electron-node-nan-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
env:
ELECTRON_OUT_DIR: Default

View File

@@ -15,12 +15,12 @@ jobs:
- name: Trigger Slack workflow
uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0
with:
webhook: ${{ secrets.BACKPORT_REQUESTED_SLACK_WEBHOOK_URL }}
webhook-type: webhook-trigger
payload: |
{
"url": "${{ github.event.pull_request.html_url }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.BACKPORT_REQUESTED_SLACK_WEBHOOK_URL }}
pull-request-labeled-deprecation-review-complete:
name: deprecation-review/complete label added
if: github.event.label.name == 'deprecation-review/complete ✅'
@@ -33,7 +33,7 @@ jobs:
creds: ${{ secrets.RELEASE_BOARD_GH_APP_CREDS }}
org: electron
- name: Set status
uses: dsanders11/project-actions/edit-item@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/edit-item@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
with:
token: ${{ steps.generate-token.outputs.token }}
project-number: 94

View File

@@ -42,7 +42,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
with:
name: SARIF file
path: results.sarif
@@ -50,6 +50,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1
uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
with:
sarif_file: results.sarif

View File

@@ -27,7 +27,7 @@ jobs:
PROJECT_NUMBER=$(gh project list --owner electron --format json | jq -r '.projects | map(select(.title | test("^[0-9]+-x-y$"))) | max_by(.number) | .number')
echo "PROJECT_NUMBER=$PROJECT_NUMBER" >> "$GITHUB_OUTPUT"
- name: Update Completed Stable Prep Items
uses: dsanders11/project-actions/completed-by@9c80cd31f58599941c64f74636bea95ba5d46090 # v1.5.1
uses: dsanders11/project-actions/completed-by@438b25e007c2f4efec324497fadc6402e7cc61a6 # v1.4.0
with:
field: Prep Status
field-value: ✅ Complete

View File

@@ -44,7 +44,7 @@ jobs:
fi
- name: (Optionally) Update Appveyor Image
if: ${{ env.APPVEYOR_IMAGE_VERSION }}
uses: mikefarah/yq@8bf425b4d1344db7cd469a8d10a390876e0c77fd # v4.45.1
uses: mikefarah/yq@4839dbbf80445070a31c7a9c1055da527db2d5ee # v4.44.6
with:
cmd: |
yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor.yml" > "appveyor2.yml"

2
DEPS
View File

@@ -4,7 +4,7 @@ vars = {
'chromium_version':
'133.0.6920.0',
'node_version':
'v22.11.0',
'v22.9.0',
'nan_version':
'e14bdcd1f72d62bca1d541b66da43130384ec213',
'squirrel.mac_version':

View File

@@ -127,6 +127,7 @@ These individual tutorials expand on topics discussed in the guide above.
* [pushNotifications](api/push-notifications.md)
* [safeStorage](api/safe-storage.md)
* [screen](api/screen.md)
* [ServiceWorkerMain](api/service-worker-main.md)
* [session](api/session.md)
* [ShareMenu](api/share-menu.md)
* [systemPreferences](api/system-preferences.md)

View File

@@ -61,6 +61,20 @@ The `contextBridge` module has the following methods:
* `apiKey` string - The key to inject the API onto `window` with. The API will be accessible on `window[apiKey]`.
* `api` any - Your API, more information on what this API can be and how it works is available below.
### `contextBridge.executeInMainWorld(executionScript)` _Experimental_
<!-- TODO(samuelmaddock): add generics to map the `args` types to the `func` params -->
* `executionScript` Object
* `func` (...args: any[]) => any - A JavaScript function to execute. This function will be serialized which means
that any bound parameters and execution context will be lost.
* `args` any[] (optional) - An array of arguments to pass to the provided function. These
arguments will be copied between worlds in accordance with
[the table of supported types.](#parameter--error--return-type-support)
Returns `any` - A copy of the resulting value from executing the function in the main world.
[Refer to the table](#parameter--error--return-type-support) on how values are copied between worlds.
## Usage
### API

View File

@@ -12,17 +12,9 @@ shortcuts.
not have the keyboard focus. This module cannot be used before the `ready`
event of the app module is emitted.
Please also note that it is also possible to use Chromium's
`GlobalShortcutsPortal` implementation, which allows apps to bind global
shortcuts when running within a Wayland session.
```js
const { app, globalShortcut } = require('electron')
// Enable usage of Portal's globalShortcuts. This is essential for cases when
// the app runs in a Wayland session.
app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal')
app.whenReady().then(() => {
// Register a 'CommandOrControl+X' shortcut listener.
const ret = globalShortcut.register('CommandOrControl+X', () => {

View File

@@ -41,6 +41,16 @@ The `ipcRenderer` module has the following method to listen for events and send
Listens to `channel`, when a new message arrives `listener` would be called with
`listener(event, args...)`.
:::warning
Do not expose the `event` argument to the renderer for security reasons! Wrap any
callback that you receive from the renderer in another function like this:
`ipcRenderer.on('my-channel', (event, ...args) => callback(...args))`.
Not wrapping the callback in such a function would expose dangerous Electron APIs
to the renderer process. See the
[security guide](../tutorial/security.md#20-do-not-expose-electron-apis-to-untrusted-web-content)
for more info.
:::
### `ipcRenderer.off(channel, listener)`
* `channel` string

View File

@@ -0,0 +1,34 @@
# ServiceWorkerMain
> An instance of a Service Worker representing a version of a script for a given scope.
Process: [Main](../glossary.md#main-process)
## Class: ServiceWorkerMain
Process: [Main](../glossary.md#main-process)<br />
_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._
### Instance Methods
#### `serviceWorker.isDestroyed()` _Experimental_
Returns `boolean` - Whether the service worker has been destroyed.
#### `serviceWorker.startTask()` _Experimental_
Returns `Object`:
- `end` Function - Method to call when the task has ended. If never called, the service won't terminate while otherwise idle.
Initiate a task to keep the service worker alive until ended.
### Instance Properties
#### `serviceWorker.scope` _Readonly_ _Experimental_
A `string` representing the scope URL of the service worker.
#### `serviceWorker.versionId` _Readonly_ _Experimental_
A `number` representing the ID of the specific version of the service worker script in its scope.

View File

@@ -56,6 +56,17 @@ Returns:
Emitted when a service worker has been registered. Can occur after a call to [`navigator.serviceWorker.register('/sw.js')`](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register) successfully resolves or when a Chrome extension is loaded.
#### Event: 'running-status-changed' _Experimental_
Returns:
* `details` Event\<\>
* `versionId` number - ID of the updated service worker version
* `runningStatus` string - Running status.
Possible values include `starting`, `running`, `stopping`, or `stopped`.
Emitted when a service worker's running status has changed.
### Instance Methods
The following methods are available on instances of `ServiceWorkers`:
@@ -64,10 +75,56 @@ The following methods are available on instances of `ServiceWorkers`:
Returns `Record<number, ServiceWorkerInfo>` - A [ServiceWorkerInfo](structures/service-worker-info.md) object where the keys are the service worker version ID and the values are the information about that service worker.
#### `serviceWorkers.getFromVersionID(versionId)`
#### `serviceWorkers.getInfoFromVersionID(versionId)`
* `versionId` number
* `versionId` number - ID of the service worker version
Returns [`ServiceWorkerInfo`](structures/service-worker-info.md) - Information about this service worker
If the service worker does not exist or is not running this method will throw an exception.
#### `serviceWorkers.getFromVersionID(versionId)` _Deprecated_
* `versionId` number - ID of the service worker version
Returns [`ServiceWorkerInfo`](structures/service-worker-info.md) - Information about this service worker
If the service worker does not exist or is not running this method will throw an exception.
**Deprecated:** Use the new `serviceWorkers.getInfoFromVersionID` API.
#### `serviceWorkers.getWorkerFromVersionID(versionId)` _Experimental_
* `versionId` number - ID of the service worker version
Returns [`ServiceWorkerMain | undefined`](service-worker-main.md) - Instance of the service worker associated with the given version ID. If there's no associated version, or its running status has changed to 'stopped', this will return `undefined`.
#### `serviceWorkers.startWorkerForScope(scope)` _Experimental_
* `scope` string - The scope of the service worker to start.
Returns `Promise<ServiceWorkerMain>` - Resolves with the service worker when it's started.
Starts the service worker or does nothing if already running.
<!-- TODO(samuelmaddock): extend example to send IPC after starting worker -->
```js
const { app, session } = require('electron')
const { serviceWorkers } = session.defaultSession
// Collect service workers scopes
const workerScopes = Object.values(serviceWorkers.getAllRunning()).map((info) => info.scope)
app.on('browser-window-created', async (event, window) => {
for (const scope of workerScopes) {
try {
// Ensure worker is started
await serviceWorkers.startWorkerForScope(scope)
} catch (error) {
console.error(`Failed to start service worker for ${scope}`)
console.error(error)
}
}
})
```

View File

@@ -1330,18 +1330,43 @@ the initial state will be `interrupted`. The download will start only when the
Returns `Promise<void>` - resolves when the sessions HTTP authentication cache has been cleared.
#### `ses.setPreloads(preloads)`
#### `ses.setPreloads(preloads)` _Deprecated_
* `preloads` string[] - An array of absolute path to preload scripts
Adds scripts that will be executed on ALL web contents that are associated with
this session just before normal `preload` scripts run.
#### `ses.getPreloads()`
**Deprecated:** Use the new `ses.registerPreloadScript` API.
#### `ses.getPreloads()` _Deprecated_
Returns `string[]` an array of paths to preload scripts that have been
registered.
**Deprecated:** Use the new `ses.getPreloadScripts` API. This will only return preload script paths
for `frame` context types.
#### `ses.registerPreloadScript(script)`
* `script` [PreloadScriptRegistration](structures/preload-script-registration.md) - Preload script
Registers preload script that will be executed in its associated context type in this session. For
`frame` contexts, this will run prior to any preload defined in the web preferences of a
WebContents.
Returns `string` - The ID of the registered preload script.
#### `ses.unregisterPreloadScript(id)`
* `id` string - Preload script ID
Unregisters script.
#### `ses.getPreloadScripts()`
Returns [`PreloadScript[]`](structures/preload-script.md): An array of paths to preload scripts that have been registered.
#### `ses.setCodeCachePath(path)`
* `path` String - Absolute path to store the v8 generated JS code cache from the renderer.

View File

@@ -0,0 +1,6 @@
# PreloadScriptRegistration Object
* `type` string - Context type where the preload script will be executed.
Possible values include `frame`.
* `id` string (optional) - Unique ID of preload script. Defaults to a random UUID.
* `filePath` string - Path of the script file. Must be an absolute path.

View File

@@ -0,0 +1,6 @@
# PreloadScript Object
* `type` string - Context type where the preload script will be executed.
Possible values include `frame`.
* `id` string - Unique ID of preload script.
* `filePath` string - Path of the script file. Must be an absolute path.

View File

@@ -3,3 +3,4 @@
* `scriptUrl` string - The full URL to the script that this service worker runs
* `scope` string - The base URL that this service worker is active for.
* `renderProcessId` number - The virtual ID of the process that this service worker is running in. This is not an OS level PID. This aligns with the ID set used for `webContents.getProcessId()`.
* `versionId` number - ID of the service worker version

View File

@@ -14,6 +14,40 @@ This document uses the following convention to categorize breaking changes:
## Planned Breaking API Changes (35.0)
### Deprecated: `setPreloads`, `getPreloads` on `Session`
`registerPreloadScript`, `unregisterPreloadScript`, and `getPreloadScripts` are introduced as a
replacement for the deprecated methods. These new APIs allow third-party libraries to register
preload scripts without replacing existing scripts. Also, the new `type` option allows for
additional preload targets beyond `frame`.
```js
// Deprecated
session.setPreloads([path.join(__dirname, 'preload.js')])
// Replace with:
session.registerPreloadScript({
type: 'frame',
id: 'app-preload',
filePath: path.join(__dirname, 'preload.js')
})
```
### Deprecated: `getFromVersionID` on `session.serviceWorkers`
The `session.serviceWorkers.fromVersionID(versionId)` API has been deprecated
in favor of `session.serviceWorkers.getInfoFromVersionID(versionId)`. This was
changed to make it more clear which object is returned with the introduction
of the `session.serviceWorkers.getWorkerFromVersionID(versionId)` API.
```js
// Deprecated
session.serviceWorkers.fromVersionID(versionId)
// Replace with
session.serviceWorkers.getInfoFromVersionID(versionId)
```
### Deprecated: `level`, `message`, `line`, and `sourceId` arguments in `console-message` event on `WebContents`
The `console-message` event on `WebContents` has been updated to provide details on the `Event`
@@ -56,15 +90,15 @@ immediately upon being received. Otherwise, it's not guaranteed to point to the
same webpage as when received. To avoid misaligned expectations, Electron will
return `null` in the case of late access where the webpage has changed.
```ts
```js
ipcMain.on('unload-event', (event) => {
event.senderFrame; // ✅ accessed immediately
});
event.senderFrame // ✅ accessed immediately
})
ipcMain.on('unload-event', async (event) => {
await crossOriginNavigationPromise;
event.senderFrame; // ❌ returns `null` due to late access
});
await crossOriginNavigationPromise
event.senderFrame // ❌ returns `null` due to late access
})
```
### Behavior Changed: custom protocol URL handling on Windows

View File

@@ -22,12 +22,9 @@ In `preload.js` use the [`contextBridge`][] to inject a method `window.electron.
```js
const { contextBridge, ipcRenderer } = require('electron')
const path = require('node:path')
contextBridge.exposeInMainWorld('electron', {
startDrag: (fileName) => {
ipcRenderer.send('ondragstart', path.join(process.cwd(), fileName))
}
startDrag: (fileName) => ipcRenderer.send('ondragstart', fileName)
})
```

View File

@@ -116,6 +116,7 @@ You should at least follow these steps to improve the security of your applicati
17. [Validate the `sender` of all IPC messages](#17-validate-the-sender-of-all-ipc-messages)
18. [Avoid usage of the `file://` protocol and prefer usage of custom protocols](#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols)
19. [Check which fuses you can change](#19-check-which-fuses-you-can-change)
20. [Do not expose Electron APIs to untrusted web content](#20-do-not-expose-electron-apis-to-untrusted-web-content)
To automate the detection of misconfigurations and insecure patterns, it is
possible to use
@@ -229,7 +230,7 @@ API to remotely loaded content via the [contextBridge API](../api/context-bridge
### 3. Enable Context Isolation
:::info
This recommendation is the default behavior in Electron since 12.0.0.
Context Isolation is the default behavior in Electron since 12.0.0.
:::
Context isolation is an Electron feature that allows developers to run code
@@ -804,6 +805,48 @@ flipping these fuses easy. Check out the README of that module for more details
potential error cases, and refer to
[How do I flip the fuses?](./fuses.md#how-do-i-flip-the-fuses) in our documentation.
### 20. Do not expose Electron APIs to untrusted web content
You should not directly expose Electron's APIs, especially IPC, to untrusted web content in your
preload scripts.
### Why?
Exposing raw APIs like `ipcRenderer.on` is dangerous because it gives renderer processes direct
access to the entire IPC event system, allowing them to listen for any IPC events, not just the ones
intended for them.
To avoid that exposure, we also cannot pass callbacks directly through: The first
argument to IPC event callbacks is an `IpcRendererEvent` object, which includes properties like `sender`
that provide access to the underlying `ipcRenderer` instance. Even if you only listen for specific
events, passing the callback directly means the renderer gets access to this event object.
In short, we want the untrusted web content to only have access to necessary information and APIs.
### How?
```js title='preload'.js'
// Bad
contextBridge.exposeInMainWorld('electronAPI', {
on: ipcRenderer.on
})
// Also bad
contextBridge.exposeInMainWorld('electronAPI', {
onUpdateCounter: (callback) => ipcRenderer.on('update-counter', callback)
})
// Good
contextBridge.exposeInMainWorld('electronAPI', {
onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value))
})
```
:::info
For more information on what `contextIsolation` is and how to use it to secure your app,
please see the [Context Isolation](context-isolation.md) document.
:::
[breaking-changes]: ../breaking-changes.md
[browser-window]: ../api/browser-window.md
[webview-tag]: ../api/webview-tag.md

View File

@@ -45,6 +45,7 @@ auto_filenames = {
"docs/api/push-notifications.md",
"docs/api/safe-storage.md",
"docs/api/screen.md",
"docs/api/service-worker-main.md",
"docs/api/service-workers.md",
"docs/api/session.md",
"docs/api/share-menu.md",
@@ -114,6 +115,8 @@ auto_filenames = {
"docs/api/structures/permission-request.md",
"docs/api/structures/point.md",
"docs/api/structures/post-body.md",
"docs/api/structures/preload-script-registration.md",
"docs/api/structures/preload-script.md",
"docs/api/structures/printer-info.md",
"docs/api/structures/process-memory-info.md",
"docs/api/structures/process-metric.md",
@@ -183,6 +186,8 @@ auto_filenames = {
"lib/sandboxed_renderer/api/exports/electron.ts",
"lib/sandboxed_renderer/api/module-list.ts",
"lib/sandboxed_renderer/init.ts",
"lib/sandboxed_renderer/pre-init.ts",
"lib/sandboxed_renderer/preload.ts",
"package.json",
"tsconfig.electron.json",
"tsconfig.json",
@@ -239,6 +244,7 @@ auto_filenames = {
"lib/browser/api/push-notifications.ts",
"lib/browser/api/safe-storage.ts",
"lib/browser/api/screen.ts",
"lib/browser/api/service-worker-main.ts",
"lib/browser/api/session.ts",
"lib/browser/api/share-menu.ts",
"lib/browser/api/system-preferences.ts",

View File

@@ -296,6 +296,8 @@ filenames = {
"shell/browser/api/electron_api_screen.h",
"shell/browser/api/electron_api_service_worker_context.cc",
"shell/browser/api/electron_api_service_worker_context.h",
"shell/browser/api/electron_api_service_worker_main.cc",
"shell/browser/api/electron_api_service_worker_main.h",
"shell/browser/api/electron_api_session.cc",
"shell/browser/api/electron_api_session.h",
"shell/browser/api/electron_api_system_preferences.cc",
@@ -474,6 +476,7 @@ filenames = {
"shell/browser/osr/osr_web_contents_view.h",
"shell/browser/plugins/plugin_utils.cc",
"shell/browser/plugins/plugin_utils.h",
"shell/browser/preload_script.h",
"shell/browser/protocol_registry.cc",
"shell/browser/protocol_registry.h",
"shell/browser/relauncher.cc",
@@ -613,6 +616,8 @@ filenames = {
"shell/common/gin_converters/osr_converter.cc",
"shell/common/gin_converters/osr_converter.h",
"shell/common/gin_converters/serial_port_info_converter.h",
"shell/common/gin_converters/service_worker_converter.cc",
"shell/common/gin_converters/service_worker_converter.h",
"shell/common/gin_converters/std_converter.h",
"shell/common/gin_converters/time_converter.cc",
"shell/common/gin_converters/time_converter.h",

View File

@@ -29,6 +29,7 @@ export const browserModuleList: ElectronInternal.ModuleEntry[] = [
{ name: 'protocol', loader: () => require('./protocol') },
{ name: 'safeStorage', loader: () => require('./safe-storage') },
{ name: 'screen', loader: () => require('./screen') },
{ name: 'ServiceWorkerMain', loader: () => require('./service-worker-main') },
{ name: 'session', loader: () => require('./session') },
{ name: 'ShareMenu', loader: () => require('./share-menu') },
{ name: 'systemPreferences', loader: () => require('./system-preferences') },

View File

@@ -0,0 +1,17 @@
const { ServiceWorkerMain } = process._linkedBinding('electron_browser_service_worker_main');
ServiceWorkerMain.prototype.startTask = function () {
// TODO(samuelmaddock): maybe make timeout configurable in the future
const hasTimeout = false;
const { id, ok } = this._startExternalRequest(hasTimeout);
if (!ok) {
throw new Error('Unable to start service worker task.');
}
return {
end: () => this._finishExternalRequest(id)
};
};
module.exports = ServiceWorkerMain;

View File

@@ -1,4 +1,5 @@
import { fetchWithSession } from '@electron/internal/browser/api/net-fetch';
import * as deprecate from '@electron/internal/common/deprecate';
import { net } from 'electron/main';
@@ -36,6 +37,31 @@ Session.prototype.setDisplayMediaRequestHandler = function (handler, opts) {
}, opts);
};
const getPreloadsDeprecated = deprecate.warnOnce('session.getPreloads', 'session.getPreloadScripts');
Session.prototype.getPreloads = function () {
getPreloadsDeprecated();
return this.getPreloadScripts()
.filter((script) => script.type === 'frame')
.map((script) => script.filePath);
};
const setPreloadsDeprecated = deprecate.warnOnce('session.setPreloads', 'session.registerPreloadScript');
Session.prototype.setPreloads = function (preloads) {
setPreloadsDeprecated();
this.getPreloadScripts()
.filter((script) => script.type === 'frame')
.forEach((script) => {
this.unregisterPreloadScript(script.id);
});
preloads.map(filePath => ({
type: 'frame',
filePath,
_deprecated: true
}) as Electron.PreloadScriptRegistration).forEach(script => {
this.registerPreloadScript(script);
});
};
export default {
fromPartition,
fromPath,

View File

@@ -146,6 +146,9 @@ require('@electron/internal/browser/devtools');
// Load protocol module to ensure it is populated on app ready
require('@electron/internal/browser/api/protocol');
// Load service-worker-main module to ensure it is populated on app ready
require('@electron/internal/browser/api/service-worker-main');
// Load web-contents module to ensure it is populated on app ready
require('@electron/internal/browser/api/web-contents');

View File

@@ -5,6 +5,7 @@ import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
import { clipboard } from 'electron/common';
import * as fs from 'fs';
import * as path from 'path';
// Implements window.close()
ipcMainInternal.on(IPC_MESSAGES.BROWSER_WINDOW_CLOSE, function (event) {
@@ -43,22 +44,40 @@ ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_CLIPBOARD_SYNC, function (event, me
return (clipboard as any)[method](...args);
});
const getPreloadScript = async function (preloadPath: string) {
let preloadSrc = null;
let preloadError = null;
const getPreloadScriptsFromEvent = (event: ElectronInternal.IpcMainInternalEvent) => {
const session: Electron.Session = event.sender.session;
const preloadScripts = session.getPreloadScripts();
const framePreloads = preloadScripts.filter(script => script.type === 'frame');
const webPrefPreload = event.sender._getPreloadScript();
if (webPrefPreload) framePreloads.push(webPrefPreload);
// TODO(samuelmaddock): Remove filter after Session.setPreloads is fully
// deprecated. The new API will prevent relative paths from being registered.
return framePreloads.filter(script => path.isAbsolute(script.filePath));
};
const readPreloadScript = async function (script: Electron.PreloadScript): Promise<ElectronInternal.PreloadScript> {
let contents;
let error;
try {
preloadSrc = await fs.promises.readFile(preloadPath, 'utf8');
} catch (error) {
preloadError = error;
contents = await fs.promises.readFile(script.filePath, 'utf8');
} catch (err) {
if (err instanceof Error) {
error = err;
}
}
return { preloadPath, preloadSrc, preloadError };
return {
...script,
contents,
error
};
};
ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_SANDBOX_LOAD, async function (event) {
const preloadPaths = event.sender._getPreloadPaths();
const preloadScripts = getPreloadScriptsFromEvent(event);
return {
preloadScripts: await Promise.all(preloadPaths.map(path => getPreloadScript(path))),
preloadScripts: await Promise.all(preloadScripts.map(readPreloadScript)),
process: {
arch: process.arch,
platform: process.platform,
@@ -71,7 +90,8 @@ ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_SANDBOX_LOAD, async function (event
});
ipcMainUtils.handleSync(IPC_MESSAGES.BROWSER_NONSANDBOX_LOAD, function (event) {
return { preloadPaths: event.sender._getPreloadPaths() };
const preloadScripts = getPreloadScriptsFromEvent(event);
return { preloadPaths: preloadScripts.map(script => script.filePath) };
});
ipcMainInternal.on(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, function (event, preloadPath: string, error: Error) {

View File

@@ -871,9 +871,9 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
const binding = internalBinding('fs');
const { internalModuleStat } = binding;
internalBinding('fs').internalModuleStat = (receiver: unknown, pathArgument: string) => {
internalBinding('fs').internalModuleStat = (pathArgument: string) => {
const pathInfo = splitPath(pathArgument);
if (!pathInfo.isAsar) return internalModuleStat(receiver, pathArgument);
if (!pathInfo.isAsar) return internalModuleStat(pathArgument);
const { asarPath, filePath } = pathInfo;
// -ENOENT
@@ -908,7 +908,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
if (withFileTypes) {
initialItem = [
[...initialItem], initialItem.map((p: string) => {
return internalBinding('fs').internalModuleStat(binding, path.join(originalPath, p));
return internalBinding('fs').internalModuleStat(path.join(originalPath, p));
})
];
}
@@ -941,7 +941,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
readdirResult = [
[...files], files.map((p: string) => {
return internalBinding('fs').internalModuleStat(binding, path.join(direntPath, p));
return internalBinding('fs').internalModuleStat(path.join(direntPath, p));
})
];
} else {
@@ -962,7 +962,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
const { 0: pathArg, 1: readDir } = queue.pop();
for (const ent of readDir) {
const direntPath = path.join(pathArg, ent);
const stat = internalBinding('fs').internalModuleStat(binding, direntPath);
const stat = internalBinding('fs').internalModuleStat(direntPath);
result.push(path.relative(originalPath, direntPath));
if (stat === 1) {
@@ -1014,7 +1014,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
if (withFileTypes) {
readdirResult = [
[...readdirResult], readdirResult.map((p: string) => {
return internalBinding('fs').internalModuleStat(binding, path.join(pathArg, p));
return internalBinding('fs').internalModuleStat(path.join(pathArg, p));
})
];
}
@@ -1054,7 +1054,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
for (let i = 0; i < readdirResult.length; i++) {
const resultPath = path.join(pathArg, readdirResult[i]);
const relativeResultPath = path.relative(basePath, resultPath);
const stat = internalBinding('fs').internalModuleStat(binding, resultPath);
const stat = internalBinding('fs').internalModuleStat(resultPath);
readdirResults.push(relativeResultPath);
if (stat === 1) pathsQueue.push(resultPath);

View File

@@ -5,13 +5,17 @@ const checkContextIsolationEnabled = () => {
};
const contextBridge: Electron.ContextBridge = {
exposeInMainWorld: (key: string, api: any) => {
exposeInMainWorld: (key, api) => {
checkContextIsolationEnabled();
return binding.exposeAPIInWorld(0, key, api);
},
exposeInIsolatedWorld: (worldId: number, key: string, api: any) => {
exposeInIsolatedWorld: (worldId, key, api) => {
checkContextIsolationEnabled();
return binding.exposeAPIInWorld(worldId, key, api);
},
executeInMainWorld: (script) => {
checkContextIsolationEnabled();
return binding.executeInWorld(0, script);
}
};
@@ -27,8 +31,7 @@ export const internalContextBridge = {
},
overrideGlobalPropertyFromIsolatedWorld: (keys: string[], getter: Function, setter?: Function) => {
return binding._overrideGlobalPropertyFromIsolatedWorld(keys, getter, setter || null);
},
isInMainWorld: () => binding._isCalledFromMainWorld() as boolean
}
};
if (binding._isDebug) {

View File

@@ -1,6 +1,7 @@
import '@electron/internal/sandboxed_renderer/pre-init';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
import type * as ipcRendererInternalModule from '@electron/internal/renderer/ipc-renderer-internal';
import type * as ipcRendererUtilsModule from '@electron/internal/renderer/ipc-renderer-internal-utils';
import { createPreloadProcessObject, executeSandboxedPreloadScripts } from '@electron/internal/sandboxed_renderer/preload';
import * as events from 'events';
import { setImmediate, clearImmediate } from 'timers';
@@ -11,35 +12,14 @@ declare const binding: {
createPreloadScript: (src: string) => Function
};
const { EventEmitter } = events;
process._linkedBinding = binding.get;
const v8Util = process._linkedBinding('electron_common_v8_util');
// Expose Buffer shim as a hidden value. This is used by C++ code to
// deserialize Buffer instances sent from browser process.
v8Util.setHiddenValue(global, 'Buffer', Buffer);
// The process object created by webpack is not an event emitter, fix it so
// the API is more compatible with non-sandboxed renderers.
for (const prop of Object.keys(EventEmitter.prototype) as (keyof typeof process)[]) {
if (Object.hasOwn(process, prop)) {
delete process[prop];
}
}
Object.setPrototypeOf(process, EventEmitter.prototype);
const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal') as typeof ipcRendererInternalModule;
const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils') as typeof ipcRendererUtilsModule;
const {
preloadScripts,
process: processProps
} = ipcRendererUtils.invokeSync<{
preloadScripts: {
preloadPath: string;
preloadSrc: string | null;
preloadError: null | Error;
}[];
preloadScripts: ElectronInternal.PreloadScript[];
process: NodeJS.Process;
}>(IPC_MESSAGES.BROWSER_SANDBOX_LOAD);
@@ -60,8 +40,7 @@ const loadableModules = new Map<string, Function>([
['node:url', () => require('url')]
]);
// Pass different process object to the preload script.
const preloadProcess: NodeJS.Process = new EventEmitter() as any;
const preloadProcess = createPreloadProcessObject();
// InvokeEmitProcessEvent in ElectronSandboxedRendererClient will look for this
v8Util.setHiddenValue(global, 'emit-process-event', (event: string) => {
@@ -72,77 +51,22 @@ v8Util.setHiddenValue(global, 'emit-process-event', (event: string) => {
Object.assign(preloadProcess, binding.process);
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;
},
set (value) {
process.noDeprecation = value;
}
});
// This is the `require` function that will be visible to the preload script
function preloadRequire (module: string) {
if (loadedModules.has(module)) {
return loadedModules.get(module);
}
if (loadableModules.has(module)) {
const loadedModule = loadableModules.get(module)!();
loadedModules.set(module, loadedModule);
return loadedModule;
}
throw new Error(`module not found: ${module}`);
}
// Process command line arguments.
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
// Similar to nodes --expose-internals flag, this exposes _linkedBinding so
// that tests can call it to get access to some test only bindings
if (hasSwitch('unsafely-expose-electron-internals-for-testing')) {
preloadProcess._linkedBinding = process._linkedBinding;
}
// Common renderer initialization
require('@electron/internal/renderer/common-init');
// Wrap the script into a function executed in global scope. It won't have
// access to the current scope, so we'll expose a few objects as arguments:
//
// - `require`: The `preloadRequire` function
// - `process`: The `preloadProcess` object
// - `Buffer`: Shim of `Buffer` implementation
// - `global`: The window object, which is aliased to `global` by webpack.
function runPreloadScript (preloadSrc: string) {
const preloadWrapperSrc = `(function(require, process, Buffer, global, setImmediate, clearImmediate, exports, module) {
${preloadSrc}
})`;
// eval in window scope
const preloadFn = binding.createPreloadScript(preloadWrapperSrc);
const exports = {};
preloadFn(preloadRequire, preloadProcess, Buffer, global, setImmediate, clearImmediate, exports, { exports });
}
for (const { preloadPath, preloadSrc, preloadError } of preloadScripts) {
try {
if (preloadSrc) {
runPreloadScript(preloadSrc);
} else if (preloadError) {
throw preloadError;
}
} catch (error) {
console.error(`Unable to load preload script: ${preloadPath}`);
console.error(error);
ipcRendererInternal.send(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, preloadPath, error);
executeSandboxedPreloadScripts({
loadedModules,
loadableModules,
process: preloadProcess,
createPreloadScript: binding.createPreloadScript,
exposeGlobals: {
Buffer,
// FIXME(samuelmaddock): workaround webpack bug replacing this with just
// `__webpack_require__.g,` which causes script error
global: globalThis,
setImmediate,
clearImmediate
}
}
}, preloadScripts);

View File

@@ -0,0 +1,30 @@
// Pre-initialization code for sandboxed renderers.
import * as events from 'events';
declare const binding: {
get: (name: string) => any;
process: NodeJS.Process;
};
// Expose internal binding getter.
process._linkedBinding = binding.get;
const { EventEmitter } = events;
const v8Util = process._linkedBinding('electron_common_v8_util');
// Include properties from script 'binding' parameter.
Object.assign(process, binding.process);
// Expose Buffer shim as a hidden value. This is used by C++ code to
// deserialize Buffer instances sent from browser process.
v8Util.setHiddenValue(global, 'Buffer', Buffer);
// The process object created by webpack is not an event emitter, fix it so
// the API is more compatible with non-sandboxed renderers.
for (const prop of Object.keys(EventEmitter.prototype) as (keyof typeof process)[]) {
if (Object.hasOwn(process, prop)) {
delete process[prop];
}
}
Object.setPrototypeOf(process, EventEmitter.prototype);

View File

@@ -0,0 +1,101 @@
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
import { EventEmitter } from 'events';
interface PreloadContext {
loadedModules: Map<string, any>;
loadableModules: Map<string, any>;
/** Process object to pass into preloads. */
process: NodeJS.Process;
createPreloadScript: (src: string) => Function
/** Globals to be exposed to preload context. */
exposeGlobals: any;
}
export function createPreloadProcessObject (): NodeJS.Process {
const preloadProcess: NodeJS.Process = new EventEmitter() as any;
preloadProcess.getProcessMemoryInfo = () => {
return ipcRendererInternal.invoke<Electron.ProcessMemoryInfo>(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO);
};
Object.defineProperty(preloadProcess, 'noDeprecation', {
get () {
return process.noDeprecation;
},
set (value) {
process.noDeprecation = value;
}
});
const { hasSwitch } = process._linkedBinding('electron_common_command_line');
// Similar to nodes --expose-internals flag, this exposes _linkedBinding so
// that tests can call it to get access to some test only bindings
if (hasSwitch('unsafely-expose-electron-internals-for-testing')) {
preloadProcess._linkedBinding = process._linkedBinding;
}
return preloadProcess;
}
// This is the `require` function that will be visible to the preload script
function preloadRequire (context: PreloadContext, module: string) {
if (context.loadedModules.has(module)) {
return context.loadedModules.get(module);
}
if (context.loadableModules.has(module)) {
const loadedModule = context.loadableModules.get(module)!();
context.loadedModules.set(module, loadedModule);
return loadedModule;
}
throw new Error(`module not found: ${module}`);
}
// Wrap the script into a function executed in global scope. It won't have
// access to the current scope, so we'll expose a few objects as arguments:
//
// - `require`: The `preloadRequire` function
// - `process`: The `preloadProcess` object
// - `Buffer`: Shim of `Buffer` implementation
// - `global`: The window object, which is aliased to `global` by webpack.
function runPreloadScript (context: PreloadContext, preloadSrc: string) {
const globalVariables = [];
const fnParameters = [];
for (const [key, value] of Object.entries(context.exposeGlobals)) {
globalVariables.push(key);
fnParameters.push(value);
}
const preloadWrapperSrc = `(function(require, process, exports, module, ${globalVariables.join(', ')}) {
${preloadSrc}
})`;
// eval in window scope
const preloadFn = context.createPreloadScript(preloadWrapperSrc);
const exports = {};
preloadFn(preloadRequire.bind(null, context), context.process, exports, { exports }, ...fnParameters);
}
/**
* Execute preload scripts within a sandboxed process.
*/
export function executeSandboxedPreloadScripts (context: PreloadContext, preloadScripts: ElectronInternal.PreloadScript[]) {
for (const { filePath, contents, error } of preloadScripts) {
try {
if (contents) {
runPreloadScript(context, contents);
} else if (error) {
throw error;
}
} catch (error) {
console.error(`Unable to load preload script: ${filePath}`);
console.error(error);
ipcRendererInternal.send(IPC_MESSAGES.BROWSER_PRELOAD_ERROR, filePath, error);
}
}
}

View File

@@ -139,4 +139,4 @@ refactor_unfilter_unresponsive_events.patch
build_disable_thin_lto_mac.patch
build_add_public_config_simdutf_config.patch
revert_code_health_clean_up_stale_macwebcontentsocclusion.patch
check_for_unit_to_activate_before_notifying_about_success.patch
feat_add_signals_when_embedder_cleanup_callbacks_run_for.patch

View File

@@ -1,497 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Maksim Sisov <msisov@igalia.com>
Date: Tue, 7 Jan 2025 23:46:56 -0800
Subject: Check for unit to activate before notifying about success
Portal's globalShortcuts interface relies on the unit name to
properly assign a client for the bound commands. However, in
some scenarious, there is a race between the service to be
created, changed its name and activated. As a result, shortcuts
might be bound before the name is changed. As a result, shortcuts
might not correctly work and the client will not receive any
signals.
This is mostly not an issue for Chromium as it creates the
global shortcuts portal linux object way earlier than it gets
commands from the command service. But downstream project, which
try to bind shortcuts at the same time as that instance is created,
may experience this issue. As a result, they might not have
shortcuts working correctly after system reboot or app restart as
there is a race between those operations.
Bug: None
Change-Id: I8346d65e051d9587850c76ca0b8807669c161667
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6110782
Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
Commit-Queue: Maksim Sisov <msisov@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1403434}
diff --git a/components/dbus/xdg/systemd.cc b/components/dbus/xdg/systemd.cc
index 362a16447bf578923cb8a84674c277ae6c98228f..3cd9a55d540c07a4c53f5a62bec5cbea37c11838 100644
--- a/components/dbus/xdg/systemd.cc
+++ b/components/dbus/xdg/systemd.cc
@@ -4,9 +4,12 @@
#include "components/dbus/xdg/systemd.h"
+#include <string>
#include <vector>
#include "base/environment.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/no_destructor.h"
#include "base/sequence_checker.h"
@@ -17,7 +20,9 @@
#include "components/dbus/utils/name_has_owner.h"
#include "dbus/bus.h"
#include "dbus/message.h"
+#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
+#include "dbus/property.h"
#include "third_party/abseil-cpp/absl/types/variant.h"
namespace dbus_xdg {
@@ -37,6 +42,10 @@ constexpr char kServiceNameSystemd[] = "org.freedesktop.systemd1";
constexpr char kObjectPathSystemd[] = "/org/freedesktop/systemd1";
constexpr char kInterfaceSystemdManager[] = "org.freedesktop.systemd1.Manager";
constexpr char kMethodStartTransientUnit[] = "StartTransientUnit";
+constexpr char kMethodGetUnit[] = "GetUnit";
+
+constexpr char kInterfaceSystemdUnit[] = "org.freedesktop.systemd1.Unit";
+constexpr char kActiveStateProp[] = "ActiveState";
constexpr char kUnitNameFormat[] = "app-$1$2-$3.scope";
@@ -67,6 +76,81 @@ const char* GetAppNameSuffix(const std::string& channel) {
return "";
}
+// Declare this helper for SystemdUnitActiveStateWatcher to be used.
+void SetStateAndRunCallbacks(SystemdUnitStatus result);
+
+// Watches the object to become active and fires callbacks via
+// SetStateAndRunCallbacks. The callbacks are fired whenever a response with the
+// state being "active" or "failed" (or similar) comes.
+//
+// PS firing callbacks results in destroying this object. So any references
+// to this become invalid.
+class SystemdUnitActiveStateWatcher : public dbus::PropertySet {
+ public:
+ SystemdUnitActiveStateWatcher(scoped_refptr<dbus::Bus> bus,
+ dbus::ObjectProxy* object_proxy)
+ : dbus::PropertySet(object_proxy,
+ kInterfaceSystemdUnit,
+ base::BindRepeating(
+ &SystemdUnitActiveStateWatcher::OnPropertyChanged,
+ base::Unretained(this))),
+ bus_(bus) {
+ RegisterProperty(kActiveStateProp, &active_state_);
+ ConnectSignals();
+ GetAll();
+ }
+
+ ~SystemdUnitActiveStateWatcher() override {
+ bus_->RemoveObjectProxy(kServiceNameSystemd, object_proxy()->object_path(),
+ base::DoNothing());
+ }
+
+ private:
+ void OnPropertyChanged(const std::string& property_name) {
+ DCHECK(active_state_.is_valid());
+ const std::string state_value = active_state_.value();
+ if (callbacks_called_ || state_value == "activating" ||
+ state_value == "reloading") {
+ // Ignore if callbacks have already been fired or continue waiting until
+ // the state changes to something else.
+ return;
+ }
+
+ // There are other states as failed, inactive, and deactivating. Treat all
+ // of them as failed.
+ callbacks_called_ = true;
+ SetStateAndRunCallbacks(state_value == "active"
+ ? SystemdUnitStatus::kUnitStarted
+ : SystemdUnitStatus::kFailedToStart);
+ MaybeDeleteSelf();
+ }
+
+ void OnGetAll(dbus::Response* response) override {
+ dbus::PropertySet::OnGetAll(response);
+ keep_alive_ = false;
+ MaybeDeleteSelf();
+ }
+
+ void MaybeDeleteSelf() {
+ if (!keep_alive_ && callbacks_called_) {
+ delete this;
+ }
+ }
+
+ // Registered property that this listens updates to.
+ dbus::Property<std::string> active_state_;
+
+ // Indicates whether callbacks for the unit's state have been called.
+ bool callbacks_called_ = false;
+
+ // Control variable that helps to defer the destruction of |this| as deleting
+ // self when the state changes to active during |OnGetAll| will result in a
+ // segfault.
+ bool keep_alive_ = true;
+
+ scoped_refptr<dbus::Bus> bus_;
+};
+
// Global state for cached result or pending callbacks.
StatusOrCallbacks& GetUnitNameState() {
static base::NoDestructor<StatusOrCallbacks> state(
@@ -83,10 +167,52 @@ void SetStateAndRunCallbacks(SystemdUnitStatus result) {
}
}
-void OnStartTransientUnitResponse(dbus::Response* response) {
+void OnGetPathResponse(scoped_refptr<dbus::Bus> bus, dbus::Response* response) {
+ dbus::MessageReader reader(response);
+ dbus::ObjectPath obj_path;
+ if (!response || !reader.PopObjectPath(&obj_path) || !obj_path.IsValid()) {
+ // We didn't get a valid response. Treat this as failed service.
+ SetStateAndRunCallbacks(SystemdUnitStatus::kFailedToStart);
+ return;
+ }
+
+ dbus::ObjectProxy* unit_proxy =
+ bus->GetObjectProxy(kServiceNameSystemd, obj_path);
+ // Create the active state property watcher. It will destroy itself once
+ // it gets notified about the state change.
+ std::unique_ptr<SystemdUnitActiveStateWatcher> active_state_watcher =
+ std::make_unique<SystemdUnitActiveStateWatcher>(bus, unit_proxy);
+ active_state_watcher.release();
+}
+
+void WaitUnitActivateAndRunCallbacks(scoped_refptr<dbus::Bus> bus,
+ std::string unit_name) {
+ // Get the path of the unit, which looks similar to
+ // /org/freedesktop/systemd1/unit/app_2dorg_2echromium_2eChromium_2d3182191_2escope
+ // and then wait for it activation.
+ dbus::ObjectProxy* systemd = bus->GetObjectProxy(
+ kServiceNameSystemd, dbus::ObjectPath(kObjectPathSystemd));
+
+ dbus::MethodCall method_call(kInterfaceSystemdManager, kMethodGetUnit);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(unit_name);
+
+ systemd->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::BindOnce(&OnGetPathResponse, std::move(bus)));
+}
+
+void OnStartTransientUnitResponse(scoped_refptr<dbus::Bus> bus,
+ std::string unit_name,
+ dbus::Response* response) {
SystemdUnitStatus result = response ? SystemdUnitStatus::kUnitStarted
: SystemdUnitStatus::kFailedToStart;
- SetStateAndRunCallbacks(result);
+ // If the start of the unit failed, immediately notify the client. Otherwise,
+ // wait for its activation.
+ if (result == SystemdUnitStatus::kFailedToStart) {
+ SetStateAndRunCallbacks(result);
+ } else {
+ WaitUnitActivateAndRunCallbacks(std::move(bus), unit_name);
+ }
}
void OnNameHasOwnerResponse(scoped_refptr<dbus::Bus> bus,
@@ -128,8 +254,9 @@ void OnNameHasOwnerResponse(scoped_refptr<dbus::Bus> bus,
properties.Write(&writer);
// No auxiliary units.
Dict<VarDict>().Write(&writer);
- systemd->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
- base::BindOnce(&OnStartTransientUnitResponse));
+ systemd->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::BindOnce(&OnStartTransientUnitResponse, std::move(bus), unit_name));
}
} // namespace
diff --git a/components/dbus/xdg/systemd_unittest.cc b/components/dbus/xdg/systemd_unittest.cc
index 2e3baecabc4b479000c78d4f6bd30cb1f6e61d2e..67278d7033664d52fbbda02749a2aaa43352f402 100644
--- a/components/dbus/xdg/systemd_unittest.cc
+++ b/components/dbus/xdg/systemd_unittest.cc
@@ -16,7 +16,9 @@
#include "dbus/message.h"
#include "dbus/mock_bus.h"
#include "dbus/mock_object_proxy.h"
+#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
+#include "dbus/property.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -32,6 +34,27 @@ constexpr char kServiceNameSystemd[] = "org.freedesktop.systemd1";
constexpr char kObjectPathSystemd[] = "/org/freedesktop/systemd1";
constexpr char kInterfaceSystemdManager[] = "org.freedesktop.systemd1.Manager";
constexpr char kMethodStartTransientUnit[] = "StartTransientUnit";
+constexpr char kMethodGetUnit[] = "GetUnit";
+
+constexpr char kFakeUnitPath[] = "/fake/unit/path";
+constexpr char kActiveState[] = "ActiveState";
+constexpr char kStateActive[] = "active";
+constexpr char kStateInactive[] = "inactive";
+
+std::unique_ptr<dbus::Response> CreateActiveStateGetAllResponse(
+ const std::string& state) {
+ auto response = dbus::Response::CreateEmpty();
+ dbus::MessageWriter writer(response.get());
+ dbus::MessageWriter array_writer(nullptr);
+ dbus::MessageWriter dict_entry_writer(nullptr);
+ writer.OpenArray("{sv}", &array_writer);
+ array_writer.OpenDictEntry(&dict_entry_writer);
+ dict_entry_writer.AppendString(kActiveState);
+ dict_entry_writer.AppendVariantOfString(state);
+ array_writer.CloseContainer(&dict_entry_writer);
+ writer.CloseContainer(&array_writer);
+ return response;
+}
class SetSystemdScopeUnitNameForXdgPortalTest : public ::testing::Test {
public:
@@ -124,17 +147,48 @@ TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, StartTransientUnitSuccess) {
EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
dbus::ObjectPath(kObjectPathSystemd)))
- .WillOnce(Return(mock_systemd_proxy.get()));
+ .Times(2)
+ .WillRepeatedly(Return(mock_systemd_proxy.get()));
+
+ auto mock_dbus_unit_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kFakeUnitPath));
+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
+ dbus::ObjectPath(kFakeUnitPath)))
+ .WillOnce(Return(mock_dbus_unit_proxy.get()));
EXPECT_CALL(*mock_systemd_proxy, DoCallMethod(_, _, _))
.WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
dbus::ObjectProxy::ResponseCallback* callback) {
+ // Expect kMethodStartTransientUnit first.
EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
EXPECT_EQ(method_call->GetMember(), kMethodStartTransientUnit);
// Simulate a successful response
auto response = dbus::Response::CreateEmpty();
std::move(*callback).Run(response.get());
+ }))
+ .WillOnce(Invoke([obj_path = kFakeUnitPath](
+ dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ // Then expect kMethodGetUnit. A valid path must be provided.
+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
+ EXPECT_EQ(method_call->GetMember(), kMethodGetUnit);
+
+ // Simulate a successful response and provide a fake path to the object.
+ auto response = dbus::Response::CreateEmpty();
+ dbus::MessageWriter writer(response.get());
+ writer.AppendObjectPath(dbus::ObjectPath(obj_path));
+ std::move(*callback).Run(response.get());
+ }));
+
+ EXPECT_CALL(*mock_dbus_unit_proxy, DoCallMethod(_, _, _))
+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ EXPECT_EQ(method_call->GetInterface(), dbus::kPropertiesInterface);
+ EXPECT_EQ(method_call->GetMember(), dbus::kPropertiesGetAll);
+ // Simulate a successful response with "active" state.
+ auto response = CreateActiveStateGetAllResponse(kStateActive);
+ std::move(*callback).Run(response.get());
}));
std::optional<SystemdUnitStatus> status;
@@ -189,6 +243,142 @@ TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, StartTransientUnitFailure) {
EXPECT_EQ(status, SystemdUnitStatus::kFailedToStart);
}
+TEST_F(SetSystemdScopeUnitNameForXdgPortalTest,
+ StartTransientUnitInvalidUnitPath) {
+ scoped_refptr<dbus::MockBus> bus =
+ base::MakeRefCounted<dbus::MockBus>(dbus::Bus::Options());
+
+ auto mock_dbus_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
+ bus.get(), DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
+
+ EXPECT_CALL(
+ *bus, GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS)))
+ .WillRepeatedly(Return(mock_dbus_proxy.get()));
+
+ EXPECT_CALL(*mock_dbus_proxy, DoCallMethod(_, _, _))
+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ auto response = dbus::Response::CreateEmpty();
+ dbus::MessageWriter writer(response.get());
+ writer.AppendBool(true);
+ std::move(*callback).Run(response.get());
+ }));
+
+ auto mock_systemd_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kObjectPathSystemd));
+
+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
+ dbus::ObjectPath(kObjectPathSystemd)))
+ .Times(2)
+ .WillRepeatedly(Return(mock_systemd_proxy.get()));
+
+ EXPECT_CALL(*mock_systemd_proxy, DoCallMethod(_, _, _))
+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
+ EXPECT_EQ(method_call->GetMember(), kMethodStartTransientUnit);
+
+ // Simulate a successful response
+ auto response = dbus::Response::CreateEmpty();
+ std::move(*callback).Run(response.get());
+ }))
+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
+ EXPECT_EQ(method_call->GetMember(), kMethodGetUnit);
+
+ // Simulate a failure response.
+ std::move(*callback).Run(nullptr);
+ }));
+
+ std::optional<SystemdUnitStatus> status;
+
+ SetSystemdScopeUnitNameForXdgPortal(
+ bus.get(), base::BindLambdaForTesting(
+ [&](SystemdUnitStatus result) { status = result; }));
+
+ EXPECT_EQ(status, SystemdUnitStatus::kFailedToStart);
+}
+
+TEST_F(SetSystemdScopeUnitNameForXdgPortalTest,
+ StartTransientUnitFailToActivate) {
+ scoped_refptr<dbus::MockBus> bus =
+ base::MakeRefCounted<dbus::MockBus>(dbus::Bus::Options());
+
+ auto mock_dbus_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
+ bus.get(), DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
+
+ EXPECT_CALL(
+ *bus, GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS)))
+ .WillRepeatedly(Return(mock_dbus_proxy.get()));
+
+ EXPECT_CALL(*mock_dbus_proxy, DoCallMethod(_, _, _))
+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ auto response = dbus::Response::CreateEmpty();
+ dbus::MessageWriter writer(response.get());
+ writer.AppendBool(true);
+ std::move(*callback).Run(response.get());
+ }));
+
+ auto mock_systemd_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kObjectPathSystemd));
+
+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
+ dbus::ObjectPath(kObjectPathSystemd)))
+ .Times(2)
+ .WillRepeatedly(Return(mock_systemd_proxy.get()));
+
+ auto mock_dbus_unit_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kFakeUnitPath));
+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
+ dbus::ObjectPath(kFakeUnitPath)))
+ .WillOnce(Return(mock_dbus_unit_proxy.get()));
+
+ EXPECT_CALL(*mock_systemd_proxy, DoCallMethod(_, _, _))
+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
+ EXPECT_EQ(method_call->GetMember(), kMethodStartTransientUnit);
+
+ // Simulate a successful response
+ auto response = dbus::Response::CreateEmpty();
+ std::move(*callback).Run(response.get());
+ }))
+ .WillOnce(Invoke([obj_path = kFakeUnitPath](
+ dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
+ EXPECT_EQ(method_call->GetMember(), kMethodGetUnit);
+
+ // Simulate a successful response
+ auto response = dbus::Response::CreateEmpty();
+ dbus::MessageWriter writer(response.get());
+ writer.AppendObjectPath(dbus::ObjectPath(obj_path));
+ std::move(*callback).Run(response.get());
+ }));
+
+ EXPECT_CALL(*mock_dbus_unit_proxy, DoCallMethod(_, _, _))
+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ // Then expect kMethodGetUnit. A valid path must be provided.
+ EXPECT_EQ(method_call->GetInterface(), dbus::kPropertiesInterface);
+ EXPECT_EQ(method_call->GetMember(), dbus::kPropertiesGetAll);
+
+ // Simulate a successful response, but with inactive state.
+ auto response = CreateActiveStateGetAllResponse(kStateInactive);
+ std::move(*callback).Run(response.get());
+ }));
+
+ std::optional<SystemdUnitStatus> status;
+
+ SetSystemdScopeUnitNameForXdgPortal(
+ bus.get(), base::BindLambdaForTesting(
+ [&](SystemdUnitStatus result) { status = result; }));
+
+ EXPECT_EQ(status, SystemdUnitStatus::kFailedToStart);
+}
+
TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, UnitNameConstruction) {
scoped_refptr<dbus::MockBus> bus =
base::MakeRefCounted<dbus::MockBus>(dbus::Bus::Options());
@@ -220,7 +410,14 @@ TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, UnitNameConstruction) {
EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
dbus::ObjectPath(kObjectPathSystemd)))
- .WillOnce(Return(mock_systemd_proxy.get()));
+ .Times(2)
+ .WillRepeatedly(Return(mock_systemd_proxy.get()));
+
+ auto mock_dbus_unit_proxy = base::MakeRefCounted<dbus::MockObjectProxy>(
+ bus.get(), kServiceNameSystemd, dbus::ObjectPath(kFakeUnitPath));
+ EXPECT_CALL(*bus, GetObjectProxy(kServiceNameSystemd,
+ dbus::ObjectPath(kFakeUnitPath)))
+ .WillOnce(Return(mock_dbus_unit_proxy.get()));
EXPECT_CALL(*mock_systemd_proxy, DoCallMethod(_, _, _))
.WillOnce(Invoke([&](dbus::MethodCall* method_call, int timeout_ms,
@@ -256,6 +453,30 @@ TEST_F(SetSystemdScopeUnitNameForXdgPortalTest, UnitNameConstruction) {
auto response = dbus::Response::CreateEmpty();
std::move(*callback).Run(response.get());
+ }))
+ .WillOnce(Invoke([obj_path = kFakeUnitPath](
+ dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ EXPECT_EQ(method_call->GetInterface(), kInterfaceSystemdManager);
+ EXPECT_EQ(method_call->GetMember(), kMethodGetUnit);
+
+ // Simulate a successful response
+ auto response = dbus::Response::CreateEmpty();
+ dbus::MessageWriter writer(response.get());
+ writer.AppendObjectPath(dbus::ObjectPath(obj_path));
+ std::move(*callback).Run(response.get());
+ }));
+
+ EXPECT_CALL(*mock_dbus_unit_proxy, DoCallMethod(_, _, _))
+ .WillOnce(Invoke([](dbus::MethodCall* method_call, int timeout_ms,
+ dbus::ObjectProxy::ResponseCallback* callback) {
+ // Then expect kMethodGetUnit. A valid path must be provided.
+ EXPECT_EQ(method_call->GetInterface(), dbus::kPropertiesInterface);
+ EXPECT_EQ(method_call->GetMember(), dbus::kPropertiesGetAll);
+
+ // Simulate a successful response
+ auto response = CreateActiveStateGetAllResponse(kStateActive);
+ std::move(*callback).Run(response.get());
}));
std::optional<SystemdUnitStatus> status;

View File

@@ -0,0 +1,168 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: deepak1556 <hop2deep@gmail.com>
Date: Wed, 29 Jan 2025 17:01:03 +0900
Subject: feat: add signals when embedder cleanup callbacks run for
gin::wrappable
Current setup of finalization callbacks does not work well with
gin_helper::CleanedUpAtExit for wrappables specifically on environment
shutdown leading to UAF in the second pass.
Details at https://github.com/microsoft/vscode/issues/192119#issuecomment-2375851531
The signals exposed in this patch does the following 2 things,
1) Fix weak state of the wrapped object when the finializer callbacks
have not yet been processed
2) Avoid calling into the second pass when the embedder has already
destroyed the wrapped object via CleanedUpAtExit.
This patch is more of a bandaid fix to improve the lifetime
management with existing finalizer callbacks. We should be able to
remove this patch once gin::Wrappable can be managed by V8 Oilpan
Refs https://issues.chromium.org/issues/40210365 which is blocked
on https://issues.chromium.org/issues/42203693
diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc
index e5ee2c6b3cb787ff9f8272d4344a1e18c44971e2..22469cf0ab1025eefcf94e2cd351087e52182130 100644
--- a/gin/isolate_holder.cc
+++ b/gin/isolate_holder.cc
@@ -34,6 +34,8 @@ v8::ArrayBuffer::Allocator* g_array_buffer_allocator = nullptr;
const intptr_t* g_reference_table = nullptr;
v8::FatalErrorCallback g_fatal_error_callback = nullptr;
v8::OOMErrorCallback g_oom_error_callback = nullptr;
+bool g_initialized_microtasks_runner = false;
+bool g_destroyed_microtasks_runner = false;
std::unique_ptr<v8::Isolate::CreateParams> getModifiedIsolateParams(
std::unique_ptr<v8::Isolate::CreateParams> params,
@@ -194,10 +196,26 @@ IsolateHolder::getDefaultIsolateParams() {
return params;
}
+// static
+bool IsolateHolder::DestroyedMicrotasksRunner() {
+ return g_initialized_microtasks_runner &&
+ g_destroyed_microtasks_runner;
+}
+
void IsolateHolder::EnableIdleTasks(
std::unique_ptr<V8IdleTaskRunner> idle_task_runner) {
DCHECK(isolate_data_.get());
isolate_data_->EnableIdleTasks(std::move(idle_task_runner));
}
+void IsolateHolder::WillCreateMicrotasksRunner() {
+ DCHECK(!g_initialized_microtasks_runner);
+ g_initialized_microtasks_runner = true;
+}
+
+void IsolateHolder::WillDestroyMicrotasksRunner() {
+ DCHECK(g_initialized_microtasks_runner);
+ g_destroyed_microtasks_runner = true;
+}
+
} // namespace gin
diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h
index c22b0a7f9af621573e888a518ccdc22293ce07ef..d3e5ced425df54f42534cec5cc0c5bbfb9d79c6c 100644
--- a/gin/public/isolate_holder.h
+++ b/gin/public/isolate_holder.h
@@ -130,6 +130,8 @@ class GIN_EXPORT IsolateHolder {
// Should only be called after v8::IsolateHolder::Initialize() is invoked.
static std::unique_ptr<v8::Isolate::CreateParams> getDefaultIsolateParams();
+ static bool DestroyedMicrotasksRunner();
+
v8::Isolate* isolate() { return isolate_; }
// This method returns if v8::Locker is needed to access isolate.
@@ -143,6 +145,9 @@ class GIN_EXPORT IsolateHolder {
void EnableIdleTasks(std::unique_ptr<V8IdleTaskRunner> idle_task_runner);
+ void WillCreateMicrotasksRunner();
+ void WillDestroyMicrotasksRunner();
+
// This method returns V8IsolateMemoryDumpProvider of this isolate, used for
// testing.
V8IsolateMemoryDumpProvider* isolate_memory_dump_provider_for_testing()
diff --git a/gin/wrappable.cc b/gin/wrappable.cc
index 402355cb836cea14e9ee725a142a4bad44fd5bed..7e7f028dcfb87c7b80adebabac19ced8791f642e 100644
--- a/gin/wrappable.cc
+++ b/gin/wrappable.cc
@@ -13,6 +13,9 @@ namespace gin {
WrappableBase::WrappableBase() = default;
WrappableBase::~WrappableBase() {
+ if (!wrapper_.IsEmpty()) {
+ wrapper_.ClearWeak();
+ }
wrapper_.Reset();
}
@@ -28,15 +31,24 @@ const char* WrappableBase::GetTypeName() {
void WrappableBase::FirstWeakCallback(
const v8::WeakCallbackInfo<WrappableBase>& data) {
WrappableBase* wrappable = data.GetParameter();
- wrappable->dead_ = true;
- wrappable->wrapper_.Reset();
- data.SetSecondPassCallback(SecondWeakCallback);
+ WrappableBase* wrappable_from_field =
+ static_cast<WrappableBase*>(data.GetInternalField(1));
+ if (wrappable && wrappable == wrappable_from_field) {
+ wrappable->dead_ = true;
+ wrappable->wrapper_.Reset();
+ data.SetSecondPassCallback(SecondWeakCallback);
+ }
}
void WrappableBase::SecondWeakCallback(
const v8::WeakCallbackInfo<WrappableBase>& data) {
+ if (IsolateHolder::DestroyedMicrotasksRunner()) {
+ return;
+ }
WrappableBase* wrappable = data.GetParameter();
- delete wrappable;
+ if (wrappable) {
+ delete wrappable;
+ }
}
v8::MaybeLocal<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate,
@@ -71,10 +83,16 @@ v8::MaybeLocal<v8::Object> WrappableBase::GetWrapperImpl(v8::Isolate* isolate,
void* values[] = {info, this};
wrapper->SetAlignedPointerInInternalFields(2, indices, values);
wrapper_.Reset(isolate, wrapper);
- wrapper_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
+ wrapper_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kInternalFields);
return v8::MaybeLocal<v8::Object>(wrapper);
}
+void WrappableBase::ClearWeak() {
+ if (!wrapper_.IsEmpty()) {
+ wrapper_.ClearWeak();
+ }
+}
+
namespace internal {
void* FromV8Impl(v8::Isolate* isolate, v8::Local<v8::Value> val,
diff --git a/gin/wrappable.h b/gin/wrappable.h
index 4e7115685a5bf6997e78edcc1851e28bd00b1aa2..ca51fe33605e855438e88969e3d3cc734ef4523e 100644
--- a/gin/wrappable.h
+++ b/gin/wrappable.h
@@ -80,6 +80,13 @@ class GIN_EXPORT WrappableBase {
v8::MaybeLocal<v8::Object> GetWrapperImpl(v8::Isolate* isolate,
WrapperInfo* wrapper_info);
+ // Make this wrappable strong again. This is useful when the wrappable is
+ // destroyed outside the finalizer callbacks and we want to avoid scheduling
+ // the weak callbacks if they haven't been scheduled yet.
+ // NOTE!!! this does not prevent finalization callbacks from running if they
+ // have already been processed.
+ void ClearWeak();
+
private:
static void FirstWeakCallback(
const v8::WeakCallbackInfo<WrappableBase>& data);

View File

@@ -14,10 +14,25 @@ It also:
This may be partially upstreamed to Chromium in the future.
diff --git a/ui/gtk/select_file_dialog_linux_gtk.cc b/ui/gtk/select_file_dialog_linux_gtk.cc
index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a846f0d923 100644
index b83f0177a2adb0a19be49684f865941e6708f626..a8c7032cfc122b97665c41da9e1191e747b95a33 100644
--- a/ui/gtk/select_file_dialog_linux_gtk.cc
+++ b/ui/gtk/select_file_dialog_linux_gtk.cc
@@ -407,9 +407,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
@@ -259,8 +259,12 @@ void SelectFileDialogLinuxGtk::SelectFileImpl(
case SELECT_EXISTING_FOLDER:
dialog = CreateSelectFolderDialog(type, title_string, default_path,
owning_window);
- connect("response",
- &SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse);
+ if (allow_multiple_selection())
+ connect("response",
+ &SelectFileDialogLinuxGtk::OnSelectMultiFolderDialogResponse);
+ else
+ connect("response",
+ &SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse);
break;
case SELECT_OPEN_FILE:
dialog = CreateFileOpenDialog(title_string, default_path, owning_window);
@@ -407,9 +411,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
const std::string& title,
const base::FilePath& default_path,
gfx::NativeWindow parent) {
@@ -30,7 +45,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
SetGtkTransientForAura(dialog, parent);
AddFilters(GTK_FILE_CHOOSER(dialog));
@@ -425,6 +427,7 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
@@ -425,6 +431,7 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog),
*last_opened_path());
}
@@ -38,7 +53,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
return dialog;
}
@@ -440,11 +443,15 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
@@ -440,11 +447,15 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
? l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE)
: l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE);
}
@@ -59,7 +74,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
GtkWidget* dialog = GtkFileChooserDialogNew(
title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
@@ -466,7 +473,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
@@ -466,7 +477,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
gtk_file_filter_add_mime_type(only_folders, "inode/directory");
gtk_file_filter_add_mime_type(only_folders, "text/directory");
gtk_file_chooser_add_filter(chooser, only_folders);
@@ -69,7 +84,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
return dialog;
}
@@ -503,10 +511,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
@@ -503,10 +515,11 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
std::string title_string =
!title.empty() ? title
: l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE);
@@ -83,7 +98,7 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
GTK_RESPONSE_ACCEPT);
SetGtkTransientForAura(dialog, parent);
@@ -532,9 +541,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
@@ -532,9 +545,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
// Overwrite confirmation is always enabled in GTK4.
if (!GtkCheckVersion(4)) {
@@ -96,6 +111,65 @@ index b83f0177a2adb0a19be49684f865941e6708f626..f313c766ddc2b79f082e70138dd566a8
return dialog;
}
@@ -589,15 +603,29 @@ void SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse(
void SelectFileDialogLinuxGtk::OnSelectMultiFileDialogResponse(
GtkWidget* dialog,
int response_id) {
+ SelectMultiFileHelper(dialog, response_id, false);
+}
+
+void SelectFileDialogLinuxGtk::OnSelectMultiFolderDialogResponse(
+ GtkWidget* dialog,
+ int response_id) {
+ SelectMultiFileHelper(dialog, response_id, true);
+}
+
+void SelectFileDialogLinuxGtk::SelectMultiFileHelper(GtkWidget* dialog,
+ int response_id,
+ bool allow_folder) {
if (IsCancelResponse(response_id)) {
FileNotSelected(dialog);
return;
}
auto filenames = GtkFileChooserGetFilenames(dialog);
- std::erase_if(filenames, [this](const base::FilePath& path) {
- return CallDirectoryExistsOnUIThread(path);
+ std::erase_if(filenames, [this, &allow_folder](const base::FilePath& path) {
+ bool directory_exists = CallDirectoryExistsOnUIThread(path);
+ return !allow_folder && directory_exists;
});
+
if (filenames.empty()) {
FileNotSelected(dialog);
return;
diff --git a/ui/gtk/select_file_dialog_linux_gtk.h b/ui/gtk/select_file_dialog_linux_gtk.h
index 213eaa5ec6d657a659726cb38103e8bd671fe907..f497447c598198bf690758b1d1c5c6fe4112627f 100644
--- a/ui/gtk/select_file_dialog_linux_gtk.h
+++ b/ui/gtk/select_file_dialog_linux_gtk.h
@@ -108,6 +108,12 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
gint response_id,
bool allow_folder);
+ // Common function for OnSelectMultiFileDialogResponse and
+ // OnSelectMultiFolderDialogResponse.
+ void SelectMultiFileHelper(GtkWidget* dialog,
+ gint response_id,
+ bool allow_folder);
+
// Common function for CreateFileOpenDialog and CreateMultiFileOpenDialog.
GtkWidget* CreateFileOpenHelper(const std::string& title,
const base::FilePath& default_path,
@@ -122,6 +128,9 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
// Callback for when the user responds to a Open Multiple Files dialog.
void OnSelectMultiFileDialogResponse(GtkWidget* dialog, int response_id);
+ // Callback for when the user responds to a Select Multiple Folders dialog.
+ void OnSelectMultiFolderDialogResponse(GtkWidget* dialog, int response_id);
+
// Callback for when the file chooser gets destroyed.
void OnFileChooserDestroy(GtkWidget* dialog);
diff --git a/ui/shell_dialogs/select_file_dialog.h b/ui/shell_dialogs/select_file_dialog.h
index eb3d997598631b220c3566748f23a5cdac3e4692..b4b2f7294ce6e9349a4a8a05f614e93359eca25a 100644
--- a/ui/shell_dialogs/select_file_dialog.h
@@ -186,18 +260,90 @@ index 61683d0eddb04c494ca5e650e7d556b44968ec49..5492456a9138b250e97a5479838bb443
} // namespace ui
diff --git a/ui/shell_dialogs/select_file_dialog_linux_kde.cc b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
index 64a79ebe2e2d21d5a6b4a98042d1cdb7b6edad52..16f2ae01a8d33e6341ed52638e963c340455ebf8 100644
index 64a79ebe2e2d21d5a6b4a98042d1cdb7b6edad52..748c2506781a237641b25b426876be14c8b7ba82 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_kde.cc
+++ b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
@@ -468,7 +468,7 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
@@ -154,9 +154,20 @@ class SelectFileDialogLinuxKde : public SelectFileDialogLinux {
void OnSelectMultiFileDialogResponse(
gfx::AcceleratedWidget parent,
std::unique_ptr<KDialogOutputParams> results);
+
+ // Common function for OnSelectSingleFolderDialogResponse and
+ // OnSelectMultiFileDialogResponse.
+ void SelectMultiFileDialogHelper(
+ bool allow_folder,
+ gfx::AcceleratedWidget parent,
+ std::unique_ptr<KDialogOutputParams> results);
+
void OnSelectSingleFolderDialogResponse(
gfx::AcceleratedWidget parent,
std::unique_ptr<KDialogOutputParams> results);
+ void OnSelectMultiFolderDialogResponse(
+ gfx::AcceleratedWidget parent,
+ std::unique_ptr<KDialogOutputParams> results);
// Should be either DESKTOP_ENVIRONMENT_KDE3, KDE4, KDE5, or KDE6.
base::nix::DesktopEnvironment desktop_;
@@ -461,6 +472,7 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
int title_message_id = (type == SELECT_UPLOAD_FOLDER)
? IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE
: IDS_SELECT_FOLDER_DIALOG_TITLE;
+ bool multiple_selection = allow_multiple_selection();
pipe_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
@@ -468,10 +480,12 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
KDialogParams(
"--getexistingdirectory", GetTitle(title, title_message_id),
default_path.empty() ? *last_opened_path() : default_path, parent,
- false, false)),
+ false, allow_multiple_selection())),
+ false, multiple_selection)),
base::BindOnce(
&SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
parent));
- &SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
- parent));
+ multiple_selection
+ ? &SelectFileDialogLinuxKde::OnSelectMultiFolderDialogResponse
+ : &SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse,
+ this, parent));
}
void SelectFileDialogLinuxKde::CreateFileOpenDialog(
@@ -561,7 +575,8 @@ void SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse(
SelectSingleFileHelper(true, std::move(results));
}
-void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
+void SelectFileDialogLinuxKde::SelectMultiFileDialogHelper(
+ bool allow_folder,
gfx::AcceleratedWidget parent,
std::unique_ptr<KDialogOutputParams> results) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -579,7 +594,7 @@ void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
base::SplitStringPiece(results->output, "\n", base::KEEP_WHITESPACE,
base::SPLIT_WANT_NONEMPTY)) {
base::FilePath path(line);
- if (CallDirectoryExistsOnUIThread(path))
+ if (!allow_folder && CallDirectoryExistsOnUIThread(path))
continue;
filenames_fp.push_back(path);
}
@@ -591,4 +606,16 @@ void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
MultiFilesSelected(filenames_fp);
}
+void SelectFileDialogLinuxKde::OnSelectMultiFolderDialogResponse(
+ gfx::AcceleratedWidget parent,
+ std::unique_ptr<KDialogOutputParams> results) {
+ SelectMultiFileDialogHelper(true, parent, std::move(results));
+}
+
+void SelectFileDialogLinuxKde::OnSelectMultiFileDialogResponse(
+ gfx::AcceleratedWidget parent,
+ std::unique_ptr<KDialogOutputParams> results) {
+ SelectMultiFileDialogHelper(false, parent, std::move(results));
+}
+
} // namespace ui
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.cc b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
index 9780c80ffff7bdb715a9adcb656e5d33be974db6..cf6edf5c68a8e2f8ffda119b58c6283bc43199c0 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.cc

View File

@@ -10,17 +10,6 @@ however those files were cherry-picked from main branch and do not
really in 20/21. We have to wait until 22 is released to be able to
build with upstream GN files.
diff --git a/deps/simdjson/unofficial.gni b/deps/simdjson/unofficial.gni
index d6909b95886f4de3f0b953c2a2992f69066b7434..972955f9144aafcd3a3fe278b7aaad401cadddda 100644
--- a/deps/simdjson/unofficial.gni
+++ b/deps/simdjson/unofficial.gni
@@ -18,5 +18,6 @@ template("simdjson_gn_build") {
forward_variables_from(invoker, "*")
public_configs = [ ":simdjson_config" ]
sources = gypi_values.simdjson_sources
+ cflags_c = [ "-Wdeprecated-literal-operator" ]
}
}
diff --git a/deps/sqlite/unofficial.gni b/deps/sqlite/unofficial.gni
index ebb3ffcd6d42b4c16b6865a91ccf4428cffe864b..00225afa1fb4205f1e02d9f185aeb97d642b3fd9 100644
--- a/deps/sqlite/unofficial.gni
@@ -42,7 +31,7 @@ index ebb3ffcd6d42b4c16b6865a91ccf4428cffe864b..00225afa1fb4205f1e02d9f185aeb97d
"-Wno-unused-but-set-variable",
"-Wno-unused-function",
diff --git a/node.gni b/node.gni
index 9dca810decebd75aab427e306b3cc37c80fb55c9..852f64fa9cfb50fe6e9ce7aa46be336d3196d5b8 100644
index 9dca810decebd75aab427e306b3cc37c80fb55c9..32709b860ccb12d8d1e75342a65dda0b86129b21 100644
--- a/node.gni
+++ b/node.gni
@@ -5,10 +5,10 @@
@@ -67,29 +56,20 @@ index 9dca810decebd75aab427e306b3cc37c80fb55c9..852f64fa9cfb50fe6e9ce7aa46be336d
# Custom build tag.
node_tag = ""
@@ -58,7 +58,16 @@ declare_args() {
@@ -58,7 +58,7 @@ declare_args() {
# TODO(zcbenz): There are few broken things for now:
# 1. cross-os compilation is not supported.
# 2. node_mksnapshot crashes when cross-compiling for x64 from arm64.
- node_use_node_snapshot = (host_os == target_os) && !(host_cpu == "arm64" && target_cpu == "x64")
+ node_use_node_snapshot = false
+
+ # Build with Amaro (TypeScript utils).
+ node_use_amaro = true
+
+ # Allows downstream packagers (eg. Linux distributions) to build against system shared libraries.
+ use_system_cares = false
+ use_system_nghttp2 = false
+ use_system_llhttp = false
+ use_system_histogram = false
}
assert(!node_enable_inspector || node_use_openssl,
diff --git a/src/node_builtins.cc b/src/node_builtins.cc
index 1bec44f6f29b0b652e92d2bb336fdb74b85eee30..599b59873dbb17ae5e7463403859e088ffb86cda 100644
index 2bc7155f7c075e5a22ece7159a64a1c9ba3d8ac9..48d29a0d05538cd1d992f3f086d826e78d0d8882 100644
--- a/src/node_builtins.cc
+++ b/src/node_builtins.cc
@@ -778,6 +778,7 @@ void BuiltinLoader::RegisterExternalReferences(
@@ -775,6 +775,7 @@ void BuiltinLoader::RegisterExternalReferences(
registry->Register(GetNatives);
RegisterExternalReferencesForInternalizedBuiltinCode(registry);
@@ -111,7 +91,7 @@ index 1cb85b9058d06555382e565dc32192a9fa48ed9f..cec9be01abd107e8612f70daf19b4834
// Handles compilation and caching of built-in JavaScript modules and
// bootstrap scripts, whose source are bundled into the binary as static data.
diff --git a/tools/generate_config_gypi.py b/tools/generate_config_gypi.py
index 45b3ac5006140fb55aad0e6b78084b753a947a76..35cce2ea8fd85f21582962115ac455918d4c4553 100755
index 45b3ac5006140fb55aad0e6b78084b753a947a76..8667857107e4f2481fd98032d4333b086fb7b479 100755
--- a/tools/generate_config_gypi.py
+++ b/tools/generate_config_gypi.py
@@ -21,7 +21,7 @@ import getnapibuildversion
@@ -123,14 +103,6 @@ index 45b3ac5006140fb55aad0e6b78084b753a947a76..35cce2ea8fd85f21582962115ac45591
else:
GN = 'gn'
@@ -65,6 +65,7 @@ def translate_config(out_dir, config, v8_config):
eval(config['node_builtin_shareable_builtins']),
'node_module_version': int(config['node_module_version']),
'node_use_openssl': config['node_use_openssl'],
+ 'node_use_amaro': config['node_use_amaro'],
'node_use_node_code_cache': config['node_use_node_code_cache'],
'node_use_node_snapshot': config['node_use_node_snapshot'],
'v8_enable_inspector': # this is actually a node misnomer
diff --git a/tools/install.py b/tools/install.py
index bf54249b66c0d4e179deaae5a9fd55568e694fe0..31b94d2e4b532d3b8202b512e2d2f41d29a2a546 100755
--- a/tools/install.py
@@ -146,10 +118,10 @@ index bf54249b66c0d4e179deaae5a9fd55568e694fe0..31b94d2e4b532d3b8202b512e2d2f41d
diff --git a/tools/js2c.cc b/tools/js2c.cc
old mode 100644
new mode 100755
index 21992cbe894a880e3223c379326b62db22f2f12d..1296a5457422099035ba34f2b02624f2e9dfb0f0
index a536b5dcd857275d3b02e361bd7d37a939f6b573..b2d5678d58a79774d5aeedc15ac5d5fd786f64bb
--- a/tools/js2c.cc
+++ b/tools/js2c.cc
@@ -28,6 +28,7 @@ namespace js2c {
@@ -30,6 +30,7 @@ namespace js2c {
int Main(int argc, char* argv[]);
static bool is_verbose = false;
@@ -157,7 +129,7 @@ index 21992cbe894a880e3223c379326b62db22f2f12d..1296a5457422099035ba34f2b02624f2
void Debug(const char* format, ...) {
va_list arguments;
@@ -175,6 +176,7 @@ const char* kTemplate = R"(
@@ -196,6 +197,7 @@ const char* kTemplate = R"(
#include "node_builtins.h"
#include "node_external_reference.h"
#include "node_internals.h"
@@ -165,7 +137,7 @@ index 21992cbe894a880e3223c379326b62db22f2f12d..1296a5457422099035ba34f2b02624f2
namespace node {
@@ -190,7 +192,11 @@ const ThreadsafeCopyOnWrite<BuiltinSourceMap> global_source_map {
@@ -211,7 +213,11 @@ const ThreadsafeCopyOnWrite<BuiltinSourceMap> global_source_map {
} // anonymous namespace
void BuiltinLoader::LoadJavaScriptSource() {
@@ -178,7 +150,7 @@ index 21992cbe894a880e3223c379326b62db22f2f12d..1296a5457422099035ba34f2b02624f2
}
void RegisterExternalReferencesForInternalizedBuiltinCode(
@@ -207,6 +213,45 @@ UnionBytes BuiltinLoader::GetConfig() {
@@ -228,6 +234,45 @@ UnionBytes BuiltinLoader::GetConfig() {
} // namespace node
)";
@@ -224,7 +196,7 @@ index 21992cbe894a880e3223c379326b62db22f2f12d..1296a5457422099035ba34f2b02624f2
Fragment Format(const Fragments& definitions,
const Fragments& initializers,
const Fragments& registrations) {
@@ -216,13 +261,12 @@ Fragment Format(const Fragments& definitions,
@@ -237,13 +282,12 @@ Fragment Format(const Fragments& definitions,
size_t init_size = init_buf.size();
std::vector<char> reg_buf = Join(registrations, "\n");
size_t reg_size = reg_buf.size();
@@ -241,7 +213,7 @@ index 21992cbe894a880e3223c379326b62db22f2f12d..1296a5457422099035ba34f2b02624f2
static_cast<int>(def_buf.size()),
def_buf.data(),
static_cast<int>(init_buf.size()),
@@ -846,12 +890,15 @@ int JS2C(const FileList& js_files,
@@ -834,12 +878,15 @@ int JS2C(const FileList& js_files,
}
}
@@ -257,7 +229,7 @@ index 21992cbe894a880e3223c379326b62db22f2f12d..1296a5457422099035ba34f2b02624f2
Fragment out = Format(definitions, initializers, registrations);
return WriteIfChanged(out, dest);
}
@@ -877,6 +924,8 @@ int Main(int argc, char* argv[]) {
@@ -865,6 +912,8 @@ int Main(int argc, char* argv[]) {
std::string arg(argv[i]);
if (arg == "--verbose") {
is_verbose = true;
@@ -266,7 +238,7 @@ index 21992cbe894a880e3223c379326b62db22f2f12d..1296a5457422099035ba34f2b02624f2
} else if (arg == "--root") {
if (i == argc - 1) {
fprintf(stderr, "--root must be followed by a path\n");
@@ -925,6 +974,14 @@ int Main(int argc, char* argv[]) {
@@ -913,6 +962,14 @@ int Main(int argc, char* argv[]) {
}
}
@@ -281,7 +253,7 @@ index 21992cbe894a880e3223c379326b62db22f2f12d..1296a5457422099035ba34f2b02624f2
// Should have exactly 3 types: `.js`, `.mjs` and `.gypi`.
assert(file_map.size() == 3);
auto gypi_it = file_map.find(".gypi");
@@ -951,6 +1008,7 @@ int Main(int argc, char* argv[]) {
@@ -939,6 +996,7 @@ int Main(int argc, char* argv[]) {
std::sort(mjs_it->second.begin(), mjs_it->second.end());
return JS2C(js_it->second, mjs_it->second, gypi_it->second[0], output);
@@ -302,22 +274,10 @@ index 65d0e1be42f0a85418491ebb548278cf431aa6a0..d4a31342f1c6107b029394c6e1d00a1d
except Exception as e:
print(str(e))
diff --git a/unofficial.gni b/unofficial.gni
index c3b311e4a7f5444b07d4d7028d4621806959804e..f6793b8bf22d6ac911a1977edaa881b6dbbe7ac7 100644
index c3b311e4a7f5444b07d4d7028d4621806959804e..de6ff5548ca5282199b7d85c11941c1fa351a9d9 100644
--- a/unofficial.gni
+++ b/unofficial.gni
@@ -22,6 +22,11 @@ template("node_gn_build") {
} else {
defines += [ "HAVE_OPENSSL=0" ]
}
+ if (node_use_amaro) {
+ defines += [ "HAVE_AMARO=1" ]
+ } else {
+ defines += [ "HAVE_AMARO=0" ]
+ }
if (node_use_v8_platform) {
defines += [ "NODE_USE_V8_PLATFORM=1" ]
} else {
@@ -139,6 +144,7 @@ template("node_gn_build") {
@@ -139,6 +139,7 @@ template("node_gn_build") {
public_deps = [
"deps/ada",
"deps/uv",
@@ -325,7 +285,7 @@ index c3b311e4a7f5444b07d4d7028d4621806959804e..f6793b8bf22d6ac911a1977edaa881b6
"deps/simdjson",
"$node_v8_path",
]
@@ -150,7 +156,6 @@ template("node_gn_build") {
@@ -150,7 +151,6 @@ template("node_gn_build") {
"deps/llhttp",
"deps/nbytes",
"deps/nghttp2",
@@ -333,7 +293,7 @@ index c3b311e4a7f5444b07d4d7028d4621806959804e..f6793b8bf22d6ac911a1977edaa881b6
"deps/postject",
"deps/simdutf",
"deps/sqlite",
@@ -159,7 +164,11 @@ template("node_gn_build") {
@@ -159,7 +159,11 @@ template("node_gn_build") {
"$node_v8_path:v8_libplatform",
]
@@ -345,7 +305,7 @@ index c3b311e4a7f5444b07d4d7028d4621806959804e..f6793b8bf22d6ac911a1977edaa881b6
"$target_gen_dir/node_javascript.cc",
] + gypi_values.node_sources
@@ -178,8 +187,10 @@ template("node_gn_build") {
@@ -178,8 +182,10 @@ template("node_gn_build") {
deps += [ "//third_party/icu" ]
}
if (node_use_openssl) {
@@ -358,7 +318,7 @@ index c3b311e4a7f5444b07d4d7028d4621806959804e..f6793b8bf22d6ac911a1977edaa881b6
sources += gypi_values.node_crypto_sources
}
if (node_enable_inspector) {
@@ -276,6 +287,7 @@ template("node_gn_build") {
@@ -276,6 +282,7 @@ template("node_gn_build") {
}
executable("node_js2c") {
@@ -366,7 +326,7 @@ index c3b311e4a7f5444b07d4d7028d4621806959804e..f6793b8bf22d6ac911a1977edaa881b6
deps = [
"deps/simdutf",
"deps/uv",
@@ -286,26 +298,75 @@ template("node_gn_build") {
@@ -286,26 +293,75 @@ template("node_gn_build") {
"src/embedded_data.cc",
"src/embedded_data.h",
]
@@ -452,7 +412,7 @@ index c3b311e4a7f5444b07d4d7028d4621806959804e..f6793b8bf22d6ac911a1977edaa881b6
outputs = [ "$target_gen_dir/node_javascript.cc" ]
# Get the path to node_js2c executable of the host toolchain.
@@ -319,11 +380,11 @@ template("node_gn_build") {
@@ -319,11 +375,11 @@ template("node_gn_build") {
get_label_info(":node_js2c($host_toolchain)", "name") +
host_executable_suffix

View File

@@ -13,11 +13,28 @@ We don't need to do this for zlib, as the existing gn workflow uses the same
Upstreamed at https://github.com/nodejs/node/pull/55903
diff --git a/node.gni b/node.gni
index 18d58591e3d0f1f3512db00033c3410a65702864..99ec540ec41ddf5682eed7618ba87d6935b3b982 100644
--- a/node.gni
+++ b/node.gni
@@ -61,6 +61,12 @@ declare_args() {
# 1. cross-os compilation is not supported.
# 2. node_mksnapshot crashes when cross-compiling for x64 from arm64.
node_use_node_snapshot = false
+
+ # Allows downstream packagers (eg. Linux distributions) to build against system shared libraries.
+ use_system_cares = false
+ use_system_nghttp2 = false
+ use_system_llhttp = false
+ use_system_histogram = false
}
assert(!node_enable_inspector || node_use_openssl,
diff --git a/unofficial.gni b/unofficial.gni
index ddfbb97276b29df114ab455a2eed3b186b3af5d2..87bfc313dd1408e597e929ba93c8c0f52ae39ced 100644
index 3d8b7957e791ce2fa2a8d0937a87b6010087803d..c23922a301a721662ff34bf6e54fd26b41f25ccc 100644
--- a/unofficial.gni
+++ b/unofficial.gni
@@ -152,7 +152,6 @@ template("node_gn_build") {
@@ -147,7 +147,6 @@ template("node_gn_build") {
":run_node_js2c",
"deps/cares",
"deps/histogram",
@@ -25,7 +42,7 @@ index ddfbb97276b29df114ab455a2eed3b186b3af5d2..87bfc313dd1408e597e929ba93c8c0f5
"deps/nbytes",
"deps/nghttp2",
"deps/postject",
@@ -183,7 +182,17 @@ template("node_gn_build") {
@@ -178,7 +177,17 @@ template("node_gn_build") {
configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
configs += [ "//build/config/gcc:symbol_visibility_default" ]
}
@@ -44,7 +61,7 @@ index ddfbb97276b29df114ab455a2eed3b186b3af5d2..87bfc313dd1408e597e929ba93c8c0f5
if (v8_enable_i18n_support) {
deps += [ "//third_party/icu" ]
}
@@ -210,6 +219,19 @@ template("node_gn_build") {
@@ -205,6 +214,19 @@ template("node_gn_build") {
sources += node_inspector.node_inspector_sources +
node_inspector.node_inspector_generated_sources
}

View File

@@ -10,7 +10,7 @@ V8 requires C++20 support as of https://chromium-review.googlesource.com/c/v8/v8
This can be removed when Electron upgrades to a version of Node.js containing the required V8 version.
diff --git a/common.gypi b/common.gypi
index 34aaf439936c874bd4c8b7d4ffd69477abb40193..69d10c17ef3c5b0ce6173d1754a975df589d9b61 100644
index 74616453e2e047acbb9e25f2f93ebeab06011669..bce15fc4a8b3f2fa0b5a588e6a2b28d2b8b6ac45 100644
--- a/common.gypi
+++ b/common.gypi
@@ -518,7 +518,7 @@

View File

@@ -264,25 +264,27 @@ index 18e4f43efaae3a60b924e697918867e604513194..7cbaf01235750138c680c8ec2ed5d206
uint32_t current_chunk_seq_ = 1;
uint32_t id_;
diff --git a/src/tracing/node_trace_writer.cc b/src/tracing/node_trace_writer.cc
index 8f053efe93324b9acbb4e85f7b974b4f7712e200..1801594e727ec7a2ef3b89603975f507078b88a1 100644
index 8f053efe93324b9acbb4e85f7b974b4f7712e200..e331ed5567caa39ade90ce28cea69f1d10533812 100644
--- a/src/tracing/node_trace_writer.cc
+++ b/src/tracing/node_trace_writer.cc
@@ -96,6 +96,7 @@ void NodeTraceWriter::OpenNewFileForStreaming() {
@@ -95,7 +95,7 @@ void NodeTraceWriter::OpenNewFileForStreaming() {
fd_ = -1;
}
}
-
+#ifndef V8_USE_PERFETTO
void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
Mutex::ScopedLock scoped_lock(stream_mutex_);
// If this is the first trace event, open a new file for streaming.
@@ -112,6 +113,7 @@ void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
@@ -112,7 +112,7 @@ void NodeTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
++total_traces_;
json_trace_writer_->AppendTraceEvent(trace_event);
}
-
+#endif
void NodeTraceWriter::FlushPrivate() {
std::string str;
int highest_request_id;
diff --git a/src/tracing/node_trace_writer.h b/src/tracing/node_trace_writer.h
index cd965d77b7859ff2edcf781a934594b5a9b6d251..fe1714ba77fddef693d37eeb8c7a196ddfd15c26 100644
--- a/src/tracing/node_trace_writer.h
@@ -298,7 +300,7 @@ index cd965d77b7859ff2edcf781a934594b5a9b6d251..fe1714ba77fddef693d37eeb8c7a196d
static const int kTracesPerFile = 1 << 19;
diff --git a/src/tracing/trace_event.h b/src/tracing/trace_event.h
index a662a081dc3bf356bf93e4063fcb043e4d8df07b..c89cdfe2b2681fbf9946200a03d7d1f7bad21226 100644
index be0f55a409a71bf9c1763c36fdc252857228742e..827b5330b2f8c545338a46c548f8abf4aab7f50c 100644
--- a/src/tracing/trace_event.h
+++ b/src/tracing/trace_event.h
@@ -69,8 +69,16 @@ enum CategoryGroupEnabledFlags {
@@ -334,23 +336,21 @@ index a662a081dc3bf356bf93e4063fcb043e4d8df07b..c89cdfe2b2681fbf9946200a03d7d1f7
// Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
// on the convertable value will be called at flush time.
@@ -319,12 +332,15 @@ class TraceEventHelper {
@@ -319,10 +332,13 @@ class TraceEventHelper {
static void SetAgent(Agent* agent);
static inline const uint8_t* GetCategoryGroupEnabled(const char* group) {
+#ifndef V8_USE_PERFETTO
v8::TracingController* controller = GetTracingController();
static const uint8_t disabled = 0;
if (controller == nullptr) [[unlikely]] {
return &disabled;
}
if (UNLIKELY(controller == nullptr)) return &disabled;
return controller->GetCategoryGroupEnabled(group);
+#endif
+ return 0;
}
};
@@ -462,6 +478,7 @@ static inline uint64_t AddTraceEventImpl(
@@ -460,6 +476,7 @@ static inline uint64_t AddTraceEventImpl(
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
const char** arg_names, const uint8_t* arg_types,
const uint64_t* arg_values, unsigned int flags) {
@@ -358,7 +358,14 @@ index a662a081dc3bf356bf93e4063fcb043e4d8df07b..c89cdfe2b2681fbf9946200a03d7d1f7
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
@@ -478,6 +495,8 @@ static inline uint64_t AddTraceEventImpl(
@@ -469,13 +486,14 @@ static inline uint64_t AddTraceEventImpl(
arg_convertibles[1].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
static_cast<intptr_t>(arg_values[1])));
}
- // DCHECK(num_args, 2);
v8::TracingController* controller =
node::tracing::TraceEventHelper::GetTracingController();
if (controller == nullptr) return 0;
return controller->AddTraceEvent(phase, category_group_enabled, name, scope, id,
bind_id, num_args, arg_names, arg_types,
arg_values, arg_convertibles, flags);
@@ -367,18 +374,25 @@ index a662a081dc3bf356bf93e4063fcb043e4d8df07b..c89cdfe2b2681fbf9946200a03d7d1f7
}
static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
@@ -485,6 +504,7 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
@@ -483,6 +501,7 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args,
const char** arg_names, const uint8_t* arg_types,
const uint64_t* arg_values, unsigned int flags, int64_t timestamp) {
+#ifndef V8_USE_PERFETTO
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertables[2];
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
@@ -501,12 +521,15 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
arg_convertables[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
@@ -492,19 +511,21 @@ static V8_INLINE uint64_t AddTraceEventWithTimestampImpl(
arg_convertables[1].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
static_cast<intptr_t>(arg_values[1])));
}
- // DCHECK_LE(num_args, 2);
v8::TracingController* controller =
node::tracing::TraceEventHelper::GetTracingController();
if (controller == nullptr) return 0;
return controller->AddTraceEventWithTimestamp(
phase, category_group_enabled, name, scope, id, bind_id, num_args,
arg_names, arg_types, arg_values, arg_convertibles, flags, timestamp);
arg_names, arg_types, arg_values, arg_convertables, flags, timestamp);
+#endif
+ return 0;
}
@@ -391,7 +405,7 @@ index a662a081dc3bf356bf93e4063fcb043e4d8df07b..c89cdfe2b2681fbf9946200a03d7d1f7
std::unique_ptr<v8::ConvertableToTraceFormat> arg_convertibles[2];
if (num_args > 0 && arg_types[0] == TRACE_VALUE_TYPE_CONVERTABLE) {
arg_convertibles[0].reset(reinterpret_cast<v8::ConvertableToTraceFormat*>(
@@ -522,6 +545,7 @@ static V8_INLINE void AddMetadataEventImpl(
@@ -520,6 +541,7 @@ static V8_INLINE void AddMetadataEventImpl(
return agent->GetTracingController()->AddMetadataEvent(
category_group_enabled, name, num_args, arg_names, arg_types, arg_values,
arg_convertibles, flags);

View File

@@ -7,7 +7,7 @@ Subject: build: ensure native module compilation fails if not using a new
This should not be upstreamed, it is a quality-of-life patch for downstream module builders.
diff --git a/common.gypi b/common.gypi
index cfb1fd6b53715dd2a39ab58b6a3bee0d8aef12bc..34aaf439936c874bd4c8b7d4ffd69477abb40193 100644
index 229cb96c1385c597138719f2b01f78bd54ad44ab..74616453e2e047acbb9e25f2f93ebeab06011669 100644
--- a/common.gypi
+++ b/common.gypi
@@ -86,6 +86,8 @@
@@ -40,7 +40,7 @@ index cfb1fd6b53715dd2a39ab58b6a3bee0d8aef12bc..34aaf439936c874bd4c8b7d4ffd69477
# list in v8/BUILD.gn.
['v8_enable_v8_checks == 1', {
diff --git a/configure.py b/configure.py
index c4653f37f5a69b7cdbd6e4c32e0717ab40a00994..88db584318a4b0f95539baf1d0895d6039fb25ca 100755
index d03db1970fd7a1629a7a7719a5ff267402ab4a66..ce055fb5dfc84c75c486b99f01fea6b9531ff54b 100755
--- a/configure.py
+++ b/configure.py
@@ -1634,6 +1634,7 @@ def configure_library(lib, output, pkgname=None):

View File

@@ -34,7 +34,7 @@ index f5ecc15159f457cd0b8069c0427b7c758c916c4e..c9ce67391f321989b0af48159b4da3ab
let kResistStopPropagation;
diff --git a/src/node_builtins.cc b/src/node_builtins.cc
index 599b59873dbb17ae5e7463403859e088ffb86cda..d23cb087de5cb3cd02ef0542fd2f34207f967ad2 100644
index 48d29a0d05538cd1d992f3f086d826e78d0d8882..8987234c2d08449242b5fd037ed314b725bc42a5 100644
--- a/src/node_builtins.cc
+++ b/src/node_builtins.cc
@@ -34,6 +34,7 @@ using v8::Value;

View File

@@ -11,7 +11,7 @@ node-gyp will use the result of `process.config` that reflects the environment
in which the binary got built.
diff --git a/common.gypi b/common.gypi
index 69d10c17ef3c5b0ce6173d1754a975df589d9b61..2e3a04e90a6bb32b3437780502cf45a7acad75c0 100644
index bce15fc4a8b3f2fa0b5a588e6a2b28d2b8b6ac45..289ab5d282e93c795eafb5fb992c3bbc4790a687 100644
--- a/common.gypi
+++ b/common.gypi
@@ -125,6 +125,7 @@

View File

@@ -6,7 +6,7 @@ Subject: build: use third_party/simdutf
use the Chromium version of simdutf to avoid duplicate symbols
diff --git a/node.gni b/node.gni
index 461bff93e151c454cd0a9575daa01d3f7c0ec9c3..a1eab549b8686c24399f5206f9b611bcbce3d470 100644
index 99ec540ec41ddf5682eed7618ba87d6935b3b982..274e627fe27b318218f10e982ca5a0773a9075a5 100644
--- a/node.gni
+++ b/node.gni
@@ -12,6 +12,8 @@ declare_args() {
@@ -19,10 +19,10 @@ index 461bff93e151c454cd0a9575daa01d3f7c0ec9c3..a1eab549b8686c24399f5206f9b611bc
node_module_version = exec_script("$node_path/tools/getmoduleversion.py", [], "value")
diff --git a/unofficial.gni b/unofficial.gni
index 87bfc313dd1408e597e929ba93c8c0f52ae39ced..4ef97ab65bdfacca4d6dbbc603da0218214b039d 100644
index c23922a301a721662ff34bf6e54fd26b41f25ccc..988dd1d73e72ccd3a6eb10b326b8dc7fcd8e257b 100644
--- a/unofficial.gni
+++ b/unofficial.gni
@@ -155,7 +155,7 @@ template("node_gn_build") {
@@ -150,7 +150,7 @@ template("node_gn_build") {
"deps/nbytes",
"deps/nghttp2",
"deps/postject",
@@ -31,7 +31,7 @@ index 87bfc313dd1408e597e929ba93c8c0f52ae39ced..4ef97ab65bdfacca4d6dbbc603da0218
"deps/sqlite",
"deps/uvwasi",
"//third_party/zlib",
@@ -310,7 +310,7 @@ template("node_gn_build") {
@@ -305,7 +305,7 @@ template("node_gn_build") {
executable("node_js2c") {
defines = []
deps = [
@@ -40,7 +40,7 @@ index 87bfc313dd1408e597e929ba93c8c0f52ae39ced..4ef97ab65bdfacca4d6dbbc603da0218
"deps/uv",
]
sources = [
@@ -417,7 +417,7 @@ template("node_gn_build") {
@@ -412,7 +412,7 @@ template("node_gn_build") {
"deps/googletest",
"deps/googletest:gtest_main",
"deps/nbytes",

View File

@@ -8,7 +8,7 @@ they use themselves as the entry point. We should try to upstream some form
of this.
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
index ad8d41a06bde1ca22d0245fa49143e080365b5e1..69d7743767d025453e43d99b32235700d8122c9a 100644
index d49941881e6cfd8647a6d44a57e0daaf1c874702..f696fb263b356a76b87cd4b6c4b1a0fd60a84afd 100644
--- a/lib/internal/modules/cjs/loader.js
+++ b/lib/internal/modules/cjs/loader.js
@@ -1518,6 +1518,13 @@ Module.prototype._compile = function(content, filename, format) {
@@ -26,10 +26,10 @@ index ad8d41a06bde1ca22d0245fa49143e080365b5e1..69d7743767d025453e43d99b32235700
try {
resolvedArgv = Module._resolveFilename(process.argv[1], null, false);
diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js
index 848ff7f142fc700dd3b4b7a6b14d3c537e0fd280..be3018296dd3c63a930328fa9cb1d902cc779b89 100644
index cb96fd1bc4fcdce750ce241ee5f47f2ae39cfdc6..c46b270109697f7cc1683f8f9f463575e5040216 100644
--- a/lib/internal/process/pre_execution.js
+++ b/lib/internal/process/pre_execution.js
@@ -245,12 +245,14 @@ function patchProcessObject(expandArgv1) {
@@ -243,12 +243,14 @@ function patchProcessObject(expandArgv1) {
if (expandArgv1 && process.argv[1] &&
!StringPrototypeStartsWith(process.argv[1], '-')) {
// Expand process.argv[1] into a full path.

View File

@@ -11,7 +11,7 @@ its own blended handler between Node and Blink.
Not upstreamable.
diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js
index 2799af0f8dd4923ef5ccd372922ea39a66f93470..3012ea1da2db6b22dc6c6a1cac12ec4c5b44487a 100644
index d393d4336a0c1e681e4f6b4e5c7cf2bcc5fc287e..807cb5172e0c2178b6c20e81f8175141d3a0284f 100644
--- a/lib/internal/modules/esm/utils.js
+++ b/lib/internal/modules/esm/utils.js
@@ -30,7 +30,7 @@ const {
@@ -23,7 +23,7 @@ index 2799af0f8dd4923ef5ccd372922ea39a66f93470..3012ea1da2db6b22dc6c6a1cac12ec4c
const {
loadPreloadModules,
initializeFrozenIntrinsics,
@@ -276,12 +276,13 @@ let _forceDefaultLoader = false;
@@ -273,12 +273,13 @@ let _forceDefaultLoader = false;
* @param {boolean} [forceDefaultLoader=false] - A boolean indicating disabling custom loaders.
*/
function initializeESM(forceDefaultLoader = false) {
@@ -40,7 +40,7 @@ index 2799af0f8dd4923ef5ccd372922ea39a66f93470..3012ea1da2db6b22dc6c6a1cac12ec4c
/**
diff --git a/src/module_wrap.cc b/src/module_wrap.cc
index e2252639cf45184b72ebe669f7603bd5e6d92b9a..05353281c0a773d5cf5585cb1698126e17f677a0 100644
index 48b61e8b7600701c4992a98ff802614ce915faee..4e9835e502a8d078a448aa4253f37de0f49f4854 100644
--- a/src/module_wrap.cc
+++ b/src/module_wrap.cc
@@ -813,7 +813,7 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback(

View File

@@ -18,10 +18,10 @@ Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
diff --git a/doc/api/cli.md b/doc/api/cli.md
index 62d3d37a061f787babe44649143d45010ce90011..1f614cabf0f31d7adff9dd7a039ca591d805d3bd 100644
index 0cfed4a4a91a3d3fb5aee6c9a4db3405ba836565..61d980a12fcf7c799e726e1462c65ce478a8ed0c 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -3177,7 +3177,6 @@ V8 options that are allowed are:
@@ -3151,7 +3151,6 @@ V8 options that are allowed are:
* `--disallow-code-generation-from-strings`
* `--enable-etw-stack-walking`
* `--expose-gc`
@@ -30,10 +30,10 @@ index 62d3d37a061f787babe44649143d45010ce90011..1f614cabf0f31d7adff9dd7a039ca591
* `--jitless`
* `--max-old-space-size`
diff --git a/src/node_options.cc b/src/node_options.cc
index 6f9a8d3e0884bc6e356413f2f39522a7109c86b5..ccf740bfd631aca608244b6b3998177ca5f47f75 100644
index 4b3f7751db2871c8ce76b197a84a2417097030ea..21e53e1053fe2e4194d91b27a726d3a1306b1683 100644
--- a/src/node_options.cc
+++ b/src/node_options.cc
@@ -929,11 +929,6 @@ PerIsolateOptionsParser::PerIsolateOptionsParser(
@@ -922,11 +922,6 @@ PerIsolateOptionsParser::PerIsolateOptionsParser(
"disallow eval and friends",
V8Option{},
kAllowedInEnvvar);
@@ -46,10 +46,10 @@ index 6f9a8d3e0884bc6e356413f2f39522a7109c86b5..ccf740bfd631aca608244b6b3998177c
"disable runtime allocation of executable memory",
V8Option{},
diff --git a/test/parallel/test-cli-node-options.js b/test/parallel/test-cli-node-options.js
index 03ffe7aa03f48156f04bb527316221ec10e7e0df..69bf136559c1a8a18a7bfc444a439d161f622635 100644
index e898a81af09ca6852ddc866310e5b8e0dc82971b..22d5a342df5d55f065383a6ebe1aebe59dc0f8d2 100644
--- a/test/parallel/test-cli-node-options.js
+++ b/test/parallel/test-cli-node-options.js
@@ -72,7 +72,6 @@ if (common.hasCrypto) {
@@ -70,7 +70,6 @@ if (common.hasCrypto) {
expect('--abort_on-uncaught_exception', 'B\n');
expect('--disallow-code-generation-from-strings', 'B\n');
expect('--expose-gc', 'B\n');

View File

@@ -8,7 +8,7 @@ to child processes spawned with `ELECTRON_RUN_AS_NODE` which is used
by the crashpad client to connect with the handler process.
diff --git a/lib/child_process.js b/lib/child_process.js
index 51fc6fe995d3cf8c70ad7bc3cecf1cc00f190b08..012ad108f44b73346d19d927afc78b57c18b7718 100644
index 580a441a803bdd0b57871c0cdd8af576f11609b1..755712d24219de7ffe491957d941df7c8cf7baad 100644
--- a/lib/child_process.js
+++ b/lib/child_process.js
@@ -61,6 +61,7 @@ let debug = require('internal/util/debuglog').debuglog(
@@ -27,7 +27,7 @@ index 51fc6fe995d3cf8c70ad7bc3cecf1cc00f190b08..012ad108f44b73346d19d927afc78b57
args = [...execArgv, modulePath, ...args];
if (typeof options.stdio === 'string') {
@@ -615,6 +615,22 @@ function normalizeSpawnArguments(file, args, options) {
@@ -617,6 +617,22 @@ function normalizeSpawnArguments(file, args, options) {
'options.windowsVerbatimArguments');
}
@@ -50,7 +50,7 @@ index 51fc6fe995d3cf8c70ad7bc3cecf1cc00f190b08..012ad108f44b73346d19d927afc78b57
if (options.shell) {
validateArgumentNullCheck(options.shell, 'options.shell');
const command = ArrayPrototypeJoin([file, ...args], ' ');
@@ -648,7 +664,6 @@ function normalizeSpawnArguments(file, args, options) {
@@ -650,7 +666,6 @@ function normalizeSpawnArguments(file, args, options) {
ArrayPrototypeUnshift(args, file);
}

View File

@@ -7,7 +7,7 @@ common.gypi is a file that's included in the node header bundle, despite
the fact that we do not build node with gyp.
diff --git a/common.gypi b/common.gypi
index de83a566724a36fff8b0c4ca9ba7e151a8c39f54..cfb1fd6b53715dd2a39ab58b6a3bee0d8aef12bc 100644
index a97e77860e151f5126515d65ef99b34aa7301f76..229cb96c1385c597138719f2b01f78bd54ad44ab 100644
--- a/common.gypi
+++ b/common.gypi
@@ -88,6 +88,23 @@

View File

@@ -44,10 +44,10 @@ index 59b5a16f1309a5e4055bccfdb7a529045ad30402..bfdaf6211466a01b64b7942f7b16c480
let filename = call.getFileName();
const line = call.getLineNumber() - 1;
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 89ce587cac4506c4218a9316fe0b68070a7a8504..b74fb837fc1cfee839c8b5b8c0b9a6f805881206 100644
index f59abcb21d64b910d8d42eb23c03109f62558813..1b6613d1de8c89c8271066a652afd1024988362d 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -247,6 +247,9 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
@@ -244,6 +244,9 @@ void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
s.prepare_stack_trace_callback : PrepareStackTraceCallback;
isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
@@ -58,10 +58,10 @@ index 89ce587cac4506c4218a9316fe0b68070a7a8504..b74fb837fc1cfee839c8b5b8c0b9a6f8
}
diff --git a/src/node_options.cc b/src/node_options.cc
index 3c42f9b87c11a0f88800d6709515c1c9e2972fc0..6f9a8d3e0884bc6e356413f2f39522a7109c86b5 100644
index 29630fcccc3bd9d24ad6aec64bef2fedfc3c4031..4b3f7751db2871c8ce76b197a84a2417097030ea 100644
--- a/src/node_options.cc
+++ b/src/node_options.cc
@@ -1476,14 +1476,16 @@ void GetEmbedderOptions(const FunctionCallbackInfo<Value>& args) {
@@ -1464,14 +1464,16 @@ void GetEmbedderOptions(const FunctionCallbackInfo<Value>& args) {
}
Isolate* isolate = args.GetIsolate();

View File

@@ -11,7 +11,7 @@ before it's acceptable to upstream, as this patch comments out a couple
of tests that upstream probably cares about.
diff --git a/test/common/index.js b/test/common/index.js
index b95e812c5a9fab59f742e1557e9f218155638af4..6d2566c43f16493cbb2a0f9469ed386c41686782 100644
index 172cdb6b049824539a9850789e0e7c5baf613367..c29abc18191aec78ad8eb810093a9a4ef9e854e4 100644
--- a/test/common/index.js
+++ b/test/common/index.js
@@ -65,6 +65,8 @@ const opensslVersionNumber = (major = 0, minor = 0, patch = 0) => {
@@ -23,7 +23,7 @@ index b95e812c5a9fab59f742e1557e9f218155638af4..6d2566c43f16493cbb2a0f9469ed386c
let OPENSSL_VERSION_NUMBER;
const hasOpenSSL = (major = 0, minor = 0, patch = 0) => {
if (!hasCrypto) return false;
@@ -1008,6 +1010,7 @@ const common = {
@@ -996,6 +998,7 @@ const common = {
mustNotMutateObjectDeep,
mustSucceed,
nodeProcessAborted,
@@ -395,7 +395,7 @@ index 338a19b0e88ad6f08d2f6b6a5d38b9980996ce11..a4ee215575d072450ba66c558ddca88b
};
assert.throws(() => crypto.scrypt('pass', 'salt', 1, options, () => {}),
diff --git a/test/parallel/test-crypto-sign-verify.js b/test/parallel/test-crypto-sign-verify.js
index 8a263ec3350f5540591ac02e70fa2f552b9ac477..dcc4c2ec816d28f1b27df1c358cfce66f1a3a03b 100644
index 9dd586a1a1f9a00d9bb0af5b0532e81e7b96a5ce..a37e6d50914345829c8260a97949cee7d17ab676 100644
--- a/test/parallel/test-crypto-sign-verify.js
+++ b/test/parallel/test-crypto-sign-verify.js
@@ -29,7 +29,7 @@ const keySize = 2048;
@@ -471,21 +471,10 @@ index 008ab129f0e019c659eecf5a76b7eb412c947fe3..6688f5d916f50e1e4fcfff1619c8634a
cipher.end('Papaya!'); // Should not cause an unhandled exception.
diff --git a/test/parallel/test-crypto-x509.js b/test/parallel/test-crypto-x509.js
index 15e1f53bb05faf60fa808eb5901591d1512edf3c..329f0d00c869cd19580acea18c904cf9900fb816 100644
index 89a7521544f7051edc1779138551bbad1972b3fb..91df6acc65d4003999f29f0fa5f639056b21ee3b 100644
--- a/test/parallel/test-crypto-x509.js
+++ b/test/parallel/test-crypto-x509.js
@@ -96,8 +96,10 @@ const der = Buffer.from(
assert.strictEqual(x509.infoAccess, infoAccessCheck);
assert.strictEqual(x509.validFrom, 'Sep 3 21:40:37 2022 GMT');
assert.strictEqual(x509.validTo, 'Jun 17 21:40:37 2296 GMT');
+ if (!common.openSSLIsBoringSSL) {
assert.deepStrictEqual(x509.validFromDate, new Date('2022-09-03T21:40:37Z'));
assert.deepStrictEqual(x509.validToDate, new Date('2296-06-17T21:40:37Z'));
+ }
assert.strictEqual(
x509.fingerprint,
'8B:89:16:C4:99:87:D2:13:1A:64:94:36:38:A5:32:01:F0:95:3B:53');
@@ -113,7 +115,7 @@ const der = Buffer.from(
@@ -111,7 +111,7 @@ const der = Buffer.from(
'5A:42:63:E0:21:2F:D6:70:63:07:96:6F:27:A7:78:12:08:02:7A:8B'
);
assert.strictEqual(x509.keyUsage, undefined);
@@ -494,7 +483,7 @@ index 15e1f53bb05faf60fa808eb5901591d1512edf3c..329f0d00c869cd19580acea18c904cf9
assert.deepStrictEqual(x509.raw, der);
@@ -255,6 +257,16 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
@@ -253,6 +253,16 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
});
mc.port2.postMessage(x509);
@@ -511,7 +500,7 @@ index 15e1f53bb05faf60fa808eb5901591d1512edf3c..329f0d00c869cd19580acea18c904cf9
// Verify that legacy encoding works
const legacyObjectCheck = {
subject: Object.assign({ __proto__: null }, {
@@ -279,15 +291,7 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
@@ -277,15 +287,7 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
'OCSP - URI': ['http://ocsp.nodejs.org/'],
'CA Issuers - URI': ['http://ca.nodejs.org/ca.cert']
}),
@@ -528,7 +517,7 @@ index 15e1f53bb05faf60fa808eb5901591d1512edf3c..329f0d00c869cd19580acea18c904cf9
bits: 2048,
exponent: '0x10001',
valid_from: 'Sep 3 21:40:37 2022 GMT',
@@ -300,7 +304,7 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
@@ -298,7 +300,7 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
'51:62:18:39:E2:E2:77:F5:86:11:E8:C0:CA:54:43:7C:76:83:19:05:D0:03:' +
'24:21:B8:EB:14:61:FB:24:16:EB:BD:51:1A:17:91:04:30:03:EB:68:5F:DC:' +
'86:E1:D1:7C:FB:AF:78:ED:63:5F:29:9C:32:AF:A1:8E:22:96:D1:02',
@@ -537,7 +526,7 @@ index 15e1f53bb05faf60fa808eb5901591d1512edf3c..329f0d00c869cd19580acea18c904cf9
};
const legacyObject = x509.toLegacyObject();
@@ -309,7 +313,7 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
@@ -307,7 +309,7 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
assert.deepStrictEqual(legacyObject.subject, legacyObjectCheck.subject);
assert.deepStrictEqual(legacyObject.issuer, legacyObjectCheck.issuer);
assert.deepStrictEqual(legacyObject.infoAccess, legacyObjectCheck.infoAccess);
@@ -546,7 +535,7 @@ index 15e1f53bb05faf60fa808eb5901591d1512edf3c..329f0d00c869cd19580acea18c904cf9
assert.strictEqual(legacyObject.bits, legacyObjectCheck.bits);
assert.strictEqual(legacyObject.exponent, legacyObjectCheck.exponent);
assert.strictEqual(legacyObject.valid_from, legacyObjectCheck.valid_from);
@@ -318,11 +322,12 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
@@ -316,11 +318,12 @@ oans248kpal88CGqsN2so/wZKxVnpiXlPHMdiNL7hRSUqlHkUi07FrP2Htg8kjI=
assert.strictEqual(
legacyObject.fingerprint256,
legacyObjectCheck.fingerprint256);
@@ -557,40 +546,17 @@ index 15e1f53bb05faf60fa808eb5901591d1512edf3c..329f0d00c869cd19580acea18c904cf9
+ legacyObjectCheck.serialNumberPattern);
}
+if (!common.openSSLIsBoringSSL) {
+/*
{
// This X.509 Certificate can be parsed by OpenSSL because it contains a
// structurally sound TBSCertificate structure. However, the SPKI field of the
@@ -361,6 +366,7 @@ UcXd/5qu2GhokrKU2cPttU+XAN2Om6a0
@@ -359,3 +362,4 @@ UcXd/5qu2GhokrKU2cPttU+XAN2Om6a0
assert.strictEqual(cert.checkIssued(cert), false);
}
+}
{
// Test date parsing of `validFromDate` and `validToDate` fields, according to RFC 5280.
@@ -398,8 +404,10 @@ UidvpWWipVLZgK+oDks+bKTobcoXGW9oXobiIYqslXPy
-----END CERTIFICATE-----`.trim();
const c1 = new X509Certificate(certPemUTCTime);
+ if (!common.openSSLIsBoringSSL) {
assert.deepStrictEqual(c1.validFromDate, new Date('1949-12-25T23:59:58Z'));
assert.deepStrictEqual(c1.validToDate, new Date('1950-01-01T23:59:58Z'));
+ }
// The GeneralizedTime format is used for dates in 2050 or later.
const certPemGeneralizedTime = `-----BEGIN CERTIFICATE-----
@@ -433,6 +441,8 @@ CWwQO8JZjJqFtqtuzy2n+gLCvqePgG/gmSqHOPm2ZbLW
-----END CERTIFICATE-----`.trim();
const c2 = new X509Certificate(certPemGeneralizedTime);
+ if (!common.openSSLIsBoringSSL) {
assert.deepStrictEqual(c2.validFromDate, new Date('2049-12-26T00:00:01Z'));
assert.deepStrictEqual(c2.validToDate, new Date('2050-01-02T00:00:01Z'));
+ }
}
+*/
diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js
index 4271121881379b6c6892e89e520345f77e4181df..7a17285deee18ffbccf1d01d9d1b7b87e561bffa 100644
index 4271121881379b6c6892e89e520345f77e4181df..6c87a1ac687aa37d4ba245d1b6fc746a5f1eeffc 100644
--- a/test/parallel/test-crypto.js
+++ b/test/parallel/test-crypto.js
@@ -61,7 +61,7 @@ assert.throws(() => {
@@ -629,14 +595,23 @@ index 4271121881379b6c6892e89e520345f77e4181df..7a17285deee18ffbccf1d01d9d1b7b87
validateList(crypto.getHashes());
// Make sure all of the hashes are supported by OpenSSL
for (const algo of crypto.getHashes())
@@ -196,6 +194,7 @@ assert.throws(
@@ -195,7 +193,7 @@ assert.throws(
return true;
}
);
+if (!common.openSSLIsBoringSSL) {
-
+/*
assert.throws(() => {
const priv = [
'-----BEGIN RSA PRIVATE KEY-----',
@@ -208,6 +206,7 @@ assert.throws(() => {
].join('\n');
crypto.createSign('SHA256').update('test').sign(priv);
}, (err) => {
+ console.log(err)
if (!common.hasOpenSSL3)
assert.ok(!('opensslErrorStack' in err));
assert.throws(() => { throw err; }, common.hasOpenSSL3 ? {
@@ -216,10 +215,10 @@ assert.throws(() => {
library: 'rsa routines',
} : {
@@ -657,7 +632,7 @@ index 4271121881379b6c6892e89e520345f77e4181df..7a17285deee18ffbccf1d01d9d1b7b87
});
}
-
+}
+*/
// Make sure memory isn't released before being returned
console.log(crypto.randomBytes(16));
@@ -750,7 +725,7 @@ index b06f2fa2c53ea72f9a66f0d002dd9281d0259a0f..864fffeebfad75d95416fd47efdea7f2
const server = https.createServer(opts, (req, res) => {
diff --git a/test/parallel/test-webcrypto-derivebits.js b/test/parallel/test-webcrypto-derivebits.js
index eb09bc24f0cb8244b05987e3a7c1d203360d3a38..8c251ff2371fb59bf679160574e1c5dc1b4b2665 100644
index eb09bc24f0cb8244b05987e3a7c1d203360d3a38..011990db171faa708c5211f6ab9ae1ac0e0ab90e 100644
--- a/test/parallel/test-webcrypto-derivebits.js
+++ b/test/parallel/test-webcrypto-derivebits.js
@@ -101,8 +101,9 @@ const { subtle } = globalThis.crypto;
@@ -764,6 +739,11 @@ index eb09bc24f0cb8244b05987e3a7c1d203360d3a38..8c251ff2371fb59bf679160574e1c5dc
async function test(name) {
const [alice, bob] = await Promise.all([
subtle.generateKey({ name }, true, ['deriveBits']),
@@ -126,3 +127,4 @@ const { subtle } = globalThis.crypto;
test('X25519').then(common.mustCall());
test('X448').then(common.mustCall());
}
+
diff --git a/test/parallel/test-webcrypto-derivekey.js b/test/parallel/test-webcrypto-derivekey.js
index 558d37d90d5796b30101d1b512c9df3e7661d0db..f42bf8f4be0b439dd7e7c8d0f6f8a41e01588870 100644
--- a/test/parallel/test-webcrypto-derivekey.js

View File

@@ -19,10 +19,10 @@ index 463e76cb1abc0c2fdddba4db2ca2e00f7c591e12..d7bc3c35c77b5bf9ec122b38248d0cf1
context = { __proto__: context, source };
}
diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js
index 45a0abc6423a4e53e070f3c117fac2a3554b188d..abd89e9cccba1060f8e76580d5bb338e65a710ea 100644
index 06b31af80ebbfbf35ec787a94f345775eb512ebf..deca5aa4b8829ba9921440fcb5c285a10e40c8f0 100644
--- a/lib/internal/modules/esm/translators.js
+++ b/lib/internal/modules/esm/translators.js
@@ -287,6 +287,9 @@ function cjsPreparseModuleExports(filename, source) {
@@ -354,6 +354,9 @@ function cjsPreparseModuleExports(filename, source) {
if (module && module[kModuleExportNames] !== undefined) {
return { module, exportNames: module[kModuleExportNames] };
}
@@ -33,7 +33,7 @@ index 45a0abc6423a4e53e070f3c117fac2a3554b188d..abd89e9cccba1060f8e76580d5bb338e
if (!loaded) {
module = new CJSModule(filename);
diff --git a/lib/internal/modules/run_main.js b/lib/internal/modules/run_main.js
index ab4783a7982b9feb8fa85b62e3e3b181f93309bd..34f91026451d7347ae278712d083e4fe281e50f3 100644
index 1e1a1ea46fc6c1b43cad4038ab0d9cdf21d6ba3d..95e2fa5479ea31559fdb5a2e03515f243b231b75 100644
--- a/lib/internal/modules/run_main.js
+++ b/lib/internal/modules/run_main.js
@@ -2,6 +2,7 @@
@@ -58,7 +58,7 @@ index ab4783a7982b9feb8fa85b62e3e3b181f93309bd..34f91026451d7347ae278712d083e4fe
const defaultType = getOptionValue('--experimental-default-type');
/** @type {string} */
let mainPath;
@@ -62,6 +70,13 @@ function resolveMainPath(main) {
@@ -63,6 +71,13 @@ function resolveMainPath(main) {
* @param {string} mainPath - Absolute path to the main entry point
*/
function shouldUseESMLoader(mainPath) {

View File

@@ -6,7 +6,7 @@ Subject: fix: expose the built-in electron module via the ESM loader
This allows usage of `import { app } from 'electron'` and `import('electron')` natively in the browser + non-sandboxed renderer
diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js
index 26d0bace6cdd3905f1248c5ad3fa794eb272252d..4ec1f4f6951be40f5fcb4c1cb3d1205e69434f23 100644
index a89446df710a941390c15171fea63c551776fc93..912f03bfa96c3aa12bfa6e709746642452568bb7 100644
--- a/lib/internal/modules/esm/get_format.js
+++ b/lib/internal/modules/esm/get_format.js
@@ -26,6 +26,7 @@ const protocolHandlers = {
@@ -46,7 +46,7 @@ index 8b157f0f461c7b92c567fffe4d99357dbc09aee7..605e812d515fc467001e4ab88fc15b4a
}
}
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
index 35925ef0817273948b7a2128c6ddc12c91bc3cfd..ee2cc03892c01141b71571989b18eec387d3c766 100644
index 1fbbb6773c9479128408fa1f27cf19f1a7786ba6..f05c6f99c0037193c5802024be46a967d6cf47a0 100644
--- a/lib/internal/modules/esm/resolve.js
+++ b/lib/internal/modules/esm/resolve.js
@@ -772,6 +772,8 @@ function parsePackageName(specifier, base) {
@@ -71,10 +71,10 @@ index 35925ef0817273948b7a2128c6ddc12c91bc3cfd..ee2cc03892c01141b71571989b18eec3
parsePackageName(specifier, base);
diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js
index 9b89c3e1d52a0f724dab451844d32df67f1eab9f..25ee090bbb4884d3e5f2530cc7153f9215754fae 100644
index 8f88214f558c52ef26000fb0e1ef4d391327e84e..d182eedf5e96039e0029d36e51f40b75c6fb2a39 100644
--- a/lib/internal/modules/esm/translators.js
+++ b/lib/internal/modules/esm/translators.js
@@ -182,7 +182,7 @@ function createCJSModuleWrap(url, source, isMain, loadCJS = loadCJSModule) {
@@ -246,7 +246,7 @@ function createCJSModuleWrap(url, source, isMain, loadCJS = loadCJSModule) {
const { exportNames, module } = cjsPreparseModuleExports(filename, source);
cjsCache.set(url, module);
@@ -83,7 +83,7 @@ index 9b89c3e1d52a0f724dab451844d32df67f1eab9f..25ee090bbb4884d3e5f2530cc7153f92
[...exportNames] : ['default', ...exportNames];
if (isMain) {
@@ -204,8 +204,8 @@ function createCJSModuleWrap(url, source, isMain, loadCJS = loadCJSModule) {
@@ -268,8 +268,8 @@ function createCJSModuleWrap(url, source, isMain, loadCJS = loadCJSModule) {
({ exports } = module);
}
for (const exportName of exportNames) {
@@ -94,7 +94,7 @@ index 9b89c3e1d52a0f724dab451844d32df67f1eab9f..25ee090bbb4884d3e5f2530cc7153f92
continue;
}
// We might trigger a getter -> dont fail.
@@ -239,6 +239,10 @@ translators.set('require-commonjs', (url, source, isMain) => {
@@ -304,6 +304,10 @@ translators.set('require-commonjs', (url, source, isMain) => {
return createCJSModuleWrap(url, source);
});

View File

@@ -7,10 +7,10 @@ Subject: fix: expose tracing::Agent and use tracing::TracingController instead
This API is used by Electron to create Node's tracing controller.
diff --git a/src/api/environment.cc b/src/api/environment.cc
index ad323fc800a33c010b0504a4aa55c107498dee26..e044f10284f31f1862b18be752a04b3bd5d53401 100644
index 77c20a4b6b9db414444974f68c5def8788386d2b..5fc1b6f2446d7c786024eb60800e2edab613dcd1 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -567,6 +567,10 @@ MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
@@ -564,6 +564,10 @@ MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
return env->platform();
}

View File

@@ -17,7 +17,7 @@ Upstreams:
- https://github.com/nodejs/node/pull/39136
diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc
index 457bd2f6c5b18956d06c716fbfae429496fb352d..e954cb2e53f3d8c297d21ef9f698d824ca574106 100644
index eb3533bb4623b152605c3c590f37f086cce5f073..ded231aeaa15af22845704cfcc7d24a44bd88f8e 100644
--- a/deps/ncrypto/ncrypto.cc
+++ b/deps/ncrypto/ncrypto.cc
@@ -6,13 +6,11 @@
@@ -35,7 +35,7 @@ index 457bd2f6c5b18956d06c716fbfae429496fb352d..e954cb2e53f3d8c297d21ef9f698d824
namespace ncrypto {
namespace {
@@ -694,7 +692,7 @@ bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext) {
@@ -665,7 +663,7 @@ bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext) {
bool ok = true;
@@ -44,7 +44,7 @@ index 457bd2f6c5b18956d06c716fbfae429496fb352d..e954cb2e53f3d8c297d21ef9f698d824
GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i);
if (i != 0)
@@ -720,7 +718,7 @@ bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) {
@@ -691,7 +689,7 @@ bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) {
bool ok = true;
@@ -53,25 +53,7 @@ index 457bd2f6c5b18956d06c716fbfae429496fb352d..e954cb2e53f3d8c297d21ef9f698d824
ACCESS_DESCRIPTION* desc = sk_ACCESS_DESCRIPTION_value(descs, i);
if (i != 0)
@@ -857,13 +855,17 @@ BIOPointer X509View::getValidTo() const {
int64_t X509View::getValidToTime() const {
struct tm tp;
+#ifndef OPENSSL_IS_BORINGSSL
ASN1_TIME_to_tm(X509_get0_notAfter(cert_), &tp);
+#endif
return PortableTimeGM(&tp);
}
int64_t X509View::getValidFromTime() const {
struct tm tp;
+#ifndef OPENSSL_IS_BORINGSSL
ASN1_TIME_to_tm(X509_get0_notBefore(cert_), &tp);
+#endif
return PortableTimeGM(&tp);
}
@@ -1043,7 +1045,11 @@ BIOPointer BIOPointer::NewMem() {
@@ -1002,7 +1000,11 @@ BIOPointer BIOPointer::NewMem() {
}
BIOPointer BIOPointer::NewSecMem() {
@@ -83,7 +65,7 @@ index 457bd2f6c5b18956d06c716fbfae429496fb352d..e954cb2e53f3d8c297d21ef9f698d824
}
BIOPointer BIOPointer::New(const BIO_METHOD* method) {
@@ -1098,8 +1104,10 @@ BignumPointer DHPointer::FindGroup(const std::string_view name,
@@ -1057,8 +1059,10 @@ BignumPointer DHPointer::FindGroup(const std::string_view name,
FindGroupOption option) {
#define V(n, p) if (EqualNoCase(name, n)) return BignumPointer(p(nullptr));
if (option != FindGroupOption::NO_SMALL_PRIMES) {
@@ -94,7 +76,7 @@ index 457bd2f6c5b18956d06c716fbfae429496fb352d..e954cb2e53f3d8c297d21ef9f698d824
V("modp5", BN_get_rfc3526_prime_1536);
}
V("modp14", BN_get_rfc3526_prime_2048);
@@ -1171,11 +1179,13 @@ DHPointer::CheckPublicKeyResult DHPointer::checkPublicKey(const BignumPointer& p
@@ -1130,11 +1134,13 @@ DHPointer::CheckPublicKeyResult DHPointer::checkPublicKey(const BignumPointer& p
int codes = 0;
if (DH_check_pub_key(dh_.get(), pub_key.get(), &codes) != 1)
return DHPointer::CheckPublicKeyResult::CHECK_FAILED;
@@ -110,10 +92,10 @@ index 457bd2f6c5b18956d06c716fbfae429496fb352d..e954cb2e53f3d8c297d21ef9f698d824
}
return CheckPublicKeyResult::NONE;
diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h
index 20b69dc67b13fd4f0bd44f7adf6a0d928a2c10c4..2320f92c50543fb9b426bce1c6d182bddf7658de 100644
index 60bfce3ea8999e8e145aaf8cd14f0fdf21ed9c54..55aae783bb57273d1b49927f65b6c0830d09d115 100644
--- a/deps/ncrypto/ncrypto.h
+++ b/deps/ncrypto/ncrypto.h
@@ -493,17 +493,21 @@ public:
@@ -400,17 +400,21 @@ public:
UNABLE_TO_CHECK_GENERATOR = DH_UNABLE_TO_CHECK_GENERATOR,
NOT_SUITABLE_GENERATOR = DH_NOT_SUITABLE_GENERATOR,
Q_NOT_PRIME = DH_CHECK_Q_NOT_PRIME,
@@ -149,7 +131,7 @@ index ea024af73e215b3cad5f08796ac405f419530c86..41061b524eea74330b8d2452635a38c4
}
}
diff --git a/node.gni b/node.gni
index 852f64fa9cfb50fe6e9ce7aa46be336d3196d5b8..461bff93e151c454cd0a9575daa01d3f7c0ec9c3 100644
index 32709b860ccb12d8d1e75342a65dda0b86129b21..18d58591e3d0f1f3512db00033c3410a65702864 100644
--- a/node.gni
+++ b/node.gni
@@ -10,6 +10,8 @@ declare_args() {
@@ -162,10 +144,10 @@ index 852f64fa9cfb50fe6e9ce7aa46be336d3196d5b8..461bff93e151c454cd0a9575daa01d3f
node_module_version = exec_script("$node_path/tools/getmoduleversion.py", [], "value")
diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc
index a81ab8e95f2fc23e1e315fb9c69364934377a0c1..dbe12ba2413ef29ff06a7e8abde50000eaf277e2 100644
index fe35a8e0f6bbb7ab515a0343a7ed046c44e86474..43a7abbf237d8d809953e302b83755a3283a1bf4 100644
--- a/src/crypto/crypto_cipher.cc
+++ b/src/crypto/crypto_cipher.cc
@@ -1080,7 +1080,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
@@ -1078,7 +1078,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) {
return ThrowCryptoError(env, ERR_get_error());
}
@@ -174,7 +156,7 @@ index a81ab8e95f2fc23e1e315fb9c69364934377a0c1..dbe12ba2413ef29ff06a7e8abde50000
int rsa_pkcs1_implicit_rejection =
EVP_PKEY_CTX_ctrl_str(ctx.get(), "rsa_pkcs1_implicit_rejection", "1");
// From the doc -2 means that the option is not supported.
@@ -1096,6 +1096,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
@@ -1094,6 +1094,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
"RSA_PKCS1_PADDING is no longer supported for private decryption,"
" this can be reverted with --security-revert=CVE-2024-PEND");
}
@@ -183,7 +165,7 @@ index a81ab8e95f2fc23e1e315fb9c69364934377a0c1..dbe12ba2413ef29ff06a7e8abde50000
const EVP_MD* digest = nullptr;
diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc
index 43a126f863779d3f364f92bd237039474b489845..77a3caee93049f65faef37e93b871c467ebca7e5 100644
index 6a967702b22df0eb8aa10e853fd232794955860d..31058cccc6ffeed6b09aaecda320ee2f15849ec8 100644
--- a/src/crypto/crypto_common.cc
+++ b/src/crypto/crypto_common.cc
@@ -134,7 +134,7 @@ const char* GetClientHelloALPN(const SSLPointer& ssl) {
@@ -272,7 +254,7 @@ index 43a126f863779d3f364f92bd237039474b489845..77a3caee93049f65faef37e93b871c46
crypto::EVPKeyPointer key(raw_key);
diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc
index aa5fc61f19e435b4833f3f49df10fa1edf2142c7..0a338b018a4ec20cb5bce250faf60d3f3bf192d4 100644
index c924a54639e8c22d765dc240dffacfffb200ca0c..287afcc792a0a2b7e19126ee9a48ebe21cc8844e 100644
--- a/src/crypto/crypto_context.cc
+++ b/src/crypto/crypto_context.cc
@@ -94,7 +94,7 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
@@ -308,7 +290,7 @@ index aa5fc61f19e435b4833f3f49df10fa1edf2142c7..0a338b018a4ec20cb5bce250faf60d3f
X509_STORE_add_cert(sc->GetCertStoreOwnedByThisSecureContext(), ca);
diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc
index d760a0d3ea1d12184a558f5e87cb22043d26a0f5..f973941b3b9ea954f35f2ea135f8ee3d77b98958 100644
index e5664dfa2bc7e11922fa965f28acdf21470d1147..33ffbbb85d05f5356183e3aa1ca23707c5629b5d 100644
--- a/src/crypto/crypto_dh.cc
+++ b/src/crypto/crypto_dh.cc
@@ -7,7 +7,9 @@
@@ -393,7 +375,7 @@ index d760a0d3ea1d12184a558f5e87cb22043d26a0f5..f973941b3b9ea954f35f2ea135f8ee3d
break;
}
@@ -398,9 +398,11 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
key_params = EVPKeyPointer::New();
key_params = EVPKeyPointer(EVP_PKEY_new());
CHECK(key_params);
CHECK_EQ(EVP_PKEY_assign_DH(key_params.get(), dh.release()), 1);
- } else if (int* prime_size = std::get_if<int>(&params->params.prime)) {
@@ -416,7 +398,7 @@ index d760a0d3ea1d12184a558f5e87cb22043d26a0f5..f973941b3b9ea954f35f2ea135f8ee3d
UNREACHABLE();
}
diff --git a/src/crypto/crypto_dsa.cc b/src/crypto/crypto_dsa.cc
index b557de774117e442d7f429e92d63a6e1faa236fd..0aca233ced39269b09c383e5b32d85cf36260a1e 100644
index 5d081863cf2dcdcf8c2d09db6060eeb5e78c452f..67523ec1c406e345945e1dde663c784c43a1c624 100644
--- a/src/crypto/crypto_dsa.cc
+++ b/src/crypto/crypto_dsa.cc
@@ -40,7 +40,7 @@ namespace crypto {
@@ -440,10 +422,10 @@ index b557de774117e442d7f429e92d63a6e1faa236fd..0aca233ced39269b09c383e5b32d85cf
return EVPKeyCtxPointer();
diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc
index 6af8d089ca6bcd73aff314638443610b9cc4bf7e..c84cbd5b4708e0c403ab0a1e1ddf5fc72eb3d148 100644
index 8488fc57faaf722174032c5a927d150c76120d60..c51efc92d4818ee7701b4725585fb7e1d2d644ad 100644
--- a/src/crypto/crypto_keys.cc
+++ b/src/crypto/crypto_keys.cc
@@ -1059,6 +1059,7 @@ void KeyObjectHandle::GetAsymmetricKeyType(
@@ -1204,6 +1204,7 @@ void KeyObjectHandle::GetAsymmetricKeyType(
}
bool KeyObjectHandle::CheckEcKeyData() const {
@@ -451,7 +433,7 @@ index 6af8d089ca6bcd73aff314638443610b9cc4bf7e..c84cbd5b4708e0c403ab0a1e1ddf5fc7
MarkPopErrorOnReturn mark_pop_error_on_return;
const auto& key = data_.GetAsymmetricKey();
@@ -1075,6 +1076,9 @@ bool KeyObjectHandle::CheckEcKeyData() const {
@@ -1220,6 +1221,9 @@ bool KeyObjectHandle::CheckEcKeyData() const {
#else
return EVP_PKEY_public_check(ctx.get()) == 1;
#endif
@@ -475,25 +457,27 @@ index b59e394d9a7e2c19fdf1f2b0177753ff488da0fa..91218f49da5392c6f769495ee7f9275a
THROW_ERR_CRYPTO_OPERATION_FAILED(env, "could not generate prime");
return Nothing<void>();
diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc
index 6d360554b31d53a597d61fcbd660f703a903ca21..86fafe98222d4c18f062032d80104f3ef00dbc01 100644
index 02e8e24b4054afd4c3ca797c19a78927319a0d9e..d2a931a3f8f9490fe17ef8a82d0204ee2cca409d 100644
--- a/src/crypto/crypto_rsa.cc
+++ b/src/crypto/crypto_rsa.cc
@@ -608,10 +608,13 @@ Maybe<void> GetRsaKeyDetail(Environment* env,
@@ -608,10 +608,11 @@ Maybe<void> GetRsaKeyDetail(Environment* env,
}
if (params->saltLength != nullptr) {
+#ifndef OPENSSL_IS_BORINGSSL
- if (ASN1_INTEGER_get_int64(&salt_length, params->saltLength) != 1) {
- ThrowCryptoError(env, ERR_get_error(), "ASN1_INTEGER_get_in64 error");
- return Nothing<void>();
- }
+ // TODO(codebytere): Upstream a shim to BoringSSL?
if (ASN1_INTEGER_get_int64(&salt_length, params->saltLength) != 1) {
ThrowCryptoError(env, ERR_get_error(), "ASN1_INTEGER_get_in64 error");
return Nothing<void>();
}
+#endif
+ // if (ASN1_INTEGER_get_int64(&salt_length, params->saltLength) != 1) {
+ // ThrowCryptoError(env, ERR_get_error(), "ASN1_INTEGER_get_in64 error");
+ // return Nothing<void>();
+ // }
}
if (target
diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc
index 12ee0cde0897024bccb0face49053544a0bcfcd7..8a6a36a3c31532ed585c287ba8cee14026d315b4 100644
index 793c196f8ce538c66b20611d00e12392ff9e878b..ee81048caab4ccfe26ea9e677782c9c955d162a9 100644
--- a/src/crypto/crypto_util.cc
+++ b/src/crypto/crypto_util.cc
@@ -495,24 +495,15 @@ Maybe<void> Decorate(Environment* env,
@@ -554,7 +538,7 @@ index 12ee0cde0897024bccb0face49053544a0bcfcd7..8a6a36a3c31532ed585c287ba8cee140
} // namespace
diff --git a/src/env.h b/src/env.h
index 55124cd38e75ab67c092f6bf5c909a50e7232045..3ef093e612b23d5e1e7cacf56055e5f9818bcb02 100644
index fc8dbd615255851cad90e1d8ffe225f5e0c6a718..49ca9c0042ccf22ad1fffa54f05fd443cbc681ba 100644
--- a/src/env.h
+++ b/src/env.h
@@ -50,7 +50,7 @@
@@ -566,7 +550,7 @@ index 55124cd38e75ab67c092f6bf5c909a50e7232045..3ef093e612b23d5e1e7cacf56055e5f9
#include <openssl/evp.h>
#endif
@@ -1060,7 +1060,7 @@ class Environment final : public MemoryRetainer {
@@ -1073,7 +1073,7 @@ class Environment final : public MemoryRetainer {
kExitInfoFieldCount
};
@@ -589,7 +573,7 @@ index c59e65ad1fe3fac23f1fc25ca77e6133d1ccaccd..f2f07434e076e2977755ef7dac7d489a
#if NODE_OPENSSL_HAS_QUIC
#include <openssl/quic.h>
diff --git a/src/node_options.cc b/src/node_options.cc
index d3b59690e917afcf725cbfb1232d6ed9f298ee3a..3c42f9b87c11a0f88800d6709515c1c9e2972fc0 100644
index cfc599ec9a6197231c3469d318f02c620cdb03a8..29630fcccc3bd9d24ad6aec64bef2fedfc3c4031 100644
--- a/src/node_options.cc
+++ b/src/node_options.cc
@@ -6,7 +6,7 @@
@@ -602,7 +586,7 @@ index d3b59690e917afcf725cbfb1232d6ed9f298ee3a..3c42f9b87c11a0f88800d6709515c1c9
#endif
diff --git a/src/node_options.h b/src/node_options.h
index fc7f898a6b9b6072c15d77710c20ed1ba580966b..f39dcad0a28ae483e6d0e5df3816693119ac823e 100644
index 9e656a2815045aa5da7eb267708c03058be9f362..600e0850f01e01024414d42b25605f256200540a 100644
--- a/src/node_options.h
+++ b/src/node_options.h
@@ -11,7 +11,7 @@
@@ -615,10 +599,10 @@ index fc7f898a6b9b6072c15d77710c20ed1ba580966b..f39dcad0a28ae483e6d0e5df38166931
#endif
diff --git a/unofficial.gni b/unofficial.gni
index f6793b8bf22d6ac911a1977edaa881b6dbbe7ac7..ddfbb97276b29df114ab455a2eed3b186b3af5d2 100644
index de6ff5548ca5282199b7d85c11941c1fa351a9d9..3d8b7957e791ce2fa2a8d0937a87b6010087803d 100644
--- a/unofficial.gni
+++ b/unofficial.gni
@@ -150,7 +150,6 @@ template("node_gn_build") {
@@ -145,7 +145,6 @@ template("node_gn_build") {
]
deps = [
":run_node_js2c",
@@ -626,7 +610,7 @@ index f6793b8bf22d6ac911a1977edaa881b6dbbe7ac7..ddfbb97276b29df114ab455a2eed3b18
"deps/cares",
"deps/histogram",
"deps/llhttp",
@@ -161,6 +160,8 @@ template("node_gn_build") {
@@ -156,6 +155,8 @@ template("node_gn_build") {
"deps/sqlite",
"deps/uvwasi",
"//third_party/zlib",
@@ -635,7 +619,7 @@ index f6793b8bf22d6ac911a1977edaa881b6dbbe7ac7..ddfbb97276b29df114ab455a2eed3b18
"$node_v8_path:v8_libplatform",
]
@@ -187,10 +188,8 @@ template("node_gn_build") {
@@ -182,10 +183,8 @@ template("node_gn_build") {
deps += [ "//third_party/icu" ]
}
if (node_use_openssl) {

View File

@@ -38,11 +38,11 @@ index 605e812d515fc467001e4ab88fc15b4af3fd4aa2..463e76cb1abc0c2fdddba4db2ca2e00f
const result = dataURLProcessor(url);
if (result === 'failure') {
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
index ee2cc03892c01141b71571989b18eec387d3c766..c13475102a75d65329908f44def06a60f4a2c4f1 100644
index f05c6f99c0037193c5802024be46a967d6cf47a0..f3dad958b2ec275992554477b9344214c8c1e2c8 100644
--- a/lib/internal/modules/esm/resolve.js
+++ b/lib/internal/modules/esm/resolve.js
@@ -25,7 +25,7 @@ const {
const assert = require('internal/assert');
@@ -24,7 +24,7 @@ const {
} = primordials;
const internalFS = require('internal/fs/utils');
const { BuiltinModule } = require('internal/bootstrap/realm');
-const { realpathSync } = require('fs');
@@ -60,10 +60,10 @@ index ee2cc03892c01141b71571989b18eec387d3c766..c13475102a75d65329908f44def06a60
});
const { search, hash } = resolved;
diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js
index 25ee090bbb4884d3e5f2530cc7153f9215754fae..45a0abc6423a4e53e070f3c117fac2a3554b188d 100644
index d182eedf5e96039e0029d36e51f40b75c6fb2a39..06b31af80ebbfbf35ec787a94f345775eb512ebf 100644
--- a/lib/internal/modules/esm/translators.js
+++ b/lib/internal/modules/esm/translators.js
@@ -24,7 +24,7 @@ const {
@@ -34,7 +34,7 @@ const {
const { BuiltinModule } = require('internal/bootstrap/realm');
const assert = require('internal/assert');
@@ -71,8 +71,8 @@ index 25ee090bbb4884d3e5f2530cc7153f9215754fae..45a0abc6423a4e53e070f3c117fac2a3
+const fs = require('fs');
const { dirname, extname, isAbsolute } = require('path');
const {
assertBufferSource,
@@ -269,7 +269,7 @@ translators.set('commonjs', function commonjsStrategy(url, source, isMain) {
loadBuiltinModule,
@@ -335,7 +335,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source,
try {
// We still need to read the FS to detect the exports.
@@ -81,7 +81,7 @@ index 25ee090bbb4884d3e5f2530cc7153f9215754fae..45a0abc6423a4e53e070f3c117fac2a3
} catch {
// Continue regardless of error.
}
@@ -336,7 +336,7 @@ function cjsPreparseModuleExports(filename, source) {
@@ -403,7 +403,7 @@ function cjsPreparseModuleExports(filename, source) {
isAbsolute(resolved)) {
// TODO: this should be calling the `load` hook chain to get the source
// (and fallback to reading the FS only if the source is nullish).

View File

@@ -48,7 +48,7 @@ index 867a1c4aca54b9d41490d23a5eb55088b7e941cc..09f4c65a18efea262b1f854f993c6f18
static v8::CFunction fast_equal(v8::CFunction::Make(FastTimingSafeEqual));
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index cd51d9acf9540d506ec35812b9d2c530fce24912..07068344262f7b73a83073d4da75bffe8b747a61 100644
index 2302e8d94da3250e7fb4ee0c5e6a51d3d6941fbc..ed72476e16036d972de54d39cf4bd37bbbed5c5f 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -44,6 +44,14 @@
@@ -74,7 +74,7 @@ index cd51d9acf9540d506ec35812b9d2c530fce24912..07068344262f7b73a83073d4da75bffe
using v8::FunctionCallbackInfo;
using v8::Global;
using v8::HandleScope;
@@ -582,19 +589,24 @@ void SlowCopy(const FunctionCallbackInfo<Value>& args) {
@@ -581,19 +588,24 @@ void SlowCopy(const FunctionCallbackInfo<Value>& args) {
// Assume caller has properly validated args.
uint32_t FastCopy(Local<Value> receiver,
@@ -107,7 +107,7 @@ index cd51d9acf9540d506ec35812b9d2c530fce24912..07068344262f7b73a83073d4da75bffe
return to_copy;
}
@@ -858,19 +870,17 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
@@ -857,19 +869,17 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
}
int32_t FastCompare(v8::Local<v8::Value>,
@@ -135,7 +135,7 @@ index cd51d9acf9540d506ec35812b9d2c530fce24912..07068344262f7b73a83073d4da75bffe
}
static v8::CFunction fast_compare(v8::CFunction::Make(FastCompare));
@@ -1141,14 +1151,13 @@ void SlowIndexOfNumber(const FunctionCallbackInfo<Value>& args) {
@@ -1140,14 +1150,13 @@ void SlowIndexOfNumber(const FunctionCallbackInfo<Value>& args) {
}
int32_t FastIndexOfNumber(v8::Local<v8::Value>,
@@ -153,7 +153,7 @@ index cd51d9acf9540d506ec35812b9d2c530fce24912..07068344262f7b73a83073d4da75bffe
}
static v8::CFunction fast_index_of_number(
@@ -1501,21 +1510,31 @@ void SlowWriteString(const FunctionCallbackInfo<Value>& args) {
@@ -1552,21 +1561,31 @@ void SlowWriteString(const FunctionCallbackInfo<Value>& args) {
template <encoding encoding>
uint32_t FastWriteString(Local<Value> receiver,
@@ -194,10 +194,10 @@ index cd51d9acf9540d506ec35812b9d2c530fce24912..07068344262f7b73a83073d4da75bffe
static v8::CFunction fast_write_string_ascii(
diff --git a/src/node_external_reference.h b/src/node_external_reference.h
index 8d49a119c218323674e29a522ecf71bd22cdaf1b..d39693f2f45f39e45960453112b0f6460a1b3a4d 100644
index 38a4ff7e6c2c9997f004c7c1f94cb5a9ffc2ffe0..48e73168f994d79ae3564b813acb5546ca8f2526 100644
--- a/src/node_external_reference.h
+++ b/src/node_external_reference.h
@@ -40,16 +40,16 @@ using CFunctionCallbackWithStrings =
@@ -34,16 +34,16 @@ using CFunctionCallbackWithStrings =
const v8::FastOneByteString& base);
using CFunctionCallbackWithTwoUint8Arrays =
int32_t (*)(v8::Local<v8::Value>,
@@ -219,7 +219,7 @@ index 8d49a119c218323674e29a522ecf71bd22cdaf1b..d39693f2f45f39e45960453112b0f646
uint32_t,
int64_t,
bool);
@@ -68,18 +68,20 @@ using CFunctionWithBool = void (*)(v8::Local<v8::Value>,
@@ -58,18 +58,20 @@ using CFunctionWithBool = void (*)(v8::Local<v8::Value>, bool);
using CFunctionWriteString =
uint32_t (*)(v8::Local<v8::Value> receiver,
@@ -246,18 +246,19 @@ index 8d49a119c218323674e29a522ecf71bd22cdaf1b..d39693f2f45f39e45960453112b0f646
// This class manages the external references from the V8 heap
// to the C++ addresses in Node.js.
diff --git a/src/util.h b/src/util.h
index b1f316eebc7199a3737f05a5f9a1dd7fc289490c..23a0a486244ce38277ef11df5806da1266b901ac 100644
index a6da8720c499df54ab4608eb03cff905759c2232..43ef977363e565a6f9422c9454e25b8fe0b327d5 100644
--- a/src/util.h
+++ b/src/util.h
@@ -59,6 +59,7 @@
@@ -57,6 +57,8 @@
namespace node {
constexpr char kPathSeparator = std::filesystem::path::preferred_separator;
+static constexpr size_t kMaxSizeInHeap = 64;
+static constexpr size_t kMaxSizeInHeap = 64; \
+
#ifdef _WIN32
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
@@ -576,6 +577,16 @@ class BufferValue : public MaybeStackBuffer<char> {
#define PATH_MAX_BYTES (MAX_PATH * 4)
@@ -573,6 +575,16 @@ class BufferValue : public MaybeStackBuffer<char> {
static_cast<char*>(name->Buffer()->Data()) + name##_offset; \
if (name##_length > 0) CHECK_NE(name##_data, nullptr);

View File

@@ -11,7 +11,7 @@ This patch can be removed when we upgrade to a V8 version that
contains the above CL.
diff --git a/src/node.cc b/src/node.cc
index 1a2a43bdd37441400323a800c147fcb89f0d549a..ae0b40b40e601e86d22e223a764c20106ae29d70 100644
index ccc1085a84b214d241687fa9ebd45b55b2cc60d8..1df8e1f00a0e2ffa63bfd4369240b837ab6a9c50 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -804,7 +804,7 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args,

View File

@@ -15,10 +15,10 @@ to recognize asar files.
This reverts commit 9cf2e1f55b8446a7cde23699d00a3be73aa0c8f1.
diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js
index c13475102a75d65329908f44def06a60f4a2c4f1..e9fe83a675cb5bf681934e0f1c30a3cab447ba57 100644
index f3dad958b2ec275992554477b9344214c8c1e2c8..a086217046fd5ed7cfb09cfd2ed62f3987eb1f31 100644
--- a/lib/internal/modules/esm/resolve.js
+++ b/lib/internal/modules/esm/resolve.js
@@ -28,14 +28,13 @@ const { BuiltinModule } = require('internal/bootstrap/realm');
@@ -27,14 +27,13 @@ const { BuiltinModule } = require('internal/bootstrap/realm');
const fs = require('fs');
const { getOptionValue } = require('internal/options');
// Do not eagerly grab .manifest, it may be in TDZ
@@ -35,36 +35,56 @@ index c13475102a75d65329908f44def06a60f4a2c4f1..e9fe83a675cb5bf681934e0f1c30a3ca
const {
ERR_INPUT_TYPE_NOT_ALLOWED,
ERR_INVALID_ARG_TYPE,
@@ -183,6 +182,15 @@ const legacyMainResolveExtensionsIndexes = {
kResolvedByPackageAndNode: 9,
};
@@ -154,34 +153,13 @@ function emitLegacyIndexDeprecation(url, packageJSONUrl, base, main) {
const realpathCache = new SafeMap();
-const legacyMainResolveExtensions = [
- '',
- '.js',
- '.json',
- '.node',
- '/index.js',
- '/index.json',
- '/index.node',
- './index.js',
- './index.json',
- './index.node',
-];
-
-const legacyMainResolveExtensionsIndexes = {
- // 0-6: when packageConfig.main is defined
- kResolvedByMain: 0,
- kResolvedByMainJs: 1,
- kResolvedByMainJson: 2,
- kResolvedByMainNode: 3,
- kResolvedByMainIndexJs: 4,
- kResolvedByMainIndexJson: 5,
- kResolvedByMainIndexNode: 6,
- // 7-9: when packageConfig.main is NOT defined,
- // or when the previous case didn't found the file
- kResolvedByPackageAndJs: 7,
- kResolvedByPackageAndJson: 8,
- kResolvedByPackageAndNode: 9,
-};
+/**
+ * @param {string | URL} url
+ * @returns {boolean}
+ */
+function fileExists(url) {
+ const namespaced = toNamespacedPath(toPathIfFileURL(url));
+ return internalFsBinding.internalModuleStat(internalFsBinding, namespaced) === 0;
+ return internalFsBinding.internalModuleStat(toNamespacedPath(toPathIfFileURL(url))) === 0;
+}
+
/**
* Legacy CommonJS main resolution:
* 1. let M = pkg_url + (json main field)
@@ -199,18 +207,45 @@ function legacyMainResolve(packageJSONUrl, packageConfig, base) {
assert(isURL(packageJSONUrl));
const pkgPath = fileURLToPath(new URL('.', packageJSONUrl));
- const baseStringified = isURL(base) ? base.href : base;
@@ -196,22 +174,44 @@ const legacyMainResolveExtensionsIndexes = {
* @returns {URL}
*/
function legacyMainResolve(packageJSONUrl, packageConfig, base) {
- const packageJsonUrlString = packageJSONUrl.href;
-
- const resolvedOption = FSLegacyMainResolve(pkgPath, packageConfig.main, baseStringified);
-
- const maybeMain = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ?
- packageConfig.main || './' : '';
- const resolvedPath = resolve(pkgPath, maybeMain + legacyMainResolveExtensions[resolvedOption]);
- const resolvedUrl = pathToFileURL(resolvedPath);
-
- emitLegacyIndexDeprecation(resolvedUrl, resolvedPath, pkgPath, base, packageConfig.main);
- if (typeof packageJsonUrlString !== 'string') {
- throw new ERR_INVALID_ARG_TYPE('packageJSONUrl', ['URL'], packageJSONUrl);
+ let guess;
+ if (packageConfig.main !== undefined) {
+ // Note: fs check redundances will be handled by Descriptor cache here.
@@ -85,39 +105,277 @@ index c13475102a75d65329908f44def06a60f4a2c4f1..e9fe83a675cb5bf681934e0f1c30a3ca
+ packageJSONUrl)));
+ else guess = undefined;
+ if (guess) {
+ emitLegacyIndexDeprecation(guess, fileURLToPath(guess), pkgPath,
+ base, packageConfig.main);
+ emitLegacyIndexDeprecation(guess, packageJSONUrl, base,
+ packageConfig.main);
+ return guess;
+ }
+ }
+ // Fallthrough.
}
-
- const baseStringified = isURL(base) ? base.href : base;
-
- const resolvedOption = FSLegacyMainResolve(packageJsonUrlString, packageConfig.main, baseStringified);
-
- const baseUrl = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ? `./${packageConfig.main}` : '';
- const resolvedUrl = new URL(baseUrl + legacyMainResolveExtensions[resolvedOption], packageJSONUrl);
-
- emitLegacyIndexDeprecation(resolvedUrl, packageJSONUrl, base, packageConfig.main);
-
- return resolvedUrl;
+ // Fallthrough.
+ if (fileExists(guess = new URL('./index.js', packageJSONUrl)));
+ // So fs.
+ else if (fileExists(guess = new URL('./index.json', packageJSONUrl)));
+ else if (fileExists(guess = new URL('./index.node', packageJSONUrl)));
+ else guess = undefined;
+ if (guess) {
+ emitLegacyIndexDeprecation(guess, fileURLToPath(guess), pkgPath,
+ base, packageConfig.main);
+ emitLegacyIndexDeprecation(guess, packageJSONUrl, base, packageConfig.main);
+ return guess;
+ }
+ // Not found.
+ throw new ERR_MODULE_NOT_FOUND(pkgPath, fileURLToPath(base), null);
+ throw new ERR_MODULE_NOT_FOUND(
+ fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
}
const encodedSepRegEx = /%2F|%5C/i;
diff --git a/src/node_file.cc b/src/node_file.cc
index 0bb70eb0fcd42ddf4d5e585065cf1ad8e74faab3..b565beae625d970ba92ab667a145d8897d4e8a6e 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -19,14 +19,12 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "node_file.h" // NOLINT(build/include_inline)
-#include "ada.h"
#include "aliased_buffer-inl.h"
#include "memory_tracker-inl.h"
#include "node_buffer.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "node_file-inl.h"
-#include "node_metadata.h"
#include "node_process-inl.h"
#include "node_stat_watcher.h"
#include "node_url.h"
@@ -3208,146 +3206,6 @@ constexpr std::array<std::string_view, 10> legacy_main_extensions = {
} // namespace
-void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
- CHECK_GE(args.Length(), 1);
- CHECK(args[0]->IsString());
-
- Environment* env = Environment::GetCurrent(args);
- auto isolate = env->isolate();
-
- Utf8Value utf8_package_json_url(isolate, args[0]);
- auto package_json_url =
- ada::parse<ada::url_aggregator>(utf8_package_json_url.ToStringView());
-
- if (!package_json_url) {
- THROW_ERR_INVALID_URL(isolate, "Invalid URL");
- return;
- }
-
- std::string package_initial_file = "";
-
- ada::result<ada::url_aggregator> file_path_url;
- std::optional<std::string> initial_file_path;
- std::string file_path;
-
- if (args.Length() >= 2 && args[1]->IsString()) {
- auto package_config_main = Utf8Value(isolate, args[1]).ToString();
-
- file_path_url = ada::parse<ada::url_aggregator>(
- std::string("./") + package_config_main, &package_json_url.value());
-
- if (!file_path_url) {
- THROW_ERR_INVALID_URL(isolate, "Invalid URL");
- return;
- }
-
- initial_file_path = node::url::FileURLToPath(env, *file_path_url);
- if (!initial_file_path.has_value()) {
- return;
- }
-
- FromNamespacedPath(&initial_file_path.value());
-
- package_initial_file = *initial_file_path;
-
- for (int i = 0; i < legacy_main_extensions_with_main_end; i++) {
- file_path = *initial_file_path + std::string(legacy_main_extensions[i]);
- // TODO(anonrig): Remove this when ToNamespacedPath supports std::string
- Local<Value> local_file_path =
- Buffer::Copy(env->isolate(), file_path.c_str(), file_path.size())
- .ToLocalChecked();
- BufferValue buff_file_path(isolate, local_file_path);
- ToNamespacedPath(env, &buff_file_path);
-
- switch (FilePathIsFile(env, buff_file_path.ToString())) {
- case BindingData::FilePathIsFileReturnType::kIsFile:
- return args.GetReturnValue().Set(i);
- case BindingData::FilePathIsFileReturnType::kIsNotFile:
- continue;
- case BindingData::FilePathIsFileReturnType::
- kThrowInsufficientPermissions:
- // the default behavior when do not have permission is to return
- // and exit the execution of the method as soon as possible
- // the internal function will throw the exception
- return;
- default:
- UNREACHABLE();
- }
- }
- }
-
- file_path_url =
- ada::parse<ada::url_aggregator>("./index", &package_json_url.value());
-
- if (!file_path_url) {
- THROW_ERR_INVALID_URL(isolate, "Invalid URL");
- return;
- }
-
- initial_file_path = node::url::FileURLToPath(env, *file_path_url);
- if (!initial_file_path.has_value()) {
- return;
- }
-
- FromNamespacedPath(&initial_file_path.value());
-
- for (int i = legacy_main_extensions_with_main_end;
- i < legacy_main_extensions_package_fallback_end;
- i++) {
- file_path = *initial_file_path + std::string(legacy_main_extensions[i]);
- // TODO(anonrig): Remove this when ToNamespacedPath supports std::string
- Local<Value> local_file_path =
- Buffer::Copy(env->isolate(), file_path.c_str(), file_path.size())
- .ToLocalChecked();
- BufferValue buff_file_path(isolate, local_file_path);
- ToNamespacedPath(env, &buff_file_path);
-
- switch (FilePathIsFile(env, buff_file_path.ToString())) {
- case BindingData::FilePathIsFileReturnType::kIsFile:
- return args.GetReturnValue().Set(i);
- case BindingData::FilePathIsFileReturnType::kIsNotFile:
- continue;
- case BindingData::FilePathIsFileReturnType::kThrowInsufficientPermissions:
- // the default behavior when do not have permission is to return
- // and exit the execution of the method as soon as possible
- // the internal function will throw the exception
- return;
- default:
- UNREACHABLE();
- }
- }
-
- if (package_initial_file == "")
- package_initial_file = *initial_file_path + ".js";
-
- std::optional<std::string> module_base;
-
- if (args.Length() >= 3 && args[2]->IsString()) {
- Utf8Value utf8_base_path(isolate, args[2]);
- auto base_url =
- ada::parse<ada::url_aggregator>(utf8_base_path.ToStringView());
-
- if (!base_url) {
- THROW_ERR_INVALID_URL(isolate, "Invalid URL");
- return;
- }
-
- module_base = node::url::FileURLToPath(env, *base_url);
- if (!module_base.has_value()) {
- return;
- }
- } else {
- THROW_ERR_INVALID_ARG_TYPE(
- isolate,
- "The \"base\" argument must be of type string or an instance of URL.");
- return;
- }
-
- THROW_ERR_MODULE_NOT_FOUND(isolate,
- "Cannot find package '%s' imported from %s",
- package_initial_file,
- *module_base);
-}
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackField("stats_field_array", stats_field_array);
@@ -3448,19 +3306,6 @@ InternalFieldInfoBase* BindingData::Serialize(int index) {
return info;
}
-void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
- Local<ObjectTemplate> target) {
- Isolate* isolate = isolate_data->isolate();
-
- SetMethod(
- isolate, target, "legacyMainResolve", BindingData::LegacyMainResolve);
-}
-
-void BindingData::RegisterExternalReferences(
- ExternalReferenceRegistry* registry) {
- registry->Register(BindingData::LegacyMainResolve);
-}
-
static void CreatePerIsolateProperties(IsolateData* isolate_data,
Local<ObjectTemplate> target) {
Isolate* isolate = isolate_data->isolate();
@@ -3520,7 +3365,6 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data,
SetMethod(isolate, target, "cpSyncCheckPaths", CpSyncCheckPaths);
StatWatcher::CreatePerIsolateProperties(isolate_data, target);
- BindingData::CreatePerIsolateProperties(isolate_data, target);
target->Set(
FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
@@ -3593,7 +3437,6 @@ BindingData* FSReqBase::binding_data() {
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(Access);
StatWatcher::RegisterExternalReferences(registry);
- BindingData::RegisterExternalReferences(registry);
registry->Register(GetFormatOfExtensionlessFile);
registry->Register(Close);
diff --git a/src/node_file.h b/src/node_file.h
index bdad1ae25f4892cbbfd8cc30c4d8b4a6f600edbc..5a3c462853aa784d9ef61ff4f63010848c48b92c 100644
--- a/src/node_file.h
+++ b/src/node_file.h
@@ -86,13 +86,6 @@ class BindingData : public SnapshotableObject {
SERIALIZABLE_OBJECT_METHODS()
SET_BINDING_ID(fs_binding_data)
- static void LegacyMainResolve(
- const v8::FunctionCallbackInfo<v8::Value>& args);
-
- static void CreatePerIsolateProperties(IsolateData* isolate_data,
- v8::Local<v8::ObjectTemplate> ctor);
- static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
-
void MemoryInfo(MemoryTracker* tracker) const override;
SET_SELF_SIZE(BindingData)
SET_MEMORY_INFO_NAME(BindingData)
diff --git a/test/es-module/test-cjs-legacyMainResolve.js b/test/es-module/test-cjs-legacyMainResolve.js
index edb567bce403f2d4df482c2549c6f7cec78c3588..4567ddc3715ac0d11facb0b567c5f5763699f4c9 100644
index 0bfeb567a22b1f9d9116b749d6cb3a8fda6bcc6a..17f137c595a9fef5f051fafc4682f206034c214c 100644
--- a/test/es-module/test-cjs-legacyMainResolve.js
+++ b/test/es-module/test-cjs-legacyMainResolve.js
@@ -82,7 +82,7 @@ describe('legacyMainResolve', () => {
{},
''
),
- { message: /instance of URL/, code: 'ERR_INVALID_ARG_TYPE' },
+ { message: 'Invalid URL', code: 'ERR_INVALID_URL' },
);
});
@@ -129,7 +129,7 @@ describe('legacyMainResolve', () => {
);
assert.throws(
() => legacyMainResolve(packageJsonUrl, { main: null }, packageJsonUrl),
- { message: /index\.js/, code: 'ERR_MODULE_NOT_FOUND' },
+ { code: 'ERR_MODULE_NOT_FOUND' },
+ { code: 'ERR_INTERNAL_ASSERTION' },
);
});
@@ -126,7 +384,7 @@ index edb567bce403f2d4df482c2549c6f7cec78c3588..4567ddc3715ac0d11facb0b567c5f576
assert.throws(
() => legacyMainResolve(packageJsonUrl, { main: null }, packageJsonUrl),
- { message: /index\.js/, code: 'ERR_MODULE_NOT_FOUND' },
+ { code: 'ERR_MODULE_NOT_FOUND' },
+ { code: 'ERR_INTERNAL_ASSERTION' },
);
});
@@ -135,11 +393,11 @@ index edb567bce403f2d4df482c2549c6f7cec78c3588..4567ddc3715ac0d11facb0b567c5f576
assert.throws(
() => legacyMainResolve(packageJsonUrl, { main: './index.node' }, packageJsonUrl),
- { message: /index\.node/, code: 'ERR_MODULE_NOT_FOUND' },
+ { code: 'ERR_MODULE_NOT_FOUND' },
+ { code: 'ERR_INTERNAL_ASSERTION' },
);
});
@@ -163,11 +163,11 @@ describe('legacyMainResolve', () => {
@@ -163,7 +163,7 @@ describe('legacyMainResolve', () => {
);
assert.throws(
() => legacyMainResolve(packageJsonUrl, { main: null }, undefined),
@@ -147,9 +405,4 @@ index edb567bce403f2d4df482c2549c6f7cec78c3588..4567ddc3715ac0d11facb0b567c5f576
+ { message: 'The "path" argument must be of type string or an instance of URL. Received undefined', code: 'ERR_INVALID_ARG_TYPE' },
);
});
- it('should interpret main as a path, not a URL', () => {
+ it.skip('should interpret main as a path, not a URL', () => {
const packageJsonUrl = fixtures.fileURL('/es-modules/legacy-main-resolver/package.json');
assert.deepStrictEqual(
legacyMainResolve(packageJsonUrl, { main: '../folder%25with percentage#/' }, packageJsonUrl),
});

View File

@@ -6,10 +6,10 @@ Subject: Pass all globals through "require"
(cherry picked from commit 7d015419cb7a0ecfe6728431a4ed2056cd411d62)
diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js
index b0210e4d96348c77da9eabbe8f3d292337cd6ae4..ad8d41a06bde1ca22d0245fa49143e080365b5e1 100644
index 451b7c2195e7ad3ab0bde95259e054dc431d7de9..d49941881e6cfd8647a6d44a57e0daaf1c874702 100644
--- a/lib/internal/modules/cjs/loader.js
+++ b/lib/internal/modules/cjs/loader.js
@@ -183,6 +183,13 @@ const {
@@ -182,6 +182,13 @@ const {
CHAR_FORWARD_SLASH,
} = require('internal/constants');

View File

@@ -7,7 +7,7 @@ We use this to allow node's 'fs' module to read from ASAR files as if they were
a real filesystem.
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
index 11d585bc5b3e47b36877ca8306b72f571acb7d09..65d42428c70a3242f7076f1c1a4cec027a9c9829 100644
index f7a62364b6107ab0bad33ea2f745703c746991dc..bab2aaf3db66452216035db594dc3ebdc3606c8b 100644
--- a/lib/internal/bootstrap/node.js
+++ b/lib/internal/bootstrap/node.js
@@ -134,6 +134,10 @@ process.domain = null;

View File

@@ -15,7 +15,7 @@ In a future release of simdjson, we will provide a more convenient function that
avoids such ugly workaround.
diff --git a/src/node_modules.cc b/src/node_modules.cc
index dfd115a9eccc6b58d63a72ac450a1497354482dd..16a9f923148835daa95d3578e5941b284ff71434 100644
index 3bedd2dfecb49c3f69ea59b70d72b8b6fc605132..2b0e4905dd557e73542cf052ba81327b1e1e471f 100644
--- a/src/node_modules.cc
+++ b/src/node_modules.cc
@@ -100,11 +100,23 @@ const BindingData::PackageConfig* BindingData::GetPackageJSON(

View File

@@ -16,7 +16,7 @@ patch:
(cherry picked from commit 30329d06235a9f9733b1d4da479b403462d1b326)
diff --git a/src/env-inl.h b/src/env-inl.h
index 3b041dd28ba32f028ecbb7d87b82f9ddee406b4f..5436c1a0f21e261f2eb2fdbb7f679d4f92a14ffd 100644
index 28a15aa741ddd40c664aae641797e7cc2813442f..08fe98e10b7716c694bbc882299fe0ed9e282d73 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -62,31 +62,6 @@ inline uv_loop_t* IsolateData::event_loop() const {
@@ -52,7 +52,7 @@ index 3b041dd28ba32f028ecbb7d87b82f9ddee406b4f..5436c1a0f21e261f2eb2fdbb7f679d4f
return &(wrapper_data_->cppgc_id);
}
diff --git a/src/env.cc b/src/env.cc
index 130524cad713e8aa685feaa8c384fe4db9452500..21bc5b8a3326e759ce12b865e49029cf8ffe9995 100644
index 665b064091d4cc42a4dc9ee5b0ea9e2f190338ca..4c8cb75945d82544ce2237d94cd1406d15efe424 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -23,6 +23,7 @@
@@ -63,7 +63,7 @@ index 130524cad713e8aa685feaa8c384fe4db9452500..21bc5b8a3326e759ce12b865e49029cf
#include <algorithm>
#include <atomic>
@@ -70,7 +71,6 @@ using v8::TryCatch;
@@ -71,7 +72,6 @@ using v8::TryCatch;
using v8::Uint32;
using v8::Undefined;
using v8::Value;
@@ -146,7 +146,7 @@ index 130524cad713e8aa685feaa8c384fe4db9452500..21bc5b8a3326e759ce12b865e49029cf
void IsolateData::MemoryInfo(MemoryTracker* tracker) const {
diff --git a/src/env.h b/src/env.h
index 3ef093e612b23d5e1e7cacf56055e5f9818bcb02..9dfc1364c7206377b6d0d088b456c357c23a9151 100644
index 49ca9c0042ccf22ad1fffa54f05fd443cbc681ba..945535d0dc40f1a32f7e3ecf7d50361e591ba6c8 100644
--- a/src/env.h
+++ b/src/env.h
@@ -175,10 +175,6 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {

View File

@@ -26,10 +26,10 @@ index 3d8ccc77b5952a999c5fe48792259d32b402c460..867a1c4aca54b9d41490d23a5eb55088
}
diff --git a/src/histogram.cc b/src/histogram.cc
index c62a5b8952400ff0dd8818c31a3e07622b63725c..36f61f57e951e1abfeb2fedb831b55c61363bcbc 100644
index 4dbdea9be5721486d71a9dda77311b4919d450a3..4aacaa2a5d12533a039b4b96cb7f1fd79063d50f 100644
--- a/src/histogram.cc
+++ b/src/histogram.cc
@@ -195,7 +195,8 @@ void HistogramBase::FastRecord(Local<Value> unused,
@@ -193,7 +193,8 @@ void HistogramBase::FastRecord(Local<Value> receiver,
const int64_t value,
FastApiCallbackOptions& options) {
if (value < 1) {
@@ -40,13 +40,14 @@ index c62a5b8952400ff0dd8818c31a3e07622b63725c..36f61f57e951e1abfeb2fedb831b55c6
}
HistogramBase* histogram;
diff --git a/src/node_file.cc b/src/node_file.cc
index 6b98a13099990918dc619c47124c8538bbee5e2d..307492bf3dfce7b4a476c448bec666b8116dc431 100644
index b565beae625d970ba92ab667a145d8897d4e8a6e..31c2fe82299d6905855c4efffeea4a4d161a88d5 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -1060,22 +1060,10 @@ static int32_t FastInternalModuleStat(
@@ -1049,23 +1049,10 @@ static int32_t FastInternalModuleStat(
const FastOneByteString& input,
// NOLINTNEXTLINE(runtime/references) This is V8 api.
FastApiCallbackOptions& options) {
// This needs a HandleScope which needs an isolate.
- // This needs a HandleScope which needs an isolate.
- Isolate* isolate = Isolate::TryGetCurrent();
- if (!isolate) {
- options.fallback = true;
@@ -59,24 +60,24 @@ index 6b98a13099990918dc619c47124c8538bbee5e2d..307492bf3dfce7b4a476c448bec666b8
+ HandleScope scope(env->isolate());
auto path = std::filesystem::path(input.data, input.data + input.length);
- if (!env->permission()->is_granted(
- env, permission::PermissionScope::kFileSystemRead, path.string()))
- [[unlikely]] {
- if (UNLIKELY(!env->permission()->is_granted(
- env, permission::PermissionScope::kFileSystemRead, path.string()))) {
- options.fallback = true;
- return -1;
- }
-
switch (std::filesystem::status(path).type()) {
case std::filesystem::file_type::directory:
return 1;
diff --git a/src/node_wasi.cc b/src/node_wasi.cc
index 468c2e59903fefe58d9c178d3afac3ef5b09f611..23a376e52e08a8af49dd47c47488552e01287426 100644
index ad1da44a01f437c97e06a3857eebd2edcebc83da..7123278e1a0942b61a76e9b1e7464eb8b5064079 100644
--- a/src/node_wasi.cc
+++ b/src/node_wasi.cc
@@ -251,17 +251,19 @@ R WASI::WasiFunction<FT, F, R, Args...>::FastCallback(
return EinvalError<R>();
}
@@ -248,17 +248,18 @@ R WASI::WasiFunction<FT, F, R, Args...>::FastCallback(
WASI* wasi = reinterpret_cast<WASI*>(BaseObject::FromJSObject(receiver));
if (UNLIKELY(wasi == nullptr)) return EinvalError<R>();
- if (options.wasm_memory == nullptr || wasi->memory_.IsEmpty()) [[unlikely]] {
- if (UNLIKELY(options.wasm_memory == nullptr || wasi->memory_.IsEmpty())) {
- // fallback to slow path which to throw an error about missing memory.
- options.fallback = true;
+ v8::Isolate* isolate = receiver->GetIsolate();
@@ -86,16 +87,15 @@ index 468c2e59903fefe58d9c178d3afac3ef5b09f611..23a376e52e08a8af49dd47c47488552e
return EinvalError<R>();
}
- uint8_t* memory = nullptr;
- CHECK(options.wasm_memory->getStorageIfAligned(&memory));
- return F(*wasi,
- {reinterpret_cast<char*>(memory), options.wasm_memory->length()},
- args...);
- CHECK(LIKELY(options.wasm_memory->getStorageIfAligned(&memory)));
+ Local<ArrayBuffer> ab = wasi->memory_.Get(isolate)->Buffer();
+ size_t mem_size = ab->ByteLength();
+ char* mem_data = static_cast<char*>(ab->Data());
+ CHECK_NOT_NULL(mem_data);
+
- return F(*wasi,
- {reinterpret_cast<char*>(memory), options.wasm_memory->length()},
- args...);
+ return F(*wasi, {mem_data, mem_size}, args...);
}

View File

@@ -7,10 +7,10 @@ This refactors several allocators to allocate within the V8 memory cage,
allowing them to be compatible with the V8_SANDBOXED_POINTERS feature.
diff --git a/src/api/environment.cc b/src/api/environment.cc
index e044f10284f31f1862b18be752a04b3bd5d53401..89ce587cac4506c4218a9316fe0b68070a7a8504 100644
index 5fc1b6f2446d7c786024eb60800e2edab613dcd1..f59abcb21d64b910d8d42eb23c03109f62558813 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -102,6 +102,14 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
@@ -101,6 +101,14 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
return result;
}
@@ -26,7 +26,7 @@ index e044f10284f31f1862b18be752a04b3bd5d53401..89ce587cac4506c4218a9316fe0b6807
void* ret;
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc
index f973941b3b9ea954f35f2ea135f8ee3d77b98958..743c63ff7e3f526829919a8f2de7ebd625a93fbc 100644
index 33ffbbb85d05f5356183e3aa1ca23707c5629b5d..008d212ebe25b0022020379aa08963c12828940c 100644
--- a/src/crypto/crypto_dh.cc
+++ b/src/crypto/crypto_dh.cc
@@ -51,6 +51,25 @@ void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const {
@@ -64,7 +64,7 @@ index f973941b3b9ea954f35f2ea135f8ee3d77b98958..743c63ff7e3f526829919a8f2de7ebd6
auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>());
diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc
index 8a6a36a3c31532ed585c287ba8cee14026d315b4..3d449b5853f359d63e1b88671a857bf9152ff6af 100644
index ee81048caab4ccfe26ea9e677782c9c955d162a9..643c9d31dc2737faa2ec51684ffceb35a1014a58 100644
--- a/src/crypto/crypto_util.cc
+++ b/src/crypto/crypto_util.cc
@@ -326,10 +326,35 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept {
@@ -156,10 +156,10 @@ index 922e77091d72172ed6cfc5e8477901e3608396c5..16a236c69caed6d60248c7973531a95a
v8::Local<v8::ArrayBuffer> ToArrayBuffer(Environment* env);
diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc
index 9b9bb7be9a8daca98a2635bf13cb6d1d561ea5fb..81afe2b5f7398f0c20b340648ca75022470be544 100644
index af2f953f0388dbce326b0c519de3883552f8f009..7fb34057a486914dd886ec4d3d23be90cccb4fea 100644
--- a/src/crypto/crypto_x509.cc
+++ b/src/crypto/crypto_x509.cc
@@ -175,6 +175,19 @@ MaybeLocal<Value> ToV8Value(Local<Context> context, const BIOPointer& bio) {
@@ -174,6 +174,19 @@ MaybeLocal<Value> ToV8Value(Local<Context> context, const BIOPointer& bio) {
MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) {
if (bio == nullptr || !*bio) return {};
BUF_MEM* mem = *bio;
@@ -179,7 +179,7 @@ index 9b9bb7be9a8daca98a2635bf13cb6d1d561ea5fb..81afe2b5f7398f0c20b340648ca75022
auto backing = ArrayBuffer::NewBackingStore(
mem->data,
mem->length,
@@ -182,6 +195,8 @@ MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) {
@@ -181,6 +194,8 @@ MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) {
BIOPointer free_me(static_cast<BIO*>(data));
},
bio->release());
@@ -229,10 +229,10 @@ index 43bb68351bf0a68285e464601013bbdbd5d5df5f..4126bbff080548c91154a6dcc437359c
constexpr const char* EncodingName(const enum encoding encoding) {
diff --git a/src/node_internals.h b/src/node_internals.h
index 85b666e11f5654afe2a2f192e629221f2133b165..bd8d65247ad3ba4878f1288ab2b66e3598982b09 100644
index fe2d25decd883085e4c3f368ab4acc01a7f66f6e..bcd5c87afcff9c56429443363c63fc8079521451 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -117,7 +117,9 @@ v8::Maybe<void> InitializePrimordials(v8::Local<v8::Context> context);
@@ -117,7 +117,9 @@ v8::Maybe<bool> InitializePrimordials(v8::Local<v8::Context> context);
class NodeArrayBufferAllocator : public ArrayBufferAllocator {
public:
@@ -369,18 +369,3 @@ index 9787b14352753c5e0f8dc2b90093680e7cd10f1a..31af9e62396368af1b81f8841a705fd3
auto ab = ArrayBuffer::New(isolate, std::move(bs));
v8::Local<Uint8Array> u8 = v8::Uint8Array::New(ab, 0, 1);
diff --git a/test/parallel/test-buffer-tostring-range.js b/test/parallel/test-buffer-tostring-range.js
index 73fec107a36c3db4af6f492137d0ca174f2d0547..a1153ec381f7b12a1640b611073f6997e1ec5696 100644
--- a/test/parallel/test-buffer-tostring-range.js
+++ b/test/parallel/test-buffer-tostring-range.js
@@ -102,8 +102,8 @@ assert.throws(() => {
// Must not throw when start and end are within kMaxLength
// Cannot test on 32bit machine as we are testing the case
// when start and end are above the threshold
-if (!common.openSSLIsBoringSSL) {
+/*
const threshold = 0xFFFFFFFF;
const largeBuffer = Buffer.alloc(threshold + 20);
largeBuffer.toString('utf8', threshold, threshold + 20);
-}
+*/

View File

@@ -7,7 +7,7 @@ Instead of disabling the tests, flag them as flaky so they still run
but don't cause CI failures on flakes.
diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status
index 6b5b0ed739bc8600d46c2f65993b86a4092c680c..40beb6a5ec2e129181ce74afce4021bf88286989 100644
index 24e1a74886bad536dc08df75fbdb0508e4e1420a..7f3be73474557788050a9110b0e29e602b7d6397 100644
--- a/test/parallel/parallel.status
+++ b/test/parallel/parallel.status
@@ -5,6 +5,16 @@ prefix parallel
@@ -28,7 +28,7 @@ index 6b5b0ed739bc8600d46c2f65993b86a4092c680c..40beb6a5ec2e129181ce74afce4021bf
test-net-write-fully-async-hex-string: PASS, FLAKY
# https://github.com/nodejs/node/issues/52273
diff --git a/test/sequential/sequential.status b/test/sequential/sequential.status
index 073b29cce8dbca4c8d92ad666f9244ad511296db..338d20263f29a630febb96567f3cb708623bd09a 100644
index a539649d5537376a6a2ac9a7a46051b8648f0cb1..a03c86b752772be7ae36fab31faeccf3b0ccff64 100644
--- a/test/sequential/sequential.status
+++ b/test/sequential/sequential.status
@@ -7,6 +7,18 @@ prefix sequential

View File

@@ -64,8 +64,6 @@
"parallel/test-snapshot-namespaced-builtin",
"parallel/test-snapshot-net",
"parallel/test-snapshot-reproducible",
"parallel/test-snapshot-stack-trace-limit",
"parallel/test-snapshot-stack-trace-limit-mutation",
"parallel/test-snapshot-typescript",
"parallel/test-snapshot-umd",
"parallel/test-snapshot-warning",

View File

@@ -4,15 +4,9 @@
#include "shell/browser/api/electron_api_global_shortcut.h"
#include <string>
#include <vector>
#include "base/containers/contains.h"
#include "base/strings/utf_string_conversions.h"
#include "base/uuid.h"
#include "components/prefs/pref_service.h"
#include "electron/shell/browser/electron_browser_context.h"
#include "electron/shell/common/electron_constants.h"
#include "extensions/common/command.h"
#include "gin/dictionary.h"
#include "gin/handle.h"
@@ -68,12 +62,7 @@ void GlobalShortcut::OnKeyPressed(const ui::Accelerator& accelerator) {
void GlobalShortcut::ExecuteCommand(const extensions::ExtensionId& extension_id,
const std::string& command_id) {
if (!base::Contains(command_callback_map_, command_id)) {
// This should never occur, because if it does, GlobalShortcutListener
// notifies us with wrong command.
NOTREACHED();
}
command_callback_map_[command_id].Run();
// Ignore extension commands
}
bool GlobalShortcut::RegisterAll(
@@ -114,56 +103,13 @@ bool GlobalShortcut::Register(const ui::Accelerator& accelerator,
}
#endif
auto* instance = GlobalShortcutListener::GetInstance();
if (!instance) {
if (!GlobalShortcutListener::GetInstance()->RegisterAccelerator(accelerator,
this)) {
return false;
}
if (instance->IsRegistrationHandledExternally()) {
auto* context = ElectronBrowserContext::From("", false);
PrefService* prefs = context->prefs();
// Need a unique profile id. Set one if not generated yet, otherwise re-use
// the same so that the session for the globalShortcuts is able to get
// already registered shortcuts from the previous session. This will be used
// by GlobalShortcutListenerLinux as a session key.
std::string profile_id = prefs->GetString(kElectronGlobalShortcutsUuid);
if (profile_id.empty()) {
profile_id = base::Uuid::GenerateRandomV4().AsLowercaseString();
prefs->SetString(kElectronGlobalShortcutsUuid, profile_id);
}
// There is no way to get command id for the accelerator as it's extensions'
// thing. Instead, we can convert it to string in a following example form
// - std::string("Alt+Shift+K"). That must be sufficient enough for us to
// map this accelerator with registered commands.
const std::string command_str =
extensions::Command::AcceleratorToString(accelerator);
ui::CommandMap commands;
extensions::Command command(
command_str, base::UTF8ToUTF16("Electron shortcut " + command_str),
/*accelerator=*/std::string(), /*global=*/true);
command.set_accelerator(accelerator);
commands[command_str] = command;
// In order to distinguish the shortcuts, we must register multiple commands
// as different extensions. Otherwise, each shortcut will be an alternative
// for the very first registered and we'll not be able to distinguish them.
// For example, if Alt+Shift+K is registered first, registering and pressing
// Alt+Shift+M will trigger global shortcuts, but the command id that is
// received by GlobalShortcut will correspond to Alt+Shift+K as our command
// id is basically a stringified accelerator.
const std::string fake_extension_id = command_str + "+" + profile_id;
instance->OnCommandsChanged(fake_extension_id, profile_id, commands, this);
command_callback_map_[command_str] = callback;
return true;
} else {
if (instance->RegisterAccelerator(accelerator, this)) {
accelerator_callback_map_[accelerator] = callback;
return true;
}
}
return false;
accelerator_callback_map_[accelerator] = callback;
return true;
}
void GlobalShortcut::Unregister(const ui::Accelerator& accelerator) {
@@ -181,10 +127,8 @@ void GlobalShortcut::Unregister(const ui::Accelerator& accelerator) {
}
#endif
if (GlobalShortcutListener::GetInstance()) {
GlobalShortcutListener::GetInstance()->UnregisterAccelerator(accelerator,
this);
}
GlobalShortcutListener::GetInstance()->UnregisterAccelerator(accelerator,
this);
}
void GlobalShortcut::UnregisterSome(
@@ -195,12 +139,7 @@ void GlobalShortcut::UnregisterSome(
}
bool GlobalShortcut::IsRegistered(const ui::Accelerator& accelerator) {
if (base::Contains(accelerator_callback_map_, accelerator)) {
return true;
}
const std::string command_str =
extensions::Command::AcceleratorToString(accelerator);
return base::Contains(command_callback_map_, command_str);
return base::Contains(accelerator_callback_map_, accelerator);
}
void GlobalShortcut::UnregisterAll() {
@@ -210,9 +149,7 @@ void GlobalShortcut::UnregisterAll() {
return;
}
accelerator_callback_map_.clear();
if (GlobalShortcutListener::GetInstance()) {
GlobalShortcutListener::GetInstance()->UnregisterAccelerators(this);
}
GlobalShortcutListener::GetInstance()->UnregisterAccelerators(this);
}
// static

View File

@@ -44,7 +44,6 @@ class GlobalShortcut final
private:
typedef std::map<ui::Accelerator, base::RepeatingClosure>
AcceleratorCallbackMap;
typedef std::map<std::string, base::RepeatingClosure> CommandCallbackMap;
bool RegisterAll(const std::vector<ui::Accelerator>& accelerators,
const base::RepeatingClosure& callback);
@@ -61,7 +60,6 @@ class GlobalShortcut final
const std::string& command_id) override;
AcceleratorCallbackMap accelerator_callback_map_;
CommandCallbackMap command_callback_map_;
};
} // namespace electron::api

View File

@@ -236,6 +236,10 @@ const char* Notification::GetTypeName() {
return GetClassName();
}
void Notification::WillBeDestroyed() {
ClearWeak();
}
} // namespace electron::api
namespace {

View File

@@ -57,6 +57,9 @@ class Notification final : public gin::Wrappable<Notification>,
static gin::WrapperInfo kWrapperInfo;
const char* GetTypeName() override;
// gin_helper::CleanedUpAtExit
void WillBeDestroyed() override;
// disable copy
Notification(const Notification&) = delete;
Notification& operator=(const Notification&) = delete;

View File

@@ -13,11 +13,18 @@
#include "gin/data_object_builder.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "shell/browser/api/electron_api_service_worker_main.h"
#include "shell/browser/electron_browser_context.h"
#include "shell/browser/javascript_environment.h"
#include "shell/common/gin_converters/gurl_converter.h"
#include "shell/common/gin_converters/service_worker_converter.h"
#include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/promise.h"
#include "shell/common/node_util.h"
using ServiceWorkerStatus =
content::ServiceWorkerRunningInfo::ServiceWorkerVersionStatus;
namespace electron::api {
@@ -72,8 +79,8 @@ gin::WrapperInfo ServiceWorkerContext::kWrapperInfo = {gin::kEmbedderNativeGin};
ServiceWorkerContext::ServiceWorkerContext(
v8::Isolate* isolate,
ElectronBrowserContext* browser_context) {
service_worker_context_ =
browser_context->GetDefaultStoragePartition()->GetServiceWorkerContext();
storage_partition_ = browser_context->GetDefaultStoragePartition();
service_worker_context_ = storage_partition_->GetServiceWorkerContext();
service_worker_context_->AddObserver(this);
}
@@ -81,6 +88,23 @@ ServiceWorkerContext::~ServiceWorkerContext() {
service_worker_context_->RemoveObserver(this);
}
void ServiceWorkerContext::OnRunningStatusChanged(
int64_t version_id,
blink::EmbeddedWorkerStatus running_status) {
ServiceWorkerMain* worker =
ServiceWorkerMain::FromVersionID(version_id, storage_partition_);
if (worker)
worker->OnRunningStatusChanged(running_status);
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
EmitWithoutEvent("running-status-changed",
gin::DataObjectBuilder(isolate)
.Set("versionId", version_id)
.Set("runningStatus", running_status)
.Build());
}
void ServiceWorkerContext::OnReportConsoleMessage(
int64_t version_id,
const GURL& scope,
@@ -105,6 +129,32 @@ void ServiceWorkerContext::OnRegistrationCompleted(const GURL& scope) {
gin::DataObjectBuilder(isolate).Set("scope", scope).Build());
}
void ServiceWorkerContext::OnVersionRedundant(int64_t version_id,
const GURL& scope) {
ServiceWorkerMain* worker =
ServiceWorkerMain::FromVersionID(version_id, storage_partition_);
if (worker)
worker->OnVersionRedundant();
}
void ServiceWorkerContext::OnVersionStartingRunning(int64_t version_id) {
OnRunningStatusChanged(version_id, blink::EmbeddedWorkerStatus::kStarting);
}
void ServiceWorkerContext::OnVersionStartedRunning(
int64_t version_id,
const content::ServiceWorkerRunningInfo& running_info) {
OnRunningStatusChanged(version_id, blink::EmbeddedWorkerStatus::kRunning);
}
void ServiceWorkerContext::OnVersionStoppingRunning(int64_t version_id) {
OnRunningStatusChanged(version_id, blink::EmbeddedWorkerStatus::kStopping);
}
void ServiceWorkerContext::OnVersionStoppedRunning(int64_t version_id) {
OnRunningStatusChanged(version_id, blink::EmbeddedWorkerStatus::kStopped);
}
void ServiceWorkerContext::OnDestruct(content::ServiceWorkerContext* context) {
if (context == service_worker_context_) {
delete this;
@@ -124,7 +174,7 @@ v8::Local<v8::Value> ServiceWorkerContext::GetAllRunningWorkerInfo(
return builder.Build();
}
v8::Local<v8::Value> ServiceWorkerContext::GetWorkerInfoFromID(
v8::Local<v8::Value> ServiceWorkerContext::GetInfoFromVersionID(
gin_helper::ErrorThrower thrower,
int64_t version_id) {
const base::flat_map<int64_t, content::ServiceWorkerRunningInfo>& info_map =
@@ -138,6 +188,87 @@ v8::Local<v8::Value> ServiceWorkerContext::GetWorkerInfoFromID(
std::move(iter->second));
}
v8::Local<v8::Value> ServiceWorkerContext::GetFromVersionID(
gin_helper::ErrorThrower thrower,
int64_t version_id) {
util::EmitWarning(thrower.isolate(),
"The session.serviceWorkers.getFromVersionID API is "
"deprecated, use "
"session.serviceWorkers.getInfoFromVersionID instead.",
"ServiceWorkersDeprecateGetFromVersionID");
return GetInfoFromVersionID(thrower, version_id);
}
v8::Local<v8::Value> ServiceWorkerContext::GetWorkerFromVersionID(
v8::Isolate* isolate,
int64_t version_id) {
return ServiceWorkerMain::From(isolate, service_worker_context_,
storage_partition_, version_id)
.ToV8();
}
gin::Handle<ServiceWorkerMain>
ServiceWorkerContext::GetWorkerFromVersionIDIfExists(v8::Isolate* isolate,
int64_t version_id) {
ServiceWorkerMain* worker =
ServiceWorkerMain::FromVersionID(version_id, storage_partition_);
if (!worker)
return gin::Handle<ServiceWorkerMain>();
return gin::CreateHandle(isolate, worker);
}
v8::Local<v8::Promise> ServiceWorkerContext::StartWorkerForScope(
v8::Isolate* isolate,
GURL scope) {
auto shared_promise =
std::make_shared<gin_helper::Promise<v8::Local<v8::Value>>>(isolate);
v8::Local<v8::Promise> handle = shared_promise->GetHandle();
blink::StorageKey storage_key =
blink::StorageKey::CreateFirstParty(url::Origin::Create(scope));
service_worker_context_->StartWorkerForScope(
scope, storage_key,
base::BindOnce(&ServiceWorkerContext::DidStartWorkerForScope,
weak_ptr_factory_.GetWeakPtr(), shared_promise),
base::BindOnce(&ServiceWorkerContext::DidFailToStartWorkerForScope,
weak_ptr_factory_.GetWeakPtr(), shared_promise));
return handle;
}
void ServiceWorkerContext::DidStartWorkerForScope(
std::shared_ptr<gin_helper::Promise<v8::Local<v8::Value>>> shared_promise,
int64_t version_id,
int process_id,
int thread_id) {
v8::Isolate* isolate = shared_promise->isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> service_worker_main =
GetWorkerFromVersionID(isolate, version_id);
shared_promise->Resolve(service_worker_main);
shared_promise.reset();
}
void ServiceWorkerContext::DidFailToStartWorkerForScope(
std::shared_ptr<gin_helper::Promise<v8::Local<v8::Value>>> shared_promise,
content::StatusCodeResponse status) {
shared_promise->RejectWithErrorMessage("Failed to start service worker.");
shared_promise.reset();
}
v8::Local<v8::Promise> ServiceWorkerContext::StopAllWorkers(
v8::Isolate* isolate) {
auto promise = gin_helper::Promise<void>(isolate);
v8::Local<v8::Promise> handle = promise.GetHandle();
service_worker_context_->StopAllServiceWorkers(base::BindOnce(
[](gin_helper::Promise<void> promise) { promise.Resolve(); },
std::move(promise)));
return handle;
}
// static
gin::Handle<ServiceWorkerContext> ServiceWorkerContext::Create(
v8::Isolate* isolate,
@@ -153,8 +284,16 @@ gin::ObjectTemplateBuilder ServiceWorkerContext::GetObjectTemplateBuilder(
ServiceWorkerContext>::GetObjectTemplateBuilder(isolate)
.SetMethod("getAllRunning",
&ServiceWorkerContext::GetAllRunningWorkerInfo)
.SetMethod("getFromVersionID",
&ServiceWorkerContext::GetWorkerInfoFromID);
.SetMethod("getFromVersionID", &ServiceWorkerContext::GetFromVersionID)
.SetMethod("getInfoFromVersionID",
&ServiceWorkerContext::GetInfoFromVersionID)
.SetMethod("getWorkerFromVersionID",
&ServiceWorkerContext::GetWorkerFromVersionID)
.SetMethod("_getWorkerFromVersionIDIfExists",
&ServiceWorkerContext::GetWorkerFromVersionIDIfExists)
.SetMethod("startWorkerForScope",
&ServiceWorkerContext::StartWorkerForScope)
.SetMethod("_stopAllWorkers", &ServiceWorkerContext::StopAllWorkers);
}
const char* ServiceWorkerContext::GetTypeName() {

View File

@@ -10,18 +10,30 @@
#include "content/public/browser/service_worker_context_observer.h"
#include "gin/wrappable.h"
#include "shell/browser/event_emitter_mixin.h"
#include "third_party/blink/public/common/service_worker/embedded_worker_status.h"
namespace content {
class StoragePartition;
}
namespace gin {
template <typename T>
class Handle;
} // namespace gin
namespace gin_helper {
template <typename T>
class Promise;
} // namespace gin_helper
namespace electron {
class ElectronBrowserContext;
namespace api {
class ServiceWorkerMain;
class ServiceWorkerContext final
: public gin::Wrappable<ServiceWorkerContext>,
public gin_helper::EventEmitterMixin<ServiceWorkerContext>,
@@ -32,14 +44,39 @@ class ServiceWorkerContext final
ElectronBrowserContext* browser_context);
v8::Local<v8::Value> GetAllRunningWorkerInfo(v8::Isolate* isolate);
v8::Local<v8::Value> GetWorkerInfoFromID(gin_helper::ErrorThrower thrower,
int64_t version_id);
v8::Local<v8::Value> GetInfoFromVersionID(gin_helper::ErrorThrower thrower,
int64_t version_id);
v8::Local<v8::Value> GetFromVersionID(gin_helper::ErrorThrower thrower,
int64_t version_id);
v8::Local<v8::Value> GetWorkerFromVersionID(v8::Isolate* isolate,
int64_t version_id);
gin::Handle<ServiceWorkerMain> GetWorkerFromVersionIDIfExists(
v8::Isolate* isolate,
int64_t version_id);
v8::Local<v8::Promise> StartWorkerForScope(v8::Isolate* isolate, GURL scope);
void DidStartWorkerForScope(
std::shared_ptr<gin_helper::Promise<v8::Local<v8::Value>>> shared_promise,
int64_t version_id,
int process_id,
int thread_id);
void DidFailToStartWorkerForScope(
std::shared_ptr<gin_helper::Promise<v8::Local<v8::Value>>> shared_promise,
content::StatusCodeResponse status);
void StopWorkersForScope(GURL scope);
v8::Local<v8::Promise> StopAllWorkers(v8::Isolate* isolate);
// content::ServiceWorkerContextObserver
void OnReportConsoleMessage(int64_t version_id,
const GURL& scope,
const content::ConsoleMessage& message) override;
void OnRegistrationCompleted(const GURL& scope) override;
void OnVersionStartingRunning(int64_t version_id) override;
void OnVersionStartedRunning(
int64_t version_id,
const content::ServiceWorkerRunningInfo& running_info) override;
void OnVersionStoppingRunning(int64_t version_id) override;
void OnVersionStoppedRunning(int64_t version_id) override;
void OnVersionRedundant(int64_t version_id, const GURL& scope) override;
void OnDestruct(content::ServiceWorkerContext* context) override;
// gin::Wrappable
@@ -58,8 +95,15 @@ class ServiceWorkerContext final
~ServiceWorkerContext() override;
private:
void OnRunningStatusChanged(int64_t version_id,
blink::EmbeddedWorkerStatus running_status);
raw_ptr<content::ServiceWorkerContext> service_worker_context_;
// Service worker registration and versions are unique to a storage partition.
// Keep a reference to the storage partition to be used for lookups.
raw_ptr<content::StoragePartition> storage_partition_;
base::WeakPtrFactory<ServiceWorkerContext> weak_ptr_factory_{this};
};

View File

@@ -0,0 +1,359 @@
// Copyright (c) 2025 Salesforce, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/api/electron_api_service_worker_main.h"
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "base/logging.h"
#include "base/no_destructor.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h" // nogncheck
#include "content/browser/service_worker/service_worker_version.h" // nogncheck
#include "electron/shell/common/api/api.mojom.h"
#include "gin/handle.h"
#include "gin/object_template_builder.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "shell/browser/api/message_port.h"
#include "shell/browser/browser.h"
#include "shell/browser/javascript_environment.h"
#include "shell/common/gin_converters/blink_converter.h"
#include "shell/common/gin_converters/gurl_converter.h"
#include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/error_thrower.h"
#include "shell/common/gin_helper/object_template_builder.h"
#include "shell/common/gin_helper/promise.h"
#include "shell/common/node_includes.h"
#include "shell/common/v8_util.h"
namespace {
// Use private API to get the live version of the service worker. This will
// exist while in starting, stopping, or stopped running status.
content::ServiceWorkerVersion* GetLiveVersion(
content::ServiceWorkerContext* service_worker_context,
int64_t version_id) {
auto* wrapper = static_cast<content::ServiceWorkerContextWrapper*>(
service_worker_context);
return wrapper->GetLiveVersion(version_id);
}
// Get a public ServiceWorkerVersionBaseInfo object directly from the service
// worker.
std::optional<content::ServiceWorkerVersionBaseInfo> GetLiveVersionInfo(
content::ServiceWorkerContext* service_worker_context,
int64_t version_id) {
auto* version = GetLiveVersion(service_worker_context, version_id);
if (version) {
return version->GetInfo();
}
return std::nullopt;
}
} // namespace
namespace electron::api {
// ServiceWorkerKey -> ServiceWorkerMain*
typedef std::unordered_map<ServiceWorkerKey,
ServiceWorkerMain*,
ServiceWorkerKey::Hasher>
VersionIdMap;
VersionIdMap& GetVersionIdMap() {
static base::NoDestructor<VersionIdMap> instance;
return *instance;
}
ServiceWorkerMain* FromServiceWorkerKey(const ServiceWorkerKey& key) {
VersionIdMap& version_map = GetVersionIdMap();
auto iter = version_map.find(key);
auto* service_worker = iter == version_map.end() ? nullptr : iter->second;
return service_worker;
}
// static
ServiceWorkerMain* ServiceWorkerMain::FromVersionID(
int64_t version_id,
const content::StoragePartition* storage_partition) {
ServiceWorkerKey key(version_id, storage_partition);
return FromServiceWorkerKey(key);
}
gin::WrapperInfo ServiceWorkerMain::kWrapperInfo = {gin::kEmbedderNativeGin};
ServiceWorkerMain::ServiceWorkerMain(content::ServiceWorkerContext* sw_context,
int64_t version_id,
const ServiceWorkerKey& key)
: version_id_(version_id), key_(key), service_worker_context_(sw_context) {
GetVersionIdMap().emplace(key_, this);
InvalidateVersionInfo();
}
ServiceWorkerMain::~ServiceWorkerMain() {
Destroy();
}
void ServiceWorkerMain::Destroy() {
version_destroyed_ = true;
InvalidateVersionInfo();
MaybeDisconnectRemote();
GetVersionIdMap().erase(key_);
Unpin();
}
void ServiceWorkerMain::MaybeDisconnectRemote() {
if (remote_.is_bound() &&
(version_destroyed_ ||
(!service_worker_context_->IsLiveStartingServiceWorker(version_id_) &&
!service_worker_context_->IsLiveRunningServiceWorker(version_id_)))) {
remote_.reset();
}
}
mojom::ElectronRenderer* ServiceWorkerMain::GetRendererApi() {
if (!remote_.is_bound()) {
if (!service_worker_context_->IsLiveRunningServiceWorker(version_id_)) {
return nullptr;
}
service_worker_context_->GetRemoteAssociatedInterfaces(version_id_)
.GetInterface(&remote_);
}
return remote_.get();
}
void ServiceWorkerMain::Send(v8::Isolate* isolate,
bool internal,
const std::string& channel,
v8::Local<v8::Value> args) {
blink::CloneableMessage message;
if (!gin::ConvertFromV8(isolate, args, &message)) {
isolate->ThrowException(v8::Exception::Error(
gin::StringToV8(isolate, "Failed to serialize arguments")));
return;
}
auto* renderer_api_remote = GetRendererApi();
if (!renderer_api_remote) {
return;
}
renderer_api_remote->Message(internal, channel, std::move(message));
}
void ServiceWorkerMain::InvalidateVersionInfo() {
if (version_info_ != nullptr) {
version_info_.reset();
}
if (version_destroyed_)
return;
auto version_info = GetLiveVersionInfo(service_worker_context_, version_id_);
if (version_info) {
version_info_ =
std::make_unique<content::ServiceWorkerVersionBaseInfo>(*version_info);
} else {
// When ServiceWorkerContextCore::RemoveLiveVersion is called, it posts a
// task to notify that the service worker has stopped. At this point, the
// live version will no longer exist.
Destroy();
}
}
void ServiceWorkerMain::OnRunningStatusChanged(
blink::EmbeddedWorkerStatus running_status) {
// Disconnect remote when content::ServiceWorkerHost has terminated.
MaybeDisconnectRemote();
InvalidateVersionInfo();
// Redundant worker has been marked for deletion. Now that it's stopped, let's
// destroy our wrapper.
if (redundant_ && running_status == blink::EmbeddedWorkerStatus::kStopped) {
Destroy();
}
}
void ServiceWorkerMain::OnVersionRedundant() {
// Redundant service workers have been either unregistered or replaced. A new
// ServiceWorkerMain will need to be created.
// Set internal state to mark it for deletion once it has fully stopped.
redundant_ = true;
}
bool ServiceWorkerMain::IsDestroyed() const {
return version_destroyed_;
}
const blink::StorageKey ServiceWorkerMain::GetStorageKey() {
GURL scope = version_info_ ? version_info()->scope : GURL::EmptyGURL();
return blink::StorageKey::CreateFirstParty(url::Origin::Create(scope));
}
gin_helper::Dictionary ServiceWorkerMain::StartExternalRequest(
v8::Isolate* isolate,
bool has_timeout) {
auto details = gin_helper::Dictionary::CreateEmpty(isolate);
if (version_destroyed_) {
isolate->ThrowException(v8::Exception::TypeError(
gin::StringToV8(isolate, "ServiceWorkerMain is destroyed")));
return details;
}
auto request_uuid = base::Uuid::GenerateRandomV4();
auto timeout_type =
has_timeout
? content::ServiceWorkerExternalRequestTimeoutType::kDefault
: content::ServiceWorkerExternalRequestTimeoutType::kDoesNotTimeout;
content::ServiceWorkerExternalRequestResult start_result =
service_worker_context_->StartingExternalRequest(
version_id_, timeout_type, request_uuid);
details.Set("id", request_uuid.AsLowercaseString());
details.Set("ok",
start_result == content::ServiceWorkerExternalRequestResult::kOk);
return details;
}
void ServiceWorkerMain::FinishExternalRequest(v8::Isolate* isolate,
std::string uuid) {
base::Uuid request_uuid = base::Uuid::ParseLowercase(uuid);
if (!request_uuid.is_valid()) {
isolate->ThrowException(v8::Exception::TypeError(
gin::StringToV8(isolate, "Invalid external request UUID")));
return;
}
DCHECK(service_worker_context_);
if (!service_worker_context_)
return;
content::ServiceWorkerExternalRequestResult result =
service_worker_context_->FinishedExternalRequest(version_id_,
request_uuid);
std::string error;
switch (result) {
case content::ServiceWorkerExternalRequestResult::kOk:
break;
case content::ServiceWorkerExternalRequestResult::kBadRequestId:
error = "Unknown external request UUID";
break;
case content::ServiceWorkerExternalRequestResult::kWorkerNotRunning:
error = "Service worker is no longer running";
break;
case content::ServiceWorkerExternalRequestResult::kWorkerNotFound:
error = "Service worker was not found";
break;
case content::ServiceWorkerExternalRequestResult::kNullContext:
default:
error = "Service worker context is unavailable and may be shutting down";
break;
}
if (!error.empty()) {
isolate->ThrowException(
v8::Exception::TypeError(gin::StringToV8(isolate, error)));
}
}
size_t ServiceWorkerMain::CountExternalRequestsForTest() {
if (version_destroyed_)
return 0;
auto& storage_key = GetStorageKey();
return service_worker_context_->CountExternalRequestsForTest(storage_key);
}
int64_t ServiceWorkerMain::VersionID() const {
return version_id_;
}
GURL ServiceWorkerMain::ScopeURL() const {
if (version_destroyed_)
return GURL::EmptyGURL();
return version_info()->scope;
}
// static
gin::Handle<ServiceWorkerMain> ServiceWorkerMain::New(v8::Isolate* isolate) {
return gin::Handle<ServiceWorkerMain>();
}
// static
gin::Handle<ServiceWorkerMain> ServiceWorkerMain::From(
v8::Isolate* isolate,
content::ServiceWorkerContext* sw_context,
const content::StoragePartition* storage_partition,
int64_t version_id) {
ServiceWorkerKey service_worker_key(version_id, storage_partition);
auto* service_worker = FromServiceWorkerKey(service_worker_key);
if (service_worker)
return gin::CreateHandle(isolate, service_worker);
// Ensure ServiceWorkerVersion exists and is not redundant (pending deletion)
auto* live_version = GetLiveVersion(sw_context, version_id);
if (!live_version || live_version->is_redundant()) {
return gin::Handle<ServiceWorkerMain>();
}
auto handle = gin::CreateHandle(
isolate,
new ServiceWorkerMain(sw_context, version_id, service_worker_key));
// Prevent garbage collection of worker until it has been deleted internally.
handle->Pin(isolate);
return handle;
}
// static
void ServiceWorkerMain::FillObjectTemplate(
v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> templ) {
gin_helper::ObjectTemplateBuilder(isolate, templ)
.SetMethod("_send", &ServiceWorkerMain::Send)
.SetMethod("isDestroyed", &ServiceWorkerMain::IsDestroyed)
.SetMethod("_startExternalRequest",
&ServiceWorkerMain::StartExternalRequest)
.SetMethod("_finishExternalRequest",
&ServiceWorkerMain::FinishExternalRequest)
.SetMethod("_countExternalRequests",
&ServiceWorkerMain::CountExternalRequestsForTest)
.SetProperty("versionId", &ServiceWorkerMain::VersionID)
.SetProperty("scope", &ServiceWorkerMain::ScopeURL)
.Build();
}
const char* ServiceWorkerMain::GetTypeName() {
return GetClassName();
}
} // namespace electron::api
namespace {
using electron::api::ServiceWorkerMain;
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("ServiceWorkerMain", ServiceWorkerMain::GetConstructor(context));
}
} // namespace
NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_service_worker_main,
Initialize)

View File

@@ -0,0 +1,178 @@
// Copyright (c) 2025 Salesforce, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ELECTRON_SHELL_BROWSER_API_ELECTRON_API_SERVICE_WORKER_MAIN_H_
#define ELECTRON_SHELL_BROWSER_API_ELECTRON_API_SERVICE_WORKER_MAIN_H_
#include <optional>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/service_worker_context.h"
#include "content/public/browser/service_worker_version_base_info.h"
#include "gin/wrappable.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "shell/browser/event_emitter_mixin.h"
#include "shell/common/api/api.mojom.h"
#include "shell/common/gin_helper/constructible.h"
#include "shell/common/gin_helper/pinnable.h"
#include "third_party/blink/public/common/service_worker/embedded_worker_status.h"
class GURL;
namespace content {
class StoragePartition;
}
namespace gin {
class Arguments;
} // namespace gin
namespace gin_helper {
class Dictionary;
template <typename T>
class Handle;
template <typename T>
class Promise;
} // namespace gin_helper
namespace electron::api {
// Key to uniquely identify a ServiceWorkerMain by its Version ID within the
// associated StoragePartition.
struct ServiceWorkerKey {
int64_t version_id;
raw_ptr<const content::StoragePartition> storage_partition;
ServiceWorkerKey(int64_t id, const content::StoragePartition* partition)
: version_id(id), storage_partition(partition) {}
bool operator<(const ServiceWorkerKey& other) const {
return std::tie(version_id, storage_partition) <
std::tie(other.version_id, other.storage_partition);
}
bool operator==(const ServiceWorkerKey& other) const {
return version_id == other.version_id &&
storage_partition == other.storage_partition;
}
struct Hasher {
std::size_t operator()(const ServiceWorkerKey& key) const {
return std::hash<const content::StoragePartition*>()(
key.storage_partition) ^
std::hash<int64_t>()(key.version_id);
}
};
};
// Creates a wrapper to align with the lifecycle of the non-public
// content::ServiceWorkerVersion. Object instances are pinned for the lifetime
// of the underlying SW such that registered IPC handlers continue to dispatch.
//
// Instances are uniquely identified by pairing their version ID and the
// StoragePartition in which they're registered. In Electron, this is always
// the default StoragePartition for the associated BrowserContext.
class ServiceWorkerMain final
: public gin::Wrappable<ServiceWorkerMain>,
public gin_helper::EventEmitterMixin<ServiceWorkerMain>,
public gin_helper::Pinnable<ServiceWorkerMain>,
public gin_helper::Constructible<ServiceWorkerMain> {
public:
// Create a new ServiceWorkerMain and return the V8 wrapper of it.
static gin::Handle<ServiceWorkerMain> New(v8::Isolate* isolate);
static gin::Handle<ServiceWorkerMain> From(
v8::Isolate* isolate,
content::ServiceWorkerContext* sw_context,
const content::StoragePartition* storage_partition,
int64_t version_id);
static ServiceWorkerMain* FromVersionID(
int64_t version_id,
const content::StoragePartition* storage_partition);
// gin_helper::Constructible
static void FillObjectTemplate(v8::Isolate*, v8::Local<v8::ObjectTemplate>);
static const char* GetClassName() { return "ServiceWorkerMain"; }
// gin::Wrappable
static gin::WrapperInfo kWrapperInfo;
const char* GetTypeName() override;
// disable copy
ServiceWorkerMain(const ServiceWorkerMain&) = delete;
ServiceWorkerMain& operator=(const ServiceWorkerMain&) = delete;
void OnRunningStatusChanged(blink::EmbeddedWorkerStatus running_status);
void OnVersionRedundant();
protected:
explicit ServiceWorkerMain(content::ServiceWorkerContext* sw_context,
int64_t version_id,
const ServiceWorkerKey& key);
~ServiceWorkerMain() override;
private:
void Destroy();
void MaybeDisconnectRemote();
const blink::StorageKey GetStorageKey();
// Increments external requests for the service worker to keep it alive.
gin_helper::Dictionary StartExternalRequest(v8::Isolate* isolate,
bool has_timeout);
void FinishExternalRequest(v8::Isolate* isolate, std::string uuid);
size_t CountExternalRequestsForTest();
// Get or create a Mojo connection to the renderer process.
mojom::ElectronRenderer* GetRendererApi();
// Send a message to the renderer process.
void Send(v8::Isolate* isolate,
bool internal,
const std::string& channel,
v8::Local<v8::Value> args);
void InvalidateVersionInfo();
const content::ServiceWorkerVersionBaseInfo* version_info() const {
return version_info_.get();
}
bool IsDestroyed() const;
int64_t VersionID() const;
GURL ScopeURL() const;
// Version ID unique only to the StoragePartition.
int64_t version_id_;
// Unique identifier pairing the Version ID and StoragePartition.
ServiceWorkerKey key_;
// Whether the Service Worker version has been destroyed.
bool version_destroyed_ = false;
// Whether the Service Worker version's state is redundant.
bool redundant_ = false;
// Store copy of version info so it's accessible when not running.
std::unique_ptr<content::ServiceWorkerVersionBaseInfo> version_info_;
raw_ptr<content::ServiceWorkerContext> service_worker_context_;
mojo::AssociatedRemote<mojom::ElectronRenderer> remote_;
std::unique_ptr<gin_helper::Promise<void>> start_worker_promise_;
base::WeakPtrFactory<ServiceWorkerMain> weak_factory_{this};
};
} // namespace electron::api
#endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_SERVICE_WORKER_MAIN_H_

View File

@@ -1065,16 +1065,72 @@ void Session::CreateInterruptedDownload(const gin_helper::Dictionary& options) {
base::Time::FromSecondsSinceUnixEpoch(start_time)));
}
void Session::SetPreloads(const std::vector<base::FilePath>& preloads) {
std::string Session::RegisterPreloadScript(
gin_helper::ErrorThrower thrower,
const PreloadScript& new_preload_script) {
auto* prefs = SessionPreferences::FromBrowserContext(browser_context());
DCHECK(prefs);
prefs->set_preloads(preloads);
auto& preload_scripts = prefs->preload_scripts();
auto it = std::find_if(preload_scripts.begin(), preload_scripts.end(),
[&new_preload_script](const PreloadScript& script) {
return script.id == new_preload_script.id;
});
if (it != preload_scripts.end()) {
thrower.ThrowError(base::StringPrintf(
"Cannot register preload script with existing ID '%s'",
new_preload_script.id.c_str()));
return "";
}
if (!new_preload_script.file_path.IsAbsolute()) {
// Deprecated preload scripts logged error without throwing.
if (new_preload_script.deprecated) {
LOG(ERROR) << "preload script must have absolute path: "
<< new_preload_script.file_path;
} else {
thrower.ThrowError(
base::StringPrintf("Preload script must have absolute path: %s",
new_preload_script.file_path.value().c_str()));
return "";
}
}
preload_scripts.push_back(new_preload_script);
return new_preload_script.id;
}
std::vector<base::FilePath> Session::GetPreloads() const {
void Session::UnregisterPreloadScript(gin_helper::ErrorThrower thrower,
const std::string& script_id) {
auto* prefs = SessionPreferences::FromBrowserContext(browser_context());
DCHECK(prefs);
return prefs->preloads();
auto& preload_scripts = prefs->preload_scripts();
// Find the preload script by its ID
auto it = std::find_if(preload_scripts.begin(), preload_scripts.end(),
[&script_id](const PreloadScript& script) {
return script.id == script_id;
});
// If the script is found, erase it from the vector
if (it != preload_scripts.end()) {
preload_scripts.erase(it);
return;
}
// If the script is not found, throw an error
thrower.ThrowError(base::StringPrintf(
"Cannot unregister preload script with non-existing ID '%s'",
script_id.c_str()));
}
std::vector<PreloadScript> Session::GetPreloadScripts() const {
auto* prefs = SessionPreferences::FromBrowserContext(browser_context());
DCHECK(prefs);
return prefs->preload_scripts();
}
/**
@@ -1800,8 +1856,9 @@ void Session::FillObjectTemplate(v8::Isolate* isolate,
.SetMethod("downloadURL", &Session::DownloadURL)
.SetMethod("createInterruptedDownload",
&Session::CreateInterruptedDownload)
.SetMethod("setPreloads", &Session::SetPreloads)
.SetMethod("getPreloads", &Session::GetPreloads)
.SetMethod("registerPreloadScript", &Session::RegisterPreloadScript)
.SetMethod("unregisterPreloadScript", &Session::UnregisterPreloadScript)
.SetMethod("getPreloadScripts", &Session::GetPreloadScripts)
.SetMethod("getSharedDictionaryUsageInfo",
&Session::GetSharedDictionaryUsageInfo)
.SetMethod("getSharedDictionaryInfo", &Session::GetSharedDictionaryInfo)
@@ -1852,6 +1909,10 @@ const char* Session::GetTypeName() {
return GetClassName();
}
void Session::WillBeDestroyed() {
ClearWeak();
}
} // namespace electron::api
namespace {

View File

@@ -57,6 +57,7 @@ class ProxyConfig;
namespace electron {
class ElectronBrowserContext;
struct PreloadScript;
namespace api {
@@ -102,6 +103,9 @@ class Session final : public gin::Wrappable<Session>,
static const char* GetClassName() { return "Session"; }
const char* GetTypeName() override;
// gin_helper::CleanedUpAtExit
void WillBeDestroyed() override;
// Methods.
v8::Local<v8::Promise> ResolveHost(
std::string host,
@@ -138,8 +142,11 @@ class Session final : public gin::Wrappable<Session>,
const std::string& uuid);
void DownloadURL(const GURL& url, gin::Arguments* args);
void CreateInterruptedDownload(const gin_helper::Dictionary& options);
void SetPreloads(const std::vector<base::FilePath>& preloads);
std::vector<base::FilePath> GetPreloads() const;
std::string RegisterPreloadScript(gin_helper::ErrorThrower thrower,
const PreloadScript& new_preload_script);
void UnregisterPreloadScript(gin_helper::ErrorThrower thrower,
const std::string& script_id);
std::vector<PreloadScript> GetPreloadScripts() const;
v8::Local<v8::Promise> GetSharedDictionaryInfo(
const gin_helper::Dictionary& options);
v8::Local<v8::Promise> GetSharedDictionaryUsageInfo();

View File

@@ -431,6 +431,10 @@ const char* Tray::GetTypeName() {
return GetClassName();
}
void Tray::WillBeDestroyed() {
ClearWeak();
}
} // namespace electron::api
namespace {

View File

@@ -58,6 +58,9 @@ class Tray final : public gin::Wrappable<Tray>,
static gin::WrapperInfo kWrapperInfo;
const char* GetTypeName() override;
// gin_helper::CleanedUpAtExit
void WillBeDestroyed() override;
// disable copy
Tray(const Tray&) = delete;
Tray& operator=(const Tray&) = delete;

View File

@@ -3757,16 +3757,15 @@ void WebContents::DoGetZoomLevel(
std::move(callback).Run(GetZoomLevel());
}
std::vector<base::FilePath> WebContents::GetPreloadPaths() const {
auto result = SessionPreferences::GetValidPreloads(GetBrowserContext());
std::optional<PreloadScript> WebContents::GetPreloadScript() const {
if (auto* web_preferences = WebContentsPreferences::From(web_contents())) {
if (auto preload = web_preferences->GetPreloadPath()) {
result.emplace_back(*preload);
auto preload_script = PreloadScript{
"", PreloadScript::ScriptType::kWebFrame, preload.value()};
return preload_script;
}
}
return result;
return std::nullopt;
}
v8::Local<v8::Value> WebContents::GetLastWebPreferences(
@@ -4520,7 +4519,7 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate,
.SetMethod("setZoomFactor", &WebContents::SetZoomFactor)
.SetMethod("getZoomFactor", &WebContents::GetZoomFactor)
.SetMethod("getType", &WebContents::type)
.SetMethod("_getPreloadPaths", &WebContents::GetPreloadPaths)
.SetMethod("_getPreloadScript", &WebContents::GetPreloadScript)
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
@@ -4570,6 +4569,10 @@ const char* WebContents::GetTypeName() {
return GetClassName();
}
void WebContents::WillBeDestroyed() {
ClearWeak();
}
ElectronBrowserContext* WebContents::GetBrowserContext() const {
return static_cast<ElectronBrowserContext*>(
web_contents()->GetBrowserContext());

View File

@@ -40,6 +40,7 @@
#include "shell/browser/event_emitter_mixin.h"
#include "shell/browser/extended_web_contents_observer.h"
#include "shell/browser/osr/osr_paint_event.h"
#include "shell/browser/preload_script.h"
#include "shell/browser/ui/inspectable_web_contents_delegate.h"
#include "shell/browser/ui/inspectable_web_contents_view_delegate.h"
#include "shell/common/gin_helper/cleaned_up_at_exit.h"
@@ -179,6 +180,9 @@ class WebContents final : public ExclusiveAccessContext,
static gin::WrapperInfo kWrapperInfo;
const char* GetTypeName() override;
// gin_helper::CleanedUpAtExit
void WillBeDestroyed() override;
void Destroy();
void Close(std::optional<gin_helper::Dictionary> options);
base::WeakPtr<WebContents> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
@@ -341,8 +345,8 @@ class WebContents final : public ExclusiveAccessContext,
const std::string& features,
const scoped_refptr<network::ResourceRequestBody>& body);
// Returns the preload script path of current WebContents.
std::vector<base::FilePath> GetPreloadPaths() const;
// Returns the preload script of current WebContents.
std::optional<PreloadScript> GetPreloadScript() const;
// Returns the web preferences of current WebContents.
v8::Local<v8::Value> GetLastWebPreferences(v8::Isolate* isolate) const;

View File

@@ -306,6 +306,10 @@ const char* MessagePort::GetTypeName() {
return "MessagePort";
}
void MessagePort::WillBeDestroyed() {
ClearWeak();
}
} // namespace electron
namespace {

View File

@@ -61,6 +61,9 @@ class MessagePort final : public gin::Wrappable<MessagePort>,
v8::Isolate* isolate) override;
const char* GetTypeName() override;
// gin_helper::CleanedUpAtExit
void WillBeDestroyed() override;
private:
MessagePort();

View File

@@ -458,10 +458,6 @@ void ElectronBrowserContext::InitPrefs() {
}
}
#endif
// Unique uuid for global shortcuts.
registry->RegisterStringPref(electron::kElectronGlobalShortcutsUuid,
std::string());
}
void ElectronBrowserContext::SetUserAgent(const std::string& user_agent) {

View File

@@ -132,11 +132,16 @@ v8::Isolate* JavascriptEnvironment::GetIsolate() {
void JavascriptEnvironment::CreateMicrotasksRunner() {
DCHECK(!microtasks_runner_);
microtasks_runner_ = std::make_unique<MicrotasksRunner>(isolate());
isolate_holder_.WillCreateMicrotasksRunner();
base::CurrentThread::Get()->AddTaskObserver(microtasks_runner_.get());
}
void JavascriptEnvironment::DestroyMicrotasksRunner() {
DCHECK(microtasks_runner_);
// Should be called before running gin_helper::CleanedUpAtExit::DoCleanup.
// This helps to signal wrappable finalizer callbacks to not act on freed
// parameters.
isolate_holder_.WillDestroyMicrotasksRunner();
{
v8::HandleScope scope(isolate_);
gin_helper::CleanedUpAtExit::DoCleanup();

View File

@@ -0,0 +1,104 @@
// Copyright (c) 2025 Salesforce, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ELECTRON_SHELL_BROWSER_PRELOAD_SCRIPT_H_
#define ELECTRON_SHELL_BROWSER_PRELOAD_SCRIPT_H_
#include <string_view>
#include "base/containers/fixed_flat_map.h"
#include "base/files/file_path.h"
#include "base/uuid.h"
#include "gin/converter.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "shell/common/gin_helper/dictionary.h"
namespace electron {
struct PreloadScript {
enum class ScriptType { kWebFrame, kServiceWorker };
std::string id;
ScriptType script_type;
base::FilePath file_path;
// If set, use the deprecated validation behavior of Session.setPreloads
bool deprecated = false;
};
} // namespace electron
namespace gin {
using electron::PreloadScript;
template <>
struct Converter<PreloadScript::ScriptType> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const PreloadScript::ScriptType& in) {
using Val = PreloadScript::ScriptType;
static constexpr auto Lookup =
base::MakeFixedFlatMap<Val, std::string_view>({
{Val::kWebFrame, "frame"},
{Val::kServiceWorker, "service-worker"},
});
return StringToV8(isolate, Lookup.at(in));
}
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
PreloadScript::ScriptType* out) {
using Val = PreloadScript::ScriptType;
static constexpr auto Lookup =
base::MakeFixedFlatMap<std::string_view, Val>({
{"frame", Val::kWebFrame},
{"service-worker", Val::kServiceWorker},
});
return FromV8WithLookup(isolate, val, Lookup, out);
}
};
template <>
struct Converter<PreloadScript> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
const PreloadScript& script) {
gin::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("filePath", script.file_path.AsUTF8Unsafe());
dict.Set("id", script.id);
dict.Set("type", script.script_type);
return ConvertToV8(isolate, dict).As<v8::Object>();
}
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
PreloadScript* out) {
gin_helper::Dictionary options;
if (!ConvertFromV8(isolate, val, &options))
return false;
if (PreloadScript::ScriptType script_type;
options.Get("type", &script_type)) {
out->script_type = script_type;
} else {
return false;
}
if (base::FilePath file_path; options.Get("filePath", &file_path)) {
out->file_path = file_path;
} else {
return false;
}
if (std::string id; options.Get("id", &id)) {
out->id = id;
} else {
out->id = base::Uuid::GenerateRandomV4().AsLowercaseString();
}
if (bool deprecated; options.Get("_deprecated", &deprecated)) {
out->deprecated = deprecated;
}
return true;
}
};
} // namespace gin
#endif // ELECTRON_SHELL_BROWSER_PRELOAD_SCRIPT_H_

View File

@@ -64,5 +64,7 @@
<string>${DEFAULT_APP_ASAR_HEADER_SHA}</string>
</dict>
</dict>
<key>NSPrefersDisplaySafeAreaCompatibilityMode</key>
<false/>
</dict>
</plist>

View File

@@ -30,22 +30,4 @@ SessionPreferences* SessionPreferences::FromBrowserContext(
return static_cast<SessionPreferences*>(context->GetUserData(&kLocatorKey));
}
// static
std::vector<base::FilePath> SessionPreferences::GetValidPreloads(
content::BrowserContext* context) {
std::vector<base::FilePath> result;
if (auto* self = FromBrowserContext(context)) {
for (const auto& preload : self->preloads()) {
if (preload.IsAbsolute()) {
result.emplace_back(preload);
} else {
LOG(ERROR) << "preload script must have absolute path: " << preload;
}
}
}
return result;
}
} // namespace electron

View File

@@ -9,6 +9,7 @@
#include "base/files/file_path.h"
#include "base/supports_user_data.h"
#include "shell/browser/preload_script.h"
namespace content {
class BrowserContext;
@@ -20,17 +21,12 @@ class SessionPreferences : public base::SupportsUserData::Data {
public:
static SessionPreferences* FromBrowserContext(
content::BrowserContext* context);
static std::vector<base::FilePath> GetValidPreloads(
content::BrowserContext* context);
static void CreateForBrowserContext(content::BrowserContext* context);
~SessionPreferences() override;
void set_preloads(const std::vector<base::FilePath>& preloads) {
preloads_ = preloads;
}
const std::vector<base::FilePath>& preloads() const { return preloads_; }
std::vector<PreloadScript>& preload_scripts() { return preload_scripts_; }
private:
SessionPreferences();
@@ -38,7 +34,7 @@ class SessionPreferences : public base::SupportsUserData::Data {
// The user data key.
static int kLocatorKey;
std::vector<base::FilePath> preloads_;
std::vector<PreloadScript> preload_scripts_;
};
} // namespace electron

Some files were not shown because too many files have changed in this diff Show More