Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/html/HTMLSharedElement.cpp
Line
Count
Source (jump to first uncovered line)
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/dom/HTMLSharedElement.h"
8
#include "mozilla/dom/HTMLBaseElementBinding.h"
9
#include "mozilla/dom/HTMLDirectoryElementBinding.h"
10
#include "mozilla/dom/HTMLHeadElementBinding.h"
11
#include "mozilla/dom/HTMLHtmlElementBinding.h"
12
#include "mozilla/dom/HTMLParamElementBinding.h"
13
#include "mozilla/dom/HTMLQuoteElementBinding.h"
14
15
#include "mozilla/AsyncEventDispatcher.h"
16
#include "mozilla/MappedDeclarations.h"
17
#include "nsAttrValueInlines.h"
18
#include "nsStyleConsts.h"
19
#include "nsMappedAttributes.h"
20
#include "nsContentUtils.h"
21
#include "nsIContentSecurityPolicy.h"
22
#include "nsIURI.h"
23
24
NS_IMPL_NS_NEW_HTML_ELEMENT(Shared)
25
26
namespace mozilla {
27
namespace dom {
28
29
extern nsAttrValue::EnumTable kListTypeTable[];
30
31
HTMLSharedElement::~HTMLSharedElement()
32
0
{
33
0
}
34
35
NS_IMPL_ELEMENT_CLONE(HTMLSharedElement)
36
37
void
38
HTMLSharedElement::GetHref(nsAString& aValue)
39
0
{
40
0
  MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::base),
41
0
             "This should only get called for <base> elements");
42
0
  nsAutoString href;
43
0
  GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
44
0
45
0
  nsCOMPtr<nsIURI> uri;
46
0
  nsIDocument* doc = OwnerDoc();
47
0
  nsContentUtils::NewURIWithDocumentCharset(
48
0
    getter_AddRefs(uri), href, doc, doc->GetFallbackBaseURI());
49
0
50
0
  if (!uri) {
51
0
    aValue = href;
52
0
    return;
53
0
  }
54
0
55
0
  nsAutoCString spec;
56
0
  uri->GetSpec(spec);
57
0
  CopyUTF8toUTF16(spec, aValue);
58
0
}
59
60
void
61
HTMLSharedElement::DoneAddingChildren(bool aHaveNotified)
62
0
{
63
0
  if (mNodeInfo->Equals(nsGkAtoms::head)) {
64
0
    nsCOMPtr<nsIDocument> doc = GetUncomposedDoc();
65
0
    if (doc) {
66
0
      doc->OnL10nResourceContainerParsed();
67
0
    }
68
0
69
0
    RefPtr<AsyncEventDispatcher> asyncDispatcher =
70
0
      new AsyncEventDispatcher(this,
71
0
                              NS_LITERAL_STRING("DOMHeadElementParsed"),
72
0
                              CanBubble::eYes,
73
0
                              ChromeOnlyDispatch::eYes);
74
0
    // Always run async in order to avoid running script when the content
75
0
    // sink isn't expecting it.
76
0
    asyncDispatcher->PostDOMEvent();
77
0
  }
78
0
}
79
80
bool
81
HTMLSharedElement::ParseAttribute(int32_t aNamespaceID,
82
                                  nsAtom* aAttribute,
83
                                  const nsAString& aValue,
84
                                  nsIPrincipal* aMaybeScriptedPrincipal,
85
                                  nsAttrValue& aResult)
86
0
{
87
0
  if (aNamespaceID == kNameSpaceID_None &&
88
0
      mNodeInfo->Equals(nsGkAtoms::dir)) {
89
0
    if (aAttribute == nsGkAtoms::type) {
90
0
      return aResult.ParseEnumValue(aValue, mozilla::dom::kListTypeTable, false);
91
0
    }
92
0
    if (aAttribute == nsGkAtoms::start) {
93
0
      return aResult.ParseIntWithBounds(aValue, 1);
94
0
    }
95
0
  }
96
0
97
0
  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
98
0
                                              aMaybeScriptedPrincipal, aResult);
99
0
}
100
101
static void
102
DirectoryMapAttributesIntoRule(const nsMappedAttributes* aAttributes,
103
                               MappedDeclarations& aDecls)
104
0
{
105
0
  if (!aDecls.PropertyIsSet(eCSSProperty_list_style_type)) {
106
0
    // type: enum
107
0
    const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
108
0
    if (value) {
109
0
      if (value->Type() == nsAttrValue::eEnum) {
110
0
        aDecls.SetKeywordValue(eCSSProperty_list_style_type, value->GetEnumValue());
111
0
      } else {
112
0
        aDecls.SetKeywordValue(eCSSProperty_list_style_type, NS_STYLE_LIST_STYLE_DISC);
113
0
      }
114
0
    }
115
0
  }
116
0
117
0
  nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
118
0
}
119
120
NS_IMETHODIMP_(bool)
121
HTMLSharedElement::IsAttributeMapped(const nsAtom* aAttribute) const
122
0
{
123
0
  if (mNodeInfo->Equals(nsGkAtoms::dir)) {
124
0
    static const MappedAttributeEntry attributes[] = {
125
0
      { &nsGkAtoms::type },
126
0
      // { &nsGkAtoms::compact }, // XXX
127
0
      { nullptr}
128
0
    };
129
0
130
0
    static const MappedAttributeEntry* const map[] = {
131
0
      attributes,
132
0
      sCommonAttributeMap,
133
0
    };
134
0
135
0
    return FindAttributeDependence(aAttribute, map);
136
0
  }
137
0
138
0
  return nsGenericHTMLElement::IsAttributeMapped(aAttribute);
139
0
}
140
141
static void
142
SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch)
143
0
{
144
0
  MOZ_ASSERT(aDocument, "Need a document!");
145
0
146
0
  for (nsIContent* child = aDocument->GetFirstChild(); child;
147
0
       child = child->GetNextNode()) {
148
0
    if (child->IsHTMLElement(nsGkAtoms::base) &&
149
0
        child->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
150
0
      if (aMustMatch && child != aMustMatch) {
151
0
        return;
152
0
      }
153
0
154
0
      // Resolve the <base> element's href relative to our document's
155
0
      // fallback base URI.
156
0
      nsAutoString href;
157
0
      child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
158
0
159
0
      nsCOMPtr<nsIURI> newBaseURI;
160
0
      nsContentUtils::NewURIWithDocumentCharset(
161
0
        getter_AddRefs(newBaseURI), href, aDocument,
162
0
        aDocument->GetFallbackBaseURI());
163
0
164
0
      // Check if CSP allows this base-uri
165
0
      nsCOMPtr<nsIContentSecurityPolicy> csp;
166
0
      nsresult rv = aDocument->NodePrincipal()->GetCsp(getter_AddRefs(csp));
167
0
      NS_ASSERTION(NS_SUCCEEDED(rv), "Getting CSP Failed");
168
0
      // For all the different error cases we assign a nullptr to
169
0
      // newBaseURI, so we basically call aDocument->SetBaseURI(nullptr);
170
0
      if (NS_FAILED(rv)) {
171
0
        newBaseURI = nullptr;
172
0
      }
173
0
      if (csp && newBaseURI) {
174
0
        // base-uri is only enforced if explicitly defined in the
175
0
        // policy - do *not* consult default-src, see:
176
0
        // http://www.w3.org/TR/CSP2/#directive-default-src
177
0
        bool cspPermitsBaseURI = true;
178
0
        rv = csp->Permits(child->AsElement(), newBaseURI,
179
0
                          nsIContentSecurityPolicy::BASE_URI_DIRECTIVE,
180
0
                          true, &cspPermitsBaseURI);
181
0
        if (NS_FAILED(rv) || !cspPermitsBaseURI) {
182
0
          newBaseURI = nullptr;
183
0
        }
184
0
      }
185
0
      aDocument->SetBaseURI(newBaseURI);
186
0
      aDocument->SetChromeXHRDocBaseURI(nullptr);
187
0
      return;
188
0
    }
189
0
  }
190
0
191
0
  aDocument->SetBaseURI(nullptr);
192
0
}
193
194
static void
195
SetBaseTargetUsingFirstBaseWithTarget(nsIDocument* aDocument,
196
                                      nsIContent* aMustMatch)
197
0
{
198
0
  MOZ_ASSERT(aDocument, "Need a document!");
199
0
200
0
  for (nsIContent* child = aDocument->GetFirstChild(); child;
201
0
       child = child->GetNextNode()) {
202
0
    if (child->IsHTMLElement(nsGkAtoms::base) &&
203
0
        child->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::target)) {
204
0
      if (aMustMatch && child != aMustMatch) {
205
0
        return;
206
0
      }
207
0
208
0
      nsString target;
209
0
      child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::target, target);
210
0
      aDocument->SetBaseTarget(target);
211
0
      return;
212
0
    }
213
0
  }
214
0
215
0
  aDocument->SetBaseTarget(EmptyString());
216
0
}
217
218
nsresult
219
HTMLSharedElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
220
                                const nsAttrValue* aValue,
221
                                const nsAttrValue* aOldValue,
222
                                nsIPrincipal* aSubjectPrincipal,
223
                                bool aNotify)
224
0
{
225
0
  if (aNamespaceID == kNameSpaceID_None) {
226
0
    if (aName == nsGkAtoms::href) {
227
0
      // If the href attribute of a <base> tag is changing, we may need to
228
0
      // update the document's base URI, which will cause all the links on the
229
0
      // page to be re-resolved given the new base.
230
0
      // If the href is being unset (aValue is null), we will need to find a new
231
0
      // <base>.
232
0
      if (mNodeInfo->Equals(nsGkAtoms::base) && IsInUncomposedDoc()) {
233
0
        SetBaseURIUsingFirstBaseWithHref(GetUncomposedDoc(),
234
0
                                         aValue ? this : nullptr);
235
0
      }
236
0
    } else if (aName == nsGkAtoms::target) {
237
0
      // The target attribute is in pretty much the same situation as the href
238
0
      // attribute, above.
239
0
      if (mNodeInfo->Equals(nsGkAtoms::base) && IsInUncomposedDoc()) {
240
0
        SetBaseTargetUsingFirstBaseWithTarget(GetUncomposedDoc(),
241
0
                                              aValue ? this : nullptr);
242
0
      }
243
0
    }
244
0
  }
245
0
246
0
  return nsGenericHTMLElement::AfterSetAttr(aNamespaceID, aName, aValue,
247
0
                                            aOldValue, aSubjectPrincipal, aNotify);
248
0
}
249
250
nsresult
251
HTMLSharedElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
252
                              nsIContent* aBindingParent)
253
0
{
254
0
  nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
255
0
                                                 aBindingParent);
256
0
  NS_ENSURE_SUCCESS(rv, rv);
257
0
258
0
  // The document stores a pointer to its base URI and base target, which we may
259
0
  // need to update here.
260
0
  if (mNodeInfo->Equals(nsGkAtoms::base) &&
261
0
      aDocument) {
262
0
    if (HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
263
0
      SetBaseURIUsingFirstBaseWithHref(aDocument, this);
264
0
    }
265
0
    if (HasAttr(kNameSpaceID_None, nsGkAtoms::target)) {
266
0
      SetBaseTargetUsingFirstBaseWithTarget(aDocument, this);
267
0
    }
268
0
  }
269
0
270
0
  return NS_OK;
271
0
}
272
273
void
274
HTMLSharedElement::UnbindFromTree(bool aDeep, bool aNullParent)
275
0
{
276
0
  nsIDocument* doc = GetUncomposedDoc();
277
0
278
0
  nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
279
0
280
0
  // If we're removing a <base> from a document, we may need to update the
281
0
  // document's base URI and base target
282
0
  if (doc && mNodeInfo->Equals(nsGkAtoms::base)) {
283
0
    if (HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
284
0
      SetBaseURIUsingFirstBaseWithHref(doc, nullptr);
285
0
    }
286
0
    if (HasAttr(kNameSpaceID_None, nsGkAtoms::target)) {
287
0
      SetBaseTargetUsingFirstBaseWithTarget(doc, nullptr);
288
0
    }
289
0
  }
290
0
}
291
292
nsMapRuleToAttributesFunc
293
HTMLSharedElement::GetAttributeMappingFunction() const
294
0
{
295
0
  if (mNodeInfo->Equals(nsGkAtoms::dir)) {
296
0
    return &DirectoryMapAttributesIntoRule;
297
0
  }
298
0
299
0
  return nsGenericHTMLElement::GetAttributeMappingFunction();
300
0
}
301
302
JSObject*
303
HTMLSharedElement::WrapNode(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
304
0
{
305
0
  if (mNodeInfo->Equals(nsGkAtoms::param)) {
306
0
    return HTMLParamElement_Binding::Wrap(aCx, this, aGivenProto);
307
0
  }
308
0
  if (mNodeInfo->Equals(nsGkAtoms::base)) {
309
0
    return HTMLBaseElement_Binding::Wrap(aCx, this, aGivenProto);
310
0
  }
311
0
  if (mNodeInfo->Equals(nsGkAtoms::dir)) {
312
0
    return HTMLDirectoryElement_Binding::Wrap(aCx, this, aGivenProto);
313
0
  }
314
0
  if (mNodeInfo->Equals(nsGkAtoms::q) ||
315
0
      mNodeInfo->Equals(nsGkAtoms::blockquote)) {
316
0
    return HTMLQuoteElement_Binding::Wrap(aCx, this, aGivenProto);
317
0
  }
318
0
  if (mNodeInfo->Equals(nsGkAtoms::head)) {
319
0
    return HTMLHeadElement_Binding::Wrap(aCx, this, aGivenProto);
320
0
  }
321
0
  MOZ_ASSERT(mNodeInfo->Equals(nsGkAtoms::html));
322
0
  return HTMLHtmlElement_Binding::Wrap(aCx, this, aGivenProto);
323
0
}
324
325
} // namespace dom
326
} // namespace mozilla