Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fetch: don't set an invalid origin header #3235

Merged
merged 4 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions lib/web/fetch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

// 10. If all of the following conditions are true:
Expand Down
32 changes: 20 additions & 12 deletions lib/web/fetch/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,16 +255,23 @@ 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"
Uzlopak marked this conversation as resolved.
Show resolved Hide resolved
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
}

// 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') {
// 1. Switch on request’s referrer policy:
switch (request.referrerPolicy) {
Expand All @@ -275,13 +282,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’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))) {
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
}
Expand All @@ -290,10 +300,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)
}
}

Expand Down
3 changes: 2 additions & 1 deletion lib/web/websocket/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ try {
* @param {(response: any) => void} onEstablish
* @param {Partial<import('../../types/websocket').WebSocketInit>} 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
Expand All @@ -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',
Expand Down
2 changes: 2 additions & 0 deletions lib/web/websocket/websocket.js
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -132,6 +133,7 @@ class WebSocket extends EventTarget {
this[kController] = establishWebSocketConnection(
urlRecord,
protocols,
client,
this,
(response) => this.#onConnectionEstablished(response),
options
Expand Down
25 changes: 25 additions & 0 deletions test/fetch/issue-rsshub-15532.js
Original file line number Diff line number Diff line change
@@ -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'
})
})
Loading