From 325a719b897406f3de600bed634ec79c8c4f6503 Mon Sep 17 00:00:00 2001 From: Jason Zhang Date: Tue, 8 Oct 2024 00:02:30 +1030 Subject: [PATCH] web: mark as uncloneable when possible This tells node that the marked instances from undici are not cloneable, so that attempts to cloning those throw `DataCloneError`. --- lib/core/util.js | 8 ++++++++ lib/web/eventsource/eventsource.js | 4 +++- lib/web/fetch/formdata.js | 4 +++- lib/web/fetch/headers.js | 4 +++- lib/web/fetch/request.js | 4 +++- lib/web/fetch/response.js | 4 +++- lib/web/websocket/events.js | 5 ++++- lib/web/websocket/websocket.js | 4 +++- 8 files changed, 30 insertions(+), 7 deletions(-) diff --git a/lib/core/util.js b/lib/core/util.js index 05dd11867d7..6097026dc55 100644 --- a/lib/core/util.js +++ b/lib/core/util.js @@ -6,6 +6,7 @@ const { IncomingMessage } = require('node:http') const stream = require('node:stream') const net = require('node:net') const { Blob } = require('node:buffer') +const { markAsUncloneable } = require('node:worker_threads') const nodeUtil = require('node:util') const { stringify } = require('node:querystring') const { EventEmitter: EE } = require('node:events') @@ -816,6 +817,12 @@ function errorRequest (client, request, err) { } } +function maybeMarkAsUncloneable (target) { + if (markAsUncloneable !== undefined) { + markAsUncloneable(target) + } +} + const kEnumerableProperty = Object.create(null) kEnumerableProperty.enumerable = true @@ -875,6 +882,7 @@ module.exports = { isFormDataLike, serializePathWithQuery, addAbortListener, + maybeMarkAsUncloneable, isValidHTTPToken, isValidHeaderValue, isTokenCharCode, diff --git a/lib/web/eventsource/eventsource.js b/lib/web/eventsource/eventsource.js index 257b9573ef9..1994eb43fc5 100644 --- a/lib/web/eventsource/eventsource.js +++ b/lib/web/eventsource/eventsource.js @@ -9,7 +9,7 @@ const { parseMIMEType } = require('../fetch/data-url') const { createFastMessageEvent } = require('../websocket/events') const { isNetworkError } = require('../fetch/response') const { delay } = require('./util') -const { kEnumerableProperty } = require('../../core/util') +const { kEnumerableProperty, maybeMarkAsUncloneable } = require('../../core/util') const { environmentSettingsObject } = require('../fetch/util') let experimentalWarned = false @@ -109,6 +109,8 @@ class EventSource extends EventTarget { // 1. Let ev be a new EventSource object. super() + maybeMarkAsUncloneable(this) + const prefix = 'EventSource constructor' webidl.argumentLengthCheck(arguments, 1, prefix) diff --git a/lib/web/fetch/formdata.js b/lib/web/fetch/formdata.js index 4909e6dbc98..518ba4635f6 100644 --- a/lib/web/fetch/formdata.js +++ b/lib/web/fetch/formdata.js @@ -1,7 +1,7 @@ 'use strict' const { iteratorMixin } = require('./util') -const { kEnumerableProperty } = require('../../core/util') +const { kEnumerableProperty, maybeMarkAsUncloneable } = require('../../core/util') const { webidl } = require('./webidl') const { File: NativeFile } = require('node:buffer') const nodeUtil = require('node:util') @@ -14,6 +14,8 @@ class FormData { #state = [] constructor (form) { + maybeMarkAsUncloneable(this) + if (form !== undefined) { throw webidl.errors.conversionFailed({ prefix: 'FormData constructor', diff --git a/lib/web/fetch/headers.js b/lib/web/fetch/headers.js index 39648ad1d02..9cd2abb9a2c 100644 --- a/lib/web/fetch/headers.js +++ b/lib/web/fetch/headers.js @@ -3,7 +3,7 @@ 'use strict' const { kConstruct } = require('../../core/symbols') -const { kEnumerableProperty } = require('../../core/util') +const { kEnumerableProperty, maybeMarkAsUncloneable } = require('../../core/util') const { iteratorMixin, isValidHeaderName, @@ -189,6 +189,8 @@ class HeadersList { headersMap constructor (init) { + maybeMarkAsUncloneable(this) + if (init instanceof HeadersList) { this.headersMap = new Map(init.headersMap) this.sortedMap = init.sortedMap diff --git a/lib/web/fetch/request.js b/lib/web/fetch/request.js index b6a0d6dfdfb..8a035680e5c 100644 --- a/lib/web/fetch/request.js +++ b/lib/web/fetch/request.js @@ -22,7 +22,7 @@ const { requestCache, requestDuplex } = require('./constants') -const { kEnumerableProperty, normalizedMethodRecordsBase, normalizedMethodRecords } = util +const { kEnumerableProperty, maybeMarkAsUncloneable, normalizedMethodRecordsBase, normalizedMethodRecords } = util const { webidl } = require('./webidl') const { URLSerializer } = require('./data-url') const { kConstruct } = require('../../core/symbols') @@ -92,6 +92,8 @@ class Request { // https://fetch.spec.whatwg.org/#dom-request constructor (input, init = undefined) { + maybeMarkAsUncloneable(this) + if (input === kConstruct) { return } diff --git a/lib/web/fetch/response.js b/lib/web/fetch/response.js index 904752f6c98..b037b8f8e75 100644 --- a/lib/web/fetch/response.js +++ b/lib/web/fetch/response.js @@ -4,7 +4,7 @@ const { Headers, HeadersList, fill, getHeadersGuard, setHeadersGuard, setHeaders const { extractBody, cloneBody, mixinBody, hasFinalizationRegistry, streamRegistry, bodyUnusable } = require('./body') const util = require('../../core/util') const nodeUtil = require('node:util') -const { kEnumerableProperty } = util +const { kEnumerableProperty, maybeMarkAsUncloneable } = util const { isValidReasonPhrase, isCancelled, @@ -113,6 +113,8 @@ class Response { // https://fetch.spec.whatwg.org/#dom-response constructor (body = null, init = undefined) { + maybeMarkAsUncloneable(this) + if (body === kConstruct) { return } diff --git a/lib/web/websocket/events.js b/lib/web/websocket/events.js index 760b7297359..3cda1343617 100644 --- a/lib/web/websocket/events.js +++ b/lib/web/websocket/events.js @@ -1,7 +1,7 @@ 'use strict' const { webidl } = require('../fetch/webidl') -const { kEnumerableProperty } = require('../../core/util') +const { kEnumerableProperty, maybeMarkAsUncloneable } = require('../../core/util') const { kConstruct } = require('../../core/symbols') const { MessagePort } = require('node:worker_threads') @@ -14,6 +14,7 @@ class MessageEvent extends Event { constructor (type, eventInitDict = {}) { if (type === kConstruct) { super(arguments[1], arguments[2]) + maybeMarkAsUncloneable(this) return } @@ -26,6 +27,7 @@ class MessageEvent extends Event { super(type, eventInitDict) this.#eventInit = eventInitDict + maybeMarkAsUncloneable(this) } get data () { @@ -112,6 +114,7 @@ class CloseEvent extends Event { super(type, eventInitDict) this.#eventInit = eventInitDict + maybeMarkAsUncloneable(this) } get wasClean () { diff --git a/lib/web/websocket/websocket.js b/lib/web/websocket/websocket.js index a0cd86c92c5..03c1634af37 100644 --- a/lib/web/websocket/websocket.js +++ b/lib/web/websocket/websocket.js @@ -17,7 +17,7 @@ const { } = require('./util') const { establishWebSocketConnection, closeWebSocketConnection } = require('./connection') const { ByteParser } = require('./receiver') -const { kEnumerableProperty } = require('../../core/util') +const { kEnumerableProperty, maybeMarkAsUncloneable } = require('../../core/util') const { getGlobalDispatcher } = require('../../global') const { types } = require('node:util') const { ErrorEvent, CloseEvent, createFastMessageEvent } = require('./events') @@ -100,6 +100,8 @@ class WebSocket extends EventTarget { constructor (url, protocols = []) { super() + maybeMarkAsUncloneable(this) + const prefix = 'WebSocket constructor' webidl.argumentLengthCheck(arguments, 1, prefix)