Skip to content

h1: incomplete request head grows the caller's buffer without bound #2

@mrrubinos

Description

@mrrubinos

nhttp_h1:parse_request_headers/2 and parse_request/2 only enforce max_header_size on completed header lines. When the input ends mid-line, the incomplete-tail clause returns {more, _} with no size check, so a peer that sends a header line that never terminates (no CRLF) makes the caller buffer indefinitely. Each new arrival also rescans the whole unparsed tail, so the same input is quadratic in CPU.

The chunked decoder has the same problem in two places:

  • an incomplete trailer section returns {more, _} regardless of max_header_size
  • the chunk-size line scan accepts arbitrarily long lines while waiting for CRLF

Reproduce

Opts = #{max_header_size => 1024},
Data = <<"GET / HTTP/1.1\r\nX-Endless: ", (binary:copy(<<"x">>, 1 bsl 20))/binary>>,
{more, _} = nhttp_h1:parse_request_headers(Data, Opts).
%% expected: {error, header_too_large}

Expected

With max_header_size set, an incomplete head should be rejected as header_too_large once the buffered input exceeds max_header_size plus a request-line allowance (8 KiB, since the request line is not counted by the per-line check). The same budget should bound incomplete chunked trailer sections, and chunk-size lines should be capped (1 KiB) and rejected as invalid_chunk_size. RFC 9112 permits rejecting lines longer than the server is willing to buffer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions