tor-browser

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

LocationBase.cpp (6565B)


      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 
      7 #include "mozilla/dom/LocationBase.h"
      8 
      9 #include "mozilla/NullPrincipal.h"
     10 #include "mozilla/dom/Document.h"
     11 #include "mozilla/dom/PolicyContainer.h"
     12 #include "mozilla/dom/WindowContext.h"
     13 #include "nsCOMPtr.h"
     14 #include "nsContentUtils.h"
     15 #include "nsDocLoader.h"
     16 #include "nsDocShellLoadState.h"
     17 #include "nsError.h"
     18 #include "nsGlobalWindowInner.h"
     19 #include "nsIClassifiedChannel.h"
     20 #include "nsIScriptContext.h"
     21 #include "nsIScriptSecurityManager.h"
     22 #include "nsIWebNavigation.h"
     23 #include "nsNetUtil.h"
     24 
     25 namespace mozilla::dom {
     26 
     27 static bool IncumbentGlobalHasTransientActivation() {
     28  nsGlobalWindowInner* window = nsContentUtils::IncumbentInnerWindow();
     29  return window && window->GetWindowContext() && window->GetWindowContext() &&
     30         window->GetWindowContext()->HasValidTransientUserGestureActivation();
     31 }
     32 
     33 // https://html.spec.whatwg.org/#location-object-navigate
     34 void LocationBase::Navigate(nsIURI* aURI, nsIPrincipal& aSubjectPrincipal,
     35                            ErrorResult& aRv,
     36                            NavigationHistoryBehavior aHistoryHandling) {
     37  // Step 1
     38  RefPtr<BrowsingContext> navigable = GetBrowsingContext();
     39  if (!navigable || navigable->IsDiscarded()) {
     40    return;
     41  }
     42 
     43  // Step 2-3, except the check for if document is completely loaded.
     44  bool needsCompletelyLoadedDocument = !IncumbentGlobalHasTransientActivation();
     45 
     46  // Make the load's referrer reflect changes to the document's URI caused by
     47  // push/replaceState, if possible.  First, get the document corresponding to
     48  // fp.  If the document's original URI (i.e. its URI before
     49  // push/replaceState) matches the principal's URI, use the document's
     50  // current URI as the referrer.  If they don't match, use the principal's
     51  // URI.
     52  //
     53  // The triggering principal for this load should be the principal of the
     54  // incumbent document (which matches where the referrer information is
     55  // coming from) when there is an incumbent document, and the subject
     56  // principal otherwise.  Note that the URI in the triggering principal
     57  // may not match the referrer URI in various cases, notably including
     58  // the cases when the incumbent document's document URI was modified
     59  // after the document was loaded.
     60 
     61  nsCOMPtr<nsPIDOMWindowInner> incumbent =
     62      do_QueryInterface(mozilla::dom::GetIncumbentGlobal());
     63  nsCOMPtr<Document> doc = incumbent ? incumbent->GetDoc() : nullptr;
     64 
     65  // Step 4
     66  navigable->Navigate(aURI, doc, aSubjectPrincipal, aRv, aHistoryHandling,
     67                      needsCompletelyLoadedDocument);
     68 }
     69 
     70 void LocationBase::SetHref(const nsACString& aHref,
     71                           nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
     72  DoSetHref(aHref, aSubjectPrincipal, false, aRv);
     73 }
     74 
     75 void LocationBase::DoSetHref(const nsACString& aHref,
     76                             nsIPrincipal& aSubjectPrincipal, bool aReplace,
     77                             ErrorResult& aRv) {
     78  // Get the source of the caller
     79  nsCOMPtr<nsIURI> base = GetSourceBaseURL();
     80  SetHrefWithBase(aHref, base, aSubjectPrincipal, aReplace, aRv);
     81 }
     82 
     83 void LocationBase::SetHrefWithBase(const nsACString& aHref, nsIURI* aBase,
     84                                   nsIPrincipal& aSubjectPrincipal,
     85                                   bool aReplace, ErrorResult& aRv) {
     86  nsresult result;
     87  nsCOMPtr<nsIURI> newUri;
     88 
     89  if (Document* doc = GetEntryDocument()) {
     90    result = NS_NewURI(getter_AddRefs(newUri), aHref,
     91                       doc->GetDocumentCharacterSet(), aBase);
     92  } else {
     93    result = NS_NewURI(getter_AddRefs(newUri), aHref, nullptr, aBase);
     94  }
     95 
     96  if (NS_FAILED(result) || !newUri) {
     97    aRv.ThrowSyntaxError("'"_ns + aHref + "' is not a valid URL."_ns);
     98    return;
     99  }
    100 
    101  /* Check with the scriptContext if it is currently processing a script tag.
    102   * If so, this must be a <script> tag with a location.href in it.
    103   * we want to do a replace load, in such a situation.
    104   * In other cases, for example if a event handler or a JS timer
    105   * had a location.href in it, we want to do a normal load,
    106   * so that the new url will be appended to Session History.
    107   * This solution is tricky. Hopefully it isn't going to bite
    108   * anywhere else. This is part of solution for bug # 39938, 72197
    109   */
    110  bool inScriptTag = false;
    111  nsIScriptContext* scriptContext = nullptr;
    112  nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(GetEntryGlobal());
    113  if (win) {
    114    scriptContext = nsGlobalWindowInner::Cast(win)->GetContextInternal();
    115  }
    116 
    117  if (scriptContext) {
    118    if (scriptContext->GetProcessingScriptTag()) {
    119      // Now check to make sure that the script is running in our window,
    120      // since we only want to replace if the location is set by a
    121      // <script> tag in the same window.  See bug 178729.
    122      nsCOMPtr<nsIDocShell> docShell(GetDocShell());
    123      nsCOMPtr<nsIScriptGlobalObject> ourGlobal =
    124          docShell ? docShell->GetScriptGlobalObject() : nullptr;
    125      inScriptTag = (ourGlobal == scriptContext->GetGlobalObject());
    126    }
    127  }
    128 
    129  NavigationHistoryBehavior historyHandling = NavigationHistoryBehavior::Auto;
    130  if (aReplace || inScriptTag) {
    131    historyHandling = NavigationHistoryBehavior::Replace;
    132  }
    133 
    134  Navigate(newUri, aSubjectPrincipal, aRv, historyHandling);
    135 }
    136 
    137 void LocationBase::Replace(const nsACString& aUrl,
    138                           nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv) {
    139  DoSetHref(aUrl, aSubjectPrincipal, true, aRv);
    140 }
    141 
    142 nsIURI* LocationBase::GetSourceBaseURL() {
    143  Document* doc = GetEntryDocument();
    144 
    145  // If there's no entry document, we either have no Script Entry Point or one
    146  // that isn't a DOM Window.  This doesn't generally happen with the DOM, but
    147  // can sometimes happen with extension code in certain IPC configurations.  If
    148  // this happens, try falling back on the current document associated with the
    149  // docshell. If that fails, just return null and hope that the caller passed
    150  // an absolute URI.
    151  if (!doc) {
    152    if (nsCOMPtr<nsIDocShell> docShell = GetDocShell()) {
    153      nsCOMPtr<nsPIDOMWindowOuter> docShellWin =
    154          do_QueryInterface(docShell->GetScriptGlobalObject());
    155      if (docShellWin) {
    156        doc = docShellWin->GetDoc();
    157      }
    158    }
    159  }
    160  return doc ? doc->GetBaseURI() : nullptr;
    161 }
    162 
    163 }  // namespace mozilla::dom