tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsContentDLF.cpp (10875B)


      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 "DecoderTraits.h"
      9 #include "imgLoader.h"
     10 #include "mozilla/Encoding.h"
     11 #include "mozilla/dom/Document.h"
     12 #include "mozilla/dom/LoadURIOptionsBinding.h"
     13 #include "nsCOMPtr.h"
     14 #include "nsCRT.h"
     15 #include "nsCharsetSource.h"
     16 #include "nsContentUtils.h"
     17 #include "nsDocShell.h"
     18 #include "nsGenericHTMLElement.h"
     19 #include "nsGkAtoms.h"
     20 #include "nsIDocumentLoaderFactory.h"
     21 #include "nsIDocumentViewer.h"
     22 #include "nsIViewSourceChannel.h"
     23 #include "nsMimeTypes.h"
     24 #include "nsNetUtil.h"
     25 #include "nsNodeInfoManager.h"
     26 #include "nsString.h"
     27 
     28 // Factory code for creating variations on html documents
     29 
     30 #undef NOISY_REGISTRY
     31 
     32 using namespace mozilla;
     33 using mozilla::dom::Document;
     34 using mozilla::dom::ForceMediaDocument;
     35 
     36 already_AddRefed<nsIDocumentViewer> NS_NewDocumentViewer();
     37 
     38 static const char* const gHTMLTypes[] = {TEXT_HTML, VIEWSOURCE_CONTENT_TYPE,
     39                                         APPLICATION_XHTML_XML,
     40                                         APPLICATION_WAPXHTML_XML, 0};
     41 
     42 static const char* const gXMLTypes[] = {TEXT_XML,
     43                                        APPLICATION_XML,
     44                                        APPLICATION_MATHML_XML,
     45                                        APPLICATION_RDF_XML,
     46                                        TEXT_RDF,
     47                                        0};
     48 
     49 static const char* const gSVGTypes[] = {IMAGE_SVG_XML, 0};
     50 
     51 static bool IsTypeInList(const nsACString& aType, const char* const aList[]) {
     52  int32_t typeIndex;
     53  for (typeIndex = 0; aList[typeIndex]; ++typeIndex) {
     54    if (aType.Equals(aList[typeIndex])) {
     55      return true;
     56    }
     57  }
     58 
     59  return false;
     60 }
     61 
     62 nsresult NS_NewContentDocumentLoaderFactory(
     63    nsIDocumentLoaderFactory** aResult) {
     64  MOZ_ASSERT(aResult, "null OUT ptr");
     65  if (!aResult) {
     66    return NS_ERROR_NULL_POINTER;
     67  }
     68  auto it = MakeRefPtr<nsContentDLF>();
     69  it.forget(aResult);
     70  return NS_OK;
     71 }
     72 
     73 nsContentDLF::nsContentDLF() = default;
     74 
     75 nsContentDLF::~nsContentDLF() = default;
     76 
     77 NS_IMPL_ISUPPORTS(nsContentDLF, nsIDocumentLoaderFactory)
     78 
     79 enum class CreateDocumentKind { HTML, XML, SVG, Video, Image, None };
     80 
     81 static CreateDocumentKind GetCreateDocumentKind(nsACString& aContentType) {
     82  // HTML or plaintext; both use the same document CID
     83  if (IsTypeInList(aContentType, gHTMLTypes) ||
     84      nsContentUtils::IsPlainTextType(aContentType)) {
     85    return CreateDocumentKind::HTML;
     86  }
     87 
     88  if (IsTypeInList(aContentType, gXMLTypes)) {
     89    return CreateDocumentKind::XML;
     90  }
     91 
     92  if (IsTypeInList(aContentType, gSVGTypes)) {
     93    return CreateDocumentKind::SVG;
     94  }
     95 
     96  if (mozilla::DecoderTraits::ShouldHandleMediaType(
     97          aContentType,
     98          /* DecoderDoctorDiagnostics* */ nullptr)) {
     99    return CreateDocumentKind::Video;
    100  }
    101 
    102  if (imgLoader::SupportImageWithMimeType(aContentType)) {
    103    return CreateDocumentKind::Image;
    104  }
    105 
    106  return CreateDocumentKind::None;
    107 }
    108 
    109 static nsresult CreateDocument(const char* aCommand, nsIChannel* aChannel,
    110                               nsILoadGroup* aLoadGroup,
    111                               nsIDocShell* aContainer,
    112                               CreateDocumentKind aKind,
    113                               nsIStreamListener** aDocListener,
    114                               nsIDocumentViewer** aDocumentViewer) {
    115  // Create the document
    116  RefPtr<Document> doc;
    117  nsresult rv;
    118  switch (aKind) {
    119    case CreateDocumentKind::HTML:
    120      rv = NS_NewHTMLDocument(getter_AddRefs(doc), nullptr, nullptr);
    121      break;
    122    case CreateDocumentKind::XML:
    123      rv = NS_NewXMLDocument(getter_AddRefs(doc), nullptr, nullptr);
    124      break;
    125    case CreateDocumentKind::SVG:
    126      rv = NS_NewSVGDocument(getter_AddRefs(doc), nullptr, nullptr);
    127      break;
    128    case CreateDocumentKind::Video:
    129      rv = NS_NewVideoDocument(getter_AddRefs(doc), nullptr, nullptr);
    130      break;
    131    case CreateDocumentKind::Image:
    132      rv = NS_NewImageDocument(getter_AddRefs(doc), nullptr, nullptr);
    133      break;
    134    case CreateDocumentKind::None:
    135      MOZ_ASSERT_UNREACHABLE("Invalid kind.");
    136      rv = NS_ERROR_FAILURE;
    137      break;
    138  }
    139  NS_ENSURE_SUCCESS(rv, rv);
    140 
    141  // Create the content viewer  XXX: could reuse content viewer here!
    142  nsCOMPtr<nsIDocumentViewer> viewer = NS_NewDocumentViewer();
    143 
    144  doc->SetContainer(static_cast<nsDocShell*>(aContainer));
    145  doc->SetAllowDeclarativeShadowRoots(true);
    146 
    147  // Initialize the document to begin loading the data.  An
    148  // nsIStreamListener connected to the parser is returned in
    149  // aDocListener.
    150  rv = doc->StartDocumentLoad(aCommand, aChannel, aLoadGroup, aContainer,
    151                              aDocListener, true);
    152  NS_ENSURE_SUCCESS(rv, rv);
    153 
    154  // Bind the document to the Content Viewer
    155  viewer->LoadStart(doc);
    156 
    157  if (aKind != CreateDocumentKind::Image) {
    158    viewer->GetDocument()->MakeBrowsingContextNonSynthetic();
    159  }
    160 
    161  viewer.forget(aDocumentViewer);
    162  return NS_OK;
    163 }
    164 
    165 NS_IMETHODIMP
    166 nsContentDLF::CreateInstance(const char* aCommand, nsIChannel* aChannel,
    167                             nsILoadGroup* aLoadGroup,
    168                             const nsACString& aContentType,
    169                             nsIDocShell* aContainer, nsISupports* aExtraInfo,
    170                             nsIStreamListener** aDocListener,
    171                             nsIDocumentViewer** aDocViewer) {
    172  // Make a copy of aContentType, because we're possibly going to change it.
    173  nsAutoCString contentType(aContentType);
    174 
    175  // Are we viewing source?
    176  nsCOMPtr<nsIViewSourceChannel> viewSourceChannel =
    177      do_QueryInterface(aChannel);
    178  if (viewSourceChannel) {
    179    aCommand = "view-source";
    180 
    181    // The parser freaks out when it sees the content-type that a
    182    // view-source channel normally returns.  Get the actual content
    183    // type of the data.  If it's known, use it; otherwise use
    184    // text/plain.
    185    nsAutoCString type;
    186    (void)viewSourceChannel->GetOriginalContentType(type);
    187    bool knownType = (!type.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE) &&
    188                      IsTypeInList(type, gHTMLTypes)) ||
    189                     nsContentUtils::IsPlainTextType(type) ||
    190                     IsTypeInList(type, gXMLTypes) ||
    191                     IsTypeInList(type, gSVGTypes);
    192 
    193    if (knownType) {
    194      viewSourceChannel->SetContentType(type);
    195    } else if (imgLoader::SupportImageWithMimeType(type)) {
    196      // If it's an image, we want to display it the same way we normally would.
    197      contentType = type;
    198    } else {
    199      viewSourceChannel->SetContentType(nsLiteralCString(TEXT_PLAIN));
    200    }
    201  } else if (aContentType.EqualsLiteral(VIEWSOURCE_CONTENT_TYPE)) {
    202    aChannel->SetContentType(nsLiteralCString(TEXT_PLAIN));
    203    contentType = TEXT_PLAIN;
    204  }
    205 
    206  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
    207  CreateDocumentKind kind = CreateDocumentKind::None;
    208  // SVGDocumentWrapper::SetupViewer needs to be able to create a proper SVG
    209  // document internally even when creating an ImageDocument.
    210  if ((!aCommand || strcmp(aCommand, "external-resource") != 0) &&
    211      loadInfo->GetForceMediaDocument() != ForceMediaDocument::None) {
    212    switch (loadInfo->GetForceMediaDocument()) {
    213      case dom::ForceMediaDocument::Video:
    214        kind = CreateDocumentKind::Video;
    215        break;
    216      case dom::ForceMediaDocument::Image:
    217        kind = CreateDocumentKind::Image;
    218        break;
    219      case dom::ForceMediaDocument::None:
    220        MOZ_ASSERT_UNREACHABLE("Can't be None");
    221        break;
    222    }
    223  } else {
    224    kind = GetCreateDocumentKind(contentType);
    225  }
    226 
    227  if (kind == CreateDocumentKind::None) {
    228    // We can't handle this content type. Sorry!
    229    return NS_ERROR_FAILURE;
    230  }
    231 
    232  return CreateDocument(aCommand, aChannel, aLoadGroup, aContainer, kind,
    233                        aDocListener, aDocViewer);
    234 }
    235 
    236 NS_IMETHODIMP
    237 nsContentDLF::CreateInstanceForDocument(nsISupports* aContainer,
    238                                        Document* aDocument,
    239                                        const char* aCommand,
    240                                        nsIDocumentViewer** aDocumentViewer) {
    241  MOZ_ASSERT(aDocument);
    242 
    243  nsCOMPtr<nsIDocumentViewer> viewer = NS_NewDocumentViewer();
    244 
    245  // Bind the document to the Content Viewer
    246  viewer->LoadStart(aDocument);
    247  viewer.forget(aDocumentViewer);
    248  return NS_OK;
    249 }
    250 
    251 /* static */
    252 already_AddRefed<Document> nsContentDLF::CreateBlankDocument(
    253    nsILoadGroup* aLoadGroup, nsIPrincipal* aPrincipal,
    254    nsIPrincipal* aPartitionedPrincipal, nsDocShell* aContainer) {
    255  // create a new blank HTML document
    256  RefPtr<Document> blankDoc;
    257  (void)NS_NewHTMLDocument(getter_AddRefs(blankDoc), nullptr, nullptr);
    258 
    259  if (!blankDoc) {
    260    return nullptr;
    261  }
    262 
    263  // initialize
    264  nsCOMPtr<nsIURI> uri;
    265  NS_NewURI(getter_AddRefs(uri), "about:blank"_ns);
    266  if (!uri) {
    267    return nullptr;
    268  }
    269  blankDoc->ResetToURI(uri, aLoadGroup, aPrincipal, aPartitionedPrincipal);
    270  blankDoc->SetContainer(aContainer);
    271 
    272  blankDoc->SetAllowDeclarativeShadowRoots(true);
    273 
    274  // add some simple content structure
    275  nsNodeInfoManager* nim = blankDoc->NodeInfoManager();
    276 
    277  RefPtr<mozilla::dom::NodeInfo> htmlNodeInfo;
    278 
    279  // generate an html html element
    280  htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::html, 0, kNameSpaceID_XHTML,
    281                                  nsINode::ELEMENT_NODE);
    282  nsCOMPtr<nsIContent> htmlElement =
    283      NS_NewHTMLHtmlElement(htmlNodeInfo.forget());
    284 
    285  // generate an html head element
    286  htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::head, 0, kNameSpaceID_XHTML,
    287                                  nsINode::ELEMENT_NODE);
    288  nsCOMPtr<nsIContent> headElement =
    289      NS_NewHTMLHeadElement(htmlNodeInfo.forget());
    290 
    291  // generate an html body elemment
    292  htmlNodeInfo = nim->GetNodeInfo(nsGkAtoms::body, 0, kNameSpaceID_XHTML,
    293                                  nsINode::ELEMENT_NODE);
    294  nsCOMPtr<nsIContent> bodyElement =
    295      NS_NewHTMLBodyElement(htmlNodeInfo.forget());
    296 
    297  // blat in the structure
    298  NS_ASSERTION(blankDoc->GetChildCount() == 0, "Shouldn't have children");
    299  if (!htmlElement || !headElement || !bodyElement) {
    300    return nullptr;
    301  }
    302 
    303  mozilla::IgnoredErrorResult rv;
    304  blankDoc->AppendChildTo(htmlElement, false, rv);
    305  if (rv.Failed()) {
    306    return nullptr;
    307  }
    308 
    309  htmlElement->AppendChildTo(headElement, false, rv);
    310  if (rv.Failed()) {
    311    return nullptr;
    312  }
    313 
    314  // XXXbz Why not notifying here?
    315  htmlElement->AppendChildTo(bodyElement, false, rv);
    316  if (rv.Failed()) {
    317    return nullptr;
    318  }
    319 
    320  // add a nice bow
    321  blankDoc->SetDocumentCharacterSetSource(kCharsetFromDocTypeDefault);
    322  blankDoc->SetDocumentCharacterSet(UTF_8_ENCODING);
    323  return blankDoc.forget();
    324 }