NAME

Punk::Upload - an uploaded file from a multipart form

SYNOPSIS

post '/avatar' => sub {
    my ($c) = @_;
    my $up = $c->req->upload('avatar') or return $c->text('no file', 400);
    $up->save("/var/uploads/" . $up->filename);
    $c->json({ name => $up->filename, bytes => $up->size });
};

DESCRIPTION

A file part of a multipart/form-data request. $c->req->form parses the body once: ordinary fields become parameters ($c->param), and file parts become Punk::Upload objects reachable through $c->req->upload($name) (or $c->upload($name)) and $c->req->uploads. A field uploaded more than once yields an arrayref from uploads; upload gives the first.

The bytes are held in memory in this cut - bound your request body size accordingly; a tempfile-backed mode for large uploads is a follow-on.

METHODS

filename

The client-supplied file name (do not trust it as a path).

name

The form field name.

type

The part's Content-Type (application/octet-stream if the client sent none).

size

The byte length.

content

The uploaded bytes.

save($path)

Write the bytes to $path. Croaks if it cannot open the file.

Note what this is not: the bytes were already resident before the handler ran, so this is a write, not a stream. ->save does not reduce the memory an upload costs; it only puts a copy on disk.

SIZE, HONESTLY

An upload arrives whole, in memory, twice over - once in the server's read buffer and again as the decoded part - before a handler sees it. So:

  • the practical maximum is the server's request ceiling, which for Hyperman is max_body and defaults to 16MB

  • raising that ceiling raises a worker's worst-case resident size in proportion: roughly workers x max_body x concurrent uploads per worker

  • "max_body" in Punk does not help here. It refuses an oversize request after the bytes have arrived, which saves the parse and the handler but not the memory

For genuinely large uploads, terminate them at a proxy or hand the client a pre-signed direct-to-storage URL and take only the resulting key. Raising a server ceiling to a gigabyte to accept gigabyte uploads does work, and costs a gigabyte per concurrent upload per worker.

SEE ALSO

Punk, "upload" in Punk::Request, "max_body" in Punk, "max_body: the request ceiling" in Hyperman.

AUTHOR

LNATION <email@lnation.org>

LICENSE AND COPYRIGHT

This software is Copyright (c) 2026 by LNATION <email@lnation.org>.

This is free software, licensed under:

The Artistic License 2.0 (GPL Compatible)