Input streams and File upload - novalexei/mod_servlet GitHub Wiki

Input streams and File upload

In Dynamic content section I already mentioned that POST requests can send data to server directly. A servlet can have the access to this data via http_request::get_input_stream method.

There is also special format of the input stream: multipart/form-data. This way the client can transport to a server multiple binary parts of data. This is a good way to upload files to server. mod_servlet has API to handle mutipart input.

For the next servlet let's do something unconventional. Our next servlet will wait for multipart input and if any html file is there, it will stream it right back at us, so that we will see in the browser window the file which we uploaded. Yes, I know there are much easier way to see your html file in the browser window, but this way is just more fun.

First we will need upload form. This is a html form which will allow to select and send a file. Create upload.html file:

<html>
<head>
    <title>File Uploading Form</title>
</head>
<body>
    <br/>Select a file to upload: <br/><br/>
    <form action="http://localhost/tutorial/"
          method="post" enctype="multipart/form-data">
        <input type="file" name="file" size="50"/> <br/><br/>
        <input type="submit" value="Upload File"/>
    </form>
</body>
</html>

Now to the servlet:

class mp_stream_back_servlet : public http_servlet
{
public:
    void do_post(http_request& req, http_response& resp) override
    {
        resp.set_content_type("text/html");
        std::ostream &out = resp.get_output_stream();
        // Check if it is multipart.
        if (!req.is_multipart())
        {
           // It is not a multipart. Complain to the client.
            out << "<!DOCTYPE html>\n<html>\n<head>\n"
                   "<title>Not a multipart</title>\n</head>\n"
                   "<body>\n<p>No multipart stream</p>\n</body>\n</html>\n";
            return;
        }
        multipart_input &input = req.get_multipart_input();
        std::string file_name;
        // Iterate through the parts of the request input.
        while (input.to_next_part())
        {
            auto submitted_file = input.get_submitted_filename();
            if (!submitted_file) continue;
            auto found = submitted_file->rfind(".html");
            // Check if the file received is html
            if (found != std::string::npos && found + 5 == submitted_file->length())
            {
                // It is html. Stream it back.
                out << input.get_input_stream().rdbuf();
                return;
            }
            if (file_name.empty()) file_name = *submitted_file;
        }
        // We parsed multipart input but didn't find html file.
        // Complain to the client.
        out << "<!DOCTYPE html>\n<html>\n<head>\n"
               "<title>No html file</title>\n</head>\n"
               "<body>\n"
               "<p>Expected html file, but received " << file_name << "</p>\n"
               "</body>\n"
               "</html>\n";
    }
};

SERVLET_EXPORT(mpServlet, mp_stream_back_servlet)

Simple enough, isn't it? The important calls here are:

  • do_post method. We need POST handler here.

  • Check if it is multipart

            if (!req.is_multipart()) { ... }
  • Get multipart stream

         multipart_input &input = req.get_multipart_input();
  • Inspect parts.

         while (input.to_next_part()) { ... }

For more information see the API reference.

Now deploy and configure servlet, load the upload.html form in the browser, select file and press "Upload File" button. Be amazed!

And now we are ready to learn about Redirects, forwards and includes

To The Programming Guide

⚠️ **GitHub.com Fallback** ⚠️