tor-browser

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

NavigationPrecommitController.cpp (6789B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      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 "NavigationPrecommitController.h"
      8 
      9 #include "Navigation.h"
     10 #include "NavigationUtils.h"
     11 #include "mozilla/dom/NavigateEvent.h"
     12 #include "mozilla/dom/NavigationPrecommitControllerBinding.h"
     13 #include "nsNetUtil.h"
     14 
     15 namespace mozilla::dom {
     16 
     17 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(NavigationPrecommitController,
     18                                      mGlobalObject, mEvent)
     19 NS_IMPL_CYCLE_COLLECTING_ADDREF(NavigationPrecommitController)
     20 NS_IMPL_CYCLE_COLLECTING_RELEASE(NavigationPrecommitController)
     21 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NavigationPrecommitController)
     22  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     23  NS_INTERFACE_MAP_ENTRY(nsISupports)
     24 NS_INTERFACE_MAP_END
     25 
     26 NavigationPrecommitController::NavigationPrecommitController(
     27    NavigateEvent* aEvent, nsIGlobalObject* aGlobalObject)
     28    : mGlobalObject(aGlobalObject), mEvent(aEvent) {
     29  MOZ_DIAGNOSTIC_ASSERT(mEvent);
     30 }
     31 
     32 NavigationPrecommitController::~NavigationPrecommitController() {}
     33 
     34 JSObject* NavigationPrecommitController::WrapObject(
     35    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
     36  return NavigationPrecommitController_Binding::Wrap(aCx, this, aGivenProto);
     37 }
     38 
     39 nsIGlobalObject* NavigationPrecommitController::GetParentObject() const {
     40  return mGlobalObject;
     41 }
     42 
     43 // https://html.spec.whatwg.org/#dom-navigationprecommitcontroller-redirect
     44 void NavigationPrecommitController::Redirect(
     45    JSContext* aCx, const nsAString& aUrl,
     46    const NavigationNavigateOptions& aOptions, ErrorResult& aRv) {
     47  // The redirect(url, options) method steps are:
     48 
     49  // 1. Assert: this's event's interception state is not "none".
     50  MOZ_DIAGNOSTIC_ASSERT(mEvent->InterceptionState() !=
     51                        NavigateEvent::InterceptionState::None);
     52 
     53  // 2. Perform shared checks given this's event.
     54  mEvent->PerformSharedChecks(aRv);
     55  if (aRv.Failed()) {
     56    return;
     57  }
     58 
     59  // 3. If this's event's interception state is not "intercepted", then throw an
     60  //    "InvalidStateError" DOMException.
     61  if (mEvent->InterceptionState() !=
     62      NavigateEvent::InterceptionState::Intercepted) {
     63    aRv.ThrowInvalidStateError(
     64        "Expected interception state to be 'intercepted'");
     65    return;
     66  }
     67 
     68  // 4. If this's event's navigationType is neither "push" nor "replace", then
     69  //    throw an "InvalidStateError" DOMException.
     70  if (mEvent->NavigationType() != NavigationType::Push &&
     71      mEvent->NavigationType() != NavigationType::Replace) {
     72    aRv.ThrowInvalidStateError(
     73        "Expected navigation type to be 'push' or 'replace'");
     74    return;
     75  }
     76 
     77  // 5. Let document be this's relevant global object's associated Document.
     78  RefPtr<Document> document = mEvent->GetDocument();
     79  if (!document) {
     80    aRv.ThrowInvalidStateError("Document is not available");
     81    return;
     82  }
     83  // 6. Let destinationURL be the result of parsing url given document.
     84  RefPtr<nsIURI> destinationURL;
     85  nsresult res = NS_NewURI(getter_AddRefs(destinationURL), aUrl, nullptr,
     86                           document->GetDocBaseURI());
     87 
     88  // 7. If destinationURL is failure, then throw a "SyntaxError" DOMException.
     89  if (NS_FAILED(res)) {
     90    aRv.ThrowSyntaxError("URL given to navigate() is invalid");
     91    return;
     92  }
     93 
     94  // 8. If document cannot have its URL rewritten to destinationURL, then throw
     95  //    a "SecurityError" DOMException.
     96  if (!document->CanRewriteURL(destinationURL)) {
     97    aRv.ThrowSecurityError("Cannot rewrite URL to the given destination URL");
     98    return;
     99  }
    100 
    101  // 9. If options["history"] is "push" or "replace", then set this's event's
    102  //    navigationType to options["history"].
    103  if (aOptions.mHistory == NavigationHistoryBehavior::Push ||
    104      aOptions.mHistory == NavigationHistoryBehavior::Replace) {
    105    mEvent->SetNavigationType(
    106        *NavigationUtils::NavigationTypeFromNavigationHistoryBehavior(
    107            aOptions.mHistory));
    108  }
    109  RefPtr destination = mEvent->Destination();
    110 
    111  // 10. If options["state"] exists, then:
    112  if (!aOptions.mState.isUndefined()) {
    113    // 10.1 Let serializedState be the result of calling
    114    //      StructuredSerializeForStorage(options["state"]). This may throw an
    115    //      exception.
    116    RefPtr<nsIStructuredCloneContainer> serializedState =
    117        new nsStructuredCloneContainer();
    118    JS::Rooted<JS::Value> state(aCx, aOptions.mState);
    119 
    120    const nsresult rv = serializedState->InitFromJSVal(state, aCx);
    121    if (NS_FAILED(rv)) {
    122      JS::Rooted<JS::Value> exception(aCx);
    123      if (JS_GetPendingException(aCx, &exception)) {
    124        JS_ClearPendingException(aCx);
    125        aRv.ThrowJSException(aCx, exception);
    126      } else {
    127        // The spec only mentions that this might throw, but the tests expect
    128        // the DataCloneError.
    129        aRv.ThrowDataCloneError("Failed to serialize value for redirect().");
    130      }
    131      return;
    132    }
    133 
    134    // 10.2 Set this's event's destination's state to serializedState.
    135    destination->SetState(serializedState);
    136 
    137    // 10.3 Set this's event's target's ongoing API method tracker's serialized
    138    //      state to serializedState.
    139    if (Navigation* target =
    140            Navigation::FromEventTargetOrNull(mEvent->GetTarget())) {
    141      target->SetSerializedStateIntoOngoingAPIMethodTracker(serializedState);
    142    }
    143  }
    144 
    145  // 11. Set this's event's destination's URL to destinationURL.
    146  destination->SetURL(destinationURL);
    147  // 12. If options["info"] exists, then set this's event's info to
    148  //     options["info"].
    149  if (!aOptions.mInfo.isUndefined()) {
    150    mEvent->SetInfo(aOptions.mInfo);
    151  }
    152 }
    153 
    154 // https://html.spec.whatwg.org/#dom-navigationprecommitcontroller-addhandler
    155 void NavigationPrecommitController::AddHandler(
    156    NavigationInterceptHandler& aHandler, ErrorResult& aRv) {
    157  // 1. Assert: this's event's interception state is not "none".
    158  MOZ_DIAGNOSTIC_ASSERT(mEvent->InterceptionState() !=
    159                        NavigateEvent::InterceptionState::None);
    160 
    161  // 2. Perform shared checks given this's event.
    162  mEvent->PerformSharedChecks(aRv);
    163  if (aRv.Failed()) {
    164    return;
    165  }
    166 
    167  // 3. If this's event's interception state is not "intercepted", then throw
    168  //    an "InvalidStateError" DOMException.
    169  if (mEvent->InterceptionState() !=
    170      NavigateEvent::InterceptionState::Intercepted) {
    171    aRv.ThrowInvalidStateError(
    172        "Cannot add handler after navigation has committed");
    173    return;
    174  }
    175 
    176  // 4. Append handler to this's event's navigation handler list.
    177  mEvent->NavigationHandlerList().AppendElement(&aHandler);
    178 }
    179 
    180 }  // namespace mozilla::dom