diff --git a/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp b/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp index d0220d16..bac1f90f 100644 --- a/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp +++ b/Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp @@ -121,7 +121,8 @@ namespace Babylon::Polyfills::Internal { if (m_request.ResponseType() == UrlLib::UrlResponseType::String) { - return Napi::Value::From(Env(), m_request.ResponseString().data()); + const std::string_view responseString{m_request.ResponseString()}; + return Napi::String::New(Env(), responseString.data(), responseString.size()); } else { @@ -134,7 +135,12 @@ namespace Babylon::Polyfills::Internal Napi::Value XMLHttpRequest::GetResponseText(const Napi::CallbackInfo&) { - return Napi::Value::From(Env(), m_request.ResponseString().data()); + // The body may legitimately contain embedded nulls: Emscripten's EXPORT_ES6 output, for + // example, inlines the .wasm payload as a JavaScript string literal. Passing .data() + // alone would hand a const char* to Napi and truncate at the first null, so the length + // has to be supplied explicitly. + const std::string_view responseString{m_request.ResponseString()}; + return Napi::String::New(Env(), responseString.data(), responseString.size()); } Napi::Value XMLHttpRequest::GetResponseType(const Napi::CallbackInfo&) diff --git a/Tests/UnitTests/Assets/embedded_nulls.txt b/Tests/UnitTests/Assets/embedded_nulls.txt new file mode 100644 index 00000000..2e643b32 Binary files /dev/null and b/Tests/UnitTests/Assets/embedded_nulls.txt differ diff --git a/Tests/UnitTests/Scripts/tests.ts b/Tests/UnitTests/Scripts/tests.ts index 1dc2aa4c..fbee192a 100644 --- a/Tests/UnitTests/Scripts/tests.ts +++ b/Tests/UnitTests/Scripts/tests.ts @@ -291,6 +291,14 @@ describe("XMLHTTPRequest", function () { const vertexCount = parseInt(/element vertex (\d+)\n/.exec(header)![1]); expect(vertexCount).to.equal(18713); }); + + it("should not truncate responseText or response at an embedded null byte", async function () { + const xhr = await createRequest("GET", "app:///Assets/embedded_nulls.txt"); + expect(xhr.status).to.equal(200); + expect(xhr.responseText).to.equal("start\0middle\0end"); + expect(xhr.responseText.length).to.equal(16); + expect(xhr.response).to.equal(xhr.responseText); + }); }); describe("fetch", function () {