From ee86e3b8a7b46a10f03b2864e79e829dd599700f Mon Sep 17 00:00:00 2001 From: Khafra Date: Thu, 9 May 2024 17:13:45 -0400 Subject: [PATCH 1/4] don't set an invalid origin header (fetch) --- lib/web/fetch/index.js | 3 +-- lib/web/fetch/util.js | 35 +++++++++++++++++++------------- test/fetch/issue-rsshub-15532.js | 25 +++++++++++++++++++++++ 3 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 test/fetch/issue-rsshub-15532.js diff --git a/lib/web/fetch/index.js b/lib/web/fetch/index.js index 5fbef495ad6..7c9dc062c36 100644 --- a/lib/web/fetch/index.js +++ b/lib/web/fetch/index.js @@ -444,8 +444,7 @@ function fetching ({ // 9. If request’s origin is "client", then set request’s origin to request’s // client’s origin. if (request.origin === 'client') { - // TODO: What if request.client is null? - request.origin = request.client?.origin + request.origin = request.client?.origin ?? request.origin } // 10. If all of the following conditions are true: diff --git a/lib/web/fetch/util.js b/lib/web/fetch/util.js index 299f4e64c81..c2090a50d8e 100644 --- a/lib/web/fetch/util.js +++ b/lib/web/fetch/util.js @@ -255,16 +255,22 @@ function appendFetchMetadata (httpRequest) { // https://fetch.spec.whatwg.org/#append-a-request-origin-header function appendRequestOriginHeader (request) { - // 1. Let serializedOrigin be the result of byte-serializing a request origin with request. + // 1. Let serializedOrigin be the result of byte-serializing a request origin + // with request. + // TODO: implement "byte-serializing a request origin" let serializedOrigin = request.origin - // 2. If request’s response tainting is "cors" or request’s mode is "websocket", then append (`Origin`, serializedOrigin) to request’s header list. - if (request.responseTainting === 'cors' || request.mode === 'websocket') { - if (serializedOrigin) { - request.headersList.append('origin', serializedOrigin, true) - } + // "'client' is changed to an origin during fetching." + // This doesn't happen in undici (in most cases) because undici, by default, + // has no concept of origin. + if (serializedOrigin === 'client') { + return + } - // 3. Otherwise, if request’s method is neither `GET` nor `HEAD`, then: + // 2. If request’s response tainting is "cors" or request’s mode is "websocket", + // then append (`Origin`, serializedOrigin) to request’s header list. + if (request.responseTainting === 'cors' || request.mode === 'websocket') { + request.headersList.append('origin', serializedOrigin, true) } else if (request.method !== 'GET' && request.method !== 'HEAD') { // 1. Switch on request’s referrer policy: switch (request.referrerPolicy) { @@ -275,13 +281,16 @@ function appendRequestOriginHeader (request) { case 'no-referrer-when-downgrade': case 'strict-origin': case 'strict-origin-when-cross-origin': - // If request’s origin is a tuple origin, its scheme is "https", and request’s current URL’s scheme is not "https", then set serializedOrigin to `null`. - if (request.origin && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) { + // If request’s origin is a tuple origin, its scheme is "https", and + // request’s current URL’s scheme is not "https", then set + // serializedOrigin to `null`. + if (request.origin !== 'client' && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) { serializedOrigin = null } break case 'same-origin': - // If request’s origin is not same origin with request’s current URL’s origin, then set serializedOrigin to `null`. + // If request’s origin is not same origin with request’s current URL’s + // origin, then set serializedOrigin to `null`. if (!sameOrigin(request, requestCurrentURL(request))) { serializedOrigin = null } @@ -290,10 +299,8 @@ function appendRequestOriginHeader (request) { // Do nothing. } - if (serializedOrigin) { - // 2. Append (`Origin`, serializedOrigin) to request’s header list. - request.headersList.append('origin', serializedOrigin, true) - } + // 2. Append (`Origin`, serializedOrigin) to request’s header list. + request.headersList.append('origin', serializedOrigin, true) } } diff --git a/test/fetch/issue-rsshub-15532.js b/test/fetch/issue-rsshub-15532.js new file mode 100644 index 00000000000..11491337de5 --- /dev/null +++ b/test/fetch/issue-rsshub-15532.js @@ -0,0 +1,25 @@ +'use strict' + +const { once } = require('node:events') +const { createServer } = require('node:http') +const { test } = require('node:test') +const { fetch } = require('../..') +const { tspl } = require('@matteo.collina/tspl') + +// https://github.com/DIYgod/RSSHub/issues/15532 +test('An invalid Origin header is not set', async (t) => { + const { deepStrictEqual } = tspl(t, { plan: 1 }) + + const server = createServer((req, res) => { + deepStrictEqual(req.headers.origin, undefined) + + res.end() + }).listen(0) + + await once(server, 'listening') + t.after(server.close.bind(server)) + + await fetch(`http://localhost:${server.address().port}`, { + method: 'POST' + }) +}) From ce25f43ea687abdb0d0dd4da1db3a04212f67dd9 Mon Sep 17 00:00:00 2001 From: Khafra Date: Thu, 9 May 2024 17:15:11 -0400 Subject: [PATCH 2/4] fixup --- lib/web/fetch/util.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/web/fetch/util.js b/lib/web/fetch/util.js index c2090a50d8e..cfee6e8326c 100644 --- a/lib/web/fetch/util.js +++ b/lib/web/fetch/util.js @@ -269,6 +269,7 @@ function appendRequestOriginHeader (request) { // 2. If request’s response tainting is "cors" or request’s mode is "websocket", // then append (`Origin`, serializedOrigin) to request’s header list. + // 3. Otherwise, if request’s method is neither `GET` nor `HEAD`, then: if (request.responseTainting === 'cors' || request.mode === 'websocket') { request.headersList.append('origin', serializedOrigin, true) } else if (request.method !== 'GET' && request.method !== 'HEAD') { From f727b5fe457da6b1fc8a2e43437642258e880577 Mon Sep 17 00:00:00 2001 From: Khafra Date: Thu, 9 May 2024 17:18:30 -0400 Subject: [PATCH 3/4] fixup --- lib/web/fetch/util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web/fetch/util.js b/lib/web/fetch/util.js index cfee6e8326c..e533ac957ca 100644 --- a/lib/web/fetch/util.js +++ b/lib/web/fetch/util.js @@ -285,7 +285,7 @@ function appendRequestOriginHeader (request) { // If request’s origin is a tuple origin, its scheme is "https", and // request’s current URL’s scheme is not "https", then set // serializedOrigin to `null`. - if (request.origin !== 'client' && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) { + if (request.origin && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) { serializedOrigin = null } break From 0ee4818f4c2951c8b973b3734d98658be2970fa0 Mon Sep 17 00:00:00 2001 From: Khafra Date: Thu, 9 May 2024 17:32:13 -0400 Subject: [PATCH 4/4] fixup --- lib/web/fetch/index.js | 2 +- lib/web/websocket/connection.js | 3 ++- lib/web/websocket/websocket.js | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/web/fetch/index.js b/lib/web/fetch/index.js index 7c9dc062c36..784e0c2cdbb 100644 --- a/lib/web/fetch/index.js +++ b/lib/web/fetch/index.js @@ -444,7 +444,7 @@ function fetching ({ // 9. If request’s origin is "client", then set request’s origin to request’s // client’s origin. if (request.origin === 'client') { - request.origin = request.client?.origin ?? request.origin + request.origin = request.client.origin } // 10. If all of the following conditions are true: diff --git a/lib/web/websocket/connection.js b/lib/web/websocket/connection.js index a434e45ac82..5058fc58095 100644 --- a/lib/web/websocket/connection.js +++ b/lib/web/websocket/connection.js @@ -35,7 +35,7 @@ try { * @param {(response: any) => void} onEstablish * @param {Partial} options */ -function establishWebSocketConnection (url, protocols, ws, onEstablish, options) { +function establishWebSocketConnection (url, protocols, client, ws, onEstablish, options) { // 1. Let requestURL be a copy of url, with its scheme set to "http", if url’s // scheme is "ws", and to "https" otherwise. const requestURL = url @@ -48,6 +48,7 @@ function establishWebSocketConnection (url, protocols, ws, onEstablish, options) // and redirect mode is "error". const request = makeRequest({ urlList: [requestURL], + client, serviceWorkers: 'none', referrer: 'no-referrer', mode: 'websocket', diff --git a/lib/web/websocket/websocket.js b/lib/web/websocket/websocket.js index 892ce78c2db..97e86c3801e 100644 --- a/lib/web/websocket/websocket.js +++ b/lib/web/websocket/websocket.js @@ -124,6 +124,7 @@ class WebSocket extends EventTarget { this[kWebSocketURL] = new URL(urlRecord.href) // 11. Let client be this's relevant settings object. + const client = environmentSettingsObject.settingsObject // 12. Run this step in parallel: @@ -132,6 +133,7 @@ class WebSocket extends EventTarget { this[kController] = establishWebSocketConnection( urlRecord, protocols, + client, this, (response) => this.#onConnectionEstablished(response), options