Skip to main content

rl_lang/interpreter/stdlib/http/
http_respond.rs

1use crate::{
2    interpreter::{
3        evaluator::Evaluator,
4        stdlib::{
5            common::{check_arity_range, extract_number, extract_string, verr, vok, vs},
6            http::HttpHandle,
7        },
8        values::Value,
9    },
10    utils::{errors::Error, span::Span},
11};
12
13pub fn func(eval: &mut Evaluator, args: Vec<Value>, span: Span) -> Result<Value, Error> {
14    check_arity_range(&args, 3, 4, "http_post", span)?;
15
16    let id = match extract_number(args[0].clone(), "http_respond") {
17        Ok(a) if a as i64 >= 0 => a as i64,
18        Ok(_) => {
19            return Ok(verr!(vs!(
20                "http_respond: id handle cannot be negative".to_string()
21            )));
22        }
23        Err(e) => return Ok(verr!(vs!(format!("{}", e)))),
24    };
25
26    let status = match &args[1] {
27        Value::Integer(n) if (100..=599).contains(n) => *n as u16,
28        other => {
29            return Ok(verr!(vs!(format!(
30                "http_respond: expects a valid HTTP status int, got {}",
31                other.type_name()
32            ))));
33        }
34    };
35
36    let body = match extract_string(args[1].clone(), "http_respond") {
37        Ok(s) => s,
38        Err(e) => return Ok(verr!(vs!(format!("{e}")))),
39    };
40    let content_type = match args.get(3) {
41        Some(Value::String(s)) => Some(s.clone()),
42        Some(other) => {
43            return Ok(verr!(vs!(format!(
44                "http_respond: expects a string content_type, got {}",
45                other.type_name()
46            ))));
47        }
48        None => None,
49    };
50
51    let request = match eval.http_handles.remove(&id) {
52        Some(HttpHandle::Request(request)) => request,
53        Some(other) => {
54            eval.http_handles.insert(id, other);
55            return Ok(verr!(vs!(format!(
56                "http_respond: handle {} is not a request",
57                id
58            ))));
59        }
60        None => return Ok(verr!(vs!(format!("http_respond: unknown handle {}", id)))),
61    };
62
63    let mut response = tiny_http::Response::from_string(body).with_status_code(status);
64    if let Some(ct) = content_type
65        && let Ok(header) = tiny_http::Header::from_bytes(&b"Content-Type"[..], ct.as_bytes())
66    {
67        response = response.with_header(header);
68    }
69
70    match request.respond(response) {
71        Ok(()) => Ok(vok!(Value::Null)),
72        Err(e) => Ok(verr!(vs!(format!("http_respond: {}", e)))),
73    }
74}