diff --git a/Userland/Libraries/LibWeb/HTML/AbstractBrowsingContext.h b/Userland/Libraries/LibWeb/HTML/AbstractBrowsingContext.h index cf284234d9..dba0fd9725 100644 --- a/Userland/Libraries/LibWeb/HTML/AbstractBrowsingContext.h +++ b/Userland/Libraries/LibWeb/HTML/AbstractBrowsingContext.h @@ -28,17 +28,6 @@ public: JS::GCPtr opener_browsing_context() const { return m_opener_browsing_context; } void set_opener_browsing_context(JS::GCPtr browsing_context) { m_opener_browsing_context = browsing_context; } - virtual WebIDL::ExceptionOr navigate( - JS::NonnullGCPtr resource, - BrowsingContext& source_browsing_context, - bool exceptions_enabled = false, - HistoryHandlingBehavior history_handling = HistoryHandlingBehavior::Default, - Optional history_policy_container = {}, - DeprecatedString navigation_type = "other", - Optional navigation_id = {}, - Function)> process_response_end_of_body = {}) - = 0; - void set_is_popup(TokenizedFeature::Popup is_popup) { m_is_popup = is_popup; } virtual String const& window_handle() const = 0; diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp index 5d40a46a92..f01f83196e 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp @@ -1017,401 +1017,6 @@ void BrowsingContext::remove() // NOTE: This is done by ~BrowsingContextGroup() when the refcount reaches 0. } -// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate -WebIDL::ExceptionOr BrowsingContext::navigate( - JS::NonnullGCPtr resource, - BrowsingContext& source_browsing_context, - bool exceptions_enabled, - HistoryHandlingBehavior history_handling, - Optional history_policy_container, - DeprecatedString navigation_type, - Optional navigation_id, - Function)> process_response_end_of_body) -{ - // 1. If resource is a URL, then set resource to a new request whose URL is resource. - // NOTE: This function only accepts resources that are already a request, so this is irrelevant. - - // 2. If resource is a request and historyHandling is "reload", then set resource's reload-navigation flag. - if (history_handling == HistoryHandlingBehavior::Reload) - resource->set_reload_navigation(true); - - // 3. If the source browsing context is not allowed to navigate browsingContext, then: - if (!source_browsing_context.is_allowed_to_navigate(*this)) { - // 1. If exceptionsEnabled is given and is true, then throw a "SecurityError" DOMException. - if (exceptions_enabled) { - VERIFY(source_browsing_context.active_document()); - return WebIDL::SecurityError::create(source_browsing_context.active_document()->realm(), "Source browsing context not allowed to navigate"_fly_string); - } - - // FIXME: 2. Otherwise, the user agent may instead offer to open resource in a new top-level browsing context - // or in the top-level browsing context of the source browsing context, at the user's option, - // in which case the user agent must navigate that designated top-level browsing context - // to resource as if the user had requested it independently. - } - - // 4. If navigationId is null: - if (!navigation_id.has_value()) { - // 1. If historyHandling is "reload", and browsingContext's active document's navigation id is not null, - if (history_handling == HistoryHandlingBehavior::Reload && active_document()->navigation_id().has_value()) { - // let navigationId be browsingContext's active document's navigation id. - navigation_id = active_document()->navigation_id(); - } else { - // Otherwise let navigation id be the result of generating a random UUID. [UUID] - // FIXME: Generate a UUID. - navigation_id = "FIXME"_string; - } - } - - // FIXME: 5. If browsingContext's active document's unload counter is greater than 0, - // then invoke WebDriver BiDi navigation failed - // with a WebDriver BiDi navigation status whose id is navigationId, status is "canceled", and url is resource's url - // and return. - - // 6. If historyHandling is "default", and any of the following are true: - // - browsingContext is still on its initial about:blank Document - // - resource is a request whose URL equals browsingContext's active document's URL - // - resource is a request whose URL's scheme is "javascript" - if (history_handling == HistoryHandlingBehavior::Default - && (still_on_its_initial_about_blank_document() - || resource->url().equals(active_document()->url()) - || resource->url().scheme() == "javascript"sv)) { - // then set historyHandling to "replace". - history_handling = HistoryHandlingBehavior::Replace; - } - - // 7. If historyHandling is not "reload", resource is a request, - // resource's URL equals browsingContext's active document's URL with exclude fragments set to true, - // and resource's URL's fragment is non-null, then: - if (history_handling != HistoryHandlingBehavior::Reload - && resource->url().equals(active_document()->url(), AK::URL::ExcludeFragment::Yes) - && resource->url().fragment().has_value()) { - // 1. Navigate to a fragment given browsingContext, resource's URL, historyHandling, and navigationId. - TRY(navigate_to_a_fragment(resource->url(), history_handling, *navigation_id)); - - // 2. Return. - return {}; - } - - // FIXME: 8. Let incumbentNavigationOrigin be the origin of the incumbent settings object, - // or if no script was involved, the origin of the node document of the element that initiated the navigation. - - // FIXME: 9. Let initiatorPolicyContainer be a clone of the source browsing context's active document's policy container. - - // FIXME: 10. If resource is a request, then set resource's policy container to initiatorPolicyContainer. - - // FIXME: 11. Cancel any preexisting but not yet mature attempt to navigate browsingContext, - // including canceling any instances of the fetch algorithm started by those attempts. - // If one of those attempts has already created and initialized a new Document object, - // abort that Document also. - // (Navigation attempts that have matured already have session history entries, - // and are therefore handled during the update the session history with the new page algorithm, later.) - - // FIXME: 12. Let unloadPromptResult be the result of calling prompt to unload with the active document of browsingContext. - // If this instance of the navigation algorithm gets canceled while this step is running, - // the prompt to unload algorithm must nonetheless be run to completion. - - // FIXME: 13. If unloadPromptResult is "refuse", then return a new WebDriver BiDi navigation status whose id is navigationId and status is "canceled". - - // 14. Abort the active document of browsingContext. - active_document()->abort(); - - // FIXME: 15. If browsingContext is a child browsing context, then put it in the delaying load events mode. - // The user agent must take this child browsing context out of the delaying load events mode when this navigation algorithm later matures, - // or when it terminates (whether due to having run all the steps, or being canceled, or being aborted), - // whichever happens first. - - // FIXME: 16. Let sandboxFlags be the result of determining the creation sandboxing flags given browsingContext and browsingContext's container. - - // FIXME: 17. Let allowedToDownload be the result of running the allowed to download algorithm given the source browsing context and browsingContext. - - // 18. Let hasTransientActivation be true if the source browsing context's active window has transient activation; otherwise false. - [[maybe_unused]] bool has_transient_activation = source_browsing_context.active_window()->has_transient_activation(); - - // FIXME: 19. Invoke WebDriver BiDi navigation started with browsingContext, and a new WebDriver BiDi navigation status whose id is navigationId, url is resource's url, and status is "pending". - - // 20. Return, and continue running these steps in parallel. - - // FIXME: Implement the rest of this algorithm - (void)history_policy_container; - (void)navigation_type; - (void)process_response_end_of_body; - - // AD-HOC: - auto request = LoadRequest::create_for_url_on_page(resource->url(), page()); - request.set_method(DeprecatedString { resource->method() }); - for (auto& header : *resource->header_list()) { - request.set_header(DeprecatedString { header.name.bytes() }, DeprecatedString { header.value.bytes() }); - } - if (request.method() == "POST"sv) { - if (resource->body().has()) { - auto const& byte_buffer = resource->body().get(); - request.set_body(byte_buffer); - request.set_header("Content-Length", DeprecatedString::number(byte_buffer.size())); - } else { - request.set_header("Content-Length", DeprecatedString::number(0)); - } - } - loader().load(request, FrameLoader::Type::Navigation); - return {}; -} - -// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid -WebIDL::ExceptionOr BrowsingContext::navigate_to_a_fragment(AK::URL const& url, HistoryHandlingBehavior history_handling, String navigation_id) -{ - // 1. If historyHandling is not "replace", - if (history_handling != HistoryHandlingBehavior::Replace) { - // FIXME: then remove all the entries in browsingContext's session history after the current entry. - // (If the current entry is the last entry in the session history, then no entries are removed.) - } - - // 2. Remove any tasks queued by the history traversal task source that are associated with any Document objects - // in browsingContext's top-level browsing context's document family. - HTML::main_thread_event_loop().task_queue().remove_tasks_matching([&](HTML::Task const& task) { - return task.source() == Task::Source::HistoryTraversal - && task.document() - && top_level_browsing_context().document_family_contains(*task.document()); - }); - - // 3. Append a new session history entry to the session history whose URL is url, - // document is the current entry's document, - // policy container is the current entry's policy-container - // and scroll restoration mode is the current entry's scroll restoration mode. - auto new_entry = heap().allocate_without_realm(); - new_entry->url = url; - new_entry->document_state = *heap().allocate_without_realm(); - new_entry->document_state->set_document(current_entry().document_state->document()); - new_entry->policy_container = current_entry().policy_container; - new_entry->scroll_restoration_mode = current_entry().scroll_restoration_mode; - new_entry->browsing_context_name = {}; - new_entry->original_source_browsing_context = {}; - m_session_history.append(*new_entry); - - // 4. Traverse the history to the new entry, with historyHandling set to historyHandling. - // This will scroll to the fragment given in what is now the document's URL. - TRY(traverse_the_history(m_session_history.size() - 1, history_handling)); - - // FIXME: 5. Invoke WebDriver BiDi fragment navigated with browsingContext, - // and a new WebDriver BiDi navigation status whose id is navigationId, url is resource's url, and status is "complete". - (void)navigation_id; - - return {}; -} - -// https://html.spec.whatwg.org/multipage/browsing-the-web.html#traverse-the-history -WebIDL::ExceptionOr BrowsingContext::traverse_the_history(size_t entry_index, HistoryHandlingBehavior history_handling, bool explicit_history_navigation) -{ - auto entry = m_session_history[entry_index]; - - // 1. If entry's document is null, then: - if (!entry->document_state->document()) { - // 1. Assert: historyHandling is "default". - VERIFY(history_handling == HistoryHandlingBehavior::Default); - - // 2. Let request be a new request whose URL is entry's URL. - auto& vm = Bindings::main_thread_vm(); - auto request = Fetch::Infrastructure::Request::create(vm); - request->set_url(entry->url); - - // 3. If explicitHistoryNavigation is true, then set request's history-navigation flag. - if (explicit_history_navigation) - request->set_history_navigation(true); - - // 4. Navigate the browsing context to request with historyHandling set to "entry update" - // and with historyPolicyContainer set to entry's policy container. - // The navigation must be done using the same source browsing context as was used the first time entry was created. - VERIFY(entry->original_source_browsing_context); - TRY(navigate(request, *entry->original_source_browsing_context, false, HistoryHandlingBehavior::EntryUpdate, entry->policy_container)); - - // 5. Return. - return {}; - } - - // FIXME: 2. Save persisted state to the current entry. - - // 3. Let newDocument be entry's document. - JS::GCPtr new_document = entry->document_state->document().ptr(); - - // 4. Assert: newDocument's is initial about:blank is false, - // i.e., we never traverse back to the initial about:blank Document because it always gets replaced when we navigate away from it. - VERIFY(!new_document->is_initial_about_blank()); - - // 5. If newDocument is different than the current entry's document, or historyHandling is "entry update" or "reload", then: - if (new_document.ptr() != current_entry().document_state->document().ptr() - || history_handling == HistoryHandlingBehavior::EntryUpdate) { - // FIXME: 1. If newDocument's suspended timer handles is not empty: - // FIXME: 1. Assert: newDocument's suspension time is not zero. - // FIXME: 2. Let suspendDuration be the current high resolution time minus newDocument's suspension time. - // FIXME: 3. Let activeTimers be newDocument's relevant global object's map of active timers. - // FIXME: 4. For each handle in newDocument's suspended timer handles, if activeTimers[handle] exists, then increase activeTimers[handle] by suspendDuration. - } - - // 2. Remove any tasks queued by the history traversal task source - // that are associated with any Document objects in the top-level browsing context's document family. - HTML::main_thread_event_loop().task_queue().remove_tasks_matching([&](HTML::Task const& task) { - return task.source() == Task::Source::HistoryTraversal - && task.document() - && top_level_browsing_context().document_family_contains(*task.document()); - }); - - // 3. If newDocument's origin is not same origin with the current entry's document's origin, then: - if (!new_document->origin().is_same_origin(current_entry().document_state->document()->origin())) { - // FIXME: 1. Let entriesToUpdate be all entries in the session history whose document's origin is same origin as the active document - // and that are contiguous with the current entry. - // FIXME: 2. For each entryToUpdate of entriesToUpdate, set entryToUpdate's browsing context name to the current browsing context name. - // FIXME: 3. If the browsing context is a top-level browsing context, but not an auxiliary browsing context whose disowned is false, then set the browsing context's name to the empty string. - } - - // 4. Set the active document of the browsing context to newDocument. - set_active_document(*new_document); - - // 5. If entry's browsing context name is not null, then: - if (entry->browsing_context_name.has_value()) { - // 1. Set the browsing context's name to entry's browsing context name. - m_name = *entry->browsing_context_name; - - // FIXME: 2. Let entriesToUpdate be all entries in the session history whose document's origin is same origin as the new active document's origin and that are contiguous with entry. - // FIXME: 3. For each entryToUpdate of entriesToUpdate, set entryToUpdate's browsing context name to null. - } - - // FIXME: 6. If newDocument has any form controls whose autofill field name is "off", invoke the reset algorithm of each of those elements. - - // 7. If newDocument's current document readiness "complete", - if (new_document->readiness() == HTML::DocumentReadyState::Complete) { - // then queue a global task on the DOM manipulation task source given newDocument's relevant global object to run the following steps: - - queue_global_task(Task::Source::DOMManipulation, relevant_global_object(*new_document), [new_document] { - // 1. If newDocument's page showing flag is true, then abort these steps. - if (new_document->page_showing()) - return; - - // 2. Set newDocument's page showing flag to true. - new_document->set_page_showing(true); - - // 3. Update the visibility state of newDocument to "hidden". - new_document->update_the_visibility_state(VisibilityState::Hidden); - - // 4. Fire a page transition event named pageshow at newDocument's relevant global object with true. - auto& window = verify_cast(relevant_global_object(*new_document)); - window.fire_a_page_transition_event(HTML::EventNames::pageshow, true); - }); - } - - // 6. Set newDocument's URL to entry's URL. - new_document->set_url(entry->url); - - // 7. Let hashChanged be false, and let oldURL and newURL be null. - bool hash_changed = false; - Optional old_url; - Optional new_url; - - // 8. If entry's URL's fragment is not identical to the current entry's URL's fragment, - // and entry's document equals the current entry's document, - if (entry->url.fragment() != current_entry().url.fragment() - && entry->document_state->document().ptr() == current_entry().document_state->document().ptr()) { - // then set hashChanged to true, set oldURL to the current entry's URL, and set newURL to entry's URL. - hash_changed = true; - old_url = current_entry().url; - new_url = entry->url; - } - - // 9. If historyHandling is "replace", then remove the entry immediately before entry in the session history. - if (history_handling == HistoryHandlingBehavior::Replace) { - // FIXME: This is gnarly. - m_session_history.remove(entry_index - 1); - entry_index--; - entry = m_session_history[entry_index]; - } - - // 10. If entry's persisted user state is null, and its URL's fragment is non-null, then scroll to the fragment. - if (entry->url.fragment().has_value()) - active_document()->scroll_to_the_fragment(); - - // 11. Set the current entry to entry. - m_session_history_index = entry_index; - - // 12. Let targetRealm be the current Realm Record. - auto* target_realm = Bindings::main_thread_vm().current_realm(); - VERIFY(target_realm); - - // FIXME: 13. Let state be null. - // FIXME: 14. If entry's serialized state is not null, then set state to StructuredDeserialize(entry's serialized state, targetRealm). - // If this throws an exception, catch it and ignore the exception. - // FIXME: 15. Set newDocument's History object's state to state. - // FIXME: 16. Let stateChanged be true if newDocument has a latest entry, and that entry is not entry; otherwise let it be false. - // FIXME: 17. Set newDocument's latest entry to entry. - // FIXME: 18. If stateChanged is true, then fire an event named popstate at newDocument's relevant global object, using PopStateEvent, with the state attribute initialized to state. - // FIXME: 19. Restore persisted state from entry. - - // 20. If hashChanged is true, - if (hash_changed) { - // then queue a global task on the DOM manipulation task source given newDocument's relevant global object - queue_global_task(Task::Source::DOMManipulation, relevant_global_object(*new_document), [new_document] { - // to fire an event named hashchange at newDocument's relevant global object, - // using HashChangeEvent, with the oldURL attribute initialized to oldURL - // and the newURL attribute initialized to newURL. - - // FIXME: Implement a proper HashChangeEvent class. - auto event = DOM::Event::create(verify_cast(relevant_global_object(*new_document)).realm(), HTML::EventNames::hashchange); - new_document->dispatch_event(event); - }); - } - - return {}; -} - -// https://html.spec.whatwg.org/multipage/browsers.html#allowed-to-navigate -bool BrowsingContext::is_allowed_to_navigate(BrowsingContext const& other) const -{ - VERIFY(active_window()); - VERIFY(active_document()); - - // 1. If A is not the same browsing context as B, - // and A is not one of the ancestor browsing contexts of B, - // and B is not a top-level browsing context, - // FIXME: and A's active document's active sandboxing flag set has its sandboxed navigation browsing context flag set, - // then return false. - if (this != &other - && !this->is_ancestor_of(other) - && !other.is_top_level()) { - return false; - } - - // 2. Otherwise, if B is a top-level browsing context, and is one of the ancestor browsing contexts of A, then: - if (other.is_top_level() && other.is_ancestor_of(*this)) { - // 1. If A's active window has transient activation - // and A's active document's active sandboxing flag set has its sandboxed top-level navigation with user activation browsing context flag set, - // then return false. - if (active_window()->has_transient_activation() - && has_flag(active_document()->active_sandboxing_flag_set(), SandboxingFlagSet::SandboxedTopLevelNavigationWithUserActivation)) { - return false; - } - - // 2. Otherwise, if A's active window does not have transient activation - // and A's active document's active sandboxing flag set has its sandboxed top-level navigation without user activation browsing context flag set, - // then return false. - if (!active_window()->has_transient_activation() - && has_flag(active_document()->active_sandboxing_flag_set(), SandboxingFlagSet::SandboxedTopLevelNavigationWithoutUserActivation)) { - return false; - } - } - - // 3. Otherwise, if B is a top-level browsing context, - // and is neither A nor one of the ancestor browsing contexts of A, - // and A's Document's active sandboxing flag set has its sandboxed navigation browsing context flag set, - // and A is not the one permitted sandboxed navigator of B, - // then return false. - if (other.is_top_level() - && &other != this - && !other.is_ancestor_of(*this) - && has_flag(active_document()->active_sandboxing_flag_set(), SandboxingFlagSet::SandboxedNavigation) - && this != other.the_one_permitted_sandboxed_navigator()) { - return false; - } - - // 4. Return true. - return true; -} - // https://html.spec.whatwg.org/multipage/origin.html#one-permitted-sandboxed-navigator BrowsingContext const* BrowsingContext::the_one_permitted_sandboxed_navigator() const { diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h index 0e9ebe7a79..d97ab0bbcd 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h @@ -219,29 +219,9 @@ public: // https://html.spec.whatwg.org/multipage/browsers.html#bcg-remove void remove(); - // https://html.spec.whatwg.org/multipage/browsers.html#allowed-to-navigate - bool is_allowed_to_navigate(BrowsingContext const&) const; - - // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate - virtual WebIDL::ExceptionOr navigate( - JS::NonnullGCPtr resource, - BrowsingContext& source_browsing_context, - bool exceptions_enabled = false, - HistoryHandlingBehavior history_handling = HistoryHandlingBehavior::Default, - Optional history_policy_container = {}, - DeprecatedString navigation_type = "other", - Optional navigation_id = {}, - Function)> process_response_end_of_body = {}) override; - - // https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid - WebIDL::ExceptionOr navigate_to_a_fragment(AK::URL const&, HistoryHandlingBehavior, String navigation_id); - // https://html.spec.whatwg.org/multipage/origin.html#one-permitted-sandboxed-navigator BrowsingContext const* the_one_permitted_sandboxed_navigator() const; - // https://html.spec.whatwg.org/multipage/browsing-the-web.html#traverse-the-history - WebIDL::ExceptionOr traverse_the_history(size_t entry_index, HistoryHandlingBehavior = HistoryHandlingBehavior::Default, bool explicit_history_navigation = false); - Vector> document_family() const; bool document_family_contains(DOM::Document const&) const; diff --git a/Userland/Libraries/LibWeb/HTML/RemoteBrowsingContext.h b/Userland/Libraries/LibWeb/HTML/RemoteBrowsingContext.h index 7f3150d1a5..4d980b0ae6 100644 --- a/Userland/Libraries/LibWeb/HTML/RemoteBrowsingContext.h +++ b/Userland/Libraries/LibWeb/HTML/RemoteBrowsingContext.h @@ -22,19 +22,6 @@ public: virtual HTML::WindowProxy* window_proxy() override; virtual HTML::WindowProxy const* window_proxy() const override; - virtual WebIDL::ExceptionOr navigate( - JS::NonnullGCPtr, - BrowsingContext&, - bool, - HistoryHandlingBehavior, - Optional, - DeprecatedString, - Optional, - Function)>) override - { - return {}; - } - virtual String const& window_handle() const override { return m_window_handle; } virtual void set_window_handle(String handle) override { m_window_handle = handle; }