diff --git a/examples/async.rs b/examples/async.rs index 1c19bf9..94b7df5 100644 --- a/examples/async.rs +++ b/examples/async.rs @@ -7,26 +7,29 @@ use std::time::Instant; use ngx::core; use ngx::ffi::{ - ngx_array_push, ngx_command_t, ngx_conf_t, ngx_connection_t, ngx_event_t, ngx_http_core_module, - ngx_http_handler_pt, ngx_http_module_t, ngx_http_phases_NGX_HTTP_ACCESS_PHASE, ngx_int_t, ngx_module_t, - ngx_post_event, ngx_posted_events, ngx_posted_next_events, ngx_str_t, ngx_uint_t, NGX_CONF_TAKE1, - NGX_HTTP_LOC_CONF, NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_MODULE, + ngx_array_push, ngx_command_t, ngx_conf_t, ngx_connection_t, ngx_event_t, ngx_http_handler_pt, ngx_http_module_t, + ngx_http_phases_NGX_HTTP_ACCESS_PHASE, ngx_int_t, ngx_module_t, ngx_post_event, ngx_posted_events, + ngx_posted_next_events, ngx_str_t, ngx_uint_t, NGX_CONF_TAKE1, NGX_HTTP_LOC_CONF, NGX_HTTP_LOC_CONF_OFFSET, + NGX_HTTP_MODULE, }; -use ngx::http::{self, HTTPModule, MergeConfigError}; +use ngx::http::{self, HttpModule, MergeConfigError}; +use ngx::http::{HttpModuleLocationConf, HttpModuleMainConf, NgxHttpCoreModule}; use ngx::{http_request_handler, ngx_log_debug_http, ngx_string}; use tokio::runtime::Runtime; struct Module; -impl http::HTTPModule for Module { - type MainConf = (); - type SrvConf = (); - type LocConf = ModuleConfig; +impl http::HttpModule for Module { + fn module() -> &'static ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_async_module) } + } unsafe extern "C" fn postconfiguration(cf: *mut ngx_conf_t) -> ngx_int_t { - let cmcf = http::ngx_http_conf_get_module_main_conf(cf, &*addr_of!(ngx_http_core_module)); + // SAFETY: this function is called with non-NULL cf always + let cf = &mut *cf; + let cmcf = NgxHttpCoreModule::main_conf_mut(cf).expect("http core main conf"); - let h = ngx_array_push(&mut (*cmcf).phases[ngx_http_phases_NGX_HTTP_ACCESS_PHASE as usize].handlers) + let h = ngx_array_push(&mut cmcf.phases[ngx_http_phases_NGX_HTTP_ACCESS_PHASE as usize].handlers) as *mut ngx_http_handler_pt; if h.is_null() { return core::Status::NGX_ERROR.into(); @@ -42,6 +45,10 @@ struct ModuleConfig { enable: bool, } +unsafe impl HttpModuleLocationConf for Module { + type LocationConf = ModuleConfig; +} + static mut NGX_HTTP_ASYNC_COMMANDS: [ngx_command_t; 2] = [ ngx_command_t { name: ngx_string!("async"), @@ -57,10 +64,10 @@ static mut NGX_HTTP_ASYNC_COMMANDS: [ngx_command_t; 2] = [ static NGX_HTTP_ASYNC_MODULE_CTX: ngx_http_module_t = ngx_http_module_t { preconfiguration: Some(Module::preconfiguration), postconfiguration: Some(Module::postconfiguration), - create_main_conf: Some(Module::create_main_conf), - init_main_conf: Some(Module::init_main_conf), - create_srv_conf: Some(Module::create_srv_conf), - merge_srv_conf: Some(Module::merge_srv_conf), + create_main_conf: None, + init_main_conf: None, + create_srv_conf: None, + merge_srv_conf: None, create_loc_conf: Some(Module::create_loc_conf), merge_loc_conf: Some(Module::merge_loc_conf), }; @@ -133,8 +140,7 @@ impl Drop for RequestCTX { } http_request_handler!(async_access_handler, |request: &mut http::Request| { - let co = unsafe { request.get_module_loc_conf::(&*addr_of!(ngx_http_async_module)) }; - let co = co.expect("module config is none"); + let co = Module::location_conf(request).expect("module config is none"); ngx_log_debug_http!(request, "async module enabled: {}", co.enable); diff --git a/examples/awssig.rs b/examples/awssig.rs index 49de0be..127b484 100644 --- a/examples/awssig.rs +++ b/examples/awssig.rs @@ -1,10 +1,9 @@ use std::ffi::{c_char, c_void}; -use std::ptr::addr_of; use http::HeaderMap; use ngx::core; use ngx::ffi::{ - ngx_array_push, ngx_command_t, ngx_conf_t, ngx_http_core_module, ngx_http_handler_pt, ngx_http_module_t, + ngx_array_push, ngx_command_t, ngx_conf_t, ngx_http_handler_pt, ngx_http_module_t, ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE, ngx_int_t, ngx_module_t, ngx_str_t, ngx_uint_t, NGX_CONF_TAKE1, NGX_HTTP_LOC_CONF, NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_MODULE, NGX_HTTP_SRV_CONF, }; @@ -13,15 +12,17 @@ use ngx::{http_request_handler, ngx_log_debug_http, ngx_string}; struct Module; -impl HTTPModule for Module { - type MainConf = (); - type SrvConf = (); - type LocConf = ModuleConfig; +impl HttpModule for Module { + fn module() -> &'static ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_awssigv4_module) } + } unsafe extern "C" fn postconfiguration(cf: *mut ngx_conf_t) -> ngx_int_t { - let cmcf = ngx_http_conf_get_module_main_conf(cf, &*addr_of!(ngx_http_core_module)); + // SAFETY: this function is called with non-NULL cf always + let cf = &mut *cf; + let cmcf = NgxHttpCoreModule::main_conf_mut(cf).expect("http core main conf"); - let h = ngx_array_push(&mut (*cmcf).phases[ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE as usize].handlers) + let h = ngx_array_push(&mut cmcf.phases[ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE as usize].handlers) as *mut ngx_http_handler_pt; if h.is_null() { return core::Status::NGX_ERROR.into(); @@ -41,6 +42,10 @@ struct ModuleConfig { s3_endpoint: String, } +unsafe impl HttpModuleLocationConf for Module { + type LocationConf = ModuleConfig; +} + static mut NGX_HTTP_AWSSIGV4_COMMANDS: [ngx_command_t; 6] = [ ngx_command_t { name: ngx_string!("awssigv4"), @@ -88,10 +93,10 @@ static mut NGX_HTTP_AWSSIGV4_COMMANDS: [ngx_command_t; 6] = [ static NGX_HTTP_AWSSIGV4_MODULE_CTX: ngx_http_module_t = ngx_http_module_t { preconfiguration: Some(Module::preconfiguration), postconfiguration: Some(Module::postconfiguration), - create_main_conf: Some(Module::create_main_conf), - init_main_conf: Some(Module::init_main_conf), - create_srv_conf: Some(Module::create_srv_conf), - merge_srv_conf: Some(Module::merge_srv_conf), + create_main_conf: None, + init_main_conf: None, + create_srv_conf: None, + merge_srv_conf: None, create_loc_conf: Some(Module::create_loc_conf), merge_loc_conf: Some(Module::merge_loc_conf), }; @@ -245,8 +250,7 @@ extern "C" fn ngx_http_awssigv4_commands_set_s3_endpoint( http_request_handler!(awssigv4_header_handler, |request: &mut Request| { // get Module Config from request - let conf = unsafe { request.get_module_loc_conf::(&*addr_of!(ngx_http_awssigv4_module)) }; - let conf = conf.unwrap(); + let conf = Module::location_conf(request).expect("module conf"); ngx_log_debug_http!(request, "AWS signature V4 module {}", { if conf.enable { "enabled" diff --git a/examples/curl.rs b/examples/curl.rs index c3dd07b..7ccba61 100644 --- a/examples/curl.rs +++ b/examples/curl.rs @@ -1,26 +1,28 @@ use std::ffi::{c_char, c_void}; -use std::ptr::addr_of; use ngx::core; use ngx::ffi::{ - ngx_array_push, ngx_command_t, ngx_conf_t, ngx_http_core_module, ngx_http_handler_pt, ngx_http_module_t, + ngx_array_push, ngx_command_t, ngx_conf_t, ngx_http_handler_pt, ngx_http_module_t, ngx_http_phases_NGX_HTTP_ACCESS_PHASE, ngx_int_t, ngx_module_t, ngx_str_t, ngx_uint_t, NGX_CONF_TAKE1, NGX_HTTP_LOC_CONF, NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_MODULE, }; -use ngx::http::{self, HTTPModule, MergeConfigError}; +use ngx::http::{self, HttpModule, MergeConfigError}; +use ngx::http::{HttpModuleLocationConf, HttpModuleMainConf, NgxHttpCoreModule}; use ngx::{http_request_handler, ngx_log_debug_http, ngx_string}; struct Module; -impl http::HTTPModule for Module { - type MainConf = (); - type SrvConf = (); - type LocConf = ModuleConfig; +impl http::HttpModule for Module { + fn module() -> &'static ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_curl_module) } + } unsafe extern "C" fn postconfiguration(cf: *mut ngx_conf_t) -> ngx_int_t { - let cmcf = http::ngx_http_conf_get_module_main_conf(cf, &*addr_of!(ngx_http_core_module)); + // SAFETY: this function is called with non-NULL cf always + let cf = &mut *cf; + let cmcf = NgxHttpCoreModule::main_conf_mut(cf).expect("http core main conf"); - let h = ngx_array_push(&mut (*cmcf).phases[ngx_http_phases_NGX_HTTP_ACCESS_PHASE as usize].handlers) + let h = ngx_array_push(&mut cmcf.phases[ngx_http_phases_NGX_HTTP_ACCESS_PHASE as usize].handlers) as *mut ngx_http_handler_pt; if h.is_null() { return core::Status::NGX_ERROR.into(); @@ -36,6 +38,10 @@ struct ModuleConfig { enable: bool, } +unsafe impl HttpModuleLocationConf for Module { + type LocationConf = ModuleConfig; +} + static mut NGX_HTTP_CURL_COMMANDS: [ngx_command_t; 2] = [ ngx_command_t { name: ngx_string!("curl"), @@ -51,10 +57,10 @@ static mut NGX_HTTP_CURL_COMMANDS: [ngx_command_t; 2] = [ static NGX_HTTP_CURL_MODULE_CTX: ngx_http_module_t = ngx_http_module_t { preconfiguration: Some(Module::preconfiguration), postconfiguration: Some(Module::postconfiguration), - create_main_conf: Some(Module::create_main_conf), - init_main_conf: Some(Module::init_main_conf), - create_srv_conf: Some(Module::create_srv_conf), - merge_srv_conf: Some(Module::merge_srv_conf), + create_main_conf: None, + init_main_conf: None, + create_srv_conf: None, + merge_srv_conf: None, create_loc_conf: Some(Module::create_loc_conf), merge_loc_conf: Some(Module::merge_loc_conf), }; @@ -84,8 +90,7 @@ impl http::Merge for ModuleConfig { } http_request_handler!(curl_access_handler, |request: &mut http::Request| { - let co = unsafe { request.get_module_loc_conf::(&*addr_of!(ngx_http_curl_module)) }; - let co = co.expect("module config is none"); + let co = Module::location_conf(request).expect("module config is none"); ngx_log_debug_http!(request, "curl module enabled: {}", co.enable); diff --git a/examples/httporigdst.rs b/examples/httporigdst.rs index 02e6ddb..771333c 100644 --- a/examples/httporigdst.rs +++ b/examples/httporigdst.rs @@ -7,7 +7,7 @@ use ngx::ffi::{ ngx_http_variable_t, ngx_inet_get_port, ngx_int_t, ngx_module_t, ngx_sock_ntop, ngx_str_t, ngx_variable_value_t, sockaddr, sockaddr_storage, INET_ADDRSTRLEN, NGX_HTTP_MODULE, }; -use ngx::http::{self, HTTPModule}; +use ngx::http::{self, HttpModule}; use ngx::{http_variable_get, ngx_log_debug_http, ngx_string}; const IPV4_STRLEN: usize = INET_ADDRSTRLEN as usize; @@ -70,12 +70,12 @@ impl NgxHttpOrigDstCtx { static NGX_HTTP_ORIG_DST_MODULE_CTX: ngx_http_module_t = ngx_http_module_t { preconfiguration: Some(Module::preconfiguration), postconfiguration: Some(Module::postconfiguration), - create_main_conf: Some(Module::create_main_conf), - init_main_conf: Some(Module::init_main_conf), - create_srv_conf: Some(Module::create_srv_conf), - merge_srv_conf: Some(Module::merge_srv_conf), - create_loc_conf: Some(Module::create_loc_conf), - merge_loc_conf: Some(Module::merge_loc_conf), + create_main_conf: None, + init_main_conf: None, + create_srv_conf: None, + merge_srv_conf: None, + create_loc_conf: None, + merge_loc_conf: None, }; // Generate the `ngx_modules` table with exported modules. @@ -258,10 +258,10 @@ http_variable_get!( struct Module; -impl HTTPModule for Module { - type MainConf = (); - type SrvConf = (); - type LocConf = (); +impl HttpModule for Module { + fn module() -> &'static ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_orig_dst_module) } + } // static ngx_int_t ngx_http_orig_dst_add_variables(ngx_conf_t *cf) unsafe extern "C" fn preconfiguration(cf: *mut ngx_conf_t) -> ngx_int_t { diff --git a/examples/upstream.rs b/examples/upstream.rs index c1a3d91..27160a4 100644 --- a/examples/upstream.rs +++ b/examples/upstream.rs @@ -8,21 +8,18 @@ */ use std::ffi::{c_char, c_void}; use std::mem; -use std::ptr::addr_of; use std::slice; use ngx::core::{Pool, Status}; use ngx::ffi::{ ngx_atoi, ngx_command_t, ngx_conf_t, ngx_connection_t, ngx_event_free_peer_pt, ngx_event_get_peer_pt, ngx_http_module_t, ngx_http_upstream_init_peer_pt, ngx_http_upstream_init_pt, ngx_http_upstream_init_round_robin, - ngx_http_upstream_module, ngx_http_upstream_srv_conf_t, ngx_http_upstream_t, ngx_int_t, ngx_module_t, - ngx_peer_connection_t, ngx_str_t, ngx_uint_t, NGX_CONF_NOARGS, NGX_CONF_TAKE1, NGX_CONF_UNSET, NGX_ERROR, - NGX_HTTP_MODULE, NGX_HTTP_SRV_CONF_OFFSET, NGX_HTTP_UPS_CONF, NGX_LOG_EMERG, -}; -use ngx::http::{ - ngx_http_conf_get_module_srv_conf, ngx_http_conf_upstream_srv_conf_immutable, - ngx_http_conf_upstream_srv_conf_mutable, HTTPModule, Merge, MergeConfigError, Request, + ngx_http_upstream_srv_conf_t, ngx_http_upstream_t, ngx_int_t, ngx_module_t, ngx_peer_connection_t, ngx_str_t, + ngx_uint_t, NGX_CONF_NOARGS, NGX_CONF_TAKE1, NGX_CONF_UNSET, NGX_ERROR, NGX_HTTP_MODULE, NGX_HTTP_SRV_CONF_OFFSET, + NGX_HTTP_UPS_CONF, NGX_LOG_EMERG, }; +use ngx::http::{HttpModule, Merge, MergeConfigError, Request}; +use ngx::http::{HttpModuleServerConf, NgxHttpUpstreamModule}; use ngx::{http_upstream_init_peer_pt, ngx_conf_log_error, ngx_log_debug_http, ngx_log_debug_mask, ngx_string}; #[derive(Clone, Copy, Debug)] @@ -77,12 +74,12 @@ impl Default for UpstreamPeerData { static NGX_HTTP_UPSTREAM_CUSTOM_CTX: ngx_http_module_t = ngx_http_module_t { preconfiguration: Some(Module::preconfiguration), postconfiguration: Some(Module::postconfiguration), - create_main_conf: Some(Module::create_main_conf), - init_main_conf: Some(Module::init_main_conf), + create_main_conf: None, + init_main_conf: None, create_srv_conf: Some(Module::create_srv_conf), merge_srv_conf: Some(Module::merge_srv_conf), - create_loc_conf: Some(Module::create_loc_conf), - merge_loc_conf: Some(Module::merge_loc_conf), + create_loc_conf: None, + merge_loc_conf: None, }; static mut NGX_HTTP_UPSTREAM_CUSTOM_COMMANDS: [ngx_command_t; 2] = [ @@ -125,14 +122,14 @@ http_upstream_init_peer_pt!( return Status::NGX_ERROR; } - let maybe_conf: Option<*const SrvConfig> = - unsafe { ngx_http_conf_upstream_srv_conf_immutable(us, &*addr_of!(ngx_http_upstream_custom_module)) }; - if maybe_conf.is_none() { - return Status::NGX_ERROR; - } + // SAFETY: this function is called with non-NULL uf always + let us = unsafe { &mut *us }; + let hccf = match Module::server_conf(us) { + Some(x) => x, + None => return Status::NGX_ERROR, + }; - let hccf = maybe_conf.unwrap(); - let original_init_peer = unsafe { (*hccf).original_init_peer.unwrap() }; + let original_init_peer = hccf.original_init_peer.unwrap(); if unsafe { original_init_peer(request.into(), us) != Status::NGX_OK.into() } { return Status::NGX_ERROR; } @@ -214,26 +211,27 @@ unsafe extern "C" fn ngx_http_upstream_init_custom( ) -> ngx_int_t { ngx_log_debug_mask!(DebugMask::Http, (*cf).log, "CUSTOM UPSTREAM peer init_upstream"); - let maybe_conf: Option<*mut SrvConfig> = - ngx_http_conf_upstream_srv_conf_mutable(us, &*addr_of!(ngx_http_upstream_custom_module)); - if maybe_conf.is_none() { + // SAFETY: this function is called with non-NULL uf always + let us = unsafe { &mut *us }; + let hccf = Module::server_conf_mut(us); + if hccf.is_none() { ngx_conf_log_error!(NGX_LOG_EMERG, cf, "CUSTOM UPSTREAM no upstream srv_conf"); return isize::from(Status::NGX_ERROR); } - let hccf = maybe_conf.unwrap(); + let hccf = hccf.unwrap(); // NOTE: ngx_conf_init_uint_value macro is unavailable - if (*hccf).max == u32::MAX { - (*hccf).max = 100; + if hccf.max == u32::MAX { + hccf.max = 100; } - let init_upstream_ptr = (*hccf).original_init_upstream.unwrap(); + let init_upstream_ptr = hccf.original_init_upstream.unwrap(); if init_upstream_ptr(cf, us) != Status::NGX_OK.into() { ngx_conf_log_error!(NGX_LOG_EMERG, cf, "CUSTOM UPSTREAM failed calling init_upstream"); return isize::from(Status::NGX_ERROR); } - (*hccf).original_init_peer = (*us).peer.init; - (*us).peer.init = Some(http_upstream_init_custom_peer); + hccf.original_init_peer = us.peer.init; + us.peer.init = Some(http_upstream_init_custom_peer); ngx_log_debug_mask!(DebugMask::Http, (*cf).log, "CUSTOM UPSTREAM end peer init_upstream"); isize::from(Status::NGX_OK) @@ -247,12 +245,14 @@ unsafe extern "C" fn ngx_http_upstream_commands_set_custom( cmd: *mut ngx_command_t, conf: *mut c_void, ) -> *mut c_char { - ngx_log_debug_mask!(DebugMask::Http, (*cf).log, "CUSTOM UPSTREAM module init"); + // SAFETY: this function is called with non-NULL cf always + let cf = &mut *cf; + ngx_log_debug_mask!(DebugMask::Http, cf.log, "CUSTOM UPSTREAM module init"); let ccf = &mut (*(conf as *mut SrvConfig)); - if (*(*cf).args).nelts == 2 { - let value: &[ngx_str_t] = slice::from_raw_parts((*(*cf).args).elts as *const ngx_str_t, (*(*cf).args).nelts); + if (*cf.args).nelts == 2 { + let value: &[ngx_str_t] = slice::from_raw_parts((*cf.args).elts as *const ngx_str_t, (*cf.args).nelts); let n = ngx_atoi(value[1].data, value[1].len); if n == (NGX_ERROR as isize) || n == 0 { ngx_conf_log_error!( @@ -267,19 +267,17 @@ unsafe extern "C" fn ngx_http_upstream_commands_set_custom( ccf.max = n as u32; } - let uscf: *mut ngx_http_upstream_srv_conf_t = - ngx_http_conf_get_module_srv_conf(cf, &*addr_of!(ngx_http_upstream_module)) - as *mut ngx_http_upstream_srv_conf_t; + let uscf = NgxHttpUpstreamModule::server_conf_mut(cf).expect("http upstream srv conf"); - ccf.original_init_upstream = if (*uscf).peer.init_upstream.is_some() { - (*uscf).peer.init_upstream + ccf.original_init_upstream = if uscf.peer.init_upstream.is_some() { + uscf.peer.init_upstream } else { Some(ngx_http_upstream_init_round_robin) }; - (*uscf).peer.init_upstream = Some(ngx_http_upstream_init_custom); + uscf.peer.init_upstream = Some(ngx_http_upstream_init_custom); - ngx_log_debug_mask!(DebugMask::Http, (*cf).log, "CUSTOM UPSTREAM end module init"); + ngx_log_debug_mask!(DebugMask::Http, cf.log, "CUSTOM UPSTREAM end module init"); // NGX_CONF_OK std::ptr::null_mut() } @@ -289,10 +287,10 @@ unsafe extern "C" fn ngx_http_upstream_commands_set_custom( // implemented is our `create_srv_conf` method. struct Module; -impl HTTPModule for Module { - type MainConf = (); - type SrvConf = SrvConfig; - type LocConf = (); +impl HttpModule for Module { + fn module() -> &'static ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_upstream_custom_module) } + } unsafe extern "C" fn create_srv_conf(cf: *mut ngx_conf_t) -> *mut c_void { let mut pool = Pool::from_ngx_pool((*cf).pool); @@ -312,3 +310,7 @@ impl HTTPModule for Module { conf as *mut c_void } } + +unsafe impl HttpModuleServerConf for Module { + type ServerConf = SrvConfig; +} diff --git a/src/http/conf.rs b/src/http/conf.rs index c9f14ea..b26ecd5 100644 --- a/src/http/conf.rs +++ b/src/http/conf.rs @@ -1,63 +1,281 @@ -use core::ffi::c_void; +use ::core::ptr::NonNull; -use crate::ffi::*; +use crate::ffi::{ + ngx_http_conf_ctx_t, ngx_http_core_srv_conf_t, ngx_http_request_t, ngx_http_upstream_srv_conf_t, ngx_module_t, +}; +use crate::http::HttpModule; -/// # Safety -/// -/// The caller has provided a valid `ngx_conf_t` that points to valid memory and is non-null. -pub unsafe fn ngx_http_conf_get_module_main_conf( - cf: *mut ngx_conf_t, - module: &ngx_module_t, -) -> *mut ngx_http_core_main_conf_t { - let http_conf_ctx = (*cf).ctx as *mut ngx_http_conf_ctx_t; - *(*http_conf_ctx).main_conf.add(module.ctx_index) as *mut ngx_http_core_main_conf_t +/// Utility trait for types containing HTTP module configuration +pub trait HttpModuleConfExt { + /// Get a non-null reference to the main configuration structure for HTTP module + /// + /// # Safety + /// Caller must ensure that type `T` matches the configuration type for the specified module. + #[inline] + unsafe fn http_main_conf_unchecked(&self, _module: &ngx_module_t) -> Option> { + None + } + + /// Get a non-null reference to the server configuration structure for HTTP module + /// + /// # Safety + /// Caller must ensure that type `T` matches the configuration type for the specified module. + #[inline] + unsafe fn http_server_conf_unchecked(&self, _module: &ngx_module_t) -> Option> { + None + } + + /// Get a non-null reference to the location configuration structure for HTTP module + /// + /// Applies to a single `location`, `if` or `limit_except` block + /// + /// # Safety + /// Caller must ensure that type `T` matches the configuration type for the specified module. + #[inline] + unsafe fn http_location_conf_unchecked(&self, _module: &ngx_module_t) -> Option> { + None + } } -/// # Safety -/// -/// The caller has provided a valid `ngx_conf_t` that points to valid memory and is non-null. -pub unsafe fn ngx_http_conf_get_module_srv_conf(cf: *mut ngx_conf_t, module: &ngx_module_t) -> *mut c_void { - let http_conf_ctx = (*cf).ctx as *mut ngx_http_conf_ctx_t; - *(*http_conf_ctx).srv_conf.add(module.ctx_index) +impl HttpModuleConfExt for crate::ffi::ngx_cycle_t { + #[inline] + unsafe fn http_main_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + let http_conf = self.conf_ctx.add(nginx_sys::ngx_http_module.index).as_ref()?; + let conf_ctx = (*http_conf).cast::(); + let conf_ctx = conf_ctx.as_ref()?; + NonNull::new((*conf_ctx.main_conf.add(module.ctx_index)).cast()) + } } -/// # Safety -/// -/// The caller has provided a valid `ngx_conf_t` that points to valid memory and is non-null. -pub unsafe fn ngx_http_conf_get_module_loc_conf( - cf: *mut ngx_conf_t, - module: &ngx_module_t, -) -> *mut ngx_http_core_loc_conf_t { - let http_conf_ctx = (*cf).ctx as *mut ngx_http_conf_ctx_t; - *(*http_conf_ctx).loc_conf.add(module.ctx_index) as *mut ngx_http_core_loc_conf_t +impl HttpModuleConfExt for crate::ffi::ngx_conf_t { + #[inline] + unsafe fn http_main_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + let conf_ctx = self.ctx.cast::(); + let conf_ctx = conf_ctx.as_ref()?; + NonNull::new((*conf_ctx.main_conf.add(module.ctx_index)).cast()) + } + + #[inline] + unsafe fn http_server_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + let conf_ctx = self.ctx.cast::(); + let conf_ctx = conf_ctx.as_ref()?; + NonNull::new((*conf_ctx.srv_conf.add(module.ctx_index)).cast()) + } + + #[inline] + unsafe fn http_location_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + let conf_ctx = self.ctx.cast::(); + let conf_ctx = conf_ctx.as_ref()?; + NonNull::new((*conf_ctx.loc_conf.add(module.ctx_index)).cast()) + } } -/// # Safety +impl HttpModuleConfExt for ngx_http_core_srv_conf_t { + #[inline] + unsafe fn http_main_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + let conf_ctx = self.ctx.as_ref()?; + NonNull::new((*conf_ctx.main_conf.add(module.ctx_index)).cast()) + } + + #[inline] + unsafe fn http_server_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + let conf_ctx = self.ctx.as_ref()?; + NonNull::new((*conf_ctx.srv_conf.add(module.ctx_index)).cast()) + } + + #[inline] + unsafe fn http_location_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + let conf_ctx = self.ctx.as_ref()?; + NonNull::new((*conf_ctx.loc_conf.add(module.ctx_index)).cast()) + } +} + +impl HttpModuleConfExt for ngx_http_request_t { + #[inline] + unsafe fn http_main_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + NonNull::new((*self.main_conf.add(module.ctx_index)).cast()) + } + + #[inline] + unsafe fn http_server_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + NonNull::new((*self.srv_conf.add(module.ctx_index)).cast()) + } + + #[inline] + unsafe fn http_location_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + NonNull::new((*self.loc_conf.add(module.ctx_index)).cast()) + } +} + +impl HttpModuleConfExt for ngx_http_upstream_srv_conf_t { + #[inline] + unsafe fn http_server_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + let conf = self.srv_conf; + if conf.is_null() { + return None; + } + NonNull::new((*conf.add(module.ctx_index)).cast()) + } +} + +/// Trait to define and access main module configuration /// -/// The caller has provided a value `ngx_http_upstream_srv_conf_t. If the `us` argument is null, a -/// None Option is returned; however, if the `us` internal fields are invalid or the module index -/// is out of bounds failures may still occur. -pub unsafe fn ngx_http_conf_upstream_srv_conf_immutable( - us: *const ngx_http_upstream_srv_conf_t, - module: &ngx_module_t, -) -> Option<*const T> { - if us.is_null() { - return None; +/// # Safety +/// Caller must ensure that type `HttpModuleMainConf::MainConf` matches the configuration type +/// for the specified module. +pub unsafe trait HttpModuleMainConf: HttpModule { + /// Type for main module configuration + type MainConf; + /// Get reference to main module configuration + fn main_conf(o: &impl HttpModuleConfExt) -> Option<&'static Self::MainConf> { + unsafe { Some(o.http_main_conf_unchecked(Self::module())?.as_ref()) } + } + /// Get mutable reference to main module configuration + fn main_conf_mut(o: &impl HttpModuleConfExt) -> Option<&'static mut Self::MainConf> { + unsafe { Some(o.http_main_conf_unchecked(Self::module())?.as_mut()) } } - Some(*(*us).srv_conf.add(module.ctx_index) as *const T) } +/// Trait to define and access server-specific module configuration +/// /// # Safety +/// Caller must ensure that type `HttpModuleServerConf::ServerConf` matches the configuration type +/// for the specified module. +pub unsafe trait HttpModuleServerConf: HttpModule { + /// Type for server-specific module configuration + type ServerConf; + /// Get reference to server-specific module configuration + fn server_conf(o: &impl HttpModuleConfExt) -> Option<&'static Self::ServerConf> { + unsafe { Some(o.http_server_conf_unchecked(Self::module())?.as_ref()) } + } + /// Get mutable reference to server-specific module configuration + fn server_conf_mut(o: &impl HttpModuleConfExt) -> Option<&'static mut Self::ServerConf> { + unsafe { Some(o.http_server_conf_unchecked(Self::module())?.as_mut()) } + } +} + +/// Trait to define and access location-specific module configuration /// -/// The caller has provided a value `ngx_http_upstream_srv_conf_t. If the `us` argument is null, a -/// None Option is returned; however, if the `us` internal fields are invalid or the module index -/// is out of bounds failures may still occur. -pub unsafe fn ngx_http_conf_upstream_srv_conf_mutable( - us: *const ngx_http_upstream_srv_conf_t, - module: &ngx_module_t, -) -> Option<*mut T> { - if us.is_null() { - return None; - } - Some(*(*us).srv_conf.add(module.ctx_index) as *mut T) +/// Applies to a single `location`, `if` or `limit_except` block +/// +/// # Safety +/// Caller must ensure that type `HttpModuleLocationConf::LocationConf` matches the configuration type +/// for the specified module. +pub unsafe trait HttpModuleLocationConf: HttpModule { + /// Type for location-specific module configuration + type LocationConf; + /// Get reference to location-specific module configuration + fn location_conf(o: &impl HttpModuleConfExt) -> Option<&'static Self::LocationConf> { + unsafe { Some(o.http_location_conf_unchecked(Self::module())?.as_ref()) } + } + /// Get mutable reference to location-specific module configuration + fn location_conf_mut(o: &impl HttpModuleConfExt) -> Option<&'static mut Self::LocationConf> { + unsafe { Some(o.http_location_conf_unchecked(Self::module())?.as_mut()) } + } } + +mod core { + use crate::ffi::{ + ngx_http_core_loc_conf_t, ngx_http_core_main_conf_t, ngx_http_core_module, ngx_http_core_srv_conf_t, + }; + + /// Auxiliary structure to access `ngx_http_core_module` configuration. + pub struct NgxHttpCoreModule; + + impl crate::http::HttpModule for NgxHttpCoreModule { + fn module() -> &'static crate::ffi::ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_core_module) } + } + } + unsafe impl crate::http::HttpModuleMainConf for NgxHttpCoreModule { + type MainConf = ngx_http_core_main_conf_t; + } + unsafe impl crate::http::HttpModuleServerConf for NgxHttpCoreModule { + type ServerConf = ngx_http_core_srv_conf_t; + } + unsafe impl crate::http::HttpModuleLocationConf for NgxHttpCoreModule { + type LocationConf = ngx_http_core_loc_conf_t; + } +} + +pub use core::NgxHttpCoreModule; + +#[cfg(ngx_feature = "http_ssl")] +mod ssl { + use crate::ffi::{ngx_http_ssl_module, ngx_http_ssl_srv_conf_t}; + + /// Auxiliary structure to access `ngx_http_ssl_module` configuration. + pub struct NgxHttpSslModule; + + impl crate::http::HttpModule for NgxHttpSslModule { + fn module() -> &'static crate::ffi::ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_ssl_module) } + } + } + unsafe impl crate::http::HttpModuleServerConf for NgxHttpSslModule { + type ServerConf = ngx_http_ssl_srv_conf_t; + } +} +#[cfg(ngx_feature = "http_ssl")] +pub use ssl::NgxHttpSslModule; + +mod upstream { + use crate::ffi::{ngx_http_upstream_main_conf_t, ngx_http_upstream_module, ngx_http_upstream_srv_conf_t}; + + /// Auxiliary structure to access `ngx_http_upstream_module` configuration. + pub struct NgxHttpUpstreamModule; + + impl crate::http::HttpModule for NgxHttpUpstreamModule { + fn module() -> &'static crate::ffi::ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_upstream_module) } + } + } + unsafe impl crate::http::HttpModuleMainConf for NgxHttpUpstreamModule { + type MainConf = ngx_http_upstream_main_conf_t; + } + unsafe impl crate::http::HttpModuleServerConf for NgxHttpUpstreamModule { + type ServerConf = ngx_http_upstream_srv_conf_t; + } +} + +pub use upstream::NgxHttpUpstreamModule; + +#[cfg(ngx_feature = "http_v2")] +mod http_v2 { + use crate::ffi::{ngx_http_v2_module, ngx_http_v2_srv_conf_t}; + + /// Auxiliary structure to access `ngx_http_v2_module` configuration. + pub struct NgxHttpV2Module; + + impl crate::http::HttpModule for NgxHttpV2Module { + fn module() -> &'static crate::ffi::ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_v2_module) } + } + } + unsafe impl crate::http::HttpModuleServerConf for NgxHttpV2Module { + type ServerConf = ngx_http_v2_srv_conf_t; + } +} + +#[cfg(ngx_feature = "http_v2")] +pub use http_v2::NgxHttpV2Module; + +#[cfg(ngx_feature = "http_v3")] +mod http_v3 { + use crate::ffi::{ngx_http_v3_module, ngx_http_v3_srv_conf_t}; + + /// Auxiliary structure to access `ngx_http_v3_module` configuration. + pub struct NgxHttpV3Module; + + impl crate::http::HttpModule for NgxHttpV3Module { + fn module() -> &'static crate::ffi::ngx_module_t { + unsafe { &*::core::ptr::addr_of!(ngx_http_v3_module) } + } + } + unsafe impl crate::http::HttpModuleServerConf for NgxHttpV3Module { + type ServerConf = ngx_http_v3_srv_conf_t; + } +} + +#[cfg(ngx_feature = "http_v3")] +pub use http_v3::NgxHttpV3Module; diff --git a/src/http/module.rs b/src/http/module.rs index 6f25c97..858cf41 100644 --- a/src/http/module.rs +++ b/src/http/module.rs @@ -48,13 +48,9 @@ impl Merge for () { /// layers. /// /// See for details. -pub trait HTTPModule { - /// Configuration in the `http` block. - type MainConf: Merge + Default; - /// Configuration in a `server` block within the `http` block. - type SrvConf: Merge + Default; - /// Configuration in a `location` block within the `http` block. - type LocConf: Merge + Default; +pub trait HttpModule { + /// Returns reference to a global variable of type [ngx_module_t] created for this module. + fn module() -> &'static ngx_module_t; /// # Safety /// @@ -76,7 +72,11 @@ pub trait HTTPModule { /// /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must /// guard against null inputs or risk runtime errors. - unsafe extern "C" fn create_main_conf(cf: *mut ngx_conf_t) -> *mut c_void { + unsafe extern "C" fn create_main_conf(cf: *mut ngx_conf_t) -> *mut c_void + where + Self: super::HttpModuleMainConf, + Self::MainConf: Default, + { let mut pool = Pool::from_ngx_pool((*cf).pool); pool.allocate::(Default::default()) as *mut c_void } @@ -85,7 +85,11 @@ pub trait HTTPModule { /// /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must /// guard against null inputs or risk runtime errors. - unsafe extern "C" fn init_main_conf(_cf: *mut ngx_conf_t, _conf: *mut c_void) -> *mut c_char { + unsafe extern "C" fn init_main_conf(_cf: *mut ngx_conf_t, _conf: *mut c_void) -> *mut c_char + where + Self: super::HttpModuleMainConf, + Self::MainConf: Default, + { ptr::null_mut() } @@ -93,18 +97,26 @@ pub trait HTTPModule { /// /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must /// guard against null inputs or risk runtime errors. - unsafe extern "C" fn create_srv_conf(cf: *mut ngx_conf_t) -> *mut c_void { + unsafe extern "C" fn create_srv_conf(cf: *mut ngx_conf_t) -> *mut c_void + where + Self: super::HttpModuleServerConf, + Self::ServerConf: Default, + { let mut pool = Pool::from_ngx_pool((*cf).pool); - pool.allocate::(Default::default()) as *mut c_void + pool.allocate::(Default::default()) as *mut c_void } /// # Safety /// /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must /// guard against null inputs or risk runtime errors. - unsafe extern "C" fn merge_srv_conf(_cf: *mut ngx_conf_t, prev: *mut c_void, conf: *mut c_void) -> *mut c_char { - let prev = &mut *(prev as *mut Self::SrvConf); - let conf = &mut *(conf as *mut Self::SrvConf); + unsafe extern "C" fn merge_srv_conf(_cf: *mut ngx_conf_t, prev: *mut c_void, conf: *mut c_void) -> *mut c_char + where + Self: super::HttpModuleServerConf, + Self::ServerConf: Merge, + { + let prev = &mut *(prev as *mut Self::ServerConf); + let conf = &mut *(conf as *mut Self::ServerConf); match conf.merge(prev) { Ok(_) => ptr::null_mut(), Err(_) => NGX_CONF_ERROR as _, @@ -115,18 +127,26 @@ pub trait HTTPModule { /// /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must /// guard against null inputs or risk runtime errors. - unsafe extern "C" fn create_loc_conf(cf: *mut ngx_conf_t) -> *mut c_void { + unsafe extern "C" fn create_loc_conf(cf: *mut ngx_conf_t) -> *mut c_void + where + Self: super::HttpModuleLocationConf, + Self::LocationConf: Default, + { let mut pool = Pool::from_ngx_pool((*cf).pool); - pool.allocate::(Default::default()) as *mut c_void + pool.allocate::(Default::default()) as *mut c_void } /// # Safety /// /// Callers should provide valid non-null `ngx_conf_t` arguments. Implementers must /// guard against null inputs or risk runtime errors. - unsafe extern "C" fn merge_loc_conf(_cf: *mut ngx_conf_t, prev: *mut c_void, conf: *mut c_void) -> *mut c_char { - let prev = &mut *(prev as *mut Self::LocConf); - let conf = &mut *(conf as *mut Self::LocConf); + unsafe extern "C" fn merge_loc_conf(_cf: *mut ngx_conf_t, prev: *mut c_void, conf: *mut c_void) -> *mut c_char + where + Self: super::HttpModuleLocationConf, + Self::LocationConf: Merge, + { + let prev = &mut *(prev as *mut Self::LocationConf); + let conf = &mut *(conf as *mut Self::LocationConf); match conf.merge(prev) { Ok(_) => ptr::null_mut(), Err(_) => NGX_CONF_ERROR as _, diff --git a/src/http/request.rs b/src/http/request.rs index 66ded91..a9a66fc 100644 --- a/src/http/request.rs +++ b/src/http/request.rs @@ -1,5 +1,6 @@ use core::ffi::c_void; use core::fmt; +use core::ptr::NonNull; use core::slice; use core::str::FromStr; @@ -164,51 +165,6 @@ impl Request { unsafe { (*self.connection()).log } } - /// Global configuration for a module. - /// - /// Applies to the entire `http` block. - /// - /// # Safety - /// Caller must ensure that type `T` matches the configuration type for the specified module. - pub unsafe fn get_module_main_conf(&self, module: &ngx_module_t) -> Option<&'static T> { - // SAFETY: main conf is either NULL or allocated with ngx_p(c)alloc and - // explicitly initialized by the module - unsafe { - let scf = *self.0.main_conf.add(module.ctx_index); - scf.cast::().as_ref() - } - } - - /// Server-specific configuration for a module. - /// - /// Applies to a single `server` block. - /// - /// # Safety - /// Caller must ensure that type `T` matches the configuration type for the specified module. - pub unsafe fn get_module_srv_conf(&self, module: &ngx_module_t) -> Option<&'static T> { - // SAFETY: server conf is either NULL or allocated with ngx_p(c)alloc and - // explicitly initialized by the module - unsafe { - let scf = *self.0.srv_conf.add(module.ctx_index); - scf.cast::().as_ref() - } - } - - /// Location-specific configuration for a module. - /// - /// Applies to a signle `location`, `if` or `limit_except` block. - /// - /// # Safety - /// Caller must ensure that type `T` matches the configuration type for the specified module. - pub unsafe fn get_module_loc_conf(&self, module: &ngx_module_t) -> Option<&'static T> { - // SAFETY: location conf is either NULL or allocated with ngx_p(c)alloc and - // explicitly initialized by the module - unsafe { - let lcf = *self.0.loc_conf.add(module.ctx_index); - lcf.cast::().as_ref() - } - } - /// Get Module context pointer fn get_module_ctx_ptr(&self, module: &ngx_module_t) -> *mut c_void { unsafe { *self.0.ctx.add(module.ctx_index) } @@ -416,6 +372,29 @@ impl Request { } } +impl crate::http::HttpModuleConfExt for Request { + #[inline] + unsafe fn http_main_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + // SAFETY: main_conf[module.ctx_index] is either NULL or allocated with ngx_p(c)alloc and + // explicitly initialized by the module + NonNull::new((*self.0.main_conf.add(module.ctx_index)).cast()) + } + + #[inline] + unsafe fn http_server_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + // SAFETY: srv_conf[module.ctx_index] is either NULL or allocated with ngx_p(c)alloc and + // explicitly initialized by the module + NonNull::new((*self.0.srv_conf.add(module.ctx_index)).cast()) + } + + #[inline] + unsafe fn http_location_conf_unchecked(&self, module: &ngx_module_t) -> Option> { + // SAFETY: loc_conf[module.ctx_index] is either NULL or allocated with ngx_p(c)alloc and + // explicitly initialized by the module + NonNull::new((*self.0.loc_conf.add(module.ctx_index)).cast()) + } +} + // trait OnSubRequestDone { // }