Skip to content

Instantly share code, notes, and snippets.

@mitchellrj
Created September 14, 2012 13:20
Show Gist options
  • Save mitchellrj/3721859 to your computer and use it in GitHub Desktop.
Save mitchellrj/3721859 to your computer and use it in GitHub Desktop.
Implementations of the TRACE and OPTIONS HTTP methods for Pyramid
config.add_route('options', '/*path', request_method='OPTIONS', view='.utility_views.OptionsView')
config.add_route('trace', '/*path', request_method='TRACE', view='.utility_views.TraceView')
from pyramid.interfaces import IRequest
from pyramid.interfaces import IRootFactory
from pyramid.interfaces import IRoutesMapper
from pyramid.interfaces import IRouteRequest
from pyramid.interfaces import ITraverser
from pyramid.interfaces import IViewClassifier
from pyramid.interfaces import IView
from pyramid.traversal import DefaultRootFactory
from pyramid.traversal import ResourceTreeTraverser
from pyramid.view import view_config
from zope.interface import providedBy
@view_config(name='trace_view', request_method='TRACE', route_name='trace')
def TraceView(request):
req = '%s %s %s' % (request.method,
request.path_info,
request.environ.get('SERVER_PROTOCOL', 'HTTP/1.1'))
headers = ['%s: %s' % h for h in request.headers.iteritems()]
request_data = '\r\n'.join([req] + headers) + '\r\n\r\n' + request.body
request.response.text = request_data
request.response.content_type = 'message/http'
return request.response
@view_config(name='options_view', request_method='OPTIONS', route_name='options')
class OptionsView(object):
all_methods = set(['GET', 'HEAD', 'POST', 'OPTIONS', 'PUT', 'DELETE', 'PATCH', 'TRACE'])
def _get_view_predicates(self, view_callable):
# hack
view_predicates = view_callable.func_dict.get('__predicates__', [])
return view_predicates
def _get_allowed_methods_from_predicates(self, predicates):
allowed_methods = set(list(self.all_methods)[:])
for p in predicates:
# hack
predicate = getattr(p, '__text__', '')
if predicate.startswith('request method = '):
allowed_methods &= set(eval(predicate[17:]))
return allowed_methods
def __init__(self, request):
self.request = request
def __call__(self):
request = self.request
reg = request.registry
default_root_factory = reg.queryUtility(IRootFactory, default=DefaultRootFactory)
mapper = reg.getUtility(IRoutesMapper)
path_info = '/'.join(request.matchdict['path'])
if path_info[:1] != '/':
path_info = '/' + path_info
matched_routes = []
for route in mapper.get_routes():
if route is request.matched_route:
# Don't match ourself
continue
if route.match(path_info) is not None:
matched_routes.append(route)
allowed_methods = set(['OPTIONS']) # We're already doing OPTIONS on it
for route in matched_routes:
route_predicates = getattr(route, 'predicates', [])
route_allowed_methods = self._get_allowed_methods_from_predicates(route_predicates)
request_iface = reg.queryUtility(
IRouteRequest,
name=route.name,
default=IRequest)
root_factory = route.factory or default_root_factory
root = root_factory(route)
traverser = reg.adapters.queryAdapter(root, ITraverser)
if traverser is None:
traverser = ResourceTreeTraverser(root)
tdict = traverser(request)
view_callable = reg.adapters.lookup(
(IViewClassifier, request_iface, providedBy(tdict['context'])),
IView, name=tdict['view_name'], default=None
)
view_predicates = self._get_view_predicates(view_callable)
view_allowed_methods = self._get_allowed_methods_from_predicates(view_predicates)
allowed_methods |= route_allowed_methods & view_allowed_methods
request.response.headers['Allow'] = ', '.join(allowed_methods)
if 'Access-Control-Request-Method' in request.headers:
request.response.headers['Access-Control-Allow-Methods'] = ', '.join(allowed_methods)
return request.response
@rajanaresh
Copy link

I am in dire need of handling HTTP OPTIONS request, I am making a XHR CORS request and I need to be able to handle HTTP OPTIONS request for preflighted requests. Would be nice if I you could give an example of how to use this? Thank you very much.

Raja

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment