1use serde::de::{self, MapAccess, SeqAccess, Visitor};
7use serde::{Deserialize, Deserializer, Serialize};
8use serde_json::{Map, Value};
9use std::collections::HashSet;
10use std::fmt;
11use thiserror::Error;
12
13use crate::security::{sanitize_json_value, sanitize_text};
14
15pub const JSONRPC_VERSION: &str = "2.0";
17
18pub const DEFAULT_MAX_JSONRPC_REQUEST_SIZE: usize = 10 * 1024 * 1024;
20
21pub const MAX_JSONRPC_ID_STRING_BYTES: usize = 256;
23
24#[derive(Debug, Clone, Error, PartialEq, Eq)]
26pub enum JsonRpcParseError {
27 #[error("invalid JSON: {0}")]
28 InvalidJson(String),
29 #[error("missing jsonrpc field")]
30 MissingVersion,
31 #[error("invalid jsonrpc version: expected 2.0")]
32 InvalidVersion,
33 #[error("missing method field")]
34 MissingMethod,
35 #[error("missing id field")]
36 MissingId,
37 #[error("invalid request structure")]
38 InvalidStructure,
39 #[error("request too large")]
40 RequestTooLarge,
41 #[error("request id too large")]
42 RequestIdTooLarge,
43 #[error("request id contains sensitive data")]
44 RequestIdSensitive,
45 #[error("duplicate JSON object field")]
46 DuplicateField,
47 #[error("JSON-RPC batch requests are unsupported")]
48 BatchUnsupported,
49}
50
51const DUPLICATE_FIELD_MESSAGE: &str = "duplicate JSON object field";
52const REQUEST_ENVELOPE_FIELDS: &[&str] = &["jsonrpc", "method", "params", "id"];
53const RESPONSE_ENVELOPE_FIELDS: &[&str] = &["jsonrpc", "result", "error", "id"];
54
55struct DuplicateKeyDetector;
56
57impl<'de> Deserialize<'de> for DuplicateKeyDetector {
58 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
59 where
60 D: Deserializer<'de>,
61 {
62 deserializer.deserialize_any(DuplicateKeyVisitor)
63 }
64}
65
66struct DuplicateKeyVisitor;
67
68impl<'de> Visitor<'de> for DuplicateKeyVisitor {
69 type Value = DuplicateKeyDetector;
70
71 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
72 formatter.write_str("any JSON value without duplicate object fields")
73 }
74
75 fn visit_bool<E>(self, _value: bool) -> Result<Self::Value, E> {
76 Ok(DuplicateKeyDetector)
77 }
78
79 fn visit_i64<E>(self, _value: i64) -> Result<Self::Value, E> {
80 Ok(DuplicateKeyDetector)
81 }
82
83 fn visit_u64<E>(self, _value: u64) -> Result<Self::Value, E> {
84 Ok(DuplicateKeyDetector)
85 }
86
87 fn visit_f64<E>(self, _value: f64) -> Result<Self::Value, E> {
88 Ok(DuplicateKeyDetector)
89 }
90
91 fn visit_str<E>(self, _value: &str) -> Result<Self::Value, E>
92 where
93 E: de::Error,
94 {
95 Ok(DuplicateKeyDetector)
96 }
97
98 fn visit_string<E>(self, _value: String) -> Result<Self::Value, E> {
99 Ok(DuplicateKeyDetector)
100 }
101
102 fn visit_none<E>(self) -> Result<Self::Value, E> {
103 Ok(DuplicateKeyDetector)
104 }
105
106 fn visit_unit<E>(self) -> Result<Self::Value, E> {
107 Ok(DuplicateKeyDetector)
108 }
109
110 fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
111 where
112 D: Deserializer<'de>,
113 {
114 DuplicateKeyDetector::deserialize(deserializer)
115 }
116
117 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
118 where
119 A: SeqAccess<'de>,
120 {
121 while seq.next_element::<DuplicateKeyDetector>()?.is_some() {}
122 Ok(DuplicateKeyDetector)
123 }
124
125 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
126 where
127 A: MapAccess<'de>,
128 {
129 let mut seen = HashSet::new();
130 while let Some(key) = map.next_key::<String>()? {
131 if !seen.insert(key) {
132 return Err(de::Error::custom(DUPLICATE_FIELD_MESSAGE));
133 }
134 map.next_value::<DuplicateKeyDetector>()?;
135 }
136 Ok(DuplicateKeyDetector)
137 }
138}
139
140fn map_json_error(error: serde_json::Error) -> JsonRpcParseError {
141 if error.to_string().contains(DUPLICATE_FIELD_MESSAGE) {
142 JsonRpcParseError::DuplicateField
143 } else {
144 JsonRpcParseError::InvalidJson(error.to_string())
145 }
146}
147
148fn ensure_no_duplicate_object_fields(json: &str) -> Result<(), JsonRpcParseError> {
149 let mut deserializer = serde_json::Deserializer::from_str(json);
150 DuplicateKeyDetector::deserialize(&mut deserializer).map_err(map_json_error)?;
151 deserializer.end().map_err(map_json_error)
152}
153
154fn ensure_only_known_fields(
155 obj: &Map<String, Value>,
156 allowed: &[&str],
157) -> Result<(), JsonRpcParseError> {
158 if obj.keys().any(|key| !allowed.contains(&key.as_str())) {
159 return Err(JsonRpcParseError::InvalidStructure);
160 }
161
162 Ok(())
163}
164
165fn validate_request_id(id: &RequestId) -> Result<(), JsonRpcParseError> {
166 if let RequestId::String(id) = id {
167 if id.len() > MAX_JSONRPC_ID_STRING_BYTES {
168 return Err(JsonRpcParseError::RequestIdTooLarge);
169 }
170 if sanitize_text(id) != *id {
171 return Err(JsonRpcParseError::RequestIdSensitive);
172 }
173 }
174
175 Ok(())
176}
177
178fn validate_method_name(method: &str) -> Result<(), JsonRpcParseError> {
179 if method.is_empty() || method.starts_with("rpc.") || method.chars().any(char::is_control) {
180 return Err(JsonRpcParseError::InvalidStructure);
181 }
182
183 Ok(())
184}
185
186fn validate_response_shape(response: &JsonRpcResponse) -> Result<(), JsonRpcParseError> {
187 if response.jsonrpc != JSONRPC_VERSION {
188 return Err(JsonRpcParseError::InvalidVersion);
189 }
190
191 if matches!(response.id, RequestId::Missing) {
192 return Err(JsonRpcParseError::MissingId);
193 }
194
195 if response.result.is_some() == response.error.is_some() {
196 return Err(JsonRpcParseError::InvalidStructure);
197 }
198
199 validate_request_id(&response.id)
200}
201
202fn parse_request_id_value(
203 value: Option<&Value>,
204 missing_id: RequestId,
205) -> Result<RequestId, JsonRpcParseError> {
206 let id = match value {
207 Some(Value::String(s)) => RequestId::String(s.clone()),
208 Some(Value::Number(n)) => {
209 if let Some(i) = n.as_i64() {
210 RequestId::Number(i)
211 } else {
212 return Err(JsonRpcParseError::InvalidStructure);
213 }
214 }
215 Some(Value::Null) => RequestId::Null,
216 None => missing_id,
217 _ => return Err(JsonRpcParseError::InvalidStructure),
218 };
219
220 validate_request_id(&id)?;
221 Ok(id)
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
226#[serde(untagged)]
227pub enum RequestId {
228 String(String),
229 Number(i64),
230 Null,
231 #[default]
232 Missing,
233}
234
235impl RequestId {
236 pub fn try_from_json_value(value: &Value) -> Result<Self, JsonRpcParseError> {
238 parse_request_id_value(Some(value), RequestId::Missing)
239 }
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
244pub struct JsonRpcRequest {
245 pub jsonrpc: String,
247 pub method: String,
249 #[serde(default, skip_serializing_if = "Option::is_none")]
251 pub params: Option<Value>,
252 #[serde(default, skip_serializing_if = "is_missing_id")]
254 pub id: RequestId,
255}
256
257fn is_missing_id(id: &RequestId) -> bool {
258 matches!(id, RequestId::Missing)
259}
260
261impl JsonRpcRequest {
262 pub fn new(method: impl Into<String>, params: Option<Value>, id: RequestId) -> Self {
264 Self {
265 jsonrpc: JSONRPC_VERSION.to_string(),
266 method: method.into(),
267 params,
268 id,
269 }
270 }
271
272 pub fn notification(method: impl Into<String>, params: Option<Value>) -> Self {
274 Self {
275 jsonrpc: JSONRPC_VERSION.to_string(),
276 method: method.into(),
277 params,
278 id: RequestId::Missing,
279 }
280 }
281
282 pub fn is_notification(&self) -> bool {
284 matches!(self.id, RequestId::Missing)
285 }
286
287 pub fn params_as<T: for<'de> Deserialize<'de>>(&self) -> Option<T> {
289 self.params
290 .as_ref()
291 .and_then(|p| serde_json::from_value(p.clone()).ok())
292 }
293}
294
295#[derive(Debug, Clone, Serialize, Deserialize)]
297pub struct JsonRpcResponse {
298 pub jsonrpc: String,
300 #[serde(skip_serializing_if = "Option::is_none")]
302 pub result: Option<Value>,
303 #[serde(skip_serializing_if = "Option::is_none")]
305 pub error: Option<JsonRpcError>,
306 pub id: RequestId,
308}
309
310impl JsonRpcResponse {
311 pub fn success(id: RequestId, result: Value) -> Self {
313 Self {
314 jsonrpc: JSONRPC_VERSION.to_string(),
315 result: Some(result),
316 error: None,
317 id,
318 }
319 }
320
321 pub fn error(id: RequestId, error: JsonRpcError) -> Self {
323 Self {
324 jsonrpc: JSONRPC_VERSION.to_string(),
325 result: None,
326 error: Some(error),
327 id,
328 }
329 }
330
331 pub fn is_success(&self) -> bool {
333 self.result.is_some() && self.error.is_none()
334 }
335
336 pub fn is_error(&self) -> bool {
338 self.error.is_some()
339 }
340}
341
342#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
344pub struct JsonRpcError {
345 pub code: i32,
347 pub message: String,
349 #[serde(skip_serializing_if = "Option::is_none")]
351 pub data: Option<Value>,
352}
353
354impl JsonRpcError {
355 pub fn new(code: i32, message: impl Into<String>) -> Self {
357 Self {
358 code,
359 message: sanitize_text(&message.into()),
360 data: None,
361 }
362 }
363
364 pub fn with_data(code: i32, message: impl Into<String>, data: Value) -> Self {
366 Self {
367 code,
368 message: sanitize_text(&message.into()),
369 data: Some(sanitize_json_value(&data)),
370 }
371 }
372
373 pub fn parse_error() -> Self {
377 Self::new(-32700, "Parse error")
378 }
379
380 pub fn invalid_request() -> Self {
382 Self::new(-32600, "Invalid Request")
383 }
384
385 pub fn method_not_found() -> Self {
387 Self::new(-32601, "Method not found")
388 }
389
390 pub fn invalid_params() -> Self {
392 Self::new(-32602, "Invalid params")
393 }
394
395 pub fn internal_error() -> Self {
397 Self::new(-32603, "Internal error")
398 }
399}
400
401pub struct JsonRpcParser;
403
404impl JsonRpcParser {
405 pub fn parse_request(json: &str) -> Result<JsonRpcRequest, JsonRpcParseError> {
407 Self::parse_request_with_limit(json, DEFAULT_MAX_JSONRPC_REQUEST_SIZE)
408 }
409
410 pub fn parse_request_with_limit(
412 json: &str,
413 max_size: usize,
414 ) -> Result<JsonRpcRequest, JsonRpcParseError> {
415 if json.len() > max_size {
416 return Err(JsonRpcParseError::RequestTooLarge);
417 }
418
419 ensure_no_duplicate_object_fields(json)?;
420
421 let value: Value = serde_json::from_str(json).map_err(map_json_error)?;
422
423 Self::parse_request_value(&value)
424 }
425
426 pub fn parse_request_value(value: &Value) -> Result<JsonRpcRequest, JsonRpcParseError> {
428 if value.is_array() {
429 return Err(JsonRpcParseError::BatchUnsupported);
430 }
431
432 let obj = value
433 .as_object()
434 .ok_or(JsonRpcParseError::InvalidStructure)?;
435 ensure_only_known_fields(obj, REQUEST_ENVELOPE_FIELDS)?;
436
437 let version = obj
439 .get("jsonrpc")
440 .and_then(|v| v.as_str())
441 .ok_or(JsonRpcParseError::MissingVersion)?;
442
443 if version != JSONRPC_VERSION {
444 return Err(JsonRpcParseError::InvalidVersion);
445 }
446
447 let method = obj
449 .get("method")
450 .and_then(|v| v.as_str())
451 .ok_or(JsonRpcParseError::MissingMethod)?
452 .to_string();
453
454 validate_method_name(&method)?;
455
456 if obj.contains_key("result") || obj.contains_key("error") {
457 return Err(JsonRpcParseError::InvalidStructure);
458 }
459
460 let params = obj.get("params").cloned();
462 if let Some(params) = ¶ms {
463 if !(params.is_object() || params.is_array()) {
464 return Err(JsonRpcParseError::InvalidStructure);
465 }
466 }
467
468 let id = parse_request_id_value(obj.get("id"), RequestId::Missing)?;
470
471 Ok(JsonRpcRequest {
472 jsonrpc: JSONRPC_VERSION.to_string(),
473 method,
474 params,
475 id,
476 })
477 }
478
479 pub fn parse_response(json: &str) -> Result<JsonRpcResponse, JsonRpcParseError> {
481 Self::parse_response_with_limit(json, DEFAULT_MAX_JSONRPC_REQUEST_SIZE)
482 }
483
484 pub fn parse_response_with_limit(
486 json: &str,
487 max_size: usize,
488 ) -> Result<JsonRpcResponse, JsonRpcParseError> {
489 if json.len() > max_size {
490 return Err(JsonRpcParseError::RequestTooLarge);
491 }
492
493 ensure_no_duplicate_object_fields(json)?;
494
495 let value: Value = serde_json::from_str(json).map_err(map_json_error)?;
496
497 Self::parse_response_value(&value)
498 }
499
500 pub fn parse_response_value(value: &Value) -> Result<JsonRpcResponse, JsonRpcParseError> {
502 let obj = value
503 .as_object()
504 .ok_or(JsonRpcParseError::InvalidStructure)?;
505 ensure_only_known_fields(obj, RESPONSE_ENVELOPE_FIELDS)?;
506
507 let version = obj
509 .get("jsonrpc")
510 .and_then(|v| v.as_str())
511 .ok_or(JsonRpcParseError::MissingVersion)?;
512
513 if version != JSONRPC_VERSION {
514 return Err(JsonRpcParseError::InvalidVersion);
515 }
516
517 if obj.contains_key("method") || obj.contains_key("params") {
518 return Err(JsonRpcParseError::InvalidStructure);
519 }
520
521 let id = parse_request_id_value(obj.get("id"), RequestId::Missing)?;
523 if matches!(id, RequestId::Missing) {
524 return Err(JsonRpcParseError::MissingId);
525 }
526
527 let result = obj.get("result").cloned();
529 let error = obj
530 .get("error")
531 .map(|e| serde_json::from_value(e.clone()))
532 .transpose()
533 .map_err(|_| JsonRpcParseError::InvalidStructure)?;
534
535 if result.is_some() == error.is_some() {
536 return Err(JsonRpcParseError::InvalidStructure);
537 }
538
539 Ok(JsonRpcResponse {
540 jsonrpc: JSONRPC_VERSION.to_string(),
541 result,
542 error,
543 id,
544 })
545 }
546
547 pub fn format_request(request: &JsonRpcRequest) -> Result<String, JsonRpcParseError> {
549 if request.jsonrpc != JSONRPC_VERSION {
550 return Err(JsonRpcParseError::InvalidVersion);
551 }
552 validate_method_name(&request.method)?;
553 validate_request_id(&request.id)?;
554 serde_json::to_string(request).map_err(|e| JsonRpcParseError::InvalidJson(e.to_string()))
555 }
556
557 pub fn format_response(response: &JsonRpcResponse) -> Result<String, JsonRpcParseError> {
559 validate_response_shape(response)?;
560 let mut response = response.clone();
561 if let Some(error) = &mut response.error {
562 error.message = sanitize_text(&error.message);
563 error.data = error.data.as_ref().map(sanitize_json_value);
564 }
565
566 serde_json::to_string(&response).map_err(|e| JsonRpcParseError::InvalidJson(e.to_string()))
567 }
568}
569
570#[cfg(test)]
571mod tests {
572 use super::*;
573
574 #[test]
575 fn test_parse_request() {
576 let json = r#"{"jsonrpc":"2.0","method":"test","params":{"foo":"bar"},"id":1}"#;
577 let request = JsonRpcParser::parse_request(json).unwrap();
578
579 assert_eq!(request.jsonrpc, "2.0");
580 assert_eq!(request.method, "test");
581 assert_eq!(request.id, RequestId::Number(1));
582 assert!(request.params.is_some());
583 }
584
585 #[test]
586 fn test_parse_notification() {
587 let json = r#"{"jsonrpc":"2.0","method":"notify","params":{}}"#;
588 let request = JsonRpcParser::parse_request(json).unwrap();
589
590 assert_eq!(request.method, "notify");
591 assert!(request.is_notification());
592 }
593
594 #[test]
595 fn test_parse_request_string_id() {
596 let json = r#"{"jsonrpc":"2.0","method":"test","id":"abc-123"}"#;
597 let request = JsonRpcParser::parse_request(json).unwrap();
598
599 assert_eq!(request.id, RequestId::String("abc-123".to_string()));
600 }
601
602 #[test]
603 fn test_parse_invalid_version() {
604 let json = r#"{"jsonrpc":"1.0","method":"test","id":1}"#;
605 let result = JsonRpcParser::parse_request(json);
606
607 assert!(matches!(result, Err(JsonRpcParseError::InvalidVersion)));
608 }
609
610 #[test]
611 fn test_parse_missing_method() {
612 let json = r#"{"jsonrpc":"2.0","id":1}"#;
613 let result = JsonRpcParser::parse_request(json);
614
615 assert!(matches!(result, Err(JsonRpcParseError::MissingMethod)));
616 }
617
618 #[test]
619 fn test_format_request() {
620 let request = JsonRpcRequest::new(
621 "test",
622 Some(serde_json::json!({"a": 1})),
623 RequestId::Number(42),
624 );
625 let json = JsonRpcParser::format_request(&request).unwrap();
626
627 let parsed = JsonRpcParser::parse_request(&json).unwrap();
629 assert_eq!(parsed.method, "test");
630 assert_eq!(parsed.id, RequestId::Number(42));
631 }
632
633 #[test]
634 fn test_success_response() {
635 let response =
636 JsonRpcResponse::success(RequestId::Number(1), serde_json::json!({"result": "ok"}));
637
638 assert!(response.is_success());
639 assert!(!response.is_error());
640
641 let json = JsonRpcParser::format_response(&response).unwrap();
642 let parsed = JsonRpcParser::parse_response(&json).unwrap();
643
644 assert!(parsed.is_success());
645 assert_eq!(parsed.id, RequestId::Number(1));
646 }
647
648 #[test]
649 fn test_error_response() {
650 let response =
651 JsonRpcResponse::error(RequestId::Number(1), JsonRpcError::method_not_found());
652
653 assert!(response.is_error());
654 assert!(!response.is_success());
655
656 let json = JsonRpcParser::format_response(&response).unwrap();
657 let parsed = JsonRpcParser::parse_response(&json).unwrap();
658
659 assert!(parsed.is_error());
660 assert_eq!(parsed.error.unwrap().code, -32601);
661 }
662
663 #[test]
664 fn test_error_codes() {
665 assert_eq!(JsonRpcError::parse_error().code, -32700);
666 assert_eq!(JsonRpcError::invalid_request().code, -32600);
667 assert_eq!(JsonRpcError::method_not_found().code, -32601);
668 assert_eq!(JsonRpcError::invalid_params().code, -32602);
669 assert_eq!(JsonRpcError::internal_error().code, -32603);
670 }
671
672 #[test]
673 fn test_request_round_trip() {
674 let original = JsonRpcRequest::new(
675 "tools/call",
676 Some(serde_json::json!({
677 "name": "read_file",
678 "arguments": {"path": "/tmp/test.txt"}
679 })),
680 RequestId::String("req-001".to_string()),
681 );
682
683 let json = JsonRpcParser::format_request(&original).unwrap();
684 let parsed = JsonRpcParser::parse_request(&json).unwrap();
685
686 assert_eq!(parsed.method, original.method);
687 assert_eq!(parsed.id, original.id);
688 assert_eq!(parsed.params, original.params);
689 }
690
691 #[test]
692 fn test_response_round_trip() {
693 let original = JsonRpcResponse::success(
694 RequestId::Number(123),
695 serde_json::json!({
696 "content": [{"type": "text", "text": "Hello"}]
697 }),
698 );
699
700 let json = JsonRpcParser::format_response(&original).unwrap();
701 let parsed = JsonRpcParser::parse_response(&json).unwrap();
702
703 assert_eq!(parsed.id, original.id);
704 assert_eq!(parsed.result, original.result);
705 }
706}