From 9cc0e4178bf027e0777ad9ca4b18635660b4e56c Mon Sep 17 00:00:00 2001 From: ading2210 Date: Fri, 26 Jan 2024 20:27:15 -0500 Subject: [PATCH] handle text frames properly, add docs --- README.md | 16 ++++++++++++++ client/exported_funcs.txt | 3 ++- client/types.h | 3 ++- client/websocket.c | 16 +++++++++----- client/websocket.js | 46 +++++++++++++++++++++++++++++---------- client/wisp_client | 2 +- 6 files changed, 67 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 6778449..ac9c981 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ This is an experimental port of [libcurl](https://curl.se/libcurl/) to WebAssemb - End to end encryption between the browser and the destination server - Support for up to TLS 1.3 - Support for tunneling HTTP/2 connections +- Support for proxying WebSockets - Bypass CORS restrictions - Low latency via multiplexing and reusing open connections @@ -54,6 +55,21 @@ Most of the standard Fetch API's features are supported, with the exception of: - Sending credentials/cookies automatically - Caching +### Creating WebSocket Connections: +To use WebSockets, create a `libcurl.WebSocket` object, which works identically to the regular [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) object. +```js +let ws = new libcurl.WebSocket("wss://echo.websocket.org"); +ws.binaryType = "arraybuffer"; +ws.addEventListener("open", () => { + console.log("ws connected!"); + ws.send("hello".repeat(128)); +}); +ws.addEventListener("message", (event) => { + let text = new TextDecoder().decode(event.data); + console.log(text); +}); +``` + ### Changing the Websocket URL: You can change the URL of the websocket proxy by using `libcurl.set_websocket`. ```js diff --git a/client/exported_funcs.txt b/client/exported_funcs.txt index 2d2a440..9b8c19a 100644 --- a/client/exported_funcs.txt +++ b/client/exported_funcs.txt @@ -11,6 +11,7 @@ get_result_size get_result_buffer get_result_code get_result_closed -get_result_fragment +get_result_bytes_left +get_result_is_text free \ No newline at end of file diff --git a/client/types.h b/client/types.h index afe8c85..84fb83a 100644 --- a/client/types.h +++ b/client/types.h @@ -13,6 +13,7 @@ struct WSResult { int res; int buffer_size; int closed; - int fragment; + int bytes_left; + int is_text; char* buffer; }; \ No newline at end of file diff --git a/client/websocket.c b/client/websocket.c index 1387106..f8f58c8 100644 --- a/client/websocket.c +++ b/client/websocket.c @@ -18,13 +18,16 @@ struct WSResult* recv_from_websocket(CURL* http_handle, int buffer_size) { result->buffer = buffer; result->res = (int) res; result->closed = (ws_meta->flags & CURLWS_CLOSE); - result->fragment = ws_meta->bytesleft; + result->is_text = (ws_meta->flags & CURLWS_TEXT); + result->bytes_left = ws_meta->bytesleft; return result; } -int send_to_websocket(CURL* http_handle, const char* data, int data_len) { +int send_to_websocket(CURL* http_handle, const char* data, int data_len, int is_text) { size_t sent; - CURLcode res = curl_ws_send(http_handle, data, data_len, &sent, 0, CURLWS_BINARY); + unsigned int flags = CURLWS_BINARY; + if (is_text) flags = CURLWS_TEXT; + CURLcode res = curl_ws_send(http_handle, data, data_len, &sent, 0, flags); return (int) res; } @@ -55,6 +58,9 @@ int get_result_code (const struct WSResult* result) { int get_result_closed (const struct WSResult* result) { return result->closed; } -int get_result_fragment (const struct WSResult* result) { - return result->fragment; +int get_result_bytes_left (const struct WSResult* result) { + return result->bytes_left; +} +int get_result_is_text (const struct WSResult* result) { + return result->is_text; } \ No newline at end of file diff --git a/client/websocket.js b/client/websocket.js index 165d538..c6451d3 100644 --- a/client/websocket.js +++ b/client/websocket.js @@ -55,10 +55,11 @@ class CurlWebSocket extends EventTarget { _free(data_ptr); this.recv_buffer.push(data); - if (data_size !== buffer_size && !_get_result_fragment(result_ptr)) { //message finished + if (data_size !== buffer_size && !_get_result_bytes_left(result_ptr)) { //message finished let full_data = merge_arrays(this.recv_buffer); + let is_text = _get_result_is_text(result_ptr) this.recv_buffer = []; - this.recv_callback(full_data); + this.recv_callback(full_data, is_text); } } @@ -75,17 +76,25 @@ class CurlWebSocket extends EventTarget { }, 1); } - recv_callback(data) { - if (this.binaryType == "blob") { - data = new Blob(data); - } - else if (this.binaryType == "arraybuffer") { - data = data.buffer; + recv_callback(data, is_text=false) { + let converted; + if (is_text) { + converted = new TextDecoder().decode(data); + console.log(is_text); } else { - throw "invalid binaryType string"; + if (this.binaryType == "blob") { + converted = new Blob(data); + } + else if (this.binaryType == "arraybuffer") { + converted = data.buffer; + } + else { + throw "invalid binaryType string"; + } } - let msg_event = new MessageEvent("message", {data: data}); + + let msg_event = new MessageEvent("message", {data: converted}); this.onmessage(msg_event); this.dispatchEvent(msg_event); } @@ -118,6 +127,7 @@ class CurlWebSocket extends EventTarget { } send(data) { + let is_text = false; if (this.status === this.CONNECTING) { throw new DOMException("ws not ready yet"); } @@ -128,6 +138,7 @@ class CurlWebSocket extends EventTarget { let data_array; if (typeof data === "string") { data_array = new TextEncoder().encode(data); + is_text = true; } else if (data instanceof Blob) { data.arrayBuffer().then(array_buffer => { @@ -157,11 +168,24 @@ class CurlWebSocket extends EventTarget { let data_ptr = allocate_array(data_array); let data_len = data.length; - _send_to_websocket(this.http_handle, data_ptr, data_len); + _send_to_websocket(this.http_handle, data_ptr, data_len, is_text); _free(data_ptr); } close() { _close_websocket(this.http_handle); } + + get readyState() { + return this.status; + } + get bufferedAmount() { + return 0; + } + get protocol() { + return ""; + } + get extensions() { + return ""; + } } \ No newline at end of file diff --git a/client/wisp_client b/client/wisp_client index 0596aef..51ad95a 160000 --- a/client/wisp_client +++ b/client/wisp_client @@ -1 +1 @@ -Subproject commit 0596aefa8206bbb128cab1f4b1ad4241289d2fda +Subproject commit 51ad95a6d912ec404c20284f0cded40c0b5c4e62