diff --git a/.gitignore b/.gitignore index c322792..c6d497b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /client/build /client/out /client/fragments/tmp +/client/node_modules /server/.venv /server/websockify \ No newline at end of file diff --git a/README.md b/README.md index 5a7035c..a07eb86 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ This is a port of [libcurl](https://curl.se/libcurl/) to WebAssembly for use in - Use raw TLS sockets in the browser - Custom network transport support - Works inside web workers without needing special permissions or headers -- Works in all major browsers (Chromium >= 64, Firefox >= 65, Safari >= 14) +- Works in all major browsers (Chromium >= 64, Firefox >= 65, Safari >= 14) and Node.js - Has the ability to create multiple independent sessions - Small footprint size (552KB after compression) and low runtime memory usage - Support for Brotli and gzip compressed responses @@ -107,7 +107,7 @@ libcurl.onload = () => { Once loaded, there will be a `window.libcurl` object which includes all the API functions. The `libcurl.ready` property can also be used to know if the WASM has loaded. -There are also ES6 modules available if you are using a bundler. The `libcurl.mjs` and `libcurl_full.mjs` files provide this functionality, with the former being set as the entry point for the NPM package. +There are also ES6 modules available if you are using a bundler or running it in NodeJS. The `libcurl.mjs` and `libcurl_full.mjs` files provide this functionality, with the former being set as the entry point for the NPM package. ```js //import the regular version import { libcurl } from "libcurl.js"; diff --git a/client/build.sh b/client/build.sh index 423d7ab..818c37a 100755 --- a/client/build.sh +++ b/client/build.sh @@ -38,7 +38,7 @@ EXPORTED_FUNCS="${EXPORTED_FUNCS:1}" #compile options RUNTIME_METHODS="addFunction,removeFunction,allocate,ALLOC_NORMAL" COMPILER_OPTIONS="-o $MODULE_FILE -lcurl -lmbedtls -lmbedcrypto -lmbedx509 -lcjson -lz -lbrotlidec -lbrotlicommon -lnghttp2 -I $INCLUDE_DIR -L $LIB_DIR" -EMSCRIPTEN_OPTIONS="-lwebsocket.js -sENVIRONMENT=worker,web -sASSERTIONS=1 -sLLD_REPORT_UNDEFINED -sALLOW_TABLE_GROWTH -sALLOW_MEMORY_GROWTH -sNO_EXIT_RUNTIME -sEXPORTED_FUNCTIONS=$EXPORTED_FUNCS -sEXPORTED_RUNTIME_METHODS=$RUNTIME_METHODS" +EMSCRIPTEN_OPTIONS="-lwebsocket.js -sENVIRONMENT=node,worker,web -sASSERTIONS=1 -sLLD_REPORT_UNDEFINED -sALLOW_TABLE_GROWTH -sALLOW_MEMORY_GROWTH -sNO_EXIT_RUNTIME -sEXPORTED_FUNCTIONS=$EXPORTED_FUNCS -sEXPORTED_RUNTIME_METHODS=$RUNTIME_METHODS" #clean output dir rm -rf $OUT_DIR @@ -122,5 +122,6 @@ sed -i "/__extra_libraries__/r $WISP_CLIENT/wisp.js" $OUT_FILE python3 tools/patch_js.py $FRAGMENTS_DIR $OUT_FILE #generate es6 module -cp $OUT_FILE $ES6_FILE -sed -i 's/const libcurl = /export const libcurl = /' $ES6_FILE \ No newline at end of file +cp "$OUT_FILE" "$ES6_FILE" +sed -i 's/export const libcurl = /const libcurl = /' "$OUT_FILE" +sed -i 's/export default libcurl;//' "$OUT_FILE" \ No newline at end of file diff --git a/client/fragments/fix_node_support.js b/client/fragments/fix_node_support.js new file mode 100644 index 0000000..0d3a7b9 --- /dev/null +++ b/client/fragments/fix_node_support.js @@ -0,0 +1,10 @@ +/* REPLACE +__dirname +*/ +globalThis.__dirname + +/* DELETE +if ?\(ENVIRONMENT_IS_NODE\) ?{\s*peer\.socket\.on.+?else ?(?={\s*peer\.socket\.onopen) +*/ + + diff --git a/client/fragments/force_wsproxy.js b/client/fragments/force_wsproxy.js index d65e701..29a8d62 100644 --- a/client/fragments/force_wsproxy.js +++ b/client/fragments/force_wsproxy.js @@ -12,3 +12,8 @@ var parts = addr.split("/"); url = Module.websocket.url; if (!url.endsWith("/")) url += "/"; url += parts[0] + ":" + port; + +/* DELETE +var WebSocketConstructor.+?WebSocketConstructor ?= ?WebSocket;?\s*} +*/ + diff --git a/client/fragments/wisp_support.js b/client/fragments/wisp_support.js index aad3fcb..8efb6f9 100644 --- a/client/fragments/wisp_support.js +++ b/client/fragments/wisp_support.js @@ -3,10 +3,10 @@ ws ?= ?new WebSocketConstructor\(url, ?opts\) */ try { if (api.transport === "wisp") { - ws = new WispWebSocket(url); + ws = new WispWebSocket(url, WSImpl); } else if (api.transport === "wsproxy") { - ws = new WebSocket(url); + ws = new WSImpl(url); } else if (typeof api.transport === "string") { throw new TypeError("invalid transport type"); diff --git a/client/javascript/http.js b/client/javascript/http.js index 62843c4..46328a0 100644 --- a/client/javascript/http.js +++ b/client/javascript/http.js @@ -193,7 +193,7 @@ class HTTPSession extends CurlSession { if (params.referrer) { params.headers["Referer"] = params.referrer; } - if (!params.headers["User-Agent"]) { + if (!params.headers["User-Agent"] && typeof navigator === "object") { params.headers["User-Agent"] = navigator.userAgent; } if (body && !params.headers["Content-Type"]) { diff --git a/client/javascript/main.js b/client/javascript/main.js index fd6227b..a728ea7 100644 --- a/client/javascript/main.js +++ b/client/javascript/main.js @@ -5,7 +5,7 @@ Licensed under the GNU LGPL v3. See https://github.com/ading2210/libcurl.js */ //everything is wrapped in a function to prevent emscripten from polluting the global scope -const libcurl = (function() { +export const libcurl = (function() { //emscripten compiled code is inserted here /* __emscripten_output__ */ @@ -21,6 +21,8 @@ var main_session = null; const libcurl_version = "__library_version__"; const wisp_version = "__wisp_version__"; +const WSImpl = (typeof process !== "undefined" && typeof WebSocket === "undefined") ? require("ws").WebSocket : WebSocket; + function check_loaded(check_websocket) { if (!wasm_ready) { throw new Error("wasm not loaded yet, please call libcurl.load_wasm first"); @@ -149,4 +151,6 @@ api = { return api; -})() \ No newline at end of file +})() + +export default libcurl; \ No newline at end of file diff --git a/client/javascript/session.js b/client/javascript/session.js index c6c8d9a..f35c7be 100644 --- a/client/javascript/session.js +++ b/client/javascript/session.js @@ -186,7 +186,7 @@ class CurlSession { try { stream_controller.close(); } - catch {} + catch (e) {} end_callback(error); } diff --git a/client/package-lock.json b/client/package-lock.json new file mode 100644 index 0000000..7f6f95e --- /dev/null +++ b/client/package-lock.json @@ -0,0 +1,36 @@ +{ + "name": "libcurl.js", + "version": "0.7.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "libcurl.js", + "version": "0.7.0", + "license": "LGPL-3.0-or-later", + "dependencies": { + "ws": "^8.18.0" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/client/package.json b/client/package.json index 9e29e81..0cce0c8 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "libcurl.js", - "version": "0.7.0", + "version": "0.7.1", "description": "A port of libcurl to WebAssembly, for proxying HTTPS requests from the browser with full TLS encryption", "main": "libcurl.mjs", "exports": { @@ -16,5 +16,8 @@ "bugs": { "url": "https://github.com/ading2210/libcurl.js/issues" }, - "homepage": "https://github.com/ading2210/libcurl.js" + "homepage": "https://github.com/ading2210/libcurl.js", + "dependencies": { + "ws": "^8.18.0" + } } diff --git a/client/tools/patch_js.py b/client/tools/patch_js.py index 65efcc5..43eb258 100755 --- a/client/tools/patch_js.py +++ b/client/tools/patch_js.py @@ -16,14 +16,14 @@ for fragment_file in fragments_path.iterdir(): matches = re.findall(match_regex, fragment_text, re.S) for mode, patch_regex, patch_text, _ in matches: - fragment_matches = re.findall(patch_regex, target_text) + fragment_matches = re.findall(patch_regex, target_text, flags=re.S) if not fragment_matches: print(f"warning: regex did not match anything for '{patch_regex}'"); if mode == "DELETE": - target_text = re.sub(patch_regex, "", target_text) + target_text = re.sub(patch_regex, "", target_text, flags=re.S) elif mode == "REPLACE": - target_text = re.sub(patch_regex, patch_text, target_text) + target_text = re.sub(patch_regex, patch_text, target_text, flags=re.S) elif mode == "INSERT": - target_text = re.sub("("+patch_regex+")", r'\1'+patch_text, target_text) + target_text = re.sub("("+patch_regex+")", r'\1'+patch_text, target_text, flags=re.S) target_path.write_text(target_text) \ No newline at end of file diff --git a/client/wisp_client b/client/wisp_client index 455b918..993e055 160000 --- a/client/wisp_client +++ b/client/wisp_client @@ -1 +1 @@ -Subproject commit 455b9186bfbd0915ed7082c9d356af2157ab014f +Subproject commit 993e0556fbac89a2bb8cfcbe72f687ed5a15b0da