add CORS support
Isso can now run on a separate domain such as comments.example.org and still serve for blog.example.org using CORS.
This commit is contained in:
parent
45d4e18aef
commit
3218e16532
@ -39,14 +39,15 @@ from itsdangerous import URLSafeTimedSerializer
|
|||||||
|
|
||||||
from werkzeug.routing import Map, Rule
|
from werkzeug.routing import Map, Rule
|
||||||
from werkzeug.wrappers import Response, Request
|
from werkzeug.wrappers import Response, Request
|
||||||
from werkzeug.exceptions import HTTPException, NotFound, InternalServerError
|
from werkzeug.exceptions import HTTPException, NotFound, InternalServerError, MethodNotAllowed
|
||||||
|
|
||||||
from werkzeug.wsgi import SharedDataMiddleware
|
from werkzeug.wsgi import SharedDataMiddleware
|
||||||
from werkzeug.serving import run_simple
|
from werkzeug.serving import run_simple
|
||||||
|
from werkzeug.contrib.fixers import ProxyFix
|
||||||
|
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
from isso import db, utils, migrate, views
|
from isso import db, utils, migrate, views, wsgi
|
||||||
from isso.views import comment, admin
|
from isso.views import comment, admin
|
||||||
|
|
||||||
url_map = Map([
|
url_map = Map([
|
||||||
@ -64,10 +65,10 @@ class Isso(object):
|
|||||||
|
|
||||||
PRODUCTION = False
|
PRODUCTION = False
|
||||||
|
|
||||||
def __init__(self, dbpath, secret, base_url, max_age, passphrase):
|
def __init__(self, dbpath, secret, origin, max_age, passphrase):
|
||||||
|
|
||||||
self.DBPATH = dbpath
|
self.DBPATH = dbpath
|
||||||
self.BASE_URL = utils.normalize(base_url)
|
self.ORIGIN = utils.normalize(origin)
|
||||||
self.PASSPHRASE = passphrase
|
self.PASSPHRASE = passphrase
|
||||||
self.MAX_AGE = max_age
|
self.MAX_AGE = max_age
|
||||||
|
|
||||||
@ -101,6 +102,11 @@ class Isso(object):
|
|||||||
return handler(self, request.environ, request, **values)
|
return handler(self, request.environ, request, **values)
|
||||||
except NotFound as e:
|
except NotFound as e:
|
||||||
return Response('Not Found', 404)
|
return Response('Not Found', 404)
|
||||||
|
except MethodNotAllowed:
|
||||||
|
return Response("", 200, headers={
|
||||||
|
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
|
||||||
|
"Access-Control-Allow-Headers": "Origin, Content-Type"
|
||||||
|
})
|
||||||
except HTTPException as e:
|
except HTTPException as e:
|
||||||
return e
|
return e
|
||||||
except InternalServerError as e:
|
except InternalServerError as e:
|
||||||
@ -111,6 +117,14 @@ class Isso(object):
|
|||||||
return response(environ, start_response)
|
return response(environ, start_response)
|
||||||
|
|
||||||
def __call__(self, environ, start_response):
|
def __call__(self, environ, start_response):
|
||||||
|
|
||||||
|
script_name = environ.get('HTTP_X_SCRIPT_NAME')
|
||||||
|
if script_name:
|
||||||
|
environ['SCRIPT_NAME'] = script_name
|
||||||
|
path_info = environ['PATH_INFO']
|
||||||
|
if path_info.startswith(script_name):
|
||||||
|
environ['PATH_INFO'] = path_info[len(script_name):]
|
||||||
|
|
||||||
return self.wsgi_app(environ, start_response)
|
return self.wsgi_app(environ, start_response)
|
||||||
|
|
||||||
|
|
||||||
@ -131,7 +145,7 @@ def main():
|
|||||||
defaultcfg = [
|
defaultcfg = [
|
||||||
"[general]",
|
"[general]",
|
||||||
"dbpath = /tmp/isso.db", "secret = %r" % os.urandom(24),
|
"dbpath = /tmp/isso.db", "secret = %r" % os.urandom(24),
|
||||||
"base_url = http://localhost:8080/", "passphrase = p@$$w0rd",
|
"host = http://localhost:8080/", "passphrase = p@$$w0rd",
|
||||||
"max_age = 450",
|
"max_age = 450",
|
||||||
"[server]",
|
"[server]",
|
||||||
"host = localhost", "port = 8080"
|
"host = localhost", "port = 8080"
|
||||||
@ -145,7 +159,7 @@ def main():
|
|||||||
isso = Isso(
|
isso = Isso(
|
||||||
dbpath=conf.get('general', 'dbpath'),
|
dbpath=conf.get('general', 'dbpath'),
|
||||||
secret=conf.get('general', 'secret'),
|
secret=conf.get('general', 'secret'),
|
||||||
base_url=conf.get('general', 'base_url'),
|
origin=conf.get('general', 'host'),
|
||||||
max_age=conf.getint('general', 'max_age'),
|
max_age=conf.getint('general', 'max_age'),
|
||||||
passphrase=conf.get('general', 'passphrase')
|
passphrase=conf.get('general', 'passphrase')
|
||||||
)
|
)
|
||||||
@ -154,10 +168,10 @@ def main():
|
|||||||
migrate.disqus(isso.db, args.dump)
|
migrate.disqus(isso.db, args.dump)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
app = SharedDataMiddleware(isso.wsgi_app, {
|
app = wsgi.SubURI(SharedDataMiddleware(isso.wsgi_app, {
|
||||||
'/static': join(dirname(__file__), 'static/'),
|
'/static': join(dirname(__file__), 'static/'),
|
||||||
'/js': join(dirname(__file__), 'js/')
|
'/js': join(dirname(__file__), 'js/')
|
||||||
})
|
}))
|
||||||
|
|
||||||
run_simple(conf.get('server', 'host'), conf.getint('server', 'port'),
|
run_simple(conf.get('server', 'host'), conf.getint('server', 'port'),
|
||||||
app, processes=2)
|
app, processes=2)
|
||||||
|
@ -22,25 +22,34 @@ define(["lib/q"], function(Q) {
|
|||||||
endpoint = js[i].src.substring(0, js[i].src.length - 12);
|
endpoint = js[i].src.substring(0, js[i].src.length - 12);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endpoint == null) {
|
||||||
throw "no Isso API location found";
|
throw "no Isso API location found";
|
||||||
}
|
}
|
||||||
|
|
||||||
var curl = function(method, url, data) {
|
var curl = function(method, url, data) {
|
||||||
|
|
||||||
var request = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
var response = Q.defer();
|
var response = Q.defer();
|
||||||
|
|
||||||
|
if (! ("withCredentials" in xhr)) {
|
||||||
|
respone.reject("I won't support IE ≤ 10.")
|
||||||
|
return response.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.withCredentials = true;
|
||||||
|
|
||||||
function onload() {
|
function onload() {
|
||||||
response.resolve({status: request.status, body: request.responseText});
|
response.resolve({status: xhr.status, body: xhr.responseText});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
request.open(method, url, true);
|
xhr.open(method, url, true);
|
||||||
request.overrideMimeType("application/javascript");
|
xhr.overrideMimeType("application/javascript");
|
||||||
|
|
||||||
request.onreadystatechange = function () {
|
xhr.onreadystatechange = function () {
|
||||||
if (request.readyState === 4) {
|
if (xhr.readyState === 4) {
|
||||||
onload();
|
onload();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -48,7 +57,7 @@ define(["lib/q"], function(Q) {
|
|||||||
response.reject(exception.message);
|
response.reject(exception.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
request.send(data);
|
xhr.send(data);
|
||||||
return response.promise;
|
return response.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
16
isso/wsgi.py
Normal file
16
isso/wsgi.py
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
class SubURI(object):
|
||||||
|
|
||||||
|
def __init__(self, app):
|
||||||
|
self.app = app
|
||||||
|
|
||||||
|
def __call__(self, environ, start_response):
|
||||||
|
|
||||||
|
script_name = environ.get('HTTP_X_SCRIPT_NAME')
|
||||||
|
if script_name:
|
||||||
|
environ['SCRIPT_NAME'] = script_name
|
||||||
|
path_info = environ['PATH_INFO']
|
||||||
|
if path_info.startswith(script_name):
|
||||||
|
environ['PATH_INFO'] = path_info[len(script_name):]
|
||||||
|
|
||||||
|
return self.app(environ, start_response)
|
Loading…
Reference in New Issue
Block a user