Skip to content

Commit f744596

Browse files
authored
fetch: fix wpt test request-upload.any.js (#3234)
* fix * fix
1 parent 0a64b44 commit f744596

File tree

3 files changed

+109
-62
lines changed

3 files changed

+109
-62
lines changed

test/wpt/server/lockedresource.mjs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
export class LockedResource {
2+
constructor (resource) {
3+
this.locked = false
4+
this.waitingQueue = []
5+
this.resource = resource
6+
}
7+
8+
async acquire () {
9+
return new Promise(resolve => {
10+
if (!this.locked) {
11+
// If the lock is not already acquired, acquire it immediately
12+
this.locked = true
13+
resolve(this.resource)
14+
} else {
15+
// If the lock is already acquired, queue the resolve function
16+
this.waitingQueue.push(resolve)
17+
}
18+
})
19+
}
20+
21+
release () {
22+
if (this.waitingQueue.length > 0) {
23+
// If there are functions waiting to acquire the lock, execute the next one in the queue
24+
const nextResolve = this.waitingQueue.shift()
25+
nextResolve(this.resource)
26+
} else {
27+
// If there are no functions waiting, release the lock
28+
this.locked = false
29+
}
30+
}
31+
}
Lines changed: 78 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,132 @@
1+
import { LockedResource } from '../lockedresource.mjs'
2+
13
const stash = new Map()
4+
const lockedStash = new LockedResource(stash)
25

36
/**
47
* @see https://github.com/web-platform-tests/wpt/blob/master/fetch/connection-pool/resources/network-partition-key.py
5-
* @param {Parameters<import('http').RequestListener>[0]} req
6-
* @param {Parameters<import('http').RequestListener>[1]} res
8+
* @param {Parameters<import('http').RequestListener>[0]} request
9+
* @param {Parameters<import('http').RequestListener>[1]} response
710
* @param {URL} url
811
*/
9-
export function route (req, res, { searchParams, port }) {
10-
res.setHeader('Cache-Control', 'no-store')
12+
export async function route (request, response, { searchParams, port }) {
13+
response.setHeader('Cache-Control', 'no-store')
1114

1215
const dispatch = searchParams.get('dispatch')
1316
const uuid = searchParams.get('uuid')
1417
const partitionId = searchParams.get('partition_id')
1518

1619
if (!uuid || !dispatch || !partitionId) {
17-
res.statusCode = 404
18-
res.end('Invalid query parameters')
19-
return
20+
return simpleResponse(request, response, 404, 'Not found', 'Invalid query parameters')
2021
}
2122

2223
let testFailed = false
2324
let requestCount = 0
2425
let connectionCount = 0
2526

26-
if (searchParams.get('nocheck_partition') !== 'True') {
27-
const addressKey = `${req.socket.localAddress}|${port}`
28-
const serverState = stash.get(uuid) ?? {
29-
testFailed: false,
30-
requestCount: 0,
31-
connectionCount: 0
32-
}
27+
if (searchParams.get('nocheck_partition') !== 'true') {
28+
const stash = await lockedStash.acquire()
29+
try {
30+
const addressKey = `${request.socket.localAddress}|${port}`
31+
const serverState = stash.get(uuid) ?? {
32+
testFailed: false,
33+
requestCount: 0,
34+
connectionCount: 0,
35+
sockets: new Set()
36+
}
3337

34-
stash.delete(uuid)
35-
requestCount = serverState.requestCount + 1
36-
serverState.requestCount = requestCount
38+
stash.delete(uuid)
39+
requestCount = serverState.requestCount
40+
requestCount += 1
41+
serverState.requestCount = requestCount
3742

38-
if (Object.hasOwn(serverState, addressKey)) {
39-
if (serverState[addressKey] !== partitionId) {
40-
serverState.testFailed = true
43+
if (addressKey in serverState) {
44+
if (serverState[addressKey] !== partitionId) {
45+
serverState.testFailed = true
46+
}
47+
}
48+
49+
// We can detect if a new connection is created by checking if the socket
50+
// was already used in the test.
51+
if (serverState.sockets.has(request.socket) === false) {
52+
connectionCount = serverState.connectionCount
53+
connectionCount += 1
54+
serverState.connectionCount = connectionCount
55+
serverState.sockets.add(request.socket)
4156
}
42-
} else {
43-
connectionCount = serverState.connectionCount + 1
44-
serverState.connectionCount = connectionCount
45-
}
4657

47-
serverState[addressKey] = partitionId
48-
testFailed = serverState.testFailed
49-
stash.set(uuid, serverState)
58+
serverState[addressKey] = partitionId
59+
testFailed = serverState.testFailed
60+
stash.set(uuid, serverState)
61+
} finally {
62+
lockedStash.release()
63+
}
5064
}
5165

52-
const origin = req.headers.origin
66+
const origin = request.headers.origin
5367
if (origin) {
54-
res.setHeader('Access-Control-Allow-Origin', origin)
55-
res.setHeader('Access-Control-Allow-Credentials', 'true')
68+
response.setHeader('Access-Control-Allow-Origin', origin)
69+
response.setHeader('Access-Control-Allow-Credentials', 'true')
5670
}
5771

58-
if (req.method === 'OPTIONS') {
59-
return handlePreflight(req, res)
72+
if (request.method === 'OPTIONS') {
73+
return handlePreflight(request, response)
6074
}
6175

6276
if (dispatch === 'fetch_file') {
63-
res.end()
64-
return
77+
// There is currently no relevant wpt test that uses this dispatch
78+
return response.end()
6579
}
6680

6781
if (dispatch === 'check_partition') {
6882
const status = searchParams.get('status') ?? 200
6983

7084
if (testFailed) {
71-
res.statusCode = status
72-
res.end('Multiple partition IDs used on a socket')
73-
return
85+
return simpleResponse(request, response, status, 'OK', 'Multiple partition IDs used on a socket')
7486
}
7587

7688
let body = 'ok'
77-
if (searchParams.get('addcounter')) {
89+
if (searchParams.get('addcounter') === 'true') {
7890
body += `. Request was sent ${requestCount} times. ${connectionCount} connections were created.`
79-
res.statusCode = status
80-
res.end(body)
81-
return
91+
return simpleResponse(request, response, status, 'OK', body)
8292
}
8393
}
8494

8595
if (dispatch === 'clean_up') {
8696
stash.delete(uuid)
87-
res.statusCode = 200
8897
if (testFailed) {
89-
res.end('Test failed, but cleanup completed.')
90-
} else {
91-
res.end('cleanup complete')
98+
return simpleResponse(request, response, 200, 'OK', 'Test failed, but cleanup completed.')
9299
}
93-
94-
return
100+
return simpleResponse(request, response, 200, 'OK', 'cleanup complete')
95101
}
96102

97-
res.statusCode = 404
98-
res.end('Unrecognized dispatch parameter: ' + dispatch)
103+
return simpleResponse(request, response, 404, 'Not found', 'Unrecognized dispatch parameter: ' + dispatch)
104+
}
105+
106+
/**
107+
* @param {Parameters<import('http').RequestListener>[0]} request
108+
* @param {Parameters<import('http').RequestListener>[1]} response
109+
*/
110+
function handlePreflight (request, response) {
111+
response.statusCode = 200
112+
response.statusMessage = 'OK'
113+
response.setHeader('Access-Control-Allow-Methods', 'GET')
114+
response.setHeader('Access-Control-Allow-Headers', 'header-to-force-cors')
115+
response.setHeader('Access-Control-Max-Age', '86400')
116+
response.end('Preflight request')
99117
}
100118

101119
/**
102-
* @param {Parameters<import('http').RequestListener>[0]} req
103-
* @param {Parameters<import('http').RequestListener>[1]} res
120+
* @param {Parameters<import('http').RequestListener>[0]} request
121+
* @param {Parameters<import('http').RequestListener>[1]} response
122+
* @param {number} statusCode
123+
* @param {string} statusMessage
124+
* @param {string} body
125+
* @param {string} [contentType='text/plain']
104126
*/
105-
function handlePreflight (req, res) {
106-
res.statusCode = 200
107-
res.setHeader('Access-Control-Allow-Methods', 'GET')
108-
res.setHeader('Access-Control-Allow-Headers', 'header-to-force-cors')
109-
res.setHeader('Access-Control-Max-Age', '86400')
110-
res.end('Preflight request')
127+
function simpleResponse (request, response, statusCode, statusMessage, body, contentType = 'text/plain') {
128+
response.statusCode = statusCode
129+
response.statusMessage = statusMessage
130+
response.setHeader('Content-Type', contentType)
131+
response.end(body)
111132
}

test/wpt/status/fetch.status.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,6 @@
6868
"note": "undici doesn't filter headers",
6969
"skip": true
7070
},
71-
"request-upload.any.js": {
72-
"fail": [
73-
"Fetch with POST with text body on 421 response should be retried once on new connection."
74-
]
75-
},
7671
"request-upload.h2.any.js": {
7772
"note": "undici doesn't support http/2",
7873
"skip": true

0 commit comments

Comments
 (0)