Example #1
0
    def response(self, flow: http.HTTPFlow):
        response = flow.response
        if CONTENT_TYPE in response.headers:
            if any(
                    map(lambda t: t in response.headers[CONTENT_TYPE],
                        RELEVANT_CONTENT_TYPES)):
                # Response is a web page; proceed.
                insertedScripts: List[str] = []
                soup = BeautifulSoup(response.content,
                                     HTML_PARSER,
                                     from_encoding=inferEncoding(response))
                requestURL = flow.request.pretty_url  # should work in transparent mode too, unless the Host header is spoofed
                isApplicable: Callable[[Userscript],
                                       bool] = userscript.applicableChecker(
                                           requestURL)
                for script in self.userscripts:
                    if isApplicable(script):
                        useInline = ctx.options.inline or script.downloadURL is None
                        if useInline and len(script.unsafeSequences) > 0:
                            logError(unsafeSequencesMessage(script))
                            continue
                        logInfo(
                            f"""Injecting {script.name}{"" if script.version is None else " " + VERSION_PREFIX + script.version} into {requestURL} ({"inline" if useInline else "linked"}) ..."""
                        )
                        result = inject(
                            script, soup,
                            Options(
                                inline=ctx.options.inline,
                                verbose=ctx.options.verbose,
                            ))
                        if type(result) is BeautifulSoup:
                            soup = result
                            insertedScripts.append(script.name + (
                                "" if script.version is None else " " +
                                stringifyVersion(script.version)))
                        else:
                            logError(
                                "Injection failed due to the following error:")
                            logError(str(result))

                index_DTD: Optional[int] = indexOfDTD(soup)
                # Insert information comment:
                if ctx.options.verbose:
                    soup.insert(
                        0 if index_DTD is None else 1 + index_DTD,
                        Comment(INFO_COMMENT_PREFIX +
                                ("No matching userscripts for this URL."
                                 if insertedScripts ==
                                 [] else "These scripts were inserted:\n" +
                                 bulletList(insertedScripts)) + "\n"))
                # Prevent BS/html.parser from emitting `<!DOCTYPE doctype html>` or similar if "DOCTYPE" is not all uppercase in source HTML:
                if index_DTD is not None and REGEX_DOCTYPE.match(
                        soup.contents[index_DTD]):
                    # There is a DTD and it is invalid, so replace it.
                    soup.contents[index_DTD] = Doctype(
                        re.sub(REGEX_DOCTYPE, "", soup.contents[index_DTD]))
                # Serialize and encode:
                response.content = str(soup).encode(
                    fromOptional(soup.original_encoding, CHARSET_DEFAULT),
                    "replace")
Example #2
0
    def response(self, flow: http.HTTPFlow):
        response = flow.response
        if CONTENT_TYPE in response.headers:
            if any(
                    map(lambda t: t in response.headers[CONTENT_TYPE],
                        RELEVANT_CONTENT_TYPES)):
                # Response is a web page; proceed.
                insertedScripts: List[str] = []
                soup = BeautifulSoup(response.content,
                                     HTML_PARSER,
                                     from_encoding=inferEncoding(response))
                requestURL = flow.request.pretty_url  # should work in transparent mode too, unless the Host header is spoofed
                if requestContainsQueryParam(
                        option(T.option_query_param_to_disable), flow.request):
                    logInfo(
                        f"""Not injecting any userscripts into {requestURL} because it contains a `{option(T.option_query_param_to_disable)}` query parameter."""
                    )
                    return
                isApplicable: Callable[[Userscript],
                                       bool] = userscript.applicableChecker(
                                           requestURL)
                for script in self.userscripts:
                    if isApplicable(script):
                        useInline = option(
                            T.option_inline) or script.downloadURL is None
                        if useInline and len(script.unsafeSequences) > 0:
                            logError(unsafeSequencesMessage(script))
                            continue
                        logInfo(
                            f"""Injecting {script.name}{"" if script.version is None else " " + VERSION_PREFIX + script.version} into {requestURL} ({"inline" if useInline else "linked"}) ..."""
                        )
                        result = inject(
                            script, soup,
                            Options(inline=option(T.option_inline), ))
                        if type(result) is BeautifulSoup:
                            soup = result
                            insertedScripts.append(script.name + (
                                "" if script.version is None else " " +
                                T.stringifyVersion(script.version)))
                        else:
                            logError(
                                "Injection failed due to the following error:")
                            logError(str(result))

                index_DTD: Optional[int] = indexOfDTD(soup)
                # Insert information comment:
                if option(T.option_list_injected):
                    soup.insert(
                        0 if index_DTD is None else 1 + index_DTD,
                        Comment(HTML_INFO_COMMENT_PREFIX +
                                ("No matching userscripts for this URL."
                                 if insertedScripts ==
                                 [] else "These scripts were inserted:\n" +
                                 bulletList(insertedScripts)) + "\n"))
                # Serialize and encode:
                response.content = str(soup).encode(
                    fromOptional(soup.original_encoding, CHARSET_DEFAULT),
                    "replace")
Example #3
0
def insertLateIn(soup: BeautifulSoup, tag: Tag):
    fromOptional(soup.body, soup).append(tag)