Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ targets = []
[dependencies]
allocator-api2 = { version = "0.2.21", default-features = false }
async-task = { version = "4.7.1", optional = true }
foreign-types = "0.5.0"
lock_api = "0.4.13"
nginx-sys = { path = "nginx-sys", version = "0.5.0-beta"}
pin-project-lite = { version = "0.2.16", optional = true }
Expand Down
4 changes: 2 additions & 2 deletions examples/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
use std::sync::{Arc, OnceLock};
use std::time::Instant;

use ngx::core;
use ngx::core::{self, ForeignTypeRef};
use ngx::ffi::{
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,
Expand Down Expand Up @@ -171,7 +171,7 @@ http_request_handler!(async_access_handler, |request: &mut http::Request| {
unsafe { ngx_post_event(&mut ctx.event, addr_of_mut!(ngx_posted_next_events)) };

// Request is no longer needed and can be converted to something movable to the async block
let req = AtomicPtr::new(request.into());
let req = AtomicPtr::new(request.as_ptr());
let done_flag = ctx.done.clone();

let rt = ngx_http_async_runtime();
Expand Down
4 changes: 2 additions & 2 deletions examples/upstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use std::ffi::{c_char, c_void};
use std::mem;

use ngx::core::{Pool, Status};
use ngx::core::{ForeignTypeRef, 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,
Expand Down Expand Up @@ -133,7 +133,7 @@ http_upstream_init_peer_pt!(
};

let original_init_peer = hccf.original_init_peer.unwrap();
if unsafe { original_init_peer(request.into(), us) != Status::NGX_OK.into() } {
if unsafe { original_init_peer(request.as_ptr(), us) != Status::NGX_OK.into() } {
return Status::NGX_ERROR;
}

Expand Down
2 changes: 2 additions & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub use slab::SlabPool;
pub use status::*;
pub use string::*;

pub use foreign_types::ForeignTypeRef;

/// Gets an outer object pointer from a pointer to one of its fields.
/// While there is no corresponding C macro, the pattern is common in the NGINX source.
///
Expand Down
105 changes: 49 additions & 56 deletions src/http/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,31 +89,10 @@ macro_rules! http_variable_get {
/// requests.
///
/// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
#[repr(transparent)]
pub struct Request(ngx_http_request_t);
pub struct Request(foreign_types::Opaque);

impl<'a> From<&'a Request> for *const ngx_http_request_t {
fn from(request: &'a Request) -> Self {
&request.0 as *const _
}
}

impl<'a> From<&'a mut Request> for *mut ngx_http_request_t {
fn from(request: &'a mut Request) -> Self {
&request.0 as *const _ as *mut _
}
}

impl AsRef<ngx_http_request_t> for Request {
fn as_ref(&self) -> &ngx_http_request_t {
&self.0
}
}

impl AsMut<ngx_http_request_t> for Request {
fn as_mut(&mut self) -> &mut ngx_http_request_t {
&mut self.0
}
unsafe impl foreign_types::ForeignTypeRef for Request {
type CType = ngx_http_request_t;
}

impl Request {
Expand All @@ -123,20 +102,30 @@ impl Request {
///
/// The caller has provided a valid non-null pointer to a valid `ngx_http_request_t`
/// which shares the same representation as `Request`.
#[inline]
pub unsafe fn from_ngx_http_request<'a>(r: *mut ngx_http_request_t) -> &'a mut Request {
&mut *r.cast::<Request>()
ForeignTypeRef::from_ptr_mut(r)
}

#[inline]
fn inner(&self) -> &ngx_http_request_t {
unsafe { &*self.as_ptr() }
}
#[inline]
fn inner_mut(&mut self) -> &mut ngx_http_request_t {
unsafe { &mut *self.as_ptr() }
}

/// Is this the main request (as opposed to a subrequest)?
pub fn is_main(&self) -> bool {
let main = self.0.main.cast();
let main = self.inner().main.cast();
core::ptr::eq(self, main)
}

/// Request pool.
pub fn pool(&self) -> Pool {
// SAFETY: This request is allocated from `pool`, thus must be a valid pool.
unsafe { Pool::from_ngx_pool(self.0.pool) }
unsafe { Pool::from_ngx_pool(self.inner().pool) }
}

/// Returns the result as an `Option` if it exists, otherwise `None`.
Expand All @@ -147,17 +136,17 @@ impl Request {
/// [`ngx_http_upstream_t`] is best described in
/// <https://nginx.org/en/docs/dev/development_guide.html#http_load_balancing>
pub fn upstream(&self) -> Option<*mut ngx_http_upstream_t> {
if self.0.upstream.is_null() {
if self.inner().upstream.is_null() {
return None;
}
Some(self.0.upstream)
Some(self.inner().upstream)
}

/// Pointer to a [`ngx_connection_t`] client connection object.
///
/// [`ngx_connection_t`]: https://nginx.org/en/docs/dev/development_guide.html#connection
pub fn connection(&self) -> *mut ngx_connection_t {
self.0.connection
self.inner().connection
}

/// Pointer to a [`ngx_log_t`].
Expand All @@ -169,7 +158,7 @@ impl Request {

/// 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) }
unsafe { *self.inner().ctx.add(module.ctx_index) }
}

/// Get Module context
Expand All @@ -183,9 +172,9 @@ impl Request {
/// Sets the value as the module's context.
///
/// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
pub fn set_module_ctx(&self, value: *mut c_void, module: &ngx_module_t) {
pub fn set_module_ctx(&mut self, value: *mut c_void, module: &ngx_module_t) {
unsafe {
*self.0.ctx.add(module.ctx_index) = value;
*self.inner_mut().ctx.add(module.ctx_index) = value;
};
}

Expand All @@ -210,77 +199,81 @@ impl Request {
///
/// [request body]: https://nginx.org/en/docs/dev/development_guide.html#http_request_body
pub fn discard_request_body(&mut self) -> Status {
unsafe { Status(ngx_http_discard_request_body(&mut self.0)) }
unsafe { Status(ngx_http_discard_request_body(self.as_ptr())) }
}

/// Client HTTP [User-Agent].
///
/// [User-Agent]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
pub fn user_agent(&self) -> Option<&NgxStr> {
if !self.0.headers_in.user_agent.is_null() {
unsafe { Some(NgxStr::from_ngx_str((*self.0.headers_in.user_agent).value)) }
if !self.inner().headers_in.user_agent.is_null() {
unsafe {
Some(NgxStr::from_ngx_str(
(*self.inner().headers_in.user_agent).value,
))
}
} else {
None
}
}

/// Set HTTP status of response.
pub fn set_status(&mut self, status: HTTPStatus) {
self.0.headers_out.status = status.into();
self.inner_mut().headers_out.status = status.into();
}

/// Add header to the `headers_in` object.
///
/// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
pub fn add_header_in(&mut self, key: &str, value: &str) -> Option<()> {
let table: *mut ngx_table_elt_t =
unsafe { ngx_list_push(&mut self.0.headers_in.headers) as _ };
unsafe { add_to_ngx_table(table, self.0.pool, key, value) }
unsafe { ngx_list_push(&mut self.inner_mut().headers_in.headers) as _ };
unsafe { add_to_ngx_table(table, self.inner().pool, key, value) }
}

/// Add header to the `headers_out` object.
///
/// See <https://nginx.org/en/docs/dev/development_guide.html#http_request>
pub fn add_header_out(&mut self, key: &str, value: &str) -> Option<()> {
let table: *mut ngx_table_elt_t =
unsafe { ngx_list_push(&mut self.0.headers_out.headers) as _ };
unsafe { add_to_ngx_table(table, self.0.pool, key, value) }
unsafe { ngx_list_push(&mut self.inner_mut().headers_out.headers) as _ };
unsafe { add_to_ngx_table(table, self.inner().pool, key, value) }
}

/// Set response body [Content-Length].
///
/// [Content-Length]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length
pub fn set_content_length_n(&mut self, n: usize) {
self.0.headers_out.content_length_n = n as off_t;
self.inner_mut().headers_out.content_length_n = n as off_t;
}

/// Send the output header.
///
/// Do not call this function until all output headers are set.
pub fn send_header(&mut self) -> Status {
unsafe { Status(ngx_http_send_header(&mut self.0)) }
unsafe { Status(ngx_http_send_header(self.as_ptr())) }
}

/// Flag indicating that the output does not require a body.
///
/// For example, this flag is used by `HTTP HEAD` requests.
pub fn header_only(&self) -> bool {
self.0.header_only() != 0
self.inner().header_only() != 0
}

/// request method
pub fn method(&self) -> Method {
Method::from_ngx(self.0.method)
Method::from_ngx(self.inner().method)
}

/// path part of request only
pub fn path(&self) -> &NgxStr {
unsafe { NgxStr::from_ngx_str(self.0.uri) }
unsafe { NgxStr::from_ngx_str(self.inner().uri) }
}

/// full uri - containing path and args
pub fn unparsed_uri(&self) -> &NgxStr {
unsafe { NgxStr::from_ngx_str(self.0.unparsed_uri) }
unsafe { NgxStr::from_ngx_str(self.inner().unparsed_uri) }
}

/// Send the [response body].
Expand All @@ -290,13 +283,13 @@ impl Request {
///
/// [response body]: https://nginx.org/en/docs/dev/development_guide.html#http_request_body
pub fn output_filter(&mut self, body: &mut ngx_chain_t) -> Status {
unsafe { Status(ngx_http_output_filter(&mut self.0, body)) }
unsafe { Status(ngx_http_output_filter(self.as_ptr(), body)) }
}

/// Perform internal redirect to a location
pub fn internal_redirect(&self, location: &str) -> Status {
assert!(!location.is_empty(), "uri location is empty");
let uri_ptr = unsafe { &mut ngx_str_t::from_str(self.0.pool, location) as *mut _ };
let uri_ptr = unsafe { &mut ngx_str_t::from_str(self.inner().pool, location) as *mut _ };

// FIXME: check status of ngx_http_named_location or ngx_http_internal_redirect
if location.starts_with('@') {
Expand Down Expand Up @@ -326,7 +319,7 @@ impl Request {
ngx_int_t,
) -> ngx_int_t,
) -> Status {
let uri_ptr = unsafe { &mut ngx_str_t::from_str(self.0.pool, uri) as *mut _ };
let uri_ptr = unsafe { &mut ngx_str_t::from_str(self.inner().pool, uri) as *mut _ };
// -------------
// allocate memory and set values for ngx_http_post_subrequest_t
let sub_ptr = self
Expand Down Expand Up @@ -377,13 +370,13 @@ impl Request {
/// Iterate over headers_in
/// each header item is (&str, &str) (borrowed)
pub fn headers_in_iterator(&self) -> NgxListIterator<'_> {
unsafe { list_iterator(&self.0.headers_in.headers) }
unsafe { list_iterator(&self.inner().headers_in.headers) }
}

/// Iterate over headers_out
/// each header item is (&str, &str) (borrowed)
pub fn headers_out_iterator(&self) -> NgxListIterator<'_> {
unsafe { list_iterator(&self.0.headers_out.headers) }
unsafe { list_iterator(&self.inner().headers_out.headers) }
}
}

Expand All @@ -392,21 +385,21 @@ impl crate::http::HttpModuleConfExt for Request {
unsafe fn http_main_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
// 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())
NonNull::new((*self.inner().main_conf.add(module.ctx_index)).cast())
}

#[inline]
unsafe fn http_server_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
// 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())
NonNull::new((*self.inner().srv_conf.add(module.ctx_index)).cast())
}

#[inline]
unsafe fn http_location_conf_unchecked<T>(&self, module: &ngx_module_t) -> Option<NonNull<T>> {
// 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())
NonNull::new((*self.inner().loc_conf.add(module.ctx_index)).cast())
}
}

Expand All @@ -417,7 +410,7 @@ impl crate::http::HttpModuleConfExt for Request {
impl fmt::Debug for Request {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Request")
.field("request_", &self.0)
.field("request_", &self.inner())
.finish()
}
}
Expand Down
Loading