Created
June 2, 2018 14:40
-
-
Save motoom/95f8440c11aeff99e0f0378106b316d4 to your computer and use it in GitHub Desktop.
CherryPy API server able to serve JSON to webbrowsers using CORS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Test API</title> | |
</head> | |
<body> | |
<h1>Test API using CORS</h1> | |
<p>Result:</p> | |
<p id="result"></p> | |
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> | |
<script> | |
$.ajax({ | |
url: "http://127.0.0.1:8000/api/search", | |
dataType: "json", | |
contentType: "application/json; charset=utf-8", | |
method: "POST", | |
data: JSON.stringify({ | |
q: "banana" | |
}), | |
beforeSend: function(xhr) { | |
xhr.setRequestHeader("Authorization", "Basic " + btoa("joe" + ":" + "secret")); | |
}, | |
success: function(data) { | |
$("#result").html("OK: " + JSON.stringify(data)); | |
}, | |
error: function() { | |
alert("Error"); | |
} | |
}); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Demonstrates CORS using a webbrowser's Ajax. | |
# | |
# Status: Works | |
# | |
# Run corsapiserver-test.html in a browser for a HTML/Ajax POC page. | |
import cherrypy | |
import json | |
class CorsAuthBasicTool(cherrypy.Tool): | |
def __init__(self, priority=5): | |
cherrypy.Tool.__init__(self, "before_handler", self.basic_cors_auth, priority=priority) | |
def basic_cors_auth(self, realm, checkpassword, debug=False, accept_charset="utf-8"): | |
if cherrypy.request.method != "OPTIONS": | |
# Delegate to CherryPy's basic auth handler | |
return cherrypy.lib.auth_basic.basic_auth(realm, checkpassword, debug=debug) # Later versions also require: , accept_charset=accept_charset) | |
class API(object): | |
@cherrypy.expose | |
def search(self): | |
# Still have to handle OPTIONS request here; but it'll be called even if no credentials are given. | |
if cherrypy.request.method == "OPTIONS": | |
cherrypy.response.headers["Access-Control-Allow-Methods"] = "POST, OPTIONS" | |
cherrypy.response.headers["Access-Control-Allow-Credentials"] = "true" | |
cherrypy.response.headers["Access-Control-Max-Age"] = "86400" | |
cherrypy.response.headers["Access-Control-Allow-Headers"] = "X-Mobile, Authorization, Origin, X-Requested-With, Content-Type, Accept" | |
return "" | |
# The actual serving of the POST request. | |
if cherrypy.request.body.length: | |
data = cherrypy.request.body.read() | |
vars = json.loads(data) | |
result = dict(msg="You searched for %s" % vars["q"]) | |
else: | |
result = dict(msg="You did a %s request with headers: %r" % (cherrypy.request.method, cherrypy.request.headers)) | |
s = json.dumps(result) | |
cherrypy.response.headers["Content-Type"] = "application/json" | |
return s | |
class Root(object): | |
@cherrypy.expose | |
def index(self): | |
return "Hello from index of Root." | |
API_KEY_USER = "joe" | |
API_KEY_PASSWD = "secret" | |
if __name__ == "__main__": | |
root = Root() | |
root.api = API() | |
cherrypy.tools.cors_auth_basic = CorsAuthBasicTool() | |
conf = { | |
"global": { | |
"server.socket_host": "0.0.0.0", | |
"server.socket_port": 8000, | |
}, | |
"/": { | |
}, | |
"/api": { | |
"tools.cors_auth_basic.on": True, | |
"tools.cors_auth_basic.debug": True, | |
"tools.cors_auth_basic.realm": "Generic API", | |
"tools.cors_auth_basic.checkpassword": cherrypy.lib.auth_basic.checkpassword_dict({API_KEY_USER: API_KEY_PASSWD}), | |
# required for CORS | |
"tools.response_headers.on": True, | |
"tools.response_headers.headers": [ | |
("Access-Control-Allow-Origin", "*"), | |
], | |
}, | |
} | |
cherrypy.quickstart(root, "/", conf) | |
""" | |
# Preflight; should work without authentication | |
curl -i -X OPTIONS http://127.0.0.1:8000/api/search | |
# This is an OPTIONS with authentication, you can do that with curl but not with a webbrowser: | |
curl -i -X OPTIONS --user joe:secret http://127.0.0.1:8000/api/search | |
# Calling the actual API with authentication | |
curl -sH "Content-Type: application/json" --data '{"q": "Banana"}' --user joe:secret http://127.0.0.1:8000/api/search | json_pp | |
""" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment