Skip to main content

multipart_uploads

Function multipart_uploads 

Source
pub fn multipart_uploads(
    path: &str,
    prefix: &'static str,
    field: &'static str,
    rules: &'static Rules,
) -> Router<Ctx>
Expand description

Routes that upload large files to R2 in parts, resumably (S3 multipart uploads), for the field of a form.

The browser side is in DIRECT_UPLOAD_JS: <input type="file" name="video" data-multipart-upload-url="/videos/uploads">. The routes, under path:

RequestDoes
POST <path> with {"filename", "content_type", "size"}checks the file against rules, creates the upload of a new key under prefix, answers a MultipartUpload (signed_key, upload_id, part_size, part_count)
POST <path>/parts with {"signed_key", "upload_id", "parts": [1, 2]}answers where to PUT each part (PartUrls)
PUT <path>/parts/<n>?key=&upload_id=stores part n through the Worker, answers {"part_number", "etag"}
POST <path>/complete with {"signed_key", "upload_id", "parts": [{"part_number", "etag"}]}assembles the object (204)
POST <path>/abort with {"signed_key", "upload_id"}drops the parts (204)

Where parts go: in a release build with the R2_* settings (see presign_get), straight to R2 through presigned URLs, so the file never passes through the Worker (the bucket’s CORS rule must allow PUT and expose ETag). Otherwise (ocre dev, or no R2_* settings) through the Worker, part by part (95 MB at most each, under the 100 MB request limit). An interrupted upload resumes: the script keeps the finished parts in localStorage and sends the others.

Once complete, the form submits the signed key like a direct upload: attach_direct_upload checks the object and returns its Attachment. Costs: one R2 class A operation per part, plus the create and complete.

§Examples

use axum::Router;
use ocre::{Ctx, storage::{self, Rules}};

static VIDEO: Rules = Rules { max_bytes: 20 * 1024 * 1024 * 1024, content_types: &["video/mp4", "video/quicktime"] };

fn routes() -> Router<Ctx> {
    Router::new().merge(storage::multipart_uploads("/videos/uploads", "uploads/videos", "video", &VIDEO))
}