spikard_http/jsonrpc/
protocol.rs

1//! JSON-RPC 2.0 Protocol Types
2//!
3//! This module provides type definitions for the JSON-RPC 2.0 specification.
4//! See [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification)
5//!
6//! # Overview
7//!
8//! JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol.
9//! This module implements the complete specification including:
10//!
11//! - Request/Response messages
12//! - Standard error codes
13//! - Helper constructors for building valid messages
14//! - Full serialization support via serde
15
16use serde::{Deserialize, Serialize};
17use serde_json::Value;
18
19/// Maximum allowed length for a JSON-RPC method name
20const MAX_METHOD_NAME_LENGTH: usize = 255;
21
22/// Validates a JSON-RPC method name for security and correctness
23///
24/// This function prevents DoS attacks through method name validation by enforcing:
25/// - Maximum length of 255 characters to prevent resource exhaustion
26/// - Only allowed characters: alphanumeric (a-z, A-Z, 0-9), dot (.), underscore (_), hyphen (-)
27/// - No control characters (0x00-0x1F, 0x7F) to prevent injection attacks
28/// - No leading or trailing whitespace to ensure proper formatting
29///
30/// # Arguments
31///
32/// * `method_name` - The method name to validate
33///
34/// # Returns
35///
36/// * `Ok(())` - If the method name is valid
37/// * `Err(String)` - If the method name is invalid with a descriptive error message
38///
39/// # Example
40///
41/// ```ignore
42/// use spikard_http::jsonrpc::validate_method_name;
43///
44/// // Valid method names
45/// assert!(validate_method_name("user.getById").is_ok());
46/// assert!(validate_method_name("calculate_sum").is_ok());
47/// assert!(validate_method_name("api-v1-handler").is_ok());
48/// assert!(validate_method_name("rpc1").is_ok());
49///
50/// // Invalid method names
51/// assert!(validate_method_name("").is_err());  // Empty
52/// assert!(validate_method_name(" method").is_err());  // Leading whitespace
53/// assert!(validate_method_name("method ").is_err());  // Trailing whitespace
54/// assert!(validate_method_name("method\x00name").is_err());  // Control character
55/// assert!(validate_method_name("a".repeat(256)).is_err());  // Too long
56/// ```
57pub fn validate_method_name(method_name: &str) -> Result<(), String> {
58    if method_name.is_empty() {
59        return Err("Method name cannot be empty".to_string());
60    }
61
62    if method_name.starts_with(char::is_whitespace) || method_name.ends_with(char::is_whitespace) {
63        return Err("Method name cannot have leading or trailing whitespace".to_string());
64    }
65
66    if method_name.len() > MAX_METHOD_NAME_LENGTH {
67        return Err(format!(
68            "Method name exceeds maximum length of {} characters (got {})",
69            MAX_METHOD_NAME_LENGTH,
70            method_name.len()
71        ));
72    }
73
74    for ch in method_name.chars() {
75        match ch {
76            'a'..='z' | 'A'..='Z' | '0'..='9' => {}
77            '.' => {}
78            '_' => {}
79            '-' => {}
80            c if (c as u32) < 0x20 || (c as u32) == 0x7F => {
81                return Err(format!(
82                    "Method name contains invalid control character: 0x{:02X}",
83                    c as u32
84                ));
85            }
86            c => {
87                return Err(format!(
88                    "Method name contains invalid character: '{}' (0x{:02X}). \
89                     Only alphanumeric, dot (.), underscore (_), and hyphen (-) are allowed",
90                    c, c as u32
91                ));
92            }
93        }
94    }
95
96    Ok(())
97}
98
99/// JSON-RPC 2.0 Request
100///
101/// Represents a JSON-RPC request method invocation with optional parameters and identifier.
102///
103/// # Fields
104///
105/// * `jsonrpc` - A String specifying the JSON-RPC version. MUST be exactly "2.0"
106/// * `method` - A String containing the name of the method to be invoked
107/// * `params` - Optional structured data that serves as arguments to the method.
108///   The order of the objects in the Array is significant to the method.
109/// * `id` - A value which is used to match the response with the request that it is replying to.
110///   Can be a string, number, or NULL. Notifications MUST NOT include an "id".
111///
112/// # Example
113///
114/// ```ignore
115/// use serde_json::json;
116/// use spikard_http::jsonrpc::JsonRpcRequest;
117///
118/// // Request with parameters and ID
119/// let req = JsonRpcRequest::new("add", Some(json!([1, 2])), Some(json!(1)));
120/// assert!(!req.is_notification());
121///
122/// // Notification (no ID)
123/// let notif = JsonRpcRequest::new("notify", Some(json!({})), None);
124/// assert!(notif.is_notification());
125/// ```
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct JsonRpcRequest {
128    /// JSON-RPC version, must be "2.0"
129    pub jsonrpc: String,
130
131    /// The name of the method to invoke
132    pub method: String,
133
134    /// Optional parameters for the method
135    #[serde(skip_serializing_if = "Option::is_none")]
136    pub params: Option<Value>,
137
138    /// Optional request identifier. When absent, this is a notification.
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub id: Option<Value>,
141}
142
143impl JsonRpcRequest {
144    /// Creates a new JSON-RPC 2.0 request
145    ///
146    /// # Arguments
147    ///
148    /// * `method` - The method name to invoke
149    /// * `params` - Optional parameters (can be array, object, or null)
150    /// * `id` - Optional request identifier (string, number, or null)
151    ///
152    /// # Example
153    ///
154    /// ```ignore
155    /// use serde_json::json;
156    /// use spikard_http::jsonrpc::JsonRpcRequest;
157    ///
158    /// let req = JsonRpcRequest::new("subtract", Some(json!({"a": 5, "b": 3})), Some(json!(2)));
159    /// assert_eq!(req.method, "subtract");
160    /// assert!(!req.is_notification());
161    /// ```
162    pub fn new(method: impl Into<String>, params: Option<Value>, id: Option<Value>) -> Self {
163        Self {
164            jsonrpc: "2.0".to_string(),
165            method: method.into(),
166            params,
167            id,
168        }
169    }
170
171    /// Checks if this request is a notification
172    ///
173    /// A notification is a JSON-RPC request without an "id" field.
174    /// The server MUST NOT reply to a notification.
175    ///
176    /// # Example
177    ///
178    /// ```ignore
179    /// use spikard_http::jsonrpc::JsonRpcRequest;
180    ///
181    /// let req = JsonRpcRequest::new("method", None, Some(serde_json::json!(1)));
182    /// assert!(!req.is_notification());
183    ///
184    /// let notif = JsonRpcRequest::new("notify", None, None);
185    /// assert!(notif.is_notification());
186    /// ```
187    pub fn is_notification(&self) -> bool {
188        self.id.is_none()
189    }
190}
191
192/// JSON-RPC 2.0 Success Response
193///
194/// Represents a successful JSON-RPC response containing the result of the method invocation.
195///
196/// # Fields
197///
198/// * `jsonrpc` - A String specifying the JSON-RPC version. MUST be exactly "2.0"
199/// * `result` - The result of the method invocation. This MUST be null in case of an error.
200/// * `id` - This MUST be the same id as the request it is responding to
201///
202/// # Example
203///
204/// ```ignore
205/// use serde_json::json;
206/// use spikard_http::jsonrpc::JsonRpcResponse;
207///
208/// let response = JsonRpcResponse::success(json!(19), json!(1));
209/// assert_eq!(response.jsonrpc, "2.0");
210/// ```
211#[derive(Debug, Clone, Serialize, Deserialize)]
212pub struct JsonRpcResponse {
213    /// JSON-RPC version, must be "2.0"
214    pub jsonrpc: String,
215
216    /// The result of the method invocation
217    pub result: Value,
218
219    /// The request identifier this response corresponds to
220    pub id: Value,
221}
222
223impl JsonRpcResponse {
224    /// Creates a new JSON-RPC 2.0 success response
225    ///
226    /// # Arguments
227    ///
228    /// * `result` - The result value from the method invocation
229    /// * `id` - The request identifier from the original request
230    ///
231    /// # Example
232    ///
233    /// ```ignore
234    /// use serde_json::json;
235    /// use spikard_http::jsonrpc::JsonRpcResponse;
236    ///
237    /// let response = JsonRpcResponse::success(json!({"sum": 7}), json!("abc"));
238    /// assert_eq!(response.jsonrpc, "2.0");
239    /// ```
240    pub fn success(result: Value, id: Value) -> Self {
241        Self {
242            jsonrpc: "2.0".to_string(),
243            result,
244            id,
245        }
246    }
247}
248
249/// JSON-RPC 2.0 Error Object
250///
251/// Represents a JSON-RPC error that occurred during method invocation.
252///
253/// # Fields
254///
255/// * `code` - A Number that indicates the error type that occurred
256/// * `message` - A String providing a short description of the error
257/// * `data` - Optional additional error information
258///
259/// # Standard Error Codes
260///
261/// - `-32700`: Parse error
262/// - `-32600`: Invalid Request
263/// - `-32601`: Method not found
264/// - `-32602`: Invalid params
265/// - `-32603`: Internal error
266/// - `-32000 to -32099`: Server error (reserved)
267///
268/// # Example
269///
270/// ```ignore
271/// use spikard_http::jsonrpc::{JsonRpcError, error_codes};
272///
273/// let err = JsonRpcError {
274///     code: error_codes::INVALID_PARAMS,
275///     message: "Invalid method parameters".to_string(),
276///     data: None,
277/// };
278/// ```
279#[derive(Debug, Clone, Serialize, Deserialize)]
280pub struct JsonRpcError {
281    /// Numeric error code
282    pub code: i32,
283
284    /// Human-readable error description
285    pub message: String,
286
287    /// Optional additional error context
288    #[serde(skip_serializing_if = "Option::is_none")]
289    pub data: Option<Value>,
290}
291
292/// JSON-RPC 2.0 Error Response
293///
294/// Represents a JSON-RPC response containing an error result.
295///
296/// # Fields
297///
298/// * `jsonrpc` - A String specifying the JSON-RPC version. MUST be exactly "2.0"
299/// * `error` - An Error Object with error information
300/// * `id` - This MUST be the same id as the request it is responding to
301///
302/// # Example
303///
304/// ```ignore
305/// use serde_json::json;
306/// use spikard_http::jsonrpc::{JsonRpcErrorResponse, error_codes};
307///
308/// let err_response = JsonRpcErrorResponse::error(
309///     error_codes::METHOD_NOT_FOUND,
310///     "Method not found",
311///     json!(1)
312/// );
313/// assert_eq!(err_response.jsonrpc, "2.0");
314/// ```
315#[derive(Debug, Clone, Serialize, Deserialize)]
316pub struct JsonRpcErrorResponse {
317    /// JSON-RPC version, must be "2.0"
318    pub jsonrpc: String,
319
320    /// Error object containing error information
321    pub error: JsonRpcError,
322
323    /// The request identifier this response corresponds to
324    pub id: Value,
325}
326
327impl JsonRpcErrorResponse {
328    /// Creates a new JSON-RPC 2.0 error response
329    ///
330    /// # Arguments
331    ///
332    /// * `code` - The numeric error code
333    /// * `message` - The error message
334    /// * `id` - The request identifier from the original request
335    ///
336    /// # Example
337    ///
338    /// ```ignore
339    /// use serde_json::json;
340    /// use spikard_http::jsonrpc::{JsonRpcErrorResponse, error_codes};
341    ///
342    /// let response = JsonRpcErrorResponse::error(
343    ///     error_codes::METHOD_NOT_FOUND,
344    ///     "Unknown method",
345    ///     json!(null)
346    /// );
347    /// assert_eq!(response.jsonrpc, "2.0");
348    /// ```
349    pub fn error(code: i32, message: impl Into<String>, id: Value) -> Self {
350        Self {
351            jsonrpc: "2.0".to_string(),
352            error: JsonRpcError {
353                code,
354                message: message.into(),
355                data: None,
356            },
357            id,
358        }
359    }
360
361    /// Creates a new JSON-RPC 2.0 error response with additional error data
362    ///
363    /// # Arguments
364    ///
365    /// * `code` - The numeric error code
366    /// * `message` - The error message
367    /// * `data` - Additional context about the error
368    /// * `id` - The request identifier from the original request
369    ///
370    /// # Example
371    ///
372    /// ```ignore
373    /// use serde_json::json;
374    /// use spikard_http::jsonrpc::{JsonRpcErrorResponse, error_codes};
375    ///
376    /// let response = JsonRpcErrorResponse::error_with_data(
377    ///     error_codes::INVALID_PARAMS,
378    ///     "Invalid method parameters",
379    ///     json!({"reason": "Missing required field 'name'"}),
380    ///     json!(1)
381    /// );
382    /// assert_eq!(response.jsonrpc, "2.0");
383    /// assert!(response.error.data.is_some());
384    /// ```
385    pub fn error_with_data(code: i32, message: impl Into<String>, data: Value, id: Value) -> Self {
386        Self {
387            jsonrpc: "2.0".to_string(),
388            error: JsonRpcError {
389                code,
390                message: message.into(),
391                data: Some(data),
392            },
393            id,
394        }
395    }
396}
397
398/// JSON-RPC 2.0 Response Type
399///
400/// An enum that represents either a successful response or an error response.
401/// This is useful for untagged deserialization and handling both response types uniformly.
402///
403/// # Variants
404///
405/// * `Success(JsonRpcResponse)` - A successful response with a result
406/// * `Error(JsonRpcErrorResponse)` - An error response with error details
407///
408/// # Example
409///
410/// ```ignore
411/// use serde_json::json;
412/// use spikard_http::jsonrpc::{JsonRpcResponseType, JsonRpcResponse, JsonRpcErrorResponse, error_codes};
413///
414/// let success = JsonRpcResponseType::Success(
415///     JsonRpcResponse::success(json!(42), json!(1))
416/// );
417///
418/// let error = JsonRpcResponseType::Error(
419///     JsonRpcErrorResponse::error(error_codes::INVALID_PARAMS, "Bad params", json!(1))
420/// );
421/// ```
422#[derive(Debug, Clone, Serialize, Deserialize)]
423#[serde(untagged)]
424pub enum JsonRpcResponseType {
425    /// Successful response containing a result
426    Success(JsonRpcResponse),
427
428    /// Error response containing error details
429    Error(JsonRpcErrorResponse),
430}
431
432/// JSON-RPC 2.0 Standard Error Codes
433///
434/// This module contains the standard error codes defined by the JSON-RPC 2.0 specification.
435/// The error codes from -32768 to -32000 are reserved for JSON-RPC specification use.
436pub mod error_codes {
437    /// Parse error
438    ///
439    /// Invalid JSON was received by the server.
440    /// An error occurred on the server while parsing the JSON text.
441    pub const PARSE_ERROR: i32 = -32700;
442
443    /// Invalid Request
444    ///
445    /// The JSON sent is not a valid Request object.
446    pub const INVALID_REQUEST: i32 = -32600;
447
448    /// Method not found
449    ///
450    /// The method does not exist / is not available.
451    pub const METHOD_NOT_FOUND: i32 = -32601;
452
453    /// Invalid params
454    ///
455    /// Invalid method parameter(s).
456    pub const INVALID_PARAMS: i32 = -32602;
457
458    /// Internal error
459    ///
460    /// Internal JSON-RPC error.
461    pub const INTERNAL_ERROR: i32 = -32603;
462
463    /// Server error (base)
464    ///
465    /// Server errors are reserved for implementation-defined server-errors.
466    /// The error codes from -32099 to -32000 are reserved for server error codes.
467    pub const SERVER_ERROR_BASE: i32 = -32000;
468
469    /// Server error (end of reserved range)
470    pub const SERVER_ERROR_END: i32 = -32099;
471
472    /// Helper function to check if a code is a reserved server error code
473    pub fn is_server_error(code: i32) -> bool {
474        (SERVER_ERROR_END..=SERVER_ERROR_BASE).contains(&code)
475    }
476}
477
478#[cfg(test)]
479mod tests {
480    use super::*;
481    use serde_json::json;
482
483    #[test]
484    fn test_jsonrpc_request_creation() {
485        let req = JsonRpcRequest::new("method", Some(json!({"key": "value"})), Some(json!(1)));
486        assert_eq!(req.jsonrpc, "2.0");
487        assert_eq!(req.method, "method");
488        assert!(!req.is_notification());
489    }
490
491    #[test]
492    fn test_jsonrpc_notification() {
493        let notif = JsonRpcRequest::new("notify", None, None);
494        assert!(notif.is_notification());
495    }
496
497    #[test]
498    fn test_jsonrpc_response_success() {
499        let response = JsonRpcResponse::success(json!(42), json!(1));
500        assert_eq!(response.jsonrpc, "2.0");
501        assert_eq!(response.result, json!(42));
502        assert_eq!(response.id, json!(1));
503    }
504
505    #[test]
506    fn test_jsonrpc_error_response() {
507        let err = JsonRpcErrorResponse::error(error_codes::METHOD_NOT_FOUND, "Method not found", json!(1));
508        assert_eq!(err.jsonrpc, "2.0");
509        assert_eq!(err.error.code, error_codes::METHOD_NOT_FOUND);
510        assert_eq!(err.error.message, "Method not found");
511        assert!(err.error.data.is_none());
512    }
513
514    #[test]
515    fn test_jsonrpc_error_response_with_data() {
516        let data = json!({"reason": "Missing parameter"});
517        let err = JsonRpcErrorResponse::error_with_data(
518            error_codes::INVALID_PARAMS,
519            "Invalid parameters",
520            data.clone(),
521            json!(null),
522        );
523        assert_eq!(err.error.code, error_codes::INVALID_PARAMS);
524        assert_eq!(err.error.data, Some(data));
525    }
526
527    #[test]
528    fn test_error_codes_constants() {
529        assert_eq!(error_codes::PARSE_ERROR, -32700);
530        assert_eq!(error_codes::INVALID_REQUEST, -32600);
531        assert_eq!(error_codes::METHOD_NOT_FOUND, -32601);
532        assert_eq!(error_codes::INVALID_PARAMS, -32602);
533        assert_eq!(error_codes::INTERNAL_ERROR, -32603);
534    }
535
536    #[test]
537    fn test_is_server_error() {
538        assert!(error_codes::is_server_error(-32000));
539        assert!(error_codes::is_server_error(-32050));
540        assert!(error_codes::is_server_error(-32099));
541        assert!(!error_codes::is_server_error(-32700));
542        assert!(!error_codes::is_server_error(0));
543    }
544
545    #[test]
546    fn test_request_serialization() {
547        let req = JsonRpcRequest::new("test", Some(json!([1, 2])), Some(json!(1)));
548        let json = serde_json::to_value(&req).unwrap();
549        assert_eq!(json["jsonrpc"], "2.0");
550        assert_eq!(json["method"], "test");
551        assert!(json["params"].is_array());
552        assert_eq!(json["id"], 1);
553    }
554
555    #[test]
556    fn test_notification_serialization() {
557        let notif = JsonRpcRequest::new("notify", Some(json!({})), None);
558        let json = serde_json::to_value(&notif).unwrap();
559        assert!(!json.get("id").is_some() || json["id"].is_null());
560    }
561
562    #[test]
563    fn test_response_serialization() {
564        let resp = JsonRpcResponse::success(json!({"result": 100}), json!("string-id"));
565        let json = serde_json::to_value(&resp).unwrap();
566        assert_eq!(json["jsonrpc"], "2.0");
567        assert_eq!(json["id"], "string-id");
568    }
569
570    #[test]
571    fn test_error_response_serialization() {
572        let err = JsonRpcErrorResponse::error(error_codes::PARSE_ERROR, "Parse error", json!(null));
573        let json = serde_json::to_value(&err).unwrap();
574        assert_eq!(json["jsonrpc"], "2.0");
575        assert_eq!(json["error"]["code"], -32700);
576        assert_eq!(json["error"]["message"], "Parse error");
577    }
578
579    #[test]
580    fn test_response_type_enum() {
581        let success_resp = JsonRpcResponseType::Success(JsonRpcResponse::success(json!(1), json!(1)));
582        let error_resp = JsonRpcResponseType::Error(JsonRpcErrorResponse::error(
583            error_codes::INVALID_REQUEST,
584            "Invalid",
585            json!(1),
586        ));
587
588        let _success_json = serde_json::to_value(&success_resp).unwrap();
589        let _error_json = serde_json::to_value(&error_resp).unwrap();
590    }
591
592    #[test]
593    fn test_validate_method_name_valid_simple() {
594        assert!(validate_method_name("test").is_ok());
595        assert!(validate_method_name("method").is_ok());
596        assert!(validate_method_name("rpc").is_ok());
597    }
598
599    #[test]
600    fn test_validate_method_name_valid_with_dot() {
601        assert!(validate_method_name("user.get").is_ok());
602        assert!(validate_method_name("api.v1.endpoint").is_ok());
603        assert!(validate_method_name("service.method.action").is_ok());
604    }
605
606    #[test]
607    fn test_validate_method_name_valid_with_underscore() {
608        assert!(validate_method_name("get_user").is_ok());
609        assert!(validate_method_name("_private_method").is_ok());
610        assert!(validate_method_name("method_v1").is_ok());
611    }
612
613    #[test]
614    fn test_validate_method_name_valid_with_hyphen() {
615        assert!(validate_method_name("get-user").is_ok());
616        assert!(validate_method_name("api-v1").is_ok());
617        assert!(validate_method_name("my-method-name").is_ok());
618    }
619
620    #[test]
621    fn test_validate_method_name_valid_with_numbers() {
622        assert!(validate_method_name("method1").is_ok());
623        assert!(validate_method_name("v2.endpoint").is_ok());
624        assert!(validate_method_name("rpc123abc").is_ok());
625    }
626
627    #[test]
628    fn test_validate_method_name_valid_mixed() {
629        assert!(validate_method_name("user.get_by_id").is_ok());
630        assert!(validate_method_name("api-v1.service_name").is_ok());
631        assert!(validate_method_name("Service_v1_2_3").is_ok());
632    }
633
634    #[test]
635    fn test_validate_method_name_valid_max_length() {
636        let max_name = "a".repeat(255);
637        assert!(validate_method_name(&max_name).is_ok());
638    }
639
640    #[test]
641    fn test_validate_method_name_empty() {
642        let result = validate_method_name("");
643        assert!(result.is_err());
644        assert!(result.unwrap_err().contains("cannot be empty"));
645    }
646
647    #[test]
648    fn test_validate_method_name_leading_space() {
649        let result = validate_method_name(" method");
650        assert!(result.is_err());
651        assert!(result.unwrap_err().contains("leading or trailing whitespace"));
652    }
653
654    #[test]
655    fn test_validate_method_name_trailing_space() {
656        let result = validate_method_name("method ");
657        assert!(result.is_err());
658        assert!(result.unwrap_err().contains("leading or trailing whitespace"));
659    }
660
661    #[test]
662    fn test_validate_method_name_leading_and_trailing_space() {
663        let result = validate_method_name(" method ");
664        assert!(result.is_err());
665        assert!(result.unwrap_err().contains("leading or trailing whitespace"));
666    }
667
668    #[test]
669    fn test_validate_method_name_internal_space() {
670        let result = validate_method_name("method name");
671        assert!(result.is_err());
672        assert!(result.unwrap_err().contains("invalid character"));
673    }
674
675    #[test]
676    fn test_validate_method_name_too_long() {
677        let too_long_name = "a".repeat(256);
678        let result = validate_method_name(&too_long_name);
679        assert!(result.is_err());
680        assert!(result.unwrap_err().contains("exceeds maximum length"));
681    }
682
683    #[test]
684    fn test_validate_method_name_null_byte() {
685        let result = validate_method_name("method\x00name");
686        assert!(result.is_err());
687        assert!(result.unwrap_err().contains("control character"));
688    }
689
690    #[test]
691    fn test_validate_method_name_newline() {
692        let result = validate_method_name("method\nname");
693        assert!(result.is_err());
694        assert!(result.unwrap_err().contains("control character"));
695    }
696
697    #[test]
698    fn test_validate_method_name_carriage_return() {
699        let result = validate_method_name("method\rname");
700        assert!(result.is_err());
701        assert!(result.unwrap_err().contains("control character"));
702    }
703
704    #[test]
705    fn test_validate_method_name_tab() {
706        let result = validate_method_name("method\tname");
707        assert!(result.is_err());
708        assert!(result.unwrap_err().contains("control character"));
709    }
710
711    #[test]
712    fn test_validate_method_name_delete_char() {
713        let result = validate_method_name("method\x7fname");
714        assert!(result.is_err());
715        assert!(result.unwrap_err().contains("control character"));
716    }
717
718    #[test]
719    fn test_validate_method_name_special_char_at_sign() {
720        let result = validate_method_name("method@name");
721        assert!(result.is_err());
722        assert!(result.unwrap_err().contains("invalid character"));
723    }
724
725    #[test]
726    fn test_validate_method_name_special_char_hash() {
727        let result = validate_method_name("method#name");
728        assert!(result.is_err());
729        assert!(result.unwrap_err().contains("invalid character"));
730    }
731
732    #[test]
733    fn test_validate_method_name_special_char_percent() {
734        let result = validate_method_name("method%name");
735        assert!(result.is_err());
736        assert!(result.unwrap_err().contains("invalid character"));
737    }
738
739    #[test]
740    fn test_validate_method_name_special_char_slash() {
741        let result = validate_method_name("method/name");
742        assert!(result.is_err());
743        assert!(result.unwrap_err().contains("invalid character"));
744    }
745
746    #[test]
747    fn test_validate_method_name_special_char_backslash() {
748        let result = validate_method_name("method\\name");
749        assert!(result.is_err());
750        assert!(result.unwrap_err().contains("invalid character"));
751    }
752
753    #[test]
754    fn test_validate_method_name_special_char_quote() {
755        let result = validate_method_name("method\"name");
756        assert!(result.is_err());
757        assert!(result.unwrap_err().contains("invalid character"));
758    }
759
760    #[test]
761    fn test_validate_method_name_dos_attack_very_long() {
762        let very_long = "a".repeat(10000);
763        let result = validate_method_name(&very_long);
764        assert!(result.is_err());
765        assert!(result.unwrap_err().contains("exceeds maximum length"));
766    }
767
768    #[test]
769    fn test_validate_method_name_dos_attack_control_chars() {
770        let result = validate_method_name("method\x00\x00\x00\x00");
771        assert!(result.is_err());
772        assert!(result.unwrap_err().contains("control character"));
773    }
774
775    #[test]
776    fn test_validate_method_name_edge_case_single_char() {
777        assert!(validate_method_name("a").is_ok());
778        assert!(validate_method_name("_").is_ok());
779        assert!(validate_method_name("-").is_ok());
780        assert!(validate_method_name(".").is_ok());
781    }
782
783    #[test]
784    fn test_request_with_null_id_is_notification() {
785        let json = json!({
786            "jsonrpc": "2.0",
787            "method": "notify",
788            "params": []
789        });
790
791        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
792
793        assert!(request.is_notification());
794        assert_eq!(request.method, "notify");
795    }
796
797    #[test]
798    fn test_request_with_string_id_preserved() {
799        let json = json!({
800            "jsonrpc": "2.0",
801            "method": "add",
802            "params": [1, 2],
803            "id": "abc-123"
804        });
805
806        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
807
808        assert!(!request.is_notification());
809        assert_eq!(request.id, Some(json!("abc-123")));
810    }
811
812    #[test]
813    fn test_request_with_zero_id_valid() {
814        let json = json!({
815            "jsonrpc": "2.0",
816            "method": "test",
817            "id": 0
818        });
819
820        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
821
822        assert!(!request.is_notification());
823        assert_eq!(request.id, Some(json!(0)));
824    }
825
826    #[test]
827    fn test_request_with_negative_id_valid() {
828        let json = json!({
829            "jsonrpc": "2.0",
830            "method": "test",
831            "id": -999
832        });
833
834        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
835
836        assert!(!request.is_notification());
837        assert_eq!(request.id, Some(json!(-999)));
838    }
839
840    #[test]
841    fn test_request_without_jsonrpc_field_invalid() {
842        let json = json!({
843            "method": "test",
844            "id": 1
845        });
846
847        let result: serde_json::Result<JsonRpcRequest> = serde_json::from_value(json);
848
849        assert!(result.is_err());
850    }
851
852    #[test]
853    fn test_response_preserves_id_type_numeric() {
854        let response = JsonRpcResponse::success(json!(42), json!(999));
855        let serialized = serde_json::to_value(&response).unwrap();
856
857        assert_eq!(serialized["id"], 999);
858        assert!(serialized["id"].is_number());
859    }
860
861    #[test]
862    fn test_error_response_never_has_result_field() {
863        let err = JsonRpcErrorResponse::error(error_codes::INVALID_PARAMS, "Bad params", json!(1));
864        let serialized = serde_json::to_value(&err).unwrap();
865
866        assert!(serialized.get("result").is_none());
867        assert!(serialized.get("error").is_some());
868    }
869
870    #[test]
871    fn test_success_response_never_has_error_field() {
872        let success = JsonRpcResponse::success(json!({"data": 123}), json!(1));
873        let serialized = serde_json::to_value(&success).unwrap();
874
875        assert!(serialized.get("error").is_none());
876        assert!(serialized.get("result").is_some());
877    }
878
879    #[test]
880    fn test_params_array_type() {
881        let json = json!({
882            "jsonrpc": "2.0",
883            "method": "sum",
884            "params": [1, 2, 3, 4, 5],
885            "id": 1
886        });
887
888        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
889
890        assert!(request.params.is_some());
891        let params = request.params.unwrap();
892        assert!(params.is_array());
893        let arr = params.as_array().unwrap();
894        assert_eq!(arr.len(), 5);
895        assert_eq!(arr[0], json!(1));
896    }
897
898    #[test]
899    fn test_params_object_type() {
900        let json = json!({
901            "jsonrpc": "2.0",
902            "method": "subtract",
903            "params": {"a": 5, "b": 3},
904            "id": 2
905        });
906
907        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
908
909        assert!(request.params.is_some());
910        let params = request.params.unwrap();
911        assert!(params.is_object());
912        let obj = params.as_object().unwrap();
913        assert_eq!(obj.get("a"), Some(&json!(5)));
914        assert_eq!(obj.get("b"), Some(&json!(3)));
915    }
916
917    #[test]
918    fn test_params_null_type() {
919        let json_no_params = json!({
920            "jsonrpc": "2.0",
921            "method": "test",
922            "id": 3
923        });
924
925        let request: JsonRpcRequest = serde_json::from_value(json_no_params).unwrap();
926        assert!(request.params.is_none());
927    }
928
929    #[test]
930    fn test_params_primitive_string() {
931        let json = json!({
932            "jsonrpc": "2.0",
933            "method": "echo",
934            "params": "hello world",
935            "id": 4
936        });
937
938        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
939
940        assert!(request.params.is_some());
941        assert_eq!(request.params.unwrap(), json!("hello world"));
942    }
943
944    #[test]
945    fn test_params_primitive_number() {
946        let json = json!({
947            "jsonrpc": "2.0",
948            "method": "increment",
949            "params": 42,
950            "id": 5
951        });
952
953        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
954
955        assert!(request.params.is_some());
956        assert_eq!(request.params.unwrap(), json!(42));
957    }
958
959    #[test]
960    fn test_params_deeply_nested() {
961        let json = json!({
962            "jsonrpc": "2.0",
963            "method": "process",
964            "params": {
965                "level1": {
966                    "level2": {
967                        "level3": {
968                            "level4": {
969                                "level5": {
970                                    "level6": {
971                                        "level7": {
972                                            "level8": {
973                                                "level9": {
974                                                    "level10": "deep value"
975                                                }
976                                            }
977                                        }
978                                    }
979                                }
980                            }
981                        }
982                    }
983                }
984            },
985            "id": 6
986        });
987
988        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
989
990        assert!(request.params.is_some());
991        let deep = request.params.unwrap();
992        assert!(
993            deep["level1"]["level2"]["level3"]["level4"]["level5"]["level6"]["level7"]["level8"]["level9"]["level10"]
994                .is_string()
995        );
996        assert_eq!(
997            deep["level1"]["level2"]["level3"]["level4"]["level5"]["level6"]["level7"]["level8"]["level9"]["level10"],
998            "deep value"
999        );
1000    }
1001
1002    #[test]
1003    fn test_params_unicode_strings() {
1004        let json = json!({
1005            "jsonrpc": "2.0",
1006            "method": "translate",
1007            "params": {
1008                "emoji": "Hello 👋 World 🌍",
1009                "rtl": "שלום עולם",
1010                "cjk": "你好世界",
1011                "special": "café ñ ü"
1012            },
1013            "id": 7
1014        });
1015
1016        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
1017
1018        let params = request.params.unwrap();
1019        assert_eq!(params["emoji"], "Hello 👋 World 🌍");
1020        assert_eq!(params["rtl"], "שלום עולם");
1021        assert_eq!(params["cjk"], "你好世界");
1022        assert_eq!(params["special"], "café ñ ü");
1023    }
1024
1025    #[test]
1026    fn test_response_result_with_null_valid() {
1027        let response = JsonRpcResponse::success(json!(null), json!(1));
1028        let serialized = serde_json::to_value(&response).unwrap();
1029
1030        assert_eq!(serialized["jsonrpc"], "2.0");
1031        assert_eq!(serialized["id"], 1);
1032        assert_eq!(serialized["result"], json!(null));
1033        assert!(serialized.get("error").is_none());
1034    }
1035
1036    #[test]
1037    fn test_response_result_with_false_valid() {
1038        let response = JsonRpcResponse::success(json!(false), json!(2));
1039        let serialized = serde_json::to_value(&response).unwrap();
1040
1041        assert_eq!(serialized["jsonrpc"], "2.0");
1042        assert_eq!(serialized["id"], 2);
1043        assert_eq!(serialized["result"], json!(false));
1044        assert!(serialized.get("error").is_none());
1045    }
1046
1047    #[test]
1048    fn test_response_result_with_zero_valid() {
1049        let response = JsonRpcResponse::success(json!(0), json!(3));
1050        let serialized = serde_json::to_value(&response).unwrap();
1051
1052        assert_eq!(serialized["jsonrpc"], "2.0");
1053        assert_eq!(serialized["id"], 3);
1054        assert_eq!(serialized["result"], json!(0));
1055        assert!(serialized.get("error").is_none());
1056    }
1057
1058    #[test]
1059    fn test_response_result_with_empty_object_valid() {
1060        let response = JsonRpcResponse::success(json!({}), json!(4));
1061        let serialized = serde_json::to_value(&response).unwrap();
1062
1063        assert_eq!(serialized["jsonrpc"], "2.0");
1064        assert_eq!(serialized["id"], 4);
1065        assert_eq!(serialized["result"], json!({}));
1066        assert!(serialized.get("error").is_none());
1067    }
1068
1069    #[test]
1070    fn test_response_result_with_empty_array_valid() {
1071        let response = JsonRpcResponse::success(json!([]), json!(5));
1072        let serialized = serde_json::to_value(&response).unwrap();
1073
1074        assert_eq!(serialized["jsonrpc"], "2.0");
1075        assert_eq!(serialized["id"], 5);
1076        assert_eq!(serialized["result"], json!([]));
1077        assert!(serialized.get("error").is_none());
1078    }
1079
1080    #[test]
1081    fn test_error_code_parse_error() {
1082        let err = JsonRpcErrorResponse::error(error_codes::PARSE_ERROR, "Parse error", json!(null));
1083        let serialized = serde_json::to_value(&err).unwrap();
1084
1085        assert_eq!(serialized["error"]["code"], -32700);
1086        assert!(serialized.get("result").is_none());
1087    }
1088
1089    #[test]
1090    fn test_error_code_roundtrip() {
1091        let codes = vec![
1092            error_codes::PARSE_ERROR,
1093            error_codes::INVALID_REQUEST,
1094            error_codes::METHOD_NOT_FOUND,
1095            error_codes::INVALID_PARAMS,
1096            error_codes::INTERNAL_ERROR,
1097        ];
1098
1099        for code in codes {
1100            let err = JsonRpcErrorResponse::error(code, "Test error", json!(1));
1101            let serialized = serde_json::to_value(&err).unwrap();
1102            let deserialized: JsonRpcErrorResponse = serde_json::from_value(serialized).unwrap();
1103
1104            assert_eq!(deserialized.error.code, code);
1105        }
1106    }
1107
1108    #[test]
1109    fn test_notification_has_no_id_field() {
1110        let notif = JsonRpcRequest::new("notify", None, None);
1111        let serialized = serde_json::to_value(&notif).unwrap();
1112
1113        assert!(serialized.get("id").is_none());
1114    }
1115
1116    #[test]
1117    fn test_id_preservation_in_batch() {
1118        let json_batch = json!([
1119            {
1120                "jsonrpc": "2.0",
1121                "method": "method1",
1122                "id": "string-id"
1123            },
1124            {
1125                "jsonrpc": "2.0",
1126                "method": "method2",
1127                "id": 42
1128            },
1129            {
1130                "jsonrpc": "2.0",
1131                "method": "method3"
1132            }
1133        ]);
1134
1135        let batch: Vec<JsonRpcRequest> = serde_json::from_value(json_batch).unwrap();
1136
1137        assert_eq!(batch.len(), 3);
1138        assert_eq!(batch[0].id, Some(json!("string-id")));
1139        assert_eq!(batch[1].id, Some(json!(42)));
1140        assert_eq!(batch[2].id, None);
1141    }
1142
1143    #[test]
1144    fn test_mixed_id_types_in_batch() {
1145        let responses = vec![
1146            JsonRpcResponse::success(json!(100), json!("id1")),
1147            JsonRpcResponse::success(json!(200), json!(2)),
1148            JsonRpcResponse::success(json!(300), json!(null)),
1149        ];
1150
1151        for resp in responses {
1152            let serialized = serde_json::to_value(&resp).unwrap();
1153            let deserialized: JsonRpcResponse = serde_json::from_value(serialized).unwrap();
1154            assert_eq!(deserialized.jsonrpc, "2.0");
1155        }
1156    }
1157
1158    #[test]
1159    fn test_large_numeric_id() {
1160        let large_id = i64::MAX;
1161        let json = json!({
1162            "jsonrpc": "2.0",
1163            "method": "test",
1164            "id": large_id
1165        });
1166
1167        let request: JsonRpcRequest = serde_json::from_value(json).unwrap();
1168
1169        assert_eq!(request.id, Some(json!(large_id)));
1170    }
1171
1172    #[test]
1173    fn test_error_always_has_code() {
1174        let err = JsonRpcErrorResponse::error(error_codes::METHOD_NOT_FOUND, "Not found", json!(1));
1175        let serialized = serde_json::to_value(&err).unwrap();
1176
1177        assert!(serialized["error"].get("code").is_some());
1178        assert_eq!(serialized["error"]["code"], -32601);
1179    }
1180
1181    #[test]
1182    fn test_error_always_has_message() {
1183        let err = JsonRpcErrorResponse::error(error_codes::INVALID_PARAMS, "Invalid parameters", json!(2));
1184        let serialized = serde_json::to_value(&err).unwrap();
1185
1186        assert!(serialized["error"].get("message").is_some());
1187        assert_eq!(serialized["error"]["message"], "Invalid parameters");
1188    }
1189
1190    #[test]
1191    fn test_error_data_optional() {
1192        let err_without_data = JsonRpcErrorResponse::error(error_codes::INTERNAL_ERROR, "Internal error", json!(3));
1193        let serialized_without = serde_json::to_value(&err_without_data).unwrap();
1194
1195        assert!(serialized_without["error"].get("data").is_none());
1196
1197        let err_with_data = JsonRpcErrorResponse::error_with_data(
1198            error_codes::INTERNAL_ERROR,
1199            "Internal error",
1200            json!({"details": "something went wrong"}),
1201            json!(4),
1202        );
1203        let serialized_with = serde_json::to_value(&err_with_data).unwrap();
1204
1205        assert!(serialized_with["error"].get("data").is_some());
1206    }
1207}