Skip to content

Commit

Permalink
test: verify request payload is uploaded consistently
Browse files Browse the repository at this point in the history
Node.js seems to change how it is uploaded based on the method,
but HTTP doesn't make any distinction.

Co-authored-by: Austin Wright <[email protected]>
Co-authored-by: Lenvin Gonsalves <[email protected]>
Co-authored-by: Antoine du Hamel <[email protected]>
  • Loading branch information
3 people committed May 11, 2024
1 parent ff7910b commit 1f659d4
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 0 deletions.
51 changes: 51 additions & 0 deletions test/known_issues/test-http-clientrequest-end-contentlength.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'use strict';

// Refs: https://github.com/nodejs/node/pull/34066

const common = require('../common');
const assert = require('assert');
const http = require('http');

// Test that ClientRequest#end with default options
// computes and sends a Content-Length header
const upload = 'PUT / HTTP/1.1\r\n\r\n';
const response = 'content-length: 19\r\n';

// Test that the upload is properly received with the same headers,
// regardless of request method
const methods = [ 'GET', 'HEAD', 'DELETE', 'POST', 'PATCH', 'PUT', 'OPTIONS' ];

const server = http.createServer(common.mustCall(function(req, res) {
req.on('data', function(chunk) {
assert.strictEqual(chunk, Buffer.from(upload));
});
res.setHeader('Content-Type', 'text/plain');
let payload = `${req.method}\r\n`;
for (let i = 0; i < req.rawHeaders.length; i += 2) {
// Ignore a couple headers that may vary
if (req.rawHeaders[i].toLowerCase() === 'host') continue;
if (req.rawHeaders[i].toLowerCase() === 'connection') continue;
payload += `${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`;
}
res.end(payload);
}), methods.length);

server.listen(0, function tryNextRequest() {
const method = methods.pop();
if (method === undefined) return;
const port = server.address().port;
const req = http.request({ method, port }, function(res) {
const chunks = [];
res.on('data', function(chunk) {
chunks.push(chunk);
});
res.on('end', function() {
const received = Buffer.concat(chunks).toString();
const expected = method.toLowerCase() + '\r\n' + response;
assert.strictEqual(received.toLowerCase(), expected);
tryNextRequest();
});
});

req.end(upload);
}).unref();
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict';

// Refs: https://github.com/nodejs/node/pull/34066

const common = require('../common');
const assert = require('assert');
const http = require('http');

// Test that ClientRequest#end with default options
// and empty payload sends neither Content-Length nor Transfer-Encoding.
// Sending Content-Length: 0 would be acceptable, but is unnecessary.
const upload = 'PUT / HTTP/1.1\r\n\r\n';
const response = '';

// Test that the upload is properly received with the same headers,
// regardless of request method.
const methods = [ 'GET', 'HEAD', 'DELETE', 'POST', 'PATCH', 'PUT', 'OPTIONS' ];

const server = http.createServer(common.mustCall(function(req, res) {
req.on('data', function(chunk) {
assert.strictEqual(chunk.toString(), upload);
});
res.setHeader('Content-Type', 'text/plain');
res.write(`${req.method}\r\n`);
for (let i = 0; i < req.rawHeaders.length; i += 2) {
// Ignore a couple headers that may vary
if (req.rawHeaders[i].toLowerCase() === 'host') continue;
if (req.rawHeaders[i].toLowerCase() === 'connection') continue;
res.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`);
}
res.end();
}), methods.length);

server.listen(0, function tryNextRequest() {
const method = methods.pop();
if (method === undefined) return;
const port = server.address().port;
const req = http.request({ method, port }, function(res) {
const chunks = [];
res.on('data', function(chunk) {
chunks.push(chunk);
});
res.on('end', function() {
const received = Buffer.concat(chunks).toString();
const expected = method.toLowerCase() + '\r\n' + response;
assert.strictEqual(received.toLowerCase(), expected);
tryNextRequest();
});
});

req.end();
}).unref();
52 changes: 52 additions & 0 deletions test/known_issues/test-http-clientrequest-write-chunked.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict';

// Refs: https://github.com/nodejs/node/pull/34066

const common = require('../common');
const assert = require('assert');
const http = require('http');

// Test that ClientRequest#write with default options
// uses a chunked Transfer-Encoding
const upload = 'PUT / HTTP/1.1\r\n\r\n';
const response = 'transfer-encoding: chunked\r\n';

// Test that the upload is properly received with the same headers,
// regardless of request method.
const methods = [ 'GET', 'HEAD', 'DELETE', 'POST', 'PATCH', 'PUT', 'OPTIONS' ];

const server = http.createServer(common.mustCall(function(req, res) {
req.on('data', function(chunk) {
assert.strictEqual(chunk.toString(), upload);
});
res.setHeader('Content-Type', 'text/plain');
res.write(`${req.method}\r\n`);
for (let i = 0; i < req.rawHeaders.length; i += 2) {
// Ignore a couple headers that may vary
if (req.rawHeaders[i].toLowerCase() === 'host') continue;
if (req.rawHeaders[i].toLowerCase() === 'connection') continue;
res.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`);
}
res.end();
}), methods.length);

server.listen(0, function tryNextRequest() {
const method = methods.pop();
if (method === undefined) return;
const port = server.address().port;
const req = http.request({ method, port }, function(res) {
const chunks = [];
res.on('data', function(chunk) {
chunks.push(chunk);
});
res.on('end', function() {
const received = Buffer.concat(chunks).toString();
const expected = method.toLowerCase() + '\r\n' + response;
assert.strictEqual(received.toLowerCase(), expected);
tryNextRequest();
});
});

req.write(upload);
req.end();
}).unref();
30 changes: 30 additions & 0 deletions test/parallel/test-http-request-method-delete-payload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';
const common = require('../common');

const assert = require('assert');
const http = require('http');

const data = 'PUT / HTTP/1.1\r\n\r\n';

const server = http.createServer(common.mustCall(function(req, res) {
req.on('data', function(chunk) {
assert.strictEqual(chunk, Buffer.from(data));
});
res.setHeader('Content-Type', 'text/plain');
for (let i = 0; i < req.rawHeaders.length; i += 2) {
if (req.rawHeaders[i].toLowerCase() === 'host') continue;
if (req.rawHeaders[i].toLowerCase() === 'connection') continue;
res.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`);
}
res.end();
})).unref();

server.listen(0, common.mustCall(() => {
const port = server.address().port;
const req = http.request({ method: 'DELETE', port }, function(res) {
res.resume();
});

req.write(data);
req.end();
}));

0 comments on commit 1f659d4

Please sign in to comment.