/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 | } |