Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(client): Return the digest header for partial responses #171

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ use crate::errors::DigestError;
pub struct SizedStream {
/// The length of the stream if the upstream registry sent a `Content-Length` header
pub content_length: Option<u64>,
/// The digest header value if the upstream registry sent a `Digest` header. This should be used
/// (in addition to the layer digest) for validation when using partial requests as the library
/// can't validate against the full response.
pub digest_header_value: Option<String>,
/// The stream of bytes
pub stream: BoxStream<'static, Result<bytes::Bytes, std::io::Error>>,
}
Expand Down
17 changes: 13 additions & 4 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ impl TryFrom<ClientConfig> for Client {
let no_proxy = config
.no_proxy
.as_ref()
.and_then(|no_proxy| NoProxy::from_string(&no_proxy));
.and_then(|no_proxy| NoProxy::from_string(no_proxy));
let proxy = Proxy::https(proxy_addr)?.no_proxy(no_proxy);
client_builder = client_builder.proxy(proxy);
}
Expand Down Expand Up @@ -1137,10 +1137,15 @@ impl Client {
)
}

/// Stream a single layer from an OCI registry starting with a byte offset.
/// This can be used to continue downloading a layer after a network error.
/// Stream a single layer from an OCI registry starting with a byte offset. This can be used to
/// continue downloading a layer after a network error. Please note that when doing a partial
/// download (meaning it returns the [`BlobResponse::Partial`] variant), the layer digest is not
/// verified as all the bytes are not available. The returned blob response will contain the
/// header from the request digest, if it was set, that can be used (in addition to the digest
/// from the layer) to verify the blob once all the bytes have been downloaded. Failure to do
/// this means your content will not be verified.
///
/// Returns [`Stream`](futures_util::Stream).
/// Returns [`BlobResponse`] which indicates if the response was a full or partial response.
pub async fn pull_blob_stream_partial(
&self,
image: &Reference,
Expand Down Expand Up @@ -1640,6 +1645,9 @@ fn stream_from_response(
Some(digest) => Some((Digester::new(&digest)?, digest)),
None => None,
};
let header_digest = header_digester_and_digest
.as_ref()
.map(|(_, digest)| digest.to_owned());
let stream: BoxStream<'static, std::result::Result<bytes::Bytes, std::io::Error>> = if verify {
Box::pin(VerifyingStream::new(
Box::pin(stream),
Expand All @@ -1652,6 +1660,7 @@ fn stream_from_response(
};
Ok(SizedStream {
content_length,
digest_header_value: header_digest,
stream,
})
}
Expand Down
1 change: 1 addition & 0 deletions src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ pub struct Platform {
/// This OPTIONAL property specifies an array of strings, each specifying a mandatory OS feature.
/// When `os` is `windows`, image indexes SHOULD use, and implementations SHOULD understand the following values:
/// - `win32k`: image requires `win32k.sys` on the host (Note: `win32k.sys` is missing on Nano Server)
///
/// When `os` is not `windows`, values are implementation-defined and SHOULD be submitted to this specification for standardization.
#[serde(rename = "os.features")]
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down
Loading