@@ -9,12 +9,16 @@ mod telemetry;
99
1010use axum:: {
1111 body:: Body ,
12- http:: { HeaderMap , Request , Response , StatusCode } ,
12+ extract:: Request ,
13+ http:: { HeaderMap , StatusCode } ,
14+ middleware:: Next ,
15+ response:: Response ,
1316 routing:: get,
1417} ;
1518use colored:: Colorize ;
1619use sentry_tower:: SentryHttpLayer ;
1720use serde_json:: json;
21+ use sha1:: Digest ;
1822use std:: { sync:: Arc , time:: Instant } ;
1923use tokio:: sync:: RwLock ;
2024use tower_http:: { catch_panic:: CatchPanicLayer , cors:: CorsLayer , trace:: TraceLayer } ;
@@ -65,6 +69,36 @@ fn handle_request(req: &Request<Body>, _span: &tracing::Span) {
6569 ) ;
6670}
6771
72+ async fn handle_etag ( req : Request , next : Next ) -> Result < Response , StatusCode > {
73+ let if_none_match = req. headers ( ) . get ( "If-None-Match" ) . cloned ( ) ;
74+
75+ let response = next. run ( req) . await ;
76+ let mut hash = sha1:: Sha1 :: new ( ) ;
77+
78+ let ( mut parts, body) = response. into_parts ( ) ;
79+ let body_bytes = axum:: body:: to_bytes ( body, usize:: MAX ) . await . unwrap ( ) ;
80+
81+ hash. update ( body_bytes. as_ref ( ) ) ;
82+ let hash = format ! ( "{:x}" , hash. finalize( ) ) ;
83+
84+ parts. headers . insert ( "ETag" , hash. parse ( ) . unwrap ( ) ) ;
85+
86+ if if_none_match == Some ( hash. parse ( ) . unwrap ( ) ) {
87+ let mut cached_response = Response :: builder ( )
88+ . status ( StatusCode :: NOT_MODIFIED )
89+ . body ( Body :: empty ( ) )
90+ . unwrap ( ) ;
91+
92+ for ( key, value) in parts. headers . iter ( ) {
93+ cached_response. headers_mut ( ) . insert ( key, value. clone ( ) ) ;
94+ }
95+
96+ return Ok ( cached_response) ;
97+ }
98+
99+ Ok ( Response :: from_parts ( parts, Body :: from ( body_bytes) ) )
100+ }
101+
68102#[ tokio:: main]
69103async fn main ( ) {
70104 let env = env:: Env :: parse ( ) ;
@@ -142,6 +176,7 @@ async fn main() {
142176 } ) ) ,
143177 )
144178 } )
179+ . route_layer ( axum:: middleware:: from_fn ( handle_etag) )
145180 . layer ( CatchPanicLayer :: custom ( handle_panic) )
146181 . layer ( CorsLayer :: very_permissive ( ) )
147182 . layer ( TraceLayer :: new_for_http ( ) . on_request ( handle_request) )
0 commit comments