diff --git a/docs/docs/api/MockAgent.md b/docs/docs/api/MockAgent.md index 614a339684e..e61c2080370 100644 --- a/docs/docs/api/MockAgent.md +++ b/docs/docs/api/MockAgent.md @@ -477,7 +477,7 @@ This method returns any pending interceptors registered on a mock agent. A pendi Returns: `PendingInterceptor[]` (where `PendingInterceptor` is a `MockDispatch` with an additional `origin: string`) -#### Example - List all pending inteceptors +#### Example - List all pending interceptors ```js const agent = new MockAgent() diff --git a/lib/cache/sqlite-cache-store.js b/lib/cache/sqlite-cache-store.js index e027cff84ea..e2fbc6718ab 100644 --- a/lib/cache/sqlite-cache-store.js +++ b/lib/cache/sqlite-cache-store.js @@ -115,6 +115,11 @@ module.exports = class SqliteCacheStore { this.#db = new DatabaseSync(opts?.location ?? ':memory:') this.#db.exec(` + PRAGMA journal_mode = WAL; + PRAGMA synchronous = NORMAL; + PRAGMA temp_store = memory; + PRAGMA optimize; + CREATE TABLE IF NOT EXISTS cacheInterceptorV${VERSION} ( -- Data specific to us id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -134,9 +139,8 @@ module.exports = class SqliteCacheStore { staleAt INTEGER NOT NULL ); - CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION}_url ON cacheInterceptorV${VERSION}(url); - CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION}_method ON cacheInterceptorV${VERSION}(method); - CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION}_deleteAt ON cacheInterceptorV${VERSION}(deleteAt); + CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION}_getValuesQuery ON cacheInterceptorV${VERSION}(url, method, deleteAt); + CREATE INDEX IF NOT EXISTS idx_cacheInterceptorV${VERSION}_deleteByUrlQuery ON cacheInterceptorV${VERSION}(deleteAt); `) this.#getValuesQuery = this.#db.prepare(` @@ -346,7 +350,7 @@ module.exports = class SqliteCacheStore { } #prune () { - if (this.size <= this.#maxCount) { + if (Number.isFinite(this.#maxCount) && this.size <= this.#maxCount) { return 0 } diff --git a/package.json b/package.json index e1bfb109b0b..2029f132001 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "undici", - "version": "7.7.0", + "version": "7.8.0", "description": "An HTTP/1.1 client, written from scratch for Node.js", "homepage": "https://undici.nodejs.org", "bugs": { @@ -116,7 +116,7 @@ "c8": "^10.0.0", "cross-env": "^7.0.3", "dns-packet": "^5.4.0", - "esbuild": "^0.24.0", + "esbuild": "^0.25.2", "eslint": "^9.9.0", "fast-check": "^3.17.1", "https-pem": "^3.0.0", diff --git a/test/fixtures/wpt/fetch/api/basic/WEB_FEATURES.yml b/test/fixtures/wpt/fetch/api/basic/WEB_FEATURES.yml new file mode 100644 index 00000000000..d6cd4adaeff --- /dev/null +++ b/test/fixtures/wpt/fetch/api/basic/WEB_FEATURES.yml @@ -0,0 +1,4 @@ +features: +- name: fetch-request-streams + files: + - request-upload* diff --git a/test/fixtures/wpt/fetch/http-cache/heuristic.any.js b/test/fixtures/wpt/fetch/http-cache/heuristic.any.js index d8461318882..2bec1aa4c64 100644 --- a/test/fixtures/wpt/fetch/http-cache/heuristic.any.js +++ b/test/fixtures/wpt/fetch/http-cache/heuristic.any.js @@ -32,10 +32,33 @@ var tests = [ ], }, { - expected_type: "not_cached" + expected_type: "not_cached", } ] - } + }, + { + name: "HTTP cache does not reuse a redirected response with no max-age and no Last-Modified header", + requests: [ + { + response_status: [301, "Moved Permanently"], + response_headers: [ + ["Cache-Control", "private"], + ["Location", "redirect_target"] + ], + }, + { skip: true}, // Response to first redirect + { + response_status: [301, "Moved Permanently"], + response_headers: [ + ["Cache-Control", "private"], + ["Location", "redirect_target"] + ], + expected_type: "not_cached", + }, + { skip: true}, // response to second redirect + ], + check_count: true, + }, ]; function check_status(status) { diff --git a/test/fixtures/wpt/fetch/http-cache/http-cache.js b/test/fixtures/wpt/fetch/http-cache/http-cache.js index 19f1ca9b2bc..0ca5fcc2bc0 100644 --- a/test/fixtures/wpt/fetch/http-cache/http-cache.js +++ b/test/fixtures/wpt/fetch/http-cache/http-cache.js @@ -43,17 +43,25 @@ function makeTest (test) { var uuid = token() var requests = expandTemplates(test) var fetchFunctions = makeFetchFunctions(requests, uuid) - return runTest(fetchFunctions, requests, uuid) + return runTest(fetchFunctions, test, requests, uuid) } } function makeFetchFunctions(requests, uuid) { var fetchFunctions = [] for (let i = 0; i < requests.length; ++i) { + var config = requests[i]; + if (config.skip) { + // Skip request are ones that we expect the browser to make in + // response to a redirect. We don't fetch them again, but + // the server needs them in the config to be able to respond to + // them. + continue; + } fetchFunctions.push({ code: function (idx) { var config = requests[idx] - var url = makeTestUrl(uuid, config) + var url = makeTestUrl(uuid, config); var init = fetchInit(requests, config) return fetch(url, init) .then(makeCheckResponse(idx, config)) @@ -71,7 +79,7 @@ function makeFetchFunctions(requests, uuid) { return fetchFunctions } -function runTest(fetchFunctions, requests, uuid) { +function runTest(fetchFunctions, test, requests, uuid) { var idx = 0 function runNextStep () { if (fetchFunctions.length) { @@ -93,7 +101,7 @@ function runTest(fetchFunctions, requests, uuid) { .then(function () { return getServerState(uuid) }).then(function (testState) { - checkRequests(requests, testState) + checkRequests(test, requests, testState) return Promise.resolve() }) } @@ -153,7 +161,7 @@ function makeCheckResponse (idx, config) { if ('expected_status' in config) { assert_equals(response.status, config.expected_status, `Response ${reqNum} status is ${response.status}, not ${config.expected_status}`) - } else if ('response_status' in config) { + } else if ('response_status' in config && config.response_status[0] != 301) { assert_equals(response.status, config.response_status[0], `Response ${reqNum} status is ${response.status}, not ${config.response_status[0]}`) } else { @@ -197,7 +205,7 @@ function makeCheckResponseBody (config, uuid) { } } -function checkRequests (requests, testState) { +function checkRequests (test, requests, testState) { var testIdx = 0 for (let i = 0; i < requests.length; ++i) { var expectedValidatingHeaders = [] @@ -225,6 +233,9 @@ function checkRequests (requests, testState) { }) } } + if (test?.check_count && testState) { + assert_equals(requests.length, testState.length); + } } function pause () { diff --git a/test/fixtures/wpt/fetch/http-cache/split-cache.html b/test/fixtures/wpt/fetch/http-cache/split-cache.html index fe93d2e3400..c822abba3ac 100644 --- a/test/fixtures/wpt/fetch/http-cache/split-cache.html +++ b/test/fixtures/wpt/fetch/http-cache/split-cache.html @@ -128,7 +128,7 @@ function check_server_info() { return getServerState(uuid) .then(function (testState) { - checkRequests(local_requests, testState) + checkRequests(undefined, local_requests, testState) return Promise.resolve() }) } diff --git a/test/fixtures/wpt/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js b/test/fixtures/wpt/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js deleted file mode 100644 index 33e94d57f1a..00000000000 --- a/test/fixtures/wpt/fetch/private-network-access/fenced-frame-no-preflight-required.tentative.https.window.js +++ /dev/null @@ -1,91 +0,0 @@ -// META: script=/common/dispatcher/dispatcher.js -// META: script=/common/utils.js -// META: script=resources/support.sub.js -// META: script=/fenced-frame/resources/utils.js -// META: timeout=long -// -// Spec: https://wicg.github.io/private-network-access/#integration-fetch -// -// These tests verify that contexts can navigate fenced frames to more-public or -// same address spaces without private network access preflight request header. - -setup(() => { - assert_true(window.isSecureContext); -}); - -// Source: secure local context. -// -// All fetches unaffected by Private Network Access. - -promise_test( - t => fencedFrameTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: {server: Server.HTTPS_LOCAL}, - expected: FrameTestResult.SUCCESS, - }), - 'local to local: no preflight required.'); - -promise_test( - t => fencedFrameTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: {server: Server.HTTPS_PRIVATE}, - expected: FrameTestResult.SUCCESS, - }), - 'local to private: no preflight required.'); - -promise_test( - t => fencedFrameTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: {server: Server.HTTPS_PUBLIC}, - expected: FrameTestResult.SUCCESS, - }), - 'local to public: no preflight required.'); - -promise_test( - t => fencedFrameTest(t, { - source: {server: Server.HTTPS_PRIVATE}, - target: {server: Server.HTTPS_PRIVATE}, - expected: FrameTestResult.SUCCESS, - }), - 'private to private: no preflight required.'); - -promise_test( - t => fencedFrameTest(t, { - source: {server: Server.HTTPS_PRIVATE}, - target: {server: Server.HTTPS_PUBLIC}, - expected: FrameTestResult.SUCCESS, - }), - 'private to public: no preflight required.'); - -promise_test( - t => fencedFrameTest(t, { - source: {server: Server.HTTPS_PUBLIC}, - target: {server: Server.HTTPS_PUBLIC}, - expected: FrameTestResult.SUCCESS, - }), - 'public to public: no preflight required.'); - -promise_test( - t => fencedFrameTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: {server: Server.HTTPS_PUBLIC}, - expected: FrameTestResult.SUCCESS, - }), - 'treat-as-public-address to public: no preflight required.'); - -promise_test( - t => fencedFrameTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: { - server: Server.HTTPS_PUBLIC, - behavior: {preflight: PreflightBehavior.optionalSuccess(token())} - }, - expected: FrameTestResult.SUCCESS, - }), - 'treat-as-public-address to local: optional preflight'); diff --git a/test/fixtures/wpt/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js b/test/fixtures/wpt/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js deleted file mode 100644 index 2dff325e3e1..00000000000 --- a/test/fixtures/wpt/fetch/private-network-access/fenced-frame-subresource-fetch.tentative.https.window.js +++ /dev/null @@ -1,330 +0,0 @@ -// META: script=/common/subset-tests-by-key.js -// META: script=/common/utils.js -// META: script=resources/support.sub.js -// META: script=/fenced-frame/resources/utils.js -// META: variant=?include=baseline -// META: variant=?include=from-local -// META: variant=?include=from-private -// META: variant=?include=from-public -// META: timeout=long -// -// Spec: https://wicg.github.io/private-network-access/#integration-fetch -// -// These tests verify that secure contexts can fetch subresources in fenced -// frames from all address spaces, provided that the target server, if more -// private than the initiator, respond affirmatively to preflight requests. -// - -setup(() => { - // Making sure we are in a secure context, as expected. - assert_true(window.isSecureContext); -}); - -// Source: secure local context. -// -// All fetches unaffected by Private Network Access. - -subsetTestByKey( - 'from-local', promise_test, t => fencedFrameFetchTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: {server: Server.HTTPS_LOCAL}, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.SUCCESS, - }), - 'local to local: no preflight required.'); - -subsetTestByKey( - 'from-local', promise_test, - t => fencedFrameFetchTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: { - server: Server.HTTPS_PRIVATE, - behavior: {response: ResponseBehavior.allowCrossOrigin()}, - }, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.SUCCESS, - }), - 'local to private: no preflight required.'); - - -subsetTestByKey( - 'from-local', promise_test, - t => fencedFrameFetchTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: { - server: Server.HTTPS_PUBLIC, - behavior: {response: ResponseBehavior.allowCrossOrigin()}, - }, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.SUCCESS, - }), - 'local to public: no preflight required.'); - -// Strictly speaking, the following two tests do not exercise PNA-specific -// logic, but they serve as a baseline for comparison, ensuring that non-PNA -// preflight requests are sent and handled as expected. - -subsetTestByKey( - 'baseline', promise_test, - t => fencedFrameFetchTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: { - server: Server.HTTPS_PUBLIC, - behavior: { - preflight: PreflightBehavior.failure(), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: {method: 'PUT', mode: 'cors'}, - expected: FetchTestResult.FAILURE, - }), - 'local to public: PUT preflight failure.'); - -subsetTestByKey( - 'baseline', promise_test, - t => fencedFrameFetchTest(t, { - source: {server: Server.HTTPS_LOCAL}, - target: { - server: Server.HTTPS_PUBLIC, - behavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - } - }, - fetchOptions: {method: 'PUT', mode: 'cors'}, - expected: FetchTestResult.SUCCESS, - }), - 'local to public: PUT preflight success.'); - -// Generates tests of preflight behavior for a single (source, target) pair. -// -// Scenarios: -// -// - cors mode: -// - preflight response has non-2xx HTTP code -// - preflight response is missing CORS headers -// - preflight response is missing the PNA-specific `Access-Control` header -// - final response is missing CORS headers -// - success -// - success with PUT method (non-"simple" request) -// - no-cors mode: -// - preflight response has non-2xx HTTP code -// - preflight response is missing CORS headers -// - preflight response is missing the PNA-specific `Access-Control` header -// - success -// -function makePreflightTests({ - subsetKey, - source, - sourceDescription, - targetServer, - targetDescription, -}) { - const prefix = `${sourceDescription} to ${targetDescription}: `; - - subsetTestByKey( - subsetKey, promise_test, - t => fencedFrameFetchTest(t, { - source, - target: { - server: targetServer, - behavior: { - preflight: PreflightBehavior.failure(), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.FAILURE, - }), - prefix + 'failed preflight.'); - - subsetTestByKey( - subsetKey, promise_test, - t => fencedFrameFetchTest(t, { - source, - target: { - server: targetServer, - behavior: { - preflight: PreflightBehavior.noCorsHeader(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.FAILURE, - }), - prefix + 'missing CORS headers on preflight response.'); - - subsetTestByKey( - subsetKey, promise_test, - t => fencedFrameFetchTest(t, { - source, - target: { - server: targetServer, - behavior: { - preflight: PreflightBehavior.noPnaHeader(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.FAILURE, - }), - prefix + 'missing PNA header on preflight response.'); - - subsetTestByKey( - subsetKey, promise_test, - t => fencedFrameFetchTest(t, { - source, - target: { - server: targetServer, - behavior: {preflight: PreflightBehavior.success(token())}, - }, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.FAILURE, - }), - prefix + 'missing CORS headers on final response.'); - - subsetTestByKey( - subsetKey, promise_test, - t => fencedFrameFetchTest(t, { - source, - target: { - server: targetServer, - behavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.SUCCESS, - }), - prefix + 'success.'); - - subsetTestByKey( - subsetKey, promise_test, - t => fencedFrameFetchTest(t, { - source, - target: { - server: targetServer, - behavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin(), - }, - }, - fetchOptions: {method: 'PUT', mode: 'cors'}, - expected: FetchTestResult.SUCCESS, - }), - prefix + 'PUT success.'); - - subsetTestByKey( - subsetKey, promise_test, t => fencedFrameFetchTest(t, { - source, - target: {server: targetServer}, - fetchOptions: {method: 'GET', mode: 'no-cors'}, - expected: FetchTestResult.FAILURE, - }), - prefix + 'no-CORS mode failed preflight.'); - - subsetTestByKey( - subsetKey, promise_test, - t => fencedFrameFetchTest(t, { - source, - target: { - server: targetServer, - behavior: {preflight: PreflightBehavior.noCorsHeader(token())}, - }, - fetchOptions: {method: 'GET', mode: 'no-cors'}, - expected: FetchTestResult.FAILURE, - }), - prefix + 'no-CORS mode missing CORS headers on preflight response.'); - - subsetTestByKey( - subsetKey, promise_test, - t => fencedFrameFetchTest(t, { - source, - target: { - server: targetServer, - behavior: {preflight: PreflightBehavior.noPnaHeader(token())}, - }, - fetchOptions: {method: 'GET', mode: 'no-cors'}, - expected: FetchTestResult.FAILURE, - }), - prefix + 'no-CORS mode missing PNA header on preflight response.'); - - subsetTestByKey( - subsetKey, promise_test, - t => fencedFrameFetchTest(t, { - source, - target: { - server: targetServer, - behavior: {preflight: PreflightBehavior.success(token())}, - }, - fetchOptions: {method: 'GET', mode: 'no-cors'}, - expected: FetchTestResult.OPAQUE, - }), - prefix + 'no-CORS mode success.'); -} - -// Source: private secure context. -// -// Fetches to the local address space require a successful preflight response -// carrying a PNA-specific header. - -makePreflightTests({ - subsetKey: 'from-private', - source: {server: Server.HTTPS_PRIVATE}, - sourceDescription: 'private', - targetServer: Server.HTTPS_LOCAL, - targetDescription: 'local', -}); - -subsetTestByKey( - 'from-private', promise_test, t => fencedFrameFetchTest(t, { - source: {server: Server.HTTPS_PRIVATE}, - target: {server: Server.HTTPS_PRIVATE}, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.SUCCESS, - }), - 'private to private: no preflight required.'); - -subsetTestByKey( - 'from-private', promise_test, - t => fencedFrameFetchTest(t, { - source: {server: Server.HTTPS_PRIVATE}, - target: { - server: Server.HTTPS_PRIVATE, - behavior: {response: ResponseBehavior.allowCrossOrigin()}, - }, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.SUCCESS, - }), - 'private to public: no preflight required.'); - -// Source: public secure context. -// -// Fetches to the local and private address spaces require a successful -// preflight response carrying a PNA-specific header. - -makePreflightTests({ - subsetKey: 'from-public', - source: {server: Server.HTTPS_PUBLIC}, - sourceDescription: 'public', - targetServer: Server.HTTPS_LOCAL, - targetDescription: 'local', -}); - -makePreflightTests({ - subsetKey: 'from-public', - source: {server: Server.HTTPS_PUBLIC}, - sourceDescription: 'public', - targetServer: Server.HTTPS_PRIVATE, - targetDescription: 'private', -}); - -subsetTestByKey( - 'from-public', promise_test, t => fencedFrameFetchTest(t, { - source: {server: Server.HTTPS_PUBLIC}, - target: {server: Server.HTTPS_PUBLIC}, - fetchOptions: {method: 'GET', mode: 'cors'}, - expected: FetchTestResult.SUCCESS, - }), - 'public to public: no preflight required.'); diff --git a/test/fixtures/wpt/fetch/private-network-access/fenced-frame.tentative.https.window.js b/test/fixtures/wpt/fetch/private-network-access/fenced-frame.tentative.https.window.js deleted file mode 100644 index 370cc9fbe9d..00000000000 --- a/test/fixtures/wpt/fetch/private-network-access/fenced-frame.tentative.https.window.js +++ /dev/null @@ -1,150 +0,0 @@ -// META: script=/common/dispatcher/dispatcher.js -// META: script=/common/utils.js -// META: script=resources/support.sub.js -// META: script=/fenced-frame/resources/utils.js -// META: timeout=long -// -// Spec: https://wicg.github.io/private-network-access/#integration-fetch -// -// These tests verify that contexts can navigate fenced frames to less-public -// address spaces iff the target server responds affirmatively to preflight -// requests. - -setup(() => { - assert_true(window.isSecureContext); -}); - -// Generates tests of preflight behavior for a single (source, target) pair. -// -// Scenarios: -// -// - parent navigates child: -// - preflight response has non-2xx HTTP code -// - preflight response is missing CORS headers -// - preflight response is missing the PNA-specific `Access-Control` header -// - preflight response has the required PNA related headers, but still fails -// because of the limitation of fenced frame that subjects to PNA checks. -// -function makePreflightTests({ - sourceName, - sourceServer, - sourceTreatAsPublic, - targetName, - targetServer, -}) { - const prefix = `${sourceName} to ${targetName}: `; - - const source = { - server: sourceServer, - treatAsPublic: sourceTreatAsPublic, - }; - - promise_test_parallel( - t => fencedFrameTest(t, { - source, - target: { - server: targetServer, - behavior: {preflight: PreflightBehavior.failure()}, - }, - expected: FrameTestResult.FAILURE, - }), - prefix + 'failed preflight.'); - - promise_test_parallel( - t => fencedFrameTest(t, { - source, - target: { - server: targetServer, - behavior: {preflight: PreflightBehavior.noCorsHeader(token())}, - }, - expected: FrameTestResult.FAILURE, - }), - prefix + 'missing CORS headers.'); - - promise_test_parallel( - t => fencedFrameTest(t, { - source, - target: { - server: targetServer, - behavior: {preflight: PreflightBehavior.noPnaHeader(token())}, - }, - expected: FrameTestResult.FAILURE, - }), - prefix + 'missing PNA header.'); - - promise_test_parallel( - t => fencedFrameTest(t, { - source, - target: { - server: targetServer, - behavior: { - preflight: PreflightBehavior.success(token()), - response: ResponseBehavior.allowCrossOrigin() - }, - }, - expected: FrameTestResult.FAILURE, - }), - prefix + 'failed because fenced frames are incompatible with PNA.'); -} - -// Source: private secure context. -// -// Fetches to the local address space require a successful preflight response -// carrying a PNA-specific header. - -makePreflightTests({ - sourceServer: Server.HTTPS_PRIVATE, - sourceName: 'private', - targetServer: Server.HTTPS_LOCAL, - targetName: 'local', -}); - -// Source: public secure context. -// -// Fetches to the local and private address spaces require a successful -// preflight response carrying a PNA-specific header. - -makePreflightTests({ - sourceServer: Server.HTTPS_PUBLIC, - sourceName: 'public', - targetServer: Server.HTTPS_LOCAL, - targetName: 'local', -}); - -makePreflightTests({ - sourceServer: Server.HTTPS_PUBLIC, - sourceName: 'public', - targetServer: Server.HTTPS_PRIVATE, - targetName: 'private', -}); - -// The following tests verify that `CSP: treat-as-public-address` makes -// documents behave as if they had been served from a public IP address. - -makePreflightTests({ - sourceServer: Server.HTTPS_LOCAL, - sourceTreatAsPublic: true, - sourceName: 'treat-as-public-address', - targetServer: Server.OTHER_HTTPS_LOCAL, - targetName: 'local', -}); - -promise_test_parallel( - t => fencedFrameTest(t, { - source: { - server: Server.HTTPS_LOCAL, - treatAsPublic: true, - }, - target: {server: Server.HTTPS_LOCAL}, - expected: FrameTestResult.FAILURE, - }), - 'treat-as-public-address to local (same-origin): fenced frame embedder ' + - 'initiated navigation has opaque origin.'); - -makePreflightTests({ - sourceServer: Server.HTTPS_LOCAL, - sourceTreatAsPublic: true, - sourceName: 'treat-as-public-address', - targetServer: Server.HTTPS_PRIVATE, - targetName: 'private', -}); diff --git a/test/fixtures/wpt/interfaces/ppa.idl b/test/fixtures/wpt/interfaces/ppa.idl index ef3eb360bdf..3524d503c18 100644 --- a/test/fixtures/wpt/interfaces/ppa.idl +++ b/test/fixtures/wpt/interfaces/ppa.idl @@ -51,6 +51,10 @@ dictionary PrivateAttributionConversionOptions { unsigned long maxValue = 1; }; +enum PrivateAttributionLogic { + "last-touch", +}; + dictionary PrivateAttributionConversionResult { required Uint8Array report; }; @@ -59,7 +63,3 @@ dictionary PrivateAttributionConversionResult { partial interface PrivateAttribution { Promise measureConversion(PrivateAttributionConversionOptions options); }; - -enum PrivateAttributionLogic { - "last-touch", -}; diff --git a/test/fixtures/wpt/interfaces/screen-capture.idl b/test/fixtures/wpt/interfaces/screen-capture.idl index 45fd0dd72c5..db9282ce0a5 100644 --- a/test/fixtures/wpt/interfaces/screen-capture.idl +++ b/test/fixtures/wpt/interfaces/screen-capture.idl @@ -71,6 +71,7 @@ partial dictionary MediaTrackSettings { DOMString cursor; boolean restrictOwnAudio; boolean suppressLocalAudioPlayback; + double screenPixelRatio; }; partial dictionary MediaTrackCapabilities { diff --git a/test/fixtures/wpt/interfaces/speech-api.idl b/test/fixtures/wpt/interfaces/speech-api.idl index bc0635fa3f2..5bc9df337dd 100644 --- a/test/fixtures/wpt/interfaces/speech-api.idl +++ b/test/fixtures/wpt/interfaces/speech-api.idl @@ -19,7 +19,7 @@ interface SpeechRecognition : EventTarget { undefined start(MediaStreamTrack audioTrack); undefined stop(); undefined abort(); - static Promise availableOnDevice(DOMString lang); + static Promise availableOnDevice(DOMString lang); static Promise installOnDevice(DOMString lang); // event methods @@ -52,6 +52,13 @@ enum SpeechRecognitionMode { "cloud-only", // Cloud speech recognition only. }; +enum AvailabilityStatus { + "unavailable", + "downloadable", + "downloading", + "available" +}; + [Exposed=Window] interface SpeechRecognitionErrorEvent : Event { constructor(DOMString type, SpeechRecognitionErrorEventInit eventInitDict); diff --git a/test/fixtures/wpt/interfaces/webrtc-stats.idl b/test/fixtures/wpt/interfaces/webrtc-stats.idl index ac820c7c9dc..1e7a2648bbb 100644 --- a/test/fixtures/wpt/interfaces/webrtc-stats.idl +++ b/test/fixtures/wpt/interfaces/webrtc-stats.idl @@ -38,6 +38,10 @@ dictionary RTCCodecStats : RTCStats { dictionary RTCReceivedRtpStreamStats : RTCRtpStreamStats { unsigned long long packetsReceived; + unsigned long long packetsReceivedWithEct1; + unsigned long long packetsReceivedWithCe; + unsigned long long packetsReportedAsLost; + unsigned long long packetsReportedAsLostButRecovered; long long packetsLost; double jitter; }; @@ -107,11 +111,13 @@ dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats { double totalRoundTripTime; double fractionLost; unsigned long long roundTripTimeMeasurements; + unsigned long long packetsWithBleachedEct1Marking; }; dictionary RTCSentRtpStreamStats : RTCRtpStreamStats { - unsigned long long packetsSent; - unsigned long long bytesSent; + unsigned long long packetsSent; + unsigned long long bytesSent; + unsigned long long packetsSentWithEct1; }; dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats { @@ -119,6 +125,7 @@ dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats { DOMString mediaSourceId; DOMString remoteId; DOMString rid; + unsigned long encodingIndex; unsigned long long headerBytesSent; unsigned long long retransmittedPacketsSent; unsigned long long retransmittedBytesSent; @@ -225,6 +232,8 @@ dictionary RTCTransportStats : RTCStats { RTCDtlsRole dtlsRole; DOMString srtpCipher; unsigned long selectedCandidatePairChanges; + unsigned long ccfbMessagesSent; + unsigned long ccfbMessagesReceived; }; enum RTCDtlsRole { diff --git a/test/fixtures/wpt/interfaces/webrtc.idl b/test/fixtures/wpt/interfaces/webrtc.idl index 174ead6261c..b6323136b09 100644 --- a/test/fixtures/wpt/interfaces/webrtc.idl +++ b/test/fixtures/wpt/interfaces/webrtc.idl @@ -163,7 +163,7 @@ dictionary RTCLocalSessionDescriptionInit { [Exposed=Window] interface RTCIceCandidate { - constructor(optional RTCIceCandidateInit candidateInitDict = {}); + constructor(optional RTCLocalIceCandidateInit candidateInitDict = {}); readonly attribute DOMString candidate; readonly attribute DOMString? sdpMid; readonly attribute unsigned short? sdpMLineIndex; @@ -179,7 +179,7 @@ interface RTCIceCandidate { readonly attribute unsigned short? relatedPort; readonly attribute DOMString? usernameFragment; readonly attribute RTCIceServerTransportProtocol? relayProtocol; - readonly attribute DOMString? url; + readonly attribute USVString? url; RTCIceCandidateInit toJSON(); }; @@ -190,6 +190,11 @@ dictionary RTCIceCandidateInit { DOMString? usernameFragment = null; }; +dictionary RTCLocalIceCandidateInit : RTCIceCandidateInit { + RTCIceServerTransportProtocol? relayProtocol = null; + USVString? url = null; +}; + enum RTCIceProtocol { "udp", "tcp" @@ -218,7 +223,7 @@ enum RTCIceServerTransportProtocol { interface RTCPeerConnectionIceEvent : Event { constructor(DOMString type, optional RTCPeerConnectionIceEventInit eventInitDict = {}); readonly attribute RTCIceCandidate? candidate; - readonly attribute DOMString? url; + readonly attribute USVString? url; }; dictionary RTCPeerConnectionIceEventInit : EventInit { diff --git a/test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html b/test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html new file mode 100644 index 00000000000..ba597d893d3 --- /dev/null +++ b/test/fixtures/wpt/service-workers/service-worker/client-url-creation-url.https.html @@ -0,0 +1,129 @@ + +Service Worker: Client.url is Window creation URL tests + + + + \ No newline at end of file diff --git a/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-iframe.html b/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-iframe.html new file mode 100644 index 00000000000..db2b9e5bbd9 --- /dev/null +++ b/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-iframe.html @@ -0,0 +1,85 @@ + +Service Worker: Client.url is Window creation URL iframe resource + \ No newline at end of file diff --git a/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-sw.js b/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-sw.js new file mode 100644 index 00000000000..013d9be4cae --- /dev/null +++ b/test/fixtures/wpt/service-workers/service-worker/resources/client-url-creation-url-sw.js @@ -0,0 +1,24 @@ +// This is a service worker script used by the client-url-creation-url test. +// It exists only to look up the client URL of the test iframe and send it back +// to the test page. +addEventListener('message', message_event => { + const port = message_event.data.port; + + const async_work = async () => { + try { + const clients = await self.clients.matchAll(); + + // In our test there should be exactly one client that is our test + // navigation iframe. + if (clients.length == 1) { + const client = clients[0]; + port.postMessage(client.url); + } else { + port.postMessage(`error: expected 1 client, not ${clients.length}`); + } + } catch (error) { + port.postMessage(`error: ${error.message}`); + } + }; + message_event.waitUntil(async_work()); +}); \ No newline at end of file diff --git a/test/fixtures/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https.html b/test/fixtures/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https.html index e32436da41b..9d6137d9c52 100644 --- a/test/fixtures/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https.html +++ b/test/fixtures/wpt/service-workers/service-worker/tentative/static-router/static-router-resource-timing.https.html @@ -68,7 +68,7 @@ assert_less_than_equal(entry.workerCacheLookupStart, entry.fetchStart, description); } break; - case 'race-network-and-fetch': + case 'race-network-and-fetch-handler': assert_equals(entry.workerCacheLookupStart, 0, description); if (entry.workerFinalSourceType === 'network') { assert_equals(entry.workerStart, 0, description); @@ -261,7 +261,7 @@ test_resource_timing({ performance: iframe.contentWindow.performance, url: url, - matched_source_type: 'race-network-and-fetch', + matched_source_type: 'race-network-and-fetch-handler', final_source_type: 'fetch-event', description: "race as source on main resource, and fetch-event wins" }); @@ -280,7 +280,7 @@ test_resource_timing({ performance: iframe.contentWindow.performance, url: url, - matched_source_type: 'race-network-and-fetch', + matched_source_type: 'race-network-and-fetch-handler', final_source_type: 'network', description: "race as source on main resource, and network wins" }); @@ -301,7 +301,7 @@ test_resource_timing({ performance: iframe.contentWindow.performance, url: `${RACE_ROUTE}${subresource}`, - matched_source_type: 'race-network-and-fetch', + matched_source_type: 'race-network-and-fetch-handler', final_source_type: 'fetch-event', description: "race as source on subresource and fetch wins" }); @@ -323,7 +323,7 @@ test_resource_timing({ performance: iframe.contentWindow.performance, url: `${RACE_ROUTE}${subresource}`, - matched_source_type: 'race-network-and-fetch', + matched_source_type: 'race-network-and-fetch-handler', final_source_type: 'network', description: "race as source on subresource and network wins" }); diff --git a/test/types/websocket.test-d.ts b/test/types/websocket.test-d.ts new file mode 100644 index 00000000000..00a22f4e351 --- /dev/null +++ b/test/types/websocket.test-d.ts @@ -0,0 +1,10 @@ +import { ReadableStream, WritableStream } from 'stream/web' +import { expectType } from 'tsd' +import { WebSocketStream } from '../../types' + +declare const webSocketStream: WebSocketStream +const webSocketStreamOpened = await webSocketStream.opened + +// Test that the readable and writable streams are of identical types to ones from stream/web +expectType(webSocketStreamOpened.writable) +expectType(webSocketStreamOpened.readable) diff --git a/test/wpt/status/service-workers/cache-storage.status.json b/test/wpt/status/service-workers/cache-storage.status.json index b97ac5e993e..84592ed0d2d 100644 --- a/test/wpt/status/service-workers/cache-storage.status.json +++ b/test/wpt/status/service-workers/cache-storage.status.json @@ -22,7 +22,10 @@ "fail": [ "cors-exposed header should be stored correctly.", "Cache.match ignores vary headers on opaque response.", - "Cache.match blob should be sliceable" + "Cache.match blob should be sliceable", + "Cache.match with POST Request", + "Cache.match with a non-2xx Response", + "Cache.match with a network error Response" ], "flaky": [ "Cache.match invoked multiple times for the same Request/Response" diff --git a/types/websocket.d.ts b/types/websocket.d.ts index 563866479f1..02e4865c7d8 100644 --- a/types/websocket.d.ts +++ b/types/websocket.d.ts @@ -1,6 +1,7 @@ /// import type { Blob } from 'buffer' +import type { ReadableStream, WritableStream } from 'stream/web' import type { MessagePort } from 'worker_threads' import { EventInit,