···1818use reqwest::header::ETAG;1919use tokio_rayon::AsyncThreadPool as _;20202121+use crate::extract::if_none_match::EntityTag;2122use crate::extract::if_none_match::IfNoneMatch;2223use crate::model::Knot;2324use crate::model::repository::ResolveRevspec as _;···3635)]3736pub async fn handle(3837 State(knot): State<Knot>,3939- if_none_match: Option<IfNoneMatch>,3838+ if_none_match: IfNoneMatch,4039 XrpcQuery(Input {4140 repo,4241 rev,···5049 let ResolvedRevspec { commit, immutable } =5150 repository.resolve_revspec(&Some(rev.as_str()))?;52515353- // Use the tree object ID as an ETag.5252+ // Use the tree object ID as an entity tag.5453 //5554 // 1. If the blob content has changed, the blob object ID will be different, and5655 // therefore the tree object ID will also be different.···5857 // 2. Using the tree object ID avoids searching the tree for the blob path.59586059 let tree = repository.get_tree(&commit)?;6161- if if_none_match.is_some_and(|etags| etags.contains(&tree.id.to_string())) {6060+ let etag = EntityTag::strong(tree.id.to_hex().to_string());6161+ if if_none_match.match_weak(&etag) {6262 return Ok(StatusCode::NOT_MODIFIED.into_response());6363 }6464···85838684 headers.insert(8785 ETAG,8888- HeaderValue::from_str(&format!("\"{}\"", tree.id))8686+ etag.to_header_value()8987 .expect("Hex-string should be a valid header value"),9088 );9189