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).
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.
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.
I want to write Python code to send a file from client to server. server needs to save the file sent from the client. But my code have some bugs which I cannot fix. Below is my server code:
# server.py
from SimpleXMLRPCServer import SimpleXMLRPCServer
import os
server = SimpleXMLRPCServer(('localhost', 9000))
def save_data(data):
handle = open("x123.dat", "wb")
handle.write(data)
handle.close()
server.register_function(save_data, 'save_data')
server.serve_forever()
And the client code:
# client.py
import sys, xmlrpclib
proxy = xmlrpclib.Server('http://localhost:9000')
handle = open(sys.argv[1], "rb")
proxy.save_data(handle.read())
handle.close()
But then I run my code, the client returns the following error (this is on Windows):
Traceback (most recent call last):
File "client.py", line 6, in <module> proxy.save_data(handle.read())
File "c:\python27\lib\xmlrpclib.py", line 1224, in __call__
return self.__send(self.__name, args)
File "c:\python27\lib\xmlrpclib.py", line 1575, in __request
verbose=self.__verbose
File "c:\python27\lib\xmlrpclib.py", line 1264, in request
return self.single_request(host, handler, request_body, verbose)
File "c:\python27\lib\xmlrpclib.py", line 1297, in single_request
return self.parse_response(response)
File "c:\python27\lib\xmlrpclib.py", line 1473, in parse_response
return u.close()
File "c:\python27\lib\xmlrpclib.py", line 793, in close
raise Fault(**self._stack[0])
xmlrpclib.Fault: <Fault 1: "<class 'xml.parsers.expat.ExpatError'>:not well-formed (invalid token): line 7, column 1">
I have some questions:
How to fix the above bug?
My code needs to transfer some big files sometimes. Since my method is so simple, I doubt that it is efficient for moving big data. Could anybody please suggest a better method to move big files? (Of course it is better to use XMLRPC on Python)
Server side:
def server_receive_file(self,arg):
with open("path/to/save/filename", "wb") as handle:
handle.write(arg.data)
return True
Client side:
with open("path/to/filename", "rb") as handle:
binary_data = xmlrpclib.Binary(handle.read())
client.server_receive_file(binary_data)
This worked for me.
You want to look into the xmlrpclib Binary object. With this class you can encode and decode to/from a base64 string.
Here is how you do it:
#!/usr/bin/env python3.7
# rpc_server.py
# Fix missing module issue: ModuleNotFoundError: No module named 'SimpleXMLRPCServer'
#from SimpleXMLRPCServer import SimpleXMLRPCServer
from xmlrpc.server import SimpleXMLRPCServer
import os
# Put in your server IP here
IP='10.198.16.73'
PORT=64001
server = SimpleXMLRPCServer((IP, PORT))
def server_receive_file(arg, filename):
curDir = os.path.dirname(os.path.realpath(__file__))
output_file_path = curDir + '/' + filename
print('output_file_path -> ({})'.format(output_file_path))
with open(output_file_path, "wb") as handle:
handle.write(arg.data)
print('Output file: {}'.format(output_file_path))
return True
server.register_function(server_receive_file, 'server_receive_file')
print('Control-c to quit')
server.serve_forever()
### rpc_client.py
#!/usr/bin/env python3.7
import os
# client.py
import sys
# The answer is that the module xmlrpc is part of python3
import xmlrpc.client
#Put your server IP here
IP='10.198.16.73'
PORT=64001
url = 'http://{}:{}'.format(IP, PORT)
###server_proxy = xmlrpclib.Server(url)
client_server_proxy = xmlrpc.client.ServerProxy(url)
curDir = os.path.dirname(os.path.realpath(__file__))
filename = sys.argv[1]
fpn = curDir + '/' + filename
print(' filename -> ({})'.format(filename))
print(' fpn -> ({})'.format(fpn))
if not os.path.exists(fpn):
print('Missing file -> ({})'.format(fpn))
sys.exit(1)
with open(fpn, "rb") as handle:
binary_data = xmlrpc.client.Binary(handle.read())
client_server_proxy.server_receive_file(binary_data, filename)