Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/build/nsContentDLF.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
#include "nsContentDLF.h"
7
8
#include "mozilla/Encoding.h"
9
10
#include "nsCOMPtr.h"
11
#include "nsDocShell.h"
12
#include "nsGenericHTMLElement.h"
13
#include "nsGkAtoms.h"
14
#include "nsIComponentManager.h"
15
#include "nsIComponentRegistrar.h"
16
#include "nsIContentViewer.h"
17
#include "nsICategoryManager.h"
18
#include "nsIDocumentLoaderFactory.h"
19
#include "nsIDocument.h"
20
#include "nsIURL.h"
21
#include "nsNodeInfoManager.h"
22
#include "nsIScriptSecurityManager.h"
23
#include "nsString.h"
24
#include "nsContentCID.h"
25
#include "nsNetUtil.h"
26
#include "nsCRT.h"
27
#include "nsIViewSourceChannel.h"
28
#include "nsContentUtils.h"
29
#include "imgLoader.h"
30
#include "nsCharsetSource.h"
31
#include "nsMimeTypes.h"
32
#include "DecoderTraits.h"
33
#ifdef MOZ_XUL
34
#include "XULDocument.h"
35
#endif
36
37
38
// plugins
39
#include "nsIPluginHost.h"
40
#include "nsPluginHost.h"
41
42
// Factory code for creating variations on html documents
43
44
#undef NOISY_REGISTRY
45
46
already_AddRefed<nsIContentViewer> NS_NewContentViewer();
47
48
static const char* const gHTMLTypes[] = {
49
  TEXT_HTML,
50
  VIEWSOURCE_CONTENT_TYPE,
51
  APPLICATION_XHTML_XML,
52
  APPLICATION_WAPXHTML_XML,
53
  0
54
};
55
56
static const char* const gXMLTypes[] = {
57
  TEXT_XML,
58
  APPLICATION_XML,
59
  APPLICATION_MATHML_XML,
60
  APPLICATION_RDF_XML,
61
  TEXT_RDF,
62
  0
63
};
64
65
static const char* const gSVGTypes[] = {
66
  IMAGE_SVG_XML,
67
  0
68
};
69
70
static const char* const gXULTypes[] = {
71
  TEXT_XUL,
72
  APPLICATION_CACHED_XUL,
73
  0
74
};
75
76
static bool
77
IsTypeInList(const nsACString& aType, const char* const aList[])
78
0
{
79
0
  int32_t typeIndex;
80
0
  for (typeIndex = 0; aList[typeIndex]; ++typeIndex) {
81
0
    if (aType.Equals(aList[typeIndex])) {
82
0
      return true;
83
0
    }
84
0
  }
85
0
86
0
  return false;
87
0
}
88
89
nsresult
90
NS_NewContentDocumentLoaderFactory(nsIDocumentLoaderFactory** aResult)
91
0
{
92
0
  MOZ_ASSERT(aResult, "null OUT ptr");
93
0
  if (!aResult) {
94
0
    return NS_ERROR_NULL_POINTER;
95
0
  }
96
0
  nsContentDLF* it = new nsContentDLF();
97
0
  if (!it) {
98
0
    return NS_ERROR_OUT_OF_MEMORY;
99
0
  }
100
0
101
0
  return CallQueryInterface(it, aResult);
102
0
}
103
104
nsContentDLF::nsContentDLF()
105
0
{
106
0
}
107
108
nsContentDLF::~nsContentDLF()
109
0
{
110
0
}
111
112
NS_IMPL_ISUPPORTS(nsContentDLF,
113
                  nsIDocumentLoaderFactory)
114
115
static bool
116
MayUseXULXBL(nsIChannel* aChannel)
117
0
{
118
0
  nsIScriptSecurityManager *securityManager =
119
0
    nsContentUtils::GetSecurityManager();
120
0
  if (!securityManager) {
121
0
    return false;
122
0
  }
123
0
124
0
  nsCOMPtr<nsIPrincipal> principal;
125
0
  securityManager->GetChannelResultPrincipal(aChannel, getter_AddRefs(principal));
126
0
  NS_ENSURE_TRUE(principal, false);
127
0
128
0
  return nsContentUtils::AllowXULXBLForPrincipal(principal);
129
0
}
130
131
NS_IMETHODIMP
132
nsContentDLF::CreateInstance(const char* aCommand,
133
                             nsIChannel* aChannel,
134
                             nsILoadGroup* aLoadGroup,
135
                             const nsACString& aContentType,
136
                             nsIDocShell* aContainer,
137
                             nsISupports* aExtraInfo,
138
                             nsIStreamListener** aDocListener,
139
                             nsIContentViewer** aDocViewer)
140
0
{
141
0
  // Make a copy of aContentType, because we're possibly going to change it.
142
0
  nsAutoCString contentType(aContentType);
143
0
144
0
  // Are we viewing source?
145
0
  nsCOMPtr<nsIViewSourceChannel> viewSourceChannel = do_QueryInterface(aChannel);
146
0
  if (viewSourceChannel)
147
0
  {
148
0
    aCommand = "view-source";
149
0
150
0
    // The parser freaks out when it sees the content-type that a
151
0
    // view-source channel normally returns.  Get the actual content
152
0
    // type of the data.  If it's known, use it; otherwise use
153
0
    // text/plain.
154
0
    nsAutoCString type;
155
0
    mozilla::Unused << viewSourceChannel->GetOriginalContentType(type);
156
0
    bool knownType =
157
0
      (!type.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE) &&
158
0
        IsTypeInList(type, gHTMLTypes)) ||
159
0
      nsContentUtils::IsPlainTextType(type) ||
160
0
      IsTypeInList(type, gXMLTypes) ||
161
0
      IsTypeInList(type, gSVGTypes) ||
162
0
      IsTypeInList(type, gXMLTypes);
163
0
164
0
    if (knownType) {
165
0
      viewSourceChannel->SetContentType(type);
166
0
    } else if (IsImageContentType(type.get())) {
167
0
      // If it's an image, we want to display it the same way we normally would.
168
0
      // Also note the lifetime of "type" allows us to safely use "get()" here.
169
0
      contentType = type;
170
0
    } else {
171
0
      viewSourceChannel->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN));
172
0
    }
173
0
  } else if (aContentType.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE)) {
174
0
    aChannel->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN));
175
0
    contentType = TEXT_PLAIN;
176
0
  }
177
0
178
0
  // Try html or plaintext; both use the same document CID
179
0
  if (IsTypeInList(contentType, gHTMLTypes) ||
180
0
      nsContentUtils::IsPlainTextType(contentType)) {
181
0
    return CreateDocument(aCommand,
182
0
                          aChannel, aLoadGroup,
183
0
                          aContainer, [] () -> already_AddRefed<nsIDocument> {
184
0
                            nsCOMPtr<nsIDocument> doc;
185
0
                            nsresult rv = NS_NewHTMLDocument(getter_AddRefs(doc));
186
0
                            NS_ENSURE_SUCCESS(rv, nullptr);
187
0
                            return doc.forget();
188
0
                          },
189
0
                          aDocListener, aDocViewer);
190
0
  }
191
0
192
0
  // Try XML
193
0
  if (IsTypeInList(contentType, gXMLTypes)) {
194
0
    return CreateDocument(aCommand,
195
0
                          aChannel, aLoadGroup,
196
0
                          aContainer, [] () -> already_AddRefed<nsIDocument> {
197
0
                            nsCOMPtr<nsIDocument> doc;
198
0
                            nsresult rv = NS_NewXMLDocument(getter_AddRefs(doc));
199
0
                            NS_ENSURE_SUCCESS(rv, nullptr);
200
0
                            return doc.forget();
201
0
                          },
202
0
                          aDocListener, aDocViewer);
203
0
  }
204
0
205
0
  // Try SVG
206
0
  if (IsTypeInList(contentType, gSVGTypes)) {
207
0
    return CreateDocument(aCommand,
208
0
                          aChannel, aLoadGroup,
209
0
                          aContainer, [] () -> already_AddRefed<nsIDocument> {
210
0
                            nsCOMPtr<nsIDocument> doc;
211
0
                            nsresult rv = NS_NewSVGDocument(getter_AddRefs(doc));
212
0
                            NS_ENSURE_SUCCESS(rv, nullptr);
213
0
                            return doc.forget();
214
0
                          },
215
0
                          aDocListener, aDocViewer);
216
0
  }
217
0
218
0
  // Try XUL
219
0
  if (IsTypeInList(contentType, gXULTypes)) {
220
0
    if (!MayUseXULXBL(aChannel)) {
221
0
      return NS_ERROR_REMOTE_XUL;
222
0
    }
223
0
224
0
    return CreateXULDocument(aCommand, aChannel, aLoadGroup, aContainer,
225
0
                             aExtraInfo, aDocListener, aDocViewer);
226
0
  }
227
0
228
0
  if (mozilla::DecoderTraits::ShouldHandleMediaType(contentType.get(),
229
0
                    /* DecoderDoctorDiagnostics* */ nullptr)) {
230
0
    return CreateDocument(aCommand,
231
0
                          aChannel, aLoadGroup,
232
0
                          aContainer, [] () -> already_AddRefed<nsIDocument> {
233
0
                            nsCOMPtr<nsIDocument> doc;
234
0
                            nsresult rv = NS_NewVideoDocument(getter_AddRefs(doc));
235
0
                            NS_ENSURE_SUCCESS(rv, nullptr);
236
0
                            return doc.forget();
237
0
                          },
238
0
                          aDocListener, aDocViewer);
239
0
  }
240
0
241
0
  // Try image types
242
0
  if (IsImageContentType(contentType.get())) {
243
0
    return CreateDocument(aCommand,
244
0
                          aChannel, aLoadGroup,
245
0
                          aContainer, [] () -> already_AddRefed<nsIDocument> {
246
0
                            nsCOMPtr<nsIDocument> doc;
247
0
                            nsresult rv = NS_NewImageDocument(getter_AddRefs(doc));
248
0
                            NS_ENSURE_SUCCESS(rv, nullptr);
249
0
                            return doc.forget();
250
0
                          },
251
0
                          aDocListener, aDocViewer);
252
0
  }
253
0
254
0
  RefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
255
0
  // Don't exclude disabled plugins, which will still trigger the "this plugin
256
0
  // is disabled" placeholder.
257
0
  if (pluginHost && pluginHost->HavePluginForType(contentType,
258
0
                                                  nsPluginHost::eExcludeNone)) {
259
0
    return CreateDocument(aCommand,
260
0
                          aChannel, aLoadGroup,
261
0
                          aContainer, [] () -> already_AddRefed<nsIDocument> {
262
0
                            nsCOMPtr<nsIDocument> doc;
263
0
                            nsresult rv = NS_NewPluginDocument(getter_AddRefs(doc));
264
0
                            NS_ENSURE_SUCCESS(rv, nullptr);
265
0
                            return doc.forget();
266
0
                          },
267
0
                          aDocListener, aDocViewer);
268
0
  }
269
0
270
0
  // If we get here, then we weren't able to create anything. Sorry!
271
0
  return NS_ERROR_FAILURE;
272
0
}
273
274
275
NS_IMETHODIMP
276
nsContentDLF::CreateInstanceForDocument(nsISupports* aContainer,
277
                                        nsIDocument* aDocument,
278
                                        const char *aCommand,
279
                                        nsIContentViewer** aContentViewer)
280
0
{
281
0
  MOZ_ASSERT(aDocument);
282
0
283
0
  nsCOMPtr<nsIContentViewer> contentViewer = NS_NewContentViewer();
284
0
285
0
  // Bind the document to the Content Viewer
286
0
  contentViewer->LoadStart(aDocument);
287
0
  contentViewer.forget(aContentViewer);
288
0
  return NS_OK;
289
0
}
290
291
/* static */ already_AddRefed<nsIDocument>
292
nsContentDLF::CreateBlankDocument(nsILoadGroup* aLoadGroup,
293
                                  nsIPrincipal* aPrincipal,
294
                                  nsDocShell* aContainer)
295
0
{
296
0
  // create a new blank HTML document
297
0
  nsCOMPtr<nsIDocument> blankDoc;
298
0
  mozilla::Unused << NS_NewHTMLDocument(getter_AddRefs(blankDoc));
299
0
300
0
  if (!blankDoc) {
301
0
    return nullptr;
302
0
  }
303
0
304
0
  // initialize
305
0
  nsCOMPtr<nsIURI> uri;
306
0
  NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:blank"));
307
0
  if (!uri) {
308
0
    return nullptr;
309
0
  }
310
0
  blankDoc->ResetToURI(uri, aLoadGroup, aPrincipal);
311
0
  blankDoc->SetContainer(aContainer);
312
0
313
0
  // add some simple content structure
314
0
  nsNodeInfoManager *nim = blankDoc->NodeInfoManager();
315
0
316
0
  RefPtr<mozilla::dom::NodeInfo> htmlNodeInfo;
317
0
318
0
  // generate an html html element
319
0
  htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::html, 0, kNameSpaceID_XHTML,
320
0
                                  nsINode::ELEMENT_NODE);
321
0
  nsCOMPtr<nsIContent> htmlElement =
322
0
    NS_NewHTMLHtmlElement(htmlNodeInfo.forget());
323
0
324
0
  // generate an html head element
325
0
  htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::head, 0, kNameSpaceID_XHTML,
326
0
                                  nsINode::ELEMENT_NODE);
327
0
  nsCOMPtr<nsIContent> headElement =
328
0
    NS_NewHTMLHeadElement(htmlNodeInfo.forget());
329
0
330
0
  // generate an html body elemment
331
0
  htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::body, 0, kNameSpaceID_XHTML,
332
0
                                  nsINode::ELEMENT_NODE);
333
0
  nsCOMPtr<nsIContent> bodyElement =
334
0
    NS_NewHTMLBodyElement(htmlNodeInfo.forget());
335
0
336
0
  // blat in the structure
337
0
  NS_ASSERTION(blankDoc->GetChildCount() == 0,
338
0
                "Shouldn't have children");
339
0
  if (!htmlElement || !headElement || !bodyElement ||
340
0
      NS_FAILED(blankDoc->AppendChildTo(htmlElement, false)) ||
341
0
      NS_FAILED(htmlElement->AppendChildTo(headElement, false)) ||
342
0
      // XXXbz Why not notifying here?
343
0
      NS_FAILED(htmlElement->AppendChildTo(bodyElement, false))) {
344
0
    return nullptr;
345
0
  }
346
0
347
0
  // add a nice bow
348
0
  blankDoc->SetDocumentCharacterSetSource(kCharsetFromDocTypeDefault);
349
0
  blankDoc->SetDocumentCharacterSet(UTF_8_ENCODING);
350
0
  return blankDoc.forget();
351
0
}
352
353
nsresult
354
nsContentDLF::CreateDocument(const char* aCommand,
355
                             nsIChannel* aChannel,
356
                             nsILoadGroup* aLoadGroup,
357
                             nsIDocShell* aContainer,
358
                             nsContentDLF::DocumentCreator
359
                               aDocumentCreator,
360
                             nsIStreamListener** aDocListener,
361
                             nsIContentViewer** aContentViewer)
362
0
{
363
0
  MOZ_ASSERT(aDocumentCreator);
364
0
365
0
  nsresult rv = NS_ERROR_FAILURE;
366
0
367
0
  nsCOMPtr<nsIURI> aURL;
368
0
  rv = aChannel->GetURI(getter_AddRefs(aURL));
369
0
  if (NS_FAILED(rv)) return rv;
370
0
371
#ifdef NOISY_CREATE_DOC
372
  if (nullptr != aURL) {
373
    nsAutoString tmp;
374
    aURL->ToString(tmp);
375
    fputs(NS_LossyConvertUTF16toASCII(tmp).get(), stdout);
376
    printf(": creating document\n");
377
  }
378
#endif
379
380
0
  // Create the document
381
0
  nsCOMPtr<nsIDocument> doc = aDocumentCreator();
382
0
  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
383
0
384
0
  // Create the content viewer  XXX: could reuse content viewer here!
385
0
  nsCOMPtr<nsIContentViewer> contentViewer = NS_NewContentViewer();
386
0
387
0
  doc->SetContainer(static_cast<nsDocShell*>(aContainer));
388
0
389
0
  // Initialize the document to begin loading the data.  An
390
0
  // nsIStreamListener connected to the parser is returned in
391
0
  // aDocListener.
392
0
  rv = doc->StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, aDocListener, true);
393
0
  NS_ENSURE_SUCCESS(rv, rv);
394
0
395
0
  // Bind the document to the Content Viewer
396
0
  contentViewer->LoadStart(doc);
397
0
  contentViewer.forget(aContentViewer);
398
0
  return NS_OK;
399
0
}
400
401
nsresult
402
nsContentDLF::CreateXULDocument(const char* aCommand,
403
                                nsIChannel* aChannel,
404
                                nsILoadGroup* aLoadGroup,
405
                                nsIDocShell* aContainer,
406
                                nsISupports* aExtraInfo,
407
                                nsIStreamListener** aDocListener,
408
                                nsIContentViewer** aContentViewer)
409
0
{
410
0
  nsCOMPtr<nsIDocument> doc;
411
0
  nsresult rv = NS_NewXULDocument(getter_AddRefs(doc));
412
0
  if (NS_FAILED(rv)) return rv;
413
0
414
0
  nsCOMPtr<nsIContentViewer> contentViewer = NS_NewContentViewer();
415
0
416
0
  nsCOMPtr<nsIURI> aURL;
417
0
  rv = aChannel->GetURI(getter_AddRefs(aURL));
418
0
  if (NS_FAILED(rv)) return rv;
419
0
420
0
  /*
421
0
   * Initialize the document to begin loading the data...
422
0
   *
423
0
   * An nsIStreamListener connected to the parser is returned in
424
0
   * aDocListener.
425
0
   */
426
0
427
0
  doc->SetContainer(static_cast<nsDocShell*>(aContainer));
428
0
429
0
  rv = doc->StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, aDocListener, true);
430
0
  if (NS_FAILED(rv)) return rv;
431
0
432
0
  /*
433
0
   * Bind the document to the Content Viewer...
434
0
   */
435
0
  contentViewer->LoadStart(doc);
436
0
  contentViewer.forget(aContentViewer);
437
0
  return NS_OK;
438
0
}
439
440
0
bool nsContentDLF::IsImageContentType(const char* aContentType) {
441
0
  return imgLoader::SupportImageWithMimeType(aContentType);
442
0
}