HTTP is the foundation of today’s internet. Not only is it used to browse webpages, but it’s also used to interact with APIs and even live stream video! HTTP owes its popularity in part to its versatility. It doesn’t matter what kind of content you want to send; HTTP will happily transmit anything. You only need to let the receiver know what kind of data you’re sending by setting a proper
But what if you need to send data of multiple types in a single request? Say, your cat’s name and picture? This is where multipart content type comes into play.
The multipart content type is widespread. You might not realize it, but you’ve most likely used it many times in your life.
The most common use for multipart requests is web forms. When you have a form with only text-based input elements — like text inputs, checkboxes, date pickers, etc. — your browser sends that data as an
application/x-www-form-urlencoded payload, which essentially means encoding the inputs as
key=value pairs. However, as soon as the form contains an input that cannot be encoded as text, such as a file input, the browser uses the
multipart/form-data content type.
The other situation where a multipart content type is used is when sending emails with attachments. A regular email is just text, and so it’s sent with
text/plain, or sometimes the
text/html content type. But PDF or image attachments aren’t text — they’re binary data formats, and so a multipart message is used to send both the email’s text and the attachment.
The syntax of multipart messages is defined in RFC 1521 — MIME, which also defines a couple other content types commonly used on the internet. The RFC defines multiple types of multipart messages (e.g.
multipart/mixed), but they all have exactly the same format. Surprisingly, this RFC doesn’t define the
multipart/form-data content type, but this content type follows the same specification.
Conceptually, a multipart message is a wrapper around multiple distinct messages. Each part declares its own content type (e.g.
image/jpeg), and optionally other metadata. This is what the example HTTP request, sent by — for example — a web browser, looks like:
POST /profile HTTP/1.1 Content-Type: multipart/form-data; boundary=example-part-boundary --example-part-boundary Content-Disposition: form-data; name="full_name" Content-Type: text/plain Arek Gil --example-part-boundary Content-Disposition: form-data; name="profile_picture"; filename="profilepic.jpeg" Content-Type: image/jpeg <binary image data> --customboundary--
When the request is triggered by submitting a form in the browser, you’ll always see that each part declares its name using the
Content-Disposition header. The
Content-Disposition header may also specify the name of the file if that part should be interpreted as a file attachment.
Multipart messages are useful when transmitting files, and PDF is a file format, so it’s no surprise that we heavily rely on multipart messages in our HTTP-based products, PSPDFKit for Web Server-Backed and PSPDFKit Processor.
Whenever you upload a new document to PSPDFKit for Web Server-Backed (a PDF, an image, or an Office file), this is done by sending a file, or by sending that file as a part of the multipart request. The latter option allows you to customize many aspects of document creation, such as setting the title and importing annotations via XFDF.
In Processor, to apply transformations to your document, you send a file and a list of instructions as parts of the multipart request. Or, when you’re using PDF Generation, the generated document’s layout information, the HTML file, and supporting assets are all distinct parts of the same multipart request.
In this post, we looked at multipart messages: when they’re used, how they look, and how we use them at PSPDFKit. The multipart format isn’t complicated, and it’s extremely widely used. And so the next time you upload files on the web, it’s likely you’ll be using this format, and you’ll know all about how it works.