///|
fn parent_ctx(stack : Array[String]) -> String {
if stack.length() == 0 {
"main"
} else {
stack[stack.length() - 1]
}
}
///|
fn enter_ctx(name : String, cur : String) -> String {
if name == "events" {
"events"
} else if name == "http" {
"http"
} else if name == "stream" {
"stream"
} else if name == "mail" {
"mail"
} else if name == "server" {
if cur == "upstream" {
cur
} else {
"server"
}
} else if name == "location" {
"location"
} else if name == "upstream" {
"upstream"
} else if name == "if" {
"if"
} else if name == "limit_except" {
"limit_except"
} else if name == "map" ||
name == "geo" ||
name == "split_clients" ||
name == "types" {
"map"
} else {
cur
}
}
///|
fn validate_dir(d : Directive, stack : Array[String]) -> Result[Unit, NgxError] {
if d.name == "#" {
return Ok(())
}
let cur = parent_ctx(stack)
if cur == "map" {
return Ok(())
}
match lookup_spec(d.name, cur) {
None => Ok(())
Some(sp) => {
if !ctx_in(sp.ctxs, cur) {
return Err(
Constraint(
line_msg(
d.line,
"directive " + d.name + " is not allowed in " + cur,
),
),
)
}
let n = d.args.length()
if n < sp.min_args || n > sp.max_args {
return Err(
Constraint(
line_msg(
d.line,
"invalid number of arguments in " + d.name + " directive",
),
),
)
}
if sp.form == 1 && !d.has_block {
return Err(
Constraint(
line_msg(d.line, "directive " + d.name + " requires a block"),
),
)
}
if sp.form == 0 && d.has_block {
return Err(
Constraint(
line_msg(d.line, "directive " + d.name + " is not terminated by ;"),
),
)
}
if d.has_block {
let next = enter_ctx(d.name, cur)
let st2 : Array[String] = []
let mut i = 0
while i < stack.length() {
st2.push(stack[i])
i = i + 1
}
st2.push(next)
validate_list(d.children, st2)
} else {
Ok(())
}
}
}
}
///|
fn validate_list(
xs : Array[Directive],
stack : Array[String],
) -> Result[Unit, NgxError] {
let mut i = 0
while i < xs.length() {
match validate_dir(xs[i], stack) {
Err(e) => return Err(e)
Ok(_) => ()
}
i = i + 1
}
Ok(())
}
///|
pub fn validate_core(cfg : Config) -> Result[Unit, NgxError] {
validate_list(cfg.parsed, [])
}
///|
pub fn parse_and_validate(text : String) -> Result[Config, NgxError] {
match parse_conf(text) {
Err(e) => Err(e)
Ok(cfg) =>
match validate_core(cfg) {
Err(e) => Err(e)
Ok(_) => Ok(cfg)
}
}
}