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.
Related
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'):
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()
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.
I am trying to implement my own version of wsgiref for learning purpose and I ended up here:
from wsgiref.simple_server import make_server
class DemoApp():
def __init__(self, environ, start_response):
self.environ = environ
self.start = start_response
def __iter__(self, status):
self.status = '200 OK'
response_headers = [('Content-type','text/plain')]
self.start(status, response_headers)
return ["Hello World"]
if __name__ == '__main__':
httpd = make_server('', 1000, DemoApp)
print("Serving on port 1000")
httpd.serve_forever()
When I go to port 1000, I am getting the attribute error.
AttributeError: 'NoneType' object has no attribute 'split'
Where am I leaving mistakes?
Stacktrace:
Serving on port 1000
Traceback (most recent call last):
File "C:\Python27\lib\wsgiref\handlers.py", line 86, in run
self.finish_response()
File "C:\Python27\lib\wsgiref\handlers.py", line 131, in finish_response
self.close()
File "C:\Python27\lib\wsgiref\simple_server.py", line 33, in close
self.status.split(' ',1)[0], self.bytes_sent
AttributeError: 'NoneType' object has no attribute 'split'
127.0.0.1 - - [11/Jan/2014 12:40:09] "GET / HTTP/1.1" 500 59
Traceback (most recent call last):
File "C:\Python27\lib\SocketServer.py", line 295, in _handle_request_noblock
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 54469)
self.process_request(request, client_address)
File "C:\Python27\lib\SocketServer.py", line 321, in process_request
self.finish_request(request, client_address)
File "C:\Python27\lib\SocketServer.py", line 334, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "C:\Python27\lib\SocketServer.py", line 649, in __init__
self.handle()
File "C:\Python27\lib\wsgiref\simple_server.py", line 124, in handle
handler.run(self.server.get_app())
File "C:\Python27\lib\wsgiref\handlers.py", line 92, in run
self.close()
File "C:\Python27\lib\wsgiref\simple_server.py", line 33, in close
self.status.split(' ',1)[0], self.bytes_sent
AttributeError: 'NoneType' object has no attribute 'split'
You should encode the returned body to utf-8
return ["Hello World".encode("utf-8")]
This code works fine with me, I am using Python 3.3.3:
from wsgiref.simple_server import make_server
def app(env, start_response):
body = "Hello"
status = "200 OK"
headers = [("Content-Type", "text/plain; charset=utf-8")]
start_response(status, headers)
return [body.encode("utf-8")]
port = 9080
httpd = make_server("localhost", port, app)
print("Server started on port: ", port)
httpd.serve_forever()
DemoApp is called; The return value of DemoApp.__init__ is used.
DemoApp.__init__ returns nothing (You can't return anything in constructor).
Try following instead of DemoApp class:
def DemoApp(environ, start_response):
response_headers = [('Content-type','text/plain')]
start_response('200 OK', response_headers)
return ["Hello World"]
Using class (Use __call__ instead of __iter__):
from wsgiref.simple_server import make_server
class DemoApp:
def __call__(self, environ, start_response):
response_headers = [('Content-type','text/plain')]
start_response('200 OK', response_headers)
return ["Hello World"]
if __name__ == '__main__':
httpd = make_server('', 1000, DemoApp()) # Don't forget instantiate a class.
# ^^
print("Serving on port 1000")
httpd.serve_forever()
How about this, you need to yield the output than returning it.
from wsgiref.simple_server import make_server
class DemoApp:
def __init__(self, environ, start_response):
self.environ = environ
self.start = start_response
def __iter__(self):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield 'Hello world!'
if __name__ == '__main__':
httpd = make_server('', 1000, DemoApp)
print("Serving HTTP on port 1000...")
httpd.serve_forever()
adding .encode("utf-8") solved the problem for me Python 3.4.2
I had the same issue.
I solved it by setting: DATA_UPLOAD_MAX_NUMBER_FIELDS = 10000 in settings.py.
Django 2.2
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).