A simple REST server in Python
Using Python’s BaseHTTPServer
, its easy to build a very simple REST server, very
handy for prototyping. In no way should this be used in a production
environment!
When visiting, via GET
a page that doesn’t exist, a very simple upload page
is presented. Revisiting the page will cause that file to be downloaded or
viewd. You need to manually (eg, using CURL) POST
to the same page to upload
a new file to the same endpoint.
All data is stored in memory, and is deleted when the process stops. Like I
said, its not for production! If you want some default or consistent data
present whenever you start the server, you can include it in the endpoints
definition in main
.
The reason for the large number of headers is to handle CORS. The settings in the file make the REST endpoint fairly accessible from anywhere.
#!/usr/bin/env python
# Basic REST Server for prototyping
import sys, cgi, BaseHTTPServer, mimetypes
# Port to listen on
PORT = 1024
# List of endpoints
class endpoint:
mimetype = ""
content = ""
def __init__(self,mimetype,content):
self.mimetype = mimetype
self.content = content
endpoints = {}
# The REST handler
class REST(BaseHTTPServer.BaseHTTPRequestHandler):
def do_OPTIONS(self):
self.send_response(200)
self.send_header("Access-Control-Allow-Origin","*")
self.send_header("Access-Control-Allow-Methods","*")
self.send_header("Access-Control-Allow-Headers","*")
self.end_headers()
def do_HEAD(self):
self.send_response(200)
self.send_header("Access-Control-Allow-Origin","*")
self.send_header("Access-Control-Allow-Methods","*")
self.send_header("Access-Control-Allow-Headers","*")
self.end_headers()
def do_GET(self):
self.path = self.path.split("?",1)[0]
if self.path in endpoints:
ep = endpoints[self.path]
self.send_response(200)
self.send_header("Access-Control-Allow-Origin","*")
self.send_header("Access-Control-Allow-Methods","*")
self.send_header("Access-Control-Allow-Headers","*")
self.send_header("Content-Type", ep.mimetype)
self.end_headers()
self.wfile.write(ep.content)
else:
self.send_response(200)
self.send_header("Access-Control-Allow-Origin","*")
self.send_header("Access-Control-Allow-Methods","*")
self.send_header("Access-Control-Allow-Headers","*")
self.send_header("Content-Type", "text/html")
self.end_headers()
self.wfile.write("""<html>
<body>
<form method="post" enctype="multipart/form-data" action=""")
self.wfile.write('"'+self.path+'"')
self.wfile.write(""">
<input type="file" name="upload"/><input type="submit" value="Submit">
</form>
</body>
</html>""")
def do_POST(self):
self.path = self.path.split("?",1)[0]
try:
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
form = cgi.FieldStorage( fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE':self.headers['Content-Type'], })
content = form['upload'].file.read()
filename = form['upload'].filename
mt = mimetypes.guess_type(form["upload"].filename)[0] or "application/octet-stream"
endpoints[self.path] = endpoint(mt,content)
self.send_response(200)
self.send_header("Access-Control-Allow-Origin","*")
self.send_header("Access-Control-Allow-Methods","*")
self.send_header("Access-Control-Allow-Headers","*")
self.send_header("Content-Type",mt)
self.end_headers()
self.wfile.write(content)
except Exception as e:
print sys.exc_info()
self.send_response(500)
self.send_header("Access-Control-Allow-Origin","*")
self.send_header("Access-Control-Allow-Methods","*")
self.send_header("Access-Control-Allow-Headers","*")
self.end_headers()
self.wfile.write(e)
if __name__ == '__main__':
endpoints = { "/": endpoint("text/plain","Hello world!"),
"/bye.html": endpoint("text/html","<html><body>Bye</body></html>")
}
print repr(endpoints)
httpd = BaseHTTPServer.HTTPServer(("",PORT), REST)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
We can use curl
for testing:
$ curl -F "upload=@./simon_duff.html" localhost:1024/owner