fix(ClientRequest): support 100 continue flow - #599
Conversation
|
For mine use case, this error occur when using localstack and calling S3 upload. Uploading for first byte take so long (timeouts), that localstack sends back 100. 100 is not handled by undici/native fetch in v20 correctly and it throws error of not handle status code by undici. |
|
I've pushed the fix where we are now able to construct a Updates the tests, no idea why they are failing only when (1) the interceptor is on; (2) the BypassMocked |
|
I'll post here, since I see it is already in conversation for Nock. This issue is also happening for me, when uploading a big file, the client first sends the I'd be happy to help implement a solution, since I don't see how I could work around this elsewhere and it is necessary for me to upgrade to nock v14 (with fetch support, thanks to mswjs/interceptors). |
|
Bump |
|
@kettanaito Maybe things changed since you worked on it, but this is working to me: const { FetchResponse } = require('./lib/node')
const { ClientRequestInterceptor } = require('./lib/node/interceptors/ClientRequest')
const http = require('http');
const interceptor = new ClientRequestInterceptor();
interceptor.apply()
// Simple HTTP server
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
let body = '';
req.on('data', chunk => (body += chunk));
req.on('end', () => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Received: ' + body);
});
} else {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World');
}
});
server.listen(3001, () => {
console.log('Server listening on http://localhost:3001');
});
// Example client making a request with 'Expect: 100-continue'
const options = {
port: 3001,
method: 'POST',
headers: {
'Content-Length': Buffer.byteLength('test body'),
'Expect': '100-continue'
}
};
const req = http.request(options, res => {
let data = '';
res.on('data', chunk => (data += chunk));
res.on('end', () => {
console.log('Response:', data);
server.close();
});
});
req.on('continue', () => {
req.write('test body');
req.end();
});The problem is if the user wants to return 100 response as mocked response: interceptor.on('request', ({controller}) => {
controller.respondWith(new FetchResponse(null, { status: 100 }))
});error:
I continue (🥁) to investigate it. |
|
I think the problem is that the request "continues" to send the body, but on the The Update: ok... I understand the issue, we get the body (after the continue) in the interceptor, but can't react to it, because we already responded to the request: interceptor.on('request', ({controller, request}) => {
request.text().then(body => controller.respondWith(new FetchResponse('Hello World', { status: 200 }))) // body = "test body" as expected
controller.respondWith(new FetchResponse(null, { status: 100 }))
});
@kettanaito WDYT? |
|
Note for future: maybe we can use |
|
Hi! Any updates on this? Anyway I can help? |
|
Implemented in #770. |
|
First of all, thank you for #770. Moving interception down to I tested What works now: the request is intercepted, which it wasn't before — that alone is a real step forward. What still deadlocks: reading the request body inside the import http from 'node:http'
import { HttpRequestInterceptor } from '@mswjs/interceptors/http'
const interceptor = new HttpRequestInterceptor()
interceptor.on('request', async ({ request, controller }) => {
await request.clone().arrayBuffer() // <- never resolves
controller.respondWith(new Response('mocked'))
})
interceptor.apply()
const body = 'hello'
const request = http.request({
host: 'example.invalid', // RFC 2606, can never resolve
port: 80,
method: 'POST',
path: '/upload',
headers: { Expect: '100-continue', 'Content-Length': Buffer.byteLength(body) },
})
request.on('continue', () => request.end(body))
request.on('response', response => console.log('response:', response.statusCode))
request.on('error', error => console.log('error:', error.code))
setTimeout(() => console.log('still pending after 5s'), 5000)Drop the
Why this still blocks the original use case: nock has to read the body to decide which interceptor matches a request, so it hits exactly this deadlock. That's why it currently passes every So while #770 fixed the architecture, consumers that need the request body still can't handle these requests. Would you accept a change where the interceptor replies |
Relevant comments:
#515 (comment)
#515 (comment)