mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-01-26 15:28:37 -05:00
Add CORS support and cross-domain response helpers.
This commit is contained in:
@@ -56,6 +56,7 @@ cache_affecting_cookies = ('reddit_first','over18','_options')
|
||||
|
||||
class Cookies(dict):
|
||||
def add(self, name, value, *k, **kw):
|
||||
name = name.encode('utf-8')
|
||||
self[name] = Cookie(value, *k, **kw)
|
||||
|
||||
class Cookie(object):
|
||||
@@ -467,6 +468,32 @@ def paginated_listing(default_page_size=25, max_page_size=100):
|
||||
def base_listing(fn):
|
||||
return paginated_listing()(fn)
|
||||
|
||||
def cross_domain(origins, **options):
|
||||
"""Set up cross domain validation and hoisting for a request handler."""
|
||||
origins = filter(None, origins)
|
||||
def cross_domain_wrap(fn):
|
||||
def cross_domain_handler(self, *args, **kwargs):
|
||||
if request.params.get("hoist") == "cookie":
|
||||
# Cookie polling response
|
||||
if g.origin in origins:
|
||||
name = request.environ["pylons.routes_dict"]["action_name"]
|
||||
resp = fn(self, *args, **kwargs)
|
||||
c.cookies.add('hoist_%s' % name, ''.join(resp.content))
|
||||
c.response_content_type = 'text/html'
|
||||
resp.content = ''
|
||||
return resp
|
||||
else:
|
||||
abort(403)
|
||||
else:
|
||||
self.check_cors()
|
||||
return fn(self, *args, **kwargs)
|
||||
|
||||
cross_domain_handler.cors_perms = {
|
||||
"allowed_origins": origins,
|
||||
"allow_credentials": bool(options.get("allow_credentials"))
|
||||
}
|
||||
return cross_domain_handler
|
||||
return cross_domain_wrap
|
||||
|
||||
class MinimalController(BaseController):
|
||||
|
||||
@@ -616,6 +643,34 @@ class MinimalController(BaseController):
|
||||
def abort403(self):
|
||||
abort(403, "forbidden")
|
||||
|
||||
def check_cors(self):
|
||||
origin = request.headers.get("Origin")
|
||||
if not origin:
|
||||
return
|
||||
|
||||
method = request.method
|
||||
if method == 'OPTIONS':
|
||||
# preflight request
|
||||
method = request.headers.get("Access-Control-Request-Method")
|
||||
if not method:
|
||||
self.abort403()
|
||||
|
||||
action = request.environ["pylons.routes_dict"]["action_name"]
|
||||
|
||||
handler = getattr(self, method + "_" + action, None)
|
||||
cors = handler and getattr(handler, "cors_perms", None)
|
||||
|
||||
if cors and origin in cors["allowed_origins"]:
|
||||
response.headers["Access-Control-Allow-Origin"] = origin
|
||||
if cors.get("allow_credentials"):
|
||||
response.headers["Access-Control-Allow-Credentials"] = "true"
|
||||
else:
|
||||
self.abort403()
|
||||
|
||||
def OPTIONS(self):
|
||||
"""Return empty responses for CORS preflight requests"""
|
||||
self.check_cors()
|
||||
|
||||
def sendpng(self, string):
|
||||
c.response_content_type = 'image/png'
|
||||
c.response.content = string
|
||||
|
||||
@@ -284,6 +284,7 @@ class Globals(object):
|
||||
|
||||
self.REDDIT_MAIN = bool(os.environ.get('REDDIT_MAIN'))
|
||||
|
||||
self.origin = "http://" + self.domain
|
||||
self.secure_domains = set([urlparse(self.payment_domain).netloc])
|
||||
|
||||
# load the unique hashed names of files under static
|
||||
|
||||
@@ -93,9 +93,15 @@ class BaseController(WSGIController):
|
||||
meth = request.method.upper()
|
||||
if meth == 'HEAD':
|
||||
meth = 'GET'
|
||||
request.environ['pylons.routes_dict']['action'] = \
|
||||
meth + '_' + action
|
||||
|
||||
if meth != 'OPTIONS':
|
||||
handler_name = meth + '_' + action
|
||||
else:
|
||||
handler_name = meth
|
||||
|
||||
request.environ['pylons.routes_dict']['action_name'] = action
|
||||
request.environ['pylons.routes_dict']['action'] = handler_name
|
||||
|
||||
c.response = Response()
|
||||
try:
|
||||
res = WSGIController.__call__(self, environ, start_response)
|
||||
|
||||
Reference in New Issue
Block a user