Skip to content

Commit 2ce09ab

Browse files
committed
feat: request handler trait
1 parent 9bfaba3 commit 2ce09ab

File tree

3 files changed

+126
-32
lines changed

3 files changed

+126
-32
lines changed

examples/curl.rs

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,21 @@ use std::ffi::{c_char, c_void};
22

33
use ngx::core;
44
use ngx::ffi::{
5-
ngx_array_push, ngx_command_t, ngx_conf_t, ngx_http_handler_pt, ngx_http_module_t,
6-
ngx_http_phases_NGX_HTTP_ACCESS_PHASE, ngx_int_t, ngx_module_t, ngx_str_t, ngx_uint_t,
5+
ngx_command_t, ngx_conf_t, ngx_http_module_t, ngx_int_t, ngx_module_t, ngx_str_t, ngx_uint_t,
76
NGX_CONF_TAKE1, NGX_HTTP_LOC_CONF, NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_MODULE, NGX_LOG_EMERG,
87
};
9-
use ngx::http::{self, HttpModule, MergeConfigError};
10-
use ngx::http::{HttpModuleLocationConf, HttpModuleMainConf, NgxHttpCoreModule};
11-
use ngx::{http_request_handler, ngx_conf_log_error, ngx_log_debug_http, ngx_string};
8+
use ngx::http::{self, HttpModule, HttpModuleLocationConf, HttpRequestHandler, MergeConfigError};
9+
use ngx::{ngx_conf_log_error, ngx_log_debug_http, ngx_string};
1210

1311
struct Module;
1412

1513
impl http::HttpModule for Module {
1614
fn module() -> &'static ngx_module_t {
1715
unsafe { &*::core::ptr::addr_of!(ngx_http_curl_module) }
1816
}
19-
2017
unsafe extern "C" fn postconfiguration(cf: *mut ngx_conf_t) -> ngx_int_t {
21-
// SAFETY: this function is called with non-NULL cf always
22-
let cf = &mut *cf;
23-
let cmcf = NgxHttpCoreModule::main_conf_mut(cf).expect("http core main conf");
24-
25-
let h = ngx_array_push(
26-
&mut cmcf.phases[ngx_http_phases_NGX_HTTP_ACCESS_PHASE as usize].handlers,
27-
) as *mut ngx_http_handler_pt;
28-
if h.is_null() {
29-
return core::Status::NGX_ERROR.into();
30-
}
31-
// set an Access phase handler
32-
*h = Some(curl_access_handler);
18+
let cf = unsafe { &mut *cf };
19+
CurlRequestHandler::register(cf);
3320
core::Status::NGX_OK.into()
3421
}
3522
}
@@ -90,25 +77,32 @@ impl http::Merge for ModuleConfig {
9077
}
9178
}
9279

93-
http_request_handler!(curl_access_handler, |request: &mut http::Request| {
94-
let co = Module::location_conf(request).expect("module config is none");
80+
struct CurlRequestHandler;
81+
82+
impl HttpRequestHandler<Option<ngx_int_t>> for CurlRequestHandler {
83+
const PHASE: nginx_sys::NgxHttpPhases = nginx_sys::NgxHttpPhases::Access;
84+
type Module = Module;
9585

96-
ngx_log_debug_http!(request, "curl module enabled: {}", co.enable);
86+
fn handler(request: &mut http::Request) -> Option<ngx_int_t> {
87+
let co = Module::location_conf(request).expect("module config is none");
9788

98-
match co.enable {
99-
true => {
100-
if request
101-
.user_agent()
102-
.is_some_and(|ua| ua.as_bytes().starts_with(b"curl"))
103-
{
104-
http::HTTPStatus::FORBIDDEN.into()
105-
} else {
106-
core::NGX_O_DECLINED
89+
ngx_log_debug_http!(request, "curl module enabled: {}", co.enable);
90+
91+
match co.enable {
92+
true => {
93+
if request
94+
.user_agent()
95+
.is_some_and(|ua| ua.as_bytes().starts_with(b"curl"))
96+
{
97+
http::HTTPStatus::FORBIDDEN.into()
98+
} else {
99+
core::NGX_O_DECLINED
100+
}
107101
}
102+
false => core::NGX_O_DECLINED,
108103
}
109-
false => core::NGX_O_DECLINED,
110104
}
111-
});
105+
}
112106

113107
extern "C" fn ngx_http_curl_commands_set_enable(
114108
cf: *mut ngx_conf_t,

nginx-sys/src/http.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,30 @@ pub const NGX_HTTP_SRV_CONF_OFFSET: usize = offset_of!(ngx_http_conf_ctx_t, srv_
1616
///
1717
/// This is used to access the location configuration context for an HTTP module.
1818
pub const NGX_HTTP_LOC_CONF_OFFSET: usize = offset_of!(ngx_http_conf_ctx_t, loc_conf);
19+
20+
/// HTTP phases in which a module can register handlers.
21+
#[repr(u32)]
22+
pub enum NgxHttpPhases {
23+
/// Post-read phase
24+
PostRead = crate::ngx_http_phases_NGX_HTTP_POST_READ_PHASE,
25+
/// Server rewrite phase
26+
ServerRewrite = crate::ngx_http_phases_NGX_HTTP_SERVER_REWRITE_PHASE,
27+
/// Find configuration phase
28+
FindConfig = crate::ngx_http_phases_NGX_HTTP_FIND_CONFIG_PHASE,
29+
/// Rewrite phase
30+
Rewrite = crate::ngx_http_phases_NGX_HTTP_REWRITE_PHASE,
31+
/// Post-rewrite phase
32+
PostRewrite = crate::ngx_http_phases_NGX_HTTP_POST_REWRITE_PHASE,
33+
/// Pre-access phase
34+
Preaccess = crate::ngx_http_phases_NGX_HTTP_PREACCESS_PHASE,
35+
/// Access phase
36+
Access = crate::ngx_http_phases_NGX_HTTP_ACCESS_PHASE,
37+
/// Post-access phase
38+
PostAccess = crate::ngx_http_phases_NGX_HTTP_POST_ACCESS_PHASE,
39+
/// Pre-content phase
40+
PreContent = crate::ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE,
41+
/// Content phase
42+
Content = crate::ngx_http_phases_NGX_HTTP_CONTENT_PHASE,
43+
/// Log phase
44+
Log = crate::ngx_http_phases_NGX_HTTP_LOG_PHASE,
45+
}

src/http/request.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use allocator_api2::alloc::Allocator;
1010
use crate::core::*;
1111
use crate::ffi::*;
1212
use crate::http::status::*;
13+
use crate::http::{HttpModule, HttpModuleMainConf, NgxHttpCoreModule};
1314

1415
/// Define a static request handler.
1516
///
@@ -89,6 +90,78 @@ macro_rules! http_variable_get {
8990
};
9091
}
9192

93+
/// Trait for static request handler.
94+
/// Predefined return types are `Option<ngx_int_t>`
95+
/// and `Result<ngx_int_t, E>` where `E: ::core::error::Error`.
96+
/// Handler with `Result<ngx_int_t, E>` return type logs the error message automatically.
97+
pub trait HttpRequestHandler<ReturnType> {
98+
/// The phase in which the handler is invoked
99+
const PHASE: NgxHttpPhases;
100+
/// The module to which the handler belongs
101+
type Module: HttpModule;
102+
103+
/// The handler function
104+
fn handler(request: &mut Request) -> ReturnType;
105+
/// Register a request handler for a specified phase.
106+
/// This function must be called from the module's `postconfiguration()` function.
107+
fn register(cf: &mut ngx_conf_t) -> bool
108+
where
109+
Self: HttpHandlerWrapper<ReturnType>,
110+
{
111+
let cmcf = NgxHttpCoreModule::main_conf_mut(cf).expect("http core main conf");
112+
let h: *mut ngx_http_handler_pt =
113+
unsafe { ngx_array_push(&mut cmcf.phases[Self::PHASE as usize].handlers) as _ };
114+
if h.is_null() {
115+
return false;
116+
}
117+
// set an H::PHASE phase handler
118+
unsafe {
119+
*h = Some(Self::handler_wrapper);
120+
}
121+
true
122+
}
123+
}
124+
125+
/// Trait for wrapping a request handler with a C-compatible function.
126+
pub trait HttpHandlerWrapper<ReturnType>: HttpRequestHandler<ReturnType> {
127+
/// Convert the handler return type to `ngx_int_t`.
128+
fn convert(r: &Request, res: ReturnType) -> ngx_int_t;
129+
/// The C-compatible handler wrapper function.
130+
///
131+
/// # Safety
132+
///
133+
/// The caller has provided a valid non-null pointer to an `ngx_http_request_t`.
134+
unsafe extern "C" fn handler_wrapper(r: *mut ngx_http_request_t) -> ngx_int_t {
135+
let r = unsafe { Request::from_ngx_http_request(r) };
136+
let res = Self::handler(r);
137+
Self::convert(r, res)
138+
}
139+
}
140+
141+
/// Implementation of `HttpHandlerWrapper` for `Option<ngx_int_t>`.
142+
impl<T> HttpHandlerWrapper<Option<ngx_int_t>> for T
143+
where
144+
T: HttpRequestHandler<Option<ngx_int_t>>,
145+
{
146+
fn convert(_r: &Request, res: Option<ngx_int_t>) -> ngx_int_t {
147+
res.unwrap_or(NGX_ERROR as _)
148+
}
149+
}
150+
151+
/// Implementation of `HttpHandlerWrapper` for `Result<ngx_int_t, E>`.
152+
impl<T, E> HttpHandlerWrapper<Result<ngx_int_t, E>> for T
153+
where
154+
T: HttpRequestHandler<Result<ngx_int_t, E>>,
155+
E: ::core::error::Error,
156+
{
157+
fn convert(r: &Request, res: Result<ngx_int_t, E>) -> ngx_int_t {
158+
res.unwrap_or_else(|err| {
159+
crate::ngx_log_error!(NGX_LOG_ERR, r.log(), "{err}");
160+
NGX_ERROR as _
161+
})
162+
}
163+
}
164+
92165
/// Wrapper struct for an [`ngx_http_request_t`] pointer, providing methods for working with HTTP
93166
/// requests.
94167
///

0 commit comments

Comments
 (0)