Merge pull request #57658 from NousResearch/bb/readtitle-race
fix(desktop): guard link-title readTitle against destroyed windows
This commit is contained in:
commit
44cb0ea9e6
3 changed files with 75 additions and 6 deletions
|
|
@ -49,4 +49,23 @@ function guardLinkTitleSession(partitionSession) {
|
|||
}
|
||||
}
|
||||
|
||||
module.exports = { createLinkTitleWindow, guardLinkTitleSession, linkTitleWindowOptions }
|
||||
// Read the page title from a title-fetch window. Callers schedule this from
|
||||
// timers that can fire after finish() destroys the window, so every access must
|
||||
// guard isDestroyed and swallow Electron's "Object has been destroyed" throws.
|
||||
function readLinkTitleWindowTitle(window) {
|
||||
try {
|
||||
if (!window || window.isDestroyed()) return ''
|
||||
const contents = window.webContents
|
||||
if (!contents || contents.isDestroyed()) return ''
|
||||
return contents.getTitle() || ''
|
||||
} catch {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createLinkTitleWindow,
|
||||
guardLinkTitleSession,
|
||||
linkTitleWindowOptions,
|
||||
readLinkTitleWindowTitle
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
const assert = require('node:assert/strict')
|
||||
const test = require('node:test')
|
||||
|
||||
const { createLinkTitleWindow, guardLinkTitleSession, linkTitleWindowOptions } = require('./link-title-window.cjs')
|
||||
const {
|
||||
createLinkTitleWindow,
|
||||
guardLinkTitleSession,
|
||||
linkTitleWindowOptions,
|
||||
readLinkTitleWindowTitle
|
||||
} = require('./link-title-window.cjs')
|
||||
|
||||
function makeFakeBrowserWindow() {
|
||||
const calls = { audioMuted: [] }
|
||||
|
|
@ -66,3 +71,44 @@ test('guardLinkTitleSession cancels downloads triggered by the title-fetch windo
|
|||
test('guardLinkTitleSession is a no-op when session.on throws', () => {
|
||||
assert.doesNotThrow(() => guardLinkTitleSession({ on() { throw new Error() } }))
|
||||
})
|
||||
|
||||
test('readLinkTitleWindowTitle returns empty for missing or destroyed windows', () => {
|
||||
assert.equal(readLinkTitleWindowTitle(null), '')
|
||||
assert.equal(readLinkTitleWindowTitle(undefined), '')
|
||||
assert.equal(readLinkTitleWindowTitle({ isDestroyed: () => true }), '')
|
||||
})
|
||||
|
||||
test('readLinkTitleWindowTitle returns empty when webContents is destroyed', () => {
|
||||
const window = {
|
||||
isDestroyed: () => false,
|
||||
webContents: { isDestroyed: () => true, getTitle: () => 'Should Not Read' }
|
||||
}
|
||||
|
||||
assert.equal(readLinkTitleWindowTitle(window), '')
|
||||
})
|
||||
|
||||
test('readLinkTitleWindowTitle swallows getTitle throws after teardown', () => {
|
||||
const window = {
|
||||
isDestroyed: () => false,
|
||||
webContents: {
|
||||
isDestroyed: () => false,
|
||||
getTitle: () => {
|
||||
throw new Error('Object has been destroyed')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.equal(readLinkTitleWindowTitle(window), '')
|
||||
})
|
||||
|
||||
test('readLinkTitleWindowTitle returns trimmed page title', () => {
|
||||
const window = {
|
||||
isDestroyed: () => false,
|
||||
webContents: {
|
||||
isDestroyed: () => false,
|
||||
getTitle: () => 'Example Domain'
|
||||
}
|
||||
}
|
||||
|
||||
assert.equal(readLinkTitleWindowTitle(window), 'Example Domain')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -36,7 +36,11 @@ const {
|
|||
SESSION_WINDOW_MIN_WIDTH
|
||||
} = require('./session-windows.cjs')
|
||||
const { canImportHermesCli, verifyHermesCli } = require('./backend-probes.cjs')
|
||||
const { createLinkTitleWindow, guardLinkTitleSession } = require('./link-title-window.cjs')
|
||||
const {
|
||||
createLinkTitleWindow,
|
||||
guardLinkTitleSession,
|
||||
readLinkTitleWindowTitle
|
||||
} = require('./link-title-window.cjs')
|
||||
const { probeGatewayWebSocket } = require('./gateway-ws-probe.cjs')
|
||||
const { adoptServedDashboardToken } = require('./dashboard-token.cjs')
|
||||
const { waitForDashboardPortAnnouncement } = require('./backend-ready.cjs')
|
||||
|
|
@ -3557,13 +3561,13 @@ function runRenderTitleJob(rawUrl) {
|
|||
return finish('')
|
||||
}
|
||||
|
||||
const readTitle = () => window?.webContents?.getTitle?.() || ''
|
||||
const finishWithTitle = () => finish(readLinkTitleWindowTitle(window))
|
||||
const scheduleGrace = () => {
|
||||
if (graceTimer) clearTimeout(graceTimer)
|
||||
graceTimer = setTimeout(() => finish(readTitle()), RENDER_TITLE_GRACE_MS)
|
||||
graceTimer = setTimeout(finishWithTitle, RENDER_TITLE_GRACE_MS)
|
||||
}
|
||||
|
||||
hardTimer = setTimeout(() => finish(readTitle()), RENDER_TITLE_TIMEOUT_MS)
|
||||
hardTimer = setTimeout(finishWithTitle, RENDER_TITLE_TIMEOUT_MS)
|
||||
|
||||
window.webContents.setUserAgent(TITLE_USER_AGENT)
|
||||
window.webContents.on('page-title-updated', scheduleGrace)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue