Now let's take a silly one
1use std::fmt;
2
3use axum::http::StatusCode;
4use axum::response::{IntoResponse, Response};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum PackLimit {
8 Objects,
9 ObjectBytes,
10 TotalBytes,
11 DeltaDepth,
12}
13
14impl fmt::Display for PackLimit {
15 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16 f.write_str(match self {
17 PackLimit::Objects => "object count",
18 PackLimit::ObjectBytes => "per-object size",
19 PackLimit::TotalBytes => "total decompressed size",
20 PackLimit::DeltaDepth => "delta chain depth",
21 })
22 }
23}
24
25#[derive(Debug, thiserror::Error)]
26pub enum PackError {
27 #[error("repository not found")]
28 NotFound,
29 #[error("repository index is warming, retry shortly")]
30 Unavailable,
31 #[error("invalid request path: {0}")]
32 BadPath(String),
33 #[error("unsupported service")]
34 UnsupportedService,
35 #[error("push is served over SSH, not HTTP")]
36 PushOverSsh,
37 #[error("protocol: {0}")]
38 Protocol(String),
39 #[error("unsupported request content-encoding: {0}")]
40 UnsupportedEncoding(String),
41 #[error("pkt-line: {0}")]
42 PktLine(#[from] std::io::Error),
43 #[error("pack: {0}")]
44 Pack(String),
45 #[error("pack exceeds {0} limit")]
46 LimitExceeded(PackLimit),
47 #[error("upload-pack selection exceeded its object-set cap")]
48 SelectionTooLarge,
49 #[error("upload-pack selection exceeded its time budget")]
50 SelectionTimeout,
51 #[error(transparent)]
52 Git(knot_git::GitError),
53}
54
55impl From<knot_git::GitError> for PackError {
56 fn from(error: knot_git::GitError) -> Self {
57 use knot_git::SelectionLimit;
58 match error {
59 knot_git::GitError::Selection(SelectionLimit::Objects) => PackError::SelectionTooLarge,
60 knot_git::GitError::Selection(SelectionLimit::Time) => PackError::SelectionTimeout,
61 other => PackError::Git(other),
62 }
63 }
64}
65
66impl IntoResponse for PackError {
67 fn into_response(self) -> Response {
68 let status = match self {
69 PackError::NotFound => StatusCode::NOT_FOUND,
70 PackError::Unavailable => StatusCode::SERVICE_UNAVAILABLE,
71 PackError::PushOverSsh => StatusCode::FORBIDDEN,
72 PackError::BadPath(_) | PackError::UnsupportedService => StatusCode::BAD_REQUEST,
73 PackError::Protocol(_) | PackError::PktLine(_) => StatusCode::BAD_REQUEST,
74 PackError::UnsupportedEncoding(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE,
75 PackError::LimitExceeded(_) => StatusCode::PAYLOAD_TOO_LARGE,
76 PackError::SelectionTooLarge | PackError::SelectionTimeout => {
77 StatusCode::SERVICE_UNAVAILABLE
78 }
79 PackError::Pack(_) | PackError::Git(_) => StatusCode::INTERNAL_SERVER_ERROR,
80 };
81 (status, self.to_string()).into_response()
82 }
83}