Remove the redundant ErrorCoder type assertion and let the
recursive call handle unsupported error types.
Make all switch cases return explicitly.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Add missing mappings for ErrFailedPrecondition (412) and
ErrResourceExhausted (429), aligning with containerd's errhttp
implementation.
Add table-driven tests covering the errdefs mappings, gRPC and
distribution errors, and wrapped and joined errors.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Fill in the `Pattern` field on an `http.Request`. This field is filled
out by the standard library's `http.ServeMux` but is not filled in by
`gorilla/mux`. It is used to identify the matching route pattern and is
primarily used for traces and metrics to reduce cardinality on paths
that have variables in the routes so they can be recorded to traces.
The primary result of this change is that HTTP request traces will now
have the name `{method} {route}` rather than only `{method}` so an
invocation of `docker ps` will show up as `GET /containers/json` instead
of just `GET`.
Signed-off-by: Jonathan A. Sternberg <jonathan.sternberg@docker.com>
Add HostConfig.Umask and pass it to the OCI process spec for container
entrypoints, exec processes, and healthchecks.
Preserve the configured umask when exec user resolution reconstructs the
OCI User value, so runtimes receive it in the per-exec process spec.
Keep the field aligned with OCI's uint32 representation - raw JSON
clients need to use 18 for octal 0022 for example.
Co-authored-by: Youfu Zhang <zhangyoufu@gmail.com>
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Add a minimal README to document that it is a hard fork of the archived
golang/gddo repository, and add Go provenance to NOTICE.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Import golang/gddo at commit 20d68f94ee1f7547de2b1c68627253df20c8d45e
into daemon/server/httputils/internal/httputil.
The upstream repository was archived in 2021. Its history was filtered
to remove repository-specific CI and project files and rewritten to its
new location.
Strategy taken:
# install filter-repo (https://github.com/newren/git-filter-repo/blob/main/INSTALL.md)
brew install git-filter-repo
cd ~/projects
# create a temporary clone of gddo
git clone --single-branch --branch master --no-tags https://github.com/golang/gddo.git tmp_gddo
cd tmp_gddo
git rev-parse HEAD
20d68f94ee1f7547de2b1c68627253df20c8d45e
git filter-repo --analyze
git filter-repo \
--path httputil/negotiate.go \
--path httputil/negotiate_test.go \
--path httputil/header/header.go \
--path httputil/header/header_test.go \
--path LICENSE \
--path-rename httputil/:daemon/server/httputils/internal/httputil/ \
--path-rename LICENSE:daemon/server/httputils/internal/httputil/LICENSE \
--prune-empty always \
--prune-degenerate always
# go to the target github.com/moby/moby repository
cd ~/projects/moby
# create a branch to work with
git checkout -b import_gddo
# add the temporary repository as an upstream and make sure it's up-to-date
git remote add tmp_gddo ~/projects/tmp_gddo
git fetch --no-tags tmp_gddo master
# merge the upstream code
git merge --allow-unrelated-histories --no-ff --signoff -S tmp_gddo/master
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Add a small wrapper around gddo's NegotiateContentEncoding utility
with a signature tailored to our use, accepting just the request
headers instead of the whole request.
This keeps content-encoding negotiation behind an internal API,
similar to the existing contenttype package, and prepares for
internalising the gddo implementation without changing callers.
Add tests covering explicit encodings, wildcard matching, quality
values, identity encoding, and the case where no encoding is
acceptable.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Select the output stream before constructing the log message, and skip
messages for disabled or unknown streams immediately.
This avoids timestamp formatting, attribute sorting and escaping, and buffer
allocation for messages that would not be written.
For messages that don't require additional formatting, write the original
message payload directly to the selected stream.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Build log messages from left to right, appending optional timestamps and
attributes before the log payload.
Avoid allocating and copying the log payload when no additional formatting
is requested. When formatting is needed, preallocate the output buffer using
the known message and timestamp sizes, with a small per-attribute estimate
to reduce reallocations while appending details.
Replace the custom sort.Interface implementation for log attributes with
slices.SortFunc, and append encoded attributes directly to the log buffer
instead of constructing an intermediate byte slice.
This preserves the existing output format while simplifying message
construction and reducing unnecessary allocations.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Drop cancellation at the kill boundary because killing starts
irreversible task and cleanup work that must finish after request
cancellation.
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
A container that defines no stop timeout of its own always got 10
seconds on Linux, or 30 on Windows, to shut down before being killed.
The value was a constant in the container package, so operators who
wanted a different grace period had to pass `--stop-timeout` on every
container.
Add a `default-stop-timeout` daemon flag and configuration file option
that supplies that fallback. Stopping a container, killing it, and
computing the daemon shutdown timeout take the value from the daemon
configuration when the container has no timeout of its own, so an
explicit per-container timeout still wins and the container
configuration itself stays untouched. The option can be reloaded, and
negative values are rejected.
mergo cannot tell an unset option from a zero value, so a configured
timeout of `0`, meaning "kill immediately", would be replaced by the
non-zero flag default while merging. Remember whether the
configuration file set the option, and restore its value after the
merge.
`ContainerConfig.StopTimeout` in the API documentation no longer
claims a fixed default of 10 seconds, because the fallback is now
whatever `default-stop-timeout` holds.
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
ContainerUpdate only starts applying per-device blkio settings in the
current API version.
The fields existed in the Go request type before that because it shares
`container.Resources` with other endpoints, but they were not documented
as supported for container update and older daemons ignored them.
Clear these fields when handling requests for older API versions so
clients pinned to those versions keep the previous behavior, while v1.55
clients can use the newly supported fields.
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
Both query parameters are now collectionFormat: multi arrays in the
swagger so they can accept multiple values later without an API
version bump. The server still operates on a single platform and
rejects requests passing more than one; type is read directly as a
list of repeated values instead of a comma-separated string.
Signed-off-by: Sopho Merkviladze <smerkviladze@mirantis.com>
Add a new Engine API endpoint that returns the in-toto attestation
statements attached to an image for a given platform. The endpoint
locates the attestation manifest(s) referencing the requested platform's
image manifest, enumerates the statement layers, and returns each
layer's OCI descriptor (including media type, digest, size, and
annotations) together with its in-toto predicate type.
Query parameters:
- platform: JSON-encoded OCI platform; defaults to the daemon's host
platform if omitted.
- type: comma-separated list of in-toto predicate type URIs; if
omitted, all statements are returned.
- statement: boolean, defaults to false. When true, the daemon reads
each matching statement blob and includes the verbatim in-toto JSON
in the response. When false (or omitted), statement blobs are not
read and the Statement field is absent from each entry.
The manifest-chain walk (locating the platform image manifest and its
associated attestation manifest) is delegated to policy-helpers'
image.ResolveSignatureChain so that moby and BuildKit agree on how to
interpret the attestation storage format. The statement-layer iteration
and blob reading is inlined: when statement bodies are requested it
fails fast on the first unreadable blob and reads matching blobs
eagerly into memory; otherwise statement-layer blobs are never read
from the content store.
The endpoint is implemented for the containerd image store. The legacy
graphdriver store returns errdefs.NotImplemented (HTTP 501).
Signed-off-by: Sopho Merkviladze <smerkviladze@mirantis.com>
The wrapOutputBufferedUntilRequestRead helper was added as a workaround
for Go not supporting full-duplex HTTP/1 responses (golang/go#15527,
golang/go#22209). Since Go 1.21, the standard library ships
http.ResponseController.EnableFullDuplex which tells the server that
the handler will interleave reads and writes, making the buffering
wrap unnecessary.
Replace the workaround with a single EnableFullDuplex call and remove
the helper types (wcf, rcNotifier, flusher, nopFlusher) that were only
used by the old path.
Fixes#51209
Signed-off-by: Vedant Madane <vedant.madane@gmail.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The [httpstatus.FromError] utility currently maps context cancellation and
deadline errors to a 500 ("internal server error"). As a result, a client
disconnecting would produce an error log:
ERRO[2026-03-11T11:54:39.872784425Z] Handler for POST /v1.54/images/create returned error: failed to resolve reference "docker.io/library/alpine:latest": failed to do request: Head "https://registry-1.docker.io/v2/library/alpine/manifests/latest": context canceled
This patch:
- Checks for context-cancelation on the context, and instead logs an "INFO"
message. For tracing/OTEL, it produces a "499" status code, which is non-
standard, but commonly accepted (and used by NGINX, CloudFront). Given that
no client should be listening anymore, it omits an actual response.
- Adds more structured logs, to align with the logs we produce in our Debug
middleware.
With this patch:
INFO[2026-03-11T16:43:55.567731845Z] API listen on /var/run/docker.sock
INFO[2026-03-11T16:43:58.152254638Z] fetch failed error="failed to do request: Head \"https://registry-1.docker.io/v2/library/alpine/manifests/latest\": context canceled" host=registry-1.docker.io
INFO[2026-03-11T16:43:58.152608805Z] Cancel with lease, leased resources will remain until expiration expires_at="2026-03-12 00:43:57.965872638 +0000 UTC m=+28803.424778128" lease=965878679-Q_SJ
INFO[2026-03-11T16:43:58.152917138Z] request cancelled by client error="failed to resolve reference \"docker.io/library/alpine:latest\": failed to do request: Head \"https://registry-1.docker.io/v2/library/alpine/manifests/latest\": context canceled" method=POST module=api request-url="/v1.54/images/create?fromImage=docker.io%2Flibrary%2Falpine&tag=latest" status=499 vars="map[version:1.54]"
Note some duplication in logs, as some logs are produced by containerd code.
[httpstatus.FromError]: https://github.com/moby/moby/blob/v2.0.0-beta.7/daemon/server/httpstatus/status.go#L44-L45
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Move parsing the wire format to the router instead of in the daemon, so
that a strong type can be used internally.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
The context arg was kept when extracting the code in 1044093bb0
but it was not handled; let's wire it up.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Commits df506c107e and aef5d996ce
fixed the content-type advertised by the `/events` endpoint, and added content
negotiation as an "opt-in" by clients.
A fallback / default value was added to keep the old (`application/json`)
content type, however, some clients may send `*/*` as a default, which
would considered as "opt-in" in the negotiation, and pick the first "offer"
(`application/jsonl`) instead of the fallback.
On docker 28.x and lower, omitting an `Accept` header, or sending `*/*`
would produce the `application/json` content-type:
```
curl -sS -D - --unix-socket /var/run/docker.sock 'http://localhost/v1.50/events?until=1' | grep 'Content-Type'
curl -sS -D - -H 'Accept: */*' --unix-socket /var/run/docker.sock 'http://localhost/v1.50/events?until=1' | grep 'Content-Type'
```
On docker 29.x, a missing accept header, or a `*/*` would use the new content-type,
not the previous default;
```
curl -sS -D - --unix-socket /var/run/docker.sock 'http://localhost/v1.50/events?until=1' | grep 'Content-Type'
curl -sS -D - -H 'Accept: */*' --unix-socket /var/run/docker.sock 'http://localhost/v1.50/events?until=1' | grep 'Content-Type'
```
With this patch, the default depends on the API version, and we only
override the content-type if there's a match with any of the types
set in the `Accept` header, ignoring wildcards (`*/*`) that are sent
as default by some clients, such as cURL or `docker-py`;
```
curl -sS -D - --unix-socket /var/run/docker.sock 'http://localhost/v1.51/events?until=1' | grep 'Content-Type'
curl -sS -D - -H 'Accept: */*' --unix-socket /var/run/docker.sock 'http://localhost/v1.51/events?until=1' | grep 'Content-Type'
curl -sS -D - --unix-socket /var/run/docker.sock 'http://localhost/v1.52/events?until=1' | grep 'Content-Type'
Content-Type: application/jsonl
curl -sS -D - -H 'Accept: */*' --unix-socket /var/run/docker.sock 'http://localhost/v1.52/events?until=1' | grep 'Content-Type'
curl -sS -D - -H 'Accept: application/json-seq' --unix-socket /var/run/docker.sock 'http://localhost/v1.50/events?until=1' | grep 'Content-Type'
```
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This allows negotiating the content-type without wildcard-matching.
In most of our uses, we want to provide the best match that the
client accepts, but have to avoid picking the first match if a
client would send "*/*" (or, e.g., "application/*").
For example, the events endpoint added support for JSON-stream
content types, but older API versions unconditionally returned
"application/json". Clients sending "*/*" (such as docker/docker-py)
would now get a different content type as before.
For convenience, also adding a wrapper for the gddo NegotiateContentType
utility with a slightly different signature (accepting just the headers
instead of the whole request).
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Extend the previous commit to support API v1.40 (Docker 19.03) by
lowering defaultMinAPIVersion and client MinAPIVersion from 1.41 to
1.40.
Reject container create requests that set the HostConfig.Capabilities
field on API v1.40, since this daemon can no longer honor it. The field
was removed before API v1.41 (24f173a003) and the Go type no longer
includes it, so without this check the field would be silently dropped.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Lower the default minimum API version from v1.44 to v1.41, restore
VirtualSize in image list and disk usage responses for API < 1.44, and
add version-gated skips for integration tests that need newer APIs.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
The `--latest` option was implemented in [moby@b295239] as a CLI shortcut
for `--last=1`.
However, as part of a large refactor of the client in [moby@d05aa41], a
`ContainerListOptions` type was introduced, which contained a `Latest`
field.
This field was never used, as the `Latest` option was handled in the CLI,
and had no corresponding option for the API (other than `limit`).
This patch removes the field from the backend, because it's not used. Removal
from the client will require a deprecation, and will be handled separately.
[moby@b295239]: https://github.com/moby/moby/commit/b295239de20f15620ee4149fcc7c13ce461cdaac
[moby@d05aa41]: https://github.com/moby/moby/commit/d05aa418b0466553a24d42896f99176cfa29765f
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>