cratestack_axum/headers/
etag.rs1use axum::http::{HeaderMap, HeaderValue, header};
2use axum::response::Response;
3use cratestack_core::CoolError;
4
5pub fn parse_if_match_version(headers: &HeaderMap) -> Result<Option<i64>, CoolError> {
9 let Some(value) = headers.get(header::IF_MATCH) else {
10 return Ok(None);
11 };
12 let raw = value
13 .to_str()
14 .map_err(|_| CoolError::BadRequest("If-Match header must be ASCII".to_owned()))?
15 .trim();
16 if raw == "*" {
17 return Err(CoolError::BadRequest(
18 "If-Match: * is not supported on versioned models".to_owned(),
19 ));
20 }
21 let stripped = raw
22 .strip_prefix('"')
23 .and_then(|s| s.strip_suffix('"'))
24 .ok_or_else(|| {
25 CoolError::BadRequest(
26 "If-Match must be a strong ETag of the form \"<integer>\"".to_owned(),
27 )
28 })?;
29 stripped
30 .parse::<i64>()
31 .map(Some)
32 .map_err(|_| CoolError::BadRequest("If-Match ETag must be an integer".to_owned()))
33}
34
35pub fn set_version_etag(response: &mut Response, version: i64) {
38 if let Ok(value) = HeaderValue::from_str(&format!("\"{version}\"")) {
39 response.headers_mut().insert(header::ETAG, value);
40 }
41}