@@ -3,13 +3,12 @@ use std::ffi::{c_char, c_void};
33use http:: HeaderMap ;
44use ngx:: core;
55use ngx:: ffi:: {
6- ngx_array_push, ngx_command_t, ngx_conf_t, ngx_http_handler_pt, ngx_http_module_t,
7- ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE, ngx_int_t, ngx_module_t, ngx_str_t, ngx_uint_t,
6+ ngx_command_t, ngx_conf_t, ngx_http_module_t, ngx_int_t, ngx_module_t, ngx_str_t, ngx_uint_t,
87 NGX_CONF_TAKE1 , NGX_HTTP_LOC_CONF , NGX_HTTP_LOC_CONF_OFFSET , NGX_HTTP_MODULE ,
98 NGX_HTTP_SRV_CONF , NGX_LOG_EMERG ,
109} ;
1110use ngx:: http:: * ;
12- use ngx:: { http_request_handler , ngx_conf_log_error, ngx_log_debug_http, ngx_string} ;
11+ use ngx:: { ngx_conf_log_error, ngx_log_debug_http, ngx_string} ;
1312
1413struct Module ;
1514
@@ -20,17 +19,8 @@ impl HttpModule for Module {
2019
2120 unsafe extern "C" fn postconfiguration ( cf : * mut ngx_conf_t ) -> ngx_int_t {
2221 // SAFETY: this function is called with non-NULL cf always
23- let cf = & mut * cf;
24- let cmcf = NgxHttpCoreModule :: main_conf_mut ( cf) . expect ( "http core main conf" ) ;
25-
26- let h = ngx_array_push (
27- & mut cmcf. phases [ ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE as usize ] . handlers ,
28- ) as * mut ngx_http_handler_pt ;
29- if h. is_null ( ) {
30- return core:: Status :: NGX_ERROR . into ( ) ;
31- }
32- // set an phase handler
33- * h = Some ( awssigv4_header_handler) ;
22+ let cf = unsafe { & mut * cf } ;
23+ AwsSigV4HeaderHandler :: register ( cf) ;
3424 core:: Status :: NGX_OK . into ( )
3525 }
3626}
@@ -261,82 +251,89 @@ extern "C" fn ngx_http_awssigv4_commands_set_s3_endpoint(
261251 ngx:: core:: NGX_CONF_OK
262252}
263253
264- http_request_handler ! ( awssigv4_header_handler, |request: & mut Request | {
265- // get Module Config from request
266- let conf = Module :: location_conf( request) . expect( "module conf" ) ;
267- ngx_log_debug_http!( request, "AWS signature V4 module {}" , {
268- if conf. enable {
269- "enabled"
270- } else {
271- "disabled"
272- }
273- } ) ;
274- if !conf. enable {
275- return core:: Status :: NGX_DECLINED ;
276- }
254+ struct AwsSigV4HeaderHandler ;
277255
278- // TODO: build url properly from the original URL from client
279- let method = request. method( ) ;
280- if !matches!( method, ngx:: http:: Method :: HEAD | ngx:: http:: Method :: GET ) {
281- return HTTPStatus :: FORBIDDEN . into( ) ;
282- }
256+ impl HttpRequestHandler < Option < ngx_int_t > > for AwsSigV4HeaderHandler {
257+ const PHASE : nginx_sys:: NgxHttpPhases = nginx_sys:: NgxHttpPhases :: PreContent ;
258+ type Module = Module ;
283259
284- let datetime = chrono:: Utc :: now( ) ;
285- let uri = match request. unparsed_uri( ) . to_str( ) {
286- Ok ( v) => format!( "https://{}.{}{}" , conf. s3_bucket, conf. s3_endpoint, v) ,
287- Err ( _) => return core:: Status :: NGX_DECLINED ,
288- } ;
260+ fn handler ( request : & mut Request ) -> Option < ngx_int_t > {
261+ // get Module Config from request
262+ let conf = Module :: location_conf ( request) . expect ( "module conf" ) ;
263+ ngx_log_debug_http ! ( request, "AWS signature V4 module {}" , {
264+ if conf. enable {
265+ "enabled"
266+ } else {
267+ "disabled"
268+ }
269+ } ) ;
270+ if !conf. enable {
271+ return Some ( core:: Status :: NGX_DECLINED . into ( ) ) ;
272+ }
273+
274+ // TODO: build url properly from the original URL from client
275+ let method = request. method ( ) ;
276+ if !matches ! ( method, ngx:: http:: Method :: HEAD | ngx:: http:: Method :: GET ) {
277+ return Some ( HTTPStatus :: FORBIDDEN . into ( ) ) ;
278+ }
289279
290- let datetime_now = datetime. format( "%Y%m%dT%H%M%SZ" ) ;
291- let datetime_now = datetime_now. to_string( ) ;
280+ let datetime = chrono:: Utc :: now ( ) ;
281+ let uri = match request. unparsed_uri ( ) . to_str ( ) {
282+ Ok ( v) => format ! ( "https://{}.{}{}" , conf. s3_bucket, conf. s3_endpoint, v) ,
283+ Err ( _) => return Some ( core:: Status :: NGX_DECLINED . into ( ) ) ,
284+ } ;
292285
293- let signature = {
294- // NOTE: aws_sign_v4::AwsSign::new() implementation requires a HeaderMap.
295- // Iterate over requests headers_in and copy into HeaderMap
296- // Copy only headers that will be used to sign the request
297- let mut headers = HeaderMap :: new( ) ;
298- for ( name, value) in request. headers_in_iterator( ) {
299- if let Ok ( name) = name. to_str( ) {
300- if name. to_lowercase( ) == "host" {
301- if let Ok ( value) = http:: HeaderValue :: from_bytes( value. as_bytes( ) ) {
302- headers. insert( http:: header:: HOST , value) ;
303- } else {
304- return core:: Status :: NGX_DECLINED ;
286+ let datetime_now = datetime. format ( "%Y%m%dT%H%M%SZ" ) ;
287+ let datetime_now = datetime_now. to_string ( ) ;
288+
289+ let signature = {
290+ // NOTE: aws_sign_v4::AwsSign::new() implementation requires a HeaderMap.
291+ // Iterate over requests headers_in and copy into HeaderMap
292+ // Copy only headers that will be used to sign the request
293+ let mut headers = HeaderMap :: new ( ) ;
294+ for ( name, value) in request. headers_in_iterator ( ) {
295+ if let Ok ( name) = name. to_str ( ) {
296+ if name. to_lowercase ( ) == "host" {
297+ if let Ok ( value) = http:: HeaderValue :: from_bytes ( value. as_bytes ( ) ) {
298+ headers. insert ( http:: header:: HOST , value) ;
299+ } else {
300+ return Some ( core:: Status :: NGX_DECLINED . into ( ) ) ;
301+ }
305302 }
303+ } else {
304+ return Some ( core:: Status :: NGX_DECLINED . into ( ) ) ;
306305 }
307- } else {
308- return core:: Status :: NGX_DECLINED ;
309306 }
310- }
311- headers. insert( "X-Amz-Date" , datetime_now. parse( ) . unwrap( ) ) ;
312- ngx_log_debug_http!( request, "headers {:?}" , headers) ;
313- ngx_log_debug_http!( request, "method {:?}" , method) ;
314- ngx_log_debug_http!( request, "uri {:?}" , uri) ;
315- ngx_log_debug_http!( request, "datetime_now {:?}" , datetime_now) ;
316-
317- let s = aws_sign_v4:: AwsSign :: new(
318- method. as_str( ) ,
319- & uri,
320- & datetime,
321- & headers,
322- "us-east-1" ,
323- conf. access_key. as_str( ) ,
324- conf. secret_key. as_str( ) ,
325- "s3" ,
326- "" ,
327- ) ;
328- s. sign( )
329- } ;
307+ headers. insert ( "X-Amz-Date" , datetime_now. parse ( ) . unwrap ( ) ) ;
308+ ngx_log_debug_http ! ( request, "headers {:?}" , headers) ;
309+ ngx_log_debug_http ! ( request, "method {:?}" , method) ;
310+ ngx_log_debug_http ! ( request, "uri {:?}" , uri) ;
311+ ngx_log_debug_http ! ( request, "datetime_now {:?}" , datetime_now) ;
312+
313+ let s = aws_sign_v4:: AwsSign :: new (
314+ method. as_str ( ) ,
315+ & uri,
316+ & datetime,
317+ & headers,
318+ "us-east-1" ,
319+ conf. access_key . as_str ( ) ,
320+ conf. secret_key . as_str ( ) ,
321+ "s3" ,
322+ "" ,
323+ ) ;
324+ s. sign ( )
325+ } ;
330326
331- request. add_header_in( "authorization" , signature. as_str( ) ) ;
332- request. add_header_in( "X-Amz-Date" , datetime_now. as_str( ) ) ;
327+ request. add_header_in ( "authorization" , signature. as_str ( ) ) ;
328+ request. add_header_in ( "X-Amz-Date" , datetime_now. as_str ( ) ) ;
333329
334- for ( name, value) in request. headers_out_iterator( ) {
335- ngx_log_debug_http!( request, "headers_out {name}: {value}" , ) ;
336- }
337- for ( name, value) in request. headers_in_iterator( ) {
338- ngx_log_debug_http!( request, "headers_in {name}: {value}" , ) ;
339- }
330+ for ( name, value) in request. headers_out_iterator ( ) {
331+ ngx_log_debug_http ! ( request, "headers_out {name}: {value}" , ) ;
332+ }
333+ for ( name, value) in request. headers_in_iterator ( ) {
334+ ngx_log_debug_http ! ( request, "headers_in {name}: {value}" , ) ;
335+ }
340336
341- core:: Status :: NGX_OK
342- } ) ;
337+ Some ( core:: Status :: NGX_OK . into ( ) )
338+ }
339+ }
0 commit comments