Blog

- October 27, 2015

File upload corresponds to the ability to send files from an HTTP client like HTML pages or Java applications to an HTTP-compliant server.

After having described the different concepts behind this issue, we will see that Restlet Framework provides a consistent support to implement it within Java applications at both client and server-side levels.

Possible use cases

Sending a single file content

If you only need to send a file, you can simply use a classical request and provide the file content within the payload, as described below. Don’t forget to use the appropriate content type for the content you send.

POST /upload HTTP/1.1
(...)
Content-Type: text/plain
Content-Length: 9

some text

 

The server doesn’t even know that the request corresponds to a file upload. It receives the content and handle it. The drawback of this approach is that you can’t send several files into the same request and only provide additional hints regarding the file like file name, create date, etc. can be added. Here is a sample below:

POST /upload HTTP/1.1
(...)
Content-Disposition: none; filename="<file name.ext>" 
Content-Type: text/plain
Content-Length: 9

some text

 

For such reasons, HTTP supports multipart payloads as well.

Sending several file contents

Such requests are natively supported by HTML forms. The latter by default encode data using the content type application/x-www-form-urlencoded. But another value is also usable at this level: multipart/form-data. This allows to send several files into a single request mixing form data and files. Such forms can contain both classical input fields like input, textarea and select and file input fields.

Multipart file upload is described by these two specifications:

Some details are also covered in the section Form submission of the HTML specification.

The following code describes how to enable multipart support in an HTML form using the attribute enctype and inputs to select files:

<form method="POST" enctype="multipart/form-data" action="/upload">
   File to upload: <input type="file" name="upfile"><br/>
   Notes about the file: <input type="text" name="note">
   <br/><br/>
   <input type="submit" value="Press"> to upload the file!
</form>

When submitting the form, the following request will be sent:

POST /upload HTTP/1.1
(...)
Content-Type: multipart/form-data; boundary=---------------------------2098012650496948462277524989
Content-Length: 339

-----------------------------2098012650496948462277524989
Content-Disposition: form-data; name="upfile"; filename="test.txt"
Content-Type: text/plain

some text
-----------------------------2098012650496948462277524989
Content-Disposition: form-data; name="note"

desc
-----------------------------2098012650496948462277524989--

As you can see, the request payload contains several parts delimited by a separator defined within the content type header as parameter. Each part contains a name and eventually a file name if it corresponds to a file content.

Now that we reviewed the foundations of file upload and multipart requests, it’s time to deal with how to handle file upload requests within a Restlet Framework server application.

Handling multipart requests within Restlet Framework server applications

Restlet Framework provides support for multipart requests through its extension `org.restlet.ext.fileupload`. The latter leverages the FileUpload library from Apache Commons and allows us to parse a multipart request and extract content from its different parts from a Restlet Framework server resource.

In this case, the server resource method needs to work directly on raw representation and detect if the received content is a multipart one:

public class UploadServerResource extends ServerResource {
   @Post
   public Representation handleUpload(Representation entity) {
       if (entity != null && MediaType.MULTIPART_FORM_DATA.equals(
                                              entity.getMediaType(), true)) {
           // Handle content
       } else {
           throw new ResourceException(
                Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE);
       }
   }
}

Let’s tackle now the way to extract data from the request.

Creating an iterator for each request parts

The first step here is to create a DiskFileItemFactory. The latter comes from Commons FileUpload itself and allows you to specify the size threshold, in bytes, below which items will be retained in memory and above which they will be stored as a file.

The class RestletFileUpload from the extension fileupload provides convenient support to extract different payload parts from the request. The file item iterator is used below to browse the received data:

DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(1000240);
RestletFileUpload upload = new RestletFileUpload(factory);
FileItemIterator fileIterator = upload.getItemIterator(entity);

You’ll notice that two other methods, `parseRepresentation` and `parseRequest`, are also available on the class `RestletFileUpload`. Contrary to the `getItemIterator` that leverages streams, these provide a list of `FileItem` objects and will result in the writing of the parts on the disk. There could be impact on performance in the case of contents with big sizes.

Iterating over parts

Now you have an iterator, you use it in a loop to iterate over the different parts. For each one, a stream on the current part can be accessed. It actually corresponds to an instance of the class FileItemStream.

while (fileIterator.hasNext()) {
   FileItemStream fi = fileIterator.next();
   (...)
}

Like the class FileItem, file item streams give access to metadata about the current parts like the field name, its content type, eventually its corresponding filename and the ability to check if the part is a file one or a form one.

String fieldName = fi.getFieldName();
String contentType = fi.getContentType();
if (!fi.isFormField()) {
   String fileName = fi.getName();
}

In both cases (file part or form part), you can get an input stream to read the content in the current part. You can notice that the following snippet describes how to get the text content. You should leverage the content type of the part and manage the stream accordingly, especially for binary content.

BufferedReader br = new BufferedReader(
new InputStreamReader(fi.openStream()));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
 sb.append(line);
}
sb.append("\n");

It’s time now to deal with the support provided by Restlet on the client part.

Sending multipart requests with Restlet

Restlet also provides support from the client side for uploading and for multipart requests. It allows to programmatically emulate a form submission.

Instead of sending the data from a form within an HTML page, you can do this directly from a Java application with Restlet Framework. In this case you need to leverage the org.restlet.extends.html extension.

The first step consists in creating parts from files you want to upload. They actually correspond to file representation that includes a content disposition to specify the file name:

Form fileForm = new Form();
fileForm.add(Disposition.NAME_FILENAME, "myimage.png");
Disposition disposition = new Disposition(Disposition.TYPE_INLINE, fileForm);
FileRepresentation entity = new FileRepresentation(f, MediaType.IMAGE_PNG);
entity.setDisposition(disposition);

You simply then have to create a multipart representation and add the previous file part. You can add another file parts but also form parts if any.

FormDataSet fds = new FormDataSet();
fds.setMultipart(true);
FormData fdFile = new FormData("fileToUpload", entity);
fds.getEntries().add(fdFile);
FormData fdValue = new FormData("field", "value");
fds.getEntries().add(fdValue);

The representation can be sent then using a classical Restlet request:

ClientResource cr = new ClientResource("http://localhost:8183/upload");
cr.post(mEntity);

Conclusion

In this article, we described how to send file content to servers using the Restlet Framework. The approach relies on standard mechanisms of HTTP and on the multipart format. The framework provides a consistent and convenient support to build and consume such payloads within your Web APIs and RESTful services.

Last closing remark, although we’re focusing here on multipart for upload requests, you could also leverage multipart payloads to send back to the client the content of several files.

  • Amila

    I’m using restlet 2.2.3
    I did not find the class MultipartRepresentation. what is the full qualified name of that class and the jar file containing that?

  • Hello,
    In fact, it was a typo in the post. The MultipartRepresentation class doesn’t exist in the org.restlet.ext.html extension. I just fixed this… Thanks!