1use crate::MAX_REQUEST_ID;
2use crate::error::{Error, ErrorKind, Result, RpcError};
3use serde::de::{DeserializeSeed, Error as _, MapAccess, SeqAccess, Visitor};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::Value;
6use std::collections::HashSet;
7use std::fmt;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
11pub struct RequestId(u64);
12
13impl RequestId {
14 pub fn new(value: u64) -> Result<Self> {
15 if value == 0 || value > MAX_REQUEST_ID {
16 return Err(Error::Protocol("request ID is outside the version 1 range"));
17 }
18 Ok(Self(value))
19 }
20
21 pub const fn get(self) -> u64 {
22 self.0
23 }
24}
25
26impl Serialize for RequestId {
27 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
28 where
29 S: Serializer,
30 {
31 serializer.serialize_u64(self.0)
32 }
33}
34
35impl<'de> Deserialize<'de> for RequestId {
36 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
37 where
38 D: Deserializer<'de>,
39 {
40 let value = u64::deserialize(deserializer)?;
41 if value == 0 || value > MAX_REQUEST_ID {
42 return Err(D::Error::custom("invalid version 1 request ID"));
43 }
44 Ok(Self(value))
45 }
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
51pub struct Version;
52
53impl Serialize for Version {
54 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
55 where
56 S: Serializer,
57 {
58 serializer.serialize_str("2.0")
59 }
60}
61
62impl<'de> Deserialize<'de> for Version {
63 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
64 where
65 D: Deserializer<'de>,
66 {
67 let value = String::deserialize(deserializer)?;
68 if value == "2.0" {
69 Ok(Self)
70 } else {
71 Err(D::Error::custom("jsonrpc must be \"2.0\""))
72 }
73 }
74}
75
76#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
77#[serde(deny_unknown_fields)]
78pub struct Meta {
79 pub deadline_unix_ms: u64,
82 #[serde(skip_serializing_if = "Option::is_none")]
85 pub parent_request_id: Option<RequestId>,
86}
87
88impl std::fmt::Debug for Request {
91 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 formatter
93 .debug_struct("Request")
94 .field("id", &self.id)
95 .field("method", &self.method)
96 .field("meta", &self.meta)
97 .field("params", &crate::protocol::Redacted)
98 .finish()
99 }
100}
101
102impl std::fmt::Debug for Notification {
103 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 formatter
105 .debug_struct("Notification")
106 .field("method", &self.method)
107 .field("params", &crate::protocol::Redacted)
108 .finish()
109 }
110}
111
112impl std::fmt::Debug for SuccessResponse {
113 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 formatter
115 .debug_struct("SuccessResponse")
116 .field("id", &self.id)
117 .field("result", &crate::protocol::Redacted)
118 .finish()
119 }
120}
121
122#[derive(Clone, PartialEq, Serialize, Deserialize)]
123#[serde(deny_unknown_fields)]
124pub struct Request {
125 pub jsonrpc: Version,
126 pub id: RequestId,
127 pub method: String,
128 #[serde(rename = "_meta")]
129 pub meta: Meta,
130 pub params: Value,
131}
132
133impl Request {
134 pub fn new(
135 id: RequestId,
136 method: impl Into<String>,
137 deadline_unix_ms: u64,
138 params: Value,
139 ) -> Result<Self> {
140 let method = method.into();
141 validate_method_and_params(&method, ¶ms)?;
142 Ok(Self {
143 jsonrpc: Version,
144 id,
145 method,
146 meta: Meta {
147 deadline_unix_ms,
148 parent_request_id: None,
149 },
150 params,
151 })
152 }
153
154 pub const fn deadline_unix_ms(&self) -> u64 {
155 self.meta.deadline_unix_ms
156 }
157
158 pub fn with_parent_request_id(mut self, parent_request_id: RequestId) -> Self {
159 self.meta.parent_request_id = Some(parent_request_id);
160 self
161 }
162}
163
164#[derive(Clone, PartialEq, Serialize, Deserialize)]
165#[serde(deny_unknown_fields)]
166pub struct Notification {
167 pub jsonrpc: Version,
168 pub method: String,
169 pub params: Value,
170}
171
172impl Notification {
173 pub fn new(method: impl Into<String>, params: Value) -> Result<Self> {
174 let method = method.into();
175 validate_method_and_params(&method, ¶ms)?;
176 Ok(Self {
177 jsonrpc: Version,
178 method,
179 params,
180 })
181 }
182}
183
184#[derive(Clone, PartialEq, Serialize, Deserialize)]
185#[serde(deny_unknown_fields)]
186pub struct SuccessResponse {
187 pub jsonrpc: Version,
188 pub id: RequestId,
189 pub result: Value,
190}
191
192#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
193#[serde(deny_unknown_fields)]
194pub struct ErrorResponse {
195 pub jsonrpc: Version,
196 #[serde(deserialize_with = "crate::protocol::deserialize_required_nullable")]
197 pub id: Option<RequestId>,
198 pub error: RpcError,
199}
200
201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
202#[serde(untagged)]
203pub enum Response {
204 Success(SuccessResponse),
205 Error(ErrorResponse),
206}
207
208impl Response {
209 pub fn success(id: RequestId, result: Value) -> Self {
210 Self::Success(SuccessResponse {
211 jsonrpc: Version,
212 id,
213 result,
214 })
215 }
216
217 pub fn error(id: Option<RequestId>, error: RpcError) -> Self {
218 Self::Error(ErrorResponse {
219 jsonrpc: Version,
220 id,
221 error,
222 })
223 }
224
225 pub const fn id(&self) -> Option<RequestId> {
226 match self {
227 Self::Success(response) => Some(response.id),
228 Self::Error(response) => response.id,
229 }
230 }
231}
232
233#[derive(Debug, Clone, PartialEq, Serialize)]
234#[serde(untagged)]
235pub enum Envelope {
236 Request(Request),
237 Notification(Notification),
238 Response(Response),
239}
240
241impl Envelope {
242 pub fn parse(bytes: &[u8]) -> Result<Self> {
245 Self::parse_classified(bytes).map_err(|(error, _)| error)
246 }
247
248 pub fn parse_classified(bytes: &[u8]) -> std::result::Result<Self, (Error, ErrorKind)> {
256 let value = parse_strict_value(bytes)?;
257 Self::from_strict_value(value).map_err(|error| (error, ErrorKind::InvalidRequest))
258 }
259
260 fn from_strict_value(value: Value) -> Result<Self> {
261 let object = value
262 .as_object()
263 .ok_or(Error::Protocol("JSON-RPC payload is not an object"))?;
264
265 let envelope = if object.contains_key("method") && object.contains_key("id") {
266 Self::Request(from_value(value)?)
267 } else if object.contains_key("method") {
268 Self::Notification(from_value(value)?)
269 } else if object.contains_key("result") || object.contains_key("error") {
270 let response: Response = from_value(value)?;
271 if let Response::Error(error) = &response {
272 error.error.validate().map_err(Error::Protocol)?;
273 }
274 Self::Response(response)
275 } else {
276 return Err(Error::Protocol("unrecognized JSON-RPC envelope"));
277 };
278
279 match &envelope {
280 Self::Request(request) => {
281 validate_method_and_params(&request.method, &request.params)?;
282 }
283 Self::Notification(notification) => {
284 validate_method_and_params(¬ification.method, ¬ification.params)?;
285 }
286 Self::Response(_) => {}
287 }
288 Ok(envelope)
289 }
290
291 pub fn to_vec(&self) -> Result<Vec<u8>> {
292 serde_json::to_vec(self).map_err(|error| Error::ProtocolOwned(error.to_string()))
293 }
294}
295
296fn validate_method_and_params(method: &str, params: &Value) -> Result<()> {
300 if method.is_empty() || method.len() > 256 {
301 return Err(Error::Protocol("method has an invalid byte length"));
302 }
303 if !params.is_object() {
304 return Err(Error::Protocol("params must be an object"));
305 }
306 Ok(())
307}
308
309fn from_value<T: for<'de> Deserialize<'de>>(value: Value) -> Result<T> {
310 serde_json::from_value(value).map_err(|error| Error::ProtocolOwned(error.to_string()))
311}
312
313fn parse_strict_value(bytes: &[u8]) -> std::result::Result<Value, (Error, ErrorKind)> {
314 let mut deserializer = serde_json::Deserializer::from_slice(bytes);
315 let value = StrictValueSeed { depth: 0 }
316 .deserialize(&mut deserializer)
317 .map_err(classify_json_error)?;
318 deserializer.end().map_err(classify_json_error)?;
319 Ok(value)
320}
321
322fn classify_json_error(error: serde_json::Error) -> (Error, ErrorKind) {
330 let kind = match error.classify() {
331 serde_json::error::Category::Data => ErrorKind::InvalidRequest,
332 _ => ErrorKind::ParseError,
333 };
334 (Error::ProtocolOwned(error.to_string()), kind)
335}
336
337const MAX_NESTING: usize = 64;
338
339struct StrictValueSeed {
340 depth: usize,
341}
342
343impl<'de> DeserializeSeed<'de> for StrictValueSeed {
344 type Value = Value;
345
346 fn deserialize<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
347 where
348 D: Deserializer<'de>,
349 {
350 deserializer.deserialize_any(StrictValueVisitor { depth: self.depth })
351 }
352}
353
354struct StrictValueVisitor {
355 depth: usize,
356}
357
358impl StrictValueVisitor {
359 fn child<E: serde::de::Error>(&self) -> std::result::Result<StrictValueSeed, E> {
360 if self.depth >= MAX_NESTING {
361 Err(E::custom("JSON nesting exceeds 64 containers"))
362 } else {
363 Ok(StrictValueSeed {
364 depth: self.depth + 1,
365 })
366 }
367 }
368}
369
370impl<'de> Visitor<'de> for StrictValueVisitor {
371 type Value = Value;
372
373 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
374 formatter.write_str("an RFC 8259 JSON value without duplicate object keys")
375 }
376
377 fn visit_bool<E>(self, value: bool) -> std::result::Result<Self::Value, E> {
378 Ok(Value::Bool(value))
379 }
380
381 fn visit_i64<E>(self, value: i64) -> std::result::Result<Self::Value, E> {
382 Ok(Value::Number(value.into()))
383 }
384
385 fn visit_u64<E>(self, value: u64) -> std::result::Result<Self::Value, E> {
386 Ok(Value::Number(value.into()))
387 }
388
389 fn visit_f64<E>(self, value: f64) -> std::result::Result<Self::Value, E>
390 where
391 E: serde::de::Error,
392 {
393 serde_json::Number::from_f64(value)
394 .map(Value::Number)
395 .ok_or_else(|| E::custom("non-finite JSON number"))
396 }
397
398 fn visit_str<E>(self, value: &str) -> std::result::Result<Self::Value, E> {
399 Ok(Value::String(value.to_string()))
400 }
401
402 fn visit_string<E>(self, value: String) -> std::result::Result<Self::Value, E> {
403 Ok(Value::String(value))
404 }
405
406 fn visit_none<E>(self) -> std::result::Result<Self::Value, E> {
407 Ok(Value::Null)
408 }
409
410 fn visit_unit<E>(self) -> std::result::Result<Self::Value, E> {
411 Ok(Value::Null)
412 }
413
414 fn visit_some<D>(self, deserializer: D) -> std::result::Result<Self::Value, D::Error>
415 where
416 D: Deserializer<'de>,
417 {
418 StrictValueSeed { depth: self.depth }.deserialize(deserializer)
419 }
420
421 fn visit_seq<A>(self, mut sequence: A) -> std::result::Result<Self::Value, A::Error>
422 where
423 A: SeqAccess<'de>,
424 {
425 let mut values = Vec::new();
426 while let Some(value) = sequence.next_element_seed(self.child()?)? {
427 values.push(value);
428 }
429 Ok(Value::Array(values))
430 }
431
432 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
433 where
434 A: MapAccess<'de>,
435 {
436 let mut values = serde_json::Map::new();
437 let mut keys = HashSet::new();
438 while let Some(key) = map.next_key::<String>()? {
439 if !keys.insert(key.clone()) {
440 return Err(A::Error::custom("duplicate JSON object key"));
441 }
442 let value = map.next_value_seed(self.child()?)?;
443 values.insert(key, value);
444 }
445 Ok(Value::Object(values))
446 }
447}
448
449#[cfg(test)]
450mod tests {
451 use super::*;
452
453 #[test]
454 fn rejection_reports_the_layer_that_refused_the_frame() {
455 for payload in [
460 br#"{"jsonrpc":"2.0",}"#.as_slice(),
461 br#"{"jsonrpc":"2.0""#.as_slice(),
462 b"\xff\xfe".as_slice(),
463 ] {
464 let (_, kind) = Envelope::parse_classified(payload).unwrap_err();
465 assert_eq!(kind, ErrorKind::ParseError, "{payload:?}");
466 }
467
468 let deep = format!("{}{}", "[".repeat(80), "]".repeat(80));
469 for payload in [
470 br#"{"jsonrpc":"2.0","jsonrpc":"2.0"}"#.as_slice(),
472 deep.as_bytes(),
473 br#"[]"#.as_slice(),
476 br#"{"jsonrpc":"2.0","id":0,"method":"x","_meta":{"deadline_unix_ms":1},"params":{}}"#
478 .as_slice(),
479 br#"{"jsonrpc":"2.0","id":1,"method":"","_meta":{"deadline_unix_ms":1},"params":{}}"#
480 .as_slice(),
481 br#"{"jsonrpc":"2.0","id":1,"method":"x","_meta":{"deadline_unix_ms":1},"params":[]}"#
482 .as_slice(),
483 br#"{"jsonrpc":"2.0"}"#.as_slice(),
484 ] {
485 let (_, kind) = Envelope::parse_classified(payload).unwrap_err();
486 assert_eq!(kind, ErrorKind::InvalidRequest, "{payload:?}");
487 }
488 }
489
490 #[test]
491 fn debug_hides_params_and_results() {
492 for payload in [
493 br#"{"jsonrpc":"2.0","id":1,"method":"resolver.set","_meta":{"deadline_unix_ms":1},"params":{"value":"hunter2"}}"#
494 .as_slice(),
495 br#"{"jsonrpc":"2.0","id":1,"result":{"value":"hunter2"}}"#.as_slice(),
496 br#"{"jsonrpc":"2.0","method":"x.note","params":{"value":"hunter2"}}"#.as_slice(),
497 ] {
498 let debug = format!("{:?}", Envelope::parse(payload).unwrap());
499 assert!(!debug.contains("hunter2"), "{debug}");
500 }
501 }
502
503 #[test]
504 fn rejects_duplicate_keys_and_batches() {
505 assert!(
506 Envelope::parse(
507 br#"{"jsonrpc":"2.0","jsonrpc":"2.0","id":1,"method":"x","_meta":{"deadline_unix_ms":1},"params":{}}"#
508 )
509 .is_err()
510 );
511 assert!(Envelope::parse(br#"[]"#).is_err());
512 }
513
514 #[test]
515 fn request_ids_are_bounded_integers() {
516 for id in ["0", "-1", "1.5", "\"1\"", "9007199254740992"] {
517 let input = format!(
518 r#"{{"jsonrpc":"2.0","id":{id},"method":"x","_meta":{{"deadline_unix_ms":1}},"params":{{}}}}"#
519 );
520 assert!(Envelope::parse(input.as_bytes()).is_err(), "accepted {id}");
521 }
522 }
523
524 #[test]
525 fn rejects_unknown_top_level_members() {
526 assert!(
527 Envelope::parse(
528 br#"{"jsonrpc":"2.0","id":1,"method":"x","_meta":{"deadline_unix_ms":1},"params":{},"extra":true}"#
529 )
530 .is_err()
531 );
532 assert!(Envelope::parse(br#"{"jsonrpc":"2.0","id":1,"result":{},"extra":true}"#).is_err());
533 assert!(
534 Envelope::parse(
535 br#"{"jsonrpc":"2.0","id":1,"result":{},"error":{"code":-32603,"message":"internal error","data":{"kind":"internal","retryable":false}}}"#
536 )
537 .is_err()
538 );
539 }
540
541 #[test]
542 fn notifications_are_closed_envelopes_with_open_methods() {
543 for payload in [
544 br#"{"jsonrpc":"2.0","method":"future.notice","params":{}}"#.as_slice(),
545 br#"{"jsonrpc":"2.0","method":"rpc.cancel","params":{"id":"bad"}}"#.as_slice(),
546 ] {
547 assert!(matches!(
548 Envelope::parse(payload),
549 Ok(Envelope::Notification(_))
550 ));
551 }
552 assert!(
553 Envelope::parse(
554 br#"{"jsonrpc":"2.0","method":"future.notice","params":{},"extra":true}"#
555 )
556 .is_err()
557 );
558 }
559
560 #[test]
561 fn request_deadline_is_required_and_round_trips() {
562 assert!(Envelope::parse(br#"{"jsonrpc":"2.0","id":1,"method":"x","params":{}}"#).is_err());
563 let parsed = Envelope::parse(
564 br#"{"jsonrpc":"2.0","id":1,"method":"x","_meta":{"deadline_unix_ms":42},"params":{}}"#,
565 )
566 .unwrap();
567 let Envelope::Request(request) = parsed else {
568 panic!("expected request")
569 };
570 assert_eq!(request.deadline_unix_ms(), 42);
571 }
572
573 #[test]
574 fn error_response_requires_an_explicit_nullable_id() {
575 assert!(
576 Envelope::parse(
577 br#"{"jsonrpc":"2.0","error":{"code":-32700,"message":"parse error","data":{"kind":"parse_error","retryable":false}}}"#
578 )
579 .is_err()
580 );
581 assert!(
582 Envelope::parse(
583 br#"{"jsonrpc":"2.0","id":null,"error":{"code":-32700,"message":"parse error","data":{"kind":"parse_error","retryable":false}}}"#
584 )
585 .is_ok()
586 );
587 }
588}