From 263dbbc29689b31aa02331037c8a2b2ed57a04b2 Mon Sep 17 00:00:00 2001 From: James Graham Date: Fri, 25 Jun 2021 13:33:30 +0100 Subject: [PATCH] Add a task queue and use it for scheduling. This adds a parallel task queue and uses it to schedule all events, rather than using "in parallel" a lot. This makes it easier to reason about the ordering of events. In addition it makes all events happens as part of a task. This seems likely to match implementations where events will presumably be triggered from event listeners rather than synchronously as in the spec at present. It also means that we don't need the event suppression hack to ensure that navigation commands return before related events are emitted. --- index.bs | 385 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 211 insertions(+), 174 deletions(-) diff --git a/index.bs b/index.bs index 75f3b878b..e2e3e5859 100644 --- a/index.bs +++ b/index.bs @@ -146,13 +146,19 @@ This specification depends on the Infra Standard. [[!INFRA]] Network protocol messages are defined using CDDL. [[!RFC8610]] +Tasks are scheduled using the WebDriver task queue, which is a +the result of [=starting a new parallel queue=]. + +To queue a WebDriver task, consisting of a list of steps, |steps|, +[=enqueue steps=] |steps| to the [=WebDriver task queue=]. + This specification defines a wait queue which is a map. Issue: Surely there's a better mechanism for doing this "wait for an event" thing.
-When an algorithm |algorithm| running [=in parallel=] awaits a set of +When an algorithm |algorithm| awaits a set of events |events|, and |resume id|: 1. Pause the execution of |algorithm|. @@ -568,8 +574,6 @@ accept the incoming connection: connections=], and proceed with the WebSocket [=server-side requirements=] when a server chooses to accept an incoming connection. -Issue: Do we support > 1 connection for a single session? -
When [=a WebSocket message has been received=] for a [=WebSocket @@ -709,7 +713,7 @@ To handle an incoming message given a [=WebSocket connection=] [=respond with an error=] given |connection|, |command id|, and [=invalid session id=], and return. - 1. Run the following steps in parallel: + 1. [=Queue a WebDriver task=] to run the following: 1. Let |result| be the result of running the [=remote end steps=] for |command| given |session| and [=command parameters=] @@ -2410,7 +2414,8 @@ To Emit a context created event given |session| and |context|: The [=remote end event trigger=] is: When the [=create a new browsing context=] algorithm is invoked, after the -[=active document=] of the browsing context is set, run the following steps: +[=active document=] of the browsing context is set, [=queue a WebDriver task=] +to run the following steps: 1. Let |context| be the newly created browsing context. @@ -2454,23 +2459,25 @@ The [=remote end event trigger=] is: Define the following [=browsing context tree discarded=] steps: -1. Let |context| be the browsing context being discarded. +1. [=Queue a WebDriver task=] to run the following steps: -1. Let |params| be the result of [=get the browsing context info=], given - |context|, 0, and 0. + 1. Let |context| be the browsing context being discarded. -1. Let |body| be a [=map=] matching the - BrowsingContextDestroyedEvent production, with the - params field set to |params|. + 1. Let |params| be the result of [=get the browsing context info=], given + |context|, 0, and 0. -1. Let |related browsing contexts| be a set containing the [=parent browsing - context=] of |context|, if that is not null, or an empty set otherwise. + 1. Let |body| be a [=map=] matching the + BrowsingContextDestroyedEvent production, with the + params field set to |params|. -1. For each |session| in the [=set of sessions for which an event is enabled=] - given "browsingContext.contextDestroyed" and |related browsing - contexts|: + 1. Let |related browsing contexts| be a set containing the [=parent browsing + context=] of |context|, if that is not null, or an empty set otherwise. - 1. [=Emit an event=] with |session| and |body|. + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "browsingContext.contextDestroyed" and |related browsing + contexts|: + + 1. [=Emit an event=] with |session| and |body|. Issue: the way this hooks into HTML feels very fragile. See https://github.com/whatwg/html/issues/6194 @@ -2497,24 +2504,26 @@ become inaccessible but not yet get discarded because bfcache. The [=remote end event trigger=] is the WebDriver BiDi navigation started steps given |context| and |navigation status|: -1. Let |params| be the result of [=get the navigation info=] given |context| - and |navigation status|. +1. [=Queue a WebDriver task=] to run the following steps: - 1. Let |body| be a [=map=] matching the - BrowsingContextNavigationStarted production, with the - params field set to |params|. + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. -1. Let |navigation id| be |navigation status|'s id. + 1. Let |body| be a [=map=] matching the + BrowsingContextNavigationStarted production, with the + params field set to |params|. -1. Let |related browsing contexts| be a set containing |context|. + 1. Let |navigation id| be |navigation status|'s id. -1. [=Resume=] with "navigation started", |navigation id|, and - |navigation status|. + 1. Let |related browsing contexts| be a set containing |context|. -1. For each |session| in the [=set of sessions for which an event is enabled=] - given "browsingContext.navigationStarted" and |related browsing contexts|: + 1. [=Resume=] with "navigation started", |navigation id|, and + |navigation status|. - 1. [=Emit an event=] with |session| and |body|. + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "browsingContext.navigationStarted" and |related browsing contexts|: + + 1. [=Emit an event=] with |session| and |body|. @@ -2536,24 +2545,26 @@ started steps given |context| and |navigation status|: The [=remote end event trigger=] is the WebDriver BiDi fragment navigated steps given |context| and |navigation status|: -1. Let |params| be the result of [=get the navigation info=] given |context| - and |navigation status|. +1. [=Queue a WebDriver task=] to run the following steps: -1. Let |body| be a [=map=] matching the - BrowsingContextFragmentNavigatedEvent production, with the - params field set to |params|. + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. -1. Let |navigation id| be |navigation status|'s id. + 1. Let |body| be a [=map=] matching the + BrowsingContextFragmentNavigatedEvent production, with the + params field set to |params|. -1. Let |related browsing contexts| be a set containing |context|. + 1. Let |navigation id| be |navigation status|'s id. -1. [=Resume=] with "fragment navigated", |navigation id|, and - |navigation status|. + 1. Let |related browsing contexts| be a set containing |context|. -1. For each |session| in the [=set of sessions for which an event is enabled=] - given "browsingContext.fragmentNavigated" and |related browsing contexts|: + 1. [=Resume=] with "fragment navigated", |navigation id|, and + |navigation status|. - 1. [=Emit an event=] with |session| and |body|. + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "browsingContext.fragmentNavigated" and |related browsing contexts|: + + 1. [=Emit an event=] with |body| and |related browsing contexts|. @@ -2575,22 +2586,31 @@ navigated steps given |context| and |navigation status|: The [=remote end event trigger=] is the WebDriver BiDi DOM content loaded steps given |context| and |navigation status|: -1. Let |params| be the result of [=get the navigation info=] given |context| - and |navigation status|. +1. [=Queue a WebDriver task=] to run the following steps: -1. Let |body| be a [=map=] matching the - BrowsingContextDomContentLoadedEvent production, with the - params field set to |params|. + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. -1. Let |related browsing contexts| be a set containing |context|. + 1. Let |body| be a [=map=] matching the + BrowsingContextDomContentLoadedEvent production, with the + params field set to |params|. -1. Let |navigation id| be |navigation status|'s id. + 1. Let |related browsing contexts| be a set containing |context|. -1. [=Resume=] with "domContentLoaded", |navigation id|, and - |navigation status|. + 1. Let |navigation id| be |navigation status|'s id. -1. For each |session| in the [=set of sessions for which an event is enabled=] - given "browsingContext.domContentLoaded" and |related browsing contexts|: + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |body| be a [=map=] matching the + BrowsingContextDomContentLoadedEvent production, with the + params field set to |params|. + + 1. [=Resume=] with "domContentLoaded", |navigation id|, and + |navigation status|. + + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "browsingContext.domContentLoaded" and |related browsing contexts|: 1. [=Emit an event=] with |session| and |body|. @@ -2614,23 +2634,25 @@ loaded steps given |context| and |navigation status|: The [=remote end event trigger=] is the WebDriver BiDi load complete steps given |context| and |navigation status|: -1. Let |params| be the result of [=get the navigation info=] given |context| - and |navigation status|. +1. [=Queue a WebDriver task=] to run the following steps: -1. Let |body| be a [=map=] matching the BrowsingContextLoadEvent - production, with the params field set to |params|. + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. -1. Let |related browsing contexts| be a set containing |context|. + 1. Let |body| be a [=map=] matching the BrowsingContextLoadEvent + production, with the params field set to |params|. -1. Let |navigation id| be |navigation status|'s id. + 1. Let |related browsing contexts| be a set containing |context|. -1. [=Resume=] with "load", |navigation id| and - |navigation status|. + 1. Let |navigation id| be |navigation status|'s id. -1. For each |session| in the [=set of sessions for which an event is enabled=] - given "browsingContext.load" and |related browsing contexts|: + 1. [=Resume=] with "load", |navigation id| and + |navigation status|. - 1. [=Emit an event=] with |session| and |body|. + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "browsingContext.load" and |related browsing contexts|: + + 1. [=Emit an event=] with |session| and |body|. @@ -2652,23 +2674,28 @@ complete steps given |context| and |navigation status|: The [=remote end event trigger=] is the WebDriver BiDi download started steps given |context| and |navigation status|: - 1. Let |params| be the result of [=get the navigation info=] given |context| - and |navigation status|. +1. [=Queue a WebDriver task=] to run the following steps: - 1. Let |body| be a [=map=] matching the + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. + + 1. Let |body| be a [=map=] matching the BrowsingContextDownloadWillBegin production, with the params field set to |params|. - 1. Let |navigation id| be |navigation status|'s id. + 1. Let |navigation id| be |navigation status|'s id. - 1. Let |related browsing contexts| be a set containing |context|. + 1. Let |related browsing contexts| be a set containing |context|. - 1. [=Resume=] with "download started", |navigation id|, and |navigation status|. + 1. [=Resume=] with "download started", |navigation id|, and |navigation status|. - 1. For each |session| in the [=set of sessions for which an event is enabled=] - given "browsingContext.downloadWillBegin" and |related browsing contexts|: + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "browsingContext.downloadWillBegin" and |related browsing contexts|: - 1. [=Emit an event=] with |session| and |body|. + 1. [=Emit an event=] with |session| and |body|. @@ -2690,23 +2717,25 @@ started steps given |context| and |navigation status|: The [=remote end event trigger=] is the WebDriver BiDi navigation aborted steps given |context| and |navigation status|: -1. Let |params| be the result of [=get the navigation info=] given |context| - and |navigation status|. +1. [=Queue a WebDriver task=] to run the following steps: -1. Let |body| be a [=map=] matching the - BrowsingContextNavigationAborted production, with the - params field set to |params|. + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. -1. Let |navigation id| be |navigation status|'s id. + 1. Let |body| be a [=map=] matching the + BrowsingContextNavigationAborted production, with the + params field set to |params|. -1. Let |related browsing contexts| be a set containing |context|. + 1. Let |navigation id| be |navigation status|'s id. -1. [=Resume=] with "navigation aborted", |navigation id|, and |navigation status|. + 1. Let |related browsing contexts| be a set containing |context|. -1. For each |session| in the [=set of sessions for which an event is enabled=] - given "browsingContext.navigationAborted" and |related browsing contexts|: + 1. [=Resume=] with "navigation aborted", |navigation id|, and |navigation status|. - 1. [=Emit an event=] with |session| and |body|. + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "browsingContext.navigationAborted" and |related browsing contexts|: + + 1. [=Emit an event=] with |session| and |body|. @@ -2729,23 +2758,25 @@ aborted steps given |context| and |navigation status|: The [=remote end event trigger=] is the WebDriver BiDi navigation failed steps given |context| and |navigation status|: -1. Let |params| be the result of [=get the navigation info=] given |context| - and |navigation status|. +1. [=Queue a WebDriver task=] to run the following steps: -1. Let |body| be a [=map=] matching the - BrowsingContextNavigationFailed production, with the - params field set to |params|. + 1. Let |params| be the result of [=get the navigation info=] given |context| + and |navigation status|. -1. Let |navigation id| be |navigation status|'s id. + 1. Let |body| be a [=map=] matching the + BrowsingContextNavigationFailed production, with the + params field set to |params|. -1. Let |related browsing contexts| be a set containing |context|. + 1. Let |navigation id| be |navigation status|'s id. -1. [=Resume=] with "navigation failed", |navigation id|, and |navigation status|. + 1. Let |related browsing contexts| be a set containing |context|. -1. For each |session| in the [=set of sessions for which an event is enabled=] - given "browsingContext.navigationFailed" and |related browsing contexts|: + 1. [=Resume=] with "navigation failed", |navigation id|, and |navigation status|. - 1. [=Emit an event=] with |session| and |body|. + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "browsingContext.navigationFailed" and |related browsing contexts|: + + 1. [=Emit an event=] with |session| and |body|. @@ -3004,7 +3035,7 @@ The [=remote end event trigger=] is: When any of the [=set up a window environment settings object=], [=set up a worker environment settings object=] or [=set up a worklet environment settings object=] algorithms are invoked, immediately prior to returning the settings -object: +object, [=queue a WebDriver task=] to run the following steps: 1. Let |environment settings| be the newly created [=environment settings object=]. @@ -3086,49 +3117,51 @@ The [=remote end event trigger=] is:
Define the following [=unloading document cleanup steps=] with |document|: -1. Let |related browsing contexts| be an empty set. +1. [=Queue a WebDriver task=] to run the following steps: -1. Append |document|'s [=Document/browsing context=] to |related browsing - contexts|. + 1. Let |related browsing contexts| be an empty set. -1. For each |worklet global scope| in |document|'s [=worklet global scopes=]: + 1. Append |document|'s [=Document/browsing context=] to |related browsing + contexts|. - 1. Let |realm| be |worklet global scope|'s [=relevant Realm=]. + 1. For each |worklet global scope| in |document|'s [=worklet global scopes=]: - 1. Let |realm id| be the [=realm id=] for |realm|. + 1. Let |realm| be |worklet global scope|'s [=relevant Realm=]. - 1. Let |params| be a map mathcing the RealmDestroyedParameters - production, with the realm field set of |realm id|. + 1. Let |realm id| be the [=realm id=] for |realm|. - 1. Let |body| be a map matching the RealmDestroyedEvent - production, with the params field set to |params|. + 1. Let |params| be a map mathcing the RealmDestroyedParameters + production, with the realm field set of |realm id|. - 1. For each |session| in the [=set of sessions for which an event is enabled=] - given "script.realmDestroyed" and |related browsing contexts|: + 1. Let |body| be a map matching the RealmDestroyedEvent + production, with the params field set to |params|. - 1. [=Emit an event=] with |session| and |body|. + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "script.realmDestroyed" and |related browsing contexts|: -1. Let |environment settings| be the [=environment settings object=] whose - [=responsible document=] is |document|. + 1. [=Emit an event=] with |session| and |body|. -1. Let |realm| be |environment settings|' [=realm execution context=]'s Realm component. + 1. Let |environment settings| be the [=environment settings object=] whose + [=responsible document=] is |document|. -1. Let |realm id| be the [=realm id=] for |realm|. + 1. Let |realm| be |environment settings|' [=realm execution context=]'s Realm component. -1. Let |params| be a map mathcing the RealmDestroyedParameters - production, with the realm field set to |realm id|. + 1. Let |realm id| be the [=realm id=] for |realm|. -1. Let |body| be a map matching the RealmDestroyedEvent - production, with the params field set to |params|. + 1. Let |params| be a map mathcing the RealmDestroyedParameters + production, with the realm field set to |realm id|. -1. For each |session| in the [=set of sessions for which an event is enabled=] - given "script.realmDestroyed" and |related browsing contexts|: + 1. Let |body| be a map matching the RealmDestroyedEvent + production, with the params field set to |params|. - 1. [=Emit an event=] with |session| and |body|. + 1. For each |session| in the [=set of sessions for which an event is enabled=] + given "script.realmDestroyed" and |related browsing contexts|: + + 1. [=Emit an event=] with |session| and |body|. Whenever a [=worker event loop=] |event loop| is destroyed, either because the worker comes to the end of its lifecycle, or prematurely via the [=terminate a -worker=] algorithm: +worker=] algorithm, [=queue a WebDriver task=] to run the following steps: 1. Let |environment settings| be the [=environment settings object=] for which |event loop| is the [=responsible event loop=]. @@ -3327,90 +3360,94 @@ The [=remote end event trigger=] is: Define the following [=console steps=] with |method|, |args|, and options: -1. If |method| is "error" or "assert", let |level| be - "error". If |method| is "debug" or - "trace" let |level| be "debug". If |method| is - "warn" or warning, let |level| be - "warning". Otherwise let - |level| be "info". +1. [=Queue a WebDriver task=] to run the following steps: -1. Let |timestamp| be a [=time value=] representing the current date and time in UTC. + 1. If |method| is "error" or "assert", let |level| be + "error". If |method| is "debug" or + "trace" let |level| be "debug". If |method| is + "warn" or warning, let |level| be + "warning". Otherwise let + |level| be "info". -1. Let |text| be an empty string. + 1. Let |timestamp| be a [=time value=] representing the current date and time in UTC. -1. If [=Type=](||args|[0]) is String, and |args|[0] contains a [=formatting - specifier=], let |formatted args| be [=Formatter=](|args|). Otherwise let - |formatted args| be |args|. + 1. Let |text| be an empty string. - Issue: This is underdefined in the console spec, so it's unclar if we can get - interoperable behaviour here. + 1. If [=Type=](||args|[0]) is String, and |args|[0] contains a [=formatting + specifier=], let |formatted args| be [=Formatter=](|args|). Otherwise let + |formatted args| be |args|. -1. For each |arg| in |formatted args|: + Issue: This is underdefined in the console spec, so it's unclar if we can get + interoperable behaviour here. - 1. If |arg| is not the first entry in |args|, append a U+0020 SPACE to |text|. + 1. For each |arg| in |formatted args|: - 1. If |arg| is a [=primitive value=], append [=ToString=](|arg|) to - |text|. Otherwise append an implementation-defined string to |text|. + 1. If |arg| is not the first entry in |args|, append a U+0020 SPACE to |text|. -1. Let |serialized args| be a new list. + 1. If |arg| is a [=primitive value=], append [=ToString=](|arg|) to + |text|. Otherwise append an implementation-defined string to |text|. -1. For each |arg| of |args|, append the result of [=serialize as a remote - value=] given |arg|, null, true, and an empty [=set=] to |serialized args|. + 1. Let |serialized args| be a new list. -1. Let |realm| be the [=realm id=] of the [=current Realm Record=]. + 1. For each |arg| of |args|, append the result of [=serialize as a remote + value=] given |arg|, null, true, and an empty [=set=] to |serialized args|. -1. If |method| is "assert", "error", - "trace", or "warn", let |stack| be the [=current - stack trace=]. Otherwise let |stack| be null. + 1. Let |realm| be the [=realm id=] of the [=current Realm Record=]. -1. Let |entry| be a map matching the ConsoleLogEntry production, - with the the level field set to |level|, the text - field set to |text|, the timestamp field set to |timestamp|, the - stackTrace field set to |stack| if |stack| is not null, or - omitted otherwise, the |method| field set to |method|, the realm - field set to |realm| and the args field set to |serialized - args|. + 1. If |method| is "assert", "error", + "trace", or "warn", let |stack| be the [=current + stack trace=]. Otherwise let |stack| be null. -1. Let |body| be a map matching the LogEntryAddedEvent production, with - the params field set to |entry|. + 1. Let |entry| be a map matching the ConsoleLogEntry production, + with the the level field set to |level|, the text + field set to |text|, the timestamp field set to |timestamp|, the + stackTrace field set to |stack| if |stack| is not null, or + omitted otherwise, the |method| field set to |method|, the realm + field set to |realm| and the args field set to |serialized + args|. -1. Let |settings| be the [=current settings object=] + 1. Let |body| be a map matching the LogEntryAddedEvent production, with + the params field set to |entry|. -1. Let |related browsing contexts| be the result of [=get related browsing - contexts=] given |settings|. + 1. Let |settings| be the [=current settings object=] -1. For each |session| in [=active BiDi sessions=]: + 1. Let |related browsing contexts| be the result of [=get related browsing + contexts=] given |settings|. - 1. If [=event is enabled=] with |session|, "log.entryAdded" and - |related browsing contexts|, [=emit an event=] with |session| and |body|. + 1. For each |session| in [=active BiDi sessions=]: - Otherwise, [=buffer a log event=] with |session|, |related browsing - contexts|, and |body|. + 1. If [=event is enabled=] with |session|, "log.entryAdded" and + |related browsing contexts|, [=emit an event=] with |session| and |body|. + + Otherwise, [=buffer a log event=] with |session|, |related browsing + contexts|, and |body|. Define the following [=error reporting steps=] with arguments |script|, line number, column number, |message| and |handled|: -1. If |handled| is true return. +1. [=Queue a WebDriver task=] to run the following steps: -1. Let |settings| be |script|'s [=script/settings object=]. + 1. If |handled| is true return. -1. Let |stack| be the [=current stack trace=] for the exception. + 1. Let |settings| be |script|'s [=script/settings object=]. -1. Let |entry| be a map matching the JavascriptLogEntry production, - with level set to "error", text set to - |message|, and the timestamp field set to |timestamp|. + 1. Let |stack| be the [=current stack trace=] for the exception. -1. Let |related browsing contexts| be the result of [=get related browsing - contexts=] given |settings|. + 1. Let |entry| be a map matching the JavascriptLogEntry production, + with level set to "error", text set to + |message|, and the timestamp field set to |timestamp|. + + 1. Let |related browsing contexts| be the result of [=get related browsing + contexts=] given |settings|. -1. For each |session| in [=active BiDi sessions=]: + 1. For each |session| in [=active BiDi sessions=]: - 1. If [=event is enabled=] with |session|, "log.entryAdded" and - |related browsing contexts|, [=emit an event=] with |session| and |body|. + 1. If [=event is enabled=] with |session|, "log.entryAdded" and + |related browsing contexts|, [=emit an event=] with |session| and |body|. - Otherwise, [=buffer a log event=] with |session|, |related browsing - contexts|, and |body|. + Otherwise, [=buffer a log event=] with |session|, |related browsing + contexts|, and |body|. Issue: Lots more things require logging. CDP has LogEntryAdded types xml, javascript, network, storage, appcache, rendering, security, deprecation,