Issue
I need to send a POST
request with curl via command line. ContentType needs to be multipart/form-data
My payload is JSON, but it's really big, so I can't send it directly via curl (Argument list too long). Instead I need to require the content via a file
Without getting the content from a file everything works fine
curl "https://domain/endpoint.php" \
-F "jsondata={\"jsonkey\":\"jsonvalue\"};type=application/json"
=>
array(1) {
["jsondata"]=>
string(23) "{"jsonkey":"jsonvalue"}"
}
(sent as multipart/form-data)
But when I put the same (small test) json in a file and use that in my curl command. The result on the server side is different
curl "https://domain/endpoint.php" \
-F "jsondata=@curl_data3.json;type=application/json"
=>
array(1) {
["jsondata"]=>
array(5) {
["name"]=>
string(15) "curl_data3.json"
["type"]=>
string(16) "application/json"
["tmp_name"]=>
string(14) "/tmp/php5k58m4"
["error"]=>
int(0)
["size"]=>
int(23)
}
}
The file (curl_data3.json) just contains {"jsonkey":"jsonvalue"}
It seems like I'm just sending the file itself and not the content of the file :-/
Solution
HTML forms, for which multipart/form-data was designed, support several kinds of input field, and in particular distinguish input fields which are 'file upload' from other fields. Fields which are files contain metadata about the file. See https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart/form-data-encoding-algorithm and as referenced RFC7578 especially 4.2:
For [a part of multipart/form-data] that represents the content of a file, a name for the file SHOULD be supplied as well, by using a "filename" parameter of the Content-Disposition header field. The file name isn't mandatory ....
curl -F field=@file
implements this per standard, and apparently your server expands this into the json structure you get.
If you instead use curl -F field=<file
(with quoting as needed because <
is special in shell, CMD or PS) it sends the contents of the file as an ordinary non-file field. See the man page:
[-F] enables uploading of binary files etc. To force the 'content' part to be a file, prefix the file name with an @ sign. To just get the content part from a file, prefix the file name with the symbol <. The difference between @ and < is then that @ makes a file get attached in the post as a file upload, while the < makes a text field and just get the contents for that text field from a file.
Answered By - dave_thompson_085