@@ -17,18 +17,21 @@ class ErrorCode
1717 ParseError = -32700
1818 end
1919
20+ DEFAULT_ALLOWED_ID_CHARACTERS = /\A [a-zA-Z0-9_-]+\z / . freeze
21+
2022 module_function
2123
22- def handle ( request , &method_finder )
24+ def handle ( request , id_validation_pattern : DEFAULT_ALLOWED_ID_CHARACTERS , &method_finder )
25+
2326 if request . is_a? Array
24- return error_response id : :unknown_id , error : {
27+ return error_response id : :unknown_id , id_validation_pattern : , error : {
2528 code : ErrorCode ::InvalidRequest ,
2629 message : 'Invalid Request' ,
2730 data : 'Request is an empty array' ,
2831 } if request . empty?
2932
3033 # Handle batch requests
31- responses = request . map { |req | process_request req , &method_finder } . compact
34+ responses = request . map { |req | process_request req , id_validation_pattern : , &method_finder } . compact
3235
3336 # A single item is hoisted out of the array
3437 return responses . first if responses . one?
@@ -37,22 +40,22 @@ def handle(request, &method_finder)
3740 responses if responses . any?
3841 elsif request . is_a? Hash
3942 # Handle single request
40- process_request request , &method_finder
43+ process_request request , id_validation_pattern : , &method_finder
4144 else
42- error_response id : :unknown_id , error : {
45+ error_response id : :unknown_id , id_validation_pattern : , error : {
4346 code : ErrorCode ::InvalidRequest ,
4447 message : 'Invalid Request' ,
4548 data : 'Request must be an array or a hash' ,
4649 }
4750 end
4851 end
4952
50- def handle_json ( request_json , &method_finder )
53+ def handle_json ( request_json , id_validation_pattern : DEFAULT_ALLOWED_ID_CHARACTERS , &method_finder )
5154 begin
5255 request = JSON . parse request_json , symbolize_names : true
53- response = handle request , &method_finder
56+ response = handle request , id_validation_pattern : , &method_finder
5457 rescue JSON ::ParserError
55- response = error_response id : :unknown_id , error : {
58+ response = error_response id : :unknown_id , id_validation_pattern : , error : {
5659 code : ErrorCode ::ParseError ,
5760 message : 'Parse error' ,
5861 data : 'Invalid JSON' ,
@@ -62,16 +65,16 @@ def handle_json(request_json, &method_finder)
6265 response . to_json if response
6366 end
6467
65- def process_request ( request , &method_finder )
68+ def process_request ( request , id_validation_pattern : , &method_finder )
6669 id = request [ :id ]
6770
6871 error = case
6972 when !valid_version? ( request [ :jsonrpc ] ) then 'JSON-RPC version must be 2.0'
70- when !valid_id? ( request [ :id ] ) then 'Request ID must be a string or an integer or null'
73+ when !valid_id? ( request [ :id ] , id_validation_pattern ) then 'Request ID must match validation pattern, or be an integer or null'
7174 when !valid_method_name? ( request [ :method ] ) then 'Method name must be a string and not start with "rpc."'
7275 end
7376
74- return error_response id : :unknown_id , error : {
77+ return error_response id : :unknown_id , id_validation_pattern : , error : {
7578 code : ErrorCode ::InvalidRequest ,
7679 message : 'Invalid Request' ,
7780 data : error ,
@@ -81,7 +84,7 @@ def process_request(request, &method_finder)
8184 params = request [ :params ]
8285
8386 unless valid_params? params
84- return error_response id :, error : {
87+ return error_response id :, id_validation_pattern : , error : {
8588 code : ErrorCode ::InvalidParams ,
8689 message : 'Invalid params' ,
8790 data : 'Method parameters must be an array or an object or null' ,
@@ -92,7 +95,7 @@ def process_request(request, &method_finder)
9295 method = method_finder . call method_name
9396
9497 if method . nil?
95- return error_response id :, error : {
98+ return error_response id :, id_validation_pattern : , error : {
9699 code : ErrorCode ::MethodNotFound ,
97100 message : 'Method not found' ,
98101 data : method_name ,
@@ -103,7 +106,7 @@ def process_request(request, &method_finder)
103106
104107 success_response id :, result :
105108 rescue StandardError => e
106- error_response id :, error : {
109+ error_response id :, id_validation_pattern : , error : {
107110 code : ErrorCode ::InternalError ,
108111 message : 'Internal error' ,
109112 data : e . message ,
@@ -115,8 +118,12 @@ def valid_version?(version)
115118 version == Version ::V2_0
116119 end
117120
118- def valid_id? ( id )
119- id . is_a? ( String ) || id . is_a? ( Integer ) || id . nil?
121+
122+ def valid_id? ( id , pattern = nil )
123+ return true if id . nil? || id . is_a? ( Integer )
124+ return false unless id . is_a? ( String )
125+
126+ pattern ? id . match? ( pattern ) : true
120127 end
121128
122129 def valid_method_name? ( method )
@@ -135,10 +142,10 @@ def success_response(id:, result:)
135142 } unless id . nil?
136143 end
137144
138- def error_response ( id :, error :)
145+ def error_response ( id :, id_validation_pattern : , error :)
139146 {
140147 jsonrpc : Version ::V2_0 ,
141- id : valid_id? ( id ) ? id : nil ,
148+ id : valid_id? ( id , id_validation_pattern ) ? id : nil ,
142149 error : error . compact ,
143150 } unless id . nil?
144151 end
0 commit comments