def __call__(self, environ, start_response): """Resolves the URL in PATH_INFO, and uses wsgi.routing_args to pass on URL resolver results.""" old_method = None if self.use_method_override: req = None # In some odd cases, there's no query string try: qs = environ['QUERY_STRING'] except KeyError: qs = '' if '_method' in qs: req = Request(environ) req.errors = 'ignore' if '_method' in req.GET: old_method = environ['REQUEST_METHOD'] environ['REQUEST_METHOD'] = req.GET['_method'].upper() if self.log_debug: log.debug("_method found in QUERY_STRING, altering request" " method to %s", environ['REQUEST_METHOD']) elif environ['REQUEST_METHOD'] == 'POST' and is_form_post(environ): if req is None: req = Request(environ) req.errors = 'ignore' if '_method' in req.POST: old_method = environ['REQUEST_METHOD'] environ['REQUEST_METHOD'] = req.POST['_method'].upper() if self.log_debug: log.debug("_method found in POST data, altering request " "method to %s", environ['REQUEST_METHOD']) # Run the actual route matching # -- Assignment of environ to config triggers route matching if self.singleton: config = request_config() config.mapper = self.mapper config.environ = environ match = config.mapper_dict route = config.route else: results = self.mapper.routematch(environ=environ) if results: match, route = results[0], results[1] else: match = route = None if old_method: environ['REQUEST_METHOD'] = old_method if not match: match = {} if self.log_debug: urlinfo = "%s %s" % (environ['REQUEST_METHOD'], environ['PATH_INFO']) log.debug("No route matched for %s", urlinfo) elif self.log_debug: urlinfo = "%s %s" % (environ['REQUEST_METHOD'], environ['PATH_INFO']) log.debug("Matched %s", urlinfo) log.debug("Route path: '%s', defaults: %s", route.routepath, route.defaults) log.debug("Match dict: %s", match) url = URLGenerator(self.mapper, environ) environ['wsgiorg.routing_args'] = ((url), match) environ['routes.route'] = route environ['routes.url'] = url if route and route.redirect: route_name = '_redirect_%s' % id(route) location = url_for(route_name, **match) log.debug("Using redirect route, redirect to '%s' with status" "code: %s", location, route.redirect_status) start_response(route.redirect_status, [('Content-Type', 'text/plain; charset=utf8'), ('Location', location)]) return [] # If the route included a path_info attribute and it should be used to # alter the environ, we'll pull it out if self.path_info and 'path_info' in match: oldpath = environ['PATH_INFO'] newpath = match.get('path_info') or '' environ['PATH_INFO'] = newpath if not environ['PATH_INFO'].startswith('/'): environ['PATH_INFO'] = '/' + environ['PATH_INFO'] environ['SCRIPT_NAME'] += re.sub(r'^(.*?)/' + re.escape(newpath) + '$', r'\1', oldpath) response = self.app(environ, start_response) # Wrapped in try as in rare cases the attribute will be gone already try: del self.mapper.environ except AttributeError: pass return response
def __call__(self, environ, start_response): """Resolves the URL in PATH_INFO, and uses wsgi.routing_args to pass on URL resolver results.""" config = request_config() config.mapper = self.mapper old_method = None if self.use_method_override: req = None # In some odd cases, there's no query string try: qs = environ['QUERY_STRING'] except KeyError: qs = '' if '_method' in qs: req = Request(environ) req.errors = 'ignore' if '_method' in req.GET: old_method = environ['REQUEST_METHOD'] environ['REQUEST_METHOD'] = req.GET['_method'].upper() if self.log_debug: log.debug( "_method found in QUERY_STRING, altering request" " method to %s", environ['REQUEST_METHOD']) elif environ['REQUEST_METHOD'] == 'POST' and is_form_post(environ): if req is None: req = Request(environ) req.errors = 'ignore' if '_method' in req.POST: old_method = environ['REQUEST_METHOD'] environ['REQUEST_METHOD'] = req.POST['_method'].upper() if self.log_debug: log.debug( "_method found in POST data, altering request " "method to %s", environ['REQUEST_METHOD']) # Run the actual route matching # -- Assignment of environ to config triggers route matching config.environ = environ match = config.mapper_dict route = config.route if old_method: environ['REQUEST_METHOD'] = old_method if not match: match = {} if self.log_debug: urlinfo = "%s %s" % (environ['REQUEST_METHOD'], environ['PATH_INFO']) log.debug("No route matched for %s", urlinfo) elif self.log_debug: urlinfo = "%s %s" % (environ['REQUEST_METHOD'], environ['PATH_INFO']) log.debug("Matched %s", urlinfo) log.debug("Route path: '%s', defaults: %s", route.routepath, route.defaults) log.debug("Match dict: %s", match) url = URLGenerator(self.mapper, environ) environ['wsgiorg.routing_args'] = ((url), match) environ['routes.route'] = route environ['routes.url'] = url if route and route.redirect: route_name = '_redirect_%s' % id(route) location = url_for(route_name, **match) log.debug( "Using redirect route, redirect to '%s' with status" "code: %s", location, route.redirect_status) start_response(route.redirect_status, [('Content-Type', 'text/plain; charset=utf8'), ('Location', location)]) return [] # If the route included a path_info attribute and it should be used to # alter the environ, we'll pull it out if self.path_info and 'path_info' in match: oldpath = environ['PATH_INFO'] newpath = match.get('path_info') or '' environ['PATH_INFO'] = newpath if not environ['PATH_INFO'].startswith('/'): environ['PATH_INFO'] = '/' + environ['PATH_INFO'] environ['SCRIPT_NAME'] += re.sub( r'^(.*?)/' + re.escape(newpath) + '$', r'\1', oldpath) if environ['SCRIPT_NAME'].endswith('/'): environ['SCRIPT_NAME'] = environ['SCRIPT_NAME'][:-1] response = self.app(environ, start_response) # Wrapped in try as in rare cases the attribute will be gone already try: del config.environ del self.mapper.environ except AttributeError: pass return response
def __call__(self, environ, start_response): """ A Router instance is a WSGI app. It accepts the standard WSGI call signature of ``environ``, ``start_response``. The Router has a few jobs. First it uses the Routes package to compare the requested path to available url patterns that have been loaded and passed to the Router upon init. Router is the most *framework-like* component of Pybald. In addition to dispatching urls to controllers, it also allows 'method override' behavior allowing other HTTP methods to be invoked such as ``put`` and ``delete`` from web clients that don't support them natively. :param environ: WSGI CGI-like request environment :param start_response: WSGI callback for starting the response and setting HTTP response headers """ req = Request(environ) req.errors = "ignore" # method override # =============== # for REST architecture, this allows a POST parameter of _method # to be used to override POST with alternate HTTP verbs (PUT, DELETE) if req.POST: override_method = req.POST.pop("_method", None) if override_method is not None: environ["REQUEST_METHOD"] = override_method.upper() console.debug("Changing request method to {0}".format(environ["REQUEST_METHOD"])) results = self.map.routematch(environ=environ) if results: match, route = results[0], results[1] else: match = route = None url = URLGenerator(self.map, environ) config = request_config() # Your mapper object config.mapper = self.map # The dict from m.match for this URL request config.mapper_dict = match config.host = req.host config.protocol = req.scheme # host_port # defines the redirect method. In this case it generates a # Webob Response object with the location and status headers # set config.redirect = lambda url: Response(location=url, status=302) environ.update( {"wsgiorg.routing_args": ((url), match), "routes.route": route, "routes.url": url, "pybald.router": self} ) # Add pybald extension # the pybald.extension is a dictionary that can be used to copy state # into a running controller (usually handled by the @action decorator) environ.setdefault("pybald.extension", {})["url_for"] = url # debug print messages console.debug("{0:=^79}".format(" {0} ".format(req.path_qs))) console.debug("Method: {0}".format(req.method)) # use routes to match the url to a path # urlvars will contain controller + other non query string # URL data. Middleware above this can override and set urlvars # and the router will use those values. # TODO: allow individual variable overrides? urlvars = environ.get("urlvars", match) or {} # lifted from Routes middleware, handles 'redirect' # routes (map.redirect) if route and route.redirect: route_name = "_redirect_{0}".format(id(route)) location = url(route_name, **match) return Response(location=location, status=route.redirect_status)(environ, start_response) req.urlvars = urlvars environ["urlvars"] = urlvars if urlvars: controller, handler = self.get_handler(urlvars) # No URL vars means nothing matched in the mapper function else: raise exc.HTTPNotFound("No URL match") try: # call the action we determined from the mapper return handler(environ, start_response) # This is a mako 'missing template' exception except exceptions.TopLevelLookupException: raise exc.HTTPNotFound("Missing Template")
def __call__(self, environ, start_response): ''' A Router instance is a WSGI app. It accepts the standard WSGI call signature of ``environ``, ``start_response``. The Router has a few jobs. First it uses the Routes package to compare the requested path to available url patterns that have been loaded and passed to the Router upon init. Router is the most *framework-like* component of Pybald. In addition to dispatching urls to controllers, it also allows 'method override' behavior allowing other HTTP methods to be invoked such as ``put`` and ``delete`` from web clients that don't support them natively. :param environ: WSGI CGI-like request environment :param start_response: WSGI callback for starting the response and setting HTTP response headers ''' req = Request(environ) req.errors = 'ignore' #method override #=============== # for REST architecture, this allows a POST parameter of _method # to be used to override POST with alternate HTTP verbs (PUT, DELETE) if req.POST: override_method = req.POST.pop('_method', None) if override_method is not None: environ['REQUEST_METHOD'] = override_method.upper() log.debug("Changing request method to {0}".format( environ["REQUEST_METHOD"])) results = self.map.routematch(environ=environ) if results: urlvars, route = results else: urlvars, route = {}, None url = URLGenerator(self.map, environ) config = request_config() # Your mapper object config.mapper = self.map # The dict from m.match for this URL request config.mapper_dict = urlvars config.host = req.host config.protocol = req.scheme # defines the redirect method. In this case it generates a # Webob Response object with the location and status headers # set config.redirect = lambda url: Response(location=url, status=302) # TODO: routing args is supposed to be pos, key dict environ.update({'wsgiorg.routing_args': ((url), urlvars), 'routes.route': route, 'routes.url': url, 'pybald.router': self}) # Add pybald extension # the pybald.extension is a dictionary that can be used to copy state # into a running controller (usually handled by the @action decorator) environ.setdefault('pybald.extension', {})["url_for"] = url # debug print messages log.debug('{0:=^79}'.format(' {0} '.format(req.path_qs))) log.debug('Method: {0}'.format(req.method)) # lifted from Routes middleware, handles 'redirect' # routes (map.redirect) if route and route.redirect: route_name = '_redirect_{0}'.format(id(route)) location = url(route_name, **urlvars) return Response(location=location, status=route.redirect_status )(environ, start_response) if urlvars: handler = self.get_handler(urlvars) # No URL vars means nothing matched in the mapper function else: raise exc.HTTPNotFound("No URL match") try: # call the action we determined from the mapper return handler(environ, start_response) # This is a mako 'missing template' exception except exceptions.TopLevelLookupException: raise exc.HTTPNotFound("Missing Template")
def __call__(self, environ, start_response): ''' A Router instance is a WSGI app. It accepts the standard WSGI call signature of ``environ``, ``start_response``. The Router has a few jobs. First it uses the Routes package to compare the requested path to available url patterns that have been loaded and passed to the Router upon init. Router is the most *framework-like* component of Pybald. In addition to dispatching urls to controllers, it also allows 'method override' behavior allowing other HTTP methods to be invoked such as ``put`` and ``delete`` from web clients that don't support them natively. ''' req = Request(environ) #method override #=============== # for REST architecture, this allows a POST parameter of _method # to be used to override POST with alternate HTTP verbs (PUT, DELETE) req.errors = 'ignore' params = req.POST if '_method' in req.params: environ['REQUEST_METHOD'] = req.params['_method'].upper() try: del req.POST['_method'] except: pass # Experiment, is it worth it to change get method too? try: del req.GET['_method'] except: pass if debug: print "Changing request method to {0}".format( environ["REQUEST_METHOD"]) # routes config object, this must be done on every request. # sets the mapper and allows link_to and redirect_to to # function on routes config = request_config() config.mapper = self.map config.environ = environ match = config.mapper_dict route = config.route url = URLGenerator(self.map, environ) environ['wsgiorg.routing_args'] = ((url), match) environ['routes.route'] = route environ['routes.url'] = url environ['pybald.router'] = self # Add pybald extension, normally gets assigned to controller object environ['pybald.extension'] = environ.get('pybald.extension', {}) environ['pybald.extension']["url_for"] = url # defines the redirect method. In this case it generates a # Webob Response object with the location and status headers # set config.redirect = lambda url: Response(location=url, status=302) # debug print messages if debug: print ''.join(['============= ',req.path,' ==============']) print 'Method: {0}'.format(req.method) # use routes to match the url to a path # urlvars will contain controller + other non query string # URL data. Middleware above this can override and set urlvars # and the router will use those values. # TODO: allow individual variable overrides? urlvars = environ.get('urlvars', self.map.match(environ=environ)) or {} # lifted from Routes middleware, handles 'redirect' # routes (map.redirect) if route and route.redirect: route_name = '_redirect_%s' % id(route) location = url(route_name, **match) return Response(location=location, status=route.redirect_status )(environ, start_response) req.urlvars = urlvars environ['urlvars'] = urlvars if urlvars: controller, handler = self.get_handler(urlvars) # No URL vars means nothing matched in the mapper function else: raise exc.HTTPNotFound("No URL match") try: # call the action we determined from the mapper return handler(environ,start_response) # This is a mako 'missing template' exception except exceptions.TopLevelLookupException: raise exc.HTTPNotFound("Missing Template") except: # All other program errors get re-raised # e.g. a 500 server error raise
def __call__(self, environ, start_response): ''' A Router instance is a WSGI app. It accepts the standard WSGI call signature of ``environ``, ``start_response``. The Router has a few jobs. First it uses the Routes package to compare the requested path to available url patterns that have been loaded and passed to the Router upon init. Router is the most *framework-like* component of Pybald. In addition to dispatching urls to controllers, it also allows 'method override' behavior allowing other HTTP methods to be invoked such as ``put`` and ``delete`` from web clients that don't support them natively. :param environ: WSGI CGI-like request environment :param start_response: WSGI callback for starting the response and setting HTTP response headers ''' req = Request(environ) req.errors = 'ignore' #method override #=============== # for REST architecture, this allows a POST parameter of _method # to be used to override POST with alternate HTTP verbs (PUT, DELETE) if req.POST: override_method = req.POST.pop('_method', None) if override_method is not None: environ['REQUEST_METHOD'] = override_method.upper() log.debug("Changing request method to {0}".format( environ["REQUEST_METHOD"])) results = self.map.routematch(environ=environ) if results: urlvars, route = results else: urlvars, route = {}, None url = URLGenerator(self.map, environ) config = request_config() # Your mapper object config.mapper = self.map # The dict from m.match for this URL request config.mapper_dict = urlvars config.host = req.host config.protocol = req.scheme # defines the redirect method. In this case it generates a # Webob Response object with the location and status headers # set config.redirect = lambda url: Response(location=url, status=302) # TODO: routing args is supposed to be pos, key dict environ.update({ 'wsgiorg.routing_args': ((url), urlvars), 'routes.route': route, 'routes.url': url, 'pybald.router': self }) # Add pybald extension # the pybald.extension is a dictionary that can be used to copy state # into a running controller (usually handled by the @action decorator) environ.setdefault('pybald.extension', {})["url_for"] = url # debug print messages log.debug('{0:=^79}'.format(' {0} '.format(req.path_qs))) log.debug('Method: {0}'.format(req.method)) # lifted from Routes middleware, handles 'redirect' # routes (map.redirect) if route and route.redirect: route_name = '_redirect_{0}'.format(id(route)) location = url(route_name, **urlvars) return Response(location=location, status=route.redirect_status)(environ, start_response) if urlvars: handler = self.get_handler(urlvars) # No URL vars means nothing matched in the mapper function else: raise exc.HTTPNotFound("No URL match") try: # call the action we determined from the mapper return handler(environ, start_response) # This is a mako 'missing template' exception except exceptions.TopLevelLookupException: raise exc.HTTPNotFound("Missing Template")