[engine.io-client] The Node.js cookie jar lets Expires override Max-Age

未关闭 适合新手
#5,590 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 2 天内回复

还没有人认领这个 Issue。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
88/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃

调研方向

从 packages/engine.io-client/lib/globals.node.ts 中的 parse() 和 packages/engine.io-client/test/node.js 中的 “should parse a complex set-cookie header” 测试开始。检查 Expires 和 Max-Age 同时出现时的处理方式,然后更新测试,覆盖两种头部属性顺序及预期的优先级。当 Max-Age 无论属性顺序如何都决定 cookie 的过期时间,且现有解析测试通过时,任务即完成。

由索引模型根据 Issue 内容生成。

描述

Describe the bug

With withCredentials: true in Node.js, the cookie jar of engine.io-client applies the Expires and Max-Age attributes in the order they appear in the Set-Cookie header, so whichever comes last wins. According to RFC 6265 (section 5.3, step 3) and MDN, Max-Age takes precedence over Expires when both are present.

Two consequences:

  • A cookie like sid=abc; Max-Age=3600; Path=/; Expires=<date> (which is what Express sends for res.cookie("sid", "abc", { maxAge: 3600000 })) is dropped right away when the client clock is ahead of the server clock by more than the max age, because the Expires date is already in the past for the client. With Max-Age taking precedence, the cookie would be kept for one hour.
  • A deletion like sid=abc; Max-Age=0; Expires=<future date> is ignored, and the cookie keeps being sent.

The existing test "should parse a complex set-cookie header" in packages/engine.io-client/test/node.js also expects the Expires date for a header that carries Max-Age=1000 before Expires.

To Reproduce

Engine.IO server version: 6.6.11

Engine.IO client version: 6.6.8 (also reproduced on main at e94e021)

Server and client

const { createServer } = require("http");
const { attach } = require("engine.io");
const { Socket } = require("engine.io-client");

const setCookie = process.argv[2];

const httpServer = createServer();
const engine = attach(httpServer);

httpServer.prependListener("request", (req) => {
  if (req.url.includes("sid=")) {
    console.log("cookie header on a later request:", req.headers.cookie);
  }
});

engine.on("initial_headers", (headers) => {
  headers["set-cookie"] = [setCookie];
});

httpServer.listen(3000, () => {
  const socket = new Socket("http://localhost:3000", {
    transports: ["polling"],
    withCredentials: true,
  });
  socket.on("open", () => {
    setTimeout(() => {
      socket.close();
      engine.close();
      httpServer.close();
    }, 200);
  });
});

Results:

Set-Cookie sent with the handshake cookie header on the next request
sid=abc; Max-Age=3600; Path=/ sid=abc
sid=abc; Max-Age=3600; Path=/; Expires=<one minute ago> none
sid=abc; Max-Age=0; Path=/; Expires=Fri, 01 Jan 2100 00:00:00 GMT sid=abc

Expected behavior

When a Set-Cookie header has both attributes, the expiry comes from Max-Age, whatever their order: the second cookie is kept for one hour and the third one is removed.

Platform:

  • Device: desktop
  • OS: Windows, Node.js 24.22.1 (the cookie jar is only used in Node.js)

Additional context

The parsing happens in parse() in packages/engine.io-client/lib/globals.node.ts. I'm happy to send a PR with a test.

AI-assisted: found and reproduced with an AI coding agent; the example above was run locally.

主要语言
TypeScript
星标
63.2k
派生
10.2k
平均合并
6 天 4 小时
30 天内合并 PR
6

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

socketio/socket.io 的其他 Issue

查看 socketio/socket.io 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。