receive binary file from POST request with BaseHTTPRequestHandler - python

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

Related

Exception happened during processing of request from [duplicate]

This question already has answers here:
Python sockets error TypeError: a bytes-like object is required, not 'str' with send function
(4 answers)
Closed 5 years ago.
here is my code I want to open a server on the localhost:8080.
from http.server import BaseHTTPRequestHandler, HTTPServer
class WebServerHandler(BaseHTTPRequestHandler):
def do_GET(self):
try:
if self.path.endswith("/hi"):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
message = ""
message += "<html><body>Hello!</body></html>"
self.wfile.write(message)
print (message)
return
except IOError:
self.send_error(404, 'File Not Found: %s' % self.path)
def main():
try:
port = 8080
server = HTTPServer(('', port), WebServerHandler)
print ("Web Server running on port %s" % port)
server.serve_forever()
except KeyboardInterrupt:
print (" ^C entered, stopping web server....")
server.socket.close()
if __name__ == '__main__':
main()
And when i'm open the server i'm supposed to get a white web page with the word "Hello!" wrote on it.
But when i open the page i have a white page and on my terminal i have this :
Exception happened during processing of request from ('10.0.2.2',49701)
Traceback (most recent call last):
File "/usr/lib/python3.5/socketserver.py", line 313, in
_handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python3.5/socketserver.py", line 341, in
process_request
self.finish_request(request, client_address)
File "/usr/lib/python3.5/socketserver.py", line 354, in
finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python3.5/socketserver.py", line 681, in __init__
self.handle()
File "/usr/lib/python3.5/http/server.py", line 422, in handle
self.handle_one_request()
File "/usr/lib/python3.5/http/server.py", line 410, in
handle_one_request
method()
File "webserver.py", line 14, in do_GET
self.wfile.write(message)
File "/usr/lib/python3.5/socket.py", line 593, in write
return self._sock.send(b)
TypeError: a bytes-like object is required, not 'str'
Issue is with this self.wfile.write(message) line
from http.server import BaseHTTPRequestHandler, HTTPServer
class WebServerHandler(BaseHTTPRequestHandler):
def do_GET(self):
try:
if self.path.endswith("/hi"):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
message = ""
message += "<html><body>Hello!</body></html>"
self.wfile.write(message.encode('utf-8'))
print (message)
return
except IOError:
self.send_error(404, 'File Not Found: %s' % self.path)
def main():
try:
port = 8080
server = HTTPServer(('', port), WebServerHandler)
print ("Web Server running on port %s" % port)
server.serve_forever()
except KeyboardInterrupt:
print (" ^C entered, stopping web server....")
server.socket.close()
if __name__ == '__main__':
main()

errno 111 connection refused with python in ubuntu vmware

Hi I have a problem in my server- client connection
I wrote the 2 codes on windows 10 and they worked perfectly. But when I tried to execute them on ubuntu in a VM I had this error:
Traceback (most recent call last):
File "client3.py", line 9, in <module>
sock.connect(('192.168.1.53', 1234))
File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 111] Connection refused
the server code:
import threading
import SocketServer
import json
import base64
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(327680)
data = json.loads(data)
cur_thread = threading.current_thread()
JL= data['Jliste']
for i in range(0,9) :
cel = json.loads(JL[i])
file_name = cel['name']
img = base64.b64decode(cel['img'])
with open(file_name,'wb') as _file:
_file.write(img)
print "image {} Received ".format(i)
response = "images Received "
print response
self.request.sendall(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
if __name__ == "__main__":
server = ThreadedTCPServer(("localhost", 1234), ThreadedTCPRequestHandler)
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print "Server loop running in thread:", server_thread.name
the client code:
import socket
import json
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 1234))
try:
def generate_names(count):
return 'User.2.{}.jpg'.format(count)
L = []
for i in range(0,9):
name = generate_names(i+1)
fp = open(name,'rb')
fp = fp.read()
fp = fp.encode('base64')
cel = {}
cel['name'] = name
cel['img'] = fp
jcel = json.dumps(cel)
L.append(jcel)
data = {}
data['Jliste'] = L
s = json.dumps(data)
sock.send(s)
response = sock.recv(1024)
print "Received: {}".format(response)
finally:
sock.close()
the new error i get is:
Exception happened during processing of request from ('127.0.0.1', 60900)
Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 596, in process_request_thread
self.finish_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 331, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python2.7/SocketServer.py", line 652, in __init__
self.handle()
File "server.py", line 12, in handle
data = json.loads(data)
File "/usr/lib/python2.7/json/__init__.py", line 339, in loads
return _default_decoder.decode(s)
File "/usr/lib/python2.7/json/decoder.py", line 364, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python2.7/json/decoder.py", line 380, in raw_decode
obj, end = self.scan_once(s, idx)
ValueError: Unterminated string starting at: line 1 column 16913 (char 16912)
Not sure why this works on Windows, but when I run your code on Ubuntu, your server just exits - just as it is supposed to. It prints "server loop running..." and then exits. As your thread is set to server_thread.daemon=True, the thread is killed as well. It does not even have time to initialise the socket.
If you change server_thread.daemon=False or add sleep(600) or something like that (you would of course an infinite loop) as the last statement in your main(), it starts listening to the socket and process requests - which is probably what you want.

How to read, process variable POST, Python HTTP Server

Server code
#!/usr/bin/env python
import BaseHTTPServer
from BaseHTTPServer import BaseHTTPRequestHandler
import SocketServer
import urlparse
import cgitb
import cgi
from cgi import parse_header, parse_multipart
class S(BaseHTTPRequestHandler):
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
self._set_headers()
self.wfile.write("<html><body><h1>hi!</h1></body></html>")
def do_HEAD(self):
self._set_headers()
def do_POST(self):
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
if ctype == 'multipart/form-data':
postvars = cgi.parse_multipart(self.rfile, pdict)
elif ctype == 'application/x-www-form-urlencoded':
length = int(self.headers.getheader('content-length'))
postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1)
else:
postvars = {}
def run(server_class=BaseHTTPServer.HTTPServer, handler_class=S, port=80):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print 'Starting httpd...'
httpd.serve_forever()
if __name__ == "__main__":
run()
Clinet
Client send POST request over program Postman.
GET works.
Post is does not work . This is Error on server when I send request
http://192.168.2.108?var1=value
ERROR ON SERVER
Exception happened during processing of request from ('192.168.2.107',
49629) Traceback (most recent call last): File
"/usr/lib/python2.7/SocketServer.py", line 295, in
_handle_request_noblock
self.process_request(request, client_address) File "/usr/lib/python2.7/SocketServer.py", line 321, in process_request
self.finish_request(request, client_address) File "/usr/lib/python2.7/SocketServer.py", line 334, in finish_request
self.RequestHandlerClass(request, client_address, self) File "/usr/lib/python2.7/SocketServer.py", line 655, in init
self.handle() File "/usr/lib/python2.7/BaseHTTPServer.py", line 340, in handle
self.handle_one_request() File "/usr/lib/python2.7/BaseHTTPServer.py", line 328, in
handle_one_request
method() File "server.py", line 37, in do_POST
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) File
"/usr/lib/python2.7/cgi.py", line 309, in parse_header
parts = _parseparam(';' + line) TypeError: cannot concatenate 'str' and 'NoneType' objects
Maybe because the request sent by your client does not include the content-type header.
You did not say how you are connecting to the server.
curl -X POST http://localhost:8880/?var1=value
Will fail as shown above. While:
curl -X POST http://localhost:8880/?var1=value -H 'Content-type: application/x-www-form-urlencoded'
Will fail also, but a bit further along the way: you also need a Content-length header. What you need is to check the values returned to you by the class methods instead of trusting everything will happen as you wish it will:
def do_POST(self):
content_type = self.headers.getheader('content-type')
if content_type is None:
raise ... # 400 Invalid Request
# otherwise go on.

Serving JPG files via wsgiref.simple_server in Python 3 - "write() argument must be a bytes instance"

I am trying to make a HTTP server in Python3. For the beginning, I only want a server that serves a single JPG file. Here's my code:
from wsgiref.simple_server import make_server
def simple_app(environ, start_response):
headers = [('Content-type', 'image/jpeg')]
start_response('200 OK', headers)
data = b''
filename = r'sunset-at-dusk.jpg'
with open(filename, 'rb', buffering=0) as f:
data = f.readall()
print(type(data)) #<class 'bytes'>
return data
httpd = make_server('', 8001, simple_app)
print("Serving on port 8001...")
httpd.serve_forever()
When I try to access the server via HTTP, I get the following error.
127.0.0.1 - - [01/Jun/2016 08:37:43] "GET / HTTP/1.1" 200 0 Traceback (most recent call last): File "C:\Anaconda3\lib\wsgiref\handlers.py", line 138, in run
self.finish_response() File "C:\Anaconda3\lib\wsgiref\handlers.py", line 180, in finish_response
self.write(data) File "C:\Anaconda3\lib\wsgiref\handlers.py", line 266, in write
"write() argument must be a bytes instance" AssertionError: write() argument must be a bytes instance
'sunset-at-dusk.jpg' is a valid JPG file in the same folder as my script.
What am I doing wrong?
Return data as list
return [data]

Keep getting exception in python webserver

I have a pretty simple python webserver that returns a few web pages, and it keeps throwing TypeError: 'str' does not support the buffer interface. Here is my code, can anyone tell what is wrong?
from os import curdir
from os.path import join as pjoin
from http.server import BaseHTTPRequestHandler, HTTPServer
class StoreHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/store.json":
with open(pjoin(curdir, 'store.json')) as fh:
self.send_response(200)
self.send_header('Content-type','text/json')
self.end_headers()
self.wfile.write(fh.read())
elif self.path == "/Stock.htm":
with open(pjoin(curdir, 'stock.htm')) as fh:
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write(fh.read())
else:
with open(pjoin(curdir, 'index.htm')) as fh:
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write(fh.read())
def do_POST(self):
if self.path == '/store.json':
length = self.headers.getheader('content-length')
data = self.rfile.read(int(length))
with open(pjoin(curdir, 'store.json'), 'w') as fh:
fh.write(data)
self.send_response(200)
server = HTTPServer(('', 8080), StoreHandler)
server.serve_forever()
Here is the exception output:
127.0.0.1 - - [30/Oct/2012 16:48:17] "GET / HTTP/1.1" 200 -
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 58645)
Traceback (most recent call last):
File "C:\Program Files\Python33\lib\socketserver.py", line 306, in _handle_request_noblock
self.process_request(request, client_address)
File "C:\Program Files\Python33\lib\socketserver.py", line 332, in process_request
self.finish_request(request, client_address)
File "C:\Program Files\Python33\lib\socketserver.py", line 345, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "C:\Program Files\Python33\lib\socketserver.py", line 666, in __init__
self.handle()
File "C:\Program Files\Python33\lib\http\server.py", line 400, in handle
self.handle_one_request()
File "C:\Program Files\Python33\lib\http\server.py", line 388, in handle_one_request
method()
File "C:\Users\Arlen\Desktop\Stock Recorder\webserver.py", line 25, in do_GET
self.wfile.write(fh.read())
File "C:\Program Files\Python33\lib\socket.py", line 317, in write
return self._sock.send(b)
TypeError: 'str' does not support the buffer interface
----------------------------------------
Update: Here is how my updated code looks:
from os import curdir
from os.path import join as pjoin
from http.server import BaseHTTPRequestHandler, HTTPServer
class StoreHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/store.json":
with open(pjoin(curdir, 'store.json')) as fh:
self.send_response(200)
self.send_header('Content-type','text/json')
self.end_headers()
self.wfile.write(fh.read(), 'rb')
elif self.path == "/Stock.htm":
with open(pjoin(curdir, 'stock.htm')) as fh:
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write(fh.read(), 'rb')
else:
with open(pjoin(curdir, 'index.htm')) as fh:
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write(fh.read(),'rb')
def do_POST(self):
if self.path == '/store.json':
length = self.headers.getheader('content-length')
data = self.rfile.read(int(length))
with open(pjoin(curdir, 'store.json'), 'w') as fh:
fh.write(data)
self.send_response(200)
server = HTTPServer(('', 8080), StoreHandler)
server.serve_forever()
Sockets send and receive bytes, but you are attempting to send over unicode strings since you opened the file without specifying the mode (remember, in Python 3 all strings are unicode by default).
You can either:
Use the bytes built-in function to transform the data
- or -
Open the file in binary mode - change open(pjoin(curdir, 'a.file')) to open(pjoin(curdir, 'store.json'), 'rb') (note the additional rb parameter).

Categories