I'm currently implementing a client application that POST's a file over HTTP and have implemented base64 encoding on the file's data parameter.
However, it appears that when inspecting the traffic between a simple HTML page with a file upload form and the server that no Content-Transfer-Encoding header is sent in the body when describing the file's parameter.
Is this the preferred way of POST'ing a file over HTTP?
No, the preferred way is using multipart/form-data encoding, exactly as you would use with HTML form based file uploads.
Related
I am trying to POST with URL encoded data. Based on the web server logs, I am not actually sending any data from Twilio (request size is always 131 bytes, no matter what I type in the Studio widget box).
What does a working form body look like? Do I need to encode it myself? How do I escape an "=" that is not part of the key-value structure?
When making an HTTP request with the widget, when it is set to make Form URL encoded requests you can set the HTTP parameter keys and values which will automatically encode the values. There are known as URL parameter as the encoding is Form URL encoding. The parameters are encoded as if they were in a URL, but they are sent as the POST body.
Flask has a method to return a file: http://flask.pocoo.org/docs/1.0/api/#flask.send_file
There is a parameter called as_attachment with a default of False, and there is a handwaavy statement about it: "For extra security you probably want to send certain files as attachment (HTML for instance)"
How do I know if my use case is "those certain files"? Or alternatively stated, what does this do as opposed to leaving this as False?
You'll find a clue in the same documentation, further down in the parameter list:
as_attachment – set to True if you want to send this file with a Content-Disposition: attachment header.
So when the flag is set, an extra header is added to the response, which controls how the browser will handle the response. From the MDN documenation on Content-Disposition:
In a regular HTTP response, the Content-Disposition response header is a header indicating if the content is expected to be displayed inline in the browser, that is, as a Web page or as part of a Web page, or as an attachment, that is downloaded and saved locally.
Without an explicit Content-Disposition header, a text/html response from your Flask server will be shown as a web page in the browser. If you needed the file to be saved to disk instead (the browser prompting you what to do with the file), then you need to have a Content-Disposition: attachment set.
So when your response content type is likely to be shown in the browser as a web page but you want the user to download it instead, use as_attachment=True. These days, in addition to HTML, you probably want to set that flag for images, PDF files, and XML as well.
I'm developing a web page with a form which returns a PDF document based on the form data. Currently I use the HTTP response fields
Content-Type:Â application/pdf
Content-Disposition: attachment; filename="foo.pdf"
However, since the field Content-Disposition is non-standard and doesn't work in all browsers I'm looking for a different approach. Do I have to save the PDF document on the server? What is the modus operandi?
Edit: By "doesn't work in all browsers" I mean that with some browsers the filename is not set to foo.pdf. Dillo, for instance, just sets the default filename (in the download dialog) to the basename of the URL path (plus query string).
Do I have to save the PDF document on the server?
No. As far as the HTTP client is concerned it, the inner workings of the server are completely opaque to it. All it sees is a TCP stream of bytes from the server and how exactly that stream is produced doesn't matter as long as it matches the specified Content-Type.
Just send the PDF right after the HTTP headers and you're done with.
Update due to comment
So if you're wondering how to supply a filename without using a header field: Just augment the URL with it. I.e. something like
http://${DOMAIN}/${PDF_GENERATOR}/${DESIRED_FILENAME}
In the HTTP server add a rewrite rule to simply omit the filename part and redirect to just
http://${DOMAIN}/${PDF_GENERATOR}
The HTTP client does not see that, all it see is some URL ending with a "filename", that it can present the user as a default for saving.
I'm trying to understand the concept of uploading and how Base64 may/may not relate.
When I have a an HTML form (with the multipart attribute) that uploads an attachment (e.g. an image/executable) upon submission - does the browser Base64 encode it first, and then send that to a processing page? Or does the browser send raw binary data to the target page?
I currently upload to a webservice on an nginx server using the upload module (http://www.grid.net.ru/nginx/upload.en.html) from a custom desktop application doing a simple multipart-form POST that sends a file in one part and a base64 encoded XML with the file's metadata in another part.
The server receives this POST, passes it to my webservice which reads the metadata, processes the file and all is good.
What I want to do now is use the upload module's upload_resumable directive to do the POST in several chunks to minimize disconnection chances and allow resume. I can currently do this following the protocol described here: http://www.grid.net.ru/nginx/resumable_uploads.en.html
One sends byte ranges of the file along with some headers to identify the chunk and the session in several posts and once all the parts have been uploaded, nginx will compose the final POST containing the file name and path and pass it to your upload_pass location (which in my case CGIs to a django app).
However, I am not clear on how one would send a multipart post with this method since the protocol indicates that the body of the POST must be the bytes indicated in the byte range. I need the final post to also contain the XML I wrote about above.
I can think of sending the XML as the first bytes of the body and a header that indicates how many bytes belong to it but that would mean extra handling of the final file to remove that header and the final files are potentially in the GB size range.
Any other ideas?
Since the protocol supported by nginx specifically states that the post should not be multipart I ended up sending the file in the body, and the rest of the parameters encoded in the URL. Not the prettiest URLs but it works.