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:
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
}
- 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
).
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:
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:
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.
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(),
}
}