Skip to content

ociclient: Content-Length "SHOULD" be present, but isn't guaranteed #38

@tianon

Description

@tianon

This is really related to what we discussed/implemented in #29 -- many of the methods in ociclient pass down a "knownDigest" value when they're making additional requests in response to a descriptor, especially so that those requests results can still have a Descriptor even if the server doesn't implement the "SHOULD" of providing the Docker-Content-Digest header:

digest := digest.Digest(resp.Header.Get("Docker-Content-Digest"))
if digest != "" {
if !ociref.IsValidDigest(string(digest)) {
return ociregistry.Descriptor{}, fmt.Errorf("bad digest %q found in response", digest)
}
} else {
digest = knownDigest
}

However, as I've noted in #29 (comment), having Content-Length is also technically not a given: https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length

We've seen cases of this in practice tripping this error block (although to be fair, they're not cases where the server is supposed to be omitting Content-Length and servers definitely should include it, but it's valid for them not to):

if resp.ContentLength < 0 {
return ociregistry.Descriptor{}, fmt.Errorf("unknown content length")
}

With respect to the OCI descriptor data type, that's digest and size, and the other relevant value is mediaType, which the code also already handles with a (sub-optimal) fallback:

contentType := resp.Header.Get("Content-Type")
if contentType == "" {
contentType = "application/octet-stream"
}

Arguably, if a request is made in response to an explicit descriptor (pulling the child of a manifest, for example), the values from the original descriptor should always be preferred as "more trusted" than the values from the response headers anyways (it's also arguable that in the case of different digest algorithms in digest, they should both be verified, but that's a whole separate concern).

For now, what I'm proposing to improve this situation is upgrading the knownDigest digest.Digest values we pass down/around to be full knownDescriptor ociregistry.Descriptor objects instead. I'm not sure how this might exhibit all the way up in ociregistry.Interface, because I think for this to work it probably has to? Maybe some way to shove a value into the context? (isn't that what context is for? apologies if not, it's not a strong suit for me, but I feel bad throwing out this issue without making an attempt at proposing solutions 🙇 ❤️)

Regardless, thanks as always for creating and maintaining such a great library. 😄 ❤️

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions