Processing file uploads

examples/http_server_upload.C is an example of using a version of getform() that handles file uploads (<input type="file"> elements inside a <form enctype="multipart/form-data">.

std::pair<x::http::form::parameters, bool>
    form=this->getform(req, hasbody,
        []
        (const x::headersbase &headers,
         const std::string &name_utf8,
         const std::string &filename_utf8,
         x::http::form::parameters::base::filereceiver &recv)
        {

        // ...

            recv.receive(
                []
                (const std::vector<char> &chunk)
                {
                    // ...
                },
                []
                {
                    // ...
                });
        }, "iso-8859-1");

Passing two additional arguments to getform() enables processing of file uploads, in addition to getform() returning the processed form parameters, as usual. If the form submission did not does not include file uploads, getform() processes the form as usual.

The first additional parameter is a functor. The second parameter specifies the character set of the field names and non-file upload field values (iso-8859-1 in this example). RFC 2388 specifies that multipart/form-data forms must explicitly indicate each form field name's and value's character set. To properly support older clients that may not specify the names' and values' character set, this parameter needs to specify the form's original character. The file upload version of getform() converts all field names and values to UTF-8 in all cases, and this indicates the character set of field names and values that do not explicitly specify it.

The functor specified by the first additional parameter gets invoked for each file uploaded through the form. The functor gets invoked more than once if the form uploaded multiple files.

The functor receives four parameters:

The functor/lambda invokes receive() passing two more functors or lambdas. The first write functor gets invoked repeatedly with std::vector<char>s with the contents of the uploaded file. The contents of the uploaded file get processed in small chunks, and the write functor gets invoked repeatedly until the entire contents of the uploaded file get passed. The second close functor gets invoked after the last call to the write functor, with the uploaded file's last chunk. If the uploaded file was empty, the close functor gets invoked without any preceding call to the write functor.

Note

The write and the close functors do not actually get invoked by receive(), but after the parent functor/lambda returns.

The write functor is responsible for enforcing its own limits on the maximum size of the file upload. Calling x::http::responseimpl::throw_request_entity_too_large() throws an exception that results in an HTTP 413 error response to the client.

A form with multiple file uploads results in multiple calls to getform()'s functor. Each call invokes receive(), passing the write and the close functor for each file (which may be different for each file in the form) that subsequently get invoked to process the upload.