1use bytes::{Buf, BufMut, BytesMut};
5use memchr::memmem;
6use serde::de::DeserializeOwned;
7use serde::Serialize;
8use std::fmt::{self, Display, Formatter};
9use std::num::ParseIntError;
10use std::str::Utf8Error;
11
12pub const MAX_CONTENT_LENGTH: usize = 50 * 1024 * 1024;
14
15pub const MAX_HEADERS_SIZE: usize = 8192;
17
18#[derive(Debug)]
20pub enum ParseError {
21 Body(serde_json::Error),
23 Encode(std::io::Error),
25 Headers(httparse::Error),
27 InvalidContentType,
29 InvalidContentLength(String),
31 MissingContentLength,
33 Utf8(Utf8Error),
35 ContentLengthTooLarge(usize),
37 HeadersTooLarge,
39 EmptyMessage,
41 EnvelopeViolation(String),
43}
44
45impl Display for ParseError {
46 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
47 match self {
48 ParseError::Body(e) => write!(f, "unable to parse JSON body: {e}"),
49 ParseError::Encode(e) => write!(f, "failed to encode response: {e}"),
50 ParseError::Headers(e) => write!(f, "failed to parse headers: {e}"),
51 ParseError::InvalidContentType => write!(f, "unable to parse content type"),
52 ParseError::InvalidContentLength(e) => {
53 write!(f, "unable to parse content length: {e}")
54 }
55 ParseError::MissingContentLength => {
56 write!(f, "missing required `Content-Length` header")
57 }
58 ParseError::Utf8(e) => write!(f, "request contains invalid UTF8: {e}"),
59 ParseError::ContentLengthTooLarge(len) => {
60 write!(
61 f,
62 "content length {len} exceeds maximum allowed size ({MAX_CONTENT_LENGTH} bytes)"
63 )
64 }
65 ParseError::HeadersTooLarge => {
66 write!(
67 f,
68 "headers size exceeds maximum allowed size ({MAX_HEADERS_SIZE} bytes)"
69 )
70 }
71 ParseError::EmptyMessage => write!(f, "empty / zero-length message received"),
72 ParseError::EnvelopeViolation(e) => {
73 write!(f, "JSON-RPC envelope violation: {e}")
74 }
75 }
76 }
77}
78
79impl std::error::Error for ParseError {
80 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
81 match self {
82 ParseError::Body(e) => Some(e),
83 ParseError::Encode(e) => Some(e),
84 ParseError::Utf8(e) => Some(e),
85 _ => None,
86 }
87 }
88}
89
90impl From<serde_json::Error> for ParseError {
91 fn from(error: serde_json::Error) -> Self {
92 ParseError::Body(error)
93 }
94}
95
96impl From<std::io::Error> for ParseError {
97 fn from(error: std::io::Error) -> Self {
98 ParseError::Encode(error)
99 }
100}
101
102impl From<httparse::Error> for ParseError {
103 fn from(error: httparse::Error) -> Self {
104 ParseError::Headers(error)
105 }
106}
107
108impl From<Utf8Error> for ParseError {
109 fn from(error: Utf8Error) -> Self {
110 ParseError::Utf8(error)
111 }
112}
113
114pub fn decode_message<T: DeserializeOwned>(
119 src: &mut BytesMut,
120 state_content_len: &mut Option<usize>,
121) -> Result<Option<T>, ParseError> {
122 if let Some(content_len) = *state_content_len {
123 if src.len() < content_len {
124 return Ok(None);
125 }
126
127 let bytes = &src[..content_len];
128 let message = std::str::from_utf8(bytes)?;
129
130 let result = if message.is_empty() {
131 Err(ParseError::EmptyMessage)
132 } else {
133 match serde_json::from_str::<serde_json::Value>(message) {
135 Ok(val) => match validate_envelope(&val) {
136 Ok(()) => match serde_json::from_value::<T>(val) {
137 Ok(parsed) => Ok(Some(parsed)),
138 Err(err) => Err(err.into()),
139 },
140 Err(err_msg) => Err(ParseError::EnvelopeViolation(err_msg.to_string())),
141 },
142 Err(err) => Err(err.into()),
143 }
144 };
145
146 src.advance(content_len);
147 *state_content_len = None; result
150 } else {
151 if let Some(pos) = memmem::find(src, b"\r\n\r\n") {
153 let headers_len = pos + 4;
154
155 if headers_len > MAX_HEADERS_SIZE {
157 src.clear();
158 return Err(ParseError::HeadersTooLarge);
159 }
160
161 let mut dst = [httparse::EMPTY_HEADER; 16];
162 let parsed = httparse::parse_headers(&src[..headers_len], &mut dst);
163
164 match parsed {
165 Ok(httparse::Status::Complete((len, headers))) => {
166 debug_assert_eq!(len, headers_len);
167
168 match decode_headers(headers) {
169 Ok(content_len) => {
170 src.advance(headers_len);
171 *state_content_len = Some(content_len);
172 decode_message(src, state_content_len)
173 }
174 Err(err) => {
175 if !src.is_empty() {
176 src.advance(1);
177 }
178 recover_garbage(src);
179 Err(err)
180 }
181 }
182 }
183 Ok(httparse::Status::Partial) => {
184 if src.len() > MAX_HEADERS_SIZE {
185 src.clear();
186 return Err(ParseError::HeadersTooLarge);
187 }
188 Ok(None)
189 }
190 Err(err) => {
191 if !src.is_empty() {
192 src.advance(1);
193 }
194 recover_garbage(src);
195 Err(err.into())
196 }
197 }
198 } else {
199 if src.len() > MAX_HEADERS_SIZE {
200 src.clear();
201 return Err(ParseError::HeadersTooLarge);
202 }
203 Ok(None)
204 }
205 }
206}
207
208pub fn encode_message<T: Serialize>(item: T, dst: &mut BytesMut) -> Result<(), ParseError> {
210 let msg = serde_json::to_string(&item)?;
211 let digits = number_of_digits(msg.len());
212 dst.reserve(msg.len() + digits + 20);
213
214 let mut writer = dst.writer();
215 std::io::Write::write_fmt(
216 &mut writer,
217 format_args!("Content-Length: {}\r\n\r\n{}", msg.len(), msg),
218 )?;
219 std::io::Write::flush(&mut writer)?;
220
221 Ok(())
222}
223
224fn number_of_digits(mut n: usize) -> usize {
225 if n == 0 {
226 return 1;
227 }
228 let mut num_digits = 0;
229 while n > 0 {
230 n /= 10;
231 num_digits += 1;
232 }
233 num_digits
234}
235
236fn decode_headers(headers: &[httparse::Header<'_>]) -> Result<usize, ParseError> {
238 let mut content_len = None;
239
240 for header in headers {
241 if header.name.is_empty() {
242 continue;
243 }
244
245 if header.name.eq_ignore_ascii_case("Content-Length") {
246 let string = std::str::from_utf8(header.value)?;
247 let parsed_len: usize = string
248 .trim()
249 .parse()
250 .map_err(|e: ParseIntError| ParseError::InvalidContentLength(e.to_string()))?;
251
252 if parsed_len > MAX_CONTENT_LENGTH {
253 return Err(ParseError::ContentLengthTooLarge(parsed_len));
254 }
255 content_len = Some(parsed_len);
256 } else if header.name.eq_ignore_ascii_case("Content-Type") {
257 let string = std::str::from_utf8(header.value)?;
258 let mut parts = string.split(';');
259 let _media_type = parts.next().unwrap_or("").trim();
260
261 let mut charset_ok = true;
265 for part in parts {
266 let part = part.trim();
267 if part.to_ascii_lowercase().starts_with("charset=") {
268 let charset_val = &part["charset=".len()..];
269 if !charset_val.eq_ignore_ascii_case("utf-8")
270 && !charset_val.eq_ignore_ascii_case("utf8")
271 {
272 charset_ok = false;
273 }
274 }
275 }
276 if !charset_ok {
277 return Err(ParseError::InvalidContentType);
278 }
279 }
280 }
281
282 if let Some(content_len) = content_len {
283 Ok(content_len)
284 } else {
285 Err(ParseError::MissingContentLength)
286 }
287}
288
289fn recover_garbage(src: &mut BytesMut) {
292 if let Some(pos) = find_case_insensitive(src, b"content-length") {
293 src.advance(pos);
294 } else {
295 let name_len = b"content-length".len();
296 if src.len() > name_len {
297 src.advance(src.len() - name_len);
298 }
299 }
300}
301
302fn find_case_insensitive(src: &[u8], target: &[u8]) -> Option<usize> {
303 if src.len() < target.len() {
304 return None;
305 }
306 for i in 0..=(src.len() - target.len()) {
307 let mut matches = true;
308 for (j, &byte) in target.iter().enumerate() {
309 if src[i + j].to_ascii_lowercase() != byte {
310 matches = false;
311 break;
312 }
313 }
314 if matches {
315 return Some(i);
316 }
317 }
318 None
319}
320
321pub fn validate_envelope(value: &serde_json::Value) -> Result<(), &'static str> {
323 let obj = match value.as_object() {
324 Some(o) => o,
325 None => return Err("JSON-RPC message must be a JSON object"),
326 };
327
328 match obj.get("jsonrpc") {
329 Some(v) => {
330 if v.as_str() != Some("2.0") {
331 return Err("jsonrpc version must be \"2.0\"");
332 }
333 }
334 None => return Err("missing jsonrpc version field"),
335 }
336
337 let has_method = obj.contains_key("method");
338 let has_result = obj.contains_key("result");
339 let has_error = obj.contains_key("error");
340
341 if has_method {
342 let method_val = obj.get("method").unwrap();
343 if !method_val.is_string() {
344 return Err("method must be a string");
345 }
346 if let Some(_id_val) = obj
347 .get("id")
348 .filter(|v| !v.is_number() && !v.is_string() && !v.is_null())
349 {
350 return Err("id must be a number, string, or null");
351 }
352 } else if has_result || has_error {
353 if has_result && has_error {
354 return Err("response cannot contain both result and error fields");
355 }
356 match obj.get("id") {
357 Some(id_val) => {
358 if !id_val.is_number() && !id_val.is_string() && !id_val.is_null() {
359 return Err("id must be a number, string, or null");
360 }
361 }
362 None => return Err("response must have an id field"),
363 }
364 if has_error {
365 let error_val = obj.get("error").unwrap();
366 let error_obj = match error_val.as_object() {
367 Some(eo) => eo,
368 None => return Err("error field must be an object"),
369 };
370 match error_obj.get("code") {
371 Some(code_val) => {
372 if !code_val.is_i64() {
373 return Err("error code must be an integer");
374 }
375 }
376 None => return Err("error object must contain a code field"),
377 }
378 match error_obj.get("message") {
379 Some(msg_val) => {
380 if !msg_val.is_string() {
381 return Err("error message must be a string");
382 }
383 }
384 None => return Err("error object must contain a message field"),
385 }
386 }
387 } else {
388 return Err(
389 "message must be either a request (with method) or a response (with result or error)",
390 );
391 }
392
393 Ok(())
394}
395
396#[cfg(test)]
397mod tests {
398 use super::*;
399
400 fn make_message(headers: &[(&str, &str)], body: &str) -> BytesMut {
401 let mut msg = String::new();
402 for (name, val) in headers {
403 msg.push_str(&format!("{}: {}\r\n", name, val));
404 }
405 msg.push_str("\r\n");
406 msg.push_str(body);
407 BytesMut::from(msg.as_str())
408 }
409
410 #[test]
411 fn test_case_insensitive_headers() {
412 let mut buf = make_message(
413 &[
414 ("content-length", "39"),
415 ("content-type", "application/vscode-jsonrpc; charset=utf8"),
416 ],
417 r#"{"jsonrpc":"2.0","method":"foo","id":1}"#,
418 );
419 let mut state = None;
420 let decoded: Result<Option<serde_json::Value>, _> = decode_message(&mut buf, &mut state);
421 assert!(decoded.is_ok());
422 let val = decoded.unwrap().unwrap();
423 assert_eq!(val["method"], "foo");
424 }
425
426 #[test]
427 fn test_optional_charset() {
428 let mut buf = make_message(
429 &[
430 ("Content-Length", "39"),
431 ("Content-Type", "application/vscode-jsonrpc"),
432 ],
433 r#"{"jsonrpc":"2.0","method":"foo","id":1}"#,
434 );
435 let mut state = None;
436 let decoded: Result<Option<serde_json::Value>, _> = decode_message(&mut buf, &mut state);
437 assert!(decoded.is_ok());
438 let val = decoded.unwrap().unwrap();
439 assert_eq!(val["method"], "foo");
440 }
441
442 #[test]
443 fn test_huge_content_length_rejected() {
444 let mut buf = make_message(
445 &[
446 ("Content-Length", "100000000"), ("Content-Type", "application/vscode-jsonrpc"),
448 ],
449 "",
450 );
451 let mut state = None;
452 let decoded: Result<Option<serde_json::Value>, _> = decode_message(&mut buf, &mut state);
453 assert!(decoded.is_err());
454 assert!(matches!(
455 decoded.err().unwrap(),
456 ParseError::ContentLengthTooLarge(_)
457 ));
458 }
459
460 #[test]
461 fn test_headers_too_large_rejected() {
462 let mut buf = BytesMut::from(vec![b'a'; 9000].as_slice());
463 let mut state = None;
464 let decoded: Result<Option<serde_json::Value>, _> = decode_message(&mut buf, &mut state);
465 assert!(decoded.is_err());
466 assert!(matches!(
467 decoded.err().unwrap(),
468 ParseError::HeadersTooLarge
469 ));
470 }
471
472 #[test]
473 fn test_zero_length_message_rejected() {
474 let mut buf = make_message(
475 &[
476 ("Content-Length", "0"),
477 ("Content-Type", "application/vscode-jsonrpc"),
478 ],
479 "",
480 );
481 let mut state = None;
482 let decoded: Result<Option<serde_json::Value>, _> = decode_message(&mut buf, &mut state);
483 assert!(decoded.is_err());
484 assert!(matches!(decoded.err().unwrap(), ParseError::EmptyMessage));
485 }
486
487 #[test]
488 fn test_jsonrpc_envelope_validation() {
489 let val1 = serde_json::json!({
491 "method": "foo",
492 "id": 1
493 });
494 assert!(validate_envelope(&val1).is_err());
495
496 let val2 = serde_json::json!({
498 "jsonrpc": "1.0",
499 "method": "foo",
500 "id": 1
501 });
502 assert!(validate_envelope(&val2).is_err());
503
504 let val3 = serde_json::json!({
506 "jsonrpc": "2.0",
507 "method": 123,
508 "id": 1
509 });
510 assert!(validate_envelope(&val3).is_err());
511
512 let val4 = serde_json::json!({
514 "jsonrpc": "2.0",
515 "method": "foo",
516 "id": {}
517 });
518 assert!(validate_envelope(&val4).is_err());
519
520 let val5 = serde_json::json!({
522 "jsonrpc": "2.0",
523 "method": "foo"
524 });
525 assert!(validate_envelope(&val5).is_ok());
526
527 let val6 = serde_json::json!({
529 "jsonrpc": "2.0",
530 "result": "ok",
531 "id": 1
532 });
533 assert!(validate_envelope(&val6).is_ok());
534 }
535
536 #[test]
537 fn test_garbage_recovery() {
538 let mut buf = BytesMut::from(
539 "some garbage content-length: 39\r\n\r\n{\"jsonrpc\":\"2.0\",\"method\":\"foo\",\"id\":1}",
540 );
541 let mut state = None;
542 let decoded: Result<Option<serde_json::Value>, _> = decode_message(&mut buf, &mut state);
545 assert!(decoded.is_err());
546
547 let decoded2: Result<Option<serde_json::Value>, _> = decode_message(&mut buf, &mut state);
549 assert!(decoded2.is_ok());
550 assert_eq!(decoded2.unwrap().unwrap()["method"], "foo");
551 }
552}