Safe accessors for the module configuration
Closed this issue · 2 comments
There's a certain unsafe pattern that is repeated in most of the examples:
let co = unsafe { request.get_module_loc_conf::<ModuleConfig>(&*addr_of!(ngx_http_curl_module)) };
let co = co.expect("module config is none");
The problems here are:
ngx_http_curl_module
is a global mutable static, requiringunsafe
for any access.- Nothing guarantees that the type requested matches an actual type allocated for the module config.
Something we can optimize here is to tie config type to a context type and to a module ptr, and hide most of the unsafe details from end user.
E.g.
impl HttpLocationConf for ngx_http_core_module_t {
type ConfType = ngx_http_core_loc_conf_t;
fn module() -> &'static ngx_module_t { unsafe { &*addr_of!(ngx_http_core_module) } }
}
fn get_loc_conf<T: HttpLocationConf>(req) -> <T as HttpLocationConf>::ConfType;
req.get_loc_conf::<ngx_http_core_module_t>().ok_or(...)?;
or with an opposite direction of the mapping
impl HttpModuleConf for ngx_http_core_loc_conf_t {
const CONTEXT: &HttpModuleConfType = HttpModuleConfType::Location;
fn module() -> &'static ngx_module_t { unsafe { &*addr_of!(ngx_http_core_module) } }
}
fn get_conf<T: HttpModuleConf>(req) -> &T;
req.get_conf::<ngx_http_core_loc_conf_t>().ok_or(...)?;
Extending the ngx::http::module::HTTPModule
trait is also a viable option.
An important thing to consider is that the module configs can be obtained from ngx_cycle_t
, ngx_conf_t
, ngx_http_request_t
or ngx_http_upstream_t
objects and all of those should provide safe accessors.
Possible variation of this interface with functions bound to module itself and using request, event, etc as a parameter.
All names are just examples and may be changed as desired.
/// Trait to be implemented for request, upstream, event, and conf_t
trait HttpMainConf {
fn get_main_conf<T>(&self) -> Option<&T>;
}
/// Trait with config types and data
/// Should be implemented for each module including standard ones
trait ModuleConf {
type MainConf;
/// . . .
fn module() -> &'static ngx_module_t;
}
/// Trait for main config
/// Similar traits should be defined for server and location configs
/// Each module may implement only necessary traits
trait GetModuleConf<M> {
fn get_main_conf(o: & impl HttpMainConf) -> Option<&M::MainConf>;
}
/// usage with request
let r: &ngx_http_request_t;
let mcf = Module::get_main_conf(r);
I do not have strong opinion regarding where to implement traits, on module vs an object.
If there are no compelling arguments for module variant. I would prefer the initial proposal (impl HttpLocationConf for ngx_http_core_module_t
).