Line data Source code
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/. */
6 :
7 : #include "mozilla/AsyncEventDispatcher.h"
8 : #include "mozilla/dom/HTMLMetaElement.h"
9 : #include "mozilla/dom/HTMLMetaElementBinding.h"
10 : #include "mozilla/dom/nsCSPService.h"
11 : #include "nsContentUtils.h"
12 : #include "nsStyleConsts.h"
13 : #include "nsIContentSecurityPolicy.h"
14 :
15 4 : NS_IMPL_NS_NEW_HTML_ELEMENT(Meta)
16 :
17 : namespace mozilla {
18 : namespace dom {
19 :
20 2 : HTMLMetaElement::HTMLMetaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
21 2 : : nsGenericHTMLElement(aNodeInfo)
22 : {
23 2 : }
24 :
25 0 : HTMLMetaElement::~HTMLMetaElement()
26 : {
27 0 : }
28 :
29 :
30 108 : NS_IMPL_ISUPPORTS_INHERITED(HTMLMetaElement, nsGenericHTMLElement,
31 : nsIDOMHTMLMetaElement)
32 :
33 0 : NS_IMPL_ELEMENT_CLONE(HTMLMetaElement)
34 :
35 :
36 0 : NS_IMPL_STRING_ATTR(HTMLMetaElement, Content, content)
37 0 : NS_IMPL_STRING_ATTR(HTMLMetaElement, HttpEquiv, httpEquiv)
38 0 : NS_IMPL_STRING_ATTR(HTMLMetaElement, Name, name)
39 0 : NS_IMPL_STRING_ATTR(HTMLMetaElement, Scheme, scheme)
40 :
41 : nsresult
42 4 : HTMLMetaElement::SetMetaReferrer(nsIDocument* aDocument)
43 : {
44 6 : if (!aDocument ||
45 2 : !AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::referrer, eIgnoreCase)) {
46 4 : return NS_OK;
47 : }
48 0 : nsAutoString content;
49 0 : nsresult rv = GetContent(content);
50 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
51 0 : return rv;
52 : }
53 0 : Element* headElt = aDocument->GetHeadElement();
54 0 : if (headElt && nsContentUtils::ContentIsDescendantOf(this, headElt)) {
55 0 : content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(content);
56 0 : aDocument->SetHeaderData(nsGkAtoms::referrer, content);
57 : }
58 0 : return NS_OK;
59 : }
60 :
61 : nsresult
62 2 : HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
63 : const nsAttrValue* aValue,
64 : const nsAttrValue* aOldValue, bool aNotify)
65 : {
66 2 : if (aNameSpaceID == kNameSpaceID_None) {
67 2 : nsIDocument *document = GetUncomposedDoc();
68 2 : if (aName == nsGkAtoms::content) {
69 0 : if (document && AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
70 : nsGkAtoms::viewport, eIgnoreCase)) {
71 0 : nsAutoString content;
72 0 : nsresult rv = GetContent(content);
73 0 : NS_ENSURE_SUCCESS(rv, rv);
74 0 : nsContentUtils::ProcessViewportInfo(document, content);
75 : }
76 0 : CreateAndDispatchEvent(document, NS_LITERAL_STRING("DOMMetaChanged"));
77 : }
78 : // Update referrer policy when it got changed from JS
79 2 : nsresult rv = SetMetaReferrer(document);
80 2 : if (NS_WARN_IF(NS_FAILED(rv))) {
81 0 : return rv;
82 : }
83 : }
84 :
85 2 : return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName, aValue,
86 2 : aOldValue, aNotify);
87 : }
88 :
89 : nsresult
90 2 : HTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
91 : nsIContent* aBindingParent,
92 : bool aCompileEventHandlers)
93 : {
94 2 : nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
95 : aBindingParent,
96 2 : aCompileEventHandlers);
97 2 : NS_ENSURE_SUCCESS(rv, rv);
98 4 : if (aDocument &&
99 2 : AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::viewport, eIgnoreCase)) {
100 0 : nsAutoString content;
101 0 : rv = GetContent(content);
102 0 : NS_ENSURE_SUCCESS(rv, rv);
103 0 : nsContentUtils::ProcessViewportInfo(aDocument, content);
104 : }
105 :
106 4 : if (CSPService::sCSPEnabled && aDocument &&
107 2 : AttrValueIs(kNameSpaceID_None, nsGkAtoms::httpEquiv, nsGkAtoms::headerCSP, eIgnoreCase)) {
108 :
109 : // only accept <meta http-equiv="Content-Security-Policy" content=""> if it appears
110 : // in the <head> element.
111 0 : Element* headElt = aDocument->GetHeadElement();
112 0 : if (headElt && nsContentUtils::ContentIsDescendantOf(this, headElt)) {
113 :
114 0 : nsAutoString content;
115 0 : rv = GetContent(content);
116 0 : NS_ENSURE_SUCCESS(rv, rv);
117 0 : content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(content);
118 :
119 0 : nsIPrincipal* principal = aDocument->NodePrincipal();
120 0 : nsCOMPtr<nsIContentSecurityPolicy> csp;
121 0 : nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDocument);
122 0 : principal->EnsureCSP(domDoc, getter_AddRefs(csp));
123 0 : if (csp) {
124 : // Multiple CSPs (delivered through either header of meta tag) need to be
125 : // joined together, see:
126 : // https://w3c.github.io/webappsec/specs/content-security-policy/#delivery-html-meta-element
127 0 : rv = csp->AppendPolicy(content,
128 : false, // csp via meta tag can not be report only
129 0 : true); // delivered through the meta tag
130 0 : NS_ENSURE_SUCCESS(rv, rv);
131 0 : aDocument->ApplySettingsFromCSP(false);
132 : }
133 : }
134 : }
135 :
136 : // Referrer Policy spec requires a <meta name="referrer" tag to be in the
137 : // <head> element.
138 2 : rv = SetMetaReferrer(aDocument);
139 2 : if (NS_WARN_IF(NS_FAILED(rv))) {
140 0 : return rv;
141 : }
142 2 : CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMMetaAdded"));
143 2 : return rv;
144 : }
145 :
146 : void
147 0 : HTMLMetaElement::UnbindFromTree(bool aDeep, bool aNullParent)
148 : {
149 0 : nsCOMPtr<nsIDocument> oldDoc = GetUncomposedDoc();
150 0 : CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMMetaRemoved"));
151 0 : nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
152 0 : }
153 :
154 : void
155 2 : HTMLMetaElement::CreateAndDispatchEvent(nsIDocument* aDoc,
156 : const nsAString& aEventName)
157 : {
158 2 : if (!aDoc)
159 0 : return;
160 :
161 : RefPtr<AsyncEventDispatcher> asyncDispatcher =
162 4 : new AsyncEventDispatcher(this, aEventName, true, true);
163 2 : asyncDispatcher->RunDOMEventWhenSafe();
164 : }
165 :
166 : JSObject*
167 0 : HTMLMetaElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
168 : {
169 0 : return HTMLMetaElementBinding::Wrap(aCx, this, aGivenProto);
170 : }
171 :
172 : } // namespace dom
173 : } // namespace mozilla
|