Skip to content

Commit

Permalink
Iterate manually over response.body
Browse files Browse the repository at this point in the history
I'm honestly not sure if there is a problem in Node itself or in undici, but I'm seeing issues with the stream reader not releasing its lock properly when using `for await...of` to iterate over `response.body` in `sendResponse`. In any case, there may be a variety of `Response` implementations that people eventually want to use with this, and async iterators are hard to get right, so dropping down to the lower-level `getReader()` API for stream iteration seems like a prudent move.
  • Loading branch information
mjackson committed Jan 25, 2025
1 parent 185e4ea commit e494971
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 7 deletions.
4 changes: 4 additions & 0 deletions packages/node-fetch-server/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

This is the changelog for [`node-fetch-server`](https://github.com/mjackson/remix-the-web/tree/main/packages/node-fetch-server). It follows [semantic versioning](https://semver.org/).

## HEAD

- Iterate manually over response bodies in `sendResponse` instead of using `for await...of`. This seems to avoid an issue where the iterator tries to read from a stream after the lock has been released.

## v0.5.0 (2024-12-09)

- Expose `createHeaders(req: http.IncomingMessage): Headers` API for creating headers from the headers of incoming request objects.
Expand Down
6 changes: 0 additions & 6 deletions packages/node-fetch-server/global.d.ts

This file was deleted.

9 changes: 9 additions & 0 deletions packages/node-fetch-server/src/lib/read-stream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export async function* readStream(stream: ReadableStream<Uint8Array>): AsyncIterable<Uint8Array> {
let reader = stream.getReader();

while (true) {
const { done, value } = await reader.read();
if (done) break;
yield value;
}
}
3 changes: 2 additions & 1 deletion packages/node-fetch-server/src/lib/request-listener.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type * as http from 'node:http';

import { type ClientAddress, type ErrorHandler, type FetchHandler } from './fetch-handler.ts';
import { readStream } from './read-stream.ts';

export interface RequestListenerOptions {
/**
Expand Down Expand Up @@ -204,7 +205,7 @@ export async function sendResponse(res: http.ServerResponse, response: Response)
res.writeHead(response.status, headers);

if (response.body != null && res.req.method !== 'HEAD') {
for await (let chunk of response.body) {
for await (let chunk of readStream(response.body)) {
res.write(chunk);
}
}
Expand Down

0 comments on commit e494971

Please sign in to comment.