char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somexperiment: use native typescript lsp supportc7a9569

main
4.2 KiB138 linesraw
1use crate::Result;
2use serde_json::Value;
3use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWrite, AsyncWriteExt};
4
5#[derive(Debug, serde::Deserialize, thiserror::Error)]
6#[error("{message}")]
7pub(crate) struct RpcError {
8    pub code: i64,
9    pub message: String,
10    #[serde(default)]
11    pub data: Option<Value>,
12}
13impl RpcError {
14    pub fn invalid(message: impl Into<String>) -> Self {
15        Self {
16            code: -32602,
17            message: message.into(),
18            data: None,
19        }
20    }
21    pub fn failed(message: impl Into<String>) -> Self {
22        Self {
23            code: -32803,
24            message: message.into(),
25            data: None,
26        }
27    }
28    pub fn modified() -> Self {
29        Self {
30            code: -32801,
31            message: "Language-service item is stale; request it again".into(),
32            data: None,
33        }
34    }
35}
36
37const MAX_HEADER: usize = 8192;
38const MAX_BODY: usize = 64 * 1024 * 1024;
39
40pub async fn read(reader: &mut (impl AsyncBufRead + Unpin)) -> Result<Option<Value>> {
41    let mut header = Vec::new();
42    loop {
43        let available = reader.fill_buf().await?;
44        if available.is_empty() {
45            return if header.is_empty() {
46                Ok(None)
47            } else {
48                Err("Truncated RPC header".into())
49            };
50        }
51        let count = available
52            .iter()
53            .position(|b| *b == b'\n')
54            .map_or(available.len(), |i| i + 1);
55        if header.len() + count > MAX_HEADER {
56            return Err("RPC header exceeds limit".into());
57        }
58        header.extend_from_slice(&available[..count]);
59        reader.consume(count);
60        if header.ends_with(b"\r\n\r\n") {
61            break;
62        }
63    }
64    let mut length = None;
65    for line in std::str::from_utf8(&header)?
66        .split("\r\n")
67        .filter(|s| !s.is_empty())
68    {
69        let (name, value) = line.split_once(':').ok_or("Invalid RPC header")?;
70        if name.eq_ignore_ascii_case("content-length") {
71            if length.is_some() {
72                return Err("Duplicate Content-Length".into());
73            }
74            length = Some(value.trim().parse::<usize>()?);
75        }
76    }
77    let length = length.ok_or("Missing Content-Length")?;
78    if length > MAX_BODY {
79        return Err("RPC body exceeds limit".into());
80    }
81    let mut body = vec![0; length];
82    reader.read_exact(&mut body).await?;
83    let message: Value = serde_json::from_slice(&body)?;
84    if !message.is_object() || message["jsonrpc"] != "2.0" {
85        return Err("Invalid JSON-RPC message".into());
86    }
87    Ok(Some(message))
88}
89
90pub async fn write(writer: &mut (impl AsyncWrite + Unpin), mut message: Value) -> Result<()> {
91    message["jsonrpc"] = Value::String("2.0".into());
92    let body = serde_json::to_vec(&message)?;
93    if body.len() > MAX_BODY {
94        return Err("RPC body exceeds limit".into());
95    }
96    writer
97        .write_all(format!("Content-Length: {}\r\n\r\n", body.len()).as_bytes())
98        .await?;
99    writer.write_all(&body).await?;
100    writer.flush().await?;
101    Ok(())
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use serde_json::json;
108    use tokio::io::BufReader;
109    #[tokio::test]
110    async fn utf8_and_multiple_frames() {
111        let mut bytes = Vec::new();
112        write(&mut bytes, json!({"id":1,"result":"😀"}))
113            .await
114            .unwrap();
115        write(&mut bytes, json!({"id":2,"result":"next"}))
116            .await
117            .unwrap();
118        let mut input = BufReader::with_capacity(1, bytes.as_slice());
119        assert_eq!(read(&mut input).await.unwrap().unwrap()["result"], "😀");
120        assert_eq!(read(&mut input).await.unwrap().unwrap()["result"], "next");
121        assert!(read(&mut input).await.unwrap().is_none());
122    }
123    #[tokio::test]
124    async fn malformed_and_bounded() {
125        for bytes in [
126            b"Content-Length: 9\r\n\r\n{}".as_slice(),
127            b"Content-Length: 1\r\nContent-Length: 1\r\n\r\n0",
128            b"Content-Length: 999999999\r\n\r\n",
129        ] {
130            assert!(read(&mut BufReader::new(bytes)).await.is_err());
131        }
132        assert!(
133            read(&mut BufReader::new(vec![b'x'; MAX_HEADER + 1].as_slice()))
134                .await
135                .is_err()
136        );
137    }
138}