mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
test(ext/http): add test for incomplete HTTP message and fix resource leak (#11717)
This commit adds a test case for "Http: connection closed before message completed" error as well as fixing an edge with resource leak when the error is raised.
This commit is contained in:
parent
163f2ef571
commit
d1d2388d7f
2 changed files with 82 additions and 2 deletions
|
@ -751,3 +751,67 @@ unitTest({ perms: { net: true } }, async function httpServerPanic() {
|
||||||
client.close();
|
client.close();
|
||||||
listener.close();
|
listener.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// https://github.com/denoland/deno/issues/11595
|
||||||
|
unitTest(
|
||||||
|
{ perms: { net: true } },
|
||||||
|
async function httpServerIncompleteMessage() {
|
||||||
|
const listener = Deno.listen({ port: 4501 });
|
||||||
|
const def1 = deferred();
|
||||||
|
const def2 = deferred();
|
||||||
|
|
||||||
|
const client = await Deno.connect({ port: 4501 });
|
||||||
|
await client.write(new TextEncoder().encode(
|
||||||
|
`GET / HTTP/1.0\r\n\r\n`,
|
||||||
|
));
|
||||||
|
|
||||||
|
const conn = await listener.accept();
|
||||||
|
const httpConn = Deno.serveHttp(conn);
|
||||||
|
const ev = await httpConn.nextRequest();
|
||||||
|
const { respondWith } = ev!;
|
||||||
|
|
||||||
|
const { readable, writable } = new TransformStream<Uint8Array>();
|
||||||
|
const writer = writable.getWriter();
|
||||||
|
|
||||||
|
async function writeResponse() {
|
||||||
|
await writer.write(
|
||||||
|
new TextEncoder().encode(
|
||||||
|
"written to the writable side of a TransformStream",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await writer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const errors: Error[] = [];
|
||||||
|
|
||||||
|
writeResponse()
|
||||||
|
.catch((error: Error) => {
|
||||||
|
errors.push(error);
|
||||||
|
})
|
||||||
|
.then(() => def1.resolve());
|
||||||
|
|
||||||
|
const res = new Response(readable);
|
||||||
|
|
||||||
|
respondWith(res)
|
||||||
|
.catch((error: Error) => errors.push(error))
|
||||||
|
.then(() => def2.resolve());
|
||||||
|
|
||||||
|
client.close();
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
def1,
|
||||||
|
def2,
|
||||||
|
]);
|
||||||
|
|
||||||
|
listener.close();
|
||||||
|
|
||||||
|
assertEquals(errors.length, 2);
|
||||||
|
for (const error of errors) {
|
||||||
|
assertEquals(error.name, "Http");
|
||||||
|
assertEquals(
|
||||||
|
error.message,
|
||||||
|
"connection closed before message completed",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
|
@ -436,17 +436,33 @@ async fn op_http_response(
|
||||||
// The only failure mode is the receiver already having dropped its end
|
// The only failure mode is the receiver already having dropped its end
|
||||||
// of the channel.
|
// of the channel.
|
||||||
if response_sender.sender.send(res).is_err() {
|
if response_sender.sender.send(res).is_err() {
|
||||||
|
if let Some(rid) = maybe_response_body_rid {
|
||||||
|
let _ = state
|
||||||
|
.borrow_mut()
|
||||||
|
.resource_table
|
||||||
|
.take::<ResponseBodyResource>(rid);
|
||||||
|
}
|
||||||
return Err(type_error("internal communication error"));
|
return Err(type_error("internal communication error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
poll_fn(|cx| match conn_resource.poll(cx) {
|
let result = poll_fn(|cx| match conn_resource.poll(cx) {
|
||||||
Poll::Ready(x) => {
|
Poll::Ready(x) => {
|
||||||
state.borrow_mut().resource_table.close(conn_rid).ok();
|
state.borrow_mut().resource_table.close(conn_rid).ok();
|
||||||
Poll::Ready(x)
|
Poll::Ready(x)
|
||||||
}
|
}
|
||||||
Poll::Pending => Poll::Ready(Ok(())),
|
Poll::Pending => Poll::Ready(Ok(())),
|
||||||
})
|
})
|
||||||
.await?;
|
.await;
|
||||||
|
|
||||||
|
if let Err(e) = result {
|
||||||
|
if let Some(rid) = maybe_response_body_rid {
|
||||||
|
let _ = state
|
||||||
|
.borrow_mut()
|
||||||
|
.resource_table
|
||||||
|
.take::<ResponseBodyResource>(rid);
|
||||||
|
}
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
if maybe_response_body_rid.is_none() {
|
if maybe_response_body_rid.is_none() {
|
||||||
conn_resource.deno_service.waker.wake();
|
conn_resource.deno_service.waker.wake();
|
||||||
|
|
Loading…
Reference in a new issue