From 9dfb9ad326b40b098e6c24385a66316d6db11a22 Mon Sep 17 00:00:00 2001 From: Carlo Piovesan Date: Fri, 29 Aug 2025 11:26:49 +0200 Subject: [PATCH] HTTPWasmClient: Implement PUT --- lib/src/http_wasm.cc | 144 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/lib/src/http_wasm.cc b/lib/src/http_wasm.cc index dc7b9b084..f09729eb2 100644 --- a/lib/src/http_wasm.cc +++ b/lib/src/http_wasm.cc @@ -435,7 +435,149 @@ class HTTPWasmClient : public HTTPClient { return res; } - unique_ptr Put(PutRequestInfo &info) override { return nullptr; } + unique_ptr Put(PutRequestInfo &info) override { + unique_ptr res; + + string path = host_port + info.url; + path = info.url; + + int n = 0; + for (auto h : info.headers) { + n++; + } + + char **z = (char **)(void *)malloc(n * 4 * 2); + + int i = 0; + for (auto h : info.headers) { + z[i] = (char *)malloc(h.first.size() * 4 + 1); + memset(z[i], 0, h.first.size() * 4 + 1); + memcpy(z[i], h.first.c_str(), h.first.size()); + i++; + z[i] = (char *)malloc(h.second.size() * 4 + 1); + memset(z[i], 0, h.second.size() * 4 + 1); + memcpy(z[i], h.second.c_str(), h.second.size()); + i++; + } + + const int buffer_length = info.buffer_in_len; + char *payload = (char *)malloc(buffer_length); + memcpy(payload, info.buffer_in, buffer_length); + + // clang-format off + char *exe = NULL; + exe = (char *)EM_ASM_PTR( + { + var url = (UTF8ToString($0)); + if (typeof XMLHttpRequest === "undefined") { + return 0; + } + const xhr = new XMLHttpRequest(); + if (false && url.startsWith("http://")) { + url = "https://" + url.substr(7); + } + xhr.open(UTF8ToString($3), url, false); + xhr.responseType = "arraybuffer"; + + var i = 0; + var len = $1; + while (i < len*2) { + var ptr1 = HEAP32[($2)/4 + i ]; + var ptr2 = HEAP32[($2)/4 + i + 1]; + + try { + var z = encodeURI(UTF8ToString(ptr1)); + if (z === "Host") z = "X-Host-Override"; + if (z === "User-Agent") z = "X-user-agent"; + if (z === "Authorization") { + xhr.setRequestHeader(z, UTF8ToString(ptr2)); + } else { + + xhr.setRequestHeader(z, encodeURI(UTF8ToString(ptr2))); + } + } catch (error) { + console.warn("Error while performing XMLHttpRequest.setRequestHeader()", error); + } + i += 2; + } + +//xhr.setRequestHeader("Content-Type", "application/octet-stream"); +//xhr.setRequestHeader("Content-Type", "text/json"); + try { + var post_payload = new Uint8Array($5); + + for (var iii = 0; iii < $5; iii++) { + post_payload[iii] = Module.HEAPU8[iii + $4]; + } + xhr.send(post_payload); +console.log(xhr.getResponseHeader("ETAG")); + } catch { + return 0; + } + if (xhr.status >= 400) return 0; + var uInt8Array = Uint8Array.from(Array.from(xhr.getResponseHeader("Etag")).map(letter => letter.charCodeAt(0))); + + var len = uInt8Array.byteLength; + var fileOnWasmHeap = _malloc(len + 4); + + var properArray = new Uint8Array(uInt8Array); + + for (var iii = 0; iii < len; iii++) { + Module.HEAPU8[iii + fileOnWasmHeap + 4] = properArray[iii]; + } + var LEN123 = new Uint8Array(4); + LEN123[0] = len % 256; + len -= LEN123[0]; + len /= 256; + LEN123[1] = len % 256; + len -= LEN123[1]; + len /= 256; + LEN123[2] = len % 256; + len -= LEN123[2]; + len /= 256; + LEN123[3] = len % 256; + len -= LEN123[3]; + len /= 256; + Module.HEAPU8.set(LEN123, fileOnWasmHeap); + return fileOnWasmHeap; + }, + path.c_str(), n, z, "PUT", payload, buffer_length); + // clang-format on + + free(payload); + + i = 0; + for (auto h : info.headers) { + free(z[i]); + i++; + free(z[i]); + i++; + } + free(z); + + if (!exe) { + res = make_uniq(HTTPStatusCode::NotFound_404); + res->reason = "Please consult the browser console for details, might be potentially a CORS error"; + } else { + res = duckdb::make_uniq(HTTPStatusCode::OK_200); + uint64_t LEN = 0; + LEN *= 256; + LEN += ((uint8_t *)exe)[3]; + LEN *= 256; + LEN += ((uint8_t *)exe)[2]; + LEN *= 256; + LEN += ((uint8_t *)exe)[1]; + LEN *= 256; + LEN += ((uint8_t *)exe)[0]; + res->headers.Insert("ETag", string(exe + 4, LEN)); + + // info.buffer_out += string(exe + 4, LEN); + + free(exe); + } + + return res; + } unique_ptr Delete(DeleteRequestInfo &info) override { return nullptr; } private: