From 4ebd969c6968df20db95431dcf53558f7335344d Mon Sep 17 00:00:00 2001 From: Gary Hsu Date: Wed, 18 Jan 2023 17:52:46 -0800 Subject: [PATCH] Update to latest UrlLib/XMLHttpRequest from BabylonNative --- CMakeLists.txt | 2 +- .../XMLHttpRequest/Source/XMLHttpRequest.cpp | 48 ++++--------------- Tests/UnitTests/index.js | 23 ++++----- 3 files changed, 20 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4eb1c09d..a6dad2f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,7 @@ if(NOT TARGET UrlLib AND JSRUNTIMEHOST_POLYFILL_XMLHTTPREQUEST) FetchContent_Declare( UrlLib GIT_REPOSITORY https://github.com/BabylonJS/UrlLib.git - GIT_TAG 0007501304a710f14626f34a73c05bcb371de92f) + GIT_TAG 558af491b2ec413d2eefefef1629dc652a5f9a04) message(STATUS "Fetching UrlLib") FetchContent_MakeAvailable(UrlLib) diff --git a/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp b/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp index 12ccde81..3e06d95f 100644 --- a/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp +++ b/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp @@ -3,29 +3,6 @@ #include #include -bool IsHexChar(const char& c) -{ - return ((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9')); -} - -std::string EncodePercent(const std::string& input) -{ - std::ostringstream encoded; - for (auto i = input.begin(), e = input.end(); i != e; ++i) - { - encoded << *i; - if (*i == '%') - { - if (std::distance(i, e) >= 2 && !(IsHexChar(*(i + 1)) && IsHexChar(*(i + 2)))) - { - // If a percent character is not followed by two hex characters, we should encode it - encoded << "25"; - } - } - } - return encoded.str(); -} - namespace Babylon::Polyfills::Internal { namespace @@ -210,28 +187,22 @@ namespace Babylon::Polyfills::Internal void XMLHttpRequest::Open(const Napi::CallbackInfo& info) { + const auto inputURL = info[1].As(); + try { - // printfs for debugging CI, will be removed - const auto inputURL{info[1].As()}; - // If the input URL contains any true % characters, encode them as %25 - const auto encodedPercentURL{Napi::String::New(info.Env(), EncodePercent(inputURL.Utf8Value()))}; - // Decode the input URL to get a completely unencoded URL - const auto decodedURL{info.Env().Global().Get("decodeURI").As().Call({encodedPercentURL})}; - // Re-encode the URL to make sure that every illegal character is encoded - const auto finalURL{info.Env().Global().Get("encodeURI").As().Call({decodedURL}).As()}; - m_request.Open(MethodType::StringToEnum(info[0].As().Utf8Value()), finalURL.Utf8Value()); - SetReadyState(ReadyState::Opened); + m_request.Open(MethodType::StringToEnum(info[0].As().Utf8Value()), inputURL); } catch (const std::exception& e) { - // If we have a parse error, catch and rethrow to JavaScript - throw Napi::Error::New(info.Env(), std::string{"Error parsing URL scheme: "} + e.what()); + throw Napi::Error::New(info.Env(), std::string{"Error opening URL: "} + e.what()); } catch (...) { - throw Napi::Error::New(info.Env(), "Unknown error parsing URL scheme"); + throw Napi::Error::New(info.Env(), "Unknown error opening URL"); } + + SetReadyState(ReadyState::Opened); } void XMLHttpRequest::Send(const Napi::CallbackInfo& info) @@ -239,9 +210,10 @@ namespace Babylon::Polyfills::Internal if (m_readyState != ReadyState::Opened) { throw Napi::Error::New(info.Env(), "XMLHttpRequest must be opened before it can be sent"); - return; } - m_request.SendAsync().then(m_runtimeScheduler, arcana::cancellation::none(), [env{info.Env()}, this](arcana::expected result) { + + m_request.SendAsync().then(m_runtimeScheduler, arcana::cancellation::none(), [env{info.Env()}, this](arcana::expected result) + { if (result.has_error()) { Napi::Error::New(env, result.error()).ThrowAsJavaScriptException(); diff --git a/Tests/UnitTests/index.js b/Tests/UnitTests/index.js index 13e7bf15..49f3052a 100644 --- a/Tests/UnitTests/index.js +++ b/Tests/UnitTests/index.js @@ -32,37 +32,32 @@ describe("XMLHTTPRequest", function () { this.timeout(0); it("should have readyState=4 when load ends", async function () { - const xhr = await createRequest("GET", "https://babylonjs.com"); + const xhr = await createRequest("GET", "https://httpbin.org/get"); expect(xhr.readyState).to.equal(4); }); it("should have status=200 for a file that exists", async function () { - const xhr = await createRequest("GET", "https://babylonjs.com"); + const xhr = await createRequest("GET", "https://httpbin.org/status/200"); expect(xhr.status).to.equal(200); }); - it("should load unescaped URLs", async function () { - const xhr = await createRequest("GET", "https://github.com/BabylonJS/Assets/raw/master/meshes/στρογγυλεμένος % κύβος.glb"); + it("should load URLs with escaped unicode characters", async function () { + const xhr = await createRequest("GET", "https://raw.githubusercontent.com/BabylonJS/Assets/master/meshes/%CF%83%CF%84%CF%81%CE%BF%CE%B3%CE%B3%CF%85%CE%BB%CE%B5%CE%BC%CE%AD%CE%BD%CE%BF%CF%82%20%25%20%CE%BA%CF%8D%CE%B2%CE%BF%CF%82.glb"); expect(xhr.status).to.equal(200); }); - it("should load partially unescaped URLs", async function () { - const xhr = await createRequest("GET", "https://github.com/BabylonJS/Assets/raw/master/meshes/στρογγυλεμένος%20%%20κύβος.glb"); + it("should load URLs with unescaped unicode characters", async function () { + const xhr = await createRequest("GET", "https://raw.githubusercontent.com/BabylonJS/Assets/master/meshes/στρογγυλεμένος%20%25%20κύβος.glb"); expect(xhr.status).to.equal(200); }); - it("should load escaped URLs", async function () { - const xhr = await createRequest("GET", "https://github.com/BabylonJS/Assets/raw/master/meshes/%CF%83%CF%84%CF%81%CE%BF%CE%B3%CE%B3%CF%85%CE%BB%CE%B5%CE%BC%CE%AD%CE%BD%CE%BF%CF%82%20%25%20%CE%BA%CF%8D%CE%B2%CE%BF%CF%82.glb"); - expect(xhr.status).to.equal(200); - }); - - it("should load URLs with unescaped %s", async function () { - const xhr = await createRequest("GET", "https://github.com/BabylonJS/Assets/raw/master/meshes/%CF%83%CF%84%CF%81%CE%BF%CE%B3%CE%B3%CF%85%CE%BB%CE%B5%CE%BC%CE%AD%CE%BD%CE%BF%CF%82%20%%20%CE%BA%CF%8D%CE%B2%CE%BF%CF%82.glb"); + it("should load URLs with unescaped unicode characters and spaces", async function () { + const xhr = await createRequest("GET", "https://raw.githubusercontent.com/BabylonJS/Assets/master/meshes/στρογγυλεμένος %25 κύβος.glb"); expect(xhr.status).to.equal(200); }); it("should have status=404 for a file that does not exist", async function () { - const xhr = await createRequest("GET", "https://babylonjs.com/invalid"); + const xhr = await createRequest("GET", "https://httpbin.org/status/404"); expect(xhr.status).to.equal(404); });