Skip to content

http: create response.overwriteHead() for things like stream piping error handlingΒ #52026

@kwpartist

Description

@kwpartist

What is the problem this feature will solve?

Problem created after fix: #45508 to throw error on multiple writeHead calls (I personally updated to 20 LTS from 14 LTS recently).

This creates a new problem when wanting to pipe read streams to http response streams as you cannot overwrite the header response code upon a file read stream error event to reflect the file error (ENOENT, EISDIR, etc..) to give appropriate http responses (404, 500, etc.).

Example that will now break:

response.writeHead(200, {"Content-Type":"..."}); // HEADER STUFF
readStream.pipe(response);

readStream.on('error', function(error){
    if(error.code == 'ENOENT')
    {
        response.writeHead(404, {"Content-Type":"text/plain; charset=utf-8"});
        response.end('404 NOT FOUND', 'utf-8');
    }
    else if(error.code == 'EISDIR')
    {
        response.writeHead(403, {"Content-Type":"text/plain; charset=utf-8"});
        response.end('403 FORBIDDEN', 'utf-8');
    }
    else 
    {
        response.writeHead(500, {"Content-Type":"text/plain; charset=utf-8"});
        response.end('500 SERVER ERROR', 'utf-8');
    }
});

What is the feature you are proposing to solve the problem?

An identical function without the #45508 changes:

if (this._header) {
    throw new ERR_HTTP_HEADERS_SENT('write');
}

Proposing http response.overwriteHead() for at least 20 LTS +

Example:

response.writeHead(200, {"Content-Type":"..."}); // HEADER STUFF
readStream.pipe(response);

readStream.on('error', function(error){
    if(error.code == 'ENOENT')
    {
        response.overwriteHead(404, {"Content-Type":"text/plain; charset=utf-8"});
        response.end('404 NOT FOUND', 'utf-8');
    }
    else if(error.code == 'EISDIR')
    {
        response.overwriteHead(403, {"Content-Type":"text/plain; charset=utf-8"});
        response.end('403 FORBIDDEN', 'utf-8');
    }
    else 
    {
        response.overwriteHead(500, {"Content-Type":"text/plain; charset=utf-8"});
        response.end('500 SERVER ERROR', 'utf-8');
    }
});

What alternatives have you considered?

I would pull and go through the process of trying to add this feature myself if I knew the pulling process well. I'm new to GitHub I've always stayed solo in development so excuse my noob-ness. I understand it's much volunteered.

I've considered breaking apart the piping for fine grain control but that defeats the purpose of piping to begin with and for others unaware it may introduce memory leaks if they don't close both read and write streams on these kinds of error events properly.

(EDIT)

If calling writeHead multiple times is not detrimental to anything other than the effect of overwriting (which needs confirming), then perhaps the documentation could better reflect that instead of throwing an error on multiple use to simplify this solution. (Issue genesis: #36721)

Current docs:
"This method must only be called once on a message and it must be called before response.end() is called..."

Re-worded to something like:
"This function must be called before response.end() is called.

If response.write() or response.end() are called before this, the implicit/mutable headers will be calculated first.

This function will directly write the supplied header values onto the network channel and merge any headers supplied with response.setHeader() beforehand. Headers supplied to this function will have priority over response.setHeader() headers.

If response.setHeader() is never called before this, response.getHeader() will not yield the expected results as internal caching is bypassed. Use response.setHeader() if progressive population, future retrieval or modification is desired.

Caution multiple calls of this function on the same response, as these calls will overwrite the current header values and response code on the network channel..."

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestIssues that request new features to be added to Node.js.httpIssues or PRs related to the http subsystem.stale

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions