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 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 : #include "nsCOMPtr.h"
39 : #include "nsContentDLF.h"
40 : #include "nsGenericHTMLElement.h"
41 : #include "nsGkAtoms.h"
42 : #include "nsIComponentManager.h"
43 : #include "nsIComponentRegistrar.h"
44 : #include "nsIContentViewer.h"
45 : #include "nsICategoryManager.h"
46 : #include "nsIDocumentLoaderFactory.h"
47 : #include "nsIDocument.h"
48 : #include "nsIURL.h"
49 : #include "nsNodeInfo.h"
50 : #include "nsNodeInfoManager.h"
51 : #include "nsIScriptSecurityManager.h"
52 : #include "nsString.h"
53 : #include "nsContentCID.h"
54 : #include "prprf.h"
55 : #include "nsNetUtil.h"
56 : #include "nsCRT.h"
57 : #include "nsIViewSourceChannel.h"
58 : #ifdef MOZ_MEDIA
59 : #include "nsHTMLMediaElement.h"
60 : #endif
61 : #include "nsContentUtils.h"
62 : #include "imgILoader.h"
63 : #include "nsIParser.h"
64 : #include "nsMimeTypes.h"
65 :
66 : #include "mozilla/FunctionTimer.h"
67 :
68 : // plugins
69 : #include "nsIPluginHost.h"
70 : #include "nsPluginHost.h"
71 : static NS_DEFINE_CID(kPluginDocumentCID, NS_PLUGINDOCUMENT_CID);
72 :
73 : // Factory code for creating variations on html documents
74 :
75 : #undef NOISY_REGISTRY
76 :
77 : static NS_DEFINE_IID(kHTMLDocumentCID, NS_HTMLDOCUMENT_CID);
78 : static NS_DEFINE_IID(kXMLDocumentCID, NS_XMLDOCUMENT_CID);
79 : static NS_DEFINE_IID(kSVGDocumentCID, NS_SVGDOCUMENT_CID);
80 : #ifdef MOZ_MEDIA
81 : static NS_DEFINE_IID(kVideoDocumentCID, NS_VIDEODOCUMENT_CID);
82 : #endif
83 : static NS_DEFINE_IID(kImageDocumentCID, NS_IMAGEDOCUMENT_CID);
84 : static NS_DEFINE_IID(kXULDocumentCID, NS_XULDOCUMENT_CID);
85 :
86 : nsresult
87 : NS_NewContentViewer(nsIContentViewer** aResult);
88 :
89 : // XXXbz if you change the MIME types here, be sure to update
90 : // nsIParser.h and DetermineParseMode in nsParser.cpp and
91 : // nsHTMLDocument::StartDocumentLoad accordingly.
92 : static const char* const gHTMLTypes[] = {
93 : TEXT_HTML,
94 : TEXT_PLAIN,
95 : TEXT_CSS,
96 : TEXT_JAVASCRIPT,
97 : TEXT_ECMASCRIPT,
98 : APPLICATION_JAVASCRIPT,
99 : APPLICATION_ECMASCRIPT,
100 : APPLICATION_XJAVASCRIPT,
101 : APPLICATION_JSON,
102 : VIEWSOURCE_CONTENT_TYPE,
103 : APPLICATION_XHTML_XML,
104 : 0
105 : };
106 :
107 : static const char* const gXMLTypes[] = {
108 : TEXT_XML,
109 : APPLICATION_XML,
110 : APPLICATION_MATHML_XML,
111 : APPLICATION_RDF_XML,
112 : TEXT_RDF,
113 : 0
114 : };
115 :
116 : static const char* const gSVGTypes[] = {
117 : IMAGE_SVG_XML,
118 : 0
119 : };
120 :
121 : static const char* const gXULTypes[] = {
122 : TEXT_XUL,
123 : APPLICATION_CACHED_XUL,
124 : 0
125 : };
126 :
127 : nsresult
128 0 : NS_NewContentDocumentLoaderFactory(nsIDocumentLoaderFactory** aResult)
129 : {
130 0 : NS_PRECONDITION(aResult, "null OUT ptr");
131 0 : if (!aResult) {
132 0 : return NS_ERROR_NULL_POINTER;
133 : }
134 0 : nsContentDLF* it = new nsContentDLF();
135 0 : if (!it) {
136 0 : return NS_ERROR_OUT_OF_MEMORY;
137 : }
138 :
139 0 : return CallQueryInterface(it, aResult);
140 : }
141 :
142 0 : nsContentDLF::nsContentDLF()
143 : {
144 0 : }
145 :
146 0 : nsContentDLF::~nsContentDLF()
147 : {
148 0 : }
149 :
150 0 : NS_IMPL_ISUPPORTS1(nsContentDLF,
151 : nsIDocumentLoaderFactory)
152 :
153 : bool
154 0 : MayUseXULXBL(nsIChannel* aChannel)
155 : {
156 : nsIScriptSecurityManager *securityManager =
157 0 : nsContentUtils::GetSecurityManager();
158 0 : if (!securityManager) {
159 0 : return false;
160 : }
161 :
162 0 : nsCOMPtr<nsIPrincipal> principal;
163 0 : securityManager->GetChannelPrincipal(aChannel, getter_AddRefs(principal));
164 0 : NS_ENSURE_TRUE(principal, false);
165 :
166 0 : return nsContentUtils::AllowXULXBLForPrincipal(principal);
167 : }
168 :
169 : NS_IMETHODIMP
170 0 : nsContentDLF::CreateInstance(const char* aCommand,
171 : nsIChannel* aChannel,
172 : nsILoadGroup* aLoadGroup,
173 : const char* aContentType,
174 : nsISupports* aContainer,
175 : nsISupports* aExtraInfo,
176 : nsIStreamListener** aDocListener,
177 : nsIContentViewer** aDocViewer)
178 : {
179 : #ifdef NS_FUNCTION_TIMER
180 : nsCAutoString channelURL__("N/A");
181 : nsCOMPtr<nsIURI> url__;
182 : if (aChannel && NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(url__)))) {
183 : url__->GetSpec(channelURL__);
184 : }
185 : NS_TIME_FUNCTION_FMT("%s (line %d) (url: %s)", MOZ_FUNCTION_NAME,
186 : __LINE__, channelURL__.get());
187 : #endif
188 :
189 : // Declare "type" here. This is because although the variable itself only
190 : // needs limited scope, we need to use the raw string memory -- as returned
191 : // by "type.get()" farther down in the function.
192 0 : nsCAutoString type;
193 :
194 : // Are we viewing source?
195 0 : nsCOMPtr<nsIViewSourceChannel> viewSourceChannel = do_QueryInterface(aChannel);
196 0 : if (viewSourceChannel)
197 : {
198 0 : aCommand = "view-source";
199 :
200 : // The parser freaks out when it sees the content-type that a
201 : // view-source channel normally returns. Get the actual content
202 : // type of the data. If it's known, use it; otherwise use
203 : // text/plain.
204 0 : viewSourceChannel->GetOriginalContentType(type);
205 0 : bool knownType = false;
206 : PRInt32 typeIndex;
207 0 : for (typeIndex = 0; gHTMLTypes[typeIndex] && !knownType; ++typeIndex) {
208 0 : if (type.Equals(gHTMLTypes[typeIndex]) &&
209 0 : !type.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE)) {
210 0 : knownType = true;
211 : }
212 : }
213 :
214 0 : for (typeIndex = 0; gXMLTypes[typeIndex] && !knownType; ++typeIndex) {
215 0 : if (type.Equals(gXMLTypes[typeIndex])) {
216 0 : knownType = true;
217 : }
218 : }
219 :
220 0 : for (typeIndex = 0; gSVGTypes[typeIndex] && !knownType; ++typeIndex) {
221 0 : if (type.Equals(gSVGTypes[typeIndex])) {
222 0 : knownType = true;
223 : }
224 : }
225 :
226 0 : for (typeIndex = 0; gXULTypes[typeIndex] && !knownType; ++typeIndex) {
227 0 : if (type.Equals(gXULTypes[typeIndex])) {
228 0 : knownType = true;
229 : }
230 : }
231 :
232 0 : if (knownType) {
233 0 : viewSourceChannel->SetContentType(type);
234 0 : } else if (IsImageContentType(type.get())) {
235 : // If it's an image, we want to display it the same way we normally would.
236 : // Also note the lifetime of "type" allows us to safely use "get()" here.
237 0 : aContentType = type.get();
238 : } else {
239 0 : viewSourceChannel->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN));
240 : }
241 0 : } else if (0 == PL_strcmp(VIEWSOURCE_CONTENT_TYPE, aContentType)) {
242 0 : aChannel->SetContentType(NS_LITERAL_CSTRING(TEXT_PLAIN));
243 0 : aContentType = TEXT_PLAIN;
244 : }
245 : // Try html
246 0 : int typeIndex=0;
247 0 : while(gHTMLTypes[typeIndex]) {
248 0 : if (0 == PL_strcmp(gHTMLTypes[typeIndex++], aContentType)) {
249 : return CreateDocument(aCommand,
250 : aChannel, aLoadGroup,
251 : aContainer, kHTMLDocumentCID,
252 0 : aDocListener, aDocViewer);
253 : }
254 : }
255 :
256 : // Try XML
257 0 : typeIndex = 0;
258 0 : while(gXMLTypes[typeIndex]) {
259 0 : if (0== PL_strcmp(gXMLTypes[typeIndex++], aContentType)) {
260 : return CreateDocument(aCommand,
261 : aChannel, aLoadGroup,
262 : aContainer, kXMLDocumentCID,
263 0 : aDocListener, aDocViewer);
264 : }
265 : }
266 :
267 : // Try SVG
268 0 : typeIndex = 0;
269 0 : while(gSVGTypes[typeIndex]) {
270 0 : if (!PL_strcmp(gSVGTypes[typeIndex++], aContentType)) {
271 : return CreateDocument(aCommand,
272 : aChannel, aLoadGroup,
273 : aContainer, kSVGDocumentCID,
274 0 : aDocListener, aDocViewer);
275 : }
276 : }
277 :
278 : // Try XUL
279 0 : typeIndex = 0;
280 0 : while (gXULTypes[typeIndex]) {
281 0 : if (0 == PL_strcmp(gXULTypes[typeIndex++], aContentType)) {
282 0 : if (!MayUseXULXBL(aChannel)) {
283 0 : return NS_ERROR_REMOTE_XUL;
284 : }
285 :
286 : return CreateXULDocument(aCommand,
287 : aChannel, aLoadGroup,
288 : aContentType, aContainer,
289 0 : aExtraInfo, aDocListener, aDocViewer);
290 : }
291 : }
292 :
293 : #ifdef MOZ_MEDIA
294 0 : if (nsHTMLMediaElement::ShouldHandleMediaType(aContentType)) {
295 : return CreateDocument(aCommand,
296 : aChannel, aLoadGroup,
297 : aContainer, kVideoDocumentCID,
298 0 : aDocListener, aDocViewer);
299 : }
300 : #endif
301 :
302 : // Try image types
303 0 : if (IsImageContentType(aContentType)) {
304 : return CreateDocument(aCommand,
305 : aChannel, aLoadGroup,
306 : aContainer, kImageDocumentCID,
307 0 : aDocListener, aDocViewer);
308 : }
309 :
310 0 : nsCOMPtr<nsIPluginHost> pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID));
311 0 : nsPluginHost *pluginHost = static_cast<nsPluginHost*>(pluginHostCOM.get());
312 0 : if(pluginHost &&
313 0 : NS_SUCCEEDED(pluginHost->IsPluginEnabledForType(aContentType))) {
314 : return CreateDocument(aCommand,
315 : aChannel, aLoadGroup,
316 : aContainer, kPluginDocumentCID,
317 0 : aDocListener, aDocViewer);
318 : }
319 :
320 : // If we get here, then we weren't able to create anything. Sorry!
321 0 : return NS_ERROR_FAILURE;
322 : }
323 :
324 :
325 : NS_IMETHODIMP
326 0 : nsContentDLF::CreateInstanceForDocument(nsISupports* aContainer,
327 : nsIDocument* aDocument,
328 : const char *aCommand,
329 : nsIContentViewer** aContentViewer)
330 : {
331 : NS_TIME_FUNCTION;
332 :
333 0 : nsCOMPtr<nsIContentViewer> contentViewer;
334 0 : nsresult rv = NS_NewContentViewer(getter_AddRefs(contentViewer));
335 0 : NS_ENSURE_SUCCESS(rv, rv);
336 :
337 : // Bind the document to the Content Viewer
338 0 : rv = contentViewer->LoadStart(aDocument);
339 0 : contentViewer.forget(aContentViewer);
340 0 : return rv;
341 : }
342 :
343 : NS_IMETHODIMP
344 0 : nsContentDLF::CreateBlankDocument(nsILoadGroup *aLoadGroup,
345 : nsIPrincipal* aPrincipal,
346 : nsIDocument **aDocument)
347 : {
348 : NS_TIME_FUNCTION;
349 :
350 0 : *aDocument = nsnull;
351 :
352 0 : nsresult rv = NS_ERROR_FAILURE;
353 :
354 : // create a new blank HTML document
355 0 : nsCOMPtr<nsIDocument> blankDoc(do_CreateInstance(kHTMLDocumentCID));
356 :
357 0 : if (blankDoc) {
358 : // initialize
359 0 : nsCOMPtr<nsIURI> uri;
360 0 : NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:blank"));
361 0 : if (uri) {
362 0 : blankDoc->ResetToURI(uri, aLoadGroup, aPrincipal);
363 0 : rv = NS_OK;
364 : }
365 : }
366 :
367 : // add some simple content structure
368 0 : if (NS_SUCCEEDED(rv)) {
369 0 : rv = NS_ERROR_FAILURE;
370 :
371 0 : nsNodeInfoManager *nim = blankDoc->NodeInfoManager();
372 :
373 0 : nsCOMPtr<nsINodeInfo> htmlNodeInfo;
374 :
375 : // generate an html html element
376 : htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::html, 0, kNameSpaceID_XHTML,
377 0 : nsIDOMNode::ELEMENT_NODE);
378 : nsCOMPtr<nsIContent> htmlElement =
379 0 : NS_NewHTMLHtmlElement(htmlNodeInfo.forget());
380 :
381 : // generate an html head element
382 : htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::head, 0, kNameSpaceID_XHTML,
383 0 : nsIDOMNode::ELEMENT_NODE);
384 : nsCOMPtr<nsIContent> headElement =
385 0 : NS_NewHTMLHeadElement(htmlNodeInfo.forget());
386 :
387 : // generate an html body elemment
388 : htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::body, 0, kNameSpaceID_XHTML,
389 0 : nsIDOMNode::ELEMENT_NODE);
390 : nsCOMPtr<nsIContent> bodyElement =
391 0 : NS_NewHTMLBodyElement(htmlNodeInfo.forget());
392 :
393 : // blat in the structure
394 0 : if (htmlElement && headElement && bodyElement) {
395 0 : NS_ASSERTION(blankDoc->GetChildCount() == 0,
396 : "Shouldn't have children");
397 0 : rv = blankDoc->AppendChildTo(htmlElement, false);
398 0 : if (NS_SUCCEEDED(rv)) {
399 0 : rv = htmlElement->AppendChildTo(headElement, false);
400 :
401 0 : if (NS_SUCCEEDED(rv)) {
402 : // XXXbz Why not notifying here?
403 0 : htmlElement->AppendChildTo(bodyElement, false);
404 : }
405 : }
406 : }
407 : }
408 :
409 : // add a nice bow
410 0 : if (NS_SUCCEEDED(rv)) {
411 0 : blankDoc->SetDocumentCharacterSetSource(kCharsetFromDocTypeDefault);
412 0 : blankDoc->SetDocumentCharacterSet(NS_LITERAL_CSTRING("UTF-8"));
413 :
414 0 : *aDocument = blankDoc;
415 0 : NS_ADDREF(*aDocument);
416 : }
417 0 : return rv;
418 : }
419 :
420 :
421 : nsresult
422 0 : nsContentDLF::CreateDocument(const char* aCommand,
423 : nsIChannel* aChannel,
424 : nsILoadGroup* aLoadGroup,
425 : nsISupports* aContainer,
426 : const nsCID& aDocumentCID,
427 : nsIStreamListener** aDocListener,
428 : nsIContentViewer** aContentViewer)
429 : {
430 : NS_TIME_FUNCTION;
431 :
432 0 : nsresult rv = NS_ERROR_FAILURE;
433 :
434 0 : nsCOMPtr<nsIURI> aURL;
435 0 : rv = aChannel->GetURI(getter_AddRefs(aURL));
436 0 : if (NS_FAILED(rv)) return rv;
437 :
438 : #ifdef NOISY_CREATE_DOC
439 : if (nsnull != aURL) {
440 : nsAutoString tmp;
441 : aURL->ToString(tmp);
442 : fputs(NS_LossyConvertUTF16toASCII(tmp).get(), stdout);
443 : printf(": creating document\n");
444 : }
445 : #endif
446 :
447 : // Create the document
448 0 : nsCOMPtr<nsIDocument> doc = do_CreateInstance(aDocumentCID, &rv);
449 0 : NS_ENSURE_SUCCESS(rv, rv);
450 :
451 : // Create the content viewer XXX: could reuse content viewer here!
452 0 : nsCOMPtr<nsIContentViewer> contentViewer;
453 0 : rv = NS_NewContentViewer(getter_AddRefs(contentViewer));
454 0 : NS_ENSURE_SUCCESS(rv, rv);
455 :
456 0 : doc->SetContainer(aContainer);
457 :
458 : // Initialize the document to begin loading the data. An
459 : // nsIStreamListener connected to the parser is returned in
460 : // aDocListener.
461 0 : rv = doc->StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, aDocListener, true);
462 0 : NS_ENSURE_SUCCESS(rv, rv);
463 :
464 : // Bind the document to the Content Viewer
465 0 : rv = contentViewer->LoadStart(doc);
466 0 : contentViewer.forget(aContentViewer);
467 0 : return rv;
468 : }
469 :
470 : nsresult
471 0 : nsContentDLF::CreateXULDocument(const char* aCommand,
472 : nsIChannel* aChannel,
473 : nsILoadGroup* aLoadGroup,
474 : const char* aContentType,
475 : nsISupports* aContainer,
476 : nsISupports* aExtraInfo,
477 : nsIStreamListener** aDocListener,
478 : nsIContentViewer** aContentViewer)
479 : {
480 : NS_TIME_FUNCTION;
481 :
482 : nsresult rv;
483 0 : nsCOMPtr<nsIDocument> doc = do_CreateInstance(kXULDocumentCID, &rv);
484 0 : if (NS_FAILED(rv)) return rv;
485 :
486 0 : nsCOMPtr<nsIContentViewer> contentViewer;
487 0 : rv = NS_NewContentViewer(getter_AddRefs(contentViewer));
488 0 : if (NS_FAILED(rv)) return rv;
489 :
490 0 : nsCOMPtr<nsIURI> aURL;
491 0 : rv = aChannel->GetURI(getter_AddRefs(aURL));
492 0 : if (NS_FAILED(rv)) return rv;
493 :
494 : /*
495 : * Initialize the document to begin loading the data...
496 : *
497 : * An nsIStreamListener connected to the parser is returned in
498 : * aDocListener.
499 : */
500 :
501 0 : doc->SetContainer(aContainer);
502 :
503 0 : rv = doc->StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer, aDocListener, true);
504 0 : if (NS_FAILED(rv)) return rv;
505 :
506 : /*
507 : * Bind the document to the Content Viewer...
508 : */
509 0 : rv = contentViewer->LoadStart(doc);
510 0 : contentViewer.forget(aContentViewer);
511 0 : return rv;
512 : }
513 :
514 0 : bool nsContentDLF::IsImageContentType(const char* aContentType) {
515 0 : nsCOMPtr<imgILoader> loader(do_GetService("@mozilla.org/image/loader;1"));
516 0 : bool isDecoderAvailable = false;
517 0 : loader->SupportImageWithMimeType(aContentType, &isDecoderAvailable);
518 0 : return isDecoderAvailable;
519 : }
|