///|
/// Send script.evaluate success response with `undefined` result.
fn BidiProtocol::send_script_undefined_result(
self : BidiProtocol,
request_id : Int,
realm_id : String,
) -> Unit {
self.send_script_remote_value_result(
request_id,
realm_id,
make_object({ "type": Json::string("undefined") }),
)
}
///|
fn BidiProtocol::send_script_remote_value_result(
self : BidiProtocol,
request_id : Int,
realm_id : String,
remote_value : Json,
) -> Unit {
let result = make_object({
"realm": Json::string(realm_id),
"result": remote_value,
})
self.send_success(request_id, Some(result))
}
///|
fn BidiProtocol::send_script_synthetic_value_response(
self : BidiProtocol,
request_id : Int,
remote_value : Json,
) -> Unit {
let payload_value = match remote_value {
Object(map) =>
match (map.get("type"), map.get("value")) {
(Some(String("string")), Some(value)) => value
(Some(String("number")), Some(value)) => value
(Some(String("boolean")), Some(value)) => value
_ => remote_value
}
_ => remote_value
}
let result = make_object({
"id": Json::number(request_id.to_double()),
"type": Json::string("success"),
"value": payload_value,
})
self.send_raw(result.stringify())
}
///|
fn BidiProtocol::send_script_remote_value_response(
self : BidiProtocol,
request_id : Int,
realm_id : String,
remote_value : Json,
unwrap_result : Bool,
) -> Unit {
if unwrap_result {
self.send_success(request_id, Some(remote_value))
} else {
self.send_script_remote_value_result(request_id, realm_id, remote_value)
}
}
///|
fn BidiProtocol::send_script_exception_result(
self : BidiProtocol,
request_id : Int,
realm_id : String,
eval_result : Json,
) -> Unit {
let exc_details = get_field(eval_result, "exceptionDetails").unwrap_or(
make_object({}),
)
let result = make_object({
"realm": Json::string(realm_id),
"exceptionDetails": exc_details,
})
self.send_success(request_id, Some(result))
}
///|
fn BidiProtocol::send_script_undefined_response(
self : BidiProtocol,
request_id : Int,
realm_id : String,
unwrap_result : Bool,
) -> Unit {
if unwrap_result {
self.send_success(
request_id,
Some(make_object({ "type": Json::string("undefined") })),
)
} else {
self.send_script_undefined_result(request_id, realm_id)
}
}
///|
fn BidiProtocol::send_script_eval_result_mode(
self : BidiProtocol,
request_id : Int,
realm_id : String,
eval_result : Json,
unwrap_result : Bool,
) -> Unit {
match get_string_field(eval_result, "type") {
Some("success") => {
let bidi_value = get_field(eval_result, "result").unwrap_or(
make_object({ "type": Json::string("undefined") }),
)
self.send_script_remote_value_response(
request_id, realm_id, bidi_value, unwrap_result,
)
}
Some("exception") =>
self.send_script_exception_result(request_id, realm_id, eval_result)
_ =>
self.send_script_undefined_response(request_id, realm_id, unwrap_result)
}
}
///|
/// Resolve unhandled prompt handler for context/prompt type.
fn BidiProtocol::resolve_unhandled_prompt_handler(
self : BidiProtocol,
ctx_id : String,
prompt_type : String,
) -> String {
let user_context_id = self.context_user_context
.get(ctx_id)
.unwrap_or("default")
let behavior_key = if prompt_type == "beforeunload" {
"beforeUnload"
} else {
prompt_type
}
match self.user_context_prompt_behavior.get(user_context_id) {
Some(Object(behavior)) =>
match behavior.get(behavior_key) {
Some(String(handler)) => handler
_ =>
match behavior.get("default") {
Some(String(default_handler)) => default_handler
_ => if prompt_type == "file" { "ignore" } else { "dismiss" }
}
}
_ => if prompt_type == "file" { "ignore" } else { "dismiss" }
}
}
///|
/// Resolve effective download behavior for a context.
fn BidiProtocol::resolve_download_behavior(
self : BidiProtocol,
ctx_id : String,
) -> Json? {
let user_context_id = self.context_user_context
.get(ctx_id)
.unwrap_or("default")
match self.user_context_download_behavior.get(user_context_id) {
Some(behavior) => Some(behavior)
None => self.global_download_behavior
}
}
///|
/// Extract prompt message argument from expression/source.
fn extract_prompt_message_from_source(
source : String,
prompt_type : String,
) -> String {
let marker_candidates : Array[String] = []
match prompt_type {
"alert" => {
marker_candidates.push("window.alert(")
marker_candidates.push("alert(")
}
"confirm" => {
marker_candidates.push("window.confirm(")
marker_candidates.push("confirm(")
}
"prompt" => {
marker_candidates.push("window.prompt(")
marker_candidates.push("prompt(")
}
_ => ()
}
for marker in marker_candidates {
match extract_quoted_after_marker(source, marker) {
Some(message) => return message
None => ()
}
}
""
}
///|
/// Extract prompt defaultValue argument when present.
fn extract_prompt_default_value_from_source(source : String) -> String? {
let marker_candidates : Array[String] = []
marker_candidates.push("window.prompt(")
marker_candidates.push("prompt(")
for marker in marker_candidates {
match extract_second_quoted_after_marker(source, marker) {
Some(value) => return Some(value)
None => ()
}
}
None
}
///|
/// Detect prompt-like inline scripts on navigated data URLs.
fn BidiProtocol::register_navigation_prompt_from_url(
self : BidiProtocol,
ctx_id : String,
url : String,
) -> Unit {
if !url.has_prefix("data:") {
return
}
match parse_data_url(url) {
Some((_content_type, content)) => {
let mut prompt_type : String? = None
let mut result_var : String? = None
if content.contains("window.alert(") {
prompt_type = Some("alert")
} else if content.contains("window.confirm(") {
prompt_type = Some("confirm")
if content.contains("window.response = window.confirm(") {
result_var = Some("window.response")
}
} else if content.contains("window.prompt(") {
prompt_type = Some("prompt")
}
match prompt_type {
Some(kind) => {
let handler = self.resolve_unhandled_prompt_handler(ctx_id, kind)
let message = extract_prompt_message_from_source(content, kind)
let default_value = if kind == "prompt" {
Some(
extract_prompt_default_value_from_source(content).unwrap_or(""),
)
} else {
None
}
self.clear_pending_prompt_state(ctx_id)
self.pending_prompt_type[ctx_id] = kind
match result_var {
Some(name) => self.pending_prompt_result_var[ctx_id] = name
None => ()
}
self.emit_user_prompt_opened(
ctx_id, kind, handler, message, default_value,
)
}
None => ()
}
}
None => ()
}
}
///|
/// Build script.evaluate result payload for a handled user prompt.
fn BidiProtocol::send_script_prompt_result(
self : BidiProtocol,
request_id : Int,
realm_id : String,
prompt_type : String,
accepted : Bool,
user_text : String?,
unwrap_result : Bool,
) -> Unit {
let remote_value = match prompt_type {
"confirm" =>
make_object({
"type": Json::string("boolean"),
"value": Json::boolean(accepted),
})
"prompt" =>
if accepted {
make_object({
"type": Json::string("string"),
"value": Json::string(user_text.unwrap_or("")),
})
} else {
make_object({ "type": Json::string("null") })
}
_ => make_object({ "type": Json::string("undefined") })
}
self.send_script_remote_value_response(
request_id, realm_id, remote_value, unwrap_result,
)
}
///|
/// Compatibility facade for the canonical remote_value_as_bool in @protocol.
fn remote_value_as_bool(value : Json) -> Bool? {
@protocol.remote_value_as_bool(value)
}
///|
/// Compatibility facade for the canonical remote_value_as_string in @protocol.
fn remote_value_as_string(value : Json) -> String? {
@protocol.remote_value_as_string(value)
}
///|
/// Compatibility facade for the canonical remote_value_as_number in @protocol.
fn remote_value_as_number(value : Json) -> Double? {
@protocol.remote_value_as_number(value)
}
///|
fn simplify_node_remote_value(value : Json) -> Json? {
match value {
Object(map) =>
match map.get("sharedId") {
Some(String(shared_id)) =>
Some(make_object({ "sharedId": Json::string(shared_id) }))
_ => None
}
_ => None
}
}