コード例 #1
0
ファイル: proxy.py プロジェクト: malthe/Deliverance
    def proxy_to_wsgi(self, request, wsgi_app):
        """ Forward a request to an inner wsgi app """
        orig_base = url_normalize(request.application_url)

        ## FIXME: should this be request.copy()?
        proxy_req = Request(request.environ.copy())
        resp = proxy_req.get_response(wsgi_app)

        return resp, orig_base, None, None
コード例 #2
0
    def proxy_to_wsgi(self, request, wsgi_app):
        """ Forward a request to an inner wsgi app """
        orig_base = url_normalize(request.application_url)

        ## FIXME: should this be request.copy()?
        proxy_req = Request(request.environ.copy())
        resp = proxy_req.get_response(wsgi_app)

        return resp, orig_base, None, None
コード例 #3
0
    def forward_request(self, environ, start_response):
        """Forward this request to the remote server, or serve locally.

        This also applies all the request and response transformations.
        """
        request = Request(environ)
        prefix = self.match.strip_prefix()
        if prefix:
            if prefix.endswith('/'):
                prefix = prefix[:-1]
            path_info = request.path_info
            if not path_info.startswith(prefix +
                                        '/') and not path_info == prefix:
                log = environ['deliverance.log']
                log.warn(
                    self,
                    "The match would strip the prefix %r from the request "
                    "path (%r), but they do not match" %
                    (prefix + '/', path_info))
            else:
                request.script_name = request.script_name + prefix
                request.path_info = path_info[len(prefix):]
        log = request.environ['deliverance.log']
        for modifier in self.request_modifications:
            request = modifier.modify_request(request, log)
        if self.dest and self.dest.__next__:
            raise AbortProxy

        dest, wsgiapp = None, None
        if self.dest:
            dest = self.dest(request, log)
            log.debug(self, '<proxy> matched; forwarding request to %s' % dest)
        else:
            wsgi_app = self.wsgi(request, log)
            log.debug(self,
                      '<proxy> matched; forwarding request to %s' % wsgi_app)

        if self.classes:
            log.debug(self,
                      'Adding class="%s" to page' % ' '.join(self.classes))
            existing_classes = request.environ.setdefault(
                'deliverance.page_classes', [])
            existing_classes.extend(self.classes)

        if dest is not None:
            response, orig_base, proxied_base, proxied_url = self.proxy_to_dest(
                request, dest)
        else:
            ## FIXME: proxied_base and proxied_url don't really have a meaning here,
            ##        but the modifier signature expects them
            response, orig_base, proxied_base, proxied_url = self.proxy_to_wsgi(
                request, wsgi_app)

        for modifier in self.response_modifications:
            response = modifier.modify_response(request, response, orig_base,
                                                proxied_base, proxied_url, log)
        return response(environ, start_response)
コード例 #4
0
 def application(self, environ, start_response):
     """The full application, that routes into the ruleset then out through
     the proxies itself.
     """
     req = Request(environ)
     log = SavingLogger(req, self.deliverator)
     req.environ['deliverance.log'] = log
     if req.path_info.startswith('/.deliverance/proxy-editor/'):
         req.path_info_pop()
         req.path_info_pop()
         return self.proxy_editor(environ, start_response)
     return self.deliverator(environ, start_response)
コード例 #5
0
ファイル: proxy.py プロジェクト: pombredanne/Deliverance
 def application(self, environ, start_response):
     """The full application, that routes into the ruleset then out through
     the proxies itself.
     """
     req = Request(environ)
     log = SavingLogger(req, self.deliverator)
     req.environ["deliverance.log"] = log
     if req.path_info.startswith("/.deliverance/proxy-editor/"):
         req.path_info_pop()
         req.path_info_pop()
         return self.proxy_editor(environ, start_response)
     return self.deliverator(environ, start_response)
コード例 #6
0
ファイル: proxy.py プロジェクト: malthe/Deliverance
    def forward_request(self, environ, start_response):
        """Forward this request to the remote server, or serve locally.

        This also applies all the request and response transformations.
        """
        request = Request(environ)
        prefix = self.match.strip_prefix()
        if prefix:
            if prefix.endswith('/'):
                prefix = prefix[:-1]
            path_info = request.path_info
            if not path_info.startswith(prefix + '/') and not path_info == prefix:
                log = environ['deliverance.log']
                log.warn(
                    self, "The match would strip the prefix %r from the request "
                    "path (%r), but they do not match"
                    % (prefix + '/', path_info))
            else:
                request.script_name = request.script_name + prefix
                request.path_info = path_info[len(prefix):]
        log = request.environ['deliverance.log']
        for modifier in self.request_modifications:
            request = modifier.modify_request(request, log)
        if self.dest and self.dest.next:
            raise AbortProxy

        dest, wsgiapp = None, None
        if self.dest:
            dest = self.dest(request, log)
            log.debug(self, '<proxy> matched; forwarding request to %s' % dest)
        else:
            wsgi_app = self.wsgi(request, log)
            log.debug(self, '<proxy> matched; forwarding request to %s' % wsgi_app)

        if self.classes:
            log.debug(self, 'Adding class="%s" to page' % ' '.join(self.classes))
            existing_classes = request.environ.setdefault('deliverance.page_classes', [])
            existing_classes.extend(self.classes)

        if dest is not None:
            response, orig_base, proxied_base, proxied_url = self.proxy_to_dest(request, dest)
        else:
            ## FIXME: proxied_base and proxied_url don't really have a meaning here,
            ##        but the modifier signature expects them
            response, orig_base, proxied_base, proxied_url = self.proxy_to_wsgi(request, wsgi_app)

        for modifier in self.response_modifications:
            response = modifier.modify_response(request, response, orig_base, 
                                                proxied_base, proxied_url, log)
        return response(environ, start_response)
コード例 #7
0
 def proxy_app(self, environ, start_response):
     """Implements the proxy, finding the matching `Proxy` object and
     forwarding the request on to that.
     """
     request = Request(environ)
     log = environ['deliverance.log']
     for index, proxy in enumerate(self.proxies):
         if proxy.editable:
             url = request.application_url + '/.deliverance/proxy-editor/%s/' % (
                 index + 1)
             name = proxy.editable_name
             if (url, name) not in log.edit_urls:
                 log.edit_urls.append((url, name))
         ## FIXME: obviously this is wonky:
         if proxy.match(request, None, None, log):
             try:
                 return proxy.forward_request(environ, start_response)
             except AbortProxy as e:
                 log.debug(self,
                           '<proxy> aborted (%s), trying next proxy' % e)
                 continue
             ## FIXME: should also allow for AbortTheme?
     log.error(
         self,
         'No proxy matched the request; aborting with a 404 Not Found error'
     )
     ## FIXME: better error handling would be nice:
     resp = exc.HTTPNotFound()
     return resp(environ, start_response)
コード例 #8
0
ファイル: proxy.py プロジェクト: deliverance/Deliverance
    def proxy_to_dest(self, request, dest):
        """Do the actual proxying, without applying any transformations"""
        # We need to remove caching headers, since the upstream parts of Deliverance
        # can't handle Not-Modified responses.
        # Not using request.copy because I don't want to copy wsgi.input
        request = Request(request.environ.copy())
        request.remove_conditional_headers()

        try:
            proxy_req = self.construct_proxy_request(request, dest)
        except TypeError:
            return self.proxy_to_file(request, dest)

        proxy_req.path_info += request.path_info

        if proxy_req.query_string and request.query_string:
            proxy_req.query_string = '%s&%s' % \
                (proxy_req.query_string, request.query_string)
        elif request.query_string:
            proxy_req.query_string = request.query_string

        proxy_req.accept_encoding = None
        try:
            resp = proxy_req.get_response(proxy_exact_request)
            if resp.status_int == 500:
                print 'Request:'
                print proxy_req
                print 'Response:'
                print resp
        except socket.error, e:
            ## FIXME: really wsgiproxy should handle this
            ## FIXME: which error?
            ## 502 HTTPBadGateway, 503 HTTPServiceUnavailable, 504 HTTPGatewayTimeout?
            if isinstance(e.args, tuple) and len(e.args) > 1:
                error = e.args[1]
            else:
                error = str(e)
            resp = exc.HTTPServiceUnavailable(
                'Could not proxy the request to %s:%s : %s' 
                % (proxy_req.server_name, proxy_req.server_port, error))
コード例 #9
0
 def modify_request(self, request, log):
     """Apply the modification to the request"""
     if self.pyref:
         if not execute_pyref(request):
             log.error(self,
                       "Security disallows executing pyref %s" % self.pyref)
         else:
             result = self.pyref(request, log)
             if isinstance(result, dict):
                 request = Request(result)
             elif isinstance(result, Request):
                 request = result
     if self.header:
         request.headers[self.header] = self.content
     return request
コード例 #10
0
ファイル: proxy.py プロジェクト: pombredanne/Deliverance
    def forward_request(self, environ, start_response):
        """Forward this request to the remote server, or serve locally.

        This also applies all the request and response transformations.
        """
        request = Request(environ)
        prefix = self.match.strip_prefix()
        if prefix:
            if prefix.endswith("/"):
                prefix = prefix[:-1]
            path_info = request.path_info
            if not path_info.startswith(prefix + "/") and not path_info == prefix:
                log = environ["deliverance.log"]
                log.warn(
                    self,
                    "The match would strip the prefix %r from the request "
                    "path (%r), but they do not match" % (prefix + "/", path_info),
                )
            else:
                request.script_name = request.script_name + prefix
                request.path_info = path_info[len(prefix) :]
        log = request.environ["deliverance.log"]
        for modifier in self.request_modifications:
            request = modifier.modify_request(request, log)
        if self.dest.next:
            raise AbortProxy
        dest = self.dest(request, log)
        log.debug(self, "<proxy> matched; forwarding request to %s" % dest)
        if self.classes:
            log.debug(self, 'Adding class="%s" to page' % " ".join(self.classes))
            existing_classes = request.environ.setdefault("deliverance.page_classes", [])
            existing_classes.extend(self.classes)
        response, orig_base, proxied_base, proxied_url = self.proxy_to_dest(request, dest)
        for modifier in self.response_modifications:
            response = modifier.modify_response(request, response, orig_base, proxied_base, proxied_url, log)
        return response(environ, start_response)
コード例 #11
0
    def proxy_to_dest(self, request, dest):
        """Do the actual proxying, without applying any transformations"""
        # We need to remove caching headers, since the upstream parts of Deliverance
        # can't handle Not-Modified responses.
        # Not using request.copy because I don't want to copy wsgi.input
        request = Request(request.environ.copy())
        request.remove_conditional_headers()

        try:
            proxy_req = self.construct_proxy_request(request, dest)
        except TypeError:
            return self.proxy_to_file(request, dest)

        proxy_req.path_info += request.path_info

        if proxy_req.query_string and request.query_string:
            proxy_req.query_string = '%s&%s' % \
                (proxy_req.query_string, request.query_string)
        elif request.query_string:
            proxy_req.query_string = request.query_string

        proxy_req.accept_encoding = None
        try:
            resp = proxy_req.get_response(proxy_exact_request)
            if resp.status_int == 500:
                print('Request:')
                print(proxy_req)
                print('Response:')
                print(resp)
        except socket.error as e:
            ## FIXME: really wsgiproxy should handle this
            ## FIXME: which error?
            ## 502 HTTPBadGateway, 503 HTTPServiceUnavailable, 504 HTTPGatewayTimeout?
            if isinstance(e.args, tuple) and len(e.args) > 1:
                error = e.args[1]
            else:
                error = str(e)
            resp = exc.HTTPServiceUnavailable(
                'Could not proxy the request to %s:%s : %s' %
                (proxy_req.server_name, proxy_req.server_port, error))

        dest = url_normalize(dest)
        orig_base = url_normalize(request.application_url)
        proxied_url = url_normalize(
            '%s://%s%s' %
            (proxy_req.scheme, proxy_req.host, proxy_req.path_qs))

        return resp, orig_base, dest, proxied_url
コード例 #12
0
 def proxy_app(self, environ, start_response):
     """Implements the proxy, finding the matching `Proxy` object and
     forwarding the request on to that.
     """
     request = Request(environ)
     log = environ['deliverance.log']
     for index, proxy in enumerate(self.proxies):
         if proxy.editable:
             url = request.application_url + '/.deliverance/proxy-editor/%s/' % (index+1)
             name = proxy.editable_name
             if (url, name) not in log.edit_urls:
                 log.edit_urls.append((url, name))
         ## FIXME: obviously this is wonky:
         if proxy.match(request, None, None, log):
             try:
                 return proxy.forward_request(environ, start_response)
             except AbortProxy, e:
                 log.debug(
                     self, '<proxy> aborted (%s), trying next proxy' % e)
                 continue
コード例 #13
0
    def construct_proxy_request(self, request, dest):
        """ 
        returns a new Request object constructed by copying `request`
        and replacing its url with the url passed in as `dest`

        @raises TypeError if `dest` is a file:// url; this can be
        caught by the caller and handled accordingly
        """

        dest = url_normalize(dest)
        scheme, netloc, path, query, fragment = urllib.parse.urlsplit(dest)
        path = urllib.parse.unquote(path)

        assert not fragment, ("Unexpected fragment: %r" % fragment)

        proxy_req = Request(request.environ.copy())

        proxy_req.path_info = path

        proxy_req.server_name = netloc.split(':', 1)[0]
        if ':' in netloc:
            proxy_req.server_port = netloc.split(':', 1)[1]
        elif scheme == 'http':
            proxy_req.server_port = '80'
        elif scheme == 'https':
            proxy_req.server_port = '443'
        elif scheme == 'file':
            raise TypeError  ## FIXME: is TypeError too general?
        else:
            assert 0, "bad scheme: %r (from %r)" % (scheme, dest)
        if not self.keep_host:
            proxy_req.host = netloc

        proxy_req.query_string = query
        proxy_req.scheme = scheme

        proxy_req.headers['X-Forwarded-For'] = request.remote_addr
        proxy_req.headers['X-Forwarded-Scheme'] = request.scheme
        proxy_req.headers['X-Forwarded-Server'] = request.host

        ## FIXME: something with path? proxy_req.headers['X-Forwarded-Path']
        ## (now we are only doing it with strip_script_name)
        if self.strip_script_name:
            proxy_req.headers['X-Forwarded-Path'] = proxy_req.script_name
            proxy_req.script_name = ''

        return proxy_req
コード例 #14
0
 def proxy_editor(self, environ, start_response):
     req = Request(environ)
     proxy = self.proxies[int(req.path_info_pop()) - 1]
     return proxy.edit_app(environ, start_response)
コード例 #15
0
ファイル: proxy.py プロジェクト: pombredanne/Deliverance
    def construct_proxy_request(self, request, dest):
        """ 
        returns a new Request object constructed by copying `request`
        and replacing its url with the url passed in as `dest`

        @raises TypeError if `dest` is a file:// url; this can be
        caught by the caller and handled accordingly
        """

        dest = url_normalize(dest)
        scheme, netloc, path, query, fragment = urlparse.urlsplit(dest)
        path = urllib.unquote(path)

        assert not fragment, "Unexpected fragment: %r" % fragment

        proxy_req = Request(request.environ.copy())

        proxy_req.path_info = path

        proxy_req.server_name = netloc.split(":", 1)[0]
        if ":" in netloc:
            proxy_req.server_port = netloc.split(":", 1)[1]
        elif scheme == "http":
            proxy_req.server_port = "80"
        elif scheme == "https":
            proxy_req.server_port = "443"
        elif scheme == "file":
            raise TypeError  ## FIXME: is TypeError too general?
        else:
            assert 0, "bad scheme: %r (from %r)" % (scheme, dest)
        if not self.keep_host:
            proxy_req.host = netloc

        proxy_req.query_string = query
        proxy_req.scheme = scheme

        proxy_req.headers["X-Forwarded-For"] = request.remote_addr
        proxy_req.headers["X-Forwarded-Scheme"] = request.scheme
        proxy_req.headers["X-Forwarded-Server"] = request.host

        ## FIXME: something with path? proxy_req.headers['X-Forwarded-Path']
        ## (now we are only doing it with strip_script_name)
        if self.strip_script_name:
            proxy_req.headers["X-Forwarded-Path"] = proxy_req.script_name
            proxy_req.script_name = ""

        return proxy_req
コード例 #16
0
ファイル: proxy.py プロジェクト: pombredanne/Deliverance
 def proxy_editor(self, environ, start_response):
     req = Request(environ)
     proxy = self.proxies[int(req.path_info_pop()) - 1]
     return proxy.edit_app(environ, start_response)