Skip to content
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

NetworkError caused by WebSocketStream cannot be caught? #22165

Closed
masx200 opened this issue Jan 29, 2024 · 5 comments
Closed

NetworkError caused by WebSocketStream cannot be caught? #22165

masx200 opened this issue Jan 29, 2024 · 5 comments

Comments

@masx200
Copy link

masx200 commented Jan 29, 2024

Version: Deno 1.40.1

const listener = Deno.listen({ port: 9000, transport: "tcp" });

try {
    for await (const conn of listener) {
        (async () => {
            const ws = new WebSocketStream("ws://loca99999999999lhost:8000", {
                headers: {
                    "x-Protocol": "Transmission Control",
                    "X-Destination-Address": "www.ba99999999999idu.com",
                    "X-Destination-Port": "80",
                },
            });
            // console.log(ws);
            try {
                const webConn = await ws.opened; //.catch(console.error);
                // console.log(webConn);
                conn.readable.pipeTo(webConn.writable).catch(function (e) {
                    try {
                        ws.close();
                        conn.close();
                    } catch (e) {
                        console.error(e);
                    }

                    return console.error(e);
                });
                webConn.readable.pipeTo(conn.writable).catch(function (e) {
                    try {
                        ws.close();
                        conn.close();
                    } catch (e) {
                        console.error(e);
                    }
                    return console.error(e);
                });
            } catch (error) {
                console.error(error);
                try {
                    ws.close();
                    conn.close();
                } catch (e) {
                    console.error(e);
                }
            }
        })().catch(console.error);
    }
} catch (error) {
    console.error(error);
}
deno run --unstable -A ./client.ts
⚠️  The `--unstable` flag is deprecated and will be removed in Deno 2.0. Use granular `--unstable-*` flags instead.
Learn more at: https://docs.deno.com/runtime/manual/tools/unstable_flags
DOMException: failed to connect to WebSocket: 不知道这样的主机。 (os error 11001)
    at new DOMException (ext:deno_web/01_dom_exception.js:116:20)
    at DOMExceptionNetworkError (ext:runtime_main/js/99_main.js:391:12)
    at ext:core/00_infra.js:200:34
    at eventLoopTick (ext:core/01_core.js:59:7)
error: Uncaught (in promise) NetworkError: failed to connect to WebSocket: 不知道这样的主机。 (os error 11001)
curl -I -v localhost:9000 -H host:www.baidu.com
*   Trying [::1]:9000...
*   Trying 127.0.0.1:9000...
* Connected to localhost (127.0.0.1) port 9000
> HEAD / HTTP/1.1
> Host:www.baidu.com
> User-Agent: curl/8.4.0
> Accept: */*
>
* Empty reply from server
* Closing connection
curl: (52) Empty reply from server
@kt3k
Copy link
Member

kt3k commented Jan 29, 2024

It looks like you also need to await ws.closed to avoid uncaught error:

 const listener = Deno.listen({ port: 9000, transport: "tcp" });

 try {
    for await (const conn of listener) {
        (async () => {
            const ws = new WebSocketStream("ws://loca99999999999lhost:8000", {
                headers: {
                    "x-Protocol": "Transmission Control",
                    "X-Destination-Address": "www.ba99999999999idu.com",
                    "X-Destination-Port": "80",
                },
            });
            // console.log(ws);
            try {
                const webConn = await ws.opened; //.catch(console.error);
                // console.log(webConn);
                conn.readable.pipeTo(webConn.writable).catch(function (e) {
                    try {
                        ws.close();
                        conn.close();
                    } catch (e) {
                        console.error(e);
                    }

                    return console.error(e);
                });
                webConn.readable.pipeTo(conn.writable).catch(function (e) {
                    try {
                        ws.close();
                        conn.close();
                    } catch (e) {
                        console.error(e);
                    }
                    return console.error(e);
                });
            } catch (error) {
                console.error(error);
                try {
                    ws.close();
                    conn.close();
+                   await ws.closed;
                } catch (e) {
                    console.error(e);
                }
            }
        })().catch(console.error);
    }
 } catch (error) {
    console.error(error);
 }

@masx200
Copy link
Author

masx200 commented Jan 29, 2024

While this can be solved, can we design a better WebSocketStream api?
It's too hard to use

@masx200
Copy link
Author

masx200 commented Jan 29, 2024

export class WebSocketStream {
    public socket: WebSocket;
    public readable: ReadableStream<Uint8Array>;
    public writable: WritableStream<Uint8Array>;

    constructor(socket: WebSocket) {
        this.socket = socket;
        this.readable = new ReadableStream({
            start(controller) {
                socket.onmessage = function ({ data }) {
                    // console.log(data);
                    return controller.enqueue(new Uint8Array(data));
                };
                socket.onerror = (e) => controller.error(e);
                socket.onclose = (/* e */) => controller.close(/* e */);
            },
            cancel(/* reason */) {
                socket.close();
            },
        });
        this.writable = new WritableStream({
            start(controller) {
                socket.onerror = (e) => controller.error(e);
            },
            write(chunk) {
                // console.log(chunk);
                socket.send(chunk);
            },
            close() {
                socket.close();
            },
            abort(e) {
                console.error(e);
                socket.close();
            },
        });
    }
}

@kt3k
Copy link
Member

kt3k commented Jan 29, 2024

WebSocketStream is designed based on Web Standard proposal whatwg/websockets#48 It's not a good idea to design it in our own way.

ref: #8831

@kt3k
Copy link
Member

kt3k commented Jan 30, 2024

Closing as the original issue is solved and nothing is actionable further.

While this can be solved, can we design a better WebSocketStream api?
It's too hard to use

You are encouraged to create 3rd party module to address those pain points

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants