Skip to content

Incorrect validation of non-utf8 characters in setHeader function #50213

Open
@jk1z

Description

@jk1z

Version

>=18.16.0

Platform

All

Subsystem

_http_common.js

What steps will reproduce the bug?

NodeJS is actively preventing characters in the extended ascii table from passing in as a string.
Evidence: When using writeHead() with headers parameter. It throws an ERR_INVALID_CHAR error.

However, when we use setHeader(). It does not validate the characters passed in.

const { createServer } = require("http");

const requestListener = function (req, res) {
    res.setHeader("Content-Length", "310");
    res.setHeader("Content-Disposition", `attachment; filename="ÇÕÑêÿ Island"`);
    // res.writeHead(200, [
    //     "Content-Length", "310",
    //     "Content-Disposition", `attachment; filename="ÇÕÑêÿ Island"`
    // ]);
    res.end();
};
const server = createServer(requestListener);
server.listen(8080);

How often does it reproduce? Is there a required condition?

It always occurs when using the setHeader() function with latin1 (extended ASCII table)

What is the expected behavior? Why is that the expected behavior?

The expected behaviour would be setHeader() function rejects non-ascii string.

Source: According to this PR http: unify header treatment by marco-ippolito · Pull Request #46528 · nodejs/node. Header value validation always rejects non-ascii characters. To support latin1 in the Content-Disposition HTTP header, the server has to parse the string as a binary string (within the ascii range). Just like what's written in the test https://github.com/nodejs/node/blob/main/test/parallel/test-http-server-non-utf8-header.js

What do you see instead?

setHeader() does not reject non-ascii string. Content-Disposition header got parsed incorrectly.

For example: An input of attachment; filename="ÇÕÑêÿ Island" becomes attachment; filename="ýýýýý Island"

Additional information

Through debugging, I found it really strange that checkInvalidHeaderChar() is behaving weirdly with the header value passed in from the writeHead() and setHeader(). writeHead() passes a string buffer which gets regex'ed/rejected correctly but setHeader() passes a plain string and it does not trigger the regex.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions