简体   繁体   中英

receive binary file from POST request with BaseHTTPRequestHandler

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'):

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM