I have been experimenting with some code from this forum. It has worked okay so far to receive pieces of json delivered in curl POST requests, but am now trying to send it a small .jpg file. It is failing in several ways at once, but I am baffled about how even the first of these problems is arising.
My code looks like this:
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs
from cgi import parse_header, parse_multipart
class ReportHandler(BaseHTTPRequestHandler):
def do_HEAD(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
def parse_POST(self):
print(self.headers)
ctype, pdict = parse_header(self.headers['content-type'])
print("ctype", ctype, ctype == 'application/octet-stream')
print(pdict)
if ctype == 'multipart/form-data':
postvars = parse_multipart(self.rfile, pdict)
elif ctype == 'application/x-www-form-urlencoded' or 'application/json':
print("here!")
length = int(self.headers['content-length'])
postvars = parse_qs(
self.rfile.read(length).decode('utf8'),
keep_blank_values=1)
print(postvars)
elif ctype == 'application/octet-stream':
print("octet stream header")
else:
print("nothing")
postvars = {}
a = self.rfile
print(dir(a))
print(a.peek())
return postvars
def do_POST(self):
postvars = self.parse_POST()
print(postvars)
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def main():
server = HTTPServer(('', 8088), ReportHandler)
try:
print('Started http server')
server.serve_forever()
except KeyboardInterrupt:
print('^C received, shutting down server')
server.socket.close()
if __name__ == "__main__":
main()
Then I give in a curl command in another terminal which looks like this:
curl --request POST -H "Content-Type:application/octet-stream" --data-binary "@test.jpg" http://127.0.0.1:8088
It comes back with the following output and error trace:
python receive_requests.py
Started http server
Host: 127.0.0.1:8088
User-Agent: curl/7.52.1
Accept: */*
Content-Type: application/octet-stream
Content-Length: 16687
Expect: 100-continue
ctype application/octet-stream True
{}
here!
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 52056)
Traceback (most recent call last):
File "/usr/local/lib/python3.6/socketserver.py", line 317, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/local/lib/python3.6/socketserver.py", line 348, in process_request
self.finish_request(request, client_address)
File "/usr/local/lib/python3.6/socketserver.py", line 361, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/local/lib/python3.6/socketserver.py", line 721, in __init__
self.handle()
File "/usr/local/lib/python3.6/http/server.py", line 418, in handle
self.handle_one_request()
File "/usr/local/lib/python3.6/http/server.py", line 406, in handle_one_request
method()
File "receive_requests.py", line 42, in do_POST
postvars = self.parse_POST()
File "receive_requests.py", line 27, in parse_POST
self.rfile.read(length).decode('utf8'),
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
----------------------------------------
So there is an error around encoding, but what I would really like to know is how it ends going here:
elif ctype == 'application/x-www-form-urlencoded' or 'application/json':
..despite
print("ctype", ctype, ctype == 'application/octet-stream')
giving
>>> ctype application/octet-stream True
If anyone knows how to fix this code so it receives the binary file please post it, otherwise how does it manage to go to the wrong elif
option? Is there something about headers or the behaviour of curl which I am missing?
Your condition will always return True. A non-empty string evaluates to True
:
elif ctype == 'application/x-www-form-urlencoded' or 'application/json':
It should be:
elif ctype == 'application/x-www-form-urlencoded' or ctype == 'application/json':
or
elif ctype in ('application/x-www-form-urlencoded', 'application/json'):