@@ -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,18 +19,10 @@ 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) ;
34- core:: Status :: NGX_OK . into ( )
22+ let cf = unsafe { & mut * cf } ;
23+ ngx:: http:: add_phase_handler :: < AwsSigV4HeaderHandler , _ > ( cf)
24+ . map_or ( core:: Status :: NGX_ERROR , |_| core:: Status :: NGX_OK )
25+ . into ( )
3526 }
3627}
3728
@@ -261,82 +252,89 @@ extern "C" fn ngx_http_awssigv4_commands_set_s3_endpoint(
261252 ngx:: core:: NGX_CONF_OK
262253}
263254
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- }
255+ struct AwsSigV4HeaderHandler ;
277256
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- }
257+ impl HttpRequestHandler for AwsSigV4HeaderHandler {
258+ const PHASE : Phases = Phases :: PreContent ;
259+ type ReturnType = Option < ngx_int_t > ;
283260
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- } ;
261+ fn handler ( request : & mut Request ) -> Option < ngx_int_t > {
262+ // get Module Config from request
263+ let conf = Module :: location_conf ( request) . expect ( "module conf" ) ;
264+ ngx_log_debug_http ! ( request, "AWS signature V4 module {}" , {
265+ if conf. enable {
266+ "enabled"
267+ } else {
268+ "disabled"
269+ }
270+ } ) ;
271+ if !conf. enable {
272+ return Some ( core:: Status :: NGX_DECLINED . into ( ) ) ;
273+ }
274+
275+ // TODO: build url properly from the original URL from client
276+ let method = request. method ( ) ;
277+ if !matches ! ( method, ngx:: http:: Method :: HEAD | ngx:: http:: Method :: GET ) {
278+ return Some ( HTTPStatus :: FORBIDDEN . into ( ) ) ;
279+ }
289280
290- let datetime_now = datetime. format( "%Y%m%dT%H%M%SZ" ) ;
291- let datetime_now = datetime_now. to_string( ) ;
281+ let datetime = chrono:: Utc :: now ( ) ;
282+ let uri = match request. unparsed_uri ( ) . to_str ( ) {
283+ Ok ( v) => format ! ( "https://{}.{}{}" , conf. s3_bucket, conf. s3_endpoint, v) ,
284+ Err ( _) => return Some ( core:: Status :: NGX_DECLINED . into ( ) ) ,
285+ } ;
292286
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 ;
287+ let datetime_now = datetime. format ( "%Y%m%dT%H%M%SZ" ) ;
288+ let datetime_now = datetime_now. to_string ( ) ;
289+
290+ let signature = {
291+ // NOTE: aws_sign_v4::AwsSign::new() implementation requires a HeaderMap.
292+ // Iterate over requests headers_in and copy into HeaderMap
293+ // Copy only headers that will be used to sign the request
294+ let mut headers = HeaderMap :: new ( ) ;
295+ for ( name, value) in request. headers_in_iterator ( ) {
296+ if let Ok ( name) = name. to_str ( ) {
297+ if name. to_lowercase ( ) == "host" {
298+ if let Ok ( value) = http:: HeaderValue :: from_bytes ( value. as_bytes ( ) ) {
299+ headers. insert ( http:: header:: HOST , value) ;
300+ } else {
301+ return Some ( core:: Status :: NGX_DECLINED . into ( ) ) ;
302+ }
305303 }
304+ } else {
305+ return Some ( core:: Status :: NGX_DECLINED . into ( ) ) ;
306306 }
307- } else {
308- return core:: Status :: NGX_DECLINED ;
309307 }
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- } ;
308+ headers. insert ( "X-Amz-Date" , datetime_now. parse ( ) . unwrap ( ) ) ;
309+ ngx_log_debug_http ! ( request, "headers {:?}" , headers) ;
310+ ngx_log_debug_http ! ( request, "method {:?}" , method) ;
311+ ngx_log_debug_http ! ( request, "uri {:?}" , uri) ;
312+ ngx_log_debug_http ! ( request, "datetime_now {:?}" , datetime_now) ;
313+
314+ let s = aws_sign_v4:: AwsSign :: new (
315+ method. as_str ( ) ,
316+ & uri,
317+ & datetime,
318+ & headers,
319+ "us-east-1" ,
320+ conf. access_key . as_str ( ) ,
321+ conf. secret_key . as_str ( ) ,
322+ "s3" ,
323+ "" ,
324+ ) ;
325+ s. sign ( )
326+ } ;
330327
331- request. add_header_in( "authorization" , signature. as_str( ) ) ;
332- request. add_header_in( "X-Amz-Date" , datetime_now. as_str( ) ) ;
328+ request. add_header_in ( "authorization" , signature. as_str ( ) ) ;
329+ request. add_header_in ( "X-Amz-Date" , datetime_now. as_str ( ) ) ;
333330
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- }
331+ for ( name, value) in request. headers_out_iterator ( ) {
332+ ngx_log_debug_http ! ( request, "headers_out {name}: {value}" , ) ;
333+ }
334+ for ( name, value) in request. headers_in_iterator ( ) {
335+ ngx_log_debug_http ! ( request, "headers_in {name}: {value}" , ) ;
336+ }
340337
341- core:: Status :: NGX_OK
342- } ) ;
338+ Some ( core:: Status :: NGX_OK . into ( ) )
339+ }
340+ }
0 commit comments