-
Notifications
You must be signed in to change notification settings - Fork 0
chore(stack): adopt current #252 into #255 #294
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7e85a7e
6b102c1
e77150f
5aa7d1a
9307eca
0b68198
cafa950
05cbc5c
f979972
0e1e47c
aadba11
583ffee
3a8c01f
615d840
65ac3ab
f0f2e20
74536b2
9bdd116
804a7a5
d5c7aea
bbdc6ac
edec535
cbd07e1
924ad97
6aaf7f3
e9d6794
363a78e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ use std::{collections::BTreeMap, error::Error, fmt}; | |
|
|
||
| use crate::{ | ||
| MAX_WEBDRIVER_BIDI_JS_UINT, WebDriverBiDiJsonEnvelope, WebDriverBiDiJsonEnvelopeRouting, | ||
| webdriver_bidi_connection::WebDriverBiDiConnectionGeneration, | ||
| }; | ||
|
|
||
| /// Maximum number of local WebDriver BiDi commands retained as outstanding at once. | ||
|
|
@@ -25,6 +26,12 @@ pub enum WebDriverBiDiCommandKind { | |
| SessionEnd, | ||
| } | ||
|
|
||
| #[derive(Clone, Copy, Debug, Eq, PartialEq)] | ||
| struct OutstandingCommand { | ||
| kind: WebDriverBiDiCommandKind, | ||
| connection_generation: Option<WebDriverBiDiConnectionGeneration>, | ||
| } | ||
|
|
||
| /// Outcome of a response after it has consumed the matching outstanding command identifier. | ||
| #[derive(Clone, Copy, Debug, Eq, PartialEq)] | ||
| pub enum WebDriverBiDiCorrelatedResponseOutcome { | ||
|
|
@@ -36,12 +43,15 @@ pub enum WebDriverBiDiCorrelatedResponseOutcome { | |
|
|
||
| /// Credential-free evidence that one parsed response consumed one outstanding local command. | ||
| /// | ||
| /// This value carries only the matched command identifier and success/error classification. It | ||
| /// does not retain result bodies, error text, browser authority, transport authority, or secrets. | ||
| /// This value carries only the matched command identifier and success/error classification. A | ||
| /// private process-local connection generation is retained when the command owner bound one before | ||
| /// I/O so later transport evidence can be compared without accepting caller-supplied provenance. | ||
| /// It does not retain result bodies, error text, browser authority, transport authority, or secrets. | ||
| #[derive(Clone, Copy, Debug, Eq, PartialEq)] | ||
| pub struct WebDriverBiDiCorrelatedResponse { | ||
| command_id: u64, | ||
| outcome: WebDriverBiDiCorrelatedResponseOutcome, | ||
| connection_generation: Option<WebDriverBiDiConnectionGeneration>, | ||
| } | ||
|
|
||
| impl WebDriverBiDiCorrelatedResponse { | ||
|
|
@@ -76,6 +86,16 @@ pub enum WebDriverBiDiCommandCorrelationError { | |
| /// Command family actually registered for the outstanding identifier. | ||
| actual: WebDriverBiDiCommandKind, | ||
| }, | ||
| /// A connection-bound consumer found an outstanding command with no connection provenance. | ||
| CommandConnectionProvenanceMissing { | ||
| /// Exact outstanding local command identifier. | ||
| command_id: u64, | ||
| }, | ||
| /// The response was received on a different verified connection from the outstanding command. | ||
| ResponseConnectionMismatch { | ||
| /// Exact outstanding local command identifier left untouched after rejection. | ||
| command_id: u64, | ||
| }, | ||
| /// An event is not a command response and cannot consume correlation state. | ||
| EventIsNotResponse, | ||
| /// A protocol error with a `null` id cannot be attributed to one outstanding command. | ||
|
|
@@ -92,6 +112,12 @@ impl fmt::Display for WebDriverBiDiCommandCorrelationError { | |
| Self::CommandKindMismatch { .. } => { | ||
| "WebDriver BiDi response command kind does not match the outstanding command" | ||
| } | ||
| Self::CommandConnectionProvenanceMissing { .. } => { | ||
| "WebDriver BiDi outstanding command lacks connection provenance" | ||
| } | ||
| Self::ResponseConnectionMismatch { .. } => { | ||
| "WebDriver BiDi response arrived on a different connection" | ||
| } | ||
| Self::EventIsNotResponse => "WebDriver BiDi event cannot be correlated as a response", | ||
| Self::UncorrelatableErrorResponse => { | ||
| "WebDriver BiDi error response has no correlatable command id" | ||
|
|
@@ -106,14 +132,17 @@ impl Error for WebDriverBiDiCommandCorrelationError {} | |
| /// Bounded local WebDriver BiDi command-response correlation state. | ||
| /// | ||
| /// Register an id together with its exact typed command family only after the caller has committed | ||
| /// to that outbound command. A success or correlatable error response consumes the id exactly once | ||
| /// only through a matching typed consumer. Events, null-id errors, and command-kind mismatches leave | ||
| /// outstanding state untouched. This type performs no I/O, retry, command serialization, browser | ||
| /// authentication, or authority grant. Debug output reports only the outstanding-count summary; | ||
| /// command identifiers and command families remain private correlation state. | ||
| /// to that outbound command. Connection-owning command adapters may additionally bind the private | ||
| /// generation of the exact established transport before I/O. A success or correlatable error | ||
| /// response consumes the id exactly once only through a matching typed consumer. Events, null-id | ||
| /// errors, command-kind mismatches, missing connection provenance, and responses received on a | ||
| /// different verified connection leave outstanding state untouched. This type performs no I/O, | ||
| /// retry, command serialization, browser authentication, or authority grant. Debug output reports | ||
| /// only the outstanding-count summary; command identifiers, families, and generations remain | ||
| /// private correlation state. | ||
| #[derive(Default)] | ||
| pub struct WebDriverBiDiCommandCorrelation { | ||
| outstanding: BTreeMap<u64, WebDriverBiDiCommandKind>, | ||
| outstanding: BTreeMap<u64, OutstandingCommand>, | ||
| } | ||
|
|
||
| impl fmt::Debug for WebDriverBiDiCommandCorrelation { | ||
|
|
@@ -147,6 +176,24 @@ impl WebDriverBiDiCommandCorrelation { | |
| &mut self, | ||
| command_id: u64, | ||
| command_kind: WebDriverBiDiCommandKind, | ||
| ) -> Result<(), WebDriverBiDiCommandCorrelationError> { | ||
| self.register(command_id, command_kind, None) | ||
| } | ||
|
|
||
| pub(crate) fn register_command_for_connection( | ||
| &mut self, | ||
| command_id: u64, | ||
| command_kind: WebDriverBiDiCommandKind, | ||
| connection_generation: WebDriverBiDiConnectionGeneration, | ||
| ) -> Result<(), WebDriverBiDiCommandCorrelationError> { | ||
| self.register(command_id, command_kind, Some(connection_generation)) | ||
| } | ||
|
|
||
| fn register( | ||
| &mut self, | ||
| command_id: u64, | ||
| command_kind: WebDriverBiDiCommandKind, | ||
| connection_generation: Option<WebDriverBiDiConnectionGeneration>, | ||
| ) -> Result<(), WebDriverBiDiCommandCorrelationError> { | ||
| if command_id > MAX_WEBDRIVER_BIDI_JS_UINT { | ||
| return Err(WebDriverBiDiCommandCorrelationError::CommandIdOutOfRange); | ||
|
|
@@ -157,7 +204,13 @@ impl WebDriverBiDiCommandCorrelation { | |
| if self.outstanding.len() >= MAX_WEBDRIVER_BIDI_OUTSTANDING_COMMANDS { | ||
| return Err(WebDriverBiDiCommandCorrelationError::OutstandingCommandLimit); | ||
| } | ||
| let _previous = self.outstanding.insert(command_id, command_kind); | ||
| let _previous = self.outstanding.insert( | ||
| command_id, | ||
| OutstandingCommand { | ||
| kind: command_kind, | ||
| connection_generation, | ||
| }, | ||
| ); | ||
| Ok(()) | ||
| } | ||
|
|
||
|
|
@@ -179,51 +232,49 @@ impl WebDriverBiDiCommandCorrelation { | |
| /// | ||
| /// Successful responses and error responses with ids consume exactly one matching command. | ||
| /// Unknown ids and command-kind mismatches fail without consuming state. Events and null-id | ||
| /// errors fail before touching the map. | ||
| /// errors fail before touching the map. This generic path does not claim received-connection | ||
| /// provenance; connection-sensitive command owners must use their connection-bound path. | ||
| pub fn correlate_response_for( | ||
| &mut self, | ||
| envelope: &WebDriverBiDiJsonEnvelope, | ||
| expected_kind: WebDriverBiDiCommandKind, | ||
| ) -> Result<WebDriverBiDiCorrelatedResponse, WebDriverBiDiCommandCorrelationError> { | ||
| match envelope.routing() { | ||
| WebDriverBiDiJsonEnvelopeRouting::Event => { | ||
| Err(WebDriverBiDiCommandCorrelationError::EventIsNotResponse) | ||
| } | ||
| WebDriverBiDiJsonEnvelopeRouting::CommandError { command_id: None } => { | ||
| Err(WebDriverBiDiCommandCorrelationError::UncorrelatableErrorResponse) | ||
| } | ||
| WebDriverBiDiJsonEnvelopeRouting::CommandError { | ||
| command_id: Some(command_id), | ||
| } => self.complete( | ||
| command_id, | ||
| expected_kind, | ||
| WebDriverBiDiCorrelatedResponseOutcome::Error, | ||
| ), | ||
| WebDriverBiDiJsonEnvelopeRouting::CommandSuccess { command_id } => self.complete( | ||
| command_id, | ||
| expected_kind, | ||
| WebDriverBiDiCorrelatedResponseOutcome::Success, | ||
| ), | ||
| } | ||
| let (command_id, outcome) = response_route(envelope)?; | ||
| self.complete(command_id, expected_kind, outcome) | ||
|
Comment on lines
+242
to
+243
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟥 Connection-bound replies remain bypassable A caller can pass a replacement connection's matching envelope to Was this helpful? React with 👍 or 👎 to provide feedback. |
||
| } | ||
|
|
||
| pub(crate) fn correlate_response_for_connection( | ||
| &mut self, | ||
| envelope: &WebDriverBiDiJsonEnvelope, | ||
| expected_kind: WebDriverBiDiCommandKind, | ||
| received_connection_generation: WebDriverBiDiConnectionGeneration, | ||
| ) -> Result<WebDriverBiDiCorrelatedResponse, WebDriverBiDiCommandCorrelationError> { | ||
| let (command_id, outcome) = response_route(envelope)?; | ||
| self.complete_on_connection( | ||
| command_id, | ||
| expected_kind, | ||
| outcome, | ||
| received_connection_generation, | ||
| ) | ||
| } | ||
|
|
||
| fn require_command_kind( | ||
| &self, | ||
| command_id: u64, | ||
| expected_kind: WebDriverBiDiCommandKind, | ||
| ) -> Result<(), WebDriverBiDiCommandCorrelationError> { | ||
| ) -> Result<OutstandingCommand, WebDriverBiDiCommandCorrelationError> { | ||
| let actual = self | ||
| .outstanding | ||
| .get(&command_id) | ||
| .copied() | ||
| .ok_or(WebDriverBiDiCommandCorrelationError::CommandNotOutstanding)?; | ||
| if actual != expected_kind { | ||
| if actual.kind != expected_kind { | ||
| return Err(WebDriverBiDiCommandCorrelationError::CommandKindMismatch { | ||
| expected: expected_kind, | ||
| actual, | ||
| actual: actual.kind, | ||
| }); | ||
| } | ||
| Ok(()) | ||
| Ok(actual) | ||
| } | ||
|
|
||
| fn complete( | ||
|
|
@@ -232,15 +283,59 @@ impl WebDriverBiDiCommandCorrelation { | |
| expected_kind: WebDriverBiDiCommandKind, | ||
| outcome: WebDriverBiDiCorrelatedResponseOutcome, | ||
| ) -> Result<WebDriverBiDiCorrelatedResponse, WebDriverBiDiCommandCorrelationError> { | ||
| self.require_command_kind(command_id, expected_kind)?; | ||
| let outstanding = self.require_command_kind(command_id, expected_kind)?; | ||
| let _removed = self.outstanding.remove(&command_id); | ||
| Ok(WebDriverBiDiCorrelatedResponse { | ||
| command_id, | ||
| outcome, | ||
| connection_generation: outstanding.connection_generation, | ||
| }) | ||
| } | ||
|
|
||
| fn complete_on_connection( | ||
| &mut self, | ||
| command_id: u64, | ||
| expected_kind: WebDriverBiDiCommandKind, | ||
| outcome: WebDriverBiDiCorrelatedResponseOutcome, | ||
| received_connection_generation: WebDriverBiDiConnectionGeneration, | ||
| ) -> Result<WebDriverBiDiCorrelatedResponse, WebDriverBiDiCommandCorrelationError> { | ||
| let outstanding = self.require_command_kind(command_id, expected_kind)?; | ||
| let expected_connection_generation = outstanding.connection_generation.ok_or( | ||
| WebDriverBiDiCommandCorrelationError::CommandConnectionProvenanceMissing { command_id }, | ||
| )?; | ||
| if expected_connection_generation != received_connection_generation { | ||
| return Err( | ||
| WebDriverBiDiCommandCorrelationError::ResponseConnectionMismatch { command_id }, | ||
| ); | ||
| } | ||
| let _removed = self.outstanding.remove(&command_id); | ||
| Ok(WebDriverBiDiCorrelatedResponse { | ||
| command_id, | ||
| outcome, | ||
| connection_generation: Some(expected_connection_generation), | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| fn response_route( | ||
| envelope: &WebDriverBiDiJsonEnvelope, | ||
| ) -> Result<(u64, WebDriverBiDiCorrelatedResponseOutcome), WebDriverBiDiCommandCorrelationError> { | ||
| match envelope.routing() { | ||
| WebDriverBiDiJsonEnvelopeRouting::Event => { | ||
| Err(WebDriverBiDiCommandCorrelationError::EventIsNotResponse) | ||
| } | ||
| WebDriverBiDiJsonEnvelopeRouting::CommandError { command_id: None } => { | ||
| Err(WebDriverBiDiCommandCorrelationError::UncorrelatableErrorResponse) | ||
| } | ||
| WebDriverBiDiJsonEnvelopeRouting::CommandError { | ||
| command_id: Some(command_id), | ||
| } => Ok((command_id, WebDriverBiDiCorrelatedResponseOutcome::Error)), | ||
| WebDriverBiDiJsonEnvelopeRouting::CommandSuccess { command_id } => { | ||
| Ok((command_id, WebDriverBiDiCorrelatedResponseOutcome::Success)) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::{WebDriverBiDiCommandCorrelationError, WebDriverBiDiCommandKind}; | ||
|
|
@@ -271,6 +366,16 @@ mod tests { | |
| }, | ||
| "WebDriver BiDi response command kind does not match the outstanding command", | ||
| ), | ||
| ( | ||
| WebDriverBiDiCommandCorrelationError::CommandConnectionProvenanceMissing { | ||
| command_id: 7, | ||
| }, | ||
| "WebDriver BiDi outstanding command lacks connection provenance", | ||
| ), | ||
| ( | ||
| WebDriverBiDiCommandCorrelationError::ResponseConnectionMismatch { command_id: 7 }, | ||
| "WebDriver BiDi response arrived on a different connection", | ||
| ), | ||
| ( | ||
| WebDriverBiDiCommandCorrelationError::EventIsNotResponse, | ||
| "WebDriver BiDi event cannot be correlated as a response", | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔍 Legacy assembly path remains public
Raw frame reads and
WebDriverBiDiWebSocketMessageAssemblerstill permit transport-detached assembly. Review whether retaining this public path leaves the provenance migration incomplete.(Refers to this code)
Was this helpful? React with 👍 or 👎 to provide feedback.