def resolve_href(self, req, resp, log): """Figure out the theme URL given a request and response. This calls the pyref, or does URI template substitution on an href attribute""" substitute = True if self.pyref: if not execute_pyref(req): log.error( self, "Security disallows executing pyref %s" % self.pyref) ## FIXME: this isn't very good; fatal exception?: href = self.href else: href = self.pyref(req, resp, log) substitute = False else: href = self.href if substitute: vars = NestedDict(req.environ, req.headers, dict(here=posixpath.dirname(self.source_location))) new_href = uri_template_substitute(href, vars) if new_href != href: log.debug( self, 'Rewrote theme href="%s" to "%s"' % (href, new_href)) href = new_href ## FIXME: is this join a good idea? if href: href = urlparse.urljoin(req.url, href) return href
def resolve_href(self, req, resp, log): """Figure out the theme URL given a request and response. This calls the pyref, or does URI template substitution on an href attribute""" substitute = True if self.pyref: if not execute_pyref(req): log.error( self, "Security disallows executing pyref %s" % self.pyref) ## FIXME: this isn't very good; fatal exception?: href = self.href else: href = self.pyref(req, resp, log) substitute = False else: href = self.href if substitute: vars = NestedDict(req.environ, req.headers, dict(here=posixpath.dirname(self.source_location))) new_href = uri_template_substitute(href, vars) if new_href != href: log.debug( self, 'Rewrote theme href="%s" to "%s"' % (href, new_href)) href = new_href ## FIXME: is this join a good idea? if href: href = urllib.parse.urljoin(req.url, href) return href
def __call__(self, request, log): """Determine the destination given the request""" assert not self.next if self.pyref: if not execute_pyref(request): log.error(self, "Security disallows executing pyref %s" % self.pyref) else: return self.pyref(request, log) ## FIXME: is this nesting really needed? ## we could just use HTTP_header keys... vars = NestedDict(request.environ, request.headers, dict(here=posixpath.dirname(self.source_location))) return uri_template_substitute(self.href, vars)
def __call__(self, request, log): """Determine the destination given the request""" assert not self.__next__ if self.pyref: if not execute_pyref(request): log.error(self, "Security disallows executing pyref %s" % self.pyref) else: return self.pyref(request, log) ## FIXME: is this nesting really needed? ## we could just use HTTP_header keys... vars = NestedDict(request.environ, request.headers, dict(here=posixpath.dirname(self.source_location))) return uri_template_substitute(self.href, vars)
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
def modify_response(self, request, response, orig_base, proxied_base, proxied_url, log): """ Modify the response however the user wanted. """ if proxied_base is not None and proxied_url is not None: # This might not have a trailing /: exact_proxied_base = proxied_base if not proxied_base.endswith('/'): proxied_base += '/' exact_orig_base = orig_base if not orig_base.endswith('/'): orig_base += '/' assert ( proxied_url.startswith(proxied_base) or proxied_url.split('?', 1)[0] == proxied_base[:-1] ), ("Unexpected proxied_url %r, doesn't start with proxied_base %r" % (proxied_url, proxied_base)) assert ( request.url.startswith(orig_base) or request.url.split('?', 1)[0] == orig_base[:-1] ), ("Unexpected request.url %r, doesn't start with orig_base %r" % (request.url, orig_base)) if self.pyref: if not execute_pyref(request): log.error(self, "Security disallows executing pyref %s" % self.pyref) else: result = self.pyref(request, response, orig_base, proxied_base, proxied_url, log) if isinstance(result, Response): response = result if self.header: response.headers[self.header] = self.content if self.rewrite_links: def link_repl_func(link): """Rewrites a link to point to this proxy""" if link == exact_proxied_base: return exact_orig_base if not link.startswith(proxied_base): # External link, so we don't rewrite it return link new = orig_base + link[len(proxied_base):] return new if response.content_type != 'text/html': log.debug( self, 'Not rewriting links in response from %s, because Content-Type is %s' % (proxied_url, response.content_type)) else: if not response.charset: ## FIXME: maybe we should guess the encoding? body = response.body else: body = response.unicode_body if len(body) > 0: body_doc = document_fromstring(body, base_url=proxied_url) body_doc.make_links_absolute() body_doc.rewrite_links(link_repl_func) response.body = tostring(body_doc) if response.location: ## FIXME: if you give a proxy like ## http://openplans.org, and it redirects to ## http://www.openplans.org, it won't be rewritten and ## that can be confusing -- it *shouldn't* be ## rewritten, but some better log message is required loc = urllib.parse.urljoin(proxied_url, response.location) loc = link_repl_func(loc) response.location = loc if 'set-cookie' in response.headers: cookies = response.headers.getall('set-cookie') del response.headers['set-cookie'] for cook in cookies: old_domain = urllib.parse.urlsplit(proxied_url)[1].lower() new_domain = request.host.split(':', 1)[0].lower() def rewrite_domain(match): """Rewrites domains to point to this proxy""" domain = match.group(2) if domain == old_domain: ## FIXME: doesn't catch wildcards and the sort return match.group(1) + new_domain + match.group(3) else: return match.group(0) cook = self._cookie_domain_re.sub(rewrite_domain, cook) response.headers.add('set-cookie', cook) return response
def modify_response(self, request, response, orig_base, proxied_base, proxied_url, log): """ Modify the response however the user wanted. """ # This might not have a trailing /: exact_proxied_base = proxied_base if not proxied_base.endswith("/"): proxied_base += "/" exact_orig_base = orig_base if not orig_base.endswith("/"): orig_base += "/" assert ( proxied_url.startswith(proxied_base) or proxied_url.split("?", 1)[0] == proxied_base[:-1] ), "Unexpected proxied_url %r, doesn't start with proxied_base %r" % (proxied_url, proxied_base) assert ( request.url.startswith(orig_base) or request.url.split("?", 1)[0] == orig_base[:-1] ), "Unexpected request.url %r, doesn't start with orig_base %r" % (request.url, orig_base) if self.pyref: if not execute_pyref(request): log.error(self, "Security disallows executing pyref %s" % self.pyref) else: result = self.pyref(request, response, orig_base, proxied_base, proxied_url, log) if isinstance(result, Response): response = result if self.header: response.headers[self.header] = self.content if self.rewrite_links: def link_repl_func(link): """Rewrites a link to point to this proxy""" if link == exact_proxied_base: return exact_orig_base if not link.startswith(proxied_base): # External link, so we don't rewrite it return link new = orig_base + link[len(proxied_base) :] return new if response.content_type != "text/html": log.debug( self, "Not rewriting links in response from %s, because Content-Type is %s" % (proxied_url, response.content_type), ) else: if not response.charset: ## FIXME: maybe we should guess the encoding? body = response.body else: body = response.unicode_body body_doc = document_fromstring(body, base_url=proxied_url) body_doc.make_links_absolute() body_doc.rewrite_links(link_repl_func) response.body = tostring(body_doc) if response.location: ## FIXME: if you give a proxy like ## http://openplans.org, and it redirects to ## http://www.openplans.org, it won't be rewritten and ## that can be confusing -- it *shouldn't* be ## rewritten, but some better log message is required loc = urlparse.urljoin(proxied_url, response.location) loc = link_repl_func(loc) response.location = loc if "set-cookie" in response.headers: cookies = response.headers.getall("set-cookie") del response.headers["set-cookie"] for cook in cookies: old_domain = urlparse.urlsplit(proxied_url)[1].lower() new_domain = request.host.split(":", 1)[0].lower() def rewrite_domain(match): """Rewrites domains to point to this proxy""" domain = match.group(2) if domain == old_domain: ## FIXME: doesn't catch wildcards and the sort return match.group(1) + new_domain + match.group(3) else: return match.group(0) cook = self._cookie_domain_re.sub(rewrite_domain, cook) response.headers.add("set-cookie", cook) return response
def __call__(self, request, resp, response_headers, log): """ Checks this match against the given request and response_headers object. `response_headers` should be a case-insensitive dictionary. `request` should be a :class:webob.Request object. """ result = True debug_name = self.debug_description() debug_context = self.log_context() if self.path: if not self.path(request.path): log.debug( debug_context, 'Skipping %s because request URL (%s) does not ' 'match path="%s"', debug_name, request.path, self.path) return False if self.domain: host = request.host.split(':', 1)[0] if not self.domain(host): log.debug( debug_context, 'Skipping %s because request domain (%s) does ' 'not match domain="%s"', debug_name, host, self.domain) return False if self.request_header: result, headers = self.request_header(request.headers) if not result: log.debug( debug_context, 'Skipping %s because request headers %s do not ' 'match request-header="%s"', debug_name, ', '.join(headers), self.request_header) return False if self.response_header: result, headers = self.response_header(response_headers) if not result: header_debug = [] for header in headers: header_debug.append( '%s: %s' % (header, response_headers.get(header, '(empty)'))) ## FIXME: maybe distinguish <meta> headers and real headers? log.debug( debug_context, 'Skipping %s because the response headers %s ' 'do not match response-header="%s"', debug_name, ', '.join(header_debug), self.response_header) return False if self.response_status: result = self.response_status(str(resp.status_int)) if not result: log.debug( debug_context, 'Skipping %s because response status %s do not ' 'match request-header="%s"', debug_name, resp.status_int, self.response_status) return False if self.environ: result, keys = self.environ(request.environ) if not result: log.debug( debug_context, 'Skipping %s because the request environ (keys %s) ' 'did not match environ="%s"', debug_name, ', '.join(keys), self.environ) return False if self.pyref: if not execute_pyref(request): log.error(self, "Security disallows executing pyref %s") else: result = self.pyref(request, resp, response_headers, log) if not result: log.debug( debug_context, 'Skipping %s because the reference <%s> returned false', debug_name, self.pyref) return False if isinstance(result, str): result = result.split() if isinstance(result, (list, tuple)): return getattr(self, 'classes', []) + list(result) return getattr(self, 'classes', None) or True
def __call__(self, request, resp, response_headers, log): """ Checks this match against the given request and response_headers object. `response_headers` should be a case-insensitive dictionary. `request` should be a :class:webob.Request object. """ result = True debug_name = self.debug_description() debug_context = self.log_context() if self.path: if not self.path(request.path): log.debug( debug_context, 'Skipping %s because request URL (%s) does not ' 'match path="%s"', debug_name, request.path, self.path) return False if self.domain: host = request.host.split(':', 1)[0] if not self.domain(host): log.debug( debug_context, 'Skipping %s because request domain (%s) does ' 'not match domain="%s"', debug_name, host, self.domain) return False if self.request_header: result, headers = self.request_header(request.headers) if not result: log.debug( debug_context, 'Skipping %s because request headers %s do not ' 'match request-header="%s"', debug_name, ', '.join(headers), self.request_header) return False if self.response_header: result, headers = self.response_header(response_headers) if not result: header_debug = [] for header in headers: header_debug.append('%s: %s' % (header, response_headers.get(header, '(empty)'))) ## FIXME: maybe distinguish <meta> headers and real headers? log.debug( debug_context, 'Skipping %s because the response headers %s ' 'do not match response-header="%s"', debug_name, ', '.join(header_debug), self.response_header) return False if self.response_status: result = self.response_status(str(resp.status_int)) if not result: log.debug( debug_context, 'Skipping %s because response status %s do not ' 'match request-header="%s"', debug_name, resp.status_int, self.response_status) return False if self.environ: result, keys = self.environ(request.environ) if not result: log.debug( debug_context, 'Skipping %s because the request environ (keys %s) ' 'did not match environ="%s"', debug_name, ', '.join(keys), self.environ) return False if self.pyref: if not execute_pyref(request): log.error( self, "Security disallows executing pyref %s") else: result = self.pyref(request, resp, response_headers, log) if not result: log.debug( debug_context, 'Skipping %s because the reference <%s> returned false', debug_name, self.pyref) return False if isinstance(result, basestring): result = result.split() if isinstance(result, (list, tuple)): return getattr(self, 'classes', []) + list(result) return getattr(self, 'classes', None) or True
def modify_response(self, request, response, orig_base, proxied_base, proxied_url, log): """ Modify the response however the user wanted. """ # This might not have a trailing /: exact_proxied_base = proxied_base if not proxied_base.endswith('/'): proxied_base += '/' exact_orig_base = orig_base if not orig_base.endswith('/'): orig_base += '/' assert (proxied_url.startswith(proxied_base) or proxied_url.split('?', 1)[0] == proxied_base[:-1]), ( "Unexpected proxied_url %r, doesn't start with proxied_base %r" % (proxied_url, proxied_base)) assert (request.url.startswith(orig_base) or request.url.split('?', 1)[0] == orig_base[:-1]), ( "Unexpected request.url %r, doesn't start with orig_base %r" % (request.url, orig_base)) #j import pdb; pdb.set_trace() if self.pyref: if not execute_pyref(request): log.error( self, "Security disallows executing pyref %s" % self.pyref) else: result = self.pyref(request, response, orig_base, proxied_base, proxied_url, log) if isinstance(result, Response): response = result if self.header: response.headers[self.header] = self.content if self.rewrite_links: def link_repl_func(link): """Rewrites a link to point to this proxy""" if link == exact_proxied_base: return exact_orig_base if not link.startswith(proxied_base): # External link, so we don't rewrite it return link new = orig_base + link[len(proxied_base):] return new if response.content_type != 'text/html': log.debug( self, 'Not rewriting links in response from %s, because Content-Type is %s' % (proxied_url, response.content_type)) elif not response.location: if not response.charset: ## FIXME: maybe we should guess the encoding? body = response.body else: body = response.unicode_body body_doc = document_fromstring(body, base_url=proxied_url) body_doc.make_links_absolute() body_doc.rewrite_links(link_repl_func) response.body = tostring(body_doc) if response.location: ## FIXME: if you give a proxy like ## http://openplans.org, and it redirects to ## http://www.openplans.org, it won't be rewritten and ## that can be confusing -- it *shouldn't* be ## rewritten, but some better log message is required #import pdb; pdb.set_trace() loc = urlparse.urljoin(proxied_url, response.location) #XXX here might be a good point to clean the location of #unwanted '//' loc = link_repl_func(loc) response.location = loc if 'set-cookie' in response.headers: cookies = response.headers.getall('set-cookie') del response.headers['set-cookie'] #stuff we need for cookie path rewriting further down _cookie_path_re = re.compile(r'(path="?)(\S*?)("?; )', re.I) orig_parts = urlparse.urlsplit(orig_base) orig_path = orig_parts[2] def rewrite_path(match): """Rewrite the path of the cookie""" old_path = match.group(2) new_path = orig_path + old_path new_path = new_path.replace('//','/') return match.group(1) + new_path + match.group(3) for cook in cookies: old_domain = urlparse.urlsplit(proxied_url)[1].lower() new_domain = request.host.split(':', 1)[0].lower() def rewrite_domain(match): """Rewrites domains to point to this proxy""" domain = match.group(2) #import pdb; pdb.set_trace() if old_domain.endswith(domain) or domain.endswith(old_domain): ## FIXME: doesn't catch wildcards and the sort return match.group(1) + new_domain + match.group(3) else: return match.group(0) cook = self._cookie_domain_re.sub(rewrite_domain, cook) cook = _cookie_path_re.sub(rewrite_path,cook) response.headers.add('Set-Cookie', cook) return response