Skip to content

Reject a -H value with no colon - #81

Merged
korya merged 1 commit into
masterfrom
korya-fix-bare-header
Aug 8, 2026
Merged

Reject a -H value with no colon#81
korya merged 1 commit into
masterfrom
korya-fix-bare-header

Conversation

@korya

@korya korya commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Problem

-H 'X-Foo' sent a header with an empty value. curl reads the same input as "remove this header".

So one input, two tools, opposite outcomes — and the user reaching for curl's idiom got precisely the header they were trying to suppress, with nothing said about it:

$ http-assert -H 'BareHeader' http://…/echo
{"headers":{"Bareheader":[""], …}}          ← sent, empty-valued

A missing colon is also an everyday typo (-H 'X-Api-Key abc123'), and nothing flagged that either — the request just went out carrying a header named X-api-key abc123.

Solution

Both forms exit 71, and the message names the fix:

$ http-assert -H 'BareHeader' http://…/
Error: Invalid value for --header flag: "BareHeader" has no ':' separator;
write "BareHeader:" to send the header with an empty value

"no separator" on its own would leave the reader guessing whether an empty value is expressible at all. It is — -H 'X-Foo:' — and the error says so rather than making them find out.

A colon with nothing in front of it (-H ': value') is refused on the same grounds: it would have put a nameless header on the wire.

The check is at the call site, not in the parser

parseHeaderLine is shared with --assert-header, --assert-header-eq and --assert-header-missing, where a name on its own is not a mistake — it is how you assert the header is present. The parser is therefore right for one caller and wrong for the other, and only the caller knows which. Validating inside it would have broken three working flags to fix one; a test asserts all three still take a bare name.

Deliberately not adopted

curl's -H 'X-Foo;' spelling for "send this empty". X-Foo: already expresses it, and the semicolon would need a parsing rule of its own — today it just becomes part of the header name. Worth doing only alongside curl's removal semantics, which is a larger change than this.

Other Changes

TestKnownIssue33BareHeaderSendsEmptyValue is deleted, replaced by TestE2EHeaderRequiresASeparator.

One test documents a pflag quirk found while writing it: a solitary -H '' never reaches this program at all. GetStringArray reads the value back through pflag's own string form, in which a lone empty entry serialises to [] and parses back as no values. It is harmless — the invocation asks for no header and gets none — but it means -H '' alone cannot be rejected, while -H 'X-Ok: 1' -H '' is. Both are pinned, so the asymmetry is recorded rather than rediscovered.

The README gains one sentence in the request options, and the -H flag description now states the expected shape.

This is a breaking change for anyone using -H 'X-Foo' to send an empty-valued header. That spelling was ambiguous with curl's opposite meaning, which is the point of the issue; -H 'X-Foo:' is the unambiguous replacement and keeps working.

There are no screenshots because there is no rendered UI; this tool's user-visible surface is terminal output, shown inline above.

Closes #33

Related:

🤖 Generated with Claude Code

https://claude.ai/code/session_019EMMhgmTkbzAsmeNy97PrP

@korya
korya force-pushed the korya-fix-bool-assertion-negation branch from df3d77c to aacdc72 Compare August 8, 2026 13:15
@korya
korya force-pushed the korya-fix-bare-header branch from f058f11 to 8d2bc4a Compare August 8, 2026 13:15
Base automatically changed from korya-fix-bool-assertion-negation to master August 8, 2026 13:17
A -H value without a colon was sent as a header with an empty value:

    $ http-assert -H 'BareHeader' http://…/echo
    {"headers":{"Bareheader":[""], …}}

curl reads the same input as "remove this header". So the two tools take
one input and do opposite things with it, and a user reaching for curl's
idiom got the header they were trying to suppress -- with nothing said
about it. A missing colon is also an ordinary typo, and nothing flagged
that either.

Both forms now exit 71, and the message names the fix, since "no
separator" alone leaves the reader guessing whether an empty value can
be expressed at all:

    Invalid value for --header flag: "BareHeader" has no ':' separator;
    write "BareHeader:" to send the header with an empty value

A colon with nothing in front of it is refused on the same grounds; it
would have put a nameless header on the wire.

The check lives at the -H call site rather than inside parseHeaderLine,
which is shared with --assert-header, --assert-header-eq and
--assert-header-missing. There a name on its own is meaningful -- it
asserts the header is present -- so the parser is right for one caller
and wrong for the other, and only the caller can tell which.

curl's `-H 'X-Foo;'` spelling for an empty value is not adopted; `X-Foo:`
already expresses it, and the semicolon would need its own parsing rule.

Closes #33

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019EMMhgmTkbzAsmeNy97PrP
@korya
korya force-pushed the korya-fix-bare-header branch from 8d2bc4a to 77c0cc5 Compare August 8, 2026 13:20
@korya
korya marked this pull request as ready for review August 8, 2026 13:21
@korya
korya merged commit afc4f6a into master Aug 8, 2026
7 checks passed
@korya
korya deleted the korya-fix-bare-header branch August 8, 2026 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

-H with no colon sends an empty-valued header instead of being rejected

1 participant