def get_theme_response(self, url, resource_fetcher, log): log.info(self, 'Fetching theme from %s' % url) log.theme_url = url ## FIXME: should do caching ## FIXME: check response status resp = resource_fetcher(url, retry_inner_if_not_200=True) if resp.status_int != 200: log.fatal( self, "The resource %s was not 200 OK: %s" % (url, resp.status)) raise AbortTheme( "The resource %s returned an error: %s" % (url, resp.status)) resp = force_charset(resp) return resp
def clientside_actions(self, req, resp, log): extra_headers = parse_meta_headers(resp.body) if extra_headers: response_headers = ResponseHeaders(resp.headerlist + extra_headers) else: response_headers = resp.headers try: classes = run_matches(self.matchers, req, resp, response_headers, log) except AbortTheme: assert 0, 'no abort should happen' if 'X-Deliverance-Page-Class' in response_headers: classes.extend( resp.headers['X-Deliverance-Page-Class'].strip().split()) if 'deliverance.page_classes' in req.environ: classes.extend(req.environ['deliverance.page_classes']) if not classes: classes = ['default'] rules = [] for class_name in classes: ## FIXME: handle case of unknown classes ## Or do that during compilation? for rule in self.rules_by_class.get(class_name, []): if rule not in rules: rules.append(rule) if rule.theme: assert 0, 'no rule themes should be present' resp = force_charset(resp) content_doc = self.parse_document(resp.unicode_body, req.url) actions = [] run_standard = True for rule in rules: if rule.match is not None: matches = rule.match(req, resp, response_headers, log) if not matches: log.debug(rule, "Skipping <rule>") continue actions.extend(rule.clientside_actions(content_doc, log)) if rule.suppress_standard: run_standard = False if run_standard: ## FIXME: should it be possible to put the standard rule in the ruleset? actions.extend(standard_rule.clientside_actions(content_doc, log)) return actions
def clientside_actions(self, req, resp, log): extra_headers = parse_meta_headers(resp.body) if extra_headers: response_headers = HeaderDict(resp.headerlist + extra_headers) else: response_headers = resp.headers try: classes = run_matches(self.matchers, req, resp, response_headers, log) except AbortTheme: assert 0, 'no abort should happen' if 'X-Deliverance-Page-Class' in response_headers: classes.extend(resp.headers['X-Deliverance-Page-Class'].strip().split()) if 'deliverance.page_classes' in req.environ: classes.extend(req.environ['deliverance.page_classes']) if not classes: classes = ['default'] rules = [] for class_name in classes: ## FIXME: handle case of unknown classes ## Or do that during compilation? for rule in self.rules_by_class.get(class_name, []): if rule not in rules: rules.append(rule) if rule.theme: assert 0, 'no rule themes should be present' resp = force_charset(resp) content_doc = self.parse_document(resp.unicode_body, req.url) actions = [] run_standard = True for rule in rules: if rule.match is not None: matches = rule.match(req, resp, response_headers, log) if not matches: log.debug(rule, "Skipping <rule>") continue actions.extend(rule.clientside_actions(content_doc, log)) if rule.suppress_standard: run_standard = False if run_standard: ## FIXME: should it be possible to put the standard rule in the ruleset? actions.extend(standard_rule.clientside_actions(content_doc, log)) return actions
def apply_rules(self, req, resp, resource_fetcher, log, default_theme=None): """ Apply the whatever the appropriate rules are to the request/response. """ extra_headers = parse_meta_headers(resp.body) if extra_headers: response_headers = HeaderDict(resp.headerlist + extra_headers) else: response_headers = resp.headers try: classes = run_matches(self.matchers, req, resp, response_headers, log) except AbortTheme: return resp if 'X-Deliverance-Page-Class' in response_headers: log.debug(self, "Found page class %s in headers", response_headers['X-Deliverance-Page-Class'].strip()) classes.extend(response_headers['X-Deliverance-Page-Class'].strip().split()) if 'deliverance.page_classes' in req.environ: log.debug(self, "Found page class in WSGI environ: %s", ' '.join(req.environ["deliverance.page_classes"])) classes.extend(req.environ['deliverance.page_classes']) if not classes: classes = ['default'] rules = [] theme = None for class_name in classes: ## FIXME: handle case of unknown classes ## Or do that during compilation? for rule in self.rules_by_class.get(class_name, []): if rule not in rules: rules.append(rule) if rule.theme: theme = rule.theme if theme is None: theme = self.default_theme if theme is None and default_theme is not None: theme = Theme(href=default_theme, source_location=self.source_location) if theme is None: log.error(self, "No theme has been defined for the request") return resp try: theme_href = theme.resolve_href(req, resp, log) original_theme_resp = self.get_theme_response( theme_href, resource_fetcher, log) theme_doc = self.get_theme_doc( original_theme_resp, theme_href, should_escape_cdata=True, should_fix_meta_charset_position=True) resp = force_charset(resp) body = resp.unicode_body body = escape_cdata(body) body = fix_meta_charset_position(body) content_doc = self.parse_document(body, req.url) run_standard = True for rule in rules: if rule.match is not None: matches = rule.match(req, resp, response_headers, log) if not matches: log.debug(rule, "Skipping <rule>") continue rule.apply(content_doc, theme_doc, resource_fetcher, log) if rule.suppress_standard: run_standard = False if run_standard: ## FIXME: should it be possible to put the standard rule in the ruleset? standard_rule.apply(content_doc, theme_doc, resource_fetcher, log) except AbortTheme: return resp remove_content_attribs(theme_doc) ## FIXME: handle caching? if original_theme_resp.body.strip().startswith("<!DOCTYPE"): tree = theme_doc.getroottree() else: tree = content_doc.getroottree() if "XHTML" in tree.docinfo.doctype: method = "xml" else: method = "html" theme_str = tostring(theme_doc, include_meta_content_type=True) theme_str = tree.docinfo.doctype + theme_str theme_doc = document_fromstring(theme_str) tree = theme_doc.getroottree() resp.body = tostring(tree, method=method, include_meta_content_type=True) resp.body = unescape_cdata(resp.body) return resp
def apply_rules(self, req, resp, resource_fetcher, log, default_theme=None): """ Apply the whatever the appropriate rules are to the request/response. """ extra_headers = parse_meta_headers(resp.body) if extra_headers: response_headers = ResponseHeaders(resp.headerlist + extra_headers) else: response_headers = resp.headers try: classes = run_matches(self.matchers, req, resp, response_headers, log) except AbortTheme: return resp if 'X-Deliverance-Page-Class' in response_headers: log.debug(self, "Found page class %s in headers", response_headers['X-Deliverance-Page-Class'].strip()) classes.extend(response_headers['X-Deliverance-Page-Class'].strip().split()) if 'deliverance.page_classes' in req.environ: log.debug(self, "Found page class in WSGI environ: %s", ' '.join(req.environ["deliverance.page_classes"])) classes.extend(req.environ['deliverance.page_classes']) if not classes: classes = ['default'] rules = [] theme = None for class_name in classes: ## FIXME: handle case of unknown classes ## Or do that during compilation? for rule in self.rules_by_class.get(class_name, []): if rule not in rules: rules.append(rule) if rule.theme: theme = rule.theme if theme is None: theme = self.default_theme if theme is None and default_theme is not None: theme = Theme(href=default_theme, source_location=self.source_location) if theme is None: log.error(self, "No theme has been defined for the request") return resp try: theme_href = theme.resolve_href(req, resp, log) original_theme_resp = self.get_theme_response( theme_href, resource_fetcher, log) theme_doc = self.get_theme_doc( original_theme_resp, theme_href, should_escape_cdata=True, should_fix_meta_charset_position=True) resp = force_charset(resp) body = resp.unicode_body body = escape_cdata(body) body = fix_meta_charset_position(body) content_doc = self.parse_document(body, req.url) run_standard = True for rule in rules: if rule.match is not None: matches = rule.match(req, resp, response_headers, log) if not matches: log.debug(rule, "Skipping <rule>") continue rule.apply(content_doc, theme_doc, resource_fetcher, log) if rule.suppress_standard: run_standard = False if run_standard: ## FIXME: should it be possible to put the standard rule in the ruleset? standard_rule.apply(content_doc, theme_doc, resource_fetcher, log) except AbortTheme: return resp remove_content_attribs(theme_doc) ## FIXME: handle caching? if original_theme_resp.body.strip().startswith("<!DOCTYPE"): tree = theme_doc.getroottree() else: tree = content_doc.getroottree() if "XHTML" in tree.docinfo.doctype: method = "xml" else: method = "html" theme_str = tostring(theme_doc, include_meta_content_type=True) theme_str = tree.docinfo.doctype + theme_str theme_doc = document_fromstring(theme_str) tree = theme_doc.getroottree() resp.body = tostring(tree, method=method, include_meta_content_type=True) resp.body = unescape_cdata(resp.body) return resp