///|
/// WebDriver BiDi emulation override state.
///
/// Each emulation feature follows the same precedence model:
/// context override, user-context override, then global override.
///
/// Per-session `@browser_http.Profile` values carry HTTP security state
/// only (cookies, auth, CORS/cache). User-agent overrides stay in this
/// emulation state so identity spoofing controls are separated from HTTP
/// credential state.
priv struct BidiEmulationState {
mut emulation_user_agent_global : String?
emulation_user_agent_by_context : Map[String, String] // top-level context -> userAgent override
emulation_user_agent_by_user_context : Map[String, String] // user context -> userAgent override
session_profiles : Map[String, @browser_http.Profile] // session id -> per-session profile
mut emulation_locale_global : String?
emulation_locale_by_context : Map[String, String] // top-level context -> locale override
emulation_locale_by_user_context : Map[String, String] // user context -> locale override
mut emulation_timezone_global : String?
emulation_timezone_by_context : Map[String, String] // top-level context -> timezone override
emulation_timezone_by_user_context : Map[String, String] // user context -> timezone override
mut emulation_geolocation_global : Json?
emulation_geolocation_by_context : Map[String, Json] // top-level context -> geolocation override
emulation_geolocation_by_user_context : Map[String, Json] // user context -> geolocation override
mut emulation_network_conditions_global : Json?
emulation_network_conditions_by_context : Map[String, Json] // top-level context -> network conditions override
emulation_network_conditions_by_user_context : Map[String, Json] // user context -> network conditions override
mut emulation_screen_orientation_global : Json?
emulation_screen_orientation_by_context : Map[String, Json] // top-level context -> screen orientation override
emulation_screen_orientation_by_user_context : Map[String, Json] // user context -> screen orientation override
mut emulation_screen_area_global : Json?
emulation_screen_area_by_context : Map[String, Json] // top-level context -> screen area override
emulation_screen_area_by_user_context : Map[String, Json] // user context -> screen area override
}
///|
fn BidiEmulationState::new() -> BidiEmulationState {
{
emulation_user_agent_global: None,
emulation_user_agent_by_context: {},
emulation_user_agent_by_user_context: {},
emulation_locale_global: None,
emulation_locale_by_context: {},
emulation_locale_by_user_context: {},
emulation_timezone_global: None,
emulation_timezone_by_context: {},
emulation_timezone_by_user_context: {},
emulation_geolocation_global: None,
emulation_geolocation_by_context: {},
emulation_geolocation_by_user_context: {},
emulation_network_conditions_global: None,
emulation_network_conditions_by_context: {},
emulation_network_conditions_by_user_context: {},
emulation_screen_orientation_global: None,
emulation_screen_orientation_by_context: {},
emulation_screen_orientation_by_user_context: {},
emulation_screen_area_global: None,
emulation_screen_area_by_context: {},
emulation_screen_area_by_user_context: {},
session_profiles: {},
}
}
///|
fn BidiEmulationState::reset(self : BidiEmulationState) -> Unit {
self.emulation_user_agent_global = None
clear_string_map(self.emulation_user_agent_by_context)
clear_string_map(self.emulation_user_agent_by_user_context)
self.emulation_locale_global = None
clear_string_map(self.emulation_locale_by_context)
clear_string_map(self.emulation_locale_by_user_context)
self.emulation_timezone_global = None
clear_string_map(self.emulation_timezone_by_context)
clear_string_map(self.emulation_timezone_by_user_context)
self.emulation_geolocation_global = None
clear_json_map(self.emulation_geolocation_by_context)
clear_json_map(self.emulation_geolocation_by_user_context)
self.emulation_network_conditions_global = None
clear_json_map(self.emulation_network_conditions_by_context)
clear_json_map(self.emulation_network_conditions_by_user_context)
self.emulation_screen_orientation_global = None
clear_json_map(self.emulation_screen_orientation_by_context)
clear_json_map(self.emulation_screen_orientation_by_user_context)
self.emulation_screen_area_global = None
clear_json_map(self.emulation_screen_area_by_context)
clear_json_map(self.emulation_screen_area_by_user_context)
clear_profile_map(self.session_profiles)
}
///|
/// Look up (or lazily create) the per-session profile for `ctx_id`.
/// Returns None when the session is unknown to the CDP session manager —
/// the caller should treat that as "ignore this update", not as an error.
fn BidiProtocol::profile_for_session(
self : BidiProtocol,
ctx_id : String,
) -> @browser_http.Profile? {
if !self.manager.has_session(ctx_id) {
return None
}
match self.emulation_state.session_profiles.get(ctx_id) {
Some(profile) => Some(profile)
None => {
let profile = @browser_http.Profile::default()
self.emulation_state.session_profiles[ctx_id] = profile
Some(profile)
}
}
}
///|
fn clear_profile_map(values : Map[String, @browser_http.Profile]) -> Unit {
let keys : Array[String] = []
for key, _ in values {
keys.push(key)
}
for key in keys {
values.remove(key)
}
}
///|
fn clear_string_map(values : Map[String, String]) -> Unit {
let keys : Array[String] = []
for key, _ in values {
keys.push(key)
}
for key in keys {
values.remove(key)
}
}
///|
fn clear_json_map(values : Map[String, Json]) -> Unit {
let keys : Array[String] = []
for key, _ in values {
keys.push(key)
}
for key in keys {
values.remove(key)
}
}