Response
The server answers with at most one channel response, the media type and the manifest verbatim, and the channel response finish; a finish with nothing before it states that the server does not hold the digest for the client.
[media_type_len: u16, big-endian][media_type: utf8 …][manifest bytes …] at most once
- The sequence. At most one channel response, followed by the channel response finish. A channel response finish that no channel response precedes states that the server does not hold the digest for the client.
- The frame. A
u16, big-endian, the byte length of the media type; the media type, UTF-8; the bytes of the manifest, verbatim, running to the end of the payload. The bytes are those the digest names.
The channel response is defined by diverge-sdk-rs/src/shared/containers/oci/manifest/response/frame.rs:
//! The manifest, whole.
use super::{EncodeError, FrameError};
use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
/// A manifest's media type and its bytes, in one frame.
///
/// The media type rides along because the runtime needs it back as
/// `Content-Type` and it is not recoverable from the bytes: an image
/// manifest and an image index are both JSON objects, and the
/// `mediaType` field inside them is optional. The bytes are the
/// manifest verbatim — the digest is of these bytes, so nothing may
/// re-serialize them.
///
/// # Two parts on the wire
///
/// `[u16 BE: byte length of the media type][media type][everything
/// after: the manifest bytes]`. The media type leads so the bytes can
/// be the rest, and it is short enough that two bytes of length are
/// plenty.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Frame<'a> {
/// The manifest's media type —
/// `application/vnd.oci.image.manifest.v1+json`,
/// `application/vnd.oci.image.index.v1+json`, or the Docker
/// equivalents.
pub media_type: &'a str,
/// The manifest's bytes, borrowed from the frame they arrived in.
pub body: &'a [u8],
}
/// The bytes the media type's length occupies.
const MEDIA_TYPE_LEN: usize = 2;
impl Encode for Frame<'_> {
/// One way to fail: a media type longer than two bytes can say.
type Error = EncodeError;
fn encode(&self, out: &mut Writer<'_>) -> Result<(), EncodeError> {
let media_type = self.media_type.as_bytes();
let len = u16::try_from(media_type.len())
.map_err(|_| EncodeError::MediaTypeLength(media_type.len()))?;
out.extend_from_slice(&len.to_be_bytes());
out.extend_from_slice(media_type);
out.extend_from_slice(self.body);
Ok(())
}
}
impl<'a> Decode<'a> for Frame<'a> {
/// Three ways to fail, none of them a parse of the manifest.
type Error = FrameError;
fn decode(bytes: &'a [u8]) -> Result<Self, FrameError> {
if bytes.len() < MEDIA_TYPE_LEN {
return Err(FrameError::Short(bytes.len()));
}
let (len, rest) = bytes.split_at(MEDIA_TYPE_LEN);
let len = usize::from(u16::from_be_bytes(
<[u8; MEDIA_TYPE_LEN]>::try_from(len).expect("split_at gave 2 bytes"),
));
if rest.len() < len {
return Err(FrameError::Truncated {
need: len,
have: rest.len(),
});
}
let (media_type, body) = rest.split_at(len);
Ok(Frame {
media_type: std::str::from_utf8(media_type)
.map_err(|_| FrameError::MediaTypeUtf8)?,
body,
})
}
}