Response
The server sends no response on the scope, unless it keeps no client image, in which case it sends exactly one, the byte 0 alone, and the response finish; otherwise the response finish follows the last answer when the client disconnects or its connection ends, and a response finish the client did not ask for states that the scope is not served.
A server that holds out the images_store
capability sends no response on the scope: every answer comes on the
channel of the ask it answers. A server that does not sends exactly
one response, the byte 0 alone, and the response finish.
(nothing) the main stream carries no response: the pull is served
[0] once, alone: the server keeps no client image, and serves no channel
- The sequence. On a server that keeps client images, no
response: the response finish follows the last answer of every
channel still open when the server receives the client’s
disconnect or the
client’s connection ends, and no frame follows the finish. On a
server that keeps none, exactly one response, the byte
0and nothing else, then the response finish; the server answers no channel, before the response or after it. - Unsupported. A payload that is the byte
0and nothing else states that the server holds out noimages_storecapability and holds no image for the client, as Capabilities provides. Bytes after it are not read. - Not served. A response finish that the client did not ask for by a disconnect, and that no response precedes, states that the server will not serve the pull, as Endpoints provides for a request not served. The server serves no channel after it.
- Malformed. A payload with no byte, and a payload whose first
byte is not
0, are malformed; a client ignores them.
The response is defined by diverge-sdk-rs/src/provider/endpoints/images/oci/server/response/frame.rs:
//! What a server's response frame carries on a pull's main stream.
use std::fmt;
use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
/// The one thing a provider says on channel `0` of a pull, and only
/// when it will not serve one: it has no image store.
///
/// An ordinary pull sends nothing on channel `0` — every answer comes
/// on an ask's own channel, and the finish is the scope's end. A
/// provider whose `images_store` is `false` — see
/// [`info`](crate::provider::endpoints::info) — sends exactly one of
/// these first, and the finish follows it; no ask is answered. A
/// payload is one byte, `0` for [`Unsupported`](Self::Unsupported),
/// and nothing after it.
///
/// | the scope | means |
/// |-----------|-------|
/// | nothing, and stays open | the provider serves the pull, and every ask the caller opens is answered on its channel |
/// | nothing, then a finish | the caller disconnected, or the provider would not serve the pull for a reason it does not say |
/// | an unsupported, then a finish | the provider has no image store; nothing was asked and nothing is held |
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Frame {
/// The provider has no image store, and will not serve the pull.
/// Tag `0`.
///
/// Carries nothing. A caller asks another provider; nothing about
/// the request is the cause.
Unsupported,
}
/// Tag for [`Frame::Unsupported`].
const UNSUPPORTED: u8 = 0;
/// The tag, and nothing after it.
impl Encode for Frame {
/// [`Infallible`](std::convert::Infallible): a known byte.
type Error = std::convert::Infallible;
fn encode(&self, out: &mut Writer<'_>) -> Result<(), Self::Error> {
match self {
Frame::Unsupported => {
out.extend_from_slice(&[UNSUPPORTED]);
Ok(())
}
}
}
}
impl Decode<'_> for Frame {
/// Two ways to fail, and neither of them is a parse.
type Error = FrameError;
fn decode(bytes: &[u8]) -> Result<Self, FrameError> {
let (tag, _) = bytes.split_first().ok_or(FrameError::Empty)?;
match *tag {
UNSUPPORTED => Ok(Frame::Unsupported),
tag => Err(FrameError::UnknownTag(tag)),
}
}
}
/// A pull response frame that could not be read.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FrameError {
/// No bytes at all, so not even a tag.
Empty,
/// A tag that is not this frame's one.
UnknownTag(u8),
}
impl fmt::Display for FrameError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FrameError::Empty => f.write_str("image pull response frame is empty"),
FrameError::UnknownTag(tag) => write!(f, "unknown image pull response frame tag {tag}"),
}
}
}
impl std::error::Error for FrameError {}