diff --git a/client/fragments/wisp_support.js b/client/fragments/wisp_support.js index 9f12c37..2dbcc65 100644 --- a/client/fragments/wisp_support.js +++ b/client/fragments/wisp_support.js @@ -3,6 +3,8 @@ ws ?= ?new WebSocketConstructor\(url, ?opts\) */ try { let transport; + let tls = url.includes("---tls-enabled---"); + url = url.replace("---tls-enabled---", ""); if (api.transport === "wisp") { transport = new WispWebSocket(url); } @@ -15,7 +17,13 @@ try { else { //custom transports transport = new api.transport(url); } - ws = new tls_shim.ReclaimTLSSocket(url, transport); + // + if (tls) { + ws = new tls_shim.ReclaimTLSSocket(url, transport); + } + else { + ws = transport; + } } catch (e) { error_msg("Error while creating a TCP connection: " + e); diff --git a/client/javascript/http.js b/client/javascript/http.js index fa36f4b..fa08dfe 100644 --- a/client/javascript/http.js +++ b/client/javascript/http.js @@ -78,12 +78,16 @@ class HTTPSession extends CurlSession { this.remove_request(http_handle); http_handle = null; } + + let url_obj = new URL(url); + let tls = url_obj.protocol === "https:"; + params.headers["Host"] = url_obj.host; body_ptr = body ? allocate_array(body) : null; let body_length = body ? body.length : 0; let params_json = JSON.stringify(params); - - http_handle = this.stream_response(url, headers_callback, finish_callback, params.signal); + + http_handle = this.stream_response(url, headers_callback, finish_callback, params.signal, tls); c_func(_http_set_options, [http_handle, params_json, body_ptr, body_length]); if (this.cookie_filename && params.credentials !== "omit") { c_func(_http_set_cookie_jar, [http_handle, this.cookie_filename]); @@ -124,8 +128,21 @@ class HTTPSession extends CurlSession { } check_proxy(params.proxy); + let redirect_mode = params.redirect; let body = await this.constructor.create_options(params); - return await this.request_async(url, params, body); + params.redirect = "manual"; + if (redirect_mode === "manual") + return await this.request_async(url, params, body); + + for (let i = 0; i < 20; i++) { + let r = await this.request_async(url, params, body); + if (r.status !== 201 && (r.status+"")[0] !== "3") + return r; + if (redirect_mode === "error") + throw new Error("Too many redirects"); + url = new URL(r.headers.get("location"), url).href; + } + throw new Error("Too many redirects"); } static create_response(response_data, response_info) { @@ -134,6 +151,13 @@ class HTTPSession extends CurlSession { if (response_info.status === 204 || response_info.status === 205) { response_data = null; } + if (response_info.url.includes("---tls-enabled---")) { + let url_obj = new URL(response_info.url); + url_obj.hostname = url_obj.hostname.replace("---tls-enabled---", ""); + url_obj.protocol = "https:"; + if (url_obj.port === "443") url_obj.port = ""; + response_info.url = url_obj.href; + } //construct base response object let response_obj = new Response(response_data, response_info); diff --git a/client/javascript/session.js b/client/javascript/session.js index 3d7fce5..568f79a 100644 --- a/client/javascript/session.js +++ b/client/javascript/session.js @@ -51,7 +51,7 @@ class CurlSession { this.request_callbacks[request_id].headers(chunk); } - create_request(url, js_data_callback, js_end_callback, js_headers_callback) { + create_request(url, js_data_callback, js_end_callback, js_headers_callback, tls=false) { this.assert_ready(); let request_id = this.last_request_id++; this.request_callbacks[request_id] = { @@ -59,6 +59,18 @@ class CurlSession { data: js_data_callback, headers: js_headers_callback } + + //if tls is enabled, add a flag to the url + if (tls) { + let url_obj = new URL(url); + url_obj.hostname += "---tls-enabled---"; + if (url_obj.protocol == "https:") url_obj.protocol = "http:"; + if (url_obj.protocol == "wss:") url_obj.protocol = "ws:"; + if (!url_obj.port) { + url_obj.href = url_obj.href.replace(url_obj.origin, url_obj.origin + ":443"); + } + url = url_obj.href; + } let request_ptr = c_func(_create_request, [ url, request_id, this.data_callback_ptr, this.end_callback_ptr, this.headers_callback_ptr @@ -133,7 +145,7 @@ class CurlSession { } //wrap request callbacks using a readable stream and return the new callbacks - stream_response(url, headers_callback, end_callback, abort_signal) { + stream_response(url, headers_callback, end_callback, abort_signal, tls) { let stream_controller; let aborted = false; let headers_received = false; @@ -190,6 +202,6 @@ class CurlSession { end_callback(error); } - return this.create_request(url, real_data_callback, real_end_callback, () => {}); + return this.create_request(url, real_data_callback, real_end_callback, () => {}, tls); } } \ No newline at end of file diff --git a/client/javascript/tls_socket.js b/client/javascript/tls_socket.js index af953af..918b021 100644 --- a/client/javascript/tls_socket.js +++ b/client/javascript/tls_socket.js @@ -43,7 +43,7 @@ class TLSSocket extends CurlSession { } } - this.http_handle = this.create_request(this.url, data_callback, finish_callback, headers_callback); + this.http_handle = this.create_request(this.url, data_callback, finish_callback, headers_callback, true); _tls_socket_set_options(this.http_handle, +this.options.verbose); if (this.options.proxy) { c_func_str(_request_set_proxy, [this.http_handle, this.options.proxy]); diff --git a/client/javascript/websocket.js b/client/javascript/websocket.js index e86229f..ffe0650 100644 --- a/client/javascript/websocket.js +++ b/client/javascript/websocket.js @@ -56,7 +56,11 @@ class CurlWebSocket extends CurlSession { request_options._libcurl_verbose = 1; } - this.http_handle = this.create_request(this.url, data_callback, finish_callback, headers_callback); + let url_obj = new URL(this.url); + let tls = url_obj.protocol === "wss:"; + request_options.headers["Host"] = url_obj.host; + + this.http_handle = this.create_request(this.url, data_callback, finish_callback, headers_callback, tls); c_func(_http_set_options, [this.http_handle, JSON.stringify(request_options), null, 0]); _websocket_set_options(this.http_handle); if (this.options.proxy) { diff --git a/client/tests/run_tests.py b/client/tests/run_tests.py index 6b12122..6f1731b 100644 --- a/client/tests/run_tests.py +++ b/client/tests/run_tests.py @@ -18,6 +18,7 @@ class JSTest(unittest.TestCase): options.add_argument("--disable-dev-shm-usage") options.add_argument("--disable-browser-side-navigation") options.add_argument("--disable-gpu") + options.add_argument("--enable-experimental-web-platform-features") options.set_capability("goog:loggingPrefs", {"browser": "ALL"}) try: diff --git a/client/tests/scripts/redirect_out.js b/client/tests/scripts/redirect_out.js index 34d2aab..52368d0 100644 --- a/client/tests/scripts/redirect_out.js +++ b/client/tests/scripts/redirect_out.js @@ -7,5 +7,5 @@ async function test() { libcurl.stderr = out_callback; await libcurl.fetch("https://example.com/", {_libcurl_verbose: 1}); console.log(output); - assert(output[0] === "* Host example.com:443 was resolved.", "unexpected output in stderr"); + assert(output[0].includes("* Host example.com"), "unexpected output in stderr"); } \ No newline at end of file diff --git a/client/tls/index.mjs b/client/tls/index.mjs index a9275b1..715921c 100644 --- a/client/tls/index.mjs +++ b/client/tls/index.mjs @@ -68,9 +68,6 @@ export class ReclaimTLSSocket extends EventTarget { //set up socket callbacks this.socket.binaryType = "arraybuffer"; - this.socket.onopen = () => { - this.tls.startHandshake(); - } this.socket.onmessage = (event) => { this.tls.handleReceivedBytes(new Uint8Array(event.data)); } @@ -82,6 +79,14 @@ export class ReclaimTLSSocket extends EventTarget { this.status = this.CLOSED; this.emit_event(new Event("error")); } + if (this.socket.readyState === this.socket.CONNECTING) { + this.socket.onopen = () => { + this.tls.startHandshake(); + } + } + else { + this.tls.startHandshake(); + } this.status = this.CONNECTING; }