content/base/src/DOMParser.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/dom/DOMParser.h"
     8 #include "nsIDOMDocument.h"
     9 #include "nsNetUtil.h"
    10 #include "nsStringStream.h"
    11 #include "nsIScriptSecurityManager.h"
    12 #include "nsCRT.h"
    13 #include "nsStreamUtils.h"
    14 #include "nsContentUtils.h"
    15 #include "nsDOMJSUtils.h"
    16 #include "nsError.h"
    17 #include "nsPIDOMWindow.h"
    18 #include "mozilla/dom/BindingUtils.h"
    20 using namespace mozilla;
    21 using namespace mozilla::dom;
    23 DOMParser::DOMParser()
    24   : mAttemptedInit(false)
    25 {
    26   SetIsDOMBinding();
    27 }
    29 DOMParser::~DOMParser()
    30 {
    31 }
    33 // QueryInterface implementation for DOMParser
    34 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMParser)
    35   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    36   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMParser)
    37   NS_INTERFACE_MAP_ENTRY(nsIDOMParser)
    38   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
    39 NS_INTERFACE_MAP_END
    41 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMParser, mOwner)
    43 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMParser)
    44 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMParser)
    46 static const char*
    47 StringFromSupportedType(SupportedType aType)
    48 {
    49   return SupportedTypeValues::strings[static_cast<int>(aType)].value;
    50 }
    52 already_AddRefed<nsIDocument>
    53 DOMParser::ParseFromString(const nsAString& aStr, SupportedType aType,
    54                            ErrorResult& rv)
    55 {
    56   nsCOMPtr<nsIDOMDocument> domDocument;
    57   rv = ParseFromString(aStr,
    58                        StringFromSupportedType(aType),
    59                        getter_AddRefs(domDocument));
    60   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
    61   return document.forget();
    62 }
    64 NS_IMETHODIMP 
    65 DOMParser::ParseFromString(const char16_t *str, 
    66                            const char *contentType,
    67                            nsIDOMDocument **aResult)
    68 {
    69   NS_ENSURE_ARG(str);
    70   // Converting a string to an enum value manually is a bit of a pain,
    71   // so let's just use a helper that takes a content-type string.
    72   return ParseFromString(nsDependentString(str), contentType, aResult);
    73 }
    75 nsresult
    76 DOMParser::ParseFromString(const nsAString& str,
    77                            const char *contentType,
    78                            nsIDOMDocument **aResult)
    79 {
    80   NS_ENSURE_ARG_POINTER(aResult);
    82   nsresult rv;
    84   if (!nsCRT::strcmp(contentType, "text/html")) {
    85     nsCOMPtr<nsIDOMDocument> domDocument;
    86     rv = SetUpDocument(DocumentFlavorHTML, getter_AddRefs(domDocument));
    87     NS_ENSURE_SUCCESS(rv, rv);
    88     nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
    90     // Keep the XULXBL state, base URL and principal setting in sync with the
    91     // XML case
    93     if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) {
    94       document->ForceEnableXULXBL();
    95     }
    97     // Make sure to give this document the right base URI
    98     document->SetBaseURI(mBaseURI);
    99     // And the right principal
   100     document->SetPrincipal(mPrincipal);
   102     rv = nsContentUtils::ParseDocumentHTML(str, document, false);
   103     NS_ENSURE_SUCCESS(rv, rv);
   105     domDocument.forget(aResult);
   106     return rv;
   107   }
   109   nsAutoCString utf8str;
   110   // Convert from UTF16 to UTF8 using fallible allocations
   111   if (!AppendUTF16toUTF8(str, utf8str, mozilla::fallible_t())) {
   112     return NS_ERROR_OUT_OF_MEMORY;
   113   }
   115   // The new stream holds a reference to the buffer
   116   nsCOMPtr<nsIInputStream> stream;
   117   rv = NS_NewByteInputStream(getter_AddRefs(stream),
   118                              utf8str.get(), utf8str.Length(),
   119                              NS_ASSIGNMENT_DEPEND);
   120   if (NS_FAILED(rv))
   121     return rv;
   123   return ParseFromStream(stream, "UTF-8", utf8str.Length(), contentType, aResult);
   124 }
   126 already_AddRefed<nsIDocument>
   127 DOMParser::ParseFromBuffer(const Sequence<uint8_t>& aBuf, uint32_t aBufLen,
   128                            SupportedType aType, ErrorResult& rv)
   129 {
   130   if (aBufLen > aBuf.Length()) {
   131     rv.Throw(NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY);
   132     return nullptr;
   133   }
   134   nsCOMPtr<nsIDOMDocument> domDocument;
   135   rv = DOMParser::ParseFromBuffer(aBuf.Elements(), aBufLen,
   136                                   StringFromSupportedType(aType),
   137                                   getter_AddRefs(domDocument));
   138   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   139   return document.forget();
   140 }
   142 already_AddRefed<nsIDocument>
   143 DOMParser::ParseFromBuffer(const Uint8Array& aBuf, uint32_t aBufLen,
   144                            SupportedType aType, ErrorResult& rv)
   145 {
   146   aBuf.ComputeLengthAndData();
   148   if (aBufLen > aBuf.Length()) {
   149     rv.Throw(NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY);
   150     return nullptr;
   151   }
   152   nsCOMPtr<nsIDOMDocument> domDocument;
   153   rv = DOMParser::ParseFromBuffer(aBuf.Data(), aBufLen,
   154                                     StringFromSupportedType(aType),
   155                                     getter_AddRefs(domDocument));
   156   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   157   return document.forget();
   158 }
   160 NS_IMETHODIMP 
   161 DOMParser::ParseFromBuffer(const uint8_t *buf,
   162                            uint32_t bufLen,
   163                            const char *contentType,
   164                            nsIDOMDocument **aResult)
   165 {
   166   NS_ENSURE_ARG_POINTER(buf);
   167   NS_ENSURE_ARG_POINTER(aResult);
   169   // The new stream holds a reference to the buffer
   170   nsCOMPtr<nsIInputStream> stream;
   171   nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream),
   172                                       reinterpret_cast<const char *>(buf),
   173                                       bufLen, NS_ASSIGNMENT_DEPEND);
   174   if (NS_FAILED(rv))
   175     return rv;
   177   return ParseFromStream(stream, nullptr, bufLen, contentType, aResult);
   178 }
   181 already_AddRefed<nsIDocument>
   182 DOMParser::ParseFromStream(nsIInputStream* aStream,
   183                            const nsAString& aCharset,
   184                            int32_t aContentLength,
   185                            SupportedType aType,
   186                            ErrorResult& rv)
   187 {
   188   nsCOMPtr<nsIDOMDocument> domDocument;
   189   rv = DOMParser::ParseFromStream(aStream,
   190                                   NS_ConvertUTF16toUTF8(aCharset).get(),
   191                                   aContentLength,
   192                                   StringFromSupportedType(aType),
   193                                   getter_AddRefs(domDocument));
   194   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   195   return document.forget();
   196 }
   198 NS_IMETHODIMP 
   199 DOMParser::ParseFromStream(nsIInputStream *stream, 
   200                            const char *charset, 
   201                            int32_t contentLength,
   202                            const char *contentType,
   203                            nsIDOMDocument **aResult)
   204 {
   205   NS_ENSURE_ARG(stream);
   206   NS_ENSURE_ARG(contentType);
   207   NS_ENSURE_ARG_POINTER(aResult);
   208   *aResult = nullptr;
   210   bool svg = nsCRT::strcmp(contentType, "image/svg+xml") == 0;
   212   // For now, we can only create XML documents.
   213   //XXXsmaug Should we create an HTMLDocument (in XHTML mode)
   214   //         for "application/xhtml+xml"?
   215   if ((nsCRT::strcmp(contentType, "text/xml") != 0) &&
   216       (nsCRT::strcmp(contentType, "application/xml") != 0) &&
   217       (nsCRT::strcmp(contentType, "application/xhtml+xml") != 0) &&
   218       !svg)
   219     return NS_ERROR_NOT_IMPLEMENTED;
   221   nsresult rv;
   223   // Put the nsCOMPtr out here so we hold a ref to the stream as needed
   224   nsCOMPtr<nsIInputStream> bufferedStream;
   225   if (!NS_InputStreamIsBuffered(stream)) {
   226     rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream,
   227                                    4096);
   228     NS_ENSURE_SUCCESS(rv, rv);
   230     stream = bufferedStream;
   231   }
   233   nsCOMPtr<nsIDOMDocument> domDocument;
   234   rv = SetUpDocument(svg ? DocumentFlavorSVG : DocumentFlavorLegacyGuess,
   235                      getter_AddRefs(domDocument));
   236   NS_ENSURE_SUCCESS(rv, rv);
   238   // Create a fake channel 
   239   nsCOMPtr<nsIChannel> parserChannel;
   240   NS_NewInputStreamChannel(getter_AddRefs(parserChannel), mDocumentURI, nullptr,
   241                            nsDependentCString(contentType), nullptr);
   242   NS_ENSURE_STATE(parserChannel);
   244   // More principal-faking here 
   245   parserChannel->SetOwner(mOriginalPrincipal);
   247   if (charset) {
   248     parserChannel->SetContentCharset(nsDependentCString(charset));
   249   }
   251   // Tell the document to start loading
   252   nsCOMPtr<nsIStreamListener> listener;
   254   // Have to pass false for reset here, else the reset will remove
   255   // our event listener.  Should that listener addition move to later
   256   // than this call?  Then we wouldn't need to mess around with
   257   // SetPrincipal, etc, probably!
   258   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDocument));
   259   if (!document) return NS_ERROR_FAILURE;
   261   // Keep the XULXBL state, base URL and principal setting in sync with the
   262   // HTML case
   264   if (nsContentUtils::IsSystemPrincipal(mOriginalPrincipal)) {
   265     document->ForceEnableXULXBL();
   266   }
   268   rv = document->StartDocumentLoad(kLoadAsData, parserChannel, 
   269                                    nullptr, nullptr, 
   270                                    getter_AddRefs(listener),
   271                                    false);
   273   // Make sure to give this document the right base URI
   274   document->SetBaseURI(mBaseURI);
   276   // And the right principal
   277   document->SetPrincipal(mPrincipal);
   279   if (NS_FAILED(rv) || !listener) {
   280     return NS_ERROR_FAILURE;
   281   }
   283   // Now start pumping data to the listener
   284   nsresult status;
   286   rv = listener->OnStartRequest(parserChannel, nullptr);
   287   if (NS_FAILED(rv))
   288     parserChannel->Cancel(rv);
   289   parserChannel->GetStatus(&status);
   291   if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(status)) {
   292     rv = listener->OnDataAvailable(parserChannel, nullptr, stream, 0,
   293                                    contentLength);
   294     if (NS_FAILED(rv))
   295       parserChannel->Cancel(rv);
   296     parserChannel->GetStatus(&status);
   297   }
   299   rv = listener->OnStopRequest(parserChannel, nullptr, status);
   300   // Failure returned from OnStopRequest does not affect the final status of
   301   // the channel, so we do not need to call Cancel(rv) as we do above.
   303   if (NS_FAILED(rv)) {
   304     return NS_ERROR_FAILURE;
   305   }
   307   domDocument.swap(*aResult);
   309   return NS_OK;
   310 }
   312 NS_IMETHODIMP
   313 DOMParser::Init(nsIPrincipal* principal, nsIURI* documentURI,
   314                 nsIURI* baseURI, nsIScriptGlobalObject* aScriptObject)
   315 {
   316   NS_ENSURE_STATE(!mAttemptedInit);
   317   mAttemptedInit = true;
   319   NS_ENSURE_ARG(principal || documentURI);
   321   mDocumentURI = documentURI;
   323   if (!mDocumentURI) {
   324     principal->GetURI(getter_AddRefs(mDocumentURI));
   325     // If we have the system principal, then we'll just use the null principals
   326     // uri.
   327     if (!mDocumentURI && !nsContentUtils::IsSystemPrincipal(principal)) {
   328       return NS_ERROR_INVALID_ARG;
   329     }
   330   }
   332   mScriptHandlingObject = do_GetWeakReference(aScriptObject);
   333   mPrincipal = principal;
   334   nsresult rv;
   335   if (!mPrincipal) {
   336     nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   337     NS_ENSURE_TRUE(secMan, NS_ERROR_NOT_AVAILABLE);
   338     rv =
   339       secMan->GetSimpleCodebasePrincipal(mDocumentURI,
   340                                          getter_AddRefs(mPrincipal));
   341     NS_ENSURE_SUCCESS(rv, rv);
   342     mOriginalPrincipal = mPrincipal;
   343   } else {
   344     mOriginalPrincipal = mPrincipal;
   345     if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
   346       // Don't give DOMParsers the system principal.  Use a null
   347       // principal instead.
   348       mPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
   349       NS_ENSURE_SUCCESS(rv, rv);
   351       if (!mDocumentURI) {
   352         rv = mPrincipal->GetURI(getter_AddRefs(mDocumentURI));
   353         NS_ENSURE_SUCCESS(rv, rv);
   354       }
   355     }
   356   }
   358   mBaseURI = baseURI;
   359   // Note: if mBaseURI is null, fine.  Leave it like that; that will use the
   360   // documentURI as the base.  Otherwise for null principals we'll get
   361   // nsDocument::SetBaseURI giving errors.
   363   NS_POSTCONDITION(mPrincipal, "Must have principal");
   364   NS_POSTCONDITION(mOriginalPrincipal, "Must have original principal");
   365   NS_POSTCONDITION(mDocumentURI, "Must have document URI");
   366   return NS_OK;
   367 }
   369 /*static */already_AddRefed<DOMParser>
   370 DOMParser::Constructor(const GlobalObject& aOwner,
   371                        nsIPrincipal* aPrincipal, nsIURI* aDocumentURI,
   372                        nsIURI* aBaseURI, ErrorResult& rv)
   373 {
   374   if (!nsContentUtils::IsCallerChrome()) {
   375     rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   376     return nullptr;
   377   }
   378   nsRefPtr<DOMParser> domParser = new DOMParser(aOwner.GetAsSupports());
   379   rv = domParser->InitInternal(aOwner.GetAsSupports(), aPrincipal, aDocumentURI,
   380                                aBaseURI);
   381   if (rv.Failed()) {
   382     return nullptr;
   383   }
   384   return domParser.forget();
   385 }
   387 /*static */already_AddRefed<DOMParser>
   388 DOMParser::Constructor(const GlobalObject& aOwner,
   389                        ErrorResult& rv)
   390 {
   391   nsCOMPtr<nsIPrincipal> prin;
   392   nsCOMPtr<nsIURI> documentURI;
   393   nsCOMPtr<nsIURI> baseURI;
   394   // No arguments; use the subject principal
   395   nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   396   if (!secMan) {
   397     rv.Throw(NS_ERROR_UNEXPECTED);
   398     return nullptr;
   399   }
   401   rv = secMan->GetSubjectPrincipal(getter_AddRefs(prin));
   402   if (rv.Failed()) {
   403     return nullptr;
   404   }
   406   // We're called from JS; there better be a subject principal, really.
   407   if (!prin) {
   408     rv.Throw(NS_ERROR_UNEXPECTED);
   409     return nullptr;
   410   }
   412   nsRefPtr<DOMParser> domParser = new DOMParser(aOwner.GetAsSupports());
   413   rv = domParser->InitInternal(aOwner.GetAsSupports(), prin, documentURI, baseURI);
   414   if (rv.Failed()) {
   415     return nullptr;
   416   }
   417   return domParser.forget();
   418 }
   420 nsresult
   421 DOMParser::InitInternal(nsISupports* aOwner, nsIPrincipal* prin,
   422                         nsIURI* documentURI, nsIURI* baseURI)
   423 {
   424   AttemptedInitMarker marker(&mAttemptedInit);
   425   if (!documentURI) {
   426     // No explicit documentURI; grab document and base URIs off the window our
   427     // constructor was called on. Error out if anything untoward happens.
   429     // Note that this is a behavior change as far as I can tell -- we're now
   430     // using the base URI and document URI of the window off of which the
   431     // DOMParser is created, not the window in which parse*() is called.
   432     // Does that matter?
   434     // Also note that |cx| matches what GetDocumentFromContext() would return,
   435     // while GetDocumentFromCaller() gives us the window that the DOMParser()
   436     // call was made on.
   438     nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aOwner);
   439     if (!window) {
   440       return NS_ERROR_UNEXPECTED;
   441     }
   443     baseURI = window->GetDocBaseURI();
   444     documentURI = window->GetDocumentURI();
   445     if (!documentURI) {
   446       return NS_ERROR_UNEXPECTED;
   447     }
   448   }
   450   nsCOMPtr<nsIScriptGlobalObject> scriptglobal = do_QueryInterface(aOwner);
   451   return Init(prin, documentURI, baseURI, scriptglobal);
   452 }
   454 void
   455 DOMParser::Init(nsIPrincipal* aPrincipal, nsIURI* aDocumentURI,
   456                 nsIURI* aBaseURI, mozilla::ErrorResult& rv)
   457 {
   458   AttemptedInitMarker marker(&mAttemptedInit);
   460   JSContext *cx = nsContentUtils::GetCurrentJSContext();
   461   if (!cx) {
   462     rv.Throw(NS_ERROR_UNEXPECTED);
   463     return;
   464   }
   466   nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
   468   nsCOMPtr<nsIPrincipal> principal = aPrincipal;
   470   if (!principal && !aDocumentURI) {
   471     nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
   472     if (!secMan) {
   473       rv.Throw(NS_ERROR_UNEXPECTED);
   474       return;
   475     }
   477     rv = secMan->GetSubjectPrincipal(getter_AddRefs(principal));
   478     if (rv.Failed()) {
   479       return;
   480     }
   482     // We're called from JS; there better be a subject principal, really.
   483     if (!principal) {
   484       rv.Throw(NS_ERROR_UNEXPECTED);
   485       return;
   486     }
   487   }
   489   rv = Init(principal, aDocumentURI, aBaseURI,
   490             scriptContext ? scriptContext->GetGlobalObject() : nullptr);
   491 }
   493 nsresult
   494 DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult)
   495 {
   496   nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
   497     do_QueryReferent(mScriptHandlingObject);
   498   nsresult rv;
   499   if (!mPrincipal) {
   500     NS_ENSURE_TRUE(!mAttemptedInit, NS_ERROR_NOT_INITIALIZED);
   501     AttemptedInitMarker marker(&mAttemptedInit);
   503     nsCOMPtr<nsIPrincipal> prin =
   504       do_CreateInstance("@mozilla.org/nullprincipal;1", &rv);
   505     NS_ENSURE_SUCCESS(rv, rv);
   507     rv = Init(prin, nullptr, nullptr, scriptHandlingObject);
   508     NS_ENSURE_SUCCESS(rv, rv);
   509   }
   511   NS_ASSERTION(mPrincipal, "Must have principal by now");
   512   NS_ASSERTION(mDocumentURI, "Must have document URI by now");
   514   // Here we have to cheat a little bit...  Setting the base URI won't
   515   // work if the document has a null principal, so use
   516   // mOriginalPrincipal when creating the document, then reset the
   517   // principal.
   518   return NS_NewDOMDocument(aResult, EmptyString(), EmptyString(), nullptr,
   519                            mDocumentURI, mBaseURI,
   520                            mOriginalPrincipal,
   521                            true,
   522                            scriptHandlingObject,
   523                            aFlavor);
   524 }

mercurial