From 350be3976ad475bc591e97108f7dc11b6fec4bde Mon Sep 17 00:00:00 2001 From: Tobias Kellner Date: Fri, 15 May 2026 12:57:38 +0200 Subject: [PATCH 1/2] feat: Support sending Blob (and File) instances --- lib/XMLHttpRequest.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/XMLHttpRequest.js b/lib/XMLHttpRequest.js index f37edf0..0ae9da6 100644 --- a/lib/XMLHttpRequest.js +++ b/lib/XMLHttpRequest.js @@ -14,6 +14,7 @@ var fs = require('fs'); var os = require('os'); var path = require('path'); +var stream = require('stream'); var spawn = require('child_process').spawn; /** * Constants @@ -727,7 +728,7 @@ function XMLHttpRequest(opts) { if (settings.method === "GET" || settings.method === "HEAD") { data = null; } else if (data) { - headers["Content-Length"] = Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data); + headers["Content-Length"] = Buffer.isBuffer(data) ? data.length : (data instanceof Blob ? data.size : Buffer.byteLength(data)); var headersKeys = Object.keys(headers); if (!headersKeys.some(function (h) { return h.toLowerCase() === 'content-type' })) { @@ -881,6 +882,9 @@ function XMLHttpRequest(opts) { // Node 0.4 and later won't accept empty data. Make sure it's needed. if (data) { + if (data instanceof Blob) { + return stream.Readable.fromWeb(data.stream()).pipe(request); + } request.write(data); } From 6f8206c343293fbea7234f8cef9a321287b01cc1 Mon Sep 17 00:00:00 2001 From: Tobias Kellner Date: Fri, 15 May 2026 18:59:24 +0200 Subject: [PATCH 2/2] test: Add data sending tests --- tests/test-send-data.js | 88 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 tests/test-send-data.js diff --git a/tests/test-send-data.js b/tests/test-send-data.js new file mode 100644 index 0000000..1bf6679 --- /dev/null +++ b/tests/test-send-data.js @@ -0,0 +1,88 @@ +var assert = require("assert") + , XMLHttpRequest = require("../lib/XMLHttpRequest").XMLHttpRequest + , http = require("http") + , xhr; + +// Test server +var server = http.createServer(function (req, res) { + if (req.method != "POST") { + res.writeHead(405, {"Content-Type": "text/plain"}); + res.end("Method not allowed"); + return; + } + const headers = {"Content-Type": "application/octet-stream"}; + if (req.headers["content-length"]) { + headers["Content-Length"] = req.headers["content-length"]; + } + res.writeHead(200, headers); + req.pipe(res); +}).listen(8000); + +// Test wrong method +xhr = new XMLHttpRequest(); + +var tests = ['WRONG_METHOD','SEND_TEXT','SEND_BUFFER','SEND_TYPEDARRAY','SEND_BLOB','SEND_FILE']; +var currentTest = 0; + +xhr.onreadystatechange = function() { + if (this.readyState == 4) { + switch (tests[currentTest]) { + case 'WRONG_METHOD': + assert.equal(this.status, 405); + + ++currentTest; + xhr.open("POST", url); + xhr.send("Hello World"); + return; + + case 'SEND_TEXT': + assert.equal(this.status, 200); + assert.equal(this.responseText, "Hello World"); + + ++currentTest; + xhr.open("POST", url); + xhr.send(Buffer.from("Hello World")); + return; + + case 'SEND_BUFFER': + assert.equal(this.status, 200); + assert.equal(this.responseText, "Hello World"); + + ++currentTest; + xhr.open("POST", url); + xhr.send(new Uint8Array(Buffer.from("Hello World"))); + return; + + case 'SEND_TYPEDARRAY': + assert.equal(this.status, 200); + assert.equal(this.responseText, "Hello World"); + + ++currentTest; + xhr.open("POST", url); + xhr.send(new Blob([Buffer.from("Hello World")])); + return; + + case 'SEND_BLOB': + assert.equal(this.status, 200); + assert.equal(this.responseText, "Hello World"); + + ++currentTest; + xhr.open("POST", url); + xhr.send(new File([Buffer.from("Hello World")], 'test.txt')); + return; + + case 'SEND_FILE': + assert.equal(this.status, 200); + assert.equal(this.responseText, "Hello World"); + server.close(); + return; + + default: + assert.fail('Unknown state'); + } + } +}; + +var url = "http://localhost:8000/"; +xhr.open("GET", url); +xhr.send();