Skip to main content

store_body

Function store_body 

Source
pub fn store_body(
    ctx: &Ctx,
    prefix: &str,
    filename: &str,
    content_type: &str,
    size: u64,
    body: Body,
) -> impl Future<Output = Result<Attachment>> + Send + use<>
Expand description

Streams body (exactly size bytes) into R2 without holding it in memory, and returns its Attachment.

For a raw request body with a Content-Length (curl -T big.zip), where Multipart would hold the whole body in memory. R2 needs the length up front: a body of another length makes the write fail and nothing is stored. The file name and content type are cleaned up like store_bytes’s; no Rules are checked, so check size and content_type first.

Free plan: one R2 class A operation (1M free per month). Chunks still pass through WebAssembly, but memory stays flat; Cloudflare refuses request bodies over 100 MB on the Free plan.

§Errors

Error::Internal (500) when the STORAGE binding is missing (the message shows the STORAGE entry to add to cloudflare.config.ts), the body is not size bytes long, or the R2 write fails.

§Examples

use axum::{body::Body, extract::State, http::{HeaderMap, header}};
use ocre::{Ctx, Error, Result, storage};

const MAX: u64 = 50 * 1024 * 1024;

// PUT /backups with `curl -T backup.zip`.
async fn upload(State(ctx): State<Ctx>, headers: HeaderMap, body: Body) -> Result<String> {
    let size: u64 = headers
        .get(header::CONTENT_LENGTH)
        .and_then(|value| value.to_str().ok()?.parse().ok())
        .ok_or_else(|| Error::bad_request("Content-Length required"))?;
    if size > MAX {
        return Err(Error::PayloadTooLarge("The backup is too large (maximum is 50 MB)".into()));
    }
    let backup = storage::store_body(&ctx, "backups", "backup.zip", "application/zip", size, body).await?;
    Ok(backup.key)
}