Skip to content

Canonicalization drops a trailing empty query, so /p? and /p produce the same signature base #979

Description

@KonstantinMirin

Found while vendoring the complete AdCP 3.1.1 request-signing vector set (#975). Reproduction is a canonicalization.json case, currently strict-xfail.

Problem

A URL with a trailing ? and an empty query loses the ? during canonicalization.

case input expected @target-uri actual
trailing-empty-query-preserved https://seller.example.com/p? https://seller.example.com/p? https://seller.example.com/p

Cause

canonicalize_target_uri() round-trips through urlsplit / urlunsplit:

return urlunsplit((scheme, netloc, path, parts.query, ""))

urlsplit maps both /p? and /p to query == "", and urlunsplit emits no ? for an empty query. The distinction between "empty query" and "no query" is erased, so the two URLs canonicalize identically.

Why it matters

RFC 9421 §2.2.2 derives @target-uri from the absolute request target, where /p? and /p are distinct. A counterparty that preserves the trailing ? computes a different signature base than the SDK, and the signature fails to verify with no diagnostic beyond request_signature_invalid — the failure mode canonicalization.json exists to catch early.

Narrow, but it is a real divergence and the fix is contained: preserve the ? when the original URL had one, e.g. by checking for "?" in url after the authority rather than relying on urlunsplit to round-trip it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions