Преглед на файлове

LibWeb: Process all task source while waiting for document population

"apply the history step" initiated by reloading or back/forward
navigation might require doing fetching while populating a document,
so it is not possible to restrict spin_until() to process only
NavigationAndTraversal task source.

"apply the history step" initiated by synchronous navigation keeps
processing only NavigationAndTraversal task source because it will
never have to populate a document. Another reason to keep synchronous
navigation blocking other task sources is that we crash if active SHE
changes in the middle of "apply the history step" initiated by sync
navigation. The new test is added to makes sure we don't regress that.
Aliaksandr Kalenik преди 1 година
родител
ревизия
d86ad2fcfa

+ 1 - 0
Tests/LibWeb/Text/expected/navigation/history-replace-push-state-race-3.txt

@@ -0,0 +1 @@
+test done!

+ 22 - 0
Tests/LibWeb/Text/input/navigation/history-replace-push-state-race-3.html

@@ -0,0 +1,22 @@
+<script src="../include.js"></script>
+<script>
+    asyncTest(done => {
+        let counter = 0;
+        setTimeout(() => {
+            history.replaceState({}, "test", "history-replace-push-state-race-3.html");
+            counter++;
+            if (counter === 2) {
+                println("test done!");
+                done();
+            }
+        }, 0);
+        setTimeout(() => {
+            history.replaceState({}, "test", "history-replace-push-state-race-3.html");
+            counter++;
+            if (counter === 2) {
+                println("test done!");
+                done();
+            }
+        }, 0);
+    });
+</script>

+ 9 - 1
Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp

@@ -587,10 +587,18 @@ TraversableNavigable::HistoryStepResult TraversableNavigable::apply_the_history_
         });
         });
     }
     }
 
 
-    main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, [&] {
+    auto check_if_document_population_tasks_completed = JS::SafeFunction<bool()>([&] {
         return changing_navigable_continuations.size() + completed_change_jobs == total_change_jobs;
         return changing_navigable_continuations.size() + completed_change_jobs == total_change_jobs;
     });
     });
 
 
+    if (synchronous_navigation == SynchronousNavigation::Yes) {
+        // NOTE: Synchronous navigation should never require document population, so it is safe to process only NavigationAndTraversal source.
+        main_thread_event_loop().spin_processing_tasks_with_source_until(Task::Source::NavigationAndTraversal, move(check_if_document_population_tasks_completed));
+    } else {
+        // NOTE: Process all task sources while waiting because reloading or back/forward navigation might require fetching to populate a document.
+        main_thread_event_loop().spin_until(move(check_if_document_population_tasks_completed));
+    }
+
     // 13. Let navigablesThatMustWaitBeforeHandlingSyncNavigation be an empty set.
     // 13. Let navigablesThatMustWaitBeforeHandlingSyncNavigation be an empty set.
     Vector<JS::GCPtr<Navigable>> navigables_that_must_wait_before_handling_sync_navigation;
     Vector<JS::GCPtr<Navigable>> navigables_that_must_wait_before_handling_sync_navigation;