Example #1
0
    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
Example #2
0
    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
Example #3
0
    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")
Example #4
0
    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")
Example #5
0
    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
Example #6
0
    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")