Esempio n. 1
0
def test_remote_css():
    """Test that remote CSS references are flagged."""

    snippet = """
    x {foo: url(http://foo.com/bar);}
    """

    err = ErrorBundle()
    csstester.test_css_snippet(err, "x.css", snippet, 0)
    assert not err.failed()

    err = ErrorBundle()
    err.detected_type = PACKAGE_THEME
    csstester.test_css_snippet(err, "x.css", snippet, 0)
    assert err.failed()
Esempio n. 2
0
def test_remote_css():
    """Test that remote CSS references are flagged."""

    snippet = """
    x {foo: url(http://foo.com/bar);}
    """

    err = ErrorBundle()
    csstester.test_css_snippet(err, 'x.css', snippet, 0)
    assert not err.failed()

    err = ErrorBundle()
    err.detected_type = PACKAGE_THEME
    csstester.test_css_snippet(err, 'x.css', snippet, 0)
    assert err.failed()
Esempio n. 3
0
def test_remote_css_ignored():
    """Test that suspicious but innocuous css-isms are ignored."""

    snippet = """
    @namespace url(http://foo.bar/asdf);
    @namespace url("http://foo.bar/asdf");
    """

    err = ErrorBundle()
    csstester.test_css_snippet(err, "x.css", snippet, 0)
    assert not err.failed()

    err = ErrorBundle()
    err.detected_type = PACKAGE_THEME
    csstester.test_css_snippet(err, "x.css", snippet, 0)
    assert not err.failed()
Esempio n. 4
0
def test_remote_css_ignored():
    """Test that suspicious but innocuous css-isms are ignored."""

    snippet = """
    @namespace url(http://foo.bar/asdf);
    @namespace url("http://foo.bar/asdf");
    """

    err = ErrorBundle()
    csstester.test_css_snippet(err, 'x.css', snippet, 0)
    assert not err.failed()

    err = ErrorBundle()
    err.detected_type = PACKAGE_THEME
    csstester.test_css_snippet(err, 'x.css', snippet, 0)
    assert not err.failed()
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == "xul:script":
            tag = "script"

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print "S: ", self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == "xbannedxtestx":
            self.err.error(("testcases_markup_markuptester",
                            "handle_starttag",
                            "banned_element"),
                           "Banned element",
                           "A banned element was detected",
                           self.filename,
                           line=self.line,
                           context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith("xbl:"):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=("testcases_markup_markuptester",
                                "handle_starttag",
                                "unsafe_theme_xbl_element"),
                        warning="Banned XBL element in theme.",
                        description=["Certain XBL elements are disallowed in "
                                     "themes.",
                                     "Element: <xbl:%s>" % tag],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == "property" and
                      any(a[0] in (u"onset", u"onget") for a in attrs)):
                    self.err.warning(
                        err_id=("testcases_markup_markuptester",
                                "handle_starttag",
                                "theme_xbl_property"),
                        warning="Themes are not allowed to use XBL properties",
                        description="XBL properties cannot be used in themes.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)


        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or
                (self.err.detected_type == PACKAGE_THEME and
                 tag in UNSAFE_THEME_TAGS)):
                self.err.warning(("testcases_markup_markuptester",
                                  "handle_starttag",
                                  "unsafe_langpack_theme"),
                                 "Unsafe tag for add-on type",
                                 ["A tag in your markup has been marked as "
                                  "being potentially unsafe. Consider "
                                  "alternate means of accomplishing what the "
                                  "code executed by this tag performs.",
                                  'Tag "%s" is disallowed.' % tag],
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
                if DEBUG:  # pragma: no cover
                    print "Unsafe Tag ------"

            # Make sure all src/href attributes are local
            for attr in attrs:
                if attr[0].lower() in ("src", "href") and \
                   not self._is_url_local(attr[1].lower()):
                    self.err.warning(("testcases_markup_markuptester",
                                      "handle_starttag",
                                      "remote_src_href"),
                                     "src/href attributes must be local.",
                                     "Language packs require that all src and "
                                     "href attributes are relative URLs.",
                                     self.filename,
                                     line=self.line,
                                     context=self.context)
                    self.err.reject = True

        if tag in ("iframe", "browser") and self.extension == "xul":
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == "type":
                    type_ = attr[1].lower()
                elif attr_name == "src":
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and
                not (type_ in SAFE_IFRAME_TYPES or
                     not remote_src)):
                self.err.warning(("testcases_markup_markuptester",
                                  "handle_starttag",
                                  "iframe_type_unsafe"),
                                 "iframe/browser missing 'type' attribute",
                                 "All iframe and browser elements must have "
                                 "either a valid `type` attribute or a `src` "
                                 "attribute that points to a local file.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
            elif ((not type_ or
                   type_ not in SAFE_IFRAME_TYPES) and
                  remote_src):
                self.err.warning(("testcases_markup_markuptester",
                                  "handle_starttag",
                                  "iframe_type_unsafe"),
                                 "Typeless iframes/browsers must be local.",
                                 "iframe and browser elements that lack a type "
                                 "attribute must always have src attributes "
                                 "that reference local resources.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)

        elif tag == "script" and self.extension == "xul":
            # Per the Addon Validator Spec (v2), scripts in XUL
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == "src":
                    src = attr[1].lower()

            if src and not self._is_url_local(src):
                self.err.warning(("testcases_markup_markuptester",
                                  "handle_starttag",
                                  "banned_remote_scripts"),
                                 "Scripts must not be remote in XUL",
                                 "In XUL, <script> tags must not be referenced "
                                 "to script files that are hosted remotely.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]

            if (attr_name == "xmlns:xbl" and
                attr_value == "http://www.mozilla.org/xbl"):
                self.xbl = True

            if (self.err.detected_type == PACKAGE_THEME and
                attr_value.startswith(("data:", "javascript:"))):

                self.err.warning(
                        err_id=("testcases_markup_markuptester",
                                "handle_starttag",
                                "theme_attr_prefix"),
                        warning="Attribute contains banned prefix",
                        description=["A mark element's attribute contains a "
                                     "prefix which is not allowed in themes.",
                                     "Attribute: %s" % attr_name],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)


            if attr_name == "style":
                csstester.test_css_snippet(self.err,
                                           self.filename,
                                           attr_value,
                                           self.line)
            elif attr_name.startswith("on"):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=("testcases_markup_markuptester",
                                "handle_starttag",
                                "dom_manipulation_handler"),
                        warning="DOM Mutation Events Prohibited",
                        description="DOM mutation events are flagged because "
                                    "of their deprecated status, as well as "
                                    "their extreme inefficiency. Consider "
                                    "using a different event.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                scripting.test_js_snippet(err=self.err,
                                          data=attr_value,
                                          filename=self.filename,
                                          line=self.line,
                                          context=self.context)

            elif (self.extension == "xul" and
                  attr_name in ("insertbefore", "insertafter") and
                  any((id in attr[1]) for id in ("menu_pageSource",
                                                 "menu_pageinspect",
                                                 "javascriptConsole",
                                                 "webConsole"))):
                self.err.notice(
                    err_id=("testcases_markup_markuptester",
                            "handle_starttag",
                            "incompatible_menu_items"),
                    notice="Menu item has been moved",
                    description="Your add-on has an overlay that uses the "
                                "insertbefore or insertafter attribute "
                                "pointing to menuitems that have been moved "
                                "to a different menu item. Your overlay items "
                                "may appear in unexpected locations because "
                                "of this. See "
                        "https://bugzilla.mozilla.org/show_bug.cgi?id=653221"
                                " for more information.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    for_appversions={
                        "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}":
                            version_range("firefox", "6.0a1", "7.0a1")},
                    compatibility_type="warning")


        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if "script" in self.xml_state and tag != "script":
            self._save_to_buffer("<" + tag + self._format_args(attrs) + ">")
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_buffer.append(unicode(""))
Esempio n. 6
0
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == "xul:script":
            tag = "script"

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print "S: ", self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == "xbannedxtestx":
            self.err.error(err_id=("markup", "starttag", "banned_element"),
                           error="Banned markup element",
                           description="A banned markup element was found.",
                           filename=self.filename,
                           line=self.line,
                           context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith("xbl:"):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "unsafe_theme_xbl_element"),
                        warning="Banned XBL element in theme.",
                        description=[
                            "Certain XBL elements are disallowed in "
                            "full themes.",
                            "Element: <xbl:%s>" % tag
                        ],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == "property"
                      and any(a[0] in (u"onset", u"onget") for a in attrs)):
                    self.err.warning(
                        err_id=("markup", "starttag", "theme_xbl_property"),
                        warning="Themes are not allowed to use XBL properties",
                        description="XBL properties cannot be used in themes.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or (self.err.detected_type == PACKAGE_THEME
                                       and tag in UNSAFE_THEME_TAGS)):
                self.err.warning(
                    err_id=("markup", "starttag", "unsafe_langpack_theme"),
                    warning="Unsafe tag for add-on type",
                    description=[
                        "A tag in your markup has been marked as "
                        "being potentially unsafe. Consider "
                        "alternate means of accomplishing what the "
                        "code executed by this tag performs.",
                        'Tag "%s" is disallowed.' % tag
                    ],
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            # Make sure all src/href attributes are local
            if any(not self._is_url_local(attr[1]) for attr in attrs
                   if attr[0] in ("src", "href")):
                self.err.warning(
                    err_id=("markup", "starttag", "remote_src_href"),
                    warning="`src`/`href` attributes must be local.",
                    description="Full Themes and language packs may not "
                    "reference remote resources.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == "prefwindow":
            # Flag <prefwindow> elements without IDs.

            if not any((key == "id") for key, val in attrs):
                self.err.warning(
                    err_id=("markup", "starttag", "prefwindow_id"),
                    warning="`<prefwindow>` elements must have IDs.",
                    description="`<prefwindow>` elements without `id` "
                    "attributes cause errors to be reported "
                    "in the error console and prevent "
                    "persistence of certain properties of the "
                    "dialog.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        elif tag in ("iframe", "browser") and self.extension == "xul":
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == "type":
                    type_ = attr[1].lower()
                elif attr_name == "src":
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and not (type_ in SAFE_IFRAME_TYPES or not remote_src)):
                self.err.warning(("markup", "starttag", "iframe_type_unsafe"),
                                 "iframe/browser missing 'type' attribute",
                                 "All iframe and browser elements must have "
                                 "either a valid `type` attribute or a `src` "
                                 "attribute that points to a local file.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
            elif ((not type_ or type_ not in SAFE_IFRAME_TYPES)
                  and remote_src):
                self.err.warning(
                    ("markup", "starttag", "iframe_type_unsafe"),
                    "Typeless iframes/browsers must be local.",
                    "iframe and browser elements that lack a type "
                    "attribute must always have src attributes "
                    "that reference local resources.",
                    self.filename,
                    line=self.line,
                    context=self.context)

        elif tag == "script":
            # Per the Addon Validator Spec (v2), scripts
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == "src":
                    src = attr[1].lower()
                    break

            if src:
                if not self._is_url_local(src):
                    self.err.warning(
                        err_id=("markup", "starttag", "banned_remote_scripts"),
                        warning="Scripts must not be remote",
                        description="<script> tags must not be referenced to "
                        "script files that are hosted remotely.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)
                else:
                    self.found_scripts.add(src)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]

            # We don't care about valueless attributes.
            if attr_value is None:
                continue

            if (attr_name == "xmlns:xbl"
                    and attr_value == "http://www.mozilla.org/xbl"):
                self.xbl = True

            # Test that an absolute URI isn't referenced in Jetpack 1.4.
            if (self.is_jetpack and attr_value.startswith("resource://")
                    and "-data/" in attr_value):
                self.err.warning(
                    err_id=("markup", "starttag", "jetpack_abs_uri"),
                    warning="Absolute URI referenced in Jetpack 1.4",
                    description=[
                        "As of Jetpack 1.4, absolute URIs are no "
                        "longer allowed within add-ons.",
                        "See %s for more information." % JETPACK_URI_URL
                    ],
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    compatibility_type="error")

            if (self.err.detected_type == PACKAGE_THEME
                    and attr_value.startswith(("data:", "javascript:"))):

                self.err.warning(err_id=("markup", "starttag",
                                         "theme_attr_prefix"),
                                 warning="Attribute contains banned prefix",
                                 description=[
                                     "A mark element's attribute contains a "
                                     "prefix which is not allowed in full "
                                     "themes.",
                                     "Attribute: %s" % attr_name
                                 ],
                                 filename=self.filename,
                                 line=self.line,
                                 context=self.context)

            if attr_name == "style":
                csstester.test_css_snippet(self.err, self.filename, attr_value,
                                           self.line)
            elif attr_name.startswith("on"):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "dom_manipulation_handler"),
                        warning="DOM Mutation Events Prohibited",
                        description="DOM mutation events are deprecated and "
                        "have severe performance implications. "
                        "Please use mutation observers instead: "
                        "https://developer.mozilla.org/docs/Web/"
                        "API/MutationObserver",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                scripting.test_js_snippet(err=self.err,
                                          data=attr_value,
                                          filename=self.filename,
                                          line=self.line,
                                          context=self.context)

            elif (self.extension == "xul"
                  and attr_name in ("insertbefore", "insertafter") and any(
                      (id in attr_value)
                      for id in ("menu_pageSource", "menu_pageinspect",
                                 "javascriptConsole", "webConsole"))):
                self.err.notice(
                    err_id=("markup", "starttag", "incompatible_menu_items"),
                    notice="Menu item has been moved",
                    description="Your add-on has an overlay that uses the "
                    "insertbefore or insertafter attribute "
                    "pointing to menuitems that have been moved "
                    "to a different menu item. Your overlay items "
                    "may appear in unexpected locations because "
                    "of this. See https://bugzil.lz/653221 "
                    "for more information.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    for_appversions=FX6_DEFINITION,
                    compatibility_type="warning")

            # Test for generic IDs
            if attr_name == "id" and attr_value in GENERIC_IDS:
                self.err.warning(
                    err_id=("markup", "starttag", "generic_ids"),
                    warning="Overlay contains generically-named IDs",
                    description="An overlay is using a generically-named ID "
                    "that could cause compatibility problems with "
                    "other add-ons. Add-ons must namespace all IDs "
                    "in the overlay, in the same way that "
                    "JavaScript objects must be namespaced.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == "script":
            self.xml_state_scripts.append(
                any((x[0] == "type" and "javascript" not in x[1])
                    for x in attrs))

        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if "script" in self.xml_state and tag != "script":
            self._save_to_buffer("<" + tag + self._format_args(attrs) + ">")
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_buffer.append(unicode(""))
Esempio n. 7
0
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == 'xul:script':
            tag = 'script'

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print 'S: ', self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == 'xbannedxtestx':
            self.err.error(err_id=('markup', 'starttag', 'banned_element'),
                           error='Banned markup element',
                           description='A banned markup element was found.',
                           filename=self.filename,
                           line=self.line,
                           context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith('xbl:'):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'unsafe_theme_xbl_element'),
                        warning='Banned XBL element in theme.',
                        description=('Certain XBL elements are disallowed in '
                                     'full themes.',
                                     'Element: <xbl:%s>' % tag),
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == 'property'
                      and any(a[0] in (u'onset', u'onget') for a in attrs)):
                    self.err.warning(
                        err_id=('markup', 'starttag', 'theme_xbl_property'),
                        warning='Themes are not allowed to use XBL properties',
                        description='XBL properties cannot be used in themes.',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or (self.err.detected_type == PACKAGE_THEME
                                       and tag in UNSAFE_THEME_TAGS)):
                self.err.warning(
                    err_id=('markup', 'starttag', 'unsafe_langpack_theme'),
                    warning='Unsafe tag for add-on type',
                    description=('A tag in your markup has been marked as '
                                 'being potentially unsafe. Consider '
                                 'alternate means of accomplishing what the '
                                 'code executed by this tag performs.',
                                 'Tag "%s" is disallowed.' % tag),
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            # Make sure all src/href attributes are local
            if any(not self._is_url_local(attr[1]) for attr in attrs
                   if attr[0] in ('src', 'href')):
                self.err.warning(
                    err_id=('markup', 'starttag', 'remote_src_href'),
                    warning='`src`/`href` attributes must be local.',
                    description='Full Themes and language packs may not '
                    'reference remote resources.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == 'prefwindow':
            # Flag <prefwindow> elements without IDs.

            if not any((key == 'id') for key, val in attrs):
                self.err.warning(
                    err_id=('markup', 'starttag', 'prefwindow_id'),
                    warning='`<prefwindow>` elements must have IDs.',
                    description='`<prefwindow>` elements without `id` '
                    'attributes cause errors to be reported '
                    'in the error console and prevent '
                    'persistence of certain properties of the '
                    'dialog.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        elif tag in ('iframe', 'browser') and self.extension == 'xul':
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == 'type':
                    type_ = attr[1].lower()
                elif attr_name == 'src':
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and not (type_ in SAFE_IFRAME_TYPES or not remote_src)):
                self.err.warning(
                    ('markup', 'starttag', 'iframe_type_unsafe'),
                    'iframe/browser missing or unsafe `type` '
                    'attribute', 'All iframe and browser elements must have '
                    'either a valid and safe `type` attribute or a'
                    '`src` attribute that points to a local file.',
                    self.filename,
                    line=self.line,
                    context=self.context)
            elif ((not type_ or type_ not in SAFE_IFRAME_TYPES)
                  and remote_src):
                self.err.warning(
                    ('markup', 'starttag', 'iframe_type_unsafe'),
                    'Typeless iframes/browsers must be local.',
                    'iframe and browser elements that lack a type '
                    'attribute must always have src attributes '
                    'that reference local resources.',
                    self.filename,
                    line=self.line,
                    context=self.context)

        elif tag == 'script':
            # Per the Addon Validator Spec (v2), scripts
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == 'src':
                    src = attr[1].lower()
                    break

            if src:
                if not self._is_url_local(src):
                    self.err.warning(
                        err_id=('markup', 'starttag', 'banned_remote_scripts'),
                        warning='Scripts must not be remote',
                        description='<script> tags must not be referenced to '
                        'script files that are hosted remotely.',
                        signing_help='Please do not attempt to load remote '
                        'scripts into any privileged contexts. '
                        'If you cannot avoid using remote '
                        'scripts, please consider loading a '
                        'remote document into an iframe, and '
                        'allow that document to load the '
                        'remote scripts that you need.',
                        signing_severity='high',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)
                else:
                    self.found_scripts.add(src)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]

            # We don't care about valueless attributes.
            if attr_value is None:
                continue

            if (attr_name == 'xmlns:xbl'
                    and attr_value == 'http://www.mozilla.org/xbl'):
                self.xbl = True

            # Test that an absolute URI isn't referenced in Jetpack 1.4.
            if (self.is_jetpack and attr_value.startswith('resource://')
                    and '-data/' in attr_value):
                self.err.warning(
                    err_id=('markup', 'starttag', 'jetpack_abs_uri'),
                    warning='Absolute URI referenced in Jetpack 1.4',
                    description=('As of Jetpack 1.4, absolute URIs are no '
                                 'longer allowed within add-ons.',
                                 'See %s for more information.' %
                                 JETPACK_URI_URL),
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    compatibility_type='error')

            if (self.err.detected_type == PACKAGE_THEME
                    and attr_value.startswith(('data:', 'javascript:'))):

                self.err.warning(
                    err_id=('markup', 'starttag', 'theme_attr_prefix'),
                    warning='Attribute contains banned prefix',
                    description=("A mark element's attribute contains a "
                                 'prefix which is not allowed in full '
                                 'themes.', 'Attribute: %s' % attr_name),
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            if attr_name == 'style':
                csstester.test_css_snippet(self.err, self.filename, attr_value,
                                           self.line)
            elif attr_name.startswith('on'):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'dom_manipulation_handler'),
                        warning='DOM Mutation Events Prohibited',
                        description='DOM mutation events are deprecated and '
                        'have severe performance implications. '
                        'Please use mutation observers instead: '
                        'https://developer.mozilla.org/docs/Web/'
                        'API/MutationObserver',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                scripting.test_js_snippet(err=self.err,
                                          data=attr_value,
                                          filename=self.filename,
                                          line=self.line,
                                          context=self.context)

            # Test for generic IDs
            if attr_name == 'id' and attr_value in GENERIC_IDS:
                self.err.warning(
                    err_id=('markup', 'starttag', 'generic_ids'),
                    warning='Overlay contains generically-named IDs',
                    description='An overlay is using a generically-named ID '
                    'that could cause compatibility problems with '
                    'other add-ons. Add-ons must namespace all IDs '
                    'in the overlay, in the same way that '
                    'JavaScript objects must be namespaced.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == 'script':
            self.xml_state_scripts.append(
                any((x[0] == 'type' and 'javascript' not in x[1])
                    for x in attrs))

        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if 'script' in self.xml_state and tag != 'script':
            self._save_to_buffer('<' + tag + self._format_args(attrs) + '>')
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_buffer.append(unicode(''))
Esempio n. 8
0
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == "xul:script":
            tag = "script"

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print "S: ", self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == "xbannedxtestx":
            self.err.error(
                err_id=("markup", "starttag", "banned_element"),
                error="Banned markup element",
                description="A banned markup element was found.",
                filename=self.filename,
                line=self.line,
                context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith("xbl:"):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "unsafe_theme_xbl_element"),
                        warning="Banned XBL element in theme.",
                        description=["Certain XBL elements are disallowed in "
                                     "full themes.",
                                     "Element: <xbl:%s>" % tag],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == "property" and
                      any(a[0] in (u"onset", u"onget") for a in attrs)):
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "theme_xbl_property"),
                        warning="Themes are not allowed to use XBL properties",
                        description="XBL properties cannot be used in themes.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or
                (self.err.detected_type == PACKAGE_THEME and
                 tag in UNSAFE_THEME_TAGS)):
                self.err.warning(
                    err_id=("markup", "starttag", "unsafe_langpack_theme"),
                    warning="Unsafe tag for add-on type",
                    description=["A tag in your markup has been marked as "
                                 "being potentially unsafe. Consider "
                                 "alternate means of accomplishing what the "
                                 "code executed by this tag performs.",
                                 'Tag "%s" is disallowed.' % tag],
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            # Make sure all src/href attributes are local
            if any(not self._is_url_local(attr[1]) for attr in attrs if
                   attr[0] in ("src", "href")):
                self.err.warning(
                    err_id=("markup", "starttag", "remote_src_href"),
                    warning="`src`/`href` attributes must be local.",
                    description="Full Themes and language packs may not "
                                "reference remote resources.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == "prefwindow":
            # Flag <prefwindow> elements without IDs.

            if not any((key == "id") for key, val in attrs):
                self.err.warning(
                        err_id=("markup", "starttag", "prefwindow_id"),
                        warning="`<prefwindow>` elements must have IDs.",
                        description="`<prefwindow>` elements without `id` "
                                    "attributes cause errors to be reported "
                                    "in the error console and prevent "
                                    "persistence of certain properties of the "
                                    "dialog.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        elif tag in ("iframe", "browser") and self.extension == "xul":
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == "type":
                    type_ = attr[1].lower()
                elif attr_name == "src":
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and
                not (type_ in SAFE_IFRAME_TYPES or
                     not remote_src)):
                self.err.warning(("markup", "starttag", "iframe_type_unsafe"),
                                 "iframe/browser missing 'type' attribute",
                                 "All iframe and browser elements must have "
                                 "either a valid `type` attribute or a `src` "
                                 "attribute that points to a local file.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
            elif ((not type_ or
                   type_ not in SAFE_IFRAME_TYPES) and
                  remote_src):
                self.err.warning(("markup", "starttag", "iframe_type_unsafe"),
                                 "Typeless iframes/browsers must be local.",
                                 "iframe and browser elements that lack a type "
                                 "attribute must always have src attributes "
                                 "that reference local resources.",
                                 self.filename,
                                 line=self.line,
                                 context=self.context)

        elif tag == "script" and self.extension == "xul":
            # Per the Addon Validator Spec (v2), scripts in XUL
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == "src":
                    src = attr[1].lower()
                    break

            if src:
                if not self._is_url_local(src):
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "banned_remote_scripts"),
                        warning="Scripts must not be remote in XUL",
                        description="In XUL, <script> tags must not be "
                                    "referenced to script files that are "
                                    "hosted remotely.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)
                else:
                    self.found_scripts.add(src)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]

            # We don't care about valueless attributes.
            if attr_value is None:
                continue

            if (attr_name == "xmlns:xbl" and
                attr_value == "http://www.mozilla.org/xbl"):
                self.xbl = True

            # Test that an absolute URI isn't referenced in Jetpack 1.4.
            if (self.is_jetpack and
                attr_value.startswith("resource://") and
                "-data/" in attr_value):
                self.err.warning(
                        err_id=("markup", "starttag",
                                "jetpack_abs_uri"),
                        warning="Absolute URI referenced in Jetpack 1.4",
                        description=["As of Jetpack 1.4, absolute URIs are no "
                                     "longer allowed within add-ons.",
                                     "See %s for more information." %
                                         JETPACK_URI_URL],
                        filename=self.filename,
                        line=self.line,
                        context=self.context,
                        compatibility_type="error")

            if (self.err.detected_type == PACKAGE_THEME and
                attr_value.startswith(("data:", "javascript:"))):

                self.err.warning(
                        err_id=("markup", "starttag",
                                "theme_attr_prefix"),
                        warning="Attribute contains banned prefix",
                        description=["A mark element's attribute contains a "
                                     "prefix which is not allowed in full "
                                     "themes.",
                                     "Attribute: %s" % attr_name],
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

            if attr_name == "style":
                csstester.test_css_snippet(self.err,
                                           self.filename,
                                           attr_value,
                                           self.line)
            elif attr_name.startswith("on"):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=("markup", "starttag",
                                "dom_manipulation_handler"),
                        warning="DOM Mutation Events Prohibited",
                        description="DOM mutation events are flagged because "
                                    "of their deprecated status, as well as "
                                    "their extreme inefficiency. Consider "
                                    "using a different event.",
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                scripting.test_js_snippet(
                    err=self.err, data=attr_value,
                    filename=self.filename, line=self.line,
                    context=self.context)

            elif (self.extension == "xul" and
                  attr_name in ("insertbefore", "insertafter") and
                  any((id in attr_value) for id in ("menu_pageSource",
                                                    "menu_pageinspect",
                                                    "javascriptConsole",
                                                    "webConsole"))):
                self.err.notice(
                    err_id=("markup", "starttag",
                            "incompatible_menu_items"),
                    notice="Menu item has been moved",
                    description="Your add-on has an overlay that uses the "
                                "insertbefore or insertafter attribute "
                                "pointing to menuitems that have been moved "
                                "to a different menu item. Your overlay items "
                                "may appear in unexpected locations because "
                                "of this. See "
                        "https://bugzilla.mozilla.org/show_bug.cgi?id=653221"
                                " for more information.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context,
                    for_appversions=FX6_DEFINITION,
                    compatibility_type="warning")


            # Test for generic IDs
            if attr_name == "id" and attr_value in GENERIC_IDS:
                self.err.warning(
                    err_id=("markup",
                            "starttag", "generic_ids"),
                    warning="Overlay contains generically-named IDs",
                    description="An overlay is using a generically-named ID "
                                "that could cause compatibility problems with "
                                "other add-ons. Add-ons must namespace all IDs "
                                "in the overlay, in the same way that "
                                "JavaScript objects must be namespaced.",
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == "script":
            self.xml_state_scripts.append(any(
                (x[0] == "type" and "javascript" not in x[1]) for x in attrs))

        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if "script" in self.xml_state and tag != "script":
            self._save_to_buffer("<" + tag + self._format_args(attrs) + ">")
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_buffer.append(unicode(""))
def test_unprefixed_moz_calc():
    err = ErrorBundle(for_appversions=FX16_DEFINITION)
    csstester.test_css_snippet(
        err, "x.css", "x {foo: -moz-calc(40% + 100px);}", 0)
    assert err.warnings
    assert any(err.compat_summary.values())
 def test_descriptor(descriptor):
     err = ErrorBundle(for_appversions=FX16_DEFINITION)
     csstester.test_css_snippet(err, "x.css", "x {%s: 0;}" % descriptor, 0)
     assert err.warnings
     assert any(err.compat_summary.values())
def test_unprefixed_moz_calc():
    err = ErrorBundle(for_appversions=FX16_DEFINITION)
    csstester.test_css_snippet(err, "x.css",
                               "x {foo: -moz-calc(40% + 100px);}", 0)
    assert err.warnings
    assert any(err.compat_summary.values())
 def test_descriptor(descriptor):
     err = ErrorBundle(for_appversions=FX16_DEFINITION)
     csstester.test_css_snippet(err, "x.css", "x {%s: 0;}" % descriptor, 0)
     assert err.warnings
     assert any(err.compat_summary.values())
Esempio n. 13
0
    def handle_starttag(self, tag, attrs, self_closing=False):

        # Normalize!
        tag = tag.lower()
        # XUL scripts are identical to normal scripts. Treat them the same.
        if tag == 'xul:script':
            tag = 'script'

        orig_tag = tag

        # Be extra sure it's not a self-closing tag.
        if not self_closing:
            self_closing = tag in SELF_CLOSING_TAGS

        if DEBUG:  # pragma: no cover
            print 'S: ', self.xml_state, tag, self_closing

        # A fictional tag for testing purposes.
        if tag == 'xbannedxtestx':
            self.err.error(
                err_id=('markup', 'starttag', 'banned_element'),
                error='Banned markup element',
                description='A banned markup element was found.',
                filename=self.filename,
                line=self.line,
                context=self.context)

        # Test for banned XBL in themes.
        if self.err.detected_type == PACKAGE_THEME:
            if tag.startswith('xbl:'):
                self.xbl = True
                tag = tag[4:]

            # Find XBL elements.
            if self.xbl:
                if tag in UNSAFE_THEME_XBL:
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'unsafe_theme_xbl_element'),
                        warning='Banned XBL element in theme.',
                        description=('Certain XBL elements are disallowed in '
                                     'full themes.',
                                     'Element: <xbl:%s>' % tag),
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                elif (tag == 'property' and
                      any(a[0] in (u'onset', u'onget') for a in attrs)):
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'theme_xbl_property'),
                        warning='Themes are not allowed to use XBL properties',
                        description='XBL properties cannot be used in themes.',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

        # Test for banned elements in language pack and theme markup.
        if self.err.detected_type in (PACKAGE_LANGPACK, PACKAGE_THEME):
            if (tag in UNSAFE_TAGS or
                (self.err.detected_type == PACKAGE_THEME and
                 tag in UNSAFE_THEME_TAGS)):
                self.err.warning(
                    err_id=('markup', 'starttag', 'unsafe_langpack_theme'),
                    warning='Unsafe tag for add-on type',
                    description=('A tag in your markup has been marked as '
                                 'being potentially unsafe. Consider '
                                 'alternate means of accomplishing what the '
                                 'code executed by this tag performs.',
                                 'Tag "%s" is disallowed.' % tag),
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            # Make sure all src/href attributes are local
            if any(not self._is_url_local(attr[1]) for attr in attrs if
                   attr[0] in ('src', 'href')):
                self.err.warning(
                    err_id=('markup', 'starttag', 'remote_src_href'),
                    warning='`src`/`href` attributes must be local.',
                    description='Full Themes and language packs may not '
                                'reference remote resources.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == 'prefwindow':
            # Flag <prefwindow> elements without IDs.

            if not any((key == 'id') for key, val, pos in attrs):
                self.err.warning(
                    err_id=('markup', 'starttag', 'prefwindow_id'),
                    warning='`<prefwindow>` elements must have IDs.',
                    description='`<prefwindow>` elements without `id` '
                                'attributes cause errors to be reported '
                                'in the error console and prevent '
                                'persistence of certain properties of the '
                                'dialog.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        elif tag in ('iframe', 'browser') and self.extension == 'xul':
            # Bork if XUL iframe has no type attribute

            type_ = None
            src = None
            for attr in attrs:
                attr_name = attr[0].lower()
                if attr_name == 'type':
                    type_ = attr[1].lower()
                elif attr_name == 'src':
                    src = attr[1].lower()

            # We say it's true by default to catch elements that are
            # type="chrome" without an src="" attribute.
            remote_src = True
            if isinstance(src, types.StringTypes):
                remote_src = not self._is_url_local(src)

            if (type_ and
                not (type_ in SAFE_IFRAME_TYPES or
                     not remote_src)):
                self.err.warning(('markup', 'starttag', 'iframe_type_unsafe'),
                                 "iframe/browser missing 'type' attribute",
                                 'All iframe and browser elements must have '
                                 'either a valid `type` attribute or a `src` '
                                 'attribute that points to a local file.',
                                 self.filename,
                                 line=self.line,
                                 context=self.context)
            elif ((not type_ or
                   type_ not in SAFE_IFRAME_TYPES) and
                  remote_src):
                self.err.warning(('markup', 'starttag', 'iframe_type_unsafe'),
                                 'Typeless iframes/browsers must be local.',
                                 'iframe and browser elements that lack a '
                                 'type attribute must always have src '
                                 'attributes that reference local resources.',
                                 self.filename,
                                 line=self.line,
                                 context=self.context)

        elif tag == 'script':
            # Per the Addon Validator Spec (v2), scripts
            # must not be remote.

            src = None
            for attr in attrs:
                if attr[0].lower() == 'src':
                    src = attr[1].lower()
                    break

            if src:
                if not self._is_url_local(src):
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'banned_remote_scripts'),
                        warning='Scripts must not be remote',
                        description='<script> tags must not be referenced to '
                                    'script files that are hosted remotely.',
                        signing_help='Please do not attempt to load remote '
                                     'scripts into any privileged contexts. '
                                     'If you cannot avoid using remote '
                                     'scripts, please consider loading a '
                                     'remote document into an iframe, and '
                                     'allow that document to load the '
                                     'remote scripts that you need.',
                        signing_severity='high',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)
                else:
                    self.err.add_script_load(self.filename, src)
                    self.found_scripts.add(src)

        # Find CSS and JS attributes and handle their values like they
        # would otherwise be handled by the standard parser flow.
        for attr in attrs:
            attr_name, attr_value = attr[0].lower(), attr[1]
            position = attr[2]

            # We don't care about valueless attributes.
            if attr_value is None:
                continue

            if (attr_name == 'xmlns:xbl' and
                    attr_value == 'http://www.mozilla.org/xbl'):
                self.xbl = True

            if (self.err.detected_type == PACKAGE_THEME and
                    attr_value.startswith(('data:', 'javascript:'))):

                self.err.warning(
                    err_id=('markup', 'starttag',
                            'theme_attr_prefix'),
                    warning='Attribute contains banned prefix',
                    description=("A mark element's attribute contains a "
                                 'prefix which is not allowed in full '
                                 'themes.',
                                 'Attribute: %s' % attr_name),
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

            if attr_name == 'style':
                csstester.test_css_snippet(self.err,
                                           self.filename,
                                           attr_value,
                                           self.line)
            elif attr_name.startswith('on'):  # JS attribute
                # Warn about DOM mutation event handlers.
                if attr_name in DOM_MUTATION_HANDLERS:
                    self.err.warning(
                        err_id=('markup', 'starttag',
                                'dom_manipulation_handler'),
                        warning='DOM Mutation Events Prohibited',
                        description='DOM mutation events are deprecated and '
                                    'have severe performance implications. '
                                    'Please use mutation observers instead: '
                                    'https://developer.mozilla.org/docs/Web/'
                                    'API/MutationObserver',
                        filename=self.filename,
                        line=self.line,
                        context=self.context)

                self.err.add_script_load(self.filename, self.filename)
                scripting.test_js_snippet(
                    err=self.err, data=attr_value,
                    filename=self.filename, line=position[0],
                    column=position[1], context=self.context)

            # Test for generic IDs
            if attr_name == 'id' and attr_value in GENERIC_IDS:
                self.err.warning(
                    err_id=('markup',
                            'starttag', 'generic_ids'),
                    warning='Overlay contains generically-named IDs',
                    description='An overlay is using a generically-named ID '
                                'that could cause compatibility problems with '
                                'other add-ons. Add-ons must namespace all '
                                'IDs in the overlay, in the same way that '
                                'JavaScript objects must be namespaced.',
                    filename=self.filename,
                    line=self.line,
                    context=self.context)

        if tag == 'script':
            self.xml_state_scripts.append(any(
                (x[0] == 'type' and 'javascript' not in x[1]) for x in attrs))

        # When the dev forgets their <!-- --> on a script tag, bad
        # things happen.
        if 'script' in self.xml_state and tag != 'script':
            self._save_to_buffer('<' + tag + self._format_args(attrs) + '>')
            return

        self.xml_state.append(orig_tag)
        self.xml_line_stack.append(self.line)
        self.xml_position_stack.append(None)
        self.xml_buffer.append(unicode(''))
Esempio n. 14
0
 def handle_starttag(self, tag, attrs, self_closing=False):
     
     # Normalize!
     tag = tag.lower()
     
     # Be extra sure it's not a self-closing tag.
     if not self_closing:
         self_closing = tag in SELF_CLOSING_TAGS
     
     if DEBUG: # pragma: no cover
         print self.xml_state, tag, self_closing
     
     # A fictional tag for testing purposes.
     if tag == "xbannedxtestx":
         self.err.error(("testcases_markup_markuptester",
                         "handle_starttag",
                         "banned_element"),
                        "Banned element",
                        "A banned element was detected",
                        self.filename,
                        line=self.line,
                        context=self.context)
     
     if self.err.detected_type == PACKAGE_LANGPACK:
         
         if tag in UNSAFE_TAGS:
             self.err.warning(("testcases_markup_markuptester",
                               "handle_starttag",
                               "unsafe_langpack"),
                              "Unsafe tag in language pack",
                              ["""A tag in your markup has been marked
                               as being potentially unsafe. Consider
                               alternate means of accomplishing what
                               the code executed by this tag
                               performs.""",
                               'Tag "%s" is disallowed.' % tag],
                              self.filename,
                              line=self.line,
                              context=self.context)
             if DEBUG: # pragma: no cover
                 print "Unsafe Tag ------"
         
         # Make sure all src/href attributes are local
         for attr in attrs:
             if attr[0].lower() in ("src", "href") and \
                not self._is_url_local(attr[1].lower()):
                 self.err.warning(("testcases_markup_markuptester",
                                   "handle_starttag",
                                   "remote_src_href"),
                                  "src/href attributes must be local.",
                                  "Language packs require that all src and "
                                  "href attributes are relative URLs.",
                                  self.filename,
                                  line=self.line,
                                  context=self.context)
                 self.err.reject = True
     
     if tag in ("iframe", "browser") and self.extension == "xul":
         # Bork if XUL iframe has no type attribute
         
         type_ = None
         src = None
         for attr in attrs:
             attr_name = attr[0].lower()
             if attr_name == "type":
                 type_ = attr[1].lower()
             elif attr_name == "src":
                 src = attr[1].lower()
         
         # We say it's true by default to catch elements that are
         # type="chrome" without an src="" attribute.
         remote_src = True
         if isinstance(src, str):
             remote_src = not self._is_url_local(src)
             
         if type_ and \
            not (type_ in SAFE_IFRAME_TYPES or 
                 not remote_src):
             self.err.warning(("testcases_markup_markuptester",
                               "handle_starttag",
                               "iframe_type_unsafe"),
                              "iframe/browser missing 'type' attribute",
                              """All iframe and browser elements must have
                              either a valid `type` attribute or a `src`
                              attribute that points to a local file.""",
                              self.filename,
                              line=self.line,
                              context=self.context)
         elif (not type_ or 
               type_ not in SAFE_IFRAME_TYPES) and \
              remote_src:
             self.err.warning(("testcases_markup_markuptester",
                               "handle_starttag",
                               "iframe_type_unsafe"),
                              "Typeless iframes/browsers must be local.",
                              """iframe and browser elements that lack a
                              type attribute must always have src
                              attributes that reference local
                              resources.""",
                              self.filename,
                              line=self.line,
                              context=self.context)
         
     elif tag == "script" and self.extension == "xul":
         # Per the Addon Validator Spec (v2), scripts in XUL
         # must not be remote.
         
         src = None
         for attr in attrs:
             if attr[0].lower() == "src":
                 src = attr[1].lower()
         
         if src and not self._is_url_local(src):
             self.err.warning(("testcases_markup_markuptester",
                               "handle_starttag",
                               "banned_remote_scripts"),
                              "Scripts must not be remote in XUL",
                              """In XUL, <script> tags must not be
                              referenced to script files that are
                              hosted remotely.""",
                              self.filename,
                              line=self.line,
                              context=self.context)
     
     # Find CSS and JS attributes and handle their values like they
     # would otherwise be handled by the standard parser flow.
     for attr in attrs:
         attr_name = attr[0].lower()
         if attr_name == "style":
             csstester.test_css_snippet(self.err,
                                        self.filename,
                                        attr[1],
                                        self.line)
         elif attr_name.startswith("on"): # JS attribute
             scripting.test_js_snippet(err=self.err,
                                       data=attr[1],
                                       filename=self.filename)
     
     # When the dev forgets their <!-- --> on a script tag, bad
     # things happen.
     if "script" in self.xml_state and tag != "script":
         self._save_to_buffer("<" + tag + self._format_args(attrs) + ">")
         return
     
     self.xml_state.append(tag)
     self.xml_buffer.append("")