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
fix(ext/http): ensure request body resource lives as long as response is alive #20206
Conversation
073f313
to
36c3a6e
Compare
@@ -721,7 +721,7 @@ function createStreamTest(count: number, delay: number, action: string) { | |||
} | |||
|
|||
for (const count of [0, 1, 2, 3]) { | |||
for (const delay of [0, 1, 1000]) { | |||
for (const delay of [0, 1, 25]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer need a 1000ms test here -- there are no more timeouts in Deno.serve that exercise this path, so we can just use 25ms and make tests faster.
@@ -133,10 +133,6 @@ class InnerRequest { | |||
} | |||
|
|||
close() { | |||
if (this.#streamRid !== undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stream closing now happens in Rust.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
4f2eb22
to
e3e94fa
Compare
0bf571a
to
968e8f7
Compare
968e8f7
to
0dd0ebf
Compare
… is alive (denoland#20206) Deno.serve's fast streaming implementation was not keeping the request body resource ID alive. We were taking the `Rc<Resource>` from the resource table during the response, so a hairpin duplex response that fed back the request body would work. However, if any JS code attempted to read from the request body (which requires the resource ID to be valid), the response would fail with a difficult-to-diagnose "EOF" error. This was affecting more complex duplex uses of `Deno.fetch` (though as far as I can tell was unreported). Simple test: ```ts const reader = request.body.getReader(); return new Response( new ReadableStream({ async pull(controller) { const { done, value } = await reader.read(); if (done) { controller.close(); } else { controller.enqueue(value); } }, }), ``` And then attempt to use the stream in duplex mode: ```ts async function testDuplex( reader: ReadableStreamDefaultReader<Uint8Array>, writable: WritableStreamDefaultWriter<Uint8Array>, ) { await writable.write(new Uint8Array([1])); const chunk1 = await reader.read(); assert(!chunk1.done); assertEquals(chunk1.value, new Uint8Array([1])); await writable.write(new Uint8Array([2])); const chunk2 = await reader.read(); assert(!chunk2.done); assertEquals(chunk2.value, new Uint8Array([2])); await writable.close(); const chunk3 = await reader.read(); assert(chunk3.done); } ``` In older versions of Deno, this would just lock up. I believe after 23ff0e7, it started throwing a more explicit error: ``` httpServerStreamDuplexJavascript => ./cli/tests/unit/serve_test.ts:1339:6 error: TypeError: request or response body error: error reading a body from connection: Connection reset by peer (os error 54) at async Object.pull (ext:deno_web/06_streams.js:810:27) ```
… is alive (#20206) Deno.serve's fast streaming implementation was not keeping the request body resource ID alive. We were taking the `Rc<Resource>` from the resource table during the response, so a hairpin duplex response that fed back the request body would work. However, if any JS code attempted to read from the request body (which requires the resource ID to be valid), the response would fail with a difficult-to-diagnose "EOF" error. This was affecting more complex duplex uses of `Deno.fetch` (though as far as I can tell was unreported). Simple test: ```ts const reader = request.body.getReader(); return new Response( new ReadableStream({ async pull(controller) { const { done, value } = await reader.read(); if (done) { controller.close(); } else { controller.enqueue(value); } }, }), ``` And then attempt to use the stream in duplex mode: ```ts async function testDuplex( reader: ReadableStreamDefaultReader<Uint8Array>, writable: WritableStreamDefaultWriter<Uint8Array>, ) { await writable.write(new Uint8Array([1])); const chunk1 = await reader.read(); assert(!chunk1.done); assertEquals(chunk1.value, new Uint8Array([1])); await writable.write(new Uint8Array([2])); const chunk2 = await reader.read(); assert(!chunk2.done); assertEquals(chunk2.value, new Uint8Array([2])); await writable.close(); const chunk3 = await reader.read(); assert(chunk3.done); } ``` In older versions of Deno, this would just lock up. I believe after 23ff0e7, it started throwing a more explicit error: ``` httpServerStreamDuplexJavascript => ./cli/tests/unit/serve_test.ts:1339:6 error: TypeError: request or response body error: error reading a body from connection: Connection reset by peer (os error 54) at async Object.pull (ext:deno_web/06_streams.js:810:27) ```
Hello guys, I am facing a problem that only happens on deno 1.36.2, I was taking a look in the repository trying to figure which could be the change that potentially caused this and due to my lack of knowledge in rust I selected this one cause the title is close enough to what I've done to fix the issue so far. The problem is that the Check my PR changes to make it work if it could help: https://github.com/deco-cx/deco/pull/392/files Tested with + deno 1.36.1 Deno.serve((_req) => {
const resp = new Response("hello, world");
return new Response(resp.body);
}); Then curl http://localhost:8000 -vvv Now with deno 1.36.2 (used |
tbh can be this one too: https://github.com/denoland/deno/pull/20057/files |
Looks like islands larger than size X are broken, partially streamed to the browser. same for large HTMLs. I'm trying to reproduce it in a simple example than I can post it here. |
Let's move the discussion to the right issue then? I can reproduce this using fresh getting started, I'm going to create a sample repo |
Issue created on fresh: #20252 |
@mcandeia Thanks for the repro! I'll look at this ASAP. |
Deno.serve's fast streaming implementation was not keeping the request body resource ID alive. We were taking the
Rc<Resource>
from the resource table during the response, so a hairpin duplex response that fed back the request body would work.However, if any JS code attempted to read from the request body (which requires the resource ID to be valid), the response would fail with a difficult-to-diagnose "EOF" error.
This was affecting more complex duplex uses of
Deno.fetch
(though as far as I can tell was unreported).Simple test:
And then attempt to use the stream in duplex mode:
In older versions of Deno, this would just lock up. I believe after 23ff0e7, it started throwing a more explicit error: