///|
/// Supported serialized argument types for script.addPreloadScript.
fn is_supported_preload_argument_type(type_name : String) -> Bool {
type_name == "array" ||
type_name == "bigint" ||
type_name == "boolean" ||
type_name == "channel" ||
type_name == "date" ||
type_name == "map" ||
type_name == "null" ||
type_name == "number" ||
type_name == "object" ||
type_name == "regexp" ||
type_name == "set" ||
type_name == "string" ||
type_name == "undefined"
}
///|
/// Parse and validate script.addPreloadScript parameters.
fn BidiProtocol::parse_add_preload_script_params(
self : BidiProtocol,
request_id : Int,
params : Json?,
) -> AddPreloadScriptParams? {
let map = match params {
Some(Object(map)) => map
_ => {
self.send_error(
request_id, "invalid argument", "params must be an object",
)
return None
}
}
let function_declaration = match
get_map_field_with_alias(map, "functionDeclaration", "function_declaration") {
Some(String(function_declaration)) => function_declaration
Some(_) => {
self.send_error(
request_id, "invalid argument", "functionDeclaration must be a string",
)
return None
}
None => {
self.send_error(
request_id, "invalid argument", "Missing functionDeclaration",
)
return None
}
}
let mut arguments : Array[Json] = []
match map.get("arguments") {
Some(Array(args)) => arguments = args
Some(_) => {
self.send_error(
request_id, "invalid argument", "arguments must be an array",
)
return None
}
None => ()
}
let argument_params = if map.contains("arguments") {
Some(make_object({ "arguments": Json::array(arguments) }))
} else {
None
}
match self.validate_arguments_param(request_id, argument_params) {
Some(_) => return None
None => ()
}
for argument in arguments {
match argument {
Object(arg_map) =>
match arg_map.get("type") {
Some(String(type_name)) => {
if !is_supported_preload_argument_type(type_name) {
self.send_error(
request_id, "invalid argument", "arguments entries must be serialized values",
)
return None
}
if type_name == "channel" {
match arg_map.get("value") {
Some(Object(channel_val)) =>
match channel_val.get("channel") {
Some(String(_)) => ()
_ => {
self.send_error(
request_id, "invalid argument", "channel.channel must be a string",
)
return None
}
}
_ => ()
}
}
}
_ => ()
}
_ => ()
}
}
let sandbox = match map.get("sandbox") {
Some(String(name)) => Some(name)
Some(_) => {
self.send_error(
request_id, "invalid argument", "sandbox must be a string",
)
return None
}
None => None
}
let contexts_raw = map.get("contexts")
let contexts : Array[String] = []
match contexts_raw {
Some(Array(items)) => {
if items.length() == 0 {
self.send_error(
request_id, "invalid argument", "contexts must not be an empty array",
)
return None
}
for item in items {
match item {
String(ctx_id) =>
if ctx_id == "" || !self.manager.has_session(ctx_id) {
self.send_error(
request_id,
"no such frame",
"Unknown context: " + ctx_id,
)
return None
} else if self.context_parent.contains(ctx_id) {
self.send_error(
request_id, "invalid argument", "contexts entries must be top-level contexts",
)
return None
} else if !array_contains(contexts, ctx_id) {
contexts.push(ctx_id)
}
_ => {
self.send_error(
request_id, "invalid argument", "contexts entries must be strings",
)
return None
}
}
}
}
Some(_) => {
self.send_error(
request_id, "invalid argument", "contexts must be an array",
)
return None
}
None => ()
}
let user_contexts_raw = get_map_field_with_alias(
map, "userContexts", "user_contexts",
)
let user_contexts : Array[String] = []
match user_contexts_raw {
Some(Array(items)) => {
if items.length() == 0 {
self.send_error(
request_id, "invalid argument", "userContexts must not be an empty array",
)
return None
}
for item in items {
match item {
String(user_context_id) =>
if user_context_id == "" ||
!self.user_contexts.contains(user_context_id) {
self.send_error(
request_id,
"no such user context",
"Unknown user context: " + user_context_id,
)
return None
} else if !array_contains(user_contexts, user_context_id) {
user_contexts.push(user_context_id)
}
_ => {
self.send_error(
request_id, "invalid argument", "userContexts entries must be strings",
)
return None
}
}
}
}
Some(_) => {
self.send_error(
request_id, "invalid argument", "userContexts must be an array",
)
return None
}
None => ()
}
if contexts.length() > 0 && user_contexts.length() > 0 {
self.send_error(
request_id, "invalid argument", "contexts and userContexts cannot be used together",
)
return None
}
Some({ function_declaration, arguments, sandbox, contexts, user_contexts })
}
///|
fn BidiProtocol::register_preload_script(
self : BidiProtocol,
parsed : AddPreloadScriptParams,
) -> String {
let script_id = "preload-" + self.next_preload_script_id.to_string()
self.next_preload_script_id += 1
self.preload_scripts.push({
script_id,
function_declaration: parsed.function_declaration,
arguments: parsed.arguments,
sandbox: parsed.sandbox,
contexts: parsed.contexts,
user_contexts: parsed.user_contexts,
})
script_id
}