415 error when uploading to API - python

I am trying to write an automatic subtitle finder in Python 3.x using The SubDB (http://thesubdb.com/api/). I'm now working on an upload feature. However, I cannot get it to work. I keep getting a 415 error (Unsupported Media Type). On the SubDB website, a 'request sample' is given:
POST /?action=upload HTTP/1.1
Host: api.thesubdb.com
User-Agent: SubDB/1.0 (Pyrrot/0.1; http://github.com/jrhames/pyrrot-cli)
Content-Length: 60047
Content-Type: multipart/form-data; boundary=xYzZY
- - --xYzZY
Content-Disposition: form-data; name="hash"
edc1981d6459c6111fe36205b4aff6c2
- - --xYzZY
Content-Disposition: form-data; name="file"; filename="subtitle.srt"
Content-Type: application/octet-stream
[PAYLOAD]
But I do not know how to interpret this and I couldn't find an answer online. This is my current code:
def uploadSubtitle(hash, path):
params = {'action': "upload", 'hash': hash}
response = requests.post(
url=base_url.format(urllib.parse.urlencode(params)),
data=open(path,'r').read(),
headers = {
'User-Agent': user_agent,
'Content-Length': 51200,
'Content-Type': "multipart/form-data; boundary=xYzZY",
'Host': "api.thesubdb.com"
}
)
return response.status_code
Any advice would be greatly appreciated!

I was having the same issues.
You may want to see this https://github.com/ivandrofly/SubDBSharp
Try following:
POST /?action=upload HTTP/1.1
Host: api.thesubdb.com
User-Agent: SubDB/1.0 (Pyrrot/0.1; http://github.com/jrhames/pyrrot-cli)
Content-Length: [Subtitle content length including boundary length]
Content-Type: multipart/form-data; boundary=xYzZY
--xYzZY
Content-Disposition: form-data; name="hash"
edc1981d6459c6111fe36205b4aff6c2
--xYzZY
Content-Disposition: form-data; name="file"; filename="subtitle.srt"
Content-Type: application/octet-stream
[SUBTITLE CONTENT]
--xYzZY
# Content-Length:
Content length should be from --xYzZY to last --xYzZY see above.
Note: Boundary started --xYzZY and ends after [SUBTITLE CONTENT]

Related

Python requests post body

i am trying to send sql query to my wordpress database using adminer script but the problem im missing somthing needed to be sent as body or headers in my opinion ( if i'm wrong please connect me )
Request raw
POST /REV/adminer-4.7.5-en.php?server=localhost&username=adepfran_wp975&db=adepfran_wp975&sql=select%20*%20from%20wplj_users HTTP/1.1
Host: mywebsite
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://mywebsite/REV/adminer-4.7.5-en.php?server=localhost&username=adepfran_wp975&db=adepfran_wp975&sql=
Content-Type: multipart/form-data; boundary=---------------------------1328964205768204682490124619
Content-Length: 425
Cookie: adminer_sid=00e0c898e031284904f8e51b591c1dee; adminer_key=320bc6e9870ffdf2f54982cb2292de87
Connection: close
Upgrade-Insecure-Requests: 1
-----------------------------1328964205768204682490124619
Content-Disposition: form-data; name="query"
select * from wplj_users
-----------------------------1328964205768204682490124619
Content-Disposition: form-data; name="limit"
-----------------------------1328964205768204682490124619
Content-Disposition: form-data; name="token"
401937:659783
-----------------------------1328964205768204682490124619--
Headers raw
-----------------------------1328964205768204682490124619
Content-Disposition: form-data; name="query"
select * from wplj_users
-----------------------------1328964205768204682490124619
Content-Disposition: form-data; name="limit"
-----------------------------1328964205768204682490124619
Content-Disposition: form-data; name="token"
401937:659783
-----------------------------1328964205768204682490124619--
also i intercepted the requests using Burp Suite to clarify further
Request raw
Request parameters
Request Headers
my actual code
ses = requests.Session()
data = {"server": "localhost",
"username": wpuser,
"db": wpdb,
"sql": "SELECT * from wplj_users"}
url="https://mywebsite/REV/adminer-4.7.5-en.php?server=localhost&username=adepfran_wp975&db=adepfran_wp975&sql=SELECT%20*%20from%20wplj_users"
request = ses.post(url,data=data )
the request without limit,query,token (Content-Disposition) does not return the wanted response , how can i pass them ?
It seems you have to send it as files=
For test I used https://httpbin.org which send back all what you get in requests so I can display it and compare with expected data
In files I used (None, "SELECT * from wplj_users") so this None will remove filename="query"
import requests
params = {
'server': 'localhost',
'username': 'adepfran_wp975',
'db': 'adepfran_wp975',
'sql': 'SELECT * from wplj_users',
}
data = {
"query": (None, "SELECT * from wplj_users"),
"limit": (None, ""),
"token": (None, "401937:659783"),
}
headers = {
'User-Agent': 'Mozilla/5.0',
#'Referer': 'https://mywebsite/REV/adminer-4.7.5-en.php?server=localhost&username=adepfran_wp975&db=adepfran_wp975&sql='
# requests.Session() should care of cookies so this header shouldn't be needed
#'Cookie': 'adminer_sid=00e0c898e031284904f8e51b591c1dee; adminer_key=320bc6e9870ffdf2f54982cb2292de87'
}
url = "https://httpbin.org/post"
#url = "https://mywebsite/REV/adminer-4.7.5-en.php"
s = requests.Session()
#r = s.get(url) # to get fresh cookies
r = s.post(url, params=params, headers=headers, files=data)
print('\n=== url ===\n')
print(r.request.url)
print('\n=== headers ===\n')
for key, val in r.request.headers.items():
print('{}: {}'.format(key, val))
print('\n=== body ===\n')
print(r.request.body.decode())
Results
=== url ===
https://httpbin.org/post?server=localhost&username=adepfran_wp975&db=adepfran_wp975&sql=SELECT+%2A+from+wplj_users
=== headers ===
User-Agent: Mozilla/5.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 331
Content-Type: multipart/form-data; boundary=79f18e4306b943ea92a49bae21b51b9c
=== body ===
--79f18e4306b943ea92a49bae21b51b9c
Content-Disposition: form-data; name="query"
SELECT * from wplj_users
--79f18e4306b943ea92a49bae21b51b9c
Content-Disposition: form-data; name="limit"
--79f18e4306b943ea92a49bae21b51b9c
Content-Disposition: form-data; name="token"
401937:659783
--79f18e4306b943ea92a49bae21b51b9c--

Missing header information using Python's requests library

I am using Python's (3.5.2) requests library (2.12.4) to post a query to the Primer-BLAST website. Below is the script I've written for this task:
#!/usr/bin/env python
import requests
# BaseURL being accessed
url = 'https://www.ncbi.nlm.nih.gov/tools/primer-blast/primertool.cgi'
# Dictionary of query parameters
data = {
'INPUT_SEQUENCE' : 'TCTTCTGAGAAAGTCTGAGGCTCCTTAGTACCTTCTCTAGTATGAACTGTTCAGCCTGCCCGCAAGTTGTAACTACGCAGGCGCCAAGACAGCCAACCAAGGAGGCTGCAGA',
'ORGANISM' : 'Mus musculus'
}
# Make a POST request and read the response
with requests.session() as session:
poster = session.post(url, data=data)
for key, value in poster.headers.items():
print(key, ':', value)
I need to retrieve the NCBI-RCGI-RetryURL field from the response's header information. However, I can only see this field when I use the HTTP trace extension in Google Chrome. Below is the full trace of the POST and response using Google Chrome:
POST https://www.ncbi.nlm.nih.gov/tools/primer-blast/primertool.cgi
Origin: https://www.ncbi.nlm.nih.gov
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBflp51Ny9ReeA5A9
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: https://www.ncbi.nlm.nih.gov/tools/primer-blast/index.cgi?LINK_LOC=reset
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8
Cookie: sv-userdata-key-www.ncbi.nlm.nih.gov=G5KxXzyQ81U_vs1aHK_7XDWciF1B8AjjDUmDunVbhIZhZ4p4t_SVK4ASpbTT8iDSJVcxBH9oUAB3K2xNWjp3G0koYCloBlYuSxdoIGIkYzl2; ncbi_sid=0751457F9A561D01_0000SID; _ga=GA1.2.567134514.1503994317; _gid=GA1.2.654339584.1503994317; _gat=1; starnext=MYGwlsDWB2CmAeAXAXAbgK7RAewIYBM4lkAmAXgAcAnMAW1ioCMRcBnRAMgBYzm3FWsXFWAALDgEZymHAUkBOMgAYA7AFYpXFQDF5AQTUA2ACIBRFRKVXrN2xI4klygMJcSltQA59R0wGY/S1tg63t3Shp6JhZ2AFI/PQA5AHlE03i9PnZBYTEMlLSHcgB3UoA6aGBGMAqQWgqwUTKAc2wANwceajoGLMR81NMHQwie6P4BtIy+nJFxEhVRqL7J9ISZoTnVh08l3pj+lWcC9KON3NFYo5OHRQkuLiUOPyd5K2eJMnvH5/JPDWefjIADNcCBBM8eIgqOhYM81F83GpniMJH4SPJnosSFxnrtAoZ5Li/IoXp5DCpuE50RIpNxPlIAtxyNBcIgwG04Q8yDI8IQEJwuAiSBw1EDvk81DxPEo/KKEfIRUYyCRDIZRYtJbtaT81HcOIYnE9DAycUA=
HTTP/1.1 200 OK
Date: Tue, 29 Aug 2017 13:38:27 GMT
Server: Apache
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Referrer-Policy: origin-when-cross-origin
Content-Security-Policy: upgrade-insecure-requests
Cache-Control: no-cache, no-store, max-age=0, private, must-revalidate
Expires: 0
NCBI-PHID: 0C421A7A9A56E5310000000000000001.m_2
NCBI-RCGI-RetryURL: https://www.ncbi.nlm.nih.gov/tools/primer-blast/primertool.cgi?ctg_time=1504013907&job_key=aWO2H68Wor6FhLSBueGQs8P6gYHu6Zqc7w
NCBI-SID: 0751457F9A561D01_0000SID
Pragma: no-cache
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS, PATCH, DELETE
Access-Control-Allow-Origin: https://www.ncbi.nlm.nih.gov
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin,X-Accept-Charset,X-Accept,Content-Type,X-Requested-With,NCBI-SID,NCBI-PHID
Content-Type: text/html
Set-Cookie: ncbi_sid=0751457F9A561D01_0000SID; domain=.nih.gov; path=/; expires=Wed, 29 Aug 2018 13:38:27 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
X-UA-Compatible: IE=Edge
X-XSS-Protection: 1; mode=block
Keep-Alive: timeout=1, max=9
Connection: Keep-Alive
Transfer-Encoding: chunked
And here is all the header information I get from my script:
Date : Tue, 29 Aug 2017 14:41:08 GMT
Server : Apache
Strict-Transport-Security : max-age=31536000; includeSubDomains; preload
Referrer-Policy : origin-when-cross-origin
Content-Security-Policy : upgrade-insecure-requests
Accept-Ranges : bytes
Vary : Accept-Encoding
Content-Encoding : gzip
X-UA-Compatible : IE=Edge
X-XSS-Protection : 1; mode=block
Content-Length : 2516
Keep-Alive : timeout=1, max=10
Connection : Keep-Alive
Content-Type : text/html
The NCBI-RCGI-RetryURL field is important because it contains the URL I need to execute a GET request on in order to retrieve the results.
EDIT:
Updated script as per Maurice Meyer's suggestion:
#!/usr/bin/env python
import requests
# BaseURL being accessed
url = 'https://www.ncbi.nlm.nih.gov/tools/primer-blast/primertool.cgi'
# Dictionary of query parameters
data = {
'INPUT_SEQUENCE' : 'TCTTCTGAGAAAGTCTGAGGCTCCTTAGTACCTTCTCTAGTATGAACTGTTCAGCCTGCCCGCAAGTTGTAACTACGCAGGCGCCAAGACAGCCAACCAAGGAGGCTGCAGA',
'ORGANISM' : 'Mus musculus'
}
# Extra headers
headers = {
'Origin' : 'https://www.ncbi.nlm.nih.gov',
'Upgrade-Insecure-Requests' : '1',
'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36',
'Content-Type' : 'multipart/form-data; boundary=----WebKitFormBoundaryBflp51Ny9ReeA5A9',
'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Referer' : 'https://www.ncbi.nlm.nih.gov/tools/primer-blast/index.cgi?LINK_LOC=reset',
'Accept-Encoding' : 'gzip, deflate, br',
'Accept-Language' : 'en-US,en;q=0.8',
'Cookie' : 'sv-userdata-key-www.ncbi.nlm.nih.gov=G5KxXzyQ81U_vs1aHK_7XDWciF1B8AjjDUmDunVbhIZhZ4p4t_SVK4ASpbTT8iDSJVcxBH9oUAB3K2xNWjp3G0koYCloBlYuSxdoIGIkYzl2; ncbi_sid=0751457F9A561D01_0000SID; _ga=GA1.2.567134514.1503994317; _gid=GA1.2.654339584.1503994317; _gat=1; starnext=MYGwlsDWB2CmAeAXAXAbgK7RAewIYBM4lkAmAXgAcAnMAW1ioCMRcBnRAMgBYzm3FWsXFWAALDgEZymHAUkBOMgAYA7AFYpXFQDF5AQTUA2ACIBRFRKVXrN2xI4klygMJcSltQA59R0wGY/S1tg63t3Shp6JhZ2AFI/PQA5AHlE03i9PnZBYTEMlLSHcgB3UoA6aGBGMAqQWgqwUTKAc2wANwceajoGLMR81NMHQwie6P4BtIy+nJFxEhVRqL7J9ISZoTnVh08l3pj+lWcC9KON3NFYo5OHRQkuLiUOPyd5K2eJMnvH5/JPDWefjIADNcCBBM8eIgqOhYM81F83GpniMJH4SPJnosSFxnrtAoZ5Li/IoXp5DCpuE50RIpNxPlIAtxyNBcIgwG04Q8yDI8IQEJwuAiSBw1EDvk81DxPEo/KKEfIRUYyCRDIZRYtJbtaT81HcOIYnE9DAycUA='
}
# Make a POST request and read the response
with requests.session() as session:
poster = session.post(url, data=data, headers=headers)
for key, value in poster.headers.items():
print(key, ':', value)
Updated output, still no difference:
Date : Tue, 29 Aug 2017 15:05:27 GMT
Server : Apache
Strict-Transport-Security : max-age=31536000; includeSubDomains; preload
Referrer-Policy : origin-when-cross-origin
Content-Security-Policy : upgrade-insecure-requests
Accept-Ranges : bytes
Vary : Accept-Encoding
Content-Encoding : gzip
X-UA-Compatible : IE=Edge
X-XSS-Protection : 1; mode=block
Content-Length : 2517
Keep-Alive : timeout=1, max=10
Connection : Keep-Alive
Content-Type : text/html
The request data between the two is totally different.
Specifically the request body data. So it really isn't missing header information using Python's requests library - it is missing information the in POST request to server.
You can't simply copy and paste the header
'Content-Type' : 'multipart/form-data; boundary=----WebKitFormBoundaryBflp51Ny9ReeA5A9',
Or just post the data INPUT_SEQUENCE and ORGANISM like that - also in any case the data you do have for ORGANISM is clearly wrong - a cursory glance shows it would be Mus musculus (taxid:10090) not Mus musculus.
So - you need to look at the whole request - headers and body, then craft a request that includes the required data by the server. Looking at it you are missing loads and loads of data that the server will need to respond.
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="INPUT_SEQUENCE"
TCTTCTGAGAAAGTCTGAGGCTCCTTAGTACCTTCTCTAGTATGAACTGTTCAGCCTGCCCGCAAGTTGTAACTACGCAGGCGCCAAGACAGCCAACCAAGGAGGCTGCAGA
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="SEQFILE"; filename=""
Content-Type: application/octet-stream
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER5_START"
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER5_END"
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER3_START"
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER3_END"
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_LEFT_INPUT"
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_RIGHT_INPUT"
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_PRODUCT_MIN"
70
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_PRODUCT_MAX"
1000
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_NUM_RETURN"
10
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_MIN_TM"
57.0
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_OPT_TM"
60.0
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_MAX_TM"
63.0
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_MAX_DIFF_TM"
3
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_ON_SPLICE_SITE"
0
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="SPLICE_SITE_OVERLAP_5END"
7
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="SPLICE_SITE_OVERLAP_3END"
4
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="MIN_INTRON_SIZE"
1000
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="MAX_INTRON_SIZE"
1000000
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="SEARCH_SPECIFIC_PRIMER"
on
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="SEARCHMODE"
0
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="PRIMER_SPECIFICITY_DATABASE"
refseq_mrna
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="CUSTOM_DB"
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="CUSTOMSEQFILE"; filename=""
Content-Type: application/octet-stream
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
Content-Disposition: form-data; name="ORGANISM"
Mus musculus (taxid:10090)
------WebKitFormBoundaryJVAJqDi2cI4BTfmc
etc...

python requests login with "multipart/form-data"

Today I tried to login on a website using python requests. That website is using multipart/form-data to login.
I tried to get the http request going through the web.
This is what I got:
1
-----------------------------25373143914744
Content-Disposition: form-data; name="csrfKey"
c720e331f5ba76c1ca5d389adfecbf7f
-----------------------------25373143914744
Content-Disposition: form-data; name="ref"
aHR0cHM6Ly93d3cuY3JhY2tpbmdvZXouY29tLz9fZnJvbUxvZ291dD0x
-----------------------------25373143914744
Content-Disposition: form-data; name="MAX_FILE_SIZE"
7340032
-----------------------------25373143914744
Content-Disposition: form-data; name="plupload"
b8f090b305d37f4f77bbf7966aa6e932
-----------------------------25373143914744
Content-Disposition: form-data; name="auth"
deewfwef
-----------------------------25373143914744
Content-Disposition: form-data; name="password"
wefwefwef
-----------------------------25373143914744
Content-Disposition: form-data; name="remember_me"
0
-----------------------------25373143914744
Content-Disposition: form-data; name="remember_me_checkbox"
1
-----------------------------25373143914744
Content-Disposition: form-data; name="signin_anonymous"
0
-----------------------------25373143914744--
Is there any way to login a website that using "multipart/form-data" with python requests?
How can I send this details to the server and get back the response?

POST file upload causes HTTP 400 error response

I am trying to upload a file using POST requests in Python (requests library).
I get HTTP 400 error as a response. I think it is because my POST request is not in the format it should be. Any ideas how to convert POST request 1 into 2?
Code:
files = {"file": ("test-file.txt", open("c:/users/johndoe/desktop/test-file.txt", "rb"), "text/plain")}
response = webdriver.request("POST", "https://something.com/attachments", files = files)
What I currently have (1):
--d9bd23df892242a489b0f638d62502a6
Content-Disposition: form-data; name="file"; filename="test-file.txt"
Content-Type: text/plain
This is a test file.
Regards,
John Doe
--d9bd23df892242a489b0f638d62502a6--
What I should have (2):
-----------------------------26789175756830
Content-Disposition: form-data; name="fileName"
test-file.txt
-----------------------------26789175756830
Content-Disposition: form-data; name="fileSize"
45
-----------------------------26789175756830
Content-Disposition: form-data; name="description"
undefined
-----------------------------26789175756830
Content-Disposition: form-data; name="file"; filename="test-file.txt"
Content-Type: text/plain
This is a test file.
Regards,
John Doe
-----------------------------26789175756830--
What I think I need to add (3):
-----------------------------26789175756830
Content-Disposition: form-data; name="fileName"
test-file.txt
-----------------------------26789175756830
Content-Disposition: form-data; name="fileSize"
45
-----------------------------26789175756830
Content-Disposition: form-data; name="description"
undefined
-----------------------------26789175756830
You have to explicitly specify the fields fileName, fileSize, and description, since requests won't generate them for you automatically:
import os
import requests
filepath = 'foo'
files = {'file': open(filepath, 'rb')}
data = {
'fileName': filepath,
'fileSize': os.path.getsize(filepath),
'description': 'undefined'
}
response = requests.post('http://www.example.com/', data=data, files=files);
This generates a request like:
POST / HTTP/1.1
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip, deflate
Host: www.example.com
User-Agent: python-requests/2.13.0
Content-Length: 439
Content-Type: multipart/form-data; boundary=75a7213b6b4f493fabe26feeafb8551c
Http.Entity.Parser.Multipart.Tempdir: /tmp/pZjDE
--75a7213b6b4f493fabe26feeafb8551c
Content-Disposition: form-data; name="description"
undefined
--75a7213b6b4f493fabe26feeafb8551c
Content-Disposition: form-data; name="fileSize"
16
--75a7213b6b4f493fabe26feeafb8551c
Content-Disposition: form-data; name="fileName"
foo
--75a7213b6b4f493fabe26feeafb8551c
Content-Disposition: form-data; name="file"; filename="foo"
contents of foo
--75a7213b6b4f493fabe26feeafb8551c--

Python - Parsing multipart/form-data request on server side

Im trying to do a http 'POST' with multipart/form-data to a python GAE backend.
My server side method is receiving the complete body but i have absolutely no idea how to parse the body content without going over it manually and splitting the text for values.
My request looks like this:
POST /android/v4/MyPostMethod HTTP/1.1
Accept: */*
Accept-Charset: *
Content-Length: 186808
Content-Type: multipart/form-data; boundary=*****; charset="utf-8"
Content_Length: 186808
Content_Type: multipart/form-data; boundary=*****
Host: myhost.appspot.com
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.2; GT-I9300 Build/XXXXX)
Via: HTTP/1.1 MSP-YV
--*****
Content-Disposition: form-data; name="value1"
Content-Type: text/plain; charset=UTF-8
f0ef73c5-54dd-40cf-9ee7-5c4cb764eb28
--*****
Content-Disposition: form-data; name="value2"
Content-Type: text/plain; charset=UTF-8
10d71e73-4d4d-4607-b271-f7efcfd0c59d
--*****
Content-Disposition: form-data; name="value3"
Content-Type: text/plain; charset=UTF-8
10d71e73-4d4d-4607-b271-f7efdfdfdfdf
--*****
Content-Disposition: form-data; name="logText"; filename="log.txt"
Content-Type: text/plain
Content-Transfer-Encoding: binary
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
...
--*****--
I've searched around and couldn't find a good explanation of how to do this trivial thing.
Appreciate if someone could help me here. Thanks.
For some reason cgi.FieldStorage() wasnt working for me, but only the deprecated method :
pdict = {'boundary':'*****'}
cgi.parse_multipart(self.request.body_file, pdict)
Dont know why but as long as its working im fine with that.
You want the .cgi python library.
Specifically something like this:
import cgi
form = cgi.FieldStorage()
value1 = form.getfirst("value1", "")
value2 = form.getfirst("value2", "")
value3 = form.getfirst("value3", "")
logtext = form.getfirst("logText", "")
If you want the uploaded files, you can do this
for upload in self.get_uploads():
If you want just a text field:
x = self.request.get('value1')

Categories

Resources