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