Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safer interface for module configuration access. #142

Merged
merged 1 commit into from
Mar 26, 2025

Conversation

ensh63
Copy link
Contributor

@ensh63 ensh63 commented Mar 19, 2025

Proposed changes

Safer interface for module configuration access; this PR resolves #105.

Public objects added for several standard HTTP modules from nginx: core, SSL, upstream, HTTP V2, and HTTP V3. New public traits are defined for each module configuration type (main, server, location) and appropriate access functions. These traits are implemented for HTTP module objects mentioned above. New modules should implement necessary traits to use new configuration interface.

New internal trait HttpModuleConfExt is defined to access configuration data in nginx types. It is implemented for ngx_cycle_t, ngx_conf_t, ngx_http_core_srv_conf_t, ngx_http_request_t, ngx_http_upstream_srv_conf_t, and for Rust shell type ngx::http::Request.

Original version was prepared by Aleksei Bavshin

Changes required to access configuration from standard HTTP modules

Sample changes needed to get main configuration of core module are shown below:

  • old code:
use ngx::ffi::ngx_http_core_module;
. . .
let cmcf: *mut ngx_http_core_main_conf_t = http::ngx_http_conf_get_module_main_conf(cf, &*addr_of!(ngx_http_core_module));
  • new code:
use ngx::http::NgxHttpCoreModule;
. . .
let cf = &mut *cf;
let cmcf: &mut ngx_http_core_main_conf_t = NgxHttpCoreModule::main_conf_mut(cf).expect("http core main conf");

Note that the type of cmcf variable changed from * mut ngx_http_core_main_conf_t to &mut ngx_http_core_main_conf_t.

These changes can be viewed in any module in examples.

Changes necessary to use new interface in Rust modules

  • New required method added to http::HttpModule. It shall be implemented for each module:
pub static mut ngx_http_some_new_module: ngx_module_t = ...;
. . .
struct Module;

impl http::HttpModule for Module {
    fn module() -> &'static ngx_module_t {
        unsafe { &*::core::ptr::addr_of!(ngx_http_some_new_module) }
    }
    . . .
}
  • Trait to implement for new module with configuration type:
#[derive(Debug, Default)]
struct ModuleConfig {
    enable: bool,
}

unsafe impl HttpModuleLocationConf for Module {
    type LocationConf = ModuleConfig;
}

Similar traits can be defined for main and server-specific configurations.

  • Changes in configuration access code:
    • old code:
      let co = unsafe { request.get_module_loc_conf::<ModuleConfig>(&*addr_of!(ngx_http_some_new_module)) };
      let co = co.expect("module config is none");  
    • new code:
      let co = Module::location_conf(request).expect("module config is none");

@ensh63 ensh63 force-pushed the conf-safety branch 2 times, most recently from 414e1e7 to 90eab04 Compare March 19, 2025 23:55
@ensh63 ensh63 changed the title wip: safer interface for module configuration access Safer interface for module configuration access Mar 20, 2025
@ensh63 ensh63 force-pushed the conf-safety branch 2 times, most recently from d82c211 to 22547da Compare March 21, 2025 01:02
Copy link
Contributor

@xeioex xeioex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the changes in the examples.

Looks good to me.

@bavshin-f5
Copy link
Member

  • NgxHttpSSLModule -> NgxHttpSslModule (https://rust-lang.github.io/api-guidelines/naming.html: In UpperCamelCase, acronyms and contractions of compound words count as one word: use Uuid rather than UUID, Usize rather than USize or Stdin rather than StdIn)
  • Please, add HttpModuleConfExt implementations for ngx_http_core_srv_conf_t and ngx_http_request_t.
  • HttpModuleConfExt can be simplified to 3 methods returning Option<NonNull<T>>, with no downsides for the safety or generated code (see https://gcc.godbolt.org/z/9Gv6WdacW with opt-level=1 or 2).
  • Methods of HttpModuleConfExt and its implementations can be marked as #[inline].

Copy link
Member

@bavshin-f5 bavshin-f5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're still following the conventional commits spec, please mark the commit as breaking by changing prefix to refactor!:.

Please, also add some description and migration guide for all the breaking changes to the commit message.

@ensh63
Copy link
Contributor Author

ensh63 commented Mar 25, 2025

  • NgxHttpSSLModule -> NgxHttpSslModule (https://rust-lang.github.io/api-guidelines/naming.html: In UpperCamelCase, acronyms and contractions of compound words count as one word: use Uuid rather than UUID, Usize rather than USize or Stdin rather than StdIn)

    • Please, add HttpModuleConfExt implementations for ngx_http_core_srv_conf_t and ngx_http_request_t.

    • HttpModuleConfExt can be simplified to 3 methods returning Option<NonNull<T>>, with no downsides for the safety or generated code (see https://gcc.godbolt.org/z/9Gv6WdacW with opt-level=1 or 2).

    • Methods of HttpModuleConfExt and its implementations can be marked as #[inline].

Done as requested. One remark: should we keep two almost identical implementations of HttpModuleConfExt for ngx_http_request_t and Request? It is possible to use Request::as_ref<ngx_http_request_t>() if needed.

@ensh63 ensh63 changed the title Safer interface for module configuration access Safer interface for module configuration access; closes #105. Mar 25, 2025
@ensh63 ensh63 changed the title Safer interface for module configuration access; closes #105. Safer interface for module configuration access. Mar 25, 2025
@ensh63 ensh63 force-pushed the conf-safety branch 2 times, most recently from be6dd4e to 9a62461 Compare March 25, 2025 23:06
* original version was prepared by Aleksei Bavshin
@bavshin-f5
Copy link
Member

bavshin-f5 commented Mar 26, 2025

Breaking changes:

  1. trait ngx::http::HTTPModule has been renamed to HttpModule.

  2. HttpModule trait has a new required method
    fn module() -> &'static ngx_module_t, returning a reference to the
    static ngx_module_t global for the current module.
    Example implementation:

    pub static mut ngx_http_some_new_module: ngx_module_t = ...;
    . . .
    struct Module;
    
    impl http::HttpModule for Module {
        fn module() -> &'static ngx_module_t {
            unsafe { &*::core::ptr::addr_of!(ngx_http_some_new_module) }
        }
        . . .
    }
  3. HttpModule associated types (MainConf, SrvConf, LocConf) have been extracted to a separate set of unsafe traits:
    HttpModuleMainConf::MainConf, HttpModuleServerConf::ServerConf, HttpModuleLocationConf::LocationConf.
    You only need to define these traits when the corresponding types exist in your module.

    #[derive(Debug, Default)]
    struct MainConfig {
        . . .
    }
    
    // SAFETY: with the default Module::create_main_conf handler being used,
    // the main configuration will be initialized as an instance of `MainConfig`
    unsafe impl HttpModuleMainConf for Module {
        type MainConf = MainConfig;
    }
    
    #[derive(Debug, Default)]
    struct ModuleConfig {
        enable: bool,
    }
    
    // SAFETY: with the default Module::create_location_conf handler being used,
    // the main configuration will be initialized as an instance of `ModuleConfig`
    unsafe impl HttpModuleLocationConf for Module {
        type LocationConf = ModuleConfig;
    }
  4. HttpModule::* static methods for creating, initializing and merging configuration types are now available only if the corresponding types are defined via traits above; you need to skip the methods or add your own callbacks when creating ngx_http_module_t global:

    static NGX_HTTP_SOME_NEW_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: None, // no server configuration, HttpModuleServerConf is not implemented
        merge_srv_conf: None, 
        create_loc_conf: Some(Module::create_loc_conf),
        merge_loc_conf: Some(Module::merge_loc_conf),
    };
  5. ngx::http::Request::get_module_x_conf methods were removed.
    The recommended way to access the module configuration structures now is as following:

    use ngx::http::{HttpModuleLocationConf, HttpModuleMainConf};
    
    // returns &<Module as HttpModuleLocationConf>::LocationConf
    let lcf = Module::location_conf(r).expect("module location configuration");
    // returns &mut <Module as HttpModuleMainConf>::MainConf
    let mcf = Module::main_conf_mut(r).expect("module main configuration");

    Anything that allows access to the module configuration structures and implements ngx::http::HttpModuleConfExt can be passed as an argument:
    ngx::http::Request, ngx_cycle_t, ngx_conf_t, ngx_http_core_srv_conf_t, ngx_http_request_t, ngx_http_upstream_srv_conf_t.

    To simplify interaction with the core nginx modules, the following set of types has been implemented:

    use ngx::http::HttpModuleMainConf;
    use ngx::http::{NgxHttpCoreModule, NgxHttpSslModule, NgxHttpUpstreamModule, NgxHttpV2Module, NgxHttpV3Module};
    
    // SAFETY: cf is always valid non-null pointer in configuration handlers
    let cf = unsafe { cf.as_ref().expect("") };
    let cmcf = NgxHttpCoreModule::main_conf_mut(cf).expect("http core global configuration");

    HttpModuleConfExt methods also allow accessing module configuration in a less safe way:

    use nginx_sys::{ngx_http_core_main_conf_t, ngx_http_core_module};
    use ngx::http::HttpModuleConfExt;
    
    let cmcf = unsafe {
        (*cf).http_main_conf_unchecked::<ngx_http_core_main_conf_t>(&*::core::ptr::addr_of!(ngx_http_core_module))
    };
  6. ngx_http_conf_get_module_loc_conf and ngx_http_conf_upstream_srv_conf_(im)mutable functions were removed; see above for the replacement.

@bavshin-f5 bavshin-f5 merged commit b6e80fc into nginx:master Mar 26, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Safe accessors for the module configuration
3 participants