Skip to content

Custom content headers are set to HttpRequestMessage resulting in header value duplication #868

Description

@Prologh

Consider this tiny snippet:

var content = new StringContent("{}", Encoding.UTF8, MediaTypeNames.Application.Json);
content.Headers.Add("X-Content-Foo", "Bar");
var url = "http://localhost:5260/webhook"; // Replace with your listener
var response = await new FlurlRequest(url).PostAsync(content);

When executed the X-Content-Foo header gets added to underlying HttpRequestMessage
at this line as part of SendAsync() method:
https://github.com/tmenier/Flurl/blob/dev/src/Flurl.Http/FlurlClient.cs#L160

This in turn results in a HttpRequestMessage with X-Content-Foo header set both in content headers and request headers. The string representation gives a glimpse what's about to happen:

Image

Flow continues to HttpClient to finally land in HttpConnection which writes entries from both header collections:
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs#L375-L384

With Wireshark you can see raw HTTP message:

Image

Since we know from RFC 7230 that:

A recipient MAY combine multiple header fields with the same field name into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field value to the combined field value in order, separated by a comma.

On the recipient side, we end up with a HTTP request that has nasty, duplicated header value, combined with comma:

X-Content-Foo: Bar,Bar
Image

Quite unexpected. Took me a good while to figure this one out. Looks like a bug within the header synchronization logic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions