liveBook · Manning

Handler

As explained in Refactoring to Rust

An NGINX HTTP handler is a module function that receives an NGINX request structure and returns an integer request-processing status.

An NGINX HTTP handler receives a request pointer and returns an integer request-processing status. A calculator handler can turn POST requests to `/calculate` into an HTTP interface for an existing Reverse Polish Notation calculator. NGINX supplies the C module; Rust supplies the handler through a foreign function interface (FFI). section 4.0 section 4.2

The request body takes a separate step to read:

  • Expose the Rust handler to C as `#[no_mangle] pub unsafe extern "C" fn ngx_http_calculator_handler(r: *mut ngx_http_request_t) -> ngx_int_t`. The C module declares the same handler by name. section 4.2 section 4.4
  • Call `ngx_http_read_client_request_body(r, Some(read_body_handler))`. Return a nonzero result immediately; otherwise return `0`. The callback runs when the body has been read. section 4.4
  • In the callback, reject a null request pointer before accessing it. The example helper checks body-buffer pointers, forms a byte slice, and converts it to UTF-8; this stage logs the body rather than returning a calculation. section 4.4

Calculator request

`curl -X POST -d '3 4 +' http://localhost:8080/calculate` illustrates the intended interface, with `7` as its result. Loading the dynamic module and enabling `calculate on` at that location connects the endpoint to the handler; the shown body-reading implementation is only one step toward that result. section 4.0 section 4.2 section 4.4

unsafe fn request_body_as_str<'a>(
  request: &'a ngx_http_request_t,
) -> Result<&'a str, &'static str> {
  if request.request_body.is_null()
    || (*request.request_body).bufs.is_null()
    || (*(*request.request_body).bufs).buf.is_null()
  {
    return Err("Request body buffers
      were not initialized as expected");
  }

  let buf = (*(*request.request_body).bufs).buf;

  let start = (*buf).pos;
  let len = (*buf).last.offset_from(start) as usize;

  let body_bytes = std::slice::from_raw_parts(start, len);

  let body_str = std::str::from_utf8(body_bytes)
    .map_err(|_| "Body contains invalid UTF-8")?;

  Ok(body_str)
}

Follow the pointer checks, buffer positions, byte-slice creation, and UTF-8 conversion that turn a loaded request body into a Rust string. section 4.4

How Refactoring to Rust covers it

How deep it goes
Explains FFI signatures, body-loading callbacks, pointer checks, and UTF-8 conversion; the illustrated handler stops at logging the body.
Examples
Shows calculator POST commands, a C handler declaration, Rust callback code, and request-buffer extraction.
What it assumes
Assumes an existing RPN calculator and NGINX module setup; introduces the Rust handler’s FFI signature through examples.
What you can do after
Apply it via NGINX’s C module API and Rust FFI to load and inspect POST request bodies.
How it connects
Connects dynamic modules, FFI, request-body callbacks, raw pointers, and UTF-8 conversion.

Also explained in

Compare how 22 books explain handler →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Refactoring to Rust. The section links point to the parts of the book it draws on.