Bug 1750871 - run mochitest-remote on fission everywhere. r=releng-reviewers,aki
[gecko.git] / dom / base / nsTreeSanitizer.cpp
blob86e97586c4dbdd2383d7072f612939bf9a18aaa5
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsTreeSanitizer.h"
9 #include "mozilla/Algorithm.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/BindingStyleRule.h"
12 #include "mozilla/DeclarationBlock.h"
13 #include "mozilla/StyleSheetInlines.h"
14 #include "mozilla/UniquePtr.h"
15 #include "mozilla/css/Rule.h"
16 #include "mozilla/dom/SanitizerBinding.h"
17 #include "mozilla/dom/CSSRuleList.h"
18 #include "mozilla/dom/DocumentFragment.h"
19 #include "mozilla/dom/HTMLTemplateElement.h"
20 #include "mozilla/dom/SRIMetadata.h"
21 #include "mozilla/NullPrincipal.h"
22 #include "nsAtom.h"
23 #include "nsCSSPropertyID.h"
24 #include "nsHashtablesFwd.h"
25 #include "nsString.h"
26 #include "nsTHashtable.h"
27 #include "nsUnicharInputStream.h"
28 #include "nsAttrName.h"
29 #include "nsIScriptError.h"
30 #include "nsIScriptSecurityManager.h"
31 #include "nsNetUtil.h"
32 #include "nsComponentManagerUtils.h"
33 #include "nsContentUtils.h"
34 #include "nsIParserUtils.h"
35 #include "mozilla/dom/Document.h"
36 #include "nsQueryObject.h"
38 #include <iterator>
40 using namespace mozilla;
41 using namespace mozilla::dom;
44 // Thanks to Mark Pilgrim and Sam Ruby for the initial whitelist
46 const nsStaticAtom* const kElementsHTML[] = {
47 // clang-format off
48 nsGkAtoms::a,
49 nsGkAtoms::abbr,
50 nsGkAtoms::acronym,
51 nsGkAtoms::address,
52 nsGkAtoms::area,
53 nsGkAtoms::article,
54 nsGkAtoms::aside,
55 nsGkAtoms::audio,
56 nsGkAtoms::b,
57 nsGkAtoms::bdi,
58 nsGkAtoms::bdo,
59 nsGkAtoms::big,
60 nsGkAtoms::blockquote,
61 // body checked specially
62 nsGkAtoms::br,
63 nsGkAtoms::button,
64 nsGkAtoms::canvas,
65 nsGkAtoms::caption,
66 nsGkAtoms::center,
67 nsGkAtoms::cite,
68 nsGkAtoms::code,
69 nsGkAtoms::col,
70 nsGkAtoms::colgroup,
71 nsGkAtoms::data,
72 nsGkAtoms::datalist,
73 nsGkAtoms::dd,
74 nsGkAtoms::del,
75 nsGkAtoms::details,
76 nsGkAtoms::dfn,
77 nsGkAtoms::dialog,
78 nsGkAtoms::dir,
79 nsGkAtoms::div,
80 nsGkAtoms::dl,
81 nsGkAtoms::dt,
82 nsGkAtoms::em,
83 nsGkAtoms::fieldset,
84 nsGkAtoms::figcaption,
85 nsGkAtoms::figure,
86 nsGkAtoms::font,
87 nsGkAtoms::footer,
88 nsGkAtoms::form,
89 nsGkAtoms::h1,
90 nsGkAtoms::h2,
91 nsGkAtoms::h3,
92 nsGkAtoms::h4,
93 nsGkAtoms::h5,
94 nsGkAtoms::h6,
95 // head checked specially
96 nsGkAtoms::header,
97 nsGkAtoms::hgroup,
98 nsGkAtoms::hr,
99 // html checked specially
100 nsGkAtoms::i,
101 nsGkAtoms::img,
102 nsGkAtoms::input,
103 nsGkAtoms::ins,
104 nsGkAtoms::kbd,
105 nsGkAtoms::keygen,
106 nsGkAtoms::label,
107 nsGkAtoms::legend,
108 nsGkAtoms::li,
109 nsGkAtoms::link,
110 nsGkAtoms::listing,
111 nsGkAtoms::main,
112 nsGkAtoms::map,
113 nsGkAtoms::mark,
114 nsGkAtoms::menu,
115 nsGkAtoms::meta,
116 nsGkAtoms::meter,
117 nsGkAtoms::nav,
118 nsGkAtoms::nobr,
119 nsGkAtoms::noscript,
120 nsGkAtoms::ol,
121 nsGkAtoms::optgroup,
122 nsGkAtoms::option,
123 nsGkAtoms::output,
124 nsGkAtoms::p,
125 nsGkAtoms::picture,
126 nsGkAtoms::pre,
127 nsGkAtoms::progress,
128 nsGkAtoms::q,
129 nsGkAtoms::rb,
130 nsGkAtoms::rp,
131 nsGkAtoms::rt,
132 nsGkAtoms::rtc,
133 nsGkAtoms::ruby,
134 nsGkAtoms::s,
135 nsGkAtoms::samp,
136 nsGkAtoms::section,
137 nsGkAtoms::select,
138 nsGkAtoms::small,
139 nsGkAtoms::source,
140 nsGkAtoms::span,
141 nsGkAtoms::strike,
142 nsGkAtoms::strong,
143 nsGkAtoms::sub,
144 nsGkAtoms::summary,
145 nsGkAtoms::sup,
146 // style checked specially
147 nsGkAtoms::table,
148 nsGkAtoms::tbody,
149 nsGkAtoms::td,
150 // template checked and traversed specially
151 nsGkAtoms::textarea,
152 nsGkAtoms::tfoot,
153 nsGkAtoms::th,
154 nsGkAtoms::thead,
155 nsGkAtoms::time,
156 // title checked specially
157 nsGkAtoms::tr,
158 nsGkAtoms::track,
159 nsGkAtoms::tt,
160 nsGkAtoms::u,
161 nsGkAtoms::ul,
162 nsGkAtoms::var,
163 nsGkAtoms::video,
164 nsGkAtoms::wbr,
165 nullptr
166 // clang-format on
169 const nsStaticAtom* const kAttributesHTML[] = {
170 // clang-format off
171 nsGkAtoms::abbr,
172 nsGkAtoms::accept,
173 nsGkAtoms::acceptcharset,
174 nsGkAtoms::accesskey,
175 nsGkAtoms::action,
176 nsGkAtoms::alt,
177 nsGkAtoms::as,
178 nsGkAtoms::autocomplete,
179 nsGkAtoms::autofocus,
180 nsGkAtoms::autoplay,
181 nsGkAtoms::axis,
182 nsGkAtoms::_char,
183 nsGkAtoms::charoff,
184 nsGkAtoms::charset,
185 nsGkAtoms::checked,
186 nsGkAtoms::cite,
187 nsGkAtoms::_class,
188 nsGkAtoms::cols,
189 nsGkAtoms::colspan,
190 nsGkAtoms::content,
191 nsGkAtoms::contenteditable,
192 nsGkAtoms::contextmenu,
193 nsGkAtoms::controls,
194 nsGkAtoms::coords,
195 nsGkAtoms::crossorigin,
196 nsGkAtoms::datetime,
197 nsGkAtoms::dir,
198 nsGkAtoms::disabled,
199 nsGkAtoms::draggable,
200 nsGkAtoms::enctype,
201 nsGkAtoms::face,
202 nsGkAtoms::_for,
203 nsGkAtoms::frame,
204 nsGkAtoms::headers,
205 nsGkAtoms::height,
206 nsGkAtoms::hidden,
207 nsGkAtoms::high,
208 nsGkAtoms::href,
209 nsGkAtoms::hreflang,
210 nsGkAtoms::icon,
211 nsGkAtoms::id,
212 nsGkAtoms::integrity,
213 nsGkAtoms::ismap,
214 nsGkAtoms::itemid,
215 nsGkAtoms::itemprop,
216 nsGkAtoms::itemref,
217 nsGkAtoms::itemscope,
218 nsGkAtoms::itemtype,
219 nsGkAtoms::kind,
220 nsGkAtoms::label,
221 nsGkAtoms::lang,
222 nsGkAtoms::list_,
223 nsGkAtoms::longdesc,
224 nsGkAtoms::loop,
225 nsGkAtoms::low,
226 nsGkAtoms::max,
227 nsGkAtoms::maxlength,
228 nsGkAtoms::media,
229 nsGkAtoms::method,
230 nsGkAtoms::min,
231 nsGkAtoms::minlength,
232 nsGkAtoms::multiple,
233 nsGkAtoms::muted,
234 nsGkAtoms::name,
235 nsGkAtoms::nohref,
236 nsGkAtoms::novalidate,
237 nsGkAtoms::nowrap,
238 nsGkAtoms::open,
239 nsGkAtoms::optimum,
240 nsGkAtoms::pattern,
241 nsGkAtoms::placeholder,
242 nsGkAtoms::playbackrate,
243 nsGkAtoms::poster,
244 nsGkAtoms::preload,
245 nsGkAtoms::prompt,
246 nsGkAtoms::pubdate,
247 nsGkAtoms::radiogroup,
248 nsGkAtoms::readonly,
249 nsGkAtoms::rel,
250 nsGkAtoms::required,
251 nsGkAtoms::rev,
252 nsGkAtoms::reversed,
253 nsGkAtoms::role,
254 nsGkAtoms::rows,
255 nsGkAtoms::rowspan,
256 nsGkAtoms::rules,
257 nsGkAtoms::scoped,
258 nsGkAtoms::scope,
259 nsGkAtoms::selected,
260 nsGkAtoms::shape,
261 nsGkAtoms::span,
262 nsGkAtoms::spellcheck,
263 nsGkAtoms::src,
264 nsGkAtoms::srclang,
265 nsGkAtoms::start,
266 nsGkAtoms::summary,
267 nsGkAtoms::tabindex,
268 nsGkAtoms::target,
269 nsGkAtoms::title,
270 nsGkAtoms::type,
271 nsGkAtoms::usemap,
272 nsGkAtoms::value,
273 nsGkAtoms::width,
274 nsGkAtoms::wrap,
275 nullptr
276 // clang-format on
279 const nsStaticAtom* const kPresAttributesHTML[] = {
280 // clang-format off
281 nsGkAtoms::align,
282 nsGkAtoms::background,
283 nsGkAtoms::bgcolor,
284 nsGkAtoms::border,
285 nsGkAtoms::cellpadding,
286 nsGkAtoms::cellspacing,
287 nsGkAtoms::color,
288 nsGkAtoms::compact,
289 nsGkAtoms::clear,
290 nsGkAtoms::hspace,
291 nsGkAtoms::noshade,
292 nsGkAtoms::pointSize,
293 nsGkAtoms::size,
294 nsGkAtoms::valign,
295 nsGkAtoms::vspace,
296 nullptr
297 // clang-format on
300 // List of HTML attributes with URLs that the
301 // browser will fetch. Should be kept in sync with
302 // https://html.spec.whatwg.org/multipage/indices.html#attributes-3
303 const nsStaticAtom* const kURLAttributesHTML[] = {
304 // clang-format off
305 nsGkAtoms::action,
306 nsGkAtoms::href,
307 nsGkAtoms::src,
308 nsGkAtoms::longdesc,
309 nsGkAtoms::cite,
310 nsGkAtoms::background,
311 nsGkAtoms::formaction,
312 nsGkAtoms::data,
313 nsGkAtoms::ping,
314 nsGkAtoms::poster,
315 nullptr
316 // clang-format on
319 const nsStaticAtom* const kElementsSVG[] = {
320 nsGkAtoms::a, // a
321 nsGkAtoms::circle, // circle
322 nsGkAtoms::clipPath, // clipPath
323 nsGkAtoms::colorProfile, // color-profile
324 nsGkAtoms::cursor, // cursor
325 nsGkAtoms::defs, // defs
326 nsGkAtoms::desc, // desc
327 nsGkAtoms::ellipse, // ellipse
328 nsGkAtoms::elevation, // elevation
329 nsGkAtoms::erode, // erode
330 nsGkAtoms::ex, // ex
331 nsGkAtoms::exact, // exact
332 nsGkAtoms::exponent, // exponent
333 nsGkAtoms::feBlend, // feBlend
334 nsGkAtoms::feColorMatrix, // feColorMatrix
335 nsGkAtoms::feComponentTransfer, // feComponentTransfer
336 nsGkAtoms::feComposite, // feComposite
337 nsGkAtoms::feConvolveMatrix, // feConvolveMatrix
338 nsGkAtoms::feDiffuseLighting, // feDiffuseLighting
339 nsGkAtoms::feDisplacementMap, // feDisplacementMap
340 nsGkAtoms::feDistantLight, // feDistantLight
341 nsGkAtoms::feDropShadow, // feDropShadow
342 nsGkAtoms::feFlood, // feFlood
343 nsGkAtoms::feFuncA, // feFuncA
344 nsGkAtoms::feFuncB, // feFuncB
345 nsGkAtoms::feFuncG, // feFuncG
346 nsGkAtoms::feFuncR, // feFuncR
347 nsGkAtoms::feGaussianBlur, // feGaussianBlur
348 nsGkAtoms::feImage, // feImage
349 nsGkAtoms::feMerge, // feMerge
350 nsGkAtoms::feMergeNode, // feMergeNode
351 nsGkAtoms::feMorphology, // feMorphology
352 nsGkAtoms::feOffset, // feOffset
353 nsGkAtoms::fePointLight, // fePointLight
354 nsGkAtoms::feSpecularLighting, // feSpecularLighting
355 nsGkAtoms::feSpotLight, // feSpotLight
356 nsGkAtoms::feTile, // feTile
357 nsGkAtoms::feTurbulence, // feTurbulence
358 nsGkAtoms::filter, // filter
359 nsGkAtoms::font, // font
360 nsGkAtoms::font_face, // font-face
361 nsGkAtoms::font_face_format, // font-face-format
362 nsGkAtoms::font_face_name, // font-face-name
363 nsGkAtoms::font_face_src, // font-face-src
364 nsGkAtoms::font_face_uri, // font-face-uri
365 nsGkAtoms::foreignObject, // foreignObject
366 nsGkAtoms::g, // g
367 // glyph
368 nsGkAtoms::glyphRef, // glyphRef
369 // hkern
370 nsGkAtoms::image, // image
371 nsGkAtoms::line, // line
372 nsGkAtoms::linearGradient, // linearGradient
373 nsGkAtoms::marker, // marker
374 nsGkAtoms::mask, // mask
375 nsGkAtoms::metadata, // metadata
376 nsGkAtoms::missingGlyph, // missingGlyph
377 nsGkAtoms::mpath, // mpath
378 nsGkAtoms::path, // path
379 nsGkAtoms::pattern, // pattern
380 nsGkAtoms::polygon, // polygon
381 nsGkAtoms::polyline, // polyline
382 nsGkAtoms::radialGradient, // radialGradient
383 nsGkAtoms::rect, // rect
384 nsGkAtoms::stop, // stop
385 nsGkAtoms::svg, // svg
386 nsGkAtoms::svgSwitch, // switch
387 nsGkAtoms::symbol, // symbol
388 nsGkAtoms::text, // text
389 nsGkAtoms::textPath, // textPath
390 nsGkAtoms::title, // title
391 nsGkAtoms::tref, // tref
392 nsGkAtoms::tspan, // tspan
393 nsGkAtoms::use, // use
394 nsGkAtoms::view, // view
395 // vkern
396 nullptr};
398 constexpr const nsStaticAtom* const kAttributesSVG[] = {
399 // accent-height
400 nsGkAtoms::accumulate, // accumulate
401 nsGkAtoms::additive, // additive
402 nsGkAtoms::alignment_baseline, // alignment-baseline
403 // alphabetic
404 nsGkAtoms::amplitude, // amplitude
405 // arabic-form
406 // ascent
407 nsGkAtoms::attributeName, // attributeName
408 nsGkAtoms::attributeType, // attributeType
409 nsGkAtoms::azimuth, // azimuth
410 nsGkAtoms::baseFrequency, // baseFrequency
411 nsGkAtoms::baseline_shift, // baseline-shift
412 // baseProfile
413 // bbox
414 nsGkAtoms::begin, // begin
415 nsGkAtoms::bias, // bias
416 nsGkAtoms::by, // by
417 nsGkAtoms::calcMode, // calcMode
418 // cap-height
419 nsGkAtoms::_class, // class
420 nsGkAtoms::clip_path, // clip-path
421 nsGkAtoms::clip_rule, // clip-rule
422 nsGkAtoms::clipPathUnits, // clipPathUnits
423 nsGkAtoms::color, // color
424 nsGkAtoms::colorInterpolation, // color-interpolation
425 nsGkAtoms::colorInterpolationFilters, // color-interpolation-filters
426 nsGkAtoms::cursor, // cursor
427 nsGkAtoms::cx, // cx
428 nsGkAtoms::cy, // cy
429 nsGkAtoms::d, // d
430 // descent
431 nsGkAtoms::diffuseConstant, // diffuseConstant
432 nsGkAtoms::direction, // direction
433 nsGkAtoms::display, // display
434 nsGkAtoms::divisor, // divisor
435 nsGkAtoms::dominant_baseline, // dominant-baseline
436 nsGkAtoms::dur, // dur
437 nsGkAtoms::dx, // dx
438 nsGkAtoms::dy, // dy
439 nsGkAtoms::edgeMode, // edgeMode
440 nsGkAtoms::elevation, // elevation
441 // enable-background
442 nsGkAtoms::end, // end
443 nsGkAtoms::fill, // fill
444 nsGkAtoms::fill_opacity, // fill-opacity
445 nsGkAtoms::fill_rule, // fill-rule
446 nsGkAtoms::filter, // filter
447 nsGkAtoms::filterUnits, // filterUnits
448 nsGkAtoms::flood_color, // flood-color
449 nsGkAtoms::flood_opacity, // flood-opacity
450 // XXX focusable
451 nsGkAtoms::font, // font
452 nsGkAtoms::font_family, // font-family
453 nsGkAtoms::font_size, // font-size
454 nsGkAtoms::font_size_adjust, // font-size-adjust
455 nsGkAtoms::font_stretch, // font-stretch
456 nsGkAtoms::font_style, // font-style
457 nsGkAtoms::font_variant, // font-variant
458 nsGkAtoms::fontWeight, // font-weight
459 nsGkAtoms::format, // format
460 nsGkAtoms::from, // from
461 nsGkAtoms::fx, // fx
462 nsGkAtoms::fy, // fy
463 // g1
464 // g2
465 // glyph-name
466 // glyphRef
467 // glyph-orientation-horizontal
468 // glyph-orientation-vertical
469 nsGkAtoms::gradientTransform, // gradientTransform
470 nsGkAtoms::gradientUnits, // gradientUnits
471 nsGkAtoms::height, // height
472 nsGkAtoms::href,
473 // horiz-adv-x
474 // horiz-origin-x
475 // horiz-origin-y
476 nsGkAtoms::id, // id
477 // ideographic
478 nsGkAtoms::image_rendering, // image-rendering
479 nsGkAtoms::in, // in
480 nsGkAtoms::in2, // in2
481 nsGkAtoms::intercept, // intercept
482 // k
483 nsGkAtoms::k1, // k1
484 nsGkAtoms::k2, // k2
485 nsGkAtoms::k3, // k3
486 nsGkAtoms::k4, // k4
487 // kerning
488 nsGkAtoms::kernelMatrix, // kernelMatrix
489 nsGkAtoms::kernelUnitLength, // kernelUnitLength
490 nsGkAtoms::keyPoints, // keyPoints
491 nsGkAtoms::keySplines, // keySplines
492 nsGkAtoms::keyTimes, // keyTimes
493 nsGkAtoms::lang, // lang
494 // lengthAdjust
495 nsGkAtoms::letter_spacing, // letter-spacing
496 nsGkAtoms::lighting_color, // lighting-color
497 nsGkAtoms::limitingConeAngle, // limitingConeAngle
498 // local
499 nsGkAtoms::marker, // marker
500 nsGkAtoms::marker_end, // marker-end
501 nsGkAtoms::marker_mid, // marker-mid
502 nsGkAtoms::marker_start, // marker-start
503 nsGkAtoms::markerHeight, // markerHeight
504 nsGkAtoms::markerUnits, // markerUnits
505 nsGkAtoms::markerWidth, // markerWidth
506 nsGkAtoms::mask, // mask
507 nsGkAtoms::maskContentUnits, // maskContentUnits
508 nsGkAtoms::maskUnits, // maskUnits
509 // mathematical
510 nsGkAtoms::max, // max
511 nsGkAtoms::media, // media
512 nsGkAtoms::method, // method
513 nsGkAtoms::min, // min
514 nsGkAtoms::mode, // mode
515 nsGkAtoms::name, // name
516 nsGkAtoms::numOctaves, // numOctaves
517 nsGkAtoms::offset, // offset
518 nsGkAtoms::opacity, // opacity
519 nsGkAtoms::_operator, // operator
520 nsGkAtoms::order, // order
521 nsGkAtoms::orient, // orient
522 nsGkAtoms::orientation, // orientation
523 // origin
524 // overline-position
525 // overline-thickness
526 nsGkAtoms::overflow, // overflow
527 // panose-1
528 nsGkAtoms::path, // path
529 nsGkAtoms::pathLength, // pathLength
530 nsGkAtoms::patternContentUnits, // patternContentUnits
531 nsGkAtoms::patternTransform, // patternTransform
532 nsGkAtoms::patternUnits, // patternUnits
533 nsGkAtoms::pointer_events, // pointer-events XXX is this safe?
534 nsGkAtoms::points, // points
535 nsGkAtoms::pointsAtX, // pointsAtX
536 nsGkAtoms::pointsAtY, // pointsAtY
537 nsGkAtoms::pointsAtZ, // pointsAtZ
538 nsGkAtoms::preserveAlpha, // preserveAlpha
539 nsGkAtoms::preserveAspectRatio, // preserveAspectRatio
540 nsGkAtoms::primitiveUnits, // primitiveUnits
541 nsGkAtoms::r, // r
542 nsGkAtoms::radius, // radius
543 nsGkAtoms::refX, // refX
544 nsGkAtoms::refY, // refY
545 nsGkAtoms::repeatCount, // repeatCount
546 nsGkAtoms::repeatDur, // repeatDur
547 nsGkAtoms::requiredExtensions, // requiredExtensions
548 nsGkAtoms::requiredFeatures, // requiredFeatures
549 nsGkAtoms::restart, // restart
550 nsGkAtoms::result, // result
551 nsGkAtoms::rotate, // rotate
552 nsGkAtoms::rx, // rx
553 nsGkAtoms::ry, // ry
554 nsGkAtoms::scale, // scale
555 nsGkAtoms::seed, // seed
556 nsGkAtoms::shape_rendering, // shape-rendering
557 nsGkAtoms::slope, // slope
558 nsGkAtoms::spacing, // spacing
559 nsGkAtoms::specularConstant, // specularConstant
560 nsGkAtoms::specularExponent, // specularExponent
561 nsGkAtoms::spreadMethod, // spreadMethod
562 nsGkAtoms::startOffset, // startOffset
563 nsGkAtoms::stdDeviation, // stdDeviation
564 // stemh
565 // stemv
566 nsGkAtoms::stitchTiles, // stitchTiles
567 nsGkAtoms::stop_color, // stop-color
568 nsGkAtoms::stop_opacity, // stop-opacity
569 // strikethrough-position
570 // strikethrough-thickness
571 nsGkAtoms::string, // string
572 nsGkAtoms::stroke, // stroke
573 nsGkAtoms::stroke_dasharray, // stroke-dasharray
574 nsGkAtoms::stroke_dashoffset, // stroke-dashoffset
575 nsGkAtoms::stroke_linecap, // stroke-linecap
576 nsGkAtoms::stroke_linejoin, // stroke-linejoin
577 nsGkAtoms::stroke_miterlimit, // stroke-miterlimit
578 nsGkAtoms::stroke_opacity, // stroke-opacity
579 nsGkAtoms::stroke_width, // stroke-width
580 nsGkAtoms::surfaceScale, // surfaceScale
581 nsGkAtoms::systemLanguage, // systemLanguage
582 nsGkAtoms::tableValues, // tableValues
583 nsGkAtoms::target, // target
584 nsGkAtoms::targetX, // targetX
585 nsGkAtoms::targetY, // targetY
586 nsGkAtoms::text_anchor, // text-anchor
587 nsGkAtoms::text_decoration, // text-decoration
588 // textLength
589 nsGkAtoms::text_rendering, // text-rendering
590 nsGkAtoms::title, // title
591 nsGkAtoms::to, // to
592 nsGkAtoms::transform, // transform
593 nsGkAtoms::transform_origin, // transform-origin
594 nsGkAtoms::type, // type
595 // u1
596 // u2
597 // underline-position
598 // underline-thickness
599 // unicode
600 nsGkAtoms::unicode_bidi, // unicode-bidi
601 // unicode-range
602 // units-per-em
603 // v-alphabetic
604 // v-hanging
605 // v-ideographic
606 // v-mathematical
607 nsGkAtoms::values, // values
608 nsGkAtoms::vector_effect, // vector-effect
609 // vert-adv-y
610 // vert-origin-x
611 // vert-origin-y
612 nsGkAtoms::viewBox, // viewBox
613 nsGkAtoms::viewTarget, // viewTarget
614 nsGkAtoms::visibility, // visibility
615 nsGkAtoms::width, // width
616 // widths
617 nsGkAtoms::word_spacing, // word-spacing
618 nsGkAtoms::writing_mode, // writing-mode
619 nsGkAtoms::x, // x
620 // x-height
621 nsGkAtoms::x1, // x1
622 nsGkAtoms::x2, // x2
623 nsGkAtoms::xChannelSelector, // xChannelSelector
624 nsGkAtoms::y, // y
625 nsGkAtoms::y1, // y1
626 nsGkAtoms::y2, // y2
627 nsGkAtoms::yChannelSelector, // yChannelSelector
628 nsGkAtoms::z, // z
629 nsGkAtoms::zoomAndPan, // zoomAndPan
630 nullptr};
632 constexpr const nsStaticAtom* const kURLAttributesSVG[] = {nsGkAtoms::href,
633 nullptr};
635 static_assert(AllOf(std::begin(kURLAttributesSVG), std::end(kURLAttributesSVG),
636 [](auto aURLAttributeSVG) {
637 return AnyOf(std::begin(kAttributesSVG),
638 std::end(kAttributesSVG),
639 [&](auto aAttributeSVG) {
640 return aAttributeSVG == aURLAttributeSVG;
642 }));
644 const nsStaticAtom* const kElementsMathML[] = {
645 nsGkAtoms::abs_, // abs
646 nsGkAtoms::_and, // and
647 nsGkAtoms::annotation_, // annotation
648 nsGkAtoms::annotation_xml_, // annotation-xml
649 nsGkAtoms::apply_, // apply
650 nsGkAtoms::approx_, // approx
651 nsGkAtoms::arccos_, // arccos
652 nsGkAtoms::arccosh_, // arccosh
653 nsGkAtoms::arccot_, // arccot
654 nsGkAtoms::arccoth_, // arccoth
655 nsGkAtoms::arccsc_, // arccsc
656 nsGkAtoms::arccsch_, // arccsch
657 nsGkAtoms::arcsec_, // arcsec
658 nsGkAtoms::arcsech_, // arcsech
659 nsGkAtoms::arcsin_, // arcsin
660 nsGkAtoms::arcsinh_, // arcsinh
661 nsGkAtoms::arctan_, // arctan
662 nsGkAtoms::arctanh_, // arctanh
663 nsGkAtoms::arg_, // arg
664 nsGkAtoms::bind_, // bind
665 nsGkAtoms::bvar_, // bvar
666 nsGkAtoms::card_, // card
667 nsGkAtoms::cartesianproduct_, // cartesianproduct
668 nsGkAtoms::cbytes_, // cbytes
669 nsGkAtoms::ceiling, // ceiling
670 nsGkAtoms::cerror_, // cerror
671 nsGkAtoms::ci_, // ci
672 nsGkAtoms::cn_, // cn
673 nsGkAtoms::codomain_, // codomain
674 nsGkAtoms::complexes_, // complexes
675 nsGkAtoms::compose_, // compose
676 nsGkAtoms::condition_, // condition
677 nsGkAtoms::conjugate_, // conjugate
678 nsGkAtoms::cos_, // cos
679 nsGkAtoms::cosh_, // cosh
680 nsGkAtoms::cot_, // cot
681 nsGkAtoms::coth_, // coth
682 nsGkAtoms::cs_, // cs
683 nsGkAtoms::csc_, // csc
684 nsGkAtoms::csch_, // csch
685 nsGkAtoms::csymbol_, // csymbol
686 nsGkAtoms::curl_, // curl
687 nsGkAtoms::declare, // declare
688 nsGkAtoms::degree_, // degree
689 nsGkAtoms::determinant_, // determinant
690 nsGkAtoms::diff_, // diff
691 nsGkAtoms::divergence_, // divergence
692 nsGkAtoms::divide_, // divide
693 nsGkAtoms::domain_, // domain
694 nsGkAtoms::domainofapplication_, // domainofapplication
695 nsGkAtoms::el, // el
696 nsGkAtoms::emptyset_, // emptyset
697 nsGkAtoms::eq_, // eq
698 nsGkAtoms::equivalent_, // equivalent
699 nsGkAtoms::eulergamma_, // eulergamma
700 nsGkAtoms::exists_, // exists
701 nsGkAtoms::exp_, // exp
702 nsGkAtoms::exponentiale_, // exponentiale
703 nsGkAtoms::factorial_, // factorial
704 nsGkAtoms::factorof_, // factorof
705 nsGkAtoms::_false, // false
706 nsGkAtoms::floor, // floor
707 nsGkAtoms::fn_, // fn
708 nsGkAtoms::forall_, // forall
709 nsGkAtoms::gcd_, // gcd
710 nsGkAtoms::geq_, // geq
711 nsGkAtoms::grad, // grad
712 nsGkAtoms::gt_, // gt
713 nsGkAtoms::ident_, // ident
714 nsGkAtoms::image, // image
715 nsGkAtoms::imaginary_, // imaginary
716 nsGkAtoms::imaginaryi_, // imaginaryi
717 nsGkAtoms::implies_, // implies
718 nsGkAtoms::in, // in
719 nsGkAtoms::infinity, // infinity
720 nsGkAtoms::int_, // int
721 nsGkAtoms::integers_, // integers
722 nsGkAtoms::intersect_, // intersect
723 nsGkAtoms::interval_, // interval
724 nsGkAtoms::inverse_, // inverse
725 nsGkAtoms::lambda_, // lambda
726 nsGkAtoms::laplacian_, // laplacian
727 nsGkAtoms::lcm_, // lcm
728 nsGkAtoms::leq_, // leq
729 nsGkAtoms::limit_, // limit
730 nsGkAtoms::list_, // list
731 nsGkAtoms::ln_, // ln
732 nsGkAtoms::log_, // log
733 nsGkAtoms::logbase_, // logbase
734 nsGkAtoms::lowlimit_, // lowlimit
735 nsGkAtoms::lt_, // lt
736 nsGkAtoms::maction_, // maction
737 nsGkAtoms::maligngroup_, // maligngroup
738 nsGkAtoms::malignmark_, // malignmark
739 nsGkAtoms::math, // math
740 nsGkAtoms::matrix, // matrix
741 nsGkAtoms::matrixrow_, // matrixrow
742 nsGkAtoms::max, // max
743 nsGkAtoms::mean_, // mean
744 nsGkAtoms::median_, // median
745 nsGkAtoms::menclose_, // menclose
746 nsGkAtoms::merror_, // merror
747 nsGkAtoms::mfenced_, // mfenced
748 nsGkAtoms::mfrac_, // mfrac
749 nsGkAtoms::mglyph_, // mglyph
750 nsGkAtoms::mi_, // mi
751 nsGkAtoms::min, // min
752 nsGkAtoms::minus_, // minus
753 nsGkAtoms::mlabeledtr_, // mlabeledtr
754 nsGkAtoms::mlongdiv_, // mlongdiv
755 nsGkAtoms::mmultiscripts_, // mmultiscripts
756 nsGkAtoms::mn_, // mn
757 nsGkAtoms::mo_, // mo
758 nsGkAtoms::mode, // mode
759 nsGkAtoms::moment_, // moment
760 nsGkAtoms::momentabout_, // momentabout
761 nsGkAtoms::mover_, // mover
762 nsGkAtoms::mpadded_, // mpadded
763 nsGkAtoms::mphantom_, // mphantom
764 nsGkAtoms::mprescripts_, // mprescripts
765 nsGkAtoms::mroot_, // mroot
766 nsGkAtoms::mrow_, // mrow
767 nsGkAtoms::ms_, // ms
768 nsGkAtoms::mscarries_, // mscarries
769 nsGkAtoms::mscarry_, // mscarry
770 nsGkAtoms::msgroup_, // msgroup
771 nsGkAtoms::msline_, // msline
772 nsGkAtoms::mspace_, // mspace
773 nsGkAtoms::msqrt_, // msqrt
774 nsGkAtoms::msrow_, // msrow
775 nsGkAtoms::mstack_, // mstack
776 nsGkAtoms::mstyle_, // mstyle
777 nsGkAtoms::msub_, // msub
778 nsGkAtoms::msubsup_, // msubsup
779 nsGkAtoms::msup_, // msup
780 nsGkAtoms::mtable_, // mtable
781 nsGkAtoms::mtd_, // mtd
782 nsGkAtoms::mtext_, // mtext
783 nsGkAtoms::mtr_, // mtr
784 nsGkAtoms::munder_, // munder
785 nsGkAtoms::munderover_, // munderover
786 nsGkAtoms::naturalnumbers_, // naturalnumbers
787 nsGkAtoms::neq_, // neq
788 nsGkAtoms::none, // none
789 nsGkAtoms::_not, // not
790 nsGkAtoms::notanumber_, // notanumber
791 nsGkAtoms::note_, // note
792 nsGkAtoms::notin_, // notin
793 nsGkAtoms::notprsubset_, // notprsubset
794 nsGkAtoms::notsubset_, // notsubset
795 nsGkAtoms::_or, // or
796 nsGkAtoms::otherwise, // otherwise
797 nsGkAtoms::outerproduct_, // outerproduct
798 nsGkAtoms::partialdiff_, // partialdiff
799 nsGkAtoms::pi_, // pi
800 nsGkAtoms::piece_, // piece
801 nsGkAtoms::piecewise_, // piecewise
802 nsGkAtoms::plus_, // plus
803 nsGkAtoms::power_, // power
804 nsGkAtoms::primes_, // primes
805 nsGkAtoms::product_, // product
806 nsGkAtoms::prsubset_, // prsubset
807 nsGkAtoms::quotient_, // quotient
808 nsGkAtoms::rationals_, // rationals
809 nsGkAtoms::real_, // real
810 nsGkAtoms::reals_, // reals
811 nsGkAtoms::reln_, // reln
812 nsGkAtoms::rem, // rem
813 nsGkAtoms::root_, // root
814 nsGkAtoms::scalarproduct_, // scalarproduct
815 nsGkAtoms::sdev_, // sdev
816 nsGkAtoms::sec_, // sec
817 nsGkAtoms::sech_, // sech
818 nsGkAtoms::selector_, // selector
819 nsGkAtoms::semantics_, // semantics
820 nsGkAtoms::sep_, // sep
821 nsGkAtoms::set, // set
822 nsGkAtoms::setdiff_, // setdiff
823 nsGkAtoms::share_, // share
824 nsGkAtoms::sin_, // sin
825 nsGkAtoms::sinh_, // sinh
826 nsGkAtoms::subset_, // subset
827 nsGkAtoms::sum, // sum
828 nsGkAtoms::tan_, // tan
829 nsGkAtoms::tanh_, // tanh
830 nsGkAtoms::tendsto_, // tendsto
831 nsGkAtoms::times_, // times
832 nsGkAtoms::transpose_, // transpose
833 nsGkAtoms::_true, // true
834 nsGkAtoms::union_, // union
835 nsGkAtoms::uplimit_, // uplimit
836 nsGkAtoms::variance_, // variance
837 nsGkAtoms::vector_, // vector
838 nsGkAtoms::vectorproduct_, // vectorproduct
839 nsGkAtoms::xor_, // xor
840 nullptr};
842 const nsStaticAtom* const kAttributesMathML[] = {
843 nsGkAtoms::accent_, // accent
844 nsGkAtoms::accentunder_, // accentunder
845 nsGkAtoms::actiontype_, // actiontype
846 nsGkAtoms::align, // align
847 nsGkAtoms::alignmentscope_, // alignmentscope
848 nsGkAtoms::alt, // alt
849 nsGkAtoms::altimg_, // altimg
850 nsGkAtoms::altimg_height_, // altimg-height
851 nsGkAtoms::altimg_valign_, // altimg-valign
852 nsGkAtoms::altimg_width_, // altimg-width
853 nsGkAtoms::background, // background
854 nsGkAtoms::base, // base
855 nsGkAtoms::bevelled_, // bevelled
856 nsGkAtoms::cd_, // cd
857 nsGkAtoms::cdgroup_, // cdgroup
858 nsGkAtoms::charalign_, // charalign
859 nsGkAtoms::close, // close
860 nsGkAtoms::closure_, // closure
861 nsGkAtoms::color, // color
862 nsGkAtoms::columnalign_, // columnalign
863 nsGkAtoms::columnalignment_, // columnalignment
864 nsGkAtoms::columnlines_, // columnlines
865 nsGkAtoms::columnspacing_, // columnspacing
866 nsGkAtoms::columnspan_, // columnspan
867 nsGkAtoms::columnwidth_, // columnwidth
868 nsGkAtoms::crossout_, // crossout
869 nsGkAtoms::decimalpoint_, // decimalpoint
870 nsGkAtoms::definitionURL_, // definitionURL
871 nsGkAtoms::denomalign_, // denomalign
872 nsGkAtoms::depth_, // depth
873 nsGkAtoms::dir, // dir
874 nsGkAtoms::display, // display
875 nsGkAtoms::displaystyle_, // displaystyle
876 nsGkAtoms::edge_, // edge
877 nsGkAtoms::encoding, // encoding
878 nsGkAtoms::equalcolumns_, // equalcolumns
879 nsGkAtoms::equalrows_, // equalrows
880 nsGkAtoms::fence_, // fence
881 nsGkAtoms::fontfamily_, // fontfamily
882 nsGkAtoms::fontsize_, // fontsize
883 nsGkAtoms::fontstyle_, // fontstyle
884 nsGkAtoms::fontweight_, // fontweight
885 nsGkAtoms::form, // form
886 nsGkAtoms::frame, // frame
887 nsGkAtoms::framespacing_, // framespacing
888 nsGkAtoms::groupalign_, // groupalign
889 nsGkAtoms::height, // height
890 nsGkAtoms::href, // href
891 nsGkAtoms::id, // id
892 nsGkAtoms::indentalign_, // indentalign
893 nsGkAtoms::indentalignfirst_, // indentalignfirst
894 nsGkAtoms::indentalignlast_, // indentalignlast
895 nsGkAtoms::indentshift_, // indentshift
896 nsGkAtoms::indentshiftfirst_, // indentshiftfirst
897 nsGkAtoms::indenttarget_, // indenttarget
898 nsGkAtoms::index, // index
899 nsGkAtoms::integer, // integer
900 nsGkAtoms::largeop_, // largeop
901 nsGkAtoms::length, // length
902 nsGkAtoms::linebreak_, // linebreak
903 nsGkAtoms::linebreakmultchar_, // linebreakmultchar
904 nsGkAtoms::linebreakstyle_, // linebreakstyle
905 nsGkAtoms::linethickness_, // linethickness
906 nsGkAtoms::location_, // location
907 nsGkAtoms::longdivstyle_, // longdivstyle
908 nsGkAtoms::lquote_, // lquote
909 nsGkAtoms::lspace_, // lspace
910 nsGkAtoms::ltr, // ltr
911 nsGkAtoms::mathbackground_, // mathbackground
912 nsGkAtoms::mathcolor_, // mathcolor
913 nsGkAtoms::mathsize_, // mathsize
914 nsGkAtoms::mathvariant_, // mathvariant
915 nsGkAtoms::maxsize_, // maxsize
916 nsGkAtoms::minlabelspacing_, // minlabelspacing
917 nsGkAtoms::minsize_, // minsize
918 nsGkAtoms::movablelimits_, // movablelimits
919 nsGkAtoms::msgroup_, // msgroup
920 nsGkAtoms::name, // name
921 nsGkAtoms::newline, // newline
922 nsGkAtoms::notation_, // notation
923 nsGkAtoms::numalign_, // numalign
924 nsGkAtoms::number, // number
925 nsGkAtoms::open, // open
926 nsGkAtoms::order, // order
927 nsGkAtoms::other, // other
928 nsGkAtoms::overflow, // overflow
929 nsGkAtoms::position, // position
930 nsGkAtoms::role, // role
931 nsGkAtoms::rowalign_, // rowalign
932 nsGkAtoms::rowlines_, // rowlines
933 nsGkAtoms::rowspacing_, // rowspacing
934 nsGkAtoms::rowspan, // rowspan
935 nsGkAtoms::rquote_, // rquote
936 nsGkAtoms::rspace_, // rspace
937 nsGkAtoms::schemaLocation_, // schemaLocation
938 nsGkAtoms::scriptlevel_, // scriptlevel
939 nsGkAtoms::scriptminsize_, // scriptminsize
940 nsGkAtoms::scriptsize_, // scriptsize
941 nsGkAtoms::scriptsizemultiplier_, // scriptsizemultiplier
942 nsGkAtoms::selection_, // selection
943 nsGkAtoms::separator_, // separator
944 nsGkAtoms::separators_, // separators
945 nsGkAtoms::shift_, // shift
946 nsGkAtoms::side_, // side
947 nsGkAtoms::src, // src
948 nsGkAtoms::stackalign_, // stackalign
949 nsGkAtoms::stretchy_, // stretchy
950 nsGkAtoms::subscriptshift_, // subscriptshift
951 nsGkAtoms::superscriptshift_, // superscriptshift
952 nsGkAtoms::symmetric_, // symmetric
953 nsGkAtoms::type, // type
954 nsGkAtoms::voffset_, // voffset
955 nsGkAtoms::width, // width
956 nsGkAtoms::xref_, // xref
957 nullptr};
959 const nsStaticAtom* const kURLAttributesMathML[] = {
960 // clang-format off
961 nsGkAtoms::href,
962 nsGkAtoms::src,
963 nsGkAtoms::cdgroup_,
964 nsGkAtoms::altimg_,
965 nsGkAtoms::definitionURL_,
966 nullptr
967 // clang-format on
970 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sElementsHTML = nullptr;
971 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sAttributesHTML = nullptr;
972 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sPresAttributesHTML = nullptr;
973 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sElementsSVG = nullptr;
974 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sAttributesSVG = nullptr;
975 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sElementsMathML = nullptr;
976 nsTreeSanitizer::AtomsTable* nsTreeSanitizer::sAttributesMathML = nullptr;
977 nsIPrincipal* nsTreeSanitizer::sNullPrincipal = nullptr;
979 nsTreeSanitizer::nsTreeSanitizer(uint32_t aFlags)
980 : mAllowStyles(aFlags & nsIParserUtils::SanitizerAllowStyle),
981 mAllowComments(aFlags & nsIParserUtils::SanitizerAllowComments),
982 mDropNonCSSPresentation(aFlags &
983 nsIParserUtils::SanitizerDropNonCSSPresentation),
984 mDropForms(aFlags & nsIParserUtils::SanitizerDropForms),
985 mCidEmbedsOnly(aFlags & nsIParserUtils::SanitizerCidEmbedsOnly),
986 mDropMedia(aFlags & nsIParserUtils::SanitizerDropMedia),
987 mFullDocument(false),
988 mLogRemovals(aFlags & nsIParserUtils::SanitizerLogRemovals),
989 mOnlyConditionalCSS(aFlags &
990 nsIParserUtils::SanitizerRemoveOnlyConditionalCSS) {
991 if (mCidEmbedsOnly) {
992 // Sanitizing styles for external references is not supported.
993 mAllowStyles = false;
996 mAllowedElements = nullptr;
997 mBlockedElements = nullptr;
999 if (!sElementsHTML) {
1000 // Initialize lazily to avoid having to initialize at all if the user
1001 // doesn't paste HTML or load feeds.
1002 InitializeStatics();
1004 /* Ensure SanitizerRemoveOnlyConditionalCSS isn't combined with any
1005 * flags, except SanitizerLogRemovals. */
1006 MOZ_ASSERT(!mOnlyConditionalCSS ||
1007 0 ==
1008 (aFlags & ~(nsIParserUtils::SanitizerRemoveOnlyConditionalCSS |
1009 nsIParserUtils::SanitizerLogRemovals)));
1012 bool nsTreeSanitizer::MustFlatten(int32_t aNamespace, nsAtom* aLocal) {
1013 if (aNamespace == kNameSpaceID_XHTML) {
1014 if (mIsCustomized) {
1015 // TODO(freddy): Make it work for other namespaces.
1016 // See https://github.com/WICG/sanitizer-api/issues/72
1017 return ((mAllowedElements && !mAllowedElements->Contains(aLocal)) ||
1018 ((mBlockedElements && mBlockedElements->Contains(aLocal))));
1020 if (mDropNonCSSPresentation &&
1021 (nsGkAtoms::font == aLocal || nsGkAtoms::center == aLocal)) {
1022 return true;
1024 if (mDropForms &&
1025 (nsGkAtoms::form == aLocal || nsGkAtoms::input == aLocal ||
1026 nsGkAtoms::option == aLocal || nsGkAtoms::optgroup == aLocal)) {
1027 return true;
1029 if (mFullDocument &&
1030 (nsGkAtoms::title == aLocal || nsGkAtoms::html == aLocal ||
1031 nsGkAtoms::head == aLocal || nsGkAtoms::body == aLocal)) {
1032 return false;
1034 if (nsGkAtoms::_template == aLocal) {
1035 return false;
1037 return !sElementsHTML->Contains(aLocal);
1039 if (aNamespace == kNameSpaceID_SVG) {
1040 if (mCidEmbedsOnly || mDropMedia) {
1041 // Sanitizing CSS-based URL references inside SVG presentational
1042 // attributes is not supported, so flattening for cid: embed case.
1043 return true;
1045 return !sElementsSVG->Contains(aLocal);
1047 if (aNamespace == kNameSpaceID_MathML) {
1048 return !sElementsMathML->Contains(aLocal);
1050 return true;
1053 bool nsTreeSanitizer::IsURL(const nsStaticAtom* const* aURLs,
1054 nsAtom* aLocalName) {
1055 const nsStaticAtom* atom;
1056 while ((atom = *aURLs)) {
1057 if (atom == aLocalName) {
1058 return true;
1060 ++aURLs;
1062 return false;
1065 bool nsTreeSanitizer::MustPrune(int32_t aNamespace, nsAtom* aLocal,
1066 mozilla::dom::Element* aElement) {
1067 // To avoid attacks where a MathML script becomes something that gets
1068 // serialized in a way that it parses back as an HTML script, let's just
1069 // drop elements with the local name 'script' regardless of namespace.
1070 if (nsGkAtoms::script == aLocal) {
1071 return true;
1073 if (aNamespace == kNameSpaceID_XHTML) {
1074 if (nsGkAtoms::title == aLocal && !mFullDocument) {
1075 // emulate the quirks of the old parser
1076 return true;
1078 if (mDropForms &&
1079 (nsGkAtoms::select == aLocal || nsGkAtoms::button == aLocal ||
1080 nsGkAtoms::datalist == aLocal)) {
1081 return true;
1083 if (mDropMedia &&
1084 (nsGkAtoms::img == aLocal || nsGkAtoms::video == aLocal ||
1085 nsGkAtoms::audio == aLocal || nsGkAtoms::source == aLocal)) {
1086 return true;
1088 if (nsGkAtoms::meta == aLocal &&
1089 (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::charset) ||
1090 aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv))) {
1091 // Throw away charset declarations even if they also have microdata
1092 // which they can't validly have.
1093 return true;
1095 if (((!mFullDocument && nsGkAtoms::meta == aLocal) ||
1096 nsGkAtoms::link == aLocal) &&
1097 !(aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::itemprop) ||
1098 aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::itemscope))) {
1099 // emulate old behavior for non-Microdata <meta> and <link> presumably
1100 // in <head>. <meta> and <link> are whitelisted in order to avoid
1101 // corrupting Microdata when they appear in <body>. Note that
1102 // SanitizeAttributes() will remove the rel attribute from <link> and
1103 // the name attribute from <meta>.
1104 return true;
1107 if (mAllowStyles) {
1108 return nsGkAtoms::style == aLocal && !(aNamespace == kNameSpaceID_XHTML ||
1109 aNamespace == kNameSpaceID_SVG);
1111 if (nsGkAtoms::style == aLocal) {
1112 return true;
1114 return false;
1117 void nsTreeSanitizer::SanitizeStyleSheet(const nsAString& aOriginal,
1118 nsAString& aSanitized,
1119 Document* aDocument,
1120 nsIURI* aBaseURI) {
1121 aSanitized.Truncate();
1123 NS_ConvertUTF16toUTF8 style(aOriginal);
1124 RefPtr<nsIReferrerInfo> referrer =
1125 ReferrerInfo::CreateForInternalCSSResources(aDocument);
1126 auto extraData =
1127 MakeRefPtr<URLExtraData>(aBaseURI, referrer, aDocument->NodePrincipal());
1128 auto sanitizationKind = mOnlyConditionalCSS
1129 ? StyleSanitizationKind::NoConditionalRules
1130 : StyleSanitizationKind::Standard;
1131 RefPtr<RawServoStyleSheetContents> contents =
1132 Servo_StyleSheet_FromUTF8Bytes(
1133 /* loader = */ nullptr,
1134 /* stylesheet = */ nullptr,
1135 /* load_data = */ nullptr, &style,
1136 css::SheetParsingMode::eAuthorSheetFeatures, extraData.get(),
1137 /* line_number_offset = */ 0, aDocument->GetCompatibilityMode(),
1138 /* reusable_sheets = */ nullptr,
1139 /* use_counters = */ nullptr, StyleAllowImportRules::Yes,
1140 sanitizationKind, &aSanitized)
1141 .Consume();
1143 if (mLogRemovals && aSanitized.Length() != aOriginal.Length()) {
1144 LogMessage("Removed some rules and/or properties from stylesheet.",
1145 aDocument);
1149 template <size_t Len>
1150 static bool UTF16StringStartsWith(const char16_t* aStr, uint32_t aLength,
1151 const char16_t (&aNeedle)[Len]) {
1152 MOZ_ASSERT(aNeedle[Len - 1] == '\0',
1153 "needle should be a UTF-16 encoded string literal");
1155 if (aLength < Len - 1) {
1156 return false;
1158 for (size_t i = 0; i < Len - 1; i++) {
1159 if (aStr[i] != aNeedle[i]) {
1160 return false;
1163 return true;
1166 void nsTreeSanitizer::SanitizeAttributes(mozilla::dom::Element* aElement,
1167 AllowedAttributes aAllowed) {
1168 int32_t ac = (int)aElement->GetAttrCount();
1170 for (int32_t i = ac - 1; i >= 0; --i) {
1171 const nsAttrName* attrName = aElement->GetAttrNameAt(i);
1172 int32_t attrNs = attrName->NamespaceID();
1173 RefPtr<nsAtom> attrLocal = attrName->LocalName();
1175 if (mIsCustomized) {
1176 bool shouldRemove = true;
1177 RefPtr<nsAtom> elemName = aElement->NodeInfo()->NameAtom();
1179 // check allow list
1180 if (mAllowedAttributes) {
1181 auto allowedElements = mAllowedAttributes->Lookup(attrLocal);
1182 if (allowedElements) {
1183 if (allowedElements.Data()->Contains(elemName) ||
1184 allowedElements.Data()->Contains(nsGkAtoms::_asterisk)) {
1185 shouldRemove = false;
1189 // checking drop list last
1190 // i.e., if listd as both allowed and dropped, it will still be dropped
1191 if (mDroppedAttributes) {
1192 auto dropElements = mDroppedAttributes->Lookup(attrLocal);
1193 if (dropElements) {
1194 if (dropElements.Data()->Contains(elemName) ||
1195 dropElements.Data()->Contains(nsGkAtoms::_asterisk)) {
1196 shouldRemove = true;
1200 if (shouldRemove) {
1201 aElement->UnsetAttr(kNameSpaceID_None, attrLocal, false);
1202 // in case the attribute removal shuffled the attribute order, start
1203 // the loop again.
1204 --ac;
1205 i = ac; // i will be decremented immediately thanks to the for loop
1207 continue;
1210 if (kNameSpaceID_None == attrNs) {
1211 if (aAllowed.mStyle && nsGkAtoms::style == attrLocal) {
1212 continue;
1214 if (aAllowed.mDangerousSrc && nsGkAtoms::src == attrLocal) {
1215 continue;
1217 if (IsURL(aAllowed.mURLs, attrLocal)) {
1218 if (SanitizeURL(aElement, attrNs, attrLocal)) {
1219 // in case the attribute removal shuffled the attribute order, start
1220 // the loop again.
1221 --ac;
1222 i = ac; // i will be decremented immediately thanks to the for loop
1223 continue;
1225 // else fall through to see if there's another reason to drop this
1226 // attribute (in particular if the attribute is background="" on an
1227 // HTML element)
1229 if (!mDropNonCSSPresentation &&
1230 (aAllowed.mNames == sAttributesHTML) && // element is HTML
1231 sPresAttributesHTML->Contains(attrLocal)) {
1232 continue;
1234 if (aAllowed.mNames->Contains(attrLocal) &&
1235 !((attrLocal == nsGkAtoms::rel &&
1236 aElement->IsHTMLElement(nsGkAtoms::link)) ||
1237 (!mFullDocument && attrLocal == nsGkAtoms::name &&
1238 aElement->IsHTMLElement(nsGkAtoms::meta)))) {
1239 // name="" and rel="" are whitelisted, but treat them as blacklisted
1240 // for <meta name> (fragment case) and <link rel> (all cases) to avoid
1241 // document-wide metadata or styling overrides with non-conforming
1242 // <meta name itemprop> or
1243 // <link rel itemprop>
1244 continue;
1246 const char16_t* localStr = attrLocal->GetUTF16String();
1247 uint32_t localLen = attrLocal->GetLength();
1248 // Allow underscore to cater to the MCE editor library.
1249 // Allow data-* on SVG and MathML, too, as a forward-compat measure.
1250 // Allow aria-* on all for simplicity.
1251 if (UTF16StringStartsWith(localStr, localLen, u"_") ||
1252 UTF16StringStartsWith(localStr, localLen, u"data-") ||
1253 UTF16StringStartsWith(localStr, localLen, u"aria-")) {
1254 continue;
1256 // else not allowed
1257 } else if (kNameSpaceID_XML == attrNs) {
1258 if (nsGkAtoms::lang == attrLocal || nsGkAtoms::space == attrLocal) {
1259 continue;
1261 // else not allowed
1262 } else if (aAllowed.mXLink && kNameSpaceID_XLink == attrNs) {
1263 if (nsGkAtoms::href == attrLocal) {
1264 if (SanitizeURL(aElement, attrNs, attrLocal)) {
1265 // in case the attribute removal shuffled the attribute order, start
1266 // the loop again.
1267 --ac;
1268 i = ac; // i will be decremented immediately thanks to the for loop
1270 continue;
1272 if (nsGkAtoms::type == attrLocal || nsGkAtoms::title == attrLocal ||
1273 nsGkAtoms::show == attrLocal || nsGkAtoms::actuate == attrLocal) {
1274 continue;
1276 // else not allowed
1278 aElement->UnsetAttr(kNameSpaceID_None, attrLocal, false);
1279 if (mLogRemovals) {
1280 LogMessage("Removed unsafe attribute.", aElement->OwnerDoc(), aElement,
1281 attrLocal);
1283 // in case the attribute removal shuffled the attribute order, start the
1284 // loop again.
1285 --ac;
1286 i = ac; // i will be decremented immediately thanks to the for loop
1289 // If we've got HTML audio or video, add the controls attribute, because
1290 // otherwise the content is unplayable with scripts removed.
1291 if (aElement->IsAnyOfHTMLElements(nsGkAtoms::video, nsGkAtoms::audio)) {
1292 aElement->SetAttr(kNameSpaceID_None, nsGkAtoms::controls, u""_ns, false);
1296 bool nsTreeSanitizer::SanitizeURL(mozilla::dom::Element* aElement,
1297 int32_t aNamespace, nsAtom* aLocalName) {
1298 nsAutoString value;
1299 aElement->GetAttr(aNamespace, aLocalName, value);
1301 // Get value and remove mandatory quotes
1302 static const char* kWhitespace = "\n\r\t\b";
1303 const nsAString& v = nsContentUtils::TrimCharsInSet(kWhitespace, value);
1304 // Fragment-only url cannot be harmful.
1305 if (!v.IsEmpty() && v.First() == u'#') {
1306 return false;
1309 nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
1310 uint32_t flags = nsIScriptSecurityManager::DISALLOW_INHERIT_PRINCIPAL;
1312 nsCOMPtr<nsIURI> attrURI;
1313 nsresult rv =
1314 NS_NewURI(getter_AddRefs(attrURI), v, nullptr, aElement->GetBaseURI());
1315 if (NS_SUCCEEDED(rv)) {
1316 if (mCidEmbedsOnly && kNameSpaceID_None == aNamespace) {
1317 if (nsGkAtoms::src == aLocalName || nsGkAtoms::background == aLocalName) {
1318 // comm-central uses a hack that makes nsIURIs created with cid: specs
1319 // actually have an about:blank spec. Therefore, nsIURI facilities are
1320 // useless for cid: when comm-central code is participating.
1321 if (!(v.Length() > 4 && (v[0] == 'c' || v[0] == 'C') &&
1322 (v[1] == 'i' || v[1] == 'I') && (v[2] == 'd' || v[2] == 'D') &&
1323 v[3] == ':')) {
1324 rv = NS_ERROR_FAILURE;
1326 } else if (nsGkAtoms::cdgroup_ == aLocalName ||
1327 nsGkAtoms::altimg_ == aLocalName ||
1328 nsGkAtoms::definitionURL_ == aLocalName) {
1329 // Gecko doesn't fetch these now and shouldn't in the future, but
1330 // in case someone goofs with these in the future, let's drop them.
1331 rv = NS_ERROR_FAILURE;
1332 } else {
1333 rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags,
1336 } else {
1337 rv = secMan->CheckLoadURIWithPrincipal(sNullPrincipal, attrURI, flags, 0);
1340 if (NS_FAILED(rv)) {
1341 aElement->UnsetAttr(aNamespace, aLocalName, false);
1342 if (mLogRemovals) {
1343 LogMessage("Removed unsafe URI from element attribute.",
1344 aElement->OwnerDoc(), aElement, aLocalName);
1346 return true;
1348 return false;
1351 void nsTreeSanitizer::Sanitize(DocumentFragment* aFragment) {
1352 // If you want to relax these preconditions, be sure to check the code in
1353 // here that notifies / does not notify or that fires mutation events if
1354 // in tree.
1355 MOZ_ASSERT(!aFragment->IsInUncomposedDoc(), "The fragment is in doc?");
1357 mFullDocument = false;
1358 SanitizeChildren(aFragment);
1361 void nsTreeSanitizer::Sanitize(Document* aDocument) {
1362 // If you want to relax these preconditions, be sure to check the code in
1363 // here that notifies / does not notify or that fires mutation events if
1364 // in tree.
1365 #ifdef DEBUG
1366 MOZ_ASSERT(!aDocument->GetContainer(), "The document is in a shell.");
1367 RefPtr<mozilla::dom::Element> root = aDocument->GetRootElement();
1368 MOZ_ASSERT(root->IsHTMLElement(nsGkAtoms::html), "Not HTML root.");
1369 #endif
1371 mFullDocument = true;
1372 SanitizeChildren(aDocument);
1375 void nsTreeSanitizer::SanitizeChildren(nsINode* aRoot) {
1376 nsIContent* node = aRoot->GetFirstChild();
1377 while (node) {
1378 if (node->IsElement()) {
1379 mozilla::dom::Element* elt = node->AsElement();
1380 mozilla::dom::NodeInfo* nodeInfo = node->NodeInfo();
1381 nsAtom* localName = nodeInfo->NameAtom();
1382 int32_t ns = nodeInfo->NamespaceID();
1384 if (!mOnlyConditionalCSS && MustPrune(ns, localName, elt)) {
1385 if (mLogRemovals) {
1386 LogMessage("Removing unsafe node.", elt->OwnerDoc(), elt);
1388 RemoveAllAttributes(elt);
1389 nsIContent* descendant = node;
1390 while ((descendant = descendant->GetNextNode(node))) {
1391 if (descendant->IsElement()) {
1392 RemoveAllAttributes(descendant->AsElement());
1395 nsIContent* next = node->GetNextNonChildNode(aRoot);
1396 node->RemoveFromParent();
1397 node = next;
1398 continue;
1400 if (auto* templateEl = HTMLTemplateElement::FromNode(elt)) {
1401 // traverse into the DocFragment content attribute of template elements
1402 bool wasFullDocument = mFullDocument;
1403 mFullDocument = false;
1404 RefPtr<DocumentFragment> frag = templateEl->Content();
1405 SanitizeChildren(frag);
1406 mFullDocument = wasFullDocument;
1408 if (nsGkAtoms::style == localName) {
1409 // If !mOnlyConditionalCSS check the following condition:
1410 // If styles aren't allowed, style elements got pruned above. Even
1411 // if styles are allowed, non-HTML, non-SVG style elements got pruned
1412 // above.
1413 NS_ASSERTION((ns == kNameSpaceID_XHTML || ns == kNameSpaceID_SVG) ||
1414 mOnlyConditionalCSS,
1415 "Should have only HTML or SVG here!");
1416 nsAutoString styleText;
1417 nsContentUtils::GetNodeTextContent(node, false, styleText);
1419 nsAutoString sanitizedStyle;
1420 SanitizeStyleSheet(styleText, sanitizedStyle, aRoot->OwnerDoc(),
1421 node->GetBaseURI());
1422 RemoveAllAttributesFromDescendants(elt);
1423 nsContentUtils::SetNodeTextContent(node, sanitizedStyle, true);
1425 if (!mOnlyConditionalCSS) {
1426 AllowedAttributes allowed;
1427 allowed.mStyle = mAllowStyles;
1428 if (ns == kNameSpaceID_XHTML) {
1429 allowed.mNames = sAttributesHTML;
1430 allowed.mURLs = kURLAttributesHTML;
1431 SanitizeAttributes(elt, allowed);
1432 } else {
1433 allowed.mNames = sAttributesSVG;
1434 allowed.mURLs = kURLAttributesSVG;
1435 allowed.mXLink = true;
1436 SanitizeAttributes(elt, allowed);
1439 node = node->GetNextNonChildNode(aRoot);
1440 continue;
1442 if (!mOnlyConditionalCSS && MustFlatten(ns, localName)) {
1443 if (mLogRemovals) {
1444 LogMessage("Flattening unsafe node (descendants are preserved).",
1445 elt->OwnerDoc(), elt);
1447 RemoveAllAttributes(elt);
1448 nsCOMPtr<nsIContent> next = node->GetNextNode(aRoot);
1449 nsCOMPtr<nsIContent> parent = node->GetParent();
1450 nsCOMPtr<nsIContent> child; // Must keep the child alive during move
1451 ErrorResult rv;
1452 while ((child = node->GetFirstChild())) {
1453 nsCOMPtr<nsINode> refNode = node;
1454 parent->InsertBefore(*child, refNode, rv);
1455 if (rv.Failed()) {
1456 break;
1459 node->RemoveFromParent();
1460 node = next;
1461 continue;
1463 if (!mOnlyConditionalCSS) {
1464 NS_ASSERTION(ns == kNameSpaceID_XHTML || ns == kNameSpaceID_SVG ||
1465 ns == kNameSpaceID_MathML,
1466 "Should have only HTML, MathML or SVG here!");
1467 AllowedAttributes allowed;
1468 if (ns == kNameSpaceID_XHTML) {
1469 allowed.mNames = sAttributesHTML;
1470 allowed.mURLs = kURLAttributesHTML;
1471 allowed.mStyle = mAllowStyles;
1472 allowed.mDangerousSrc =
1473 nsGkAtoms::img == localName && !mCidEmbedsOnly;
1474 SanitizeAttributes(elt, allowed);
1475 } else if (ns == kNameSpaceID_SVG) {
1476 allowed.mNames = sAttributesSVG;
1477 allowed.mURLs = kURLAttributesSVG;
1478 allowed.mXLink = true;
1479 allowed.mStyle = mAllowStyles;
1480 SanitizeAttributes(elt, allowed);
1481 } else {
1482 allowed.mNames = sAttributesMathML;
1483 allowed.mURLs = kURLAttributesMathML;
1484 allowed.mXLink = true;
1485 SanitizeAttributes(elt, allowed);
1488 node = node->GetNextNode(aRoot);
1489 continue;
1491 NS_ASSERTION(!node->GetFirstChild(), "How come non-element node had kids?");
1492 nsIContent* next = node->GetNextNonChildNode(aRoot);
1493 if (!mOnlyConditionalCSS && (!mAllowComments && node->IsComment())) {
1494 node->RemoveFromParent();
1496 node = next;
1500 void nsTreeSanitizer::RemoveAllAttributes(Element* aElement) {
1501 const nsAttrName* attrName;
1502 while ((attrName = aElement->GetAttrNameAt(0))) {
1503 int32_t attrNs = attrName->NamespaceID();
1504 RefPtr<nsAtom> attrLocal = attrName->LocalName();
1505 aElement->UnsetAttr(attrNs, attrLocal, false);
1509 void nsTreeSanitizer::RemoveAllAttributesFromDescendants(
1510 mozilla::dom::Element* aElement) {
1511 nsIContent* node = aElement->GetFirstChild();
1512 while (node) {
1513 if (node->IsElement()) {
1514 mozilla::dom::Element* elt = node->AsElement();
1515 RemoveAllAttributes(elt);
1517 node = node->GetNextNode(aElement);
1521 void nsTreeSanitizer::LogMessage(const char* aMessage, Document* aDoc,
1522 Element* aElement, nsAtom* aAttr) {
1523 if (mLogRemovals) {
1524 nsAutoString msg;
1525 msg.Assign(NS_ConvertASCIItoUTF16(aMessage));
1526 if (aElement) {
1527 msg.Append(u" Element: "_ns + aElement->LocalName() + u"."_ns);
1529 if (aAttr) {
1530 msg.Append(u" Attribute: "_ns + nsDependentAtomString(aAttr) + u"."_ns);
1533 nsContentUtils::ReportToConsoleNonLocalized(
1534 msg, nsIScriptError::warningFlag, "DOM"_ns, aDoc);
1538 void nsTreeSanitizer::InitializeStatics() {
1539 MOZ_ASSERT(!sElementsHTML, "Initializing a second time.");
1541 sElementsHTML = new AtomsTable(ArrayLength(kElementsHTML));
1542 for (uint32_t i = 0; kElementsHTML[i]; i++) {
1543 sElementsHTML->Insert(kElementsHTML[i]);
1546 sAttributesHTML = new AtomsTable(ArrayLength(kAttributesHTML));
1547 for (uint32_t i = 0; kAttributesHTML[i]; i++) {
1548 sAttributesHTML->Insert(kAttributesHTML[i]);
1551 sPresAttributesHTML = new AtomsTable(ArrayLength(kPresAttributesHTML));
1552 for (uint32_t i = 0; kPresAttributesHTML[i]; i++) {
1553 sPresAttributesHTML->Insert(kPresAttributesHTML[i]);
1556 sElementsSVG = new AtomsTable(ArrayLength(kElementsSVG));
1557 for (uint32_t i = 0; kElementsSVG[i]; i++) {
1558 sElementsSVG->Insert(kElementsSVG[i]);
1561 sAttributesSVG = new AtomsTable(ArrayLength(kAttributesSVG));
1562 for (uint32_t i = 0; kAttributesSVG[i]; i++) {
1563 sAttributesSVG->Insert(kAttributesSVG[i]);
1566 sElementsMathML = new AtomsTable(ArrayLength(kElementsMathML));
1567 for (uint32_t i = 0; kElementsMathML[i]; i++) {
1568 sElementsMathML->Insert(kElementsMathML[i]);
1571 sAttributesMathML = new AtomsTable(ArrayLength(kAttributesMathML));
1572 for (uint32_t i = 0; kAttributesMathML[i]; i++) {
1573 sAttributesMathML->Insert(kAttributesMathML[i]);
1576 nsCOMPtr<nsIPrincipal> principal =
1577 NullPrincipal::CreateWithoutOriginAttributes();
1578 principal.forget(&sNullPrincipal);
1581 void nsTreeSanitizer::ReleaseStatics() {
1582 delete sElementsHTML;
1583 sElementsHTML = nullptr;
1585 delete sAttributesHTML;
1586 sAttributesHTML = nullptr;
1588 delete sPresAttributesHTML;
1589 sPresAttributesHTML = nullptr;
1591 delete sElementsSVG;
1592 sElementsSVG = nullptr;
1594 delete sAttributesSVG;
1595 sAttributesSVG = nullptr;
1597 delete sElementsMathML;
1598 sElementsMathML = nullptr;
1600 delete sAttributesMathML;
1601 sAttributesMathML = nullptr;
1603 NS_IF_RELEASE(sNullPrincipal);
1606 void nsTreeSanitizer::WithWebSanitizerOptions(
1607 const mozilla::dom::SanitizerConfig& aOptions) {
1608 if (!aOptions.IsAnyMemberPresent()) {
1609 return;
1611 if (aOptions.mAllowComments.WasPassed()) {
1612 mAllowComments = aOptions.mAllowComments.Value();
1614 if (aOptions.mAllowElements.WasPassed()) {
1615 mIsCustomized = true;
1616 const Sequence<nsString>& allowedElements = aOptions.mAllowElements.Value();
1617 mAllowedElements = MakeUnique<DynamicAtomsTable>(allowedElements.Length());
1618 for (const nsString& elem : allowedElements) {
1619 nsAutoString lowercaseElem;
1620 nsContentUtils::ASCIIToLower(elem, lowercaseElem);
1621 RefPtr<nsAtom> elAsAtom = NS_Atomize(lowercaseElem);
1622 mAllowedElements->Insert(elAsAtom);
1624 } else {
1625 mAllowedElements = nullptr;
1627 if (aOptions.mBlockElements.WasPassed()) {
1628 mIsCustomized = true;
1629 const Sequence<nsString>& blockedElements = aOptions.mBlockElements.Value();
1630 mBlockedElements = MakeUnique<DynamicAtomsTable>(blockedElements.Length());
1631 for (const nsString& elem : blockedElements) {
1632 nsAutoString lowercaseElem;
1633 nsContentUtils::ASCIIToLower(elem, lowercaseElem);
1634 RefPtr<nsAtom> elAsAtom = NS_Atomize(lowercaseElem);
1635 mBlockedElements->Insert(elAsAtom);
1637 } else {
1638 mBlockedElements = nullptr;
1640 if (aOptions.mAllowAttributes.WasPassed()) {
1641 mIsCustomized = true;
1642 const Record<nsString, Sequence<nsString>>& allowedAttributes =
1643 aOptions.mAllowAttributes.Value();
1644 mAllowedAttributes = MakeUnique<
1645 nsTHashMap<RefPtr<nsAtom>, mozilla::UniquePtr<DynamicAtomsTable>>>();
1646 nsAutoString name;
1647 for (const auto& entries : allowedAttributes.Entries()) {
1648 UniquePtr<DynamicAtomsTable> elems =
1649 MakeUnique<DynamicAtomsTable>(allowedAttributes.Entries().Length());
1650 for (const auto& elem : entries.mValue) {
1651 nsAutoString lowercaseElem;
1652 nsContentUtils::ASCIIToLower(elem, lowercaseElem);
1653 RefPtr<nsAtom> elAsAtom = NS_Atomize(lowercaseElem);
1654 elems->Insert(elAsAtom);
1656 nsAutoString attrName;
1657 nsContentUtils::ASCIIToLower(entries.mKey, attrName);
1658 RefPtr<nsAtom> attrAtom = NS_Atomize(attrName);
1659 mAllowedAttributes->InsertOrUpdate(attrAtom, std::move(elems));
1661 } else {
1662 mAllowedAttributes = nullptr;
1664 if (aOptions.mDropAttributes.WasPassed()) {
1665 mIsCustomized = true;
1666 const Record<nsString, Sequence<nsString>>& droppedAttributes =
1667 aOptions.mDropAttributes.Value();
1668 mDroppedAttributes = MakeUnique<
1669 nsTHashMap<RefPtr<nsAtom>, mozilla::UniquePtr<DynamicAtomsTable>>>();
1670 nsAutoString name;
1671 for (const auto& entries : droppedAttributes.Entries()) {
1672 UniquePtr<DynamicAtomsTable> elems =
1673 MakeUnique<DynamicAtomsTable>(droppedAttributes.Entries().Length());
1674 for (const auto& elem : entries.mValue) {
1675 nsAutoString lowercaseElem;
1676 nsContentUtils::ASCIIToLower(elem, lowercaseElem);
1677 RefPtr<nsAtom> elAsAtom = NS_Atomize(lowercaseElem);
1678 elems->Insert(elAsAtom);
1680 nsAutoString attrName;
1681 nsContentUtils::ASCIIToLower(entries.mKey, attrName);
1682 RefPtr<nsAtom> attrAtom = NS_Atomize(attrName);
1683 mDroppedAttributes->InsertOrUpdate(attrAtom, std::move(elems));
1685 } else {
1686 mDroppedAttributes = nullptr;
1688 // TODO(freddy) Add handling of other keys in SanitizerConfig