Skip to content

Send a User-Agent header on registry requests#753

Open
adityasingh2400 wants to merge 1 commit into
apple:mainfrom
adityasingh2400:registry-user-agent
Open

Send a User-Agent header on registry requests#753
adityasingh2400 wants to merge 1 commit into
apple:mainfrom
adityasingh2400:registry-user-agent

Conversation

@adityasingh2400
Copy link
Copy Markdown

@adityasingh2400 adityasingh2400 commented May 25, 2026

Registry requests built by RegistryClient go out without a User-Agent header. The central request() method constructs an HTTPClientRequest and only ever sets Authorization plus whatever caller headers are passed, and AsyncHTTPClient does not add a default User-Agent of its own. As a result every registry operation (manifest resolves, blob fetches, token exchanges, and pushes) is anonymous on the wire, which is what the issue reporter saw when proxying the traffic.

HTTP/1.1 only recommends User-Agent rather than requiring it, but in practice some registries and forward proxies reject, rate-limit, or otherwise mishandle requests that omit it, and operators rely on it for attribution and debugging.

The client already carries a clientID (containerization-registry-client by default), but it was only used as the OAuth client_id form field when fetching tokens, never as an HTTP header. This sets the User-Agent from clientID at the single point where requests are constructed, so it applies uniformly to every registry call including retries and token fetches. A caller that supplies its own User-Agent in the per-request headers still takes precedence, and no duplicate header is emitted.

Added unit tests in ContainerizationOCITests covering the default User-Agent, propagation of a custom clientID, caller override, and coexistence with other headers. With the header omitted the new tests fail (the header reads as empty); with the fix they pass. Verified locally with swift test --filter RegistryRequestHeaderTests -Xswiftc -warnings-as-errors.

Reported in apple/container#1583 (the registry client lives in this repository).

Registry requests built by RegistryClient went out without a User-Agent
header. The central request() method constructed an HTTPClientRequest and
only ever set Authorization plus any caller-supplied headers, and
AsyncHTTPClient does not add a default User-Agent of its own, so every
registry operation (manifest resolves, blob fetches, token exchanges, and
pushes) was anonymous on the wire.

HTTP/1.1 only recommends User-Agent rather than requiring it, but in
practice some registries and forward proxies reject, rate-limit, or
otherwise mishandle requests that omit it, and operators rely on it for
attribution and debugging.

The client already carried a clientID ("containerization-registry-client"
by default), but it was only used as the OAuth client_id form field when
fetching tokens, never as an HTTP header. Set the User-Agent from clientID
at the single point where requests are constructed so it applies uniformly
to every registry call including retries and token fetches. A caller that
passes its own User-Agent in the per-request headers still takes
precedence, and no duplicate header is emitted.
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.

1 participant