support multipart POST for apachebench? - performance

I want to use apachebench (ab) to test file upload performance.
I have read the manual and can't find a way to achieve my goal.
My goal is try to upload a file by a HTTP Request with POST method and multipart/form-data format.
The ab support "-p POST-FILE", but I only can find the format key=value&key2=value2
What the post data I want to send is
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryuUlX4554LPBjInc5
------WebKitFormBoundaryuUlX4554LPBjInc5
Content-Disposition: form-data; name="file"; filename="411c40d9.jpg"
Content-Type: image/jpeg
XXXXXXXXXXXXXXX (IMAGE DATA)
YYYYYYYYYYYYYYYYYYYYYYYYYYYYY
I googled for a while and can't find any related article or way to achieve that.
I use cURL and it works fine, but I want to do stress testing.
So I need use ab to achieve that goal.
Any suggestions?

This may be very late but might help others who were searching for the same thing...
$ ab -c 5 -n 5 -v 4 -p example_post.txt -T "multipart/form-data; boundary=miuxupsktcqtriloonfbdudrgtawascl" http://yourapplication.local/upload/
Credit to this guy.

Related

Adapt multipart/form-data request to curl with image and json in the same request

I need to rewrite this curl request extracted from the browser to execute it from bash, it is a multipart/form-data that combines the upload of an image together with a json in the same request, I have carried out several tests substituting the raw data for two -F but the server responds with error.
What would be the correct way?
I also fail to understand the key that is next to WebKitFormBoundary is a value that seems random, is it just a separator? can i use anything?
I have removed the headers that I considered irrelevant
curl 'https://localhost' \
-H 'Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryXXXXXXXXXXXXXXXX'
-H 'Accept: */*' \
--data-raw $'------WebKitFormBoundaryXXXXXXXXXXXXXXXX\r\nContent-Disposition: form-data; name="image"; filename="image.jpg"\r\nContent-Type: image/jpeg\r\n\r\n\r\n------WebKitFormBoundaryXXXXXXXXXXXXXXXX\r\nContent-Disposition: form-data; name="item"; filename="blob"\r\nContent-Type: application/json\r\n\r\n{"item1":"xxxx","item2":"yyyy"}\r\n------WebKitFormBoundaryXXXXXXXXXXXXXXXX--\r\n' \
Thanks
I also fail to understand the key that is next to WebKitFormBoundary is a value that seems random, is it just a separator? can i use anything?
yes and yes and practically speaking yes. it's supposed to be a random-guaranteed-unique string used as separator to signal start and end of forms.. if you know beforehand that none of your uploads contains the string stackoverflow, you could use Content-Type: multipart/form-data; boundary=stackoverflow for example (but this may break if you upload a file actually containing the string stackoverflow !), but you should let curl generate that string automatically, rather than specifying it yourself, curl will auto-generate a string that is practically guaranteed to be unique.
I have removed the headers that I considered irrelevant
... if you guessed wrong, the server may give you an error for missing a required header. assuimg that you didn't make any mistakes in removing irrelevant headers though, i think it's
curl 'https://localhost'\
--form "image=#image.jpg;type=image/jpeg"\
--form "item=#blob;type=application/json"
the request generated by that command is roghly:
POST / HTTP/1.1
Host: localhost
User-Agent: curl/7.81.0
Accept: */*
Content-Length: 359
Content-Type: multipart/form-data; boundary=------------------------7d0262831ce8f248
--------------------------7d0262831ce8f248
Content-Disposition: form-data; name="image"; filename="image.jpg"
Content-Type: image/jpeg
image.jpg content
--------------------------7d0262831ce8f248
Content-Disposition: form-data; name="item"; filename="blob"
Content-Type: application/json
["json lol"]
--------------------------7d0262831ce8f248--
as you can see above, Accept: */* is curl's default accept-header anyway, so there's no need to specify it, and curl auto-generated the boundary ------------------------7d0262831ce8f248 so there's no need to manually specify a boundary either.

Load testing server with http multipart/related request which contains audio content

We built a server which handles speech recorded by user using an app. The audio data is sent through http post in real time. The body looks like this:
--BOUNDARY
Content-Disposition: form-data; name="metadata"
Content-Type: application/json; charset="UTF-8"
<JSON FORMATTED METADATA HERE>
--BOUNDARY
Content-Disposition: form-data; name="audio"
Content-Type: application/octet-stream
<AUDIO BYTES HERE>
--BOUNDARY--
Now, I need to do load testing for the server. I am thinking of using ApacheBench and just do consistent uploading requests but I wish to use the same format as above for each request. How could that be setup in AB?
I was able to solve the problem by using the following command:
ab -p test -T "multipart/form-data; boundary=BOUNDARY" -c 1000 -n 1000 -l http://someipaddress.com/
where test is a file containing the post content.

JMeter Not Sending File with HTTP Request

I'm new to JMeter and trying to put a file to our API using an HTTP Request. When I put the file via curl using the -F flag, it works no problem.
Here's my curl request:
curl -X PUT -u uname:pword https://fakehostname.com/psr-1/controllers/vertx/upload/file/big/ADJTIME3 -F "upload1=#ADJTIME" -vis
and here's the relevant part of the response from the server:
> User-Agent: curl/7.37.1 Host: myfakehost.com Accept: */*
> Content-Length: 4190 Expect: 100-continue Content-Type:
> multipart/form-data; boundary=------------------------d76566a6ebb651d3
When I do the same put via JMeter, the Content-Length is 0 which makes me think that JMeter isn't reading the file for some reason. I know the path is correct because I browsed to the file from JMeter. Litte help?
In File Upload, make your file path RELATIVE to .jmx file or place next to it and specify file name only.
Thanks to everyone who offered solutions and suggestions. It turns out that the API I was trying to load test was the issue. I can PUT a file via curl no problem, but there's something about the Jmeter PUT that the API does not like. I finally tried doing a PUT to an unrelated API and was successful.

What is the proper format of a curl POST request to upload a file to Google Drive (using Drive REST API v3)?

In Google's documentation for the Drive REST API v3, they provide the following "example" for how to upload a file to Drive using the "simple upload" method:
POST /upload/drive/v3/files?uploadType=media HTTP/1.1
Host: www.googleapis.com
Content-Type: image/jpeg
Content-Length: number_of_bytes_in_file
Authorization: Bearer your_auth_token
JPEG data
I am trying to construct a curl POST request to upload a .csv to Drive. I have tried the following (as well as countless variations), with no success. It keeps returning with an Error 400 (bad request)!!! error:
curl -s "https://www.googleapis.com/upload/drive/v3/files?uploadType=media HTTP/1.1" -H "Authorization: Bearer $access_token" -H "Content-Type: $mime_type" -H "Content-Length: $file_size" -d "$file" -X POST
For reference, the variables are defined as:
file_size="$(du -b $file | awk '{ print $1 }')"
mime_type=$(file -ib "$file")
Anyway, Google doesn't explain the "JPEG data" part, and I suspect that is where my curl POST request is wrong.
I've found a bunch of relevant examples on both here and Github, but none of them worked for me (all of the ones I found were outdated, anyway). I also tried multipart uploading, but I also couldn't get that to work (and again, most of the examples here seemed outdated).

Cannot accept post in Sinatra using Curl

Just been tinkering with Sinatra and trying to get a bit of a restful web service going.
The error I'm getting at the moment is very specific though.
Take this example post method
post '/postMan/:someParam' do
#Edited here. This code can be anything. 411 is still the response
puts params[:someParam]
end
Seems simple enough. Take a param, make an object out of it, then go store it in whatever way the objects save method defines.
Heres what I use to post the data using Curl
$curl -I -X POST http://127.0.0.1/postman/123456
The only problem is, I'm getting 411 back and have no idea why.
To the best of my knowledge, 411 is length required. Here is the trace
HTTP/1.1 411 Length Required
Content-Type: text/html; charset=ISO-8859-1
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Date: Fri, 02 Mar 2012 22:27:09 GMT
Content-Length: 303
Connection: close
I 'Cannot' change the curl message in any way. So might anyone have a way to set the content length to be ignored in sinatra? Or some fix which doesn't involve changing the curl request?
For the record, it doesn't matter whether I use the parameters in the Post method or not. I could have some crazy code inside it, it will still throw the same error
As others said above, WEBrick wrongly requires POST requests to have a Content-Length header. I just pass an empty body, because it's less typing than passing in the header:
curl -X POST -d '' http://webrickwhyyounotakeemptyposts.com/
Are you sure you're on port 80 for your app?
When I run:
ruby -r sinatra -e "post('/postMan/:someParam'){puts params[:someParam]}"
and curl it:
curl -I -X POST http://127.0.0.1:4567/postMan/123456
HTTP/1.1 200 OK
X-Frame-Options: sameorigin
X-XSS-Protection: 1; mode=block
Content-Type: text/html;charset=utf-8
Content-Length: 0
Connection: keep-alive
Server: thin 1.3.1 codename Triple Espresso
it's ok. Had to change the URL to postManthough, your example threw a 404because you had postman.
The output was also as expected:
== Sinatra/1.3.2 has taken the stage on 4567 for development with backup from Thin
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:4567, CTRL+C to stop
123456
Ah. Try it without -I. It's probably sending a HEAD request and as such, not sending what you expect. Use -v if you want to show the headers.
curl -v -X POST http://127.0.0.1/postman/123456
curl -v -X POST -d "key=val" http://127.0.0.1/postman/123456
WEBrick erroneously requires POST requests to include the Content-Length header.
curl -H 'Content-Length: 0' -X POST http://example.com
Standardly, however, POST requests don't require a body and therefore don't require the Content-Length header.

Resources