Skip to content

Commit

Permalink
docs: prepare ngx to be published to crates.io
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanitskiy committed May 17, 2023
1 parent 1405454 commit a1bff29
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 18 deletions.
45 changes: 39 additions & 6 deletions Cargo.lock

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

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ name = "ngx"
version = "0.3.0-beta"
edition = "2021"
autoexamples = false
categories = ["api-bindings", "network-programming"]
description = "FFI bindings to NGINX"
repository = "https://github.com/nginxinc/ngx-rust"
homepage = "https://github.com/nginxinc/ngx-rust"
license = "Apache-2.0"
keywords = ["nginx", "module", "sys"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand All @@ -23,3 +28,6 @@ duct = "0.13.6"
ureq = { version = "2.6.2", features = ["tls"] }
flate2 = "1.0.25"
tar = "0.4.38"

[badges]
maintenance = { status = "experimental" }
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ In short, this SDK allows writing NGINX modules using the Rust language.

## Build

NGINX modules can be build against a particular version of NGINX. The following environment variables can be used to
specify particular version of NGINX or an NGINX dependency:
NGINX modules can be built against a particular version of NGINX. The following environment variables can be used to specify a particular version of NGINX or an NGINX dependency:

* `ZLIB_VERSION` (default 1.2.13) -
* `PCRE2_VERSION` (default 10.42)
Expand Down
59 changes: 55 additions & 4 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,65 @@
- [Examples](#examples)
- [CURL](#curl)
- [AWSSIG](#awssig)
- [HTTPORIGDST - NGINX Destination IP recovery module for HTTP](#httporigdst----nginx-destination-ip-recovery-module-for-http)
- [Dependencies](#dependencies)
- [Example Configuration](#example-configuration)
- [HTTP](#http)
- [Embedded Variables](#embedded-variables)
- [Usage](#usage)
- [Caveats](#caveats)


# Examples
This crate provides a couple of example using [ngx](https://crates.io/crates/ngx) crate:

- [awssig.rs](./awssig.rs) - An example of NGINX dynamic module that can sign GET request using AWS Signature v4.
- [curl](./curl.rs) - An example of the Access Phase NGINX dynamic module that blocks HTTP requests if `user-agent` header starts with `curl`.
- [httporigdst](./httporigdst.rs) - A dynamic module recovers the original IP address and port number of the destination packet.

To build all these examples simply run:

```
cargo build --package=examples --examples
```


## CURL

This module demonstrates how to create a minimal dynamic module with `http_request_handler`, that checks for User-Agent headers and returns status code 403 if UA starts with `curl`, if a module is disabled then uses `core::Status::NGX_DECLINED` to indicate the operation is rejected, for example, because it is disabled in the configuration (`curl off`). Additionally, it demonstrates how to write a defective parser.

An example of nginx configuration file that uses that module can be found at [curl.conf](./curl.conf).

## NGINX Destination IP recovery module for HTTP
How to build and run in a [Docker](../Dockerfile) container curl example:
```
# build all dynamic modules examples and specify NGINX version to use
docker buildx build --build-arg NGX_VERSION=1.23.3 -t ngx-rust .
# start NGINX using curl.conf module example:
docker run --rm -d -p 8000:8000 ngx-rust nginx -c examples/curl.conf
# test it - you should see 403 Forbidden
curl http://127.0.0.1:8000 -v -H "user-agent: curl"
# test it - you should see 404 Not Found
curl http://127.0.0.1:8000 -v -H "user-agent: foo"
```

This dynamic module recovers original IP address and port number of the destination packet. It is useful, for example, with container sidecars where all outgoing traffic is redirected to a separate container with iptables before reaching the target.
## AWSSIG

This module uses [NGX_HTTP_PRECONTENT_PHASE](https://nginx.org/en/docs/dev/development_guide.html#http_phases) and provides examples, of how to use external dependency and manipulate HTTP headers before sending client requests upstream.

An example of nginx configuration file that uses that module can be found at [awssig.conf](./awssig.conf).

## HTTPORIGDST - NGINX Destination IP recovery module for HTTP

This dynamic module recovers the original IP address and port number of the destination packet. It is useful, for example, with container sidecars where all outgoing traffic is redirected to a separate container with iptables before reaching the target.

This module can only be built with the "linux" feature enabled, and will only successfully build on a Linux OS.

### Dependencies

This modules uses the Rust crate libc and Linux **getsockopt** socket API.
This module uses the Rust crate libc and Linux **getsockopt** socket API.

### Example Configuration
#### HTTP
Expand Down
45 changes: 45 additions & 0 deletions src/core/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,27 @@ use crate::ffi::*;

use std::slice;

/// The `Buffer` trait provides methods for working with an nginx buffer (`ngx_buf_t`).
pub trait Buffer {
/// Returns a raw pointer to the underlying `ngx_buf_t` of the buffer.
fn as_ngx_buf(&self) -> *const ngx_buf_t;

/// Returns a mutable raw pointer to the underlying `ngx_buf_t` of the buffer.
fn as_ngx_buf_mut(&mut self) -> *mut ngx_buf_t;

/// Returns the buffer contents as a byte slice.
///
/// # Safety
/// This function is marked as unsafe because it involves raw pointer manipulation.
fn as_bytes(&self) -> &[u8] {
let buf = self.as_ngx_buf();
unsafe { slice::from_raw_parts((*buf).pos, self.len()) }
}

/// Returns the length of the buffer contents.
///
/// # Safety
/// This function is marked as unsafe because it involves raw pointer manipulation.
fn len(&self) -> usize {
let buf = self.as_ngx_buf();
unsafe {
Expand All @@ -22,17 +33,28 @@ pub trait Buffer {
}
}

/// Returns `true` if the buffer is empty, i.e., it has zero length.
fn is_empty(&self) -> bool {
self.len() == 0
}

/// Sets the `last_buf` flag of the buffer.
///
/// # Arguments
///
/// * `last` - A boolean indicating whether the buffer is the last buffer in a request.
fn set_last_buf(&mut self, last: bool) {
let buf = self.as_ngx_buf_mut();
unsafe {
(*buf).set_last_buf(if last { 1 } else { 0 });
}
}

/// Sets the `last_in_chain` flag of the buffer.
///
/// # Arguments
///
/// * `last` - A boolean indicating whether the buffer is the last buffer in a chain of buffers.
fn set_last_in_chain(&mut self, last: bool) {
let buf = self.as_ngx_buf_mut();
unsafe {
Expand All @@ -41,52 +63,75 @@ pub trait Buffer {
}
}

/// The `MutableBuffer` trait extends the `Buffer` trait and provides methods for working with a mutable buffer.
pub trait MutableBuffer: Buffer {
/// Returns a mutable reference to the buffer contents as a byte slice.
///
/// # Safety
/// This function is marked as unsafe because it involves raw pointer manipulation.
fn as_bytes_mut(&mut self) -> &mut [u8] {
let buf = self.as_ngx_buf_mut();
unsafe { slice::from_raw_parts_mut((*buf).pos, self.len()) }
}
}

/// Wrapper struct for a temporary buffer, providing methods for working with an `ngx_buf_t`.
pub struct TemporaryBuffer(*mut ngx_buf_t);

impl TemporaryBuffer {
/// Creates a new `TemporaryBuffer` from an `ngx_buf_t` pointer.
///
/// # Panics
/// Panics if the given buffer pointer is null.
pub fn from_ngx_buf(buf: *mut ngx_buf_t) -> TemporaryBuffer {
assert!(!buf.is_null());
TemporaryBuffer(buf)
}
}

impl Buffer for TemporaryBuffer {
/// Returns the underlying `ngx_buf_t` pointer as a raw pointer.
fn as_ngx_buf(&self) -> *const ngx_buf_t {
self.0
}

/// Returns a mutable reference to the underlying `ngx_buf_t` pointer.
fn as_ngx_buf_mut(&mut self) -> *mut ngx_buf_t {
self.0
}
}

impl MutableBuffer for TemporaryBuffer {
/// Returns a mutable reference to the buffer contents as a byte slice.
///
/// # Safety
/// This function is marked as unsafe because it involves raw pointer manipulation.
fn as_bytes_mut(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut((*self.0).pos, self.len()) }
}
}

/// Wrapper struct for a memory buffer, providing methods for working with an `ngx_buf_t`.
pub struct MemoryBuffer(*mut ngx_buf_t);

impl MemoryBuffer {
/// Creates a new `MemoryBuffer` from an `ngx_buf_t` pointer.
///
/// # Panics
/// Panics if the given buffer pointer is null.
pub fn from_ngx_buf(buf: *mut ngx_buf_t) -> MemoryBuffer {
assert!(!buf.is_null());
MemoryBuffer(buf)
}
}

impl Buffer for MemoryBuffer {
/// Returns the underlying `ngx_buf_t` pointer as a raw pointer.
fn as_ngx_buf(&self) -> *const ngx_buf_t {
self.0
}

/// Returns a mutable reference to the underlying `ngx_buf_t` pointer.
fn as_ngx_buf_mut(&mut self) -> *mut ngx_buf_t {
self.0
}
Expand Down
2 changes: 1 addition & 1 deletion src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ macro_rules! ngx_http_null_variable {
///
/// This is typically used to terminate an array of Stream variable types.
///
/// [`ngx_stream_variable_t`]: TODO: find appropriate link
/// [`ngx_stream_variable_t`]: https://github.com/nginx/nginx/blob/1a8ef991d92d22eb8aded7f49595dd31a639e8a4/src/stream/ngx_stream_variables.h#L21
#[macro_export]
macro_rules! ngx_stream_null_variable {
() => {
Expand Down
Loading

0 comments on commit a1bff29

Please sign in to comment.