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:
| Request | Does |
|---|---|
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))
}