Skip to content
Merged
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
4 changes: 2 additions & 2 deletions examples/httporigdst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl Default for NgxHttpOrigDstCtx {

impl NgxHttpOrigDstCtx {
pub fn save(&mut self, addr: &str, port: in_port_t, pool: &mut core::Pool) -> core::Status {
let addr_data = pool.alloc(addr.len());
let addr_data = pool.alloc_unaligned(addr.len());
if addr_data.is_null() {
return core::Status::NGX_ERROR;
}
Expand All @@ -37,7 +37,7 @@ impl NgxHttpOrigDstCtx {
self.orig_dst_addr.data = addr_data as *mut u8;

let port_str = port.to_string();
let port_data = pool.alloc(port_str.len());
let port_data = pool.alloc_unaligned(port_str.len());
if port_data.is_null() {
return core::Status::NGX_ERROR;
}
Expand Down
75 changes: 65 additions & 10 deletions nginx-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ mod bindings {
#[doc(no_inline)]
pub use bindings::*;

/// Convert a byte slice to a raw pointer (`*mut u_char`) allocated in the given nginx memory pool.
///
/// # Safety
///
/// The caller must provide a valid pointer to the memory pool.
pub unsafe fn bytes_to_uchar(pool: *mut ngx_pool_t, data: &[u8]) -> Option<*mut u_char> {
let ptr: *mut u_char = ngx_pnalloc(pool, data.len()) as _;
if ptr.is_null() {
return None;
}
copy_nonoverlapping(data.as_ptr(), ptr, data.len());
Some(ptr)
}

/// Convert a string slice (`&str`) to a raw pointer (`*mut u_char`) allocated in the given nginx memory pool.
///
/// # Arguments
Expand All @@ -57,7 +71,7 @@ pub use bindings::*;
/// * `data` - The string slice to convert to a raw pointer.
///
/// # Safety
/// This function is marked as unsafe because it involves raw pointer manipulation and direct memory allocation using `ngx_palloc`.
/// This function is marked as unsafe because it involves raw pointer manipulation and direct memory allocation using `ngx_pnalloc`.
///
/// # Returns
/// A raw pointer (`*mut u_char`) to the allocated memory containing the converted string data.
Expand All @@ -69,25 +83,66 @@ pub use bindings::*;
/// let ptr = str_to_uchar(pool, data);
/// ```
pub unsafe fn str_to_uchar(pool: *mut ngx_pool_t, data: &str) -> *mut u_char {
let ptr: *mut u_char = ngx_palloc(pool, data.len() as _) as _;
let ptr: *mut u_char = ngx_pnalloc(pool, data.len()) as _;
debug_assert!(!ptr.is_null());
copy_nonoverlapping(data.as_ptr(), ptr, data.len());
ptr
}

impl ngx_str_t {
/// Returns the contents of this `ngx_str_t` as a byte slice.
///
/// The returned slice will **not** contain the optional nul terminator that `ngx_str_t.data`
/// may have.
#[inline]
pub fn as_bytes(&self) -> &[u8] {
if self.is_empty() {
&[]
} else {
// SAFETY: `ngx_str_t` with non-zero len must contain a valid correctly aligned pointer
unsafe { slice::from_raw_parts(self.data, self.len) }
}
}

/// Returns the contents of this `ngx_str_t` as a mutable byte slice.
#[inline]
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
if self.is_empty() {
&mut []
} else {
// SAFETY: `ngx_str_t` with non-zero len must contain a valid correctly aligned pointer
unsafe { slice::from_raw_parts_mut(self.data, self.len) }
}
}

/// Returns `true` if the string has a length of 0.
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}

/// Convert the nginx string to a string slice (`&str`).
///
/// # Safety
/// This function is marked as unsafe because it involves raw pointer manipulation.
/// It assumes that the underlying `data` pointer is valid and points to a valid UTF-8 encoded string.
///
/// # Panics
/// This function panics if the `ngx_str_t` is not valid UTF-8.
///
/// # Returns
/// A string slice (`&str`) representing the nginx string.
pub fn to_str(&self) -> &str {
unsafe {
let slice = slice::from_raw_parts(self.data, self.len);
return std::str::from_utf8(slice).unwrap();
}
std::str::from_utf8(self.as_bytes()).unwrap()
}

/// Create an `ngx_str_t` instance from a byte slice.
///
/// # Safety
///
/// The caller must provide a valid pointer to a memory pool.
pub unsafe fn from_bytes(pool: *mut ngx_pool_t, src: &[u8]) -> Option<Self> {
Copy link
Contributor

Choose a reason for hiding this comment

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

from_string() and from_str(), both return Self, not Option<Self>, shouldn't we change them as well?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure if it's worth fixing the str conversion functions. I planned to remove these or at least mark as deprecated.

bytes_to_uchar(pool, src).map(|data| Self { data, len: src.len() })
}

/// Create an `ngx_str_t` instance from a `String`.
Expand All @@ -107,7 +162,7 @@ impl ngx_str_t {
pub unsafe fn from_string(pool: *mut ngx_pool_t, data: String) -> Self {
ngx_str_t {
data: str_to_uchar(pool, data.as_str()),
len: data.len() as _,
len: data.len(),
}
}

Expand All @@ -128,7 +183,7 @@ impl ngx_str_t {
pub unsafe fn from_str(pool: *mut ngx_pool_t, data: &str) -> Self {
ngx_str_t {
data: str_to_uchar(pool, data),
len: data.len() as _,
len: data.len(),
}
}
}
Expand Down Expand Up @@ -199,9 +254,9 @@ pub unsafe fn add_to_ngx_table(
}
table.as_mut().map(|table| {
table.hash = 1;
table.key.len = key.len() as _;
table.key.len = key.len();
table.key.data = str_to_uchar(pool, key);
table.value.len = value.len() as _;
table.value.len = value.len();
table.value.data = str_to_uchar(pool, value);
table.lowcase_key = str_to_uchar(pool, String::from(key).to_ascii_lowercase().as_str());
})
Expand Down
18 changes: 18 additions & 0 deletions src/core/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,33 +85,51 @@ impl Pool {
}

/// Allocates memory from the pool of the specified size.
/// The resulting pointer is aligned to a platform word size.
///
/// Returns a raw pointer to the allocated memory.
pub fn alloc(&mut self, size: usize) -> *mut c_void {
unsafe { ngx_palloc(self.0, size) }
}

/// Allocates memory for a type from the pool.
/// The resulting pointer is aligned to a platform word size.
///
/// Returns a typed pointer to the allocated memory.
pub fn alloc_type<T: Copy>(&mut self) -> *mut T {
self.alloc(mem::size_of::<T>()) as *mut T
}

/// Allocates zeroed memory from the pool of the specified size.
/// The resulting pointer is aligned to a platform word size.
///
/// Returns a raw pointer to the allocated memory.
pub fn calloc(&mut self, size: usize) -> *mut c_void {
unsafe { ngx_pcalloc(self.0, size) }
}

/// Allocates zeroed memory for a type from the pool.
/// The resulting pointer is aligned to a platform word size.
///
/// Returns a typed pointer to the allocated memory.
pub fn calloc_type<T: Copy>(&mut self) -> *mut T {
self.calloc(mem::size_of::<T>()) as *mut T
}

/// Allocates unaligned memory from the pool of the specified size.
///
/// Returns a raw pointer to the allocated memory.
pub fn alloc_unaligned(&mut self, size: usize) -> *mut c_void {
unsafe { ngx_pnalloc(self.0, size) }
}

/// Allocates unaligned memory for a type from the pool.
///
/// Returns a typed pointer to the allocated memory.
pub fn alloc_type_unaligned<T: Copy>(&mut self) -> *mut T {
self.alloc_unaligned(mem::size_of::<T>()) as *mut T
}

/// Allocates memory for a value of a specified type and adds a cleanup handler to the memory pool.
///
/// Returns a typed pointer to the allocated memory if successful, or a null pointer if allocation or cleanup handler addition fails.
Expand Down
Loading