Skip to content

HTTP header values are written using the MetadataValue debug representation (strings are quoted) #51

Description

@feO2x

Problem

When metadata annotated with MetadataValueAnnotation.SerializeInHttpHeader reaches the HTTP response without a registered HttpHeaderConverter, the emitted header value is the debug representation of the MetadataValue rather than its HTTP header representation.

For a string value, this means the value is wrapped in double quotes:

Cache-Control: "no-store"

instead of

Cache-Control: no-store

Cause

DefaultHttpHeaderConversionService.PrepareHttpHeader falls back to MetadataValue.ToString():

https://github.com/feO2x/Light.PortableResults/blob/main/src/Light.PortableResults/Http/Writing/Headers/DefaultHttpHeaderConversionService.cs#L37

MetadataValue.ToString() is a JSON-ish debug representation:

  • MetadataKind.String"\"{value}\"" (quoted)
  • MetadataKind.Array"[a, b]" (single bracketed, comma-space-joined string)

MetadataValue.FromDecimal stores its value as MetadataKind.String, so decimals are affected as well.

Reproduction

var service = new DefaultHttpHeaderConversionService(
    new Dictionary<string, HttpHeaderConverter>().ToFrozenDictionary()
);
var header = service.PrepareHttpHeader(
    "Cache-Control",
    MetadataValue.FromString("no-store", MetadataValueAnnotation.SerializeInHttpHeader)
);
// header.Value is "no-store" (with literal quote characters), expected: no-store

Impact

  • String and decimal header metadata is written with literal quote characters. Cache-Control, Location, ETag, correlation IDs, etc. are corrupted for any client that does not strip quotes.
  • Array header metadata is written as one bracketed string instead of multiple header values.
  • Round-tripping is asymmetric: DefaultHttpHeaderParsingService parses header values into plain strings/primitives, so writing and re-reading a string metadata value does not yield the original value.

The bug is invisible in the current test suite because the existing coverage either registers a custom converter (bypassing the fallback) or uses an Int64 value, whose debug representation happens to be identical to its header representation.

Only the fallback path is affected. Applications that register a custom HttpHeaderConverter for the metadata key are unaffected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions