Data Streaming & File Upload
If you want to generate HTTP requests with very large bodies, you may want to use streams to upload
In addition to reducing memory usage and saving the TUI from having to load and display a giant body, streaming also enables some additional features for multipart form bodies.
What is Streaming?
Streaming is when the HTTP client sends bytes directly from a source such as a file to the HTTP server without loading the entire body into memory. It's useful when the body is very large because it saves time and memory.
Streaming in Slumber
Slumber supports streaming in these contexts:
stream
request bodyform_multipart
request body fields
and from these functions:
# These bodies **WILL** be streamed
file:
method: POST
url: "{{ host }}/upload"
body:
type: stream
data: "{{ file('image.png') }}"
command:
method: POST
url: "{{ host }}/upload"
body:
type: stream
data: "here's some bytes: {{ command(['head', '-c', '1000', '/dev/random']) }}"
multipart:
method: POST
url: "{{ host }}/upload"
body:
type: form_multipart
data:
image: "{{ file('./image.png') }}"
# These bodies will **NOT** be streamed
file:
method: POST
url: "{{ host }}/upload"
# The template contains multiple chunks, so it can't be streamed
body: "{{ file('image.png') }}"
Multipart File Streaming
In addition to support for general streaming of bytes, form_multipart
fields also have special support for file uploads. If the value of a field is a template with a single chunk, and the final call of the chunk is to file()
, then the fille will be uploaded directly. This has two effects on that part of the form:
- The
Content-Type
header will be set based on the file extension - The
Content-Disposition
header will have thefilename
field set
Here's an example:
multipart_file:
method: POST
url: "{{ host }}/upload"
body:
type: form_multipart
data:
image: "{{ file('./data/data.json') }}"
This will generate a request body like:
--BOUNDARY
Content-Disposition: form-data; name="file"; filename="data.json"
Content-Type: application/json
{ "a": 1, "b": 2 }
--BOUNDARY--
But if you generate the same body with an equivalent command()
call, the body will still be streamed, however the headers will not be set based on the file path.
multipart_command:
method: POST
url: "{{ host }}/upload"
body:
type: form_multipart
data:
image: "{{ command(['cat', './data/data.json']) }}"
This will generate a request body like:
--BOUNDARY
Content-Disposition: form-data; name="file"
{ "a": 1, "b": 2 }
--BOUNDARY--