Skip to content

Low-level access

BufferedBody is Pavex's main interface to work with the bytes of the incoming request body.

BufferedBody consumes the raw byte stream and buffers the entire body of the incoming request in memory.
At the same time, it takes care of enforcing sane limits to prevent resource exhaustion attacks.

Registration

To use BufferedBody in your project, you need to register a constructor for it. You can use BufferedBody::register to register its default constructor and error handler:

src/blueprint.rs
use pavex::blueprint::Blueprint;
use pavex::request::body::{BodySizeLimit, BufferedBody};

pub fn blueprint() -> Blueprint {
    let mut bp = Blueprint::new();
    BufferedBody::register(&mut bp);
    BodySizeLimit::register(&mut bp); // (1)!
    // [...]
    bp
}
  1. You also need to register a constructor for BodySizeLimit!

If you're using the default ApiKit, you don't need to register a constructor for BufferedBody manually: it's already included in the kit.

Use cases

BufferedBody is the ideal building block for other extractors that need to have the entire body available in memory to do their job (e.g. JsonBody).

BufferedBody is also a good fit if you need to access the raw bytes of the body ahead of deserialization (e.g. to compute its hash as a step of a signature verification process). In those scenarios, make sure to inject a shared reference to BufferedBody (i.e. &BufferedBody) into your component rather than consuming it (i.e. BufferedBody).

src/buffered_body/routes.rs
use pavex::http::StatusCode;
use pavex::request::body::BufferedBody;

pub fn handler(body: &BufferedBody) -> StatusCode {
    format!("The incoming request contains {} bytes", body.bytes.len());
    // [...]
}

Body size limit

BufferedBody enforces an upper limit on the body size to prevent resource exhaustion attacks. The default limit is 2 MBs.
BufferedBody::extract returns SizeLimitExceeded if the limit is exceeded.

Custom limit

You can customize the limit by registering a custom constructor for BodySizeLimit in your Blueprint:

src/custom_limit/blueprint.rs
use pavex::blueprint::Blueprint;
use pavex::f;
use pavex::request::body::BodySizeLimit;
use pavex::unit::ToByteUnit;

pub fn body_size_limit() -> BodySizeLimit {
    BodySizeLimit::Enabled {
        max_size: 2.megabytes(),
    }
}

pub fn blueprint() -> Blueprint {
    let mut bp = Blueprint::new();
    bp.request_scoped(f!(self::body_size_limit));
    // [...]
}

No limit

You can also disable the limit altogether:

src/no_limit/blueprint.rs
use pavex::blueprint::Blueprint;
use pavex::f;
use pavex::request::body::BodySizeLimit;

pub fn body_size_limit() -> BodySizeLimit {
    BodySizeLimit::Disabled
}

pub fn blueprint() -> Blueprint {
    let mut bp = Blueprint::new();
    bp.request_scoped(f!(self::body_size_limit));
    // [...]
}

Granular limits

In large applications with many routes it can be hard (if not impossible) to find a single limit that works for all routes. You can leverage nesting to define more granular limits.

src/granular_limits/blueprint.rs
use pavex::blueprint::{router::POST, Blueprint};
use pavex::f;
use pavex::request::body::BodySizeLimit;
use pavex::unit::ToByteUnit;

pub fn blueprint() -> Blueprint {
    let mut bp = Blueprint::new();
    bp.nest(upload_bp());
    // Other routes...
    bp
}

fn upload_bp() -> Blueprint {
    let mut bp = Blueprint::new();
    // This limit will only apply to the routes registered
    // in this nested blueprint.
    bp.request_scoped(f!(self::upload_size_limit));
    bp.route(POST, "/upload", f!(crate::upload));
    bp
}

pub fn upload_size_limit() -> BodySizeLimit {
    BodySizeLimit::Enabled {
        max_size: 1.gigabytes(),
    }
}