fake-timers: HTTP Date header time faking fails on Node 15.2.0 and later
HTTP Date header time is faked just fine up to Node v15.1.0 but fails with Node v15.2.0 or later.
- FakeTimers version :
6.0.1 - Environment :
Node v15.5.0 - Other libraries you are using:
assert,http
What did you expect to happen?
Should return HTTP Date header with fake time date: "Tue, 31 Dec 2013 23:59:59 GMT".
What actually happens
Instead returns HTTP Date header with current time, e.g. date: "Sun, 03 Jan 2021 17:22:52 GMT".
How to reproduce
Following is a minimal and complete mocha test case that reproduces the issue
import assert from "assert";
import http from "http";
import fake_timers from "@sinonjs/fake-timers";
describe("fake HTTP Date header time", function()
{
let clock;
let server;
before(function(done)
{
clock = fake_timers.install({now: Date.parse("2013-12-31 23:59:59.123Z")});
server = http.createServer((req, res) =>
{
req.on("data", () => void null);
req.on("end", () =>
{
res.writeHead(200);
res.end();
});
});
server.listen(8080, done);
});
after(function(done)
{
clock.uninstall();
server.close(done);
});
it("should fake HTTP Date header time", function(done)
{
const expectedHeaders =
{
"connection": "close",
"date": "Tue, 31 Dec 2013 23:59:59 GMT",
"transfer-encoding": "chunked"
};
const opts =
{
hostname: "localhost",
method: "GET",
path: "/",
port: 8080
};
const req = http.request(opts, (res) =>
{
const {headers, statusCode, statusMessage} = res;
res.on("data", () => void null);
res.on("end", () =>
{
assert.strictEqual(statusCode, 200);
assert.strictEqual(statusMessage, "OK");
assert.deepStrictEqual(headers, expectedHeaders);
done();
});
});
req.end();
});
});
Note
Starting with Node 15.2.0 http.js imports Date from primordials while Node 15.1.0 http.js just uses the global Date object.
About this issue
- Original URL
- State: open
- Created 3 years ago
- Reactions: 2
- Comments: 19 (15 by maintainers)
Let’s see how it goes https://github.com/nodejs/node/pull/40733
I quite like the flag idea as it gives to users the more power over how Node.js internals behave. What about a
--expose-primordialsflag? I think it would be easier to implement than a--no-primordialsone, and would allow users to define a specific behaviour for Node.js internals without even changing the globals.Thank you for trying hard to fix this & sorry for the late reply.
It seems the only way forward is to ignore the HTTP
Dateheader.IMHO it’s very sad that NodeJS seems to have sacrificed it’s original, simple and beautiful idea - i.e. expose the POSIX API to ECMAScript - to such an extent that AFAIK it now blatantly violates ECMAScript itself, in that modifying a prototype is not possible and/or does not result in the correct/expected behaviour; it instead has seemingly become a micro-optimization-driven mess at it’s very core.
This seems like something we cannot fix ourselves, @gorankarlic. Ref https://github.com/nodejs/node/pull/40733#issuecomment-1016522091
Aha … true. There are more ways to skin a cat, obviously 😄 We cannot have our cake, but we can probably eat it anyway, etc, etc…
With regards to the current http implementation, just
primordials.Date.prototype.toUTCString = function(){ return 'foo' }probably won’t fly. Nodehttpcaches a direct reference toDatePrototypeToUTCString, which I think defeats any attempt we could come up with that touchesDate.This target seems to move faster than we can come up with workarounds, so I am suspecting that even if we should start replacing all methods on the
Date.prototypethe amount of usecases we actually are able to support is rather slim. Don’t mind trying, though. Or rather, I don’t mind someone trying 😃I think the point of
-r internal/test/bindingis that it exposes aprimordialsglobal object with access to all the primordials (the locked object) - in our case we would need to check (and mock)globalThis.primordials.Datepresumably.Looking at the alternatives:
--no-primordialsflag or similar makingprimordialsnot return frozen instances.httpthat sets the server time used in headersresponse.sendDate = process.env.NODE_ENV === "production"or similarI would be in favour of (1) or (2) because (3) is not practical / does not address the issue and (4) is not quite good as implementation needs to carry test code.
Looking forward to reading your opinion on this.
That sounds reasonable, I think the current behaviour is expected but the use-case wasn’t considered and the breakage wasn’t expected.
Alternatives I can think of:
--no-primordialsflag or similar makingprimordialsnot return frozen instances.httpthat sets the server time used in headers