raw
1use axum::{
2 extract,
3 http::{self, StatusCode, request},
4 response::{self, IntoResponse as _},
5};
6
7use crate::utils::{Error, Result};
8
9fn get_param<'x>(ext: &'x http::Extensions, name: &str) -> Option<&'x str> {
10 let raw = ext.get::<extract::RawPathParams>()?;
11
12 for (key, value) in raw {
13 if key == name {
14 return Some(value);
15 }
16 }
17
18 None
19}
20
21pub struct Commit(pub String);
22
23impl<S> extract::FromRequestParts<S> for Commit
24where
25 S: Sync,
26{
27 type Rejection = response::Response;
28
29 async fn from_request_parts(
30 parts: &mut request::Parts,
31 _state: &S,
32 ) -> Result<Self, Self::Rejection> {
33 let Some(raw) = get_param(&parts.extensions, "commit") else {
34 return Err(Error::new(StatusCode::NOT_FOUND, "page not found").into_response());
35 };
36
37 if raw.is_empty() {
38 return Err(
39 Error::new(StatusCode::NOT_FOUND, "commit does not exist in repo").into_response(),
40 );
41 }
42
43 for c in raw.bytes() {
44 if !c.is_ascii_hexdigit() {
45 return Err(
46 Error::new(StatusCode::NOT_FOUND, "commit does not exist in repo")
47 .into_response(),
48 );
49 }
50 }
51
52 Ok(Self(raw.to_string()))
53 }
54}
55
56pub struct Obj(pub String);
57
58impl<S> extract::FromRequestParts<S> for Obj
59where
60 S: Sync,
61{
62 type Rejection = response::Response;
63
64 async fn from_request_parts(
65 parts: &mut request::Parts,
66 _state: &S,
67 ) -> Result<Self, Self::Rejection> {
68 let Some(raw) = get_param(&parts.extensions, "obj") else {
69 return Err(Error::new(StatusCode::NOT_FOUND, "page not found").into_response());
70 };
71
72 if raw.is_empty() {
73 return Err(
74 Error::new(StatusCode::NOT_FOUND, "object does not exist in repo").into_response(),
75 );
76 }
77
78 Ok(Self(raw.to_string()))
79 }
80}
81
82pub struct ObjectName(pub String);
83
84impl<S> extract::FromRequestParts<S> for ObjectName
85where
86 S: Sync,
87{
88 type Rejection = response::Response;
89
90 async fn from_request_parts(
91 parts: &mut request::Parts,
92 _state: &S,
93 ) -> Result<Self, Self::Rejection> {
94 let Some(raw) = get_param(&parts.extensions, "object_name") else {
95 return Err(Error::new(StatusCode::NOT_FOUND, "page not found").into_response());
96 };
97
98 if raw.is_empty() {
99 return Err(
100 Error::new(StatusCode::NOT_FOUND, "object does not exist in repo").into_response(),
101 );
102 }
103
104 Ok(Self(raw.to_string()))
105 }
106}
107
108pub struct Ref(pub String);
109
110impl<S> extract::FromRequestParts<S> for Ref
111where
112 S: Sync,
113{
114 type Rejection = response::Response;
115
116 async fn from_request_parts(
117 parts: &mut request::Parts,
118 _state: &S,
119 ) -> Result<Self, Self::Rejection> {
120 let Some(raw) = get_param(&parts.extensions, "ref") else {
121 return Err(Error::new(StatusCode::NOT_FOUND, "page not found").into_response());
122 };
123
124 if raw.is_empty() {
125 return Err(
126 Error::new(StatusCode::NOT_FOUND, "ref does not exist in repo").into_response(),
127 );
128 }
129
130 Ok(Self(raw.to_string()))
131 }
132}
133
134pub struct RepoName(pub String);
135
136impl<S> extract::FromRequestParts<S> for RepoName
137where
138 S: Sync,
139{
140 type Rejection = response::Response;
141
142 async fn from_request_parts(
143 parts: &mut request::Parts,
144 _state: &S,
145 ) -> Result<Self, Self::Rejection> {
146 let Some(raw) = get_param(&parts.extensions, "repo_name") else {
147 return Err(Error::new(StatusCode::NOT_FOUND, "page not found").into_response());
148 };
149
150 if raw.is_empty() {
151 return Err(Error::new(StatusCode::NOT_FOUND, "repo does not exist").into_response());
152 }
153
154 Ok(Self(raw.to_string()))
155 }
156}
157
158pub struct Tag(pub String);
159
160impl<S> extract::FromRequestParts<S> for Tag
161where
162 S: Sync,
163{
164 type Rejection = response::Response;
165
166 async fn from_request_parts(
167 parts: &mut request::Parts,
168 _state: &S,
169 ) -> Result<Self, Self::Rejection> {
170 let Some(raw) = get_param(&parts.extensions, "tag") else {
171 return Err(Error::new(StatusCode::NOT_FOUND, "page not found").into_response());
172 };
173
174 if raw.is_empty() {
175 return Err(
176 Error::new(StatusCode::NOT_FOUND, "tag does not exist in repo").into_response(),
177 );
178 }
179
180 Ok(Self(raw.to_string()))
181 }
182}
183
184pub fn repo_name_checks(name: &str) -> Result<()> {
185 let name = name.trim();
186
187 if name.is_empty() {
188 return Err(Error::new(StatusCode::NOT_FOUND, "repo does not exist"));
189 }
190
191 Ok(())
192}
193
194pub fn commit_checks(name: &str) -> Result<()> {
195 let name = name.trim();
196
197 if name.is_empty() {
198 return Err(Error::new(StatusCode::NOT_FOUND, "repo does not exist"));
199 }
200
201 for c in name.bytes() {
202 if !c.is_ascii_hexdigit() {
203 return Err(Error::new(StatusCode::NOT_FOUND, "repo does not exist"));
204 }
205 }
206
207 Ok(())
208}
209