Skip to content

Commit

Permalink
Header handling (#5)
Browse files Browse the repository at this point in the history
* Added HeadersOut and functions to add, set and remove headers.

* Add http phase handler for any phase.
  • Loading branch information
gabioprisan authored Jun 13, 2024
1 parent 77ef3ab commit e808984
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 5 deletions.
94 changes: 89 additions & 5 deletions nginx_module/src/http_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,17 @@ pub struct HttpRequestAndContext<'a, Ctx>(ngx_http_request_t, PhantomData<&'a Ct
pub struct HttpRequest<'a>(ngx_http_request_t, PhantomData<&'a ()>);

pub struct HeadersIn<'a>(ngx_http_headers_in_t, PhantomData<&'a ()>);
pub struct HeadersInIter<'a> {
pub struct HeadersOut<'a>(ngx_http_headers_out_t, PhantomData<&'a ()>);

pub struct HeaderList<'a>(ngx_list_t, PhantomData<&'a ()>);

pub struct HeadersIter<'a> {
part: *const ngx_list_part_t,
elt_idx: usize,
_phantom: PhantomData<&'a ()>,
}


impl<'a, Ctx: Default> HttpRequestAndContext<'a, Ctx> {
///
/// # Safety
Expand Down Expand Up @@ -261,6 +266,18 @@ impl<'a> HttpRequest<'a> {
unsafe { &*(&self.0.headers_in as *const ngx_http_headers_in_t as *const HeadersIn) }
}

pub fn headers_in_mut(&mut self) -> &mut HeadersIn<'a> {
unsafe { &mut *(&mut self.0.headers_in as *mut ngx_http_headers_in_t as *mut HeadersIn) }
}

pub fn headers_out(&self) -> &HeadersOut<'a> {
unsafe { &*(&self.0.headers_out as *const ngx_http_headers_out_t as *const HeadersOut) }
}

pub fn headers_out_mut(&mut self) -> &mut HeadersOut<'a> {
unsafe { &mut *(&mut self.0.headers_out as *mut ngx_http_headers_out_t as *mut HeadersOut) }
}

// TODO:esavier its not named uri but it returns only path
// TODO:consider either helper or change results to Strings
pub fn unparsed_uri(&self) -> NgxStr {
Expand Down Expand Up @@ -523,17 +540,82 @@ impl<'a> HttpRequest<'a> {
}
}

impl<'a> HeadersIn<'a> {
pub fn iter(&self) -> HeadersInIter<'a> {
HeadersInIter {
impl<'a> HeaderList<'a> {
pub fn iter(&self) -> HeadersIter<'a> {
HeadersIter {
part: &self.0.part,
elt_idx: 0,
_phantom: PhantomData,
}
}

pub fn set(&mut self, name: NgxStr<'a>, value: NgxStr<'a>) {
let mut part_opt = Some(&mut self.0.part);
while let Some(part) = part_opt {
let elems = unsafe { std::slice::from_raw_parts_mut(part.elts as *mut ngx_table_elt_t, part.nelts) };
for elem in elems {
if unsafe { NgxStr::from_raw(elem.key) } == name {
elem.value = value.inner();
}
}
part_opt = unsafe { part.next.as_mut() };
}
}


pub fn add(&mut self, name: NgxStr<'a>, value: NgxStr<'a>) -> anyhow::Result<()> {
let h = unsafe { (ngx_list_push(&mut self.0) as *mut ngx_table_elt_t).as_mut().ok_or_else(|| anyhow::anyhow!("Cannot push to header list"))? };
h.hash = 1;
h.key = name.inner();
h.value = value.inner();
Ok(())
}

pub fn remove(&mut self, name: NgxStr<'a>) {
self.set(name, NgxStr::null())
}
}

impl<'a> Deref for HeadersIn<'a> {
type Target = HeaderList<'a>;

fn deref(&self) -> &Self::Target {
unsafe { &*(&self.0.headers as *const ngx_list_t as *const HeaderList<'a>) }
}
}

impl<'a> DerefMut for HeadersIn<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(&mut self.0.headers as *mut ngx_list_t as *mut HeaderList<'a>) }
}
}

impl<'a> Deref for HeadersOut<'a> {
type Target = HeaderList<'a>;

fn deref(&self) -> &Self::Target {
unsafe { &*(&self.0.headers as *const ngx_list_t as *const HeaderList<'a>) }
}
}

impl<'a> DerefMut for HeadersOut<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(&mut self.0.headers as *mut ngx_list_t as *mut HeaderList<'a>) }
}
}

impl<'a> HeadersOut<'a> {
pub fn iter(&self) -> HeadersIter<'a> {
HeadersIter {
part: &self.0.headers.part,
elt_idx: 0,
_phantom: PhantomData,
}
}

}

impl<'a> Iterator for HeadersInIter<'a> {
impl<'a> Iterator for HeadersIter<'a> {
type Item = (NgxStr<'a>, NgxStr<'a>);

fn next(&mut self) -> Option<Self::Item> {
Expand Down Expand Up @@ -563,3 +645,5 @@ impl<'a> Iterator for HeadersInIter<'a> {
}
}
}


43 changes: 43 additions & 0 deletions nginx_module/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ pub use bindings::{
use bindings::{
ngx_array_push, ngx_cycle, ngx_event_t, ngx_event_timer_rbtree, ngx_http_core_main_conf_t,
ngx_http_core_module, ngx_http_handler_pt, ngx_http_phases_NGX_HTTP_ACCESS_PHASE,
ngx_http_phases_NGX_HTTP_CONTENT_PHASE, ngx_http_phases_NGX_HTTP_FIND_CONFIG_PHASE,
ngx_http_phases_NGX_HTTP_LOG_PHASE, ngx_http_phases_NGX_HTTP_POST_ACCESS_PHASE,
ngx_http_phases_NGX_HTTP_POST_READ_PHASE, ngx_http_phases_NGX_HTTP_POST_REWRITE_PHASE,
ngx_http_phases_NGX_HTTP_PREACCESS_PHASE, ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE,
ngx_http_phases_NGX_HTTP_REWRITE_PHASE, ngx_http_phases_NGX_HTTP_SERVER_REWRITE_PHASE,
ngx_http_top_request_body_filter, ngx_queue_t, ngx_rbtree_delete, ngx_rbtree_insert,
};

Expand Down Expand Up @@ -286,6 +291,21 @@ pub trait HttpRequestBodyHandler<'a>: Sized {
) -> anyhow::Result<isize>;
}

#[repr(usize)]
pub enum NginxPhase {
PostRead = ngx_http_phases_NGX_HTTP_POST_READ_PHASE as usize,
ServerRewrite = ngx_http_phases_NGX_HTTP_SERVER_REWRITE_PHASE as usize,
FindConfig = ngx_http_phases_NGX_HTTP_FIND_CONFIG_PHASE as usize,
Rewrite = ngx_http_phases_NGX_HTTP_REWRITE_PHASE as usize,
PostRewrite = ngx_http_phases_NGX_HTTP_POST_REWRITE_PHASE as usize,
PreAccess = ngx_http_phases_NGX_HTTP_PREACCESS_PHASE as usize,
Access = ngx_http_phases_NGX_HTTP_ACCESS_PHASE as usize,
PostAccess = ngx_http_phases_NGX_HTTP_POST_ACCESS_PHASE as usize,
PreContent = ngx_http_phases_NGX_HTTP_PRECONTENT_PHASE as usize,
Content = ngx_http_phases_NGX_HTTP_CONTENT_PHASE as usize,
Log = ngx_http_phases_NGX_HTTP_LOG_PHASE as usize,
}

///
/// # Safety
///
Expand Down Expand Up @@ -333,6 +353,29 @@ unsafe extern "C" fn ngx_http_generic_handler<'a, H: HttpHandler<'a> + Default +
}
}

///
/// # Safety
///
/// `conf` should be a valid ngx_conf_t pointer
///
pub unsafe fn add_http_phase_handler<'a, H: HttpHandler<'a> + Default + 'a>(
conf: *mut ngx_conf_t,
phase: NginxPhase,
) -> isize {
let cmcf = (*(*((*conf).ctx as *mut ngx_http_conf_ctx_t))
.main_conf
.add(ngx_http_core_module.ctx_index)) as *mut ngx_http_core_main_conf_t;

let h =
ngx_array_push(&mut (*cmcf).phases[phase as usize].handlers) as *mut ngx_http_handler_pt;
if h.is_null() {
NGX_ERROR as isize
} else {
*h = Some(ngx_http_generic_handler::<H>);
NGX_OK as isize
}
}

pub fn add_request_body_handler<'a, H: HttpRequestBodyHandler<'a> + Default + 'a>() {
unsafe {
if let Ok(mut handler) = H::next_handler().lock() {
Expand Down

0 comments on commit e808984

Please sign in to comment.