0

trying to replicate a cURL request to an appliance API with python Requests

curl -qgsSkH "Content-Type: multipart/form-data"
--no-progress-bar
--header "X-Api-Token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
-F "filename=@cygdrive/c/tmp/test.txt"
-F "options={\"application\":\"2\",\"timeout\":\"500\",\"priority\":\"0\",
\"profiles\":[\"win7-sp1\"],\"analysistype\":\"0\",\"force\":\"true\",
\"prefetch\":\"0\"}"
https://xxx.xxx.xxx.xxx:443/apis/v1.1.0/submissions

I have succefully authenticated to the API and can use the recieved token in the POST request. My current python function is shown below.

def api_file_submit(api_token, file_name):
login_headers = {'X-Api-Token': api_token, 'Accept': 'application/json', 'Content-Type': 'multipart/form-data'}
files = {"filename": open(file_name, 'rb')}
sub_options = {"application": "-1", "timeout": "240", "priority": "0", "profiles": ["Win7 Sp1"],
               "analysistype": "0", "force": "false", "prefetch": "value"}
j = simplejson.dumps(sub_options)
data = {'options': j}
r = requests.post(api_submit, headers=login_headers, files=files, data=data, verify=False)
print "REQUEST HEADER: " + str(r.request.headers)
print "REQUEST BODY: " + str(r.request.body)
print "RESPONSE HEADER: " + str(r.headers)
print "RESPONSE CONTENT: " + str(r.content)
print "RESPONSE STATUS: " + str(r.status_code)
print "RESPONSE REASON: " + str(r.reason)
return

The API returns a HTTP 400, Bad Request when attempting to POST. below are the results of the function

    REQUEST HEADER: {'Content-Length': '424', 'Accept-Encoding': 'gzip, deflate', 'Accept': 'application/json', 'User-Agent': 'python-requests/2.11.1', 'Connection': 'keep-alive', 'X-Api-Token': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'Content-Type': 'multipart/form-data'}
REQUEST BODY: --63a06536e02c4479a846c5fe320cdf7f
Content-Disposition: form-data; name="options"

{"force": "false", "profiles": ["Win7 Sp1"], "priority": "0", "application": "-1", "prefetch": "value", "timeout": "240", "analysistype": "0"}
--63a06536e02c4479a846c5fe320cdf7f
Content-Disposition: form-data; name="filename"; filename="test.vbs"

x = msgbox("this is an test file", 0, "test file")
--63a06536e02c4479a846c5fe320cdf7f--

RESPONSE HEADER: {'Content-Length': '257', 'Expires': '0', 'Connection': 'close', 'Pragma': 'no-cache', 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Date': 'Fri, 24 Mar 2017 17:11:47 GMT', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json;charset=ISO-8859-1'}
RESPONSE CONTENT: {"apis":{"@version":"v1.1.0","description":"Error parsing options, please check you have provided a file for upload and included 'options' in json format as part of request","errorCode":"BESUB1001","httpStatus":400,"message":"Could not parse input"}}
RESPONSE STATUS: 400
RESPONSE REASON: Bad Request

Process finished with exit code 0

What am I missing to properly format the request and submit the file, replicating the cURL request above?

nate_
  • 5
  • 2
  • I recommend you add a files=files to your post request and remove it from the data area. http://stackoverflow.com/questions/22567306/python-requests-file-upload – Artagel Mar 24 '17 at 17:36

1 Answers1

0

opened the file, not as a dictionary, just got the handle formatted options as JSON, and included in the "files"

def api_file_submit(api_token, file_name):
login_headers = {'X-Api-Token': api_token, 'Accept': '*/*'}
files = open(file_name, 'rb')
sub_options = {'application': '0', 'timeout': '240', 'priority': '0', 'profiles': ['win7-sp1'], 'analysistype': '2', 'force': 'false', 'prefetch': '1'}
submissionData = ('', json.dumps(sub_options), 'application/json')
files = {'options': submissionData, 'filename': files}
r = requests.post(api_submit, headers=login_headers, files=files, verify=False)
nate_
  • 5
  • 2