federicotdn / verb

Organize and send HTTP requests from Emacs
https://melpa.org/#/verb
GNU General Public License v3.0
523 stars 21 forks source link

Multipart requests seem to not be working reliably #50

Closed bigodel closed 2 months ago

bigodel commented 1 year ago

The problem

I have been having issues using Verb for multipart requests. When trying to use to make requests to a Eclipse Jetty server I was having two kinds of issues:

  1. If I was using a "big" file, such as a PDF, it would throw an exception with the message: "Header section has more than 10240 bytes (maybe it is not properly terminated)";
  2. If I was using a small text file the exception message changed to: "Stream ended unexpectedly".

Steps to reproduce

The request I was using is the following:

POST http://myserver.com
Content-Type: multipart/form-data; boundary={{(verb-boundary)}}

{{(verb-part "file" "foo")}}
Content-Type: text/plain

{{(verb-read-file "/tmp/foo")}}
{{(verb-part)}}

where /tmp/foo's content is simply testing. And the problem occurs regardless of using \r\n as newline.

I also tried doing requests to HTTPBin to see if it was a problem with my server's setup. I constructed the request as follows

POST https://httpbin.org/post
Content-Type: multipart/form-data; boundary={{(verb-boundary)}}

{{(verb-part "file" "foo")}}
Content-Type: text/plain

{{(verb-read-file "~/tmp/foo")}}
{{(verb-part)}}

The expected result is

{
    "args": {},
    "data": "",
    "files": {
        "foo": "testing\n"
    },
    "form": {},
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate, br",
        "Content-Length": "222",
        "Content-Type": "multipart/form-data; boundary=--------------------------742230863549894201272436",
        "Host": "httpbin.org",
        "Postman-Token": "32289e44-f995-434b-8e9b-1e9d429737e3",
        "User-Agent": "PostmanRuntime/7.30.0",
        "X-Amzn-Trace-Id": "Root=1-63ac5fc2-78deed831e69a1274699c227"
    },
    "json": null,
    "origin": "187.61.201.31",
    "url": "https://httpbin.org/post"
}

but instead the response I get doesn't have anything under the "files" key (also regardless of using CLRF as newline).

Using Postman

For testing purposes, I decided to try out the same request on Postman. Roughly the same request on both my web server and HTTPBin work fine on Postman. Here's how Postman formats the HTTPBin request

POST /post HTTP/1.1
Host: httpbin.org
Content-Length: 184
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="foo"; filename="foo"
Content-Type: text/plain

testing
----WebKitFormBoundary7MA4YWxkTrZu0gW

and it is similar with my own server's request, just changing the Host header.

Closing thoughts

I have a theory that this issue is mainly caused by the lack of a space between the Content-Type: text/plain and the data from the file, but I'm not sure if that's the case on the final request, but I can observe it when exporting the requests to either Verb or cURL formats, as shown bellow

POST https://httpbin.org/post
User-Agent: Verb 2.15.0 on Emacs 28.2
Content-Type: multipart/form-data; boundary=NyiMgyfrP5nE1nvdFaG2oFNcu1NtrJjsxnFMbtDZCSEU1gjOhTiqbGnZ8tWTiecz

--NyiMgyfrP5nE1nvdFaG2oFNcu1NtrJjsxnFMbtDZCSEU1gjOhTiqbGnZ8tWTiecz
Content-Disposition: form-data; name="file"; filename="foo"
Content-Type: text/plain
testing
--NyiMgyfrP5nE1nvdFaG2oFNcu1NtrJjsxnFMbtDZCSEU1gjOhTiqbGnZ8tWTiecz--
curl 'https://httpbin.org/post' \
-H 'User-Agent: Verb 2.15.0 on Emacs 28.2' \
-H 'Content-Type: multipart/form-data; boundary=fLB58LcL3gtke9o8WvDKqGcJ9JJREyybreyDVwQeHTc6EeaqbcmR7IVZtE5wGUXy' \
-X POST \
--data-raw '--fLB58LcL3gtke9o8WvDKqGcJ9JJREyybreyDVwQeHTc6EeaqbcmR7IVZtE5wGUXy
Content-Disposition: form-data; name="file"; filename="foo"
Content-Type: text/plain
testing
--fLB58LcL3gtke9o8WvDKqGcJ9JJREyybreyDVwQeHTc6EeaqbcmR7IVZtE5wGUXy--'
bigodel commented 1 year ago

Also, I would like to propose that the cURL version of form data requests be formatted as curl -F <name>=@<filename> ....

federicotdn commented 2 months ago

I've tried to fix this in https://github.com/federicotdn/verb/commit/c4e6a75b85027f7f3d635e54d3d190c3d34fd01e, basically as you said the newlines were incorrectly set to LF when they should've been set to CRLF. There is no easy way of enforcing users to use CRLF (apart from the old README section that explained how to add them manually) so the new solution is to just add this to requests using multipart:

:properties:
:Verb-Map-Request: verb-body-cr-to-crlf
:end: