11use std:: collections:: HashMap ;
22use std:: net:: SocketAddr ;
3+ use std:: str:: from_utf8;
34
45use axum:: headers:: HeaderName ;
6+ use axum:: http:: header:: ACCEPT_ENCODING ;
57use axum:: http:: { HeaderMap , HeaderValue , StatusCode , Uri } ;
68use axum:: response:: { Html , IntoResponse , Response } ;
79use axum:: routing:: { get, get_service} ;
@@ -59,7 +61,8 @@ pub async fn run_server(options: Options, output: WasmBindgenOutput) -> Result<(
5961}
6062
6163fn get_router ( options : & Options , output : WasmBindgenOutput ) -> Router {
62- let WasmBindgenOutput { js, compressed_wasm, snippets, local_modules } = output;
64+ let WasmBindgenOutput { js, br_compressed_wasm, gzip_compressed_wasm, snippets, local_modules } =
65+ output;
6366
6467 let middleware_stack = ServiceBuilder :: new ( )
6568 . layer ( CompressionLayer :: new ( ) )
@@ -85,8 +88,35 @@ fn get_router(options: &Options, output: WasmBindgenOutput) -> Router {
8588 let serve_dir =
8689 get_service ( ServeDir :: new ( options. directory . clone ( ) ) ) . handle_error ( internal_server_error) ;
8790
88- let serve_wasm = || async move {
89- ( [ ( "content-encoding" , "br" ) ] , WithContentType ( "application/wasm" , compressed_wasm) )
91+ let serve_wasm = |headers : HeaderMap | async move {
92+ if let Some ( accept_encoding) = headers. get ( ACCEPT_ENCODING ) {
93+ match from_utf8 ( accept_encoding. as_bytes ( ) ) {
94+ Ok ( encodings) => {
95+ let split_encodings: Vec < & str > = encodings. split ( "," ) . map ( str:: trim) . collect ( ) ;
96+ if split_encodings. contains ( & "br" ) {
97+ Ok ( (
98+ [ ( "content-encoding" , "br" ) ] ,
99+ WithContentType ( "application/wasm" , br_compressed_wasm) ,
100+ ) )
101+ } else if split_encodings. contains ( & "gzip" ) {
102+ Ok ( (
103+ [ ( "content-encoding" , "gzip" ) ] ,
104+ WithContentType ( "application/wasm" , gzip_compressed_wasm) ,
105+ ) )
106+ } else {
107+ tracing:: warn!( "Unsupported encoding in request for wasm.wasm" ) ;
108+ Err ( (
109+ StatusCode :: BAD_REQUEST ,
110+ format ! ( "Unsupported encoding(s): {:?}" , split_encodings) ,
111+ ) )
112+ }
113+ }
114+ Err ( err) => Err ( ( StatusCode :: BAD_REQUEST , err. to_string ( ) ) ) ,
115+ }
116+ } else {
117+ tracing:: error!( "Received request missing the accept-encoding header" ) ;
118+ Err ( ( StatusCode :: BAD_REQUEST , "Missing `accept-encoding` header" . to_string ( ) ) )
119+ }
90120 } ;
91121
92122 Router :: new ( )
@@ -180,6 +210,7 @@ mod tests {
180210 use axum_test_helper:: TestClient ;
181211
182212 const FAKE_BR_COMPRESSED_WASM : [ u8 ; 4 ] = [ 1 , 2 , 3 , 4 ] ;
213+ const FAKE_GZIP_COMPRESSED_WASM : [ u8 ; 4 ] = [ 0x1f , 0x8b , 0x08 , 0x08 ] ;
183214
184215 fn fake_options ( ) -> Options {
185216 Options {
@@ -194,7 +225,8 @@ mod tests {
194225 fn fake_wasm_bindgen_output ( ) -> WasmBindgenOutput {
195226 WasmBindgenOutput {
196227 js : "fake js" . to_string ( ) ,
197- compressed_wasm : FAKE_BR_COMPRESSED_WASM . to_vec ( ) ,
228+ br_compressed_wasm : FAKE_BR_COMPRESSED_WASM . to_vec ( ) ,
229+ gzip_compressed_wasm : FAKE_GZIP_COMPRESSED_WASM . to_vec ( ) ,
198230 snippets : HashMap :: < String , Vec < String > > :: new ( ) ,
199231 local_modules : HashMap :: < String , String > :: new ( ) ,
200232 }
@@ -208,10 +240,17 @@ mod tests {
208240 }
209241
210242 #[ tokio:: test]
211- async fn test_router ( ) {
243+ async fn test_router_bad_request ( ) {
212244 let client = make_test_client ( ) ;
213245
214- // Test with br compression requested
246+ // Test without any supported compression
247+ let res = client. get ( "/api/wasm.wasm" ) . header ( "accept-encoding" , "deflate" ) . send ( ) . await ;
248+ assert_eq ! ( res. status( ) , StatusCode :: BAD_REQUEST ) ;
249+ }
250+
251+ #[ tokio:: test]
252+ async fn test_router_br ( ) {
253+ let client = make_test_client ( ) ;
215254 let mut res = client
216255 . get ( "/api/wasm.wasm" )
217256 . header ( "accept-encoding" , "gzip, deflate, br" )
@@ -221,4 +260,16 @@ mod tests {
221260 let result = res. chunk ( ) . await . unwrap ( ) ;
222261 assert_eq ! ( result. to_vec( ) , FAKE_BR_COMPRESSED_WASM ) ;
223262 }
263+
264+ #[ tokio:: test]
265+ async fn test_router_gzip ( ) {
266+ let client = make_test_client ( ) ;
267+ // Test without br compression, defaulting to gzip
268+ let mut res =
269+ client. get ( "/api/wasm.wasm" ) . header ( "accept-encoding" , "gzip, deflate" ) . send ( ) . await ;
270+ assert_eq ! ( res. status( ) , StatusCode :: OK ) ;
271+ let result = res. chunk ( ) . await . unwrap ( ) ;
272+ // This is the gzip 3-byte file header
273+ assert_eq ! ( result. to_vec( ) , FAKE_GZIP_COMPRESSED_WASM ) ;
274+ }
224275}
0 commit comments