Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Upload Intake Budgets and Storage Ownership

Last updated: 4 Oct 20266 min read
tutorial
IntermediateBy AITrove Editorial

An upload intake contract specifies who may start a transfer, which case it belongs to, which types and sizes are accepted, and where bytes live before review. A browser file picker and Content-Type header are hints, not server validation. The application must enforce total request size, per-file size, file count, transfer duration, and concurrent-session limits before unbounded memory or disk allocation. Storage ownership matters: an untrusted file must not be placed under a public web directory or given a user-supplied executable name. A successful transfer creates a pending asset record, not a trusted document.

Working case

Reviewer 29 attaches evidence to case 47. The permitted class is an image or PDF up to 23 MiB, with four attachments per case and two concurrent transfers per reviewer. The browser selects a file named final-report.pdf, but the server generates asset 62 and an opaque object key. It checks reviewer 29 may edit case 47 before issuing any transfer permission. The request advertises 12 MiB; the server still counts actual received bytes and stops at the cap. Temporary bytes land in a private pending area. The case detail page shows Processing rather than a download link until inspection finishes.

Implementation boundary

javascript
function withinUploadBudget(receivedBytes, limitBytes, activeCount, maxActive) {
  return receivedBytes <= limitBytes && activeCount < maxActive;
}
console.log(withinUploadBudget(24 * 1024 * 1024, 23 * 1024 * 1024, 1, 2));
// Output: false

Apply the earliest practical body limit at the edge or server and another limit in the streaming receiver. Count actual bytes, not a declared length alone. Enforce actor, case, tenant, rate, and concurrency controls before signing direct-to-storage requests or accepting multipart bodies. Restrict the storage key and allowed method; never let the browser choose a bucket path that maps directly to another tenant. Persist one pending asset ID with owner, expected size range, purpose, creation time, and expiry. If direct transfer is used, inspect the resulting object size and identity server-side before moving the record forward. Reject filenames with dangerous handling in display or logging, and store the original name only as untrusted metadata.

Cost and boundaries

Receiving n bytes costs O(n) transfer and storage, but buffering the whole request adds O(n) process memory that a streaming receiver can avoid. Parallel uploads multiply disk and network load by active sessions; a per-file cap alone does not protect capacity. A staging object and metadata record cost extra writes and need expiry cleanup. Put quotas at the user, tenant, and service levels so one busy tenant cannot consume all room. Measure rejected bytes, active sessions, incomplete staging age, object storage growth, and the delay between transfer completion and inspection.

Failure trace

The UI rejects a large file locally, but a scripted client posts a larger body directly and the server buffers it before checking length. Several requests exhaust memory. Enforce limits as bytes arrive and cap concurrent sessions. Another path writes uploaded filenames into a public directory. A crafted name collides with an existing asset or reaches an executable route. Use opaque storage keys and keep staging outside public serving. Test missing length, false length, slow transfer, many tiny parts, parallel uploads, expired permission, tenant switch, and a transfer that ends exactly at the configured boundary.

Verification

  • Declared size never replaces actual byte counting.
  • Staged objects are private and use server-owned keys.
  • Actor, tenant, concurrency, and expiry rules hold before transfer.

Practice drill

For case 47, request a transfer as reviewer 29 and confirm the server creates asset 62 in pending state. Try the same call as reviewer 62 without case rights. Stream bytes just below, at, and above 23 MiB without preloading them all in the handler. Reuse a transfer grant for a different object key and confirm rejection. Start more than two simultaneous transfers, abandon one, and verify expiry removes its pending object and releases capacity. Check that no pending byte path is reachable from a public URL.

Decision note

Authorize and bound the transfer before accepting bytes, then retain the object privately until it passes later checks.

Common Mistakes

  • Checking size only in the browser.
  • Treating the filename as a safe storage key.
  • Calling a transferred object ready for download.

Connected lessons

File Ingestion and Private Asset Lifecycle; Resumable Transfer Parts and Integrity; File Quarantine, Inspection, and Derived Previews; Private Asset Downloads, Revocation, and Expiry; Safe File Upload Pipeline; Object-Level Authorization for Reads and Writes; Retention Inventory and Expiry Workflows.

Apply and check

Build Project: private evidence file lifecycle and review Web Development: file and email delivery decisions quiz.

web-tech
web-development
Storage details