Webmaster  |  Imprint 
C++ Server Pages
Main  |  License  |  Documentation  |  Download 

HowtoHttpUpload

HTTP-upload

This document describes, how to upload files with Tntnet.

Sometimes there is a need for uploading files to the webapplication. This is done with a special html-input-element of type "file". The form-element needs to specify an enctype of with the parameter "multipart/form-data". This enctype changes the way, form-data is sent to your webapplication. Luckily Tntnet handles all difficult stuff for you and fill your aruments specified in <%args>-sections.

But with upload files the situation is a little different. First the file-data might be quite large and in would be not the most efficient way to put the data into a std::string like other arguments. The second problem is, that the file might have a additional attribute - the filename. Therefore Tntnet has a special API to handle this uploaded data.

The data comes in a special multipart-structure, which is represented in Tntnet by the class tnt::Multipart. This has references to all query-parameters including uploaded files.

You get a const reference to this multipart-object with the method getMultipart() of your request-object. Within this multipart-object you can find your file with the method find(partName). The parameter partName is the same name, you gave your upload-field in your html-form. You get a tnt::Multipart::const_iterator to the part. If the file is not found, the iterator points to the end-iterator retrieved with request.getMultipart().end(). If found, the dereferenced iterator is a reference to a tnt::Part-object, which represents your uploaded file. You can ask for the mime-type with tnt::Part::getMimetype() and for the filename with tnt::Part::getFilename().

The simplest way to fetch the data is to call tnt::Part::getBody(). You get the data as a std::string. But this is not very efficient, because Tntnet needs instantiate a std::string and copy the data. There is a iterator-interface for this. tnt::Part defines a const_iterator. Iterators to the start of your body is fetched with the getBodyBegin() and part the end with getBodyEnd(). If you don't need a std::string this is more efficient.

This all sounds very complicated, but I hope it gets a little clearer, when you see a example.

The form looks like this:

<form method="post" enctype="multipart/form-data">
 <input type="file" name="upload">
 <input type="submit">
</form>

And the code to process the uploaded file:

  <%cpp>
  const tnt::Multipart& mp = request.getMultipart();
  tnt::Multipart::const_iterator it = mp.find("myfile");
  if (it != mp.end())
  {
    // we found a uploaded file - write it to some upload-area
    std::ofstream out("upload/" + it->getFilename());

    out << it->getBody(); // this is less efficient, because a temporary std::string
                                // is created and the data is copies into it

    // more efficient is the use of iterators:
    for (tnt::Part::const_iterator pi = it->getBodyBegin(); pi != it->getBodyEnd(); ++pi)
      out << *pi;

    // ... or using STL-algorithm and ostreambuf_iterator:
    std::copy(it->getBodyBegin(),
              it->getBodyEnd(),
              std::ostreambuf_iterator(out));
  }
  </%cpp>

You can find another example in the tntnet-package in sdk/demos/upload. The application is a little online-hexdumper for the web. The user can upload a file and see the first 1024 bytes as a hexdump.

Copyright © 2008 The Tntnet Development Team
Tntnet 1.6