1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-24 08:09:08 -05:00

fix(ext/net): make unix and tcp identical on close (#13075)

std/http/server knows how to handle "Listener has been closed"
exceptions but not "operation canceled" errors.

Make "unix" listen sockets throw the same exception as "tcp" listen
sockets when the socket is closed and has a pending accept operation.

There is still a discrepancy when multiple accept requests are posted
but that's probably a less visible issue and something for another day.

Fixes #13033
This commit is contained in:
Ben Noordhuis 2021-12-14 23:27:04 +01:00 committed by GitHub
parent 2c20e621aa
commit 4d176b7b7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 13 deletions

View file

@ -147,7 +147,8 @@ Deno.test(
listener.close(); listener.close();
await assertRejects( await assertRejects(
() => p, () => p,
Deno.errors.Interrupted, Deno.errors.BadResource,
"Listener has been closed",
); );
}, },
); );
@ -185,7 +186,7 @@ Deno.test(
const listener = Deno.listen({ transport: "unix", path: filePath }); const listener = Deno.listen({ transport: "unix", path: filePath });
let acceptErrCount = 0; let acceptErrCount = 0;
const checkErr = (e: Error) => { const checkErr = (e: Error) => {
if (e instanceof Deno.errors.Interrupted) { // "operation canceled" if (e.message === "Listener has been closed") {
assertEquals(acceptErrCount, 1); assertEquals(acceptErrCount, 1);
} else if (e instanceof Deno.errors.Busy) { // "Listener already in use" } else if (e instanceof Deno.errors.Busy) { // "Listener already in use"
acceptErrCount++; acceptErrCount++;

View file

@ -103,6 +103,15 @@ pub(crate) struct AcceptArgs {
pub transport: String, pub transport: String,
} }
pub(crate) fn accept_err(e: std::io::Error) -> AnyError {
// FIXME(bartlomieju): compatibility with current JS implementation
if let std::io::ErrorKind::Interrupted = e.kind() {
bad_resource("Listener has been closed")
} else {
e.into()
}
}
async fn accept_tcp( async fn accept_tcp(
state: Rc<RefCell<OpState>>, state: Rc<RefCell<OpState>>,
args: AcceptArgs, args: AcceptArgs,
@ -119,15 +128,11 @@ async fn accept_tcp(
.try_borrow_mut() .try_borrow_mut()
.ok_or_else(|| custom_error("Busy", "Another accept task is ongoing"))?; .ok_or_else(|| custom_error("Busy", "Another accept task is ongoing"))?;
let cancel = RcRef::map(resource, |r| &r.cancel); let cancel = RcRef::map(resource, |r| &r.cancel);
let (tcp_stream, _socket_addr) = let (tcp_stream, _socket_addr) = listener
listener.accept().try_or_cancel(cancel).await.map_err(|e| { .accept()
// FIXME(bartlomieju): compatibility with current JS implementation .try_or_cancel(cancel)
if let std::io::ErrorKind::Interrupted = e.kind() { .await
bad_resource("Listener has been closed") .map_err(accept_err)?;
} else {
e.into()
}
})?;
let local_addr = tcp_stream.local_addr()?; let local_addr = tcp_stream.local_addr()?;
let remote_addr = tcp_stream.peer_addr()?; let remote_addr = tcp_stream.peer_addr()?;

View file

@ -91,8 +91,11 @@ pub(crate) async fn accept_unix(
.try_borrow_mut() .try_borrow_mut()
.ok_or_else(|| custom_error("Busy", "Listener already in use"))?; .ok_or_else(|| custom_error("Busy", "Listener already in use"))?;
let cancel = RcRef::map(resource, |r| &r.cancel); let cancel = RcRef::map(resource, |r| &r.cancel);
let (unix_stream, _socket_addr) = let (unix_stream, _socket_addr) = listener
listener.accept().try_or_cancel(cancel).await?; .accept()
.try_or_cancel(cancel)
.await
.map_err(crate::ops::accept_err)?;
let local_addr = unix_stream.local_addr()?; let local_addr = unix_stream.local_addr()?;
let remote_addr = unix_stream.peer_addr()?; let remote_addr = unix_stream.peer_addr()?;