diff --git a/client/http-client/src/client.rs b/client/http-client/src/client.rs index 45a245fab3..4d0280d86d 100644 --- a/client/http-client/src/client.rs +++ b/client/http-client/src/client.rs @@ -142,10 +142,18 @@ impl ClientT for HttpClient { } }; - let response_id = response.id.as_number().copied().ok_or(Error::InvalidRequestId)?; - - if response_id == *id.inner() { - Ok(response.result) + if let Some(response_id) = response.id.as_number().copied() { + if response_id == *id.inner() { + Ok(response.result) + } else { + Err(Error::InvalidRequestId) + } + } else if let Some(response_id) = response.id.as_str() { + if response_id == id.inner().to_string() { + Ok(response.result) + } else { + Err(Error::InvalidRequestId) + } } else { Err(Error::InvalidRequestId) } @@ -184,12 +192,26 @@ impl ClientT for HttpClient { // NOTE: `R::default` is placeholder and will be replaced in loop below. let mut responses = vec![R::default(); ordered_requests.len()]; for rp in rps { - let response_id = rp.id.as_number().copied().ok_or(Error::InvalidRequestId)?; - let pos = match request_set.get(&response_id) { - Some(pos) => *pos, - None => return Err(Error::InvalidRequestId), + match rp.id.as_number().copied() { + Some(id) => { + let pos = match request_set.get(&id) { + Some(pos) => *pos, + None => return Err(Error::InvalidRequestId), + }; + responses[pos] = rp.result + } + None => match rp.id.as_str() { + Some(s) => { + let id: u64 = s.trim().parse().map_err(|_| Error::InvalidRequestId)?; + let pos = match request_set.get(&id) { + Some(pos) => *pos, + None => return Err(Error::InvalidRequestId), + }; + responses[pos] = rp.result + } + None => return Err(Error::InvalidRequestId), + }, }; - responses[pos] = rp.result } Ok(responses) } diff --git a/client/http-client/src/tests.rs b/client/http-client/src/tests.rs index 2324443b75..43244ffd3c 100644 --- a/client/http-client/src/tests.rs +++ b/client/http-client/src/tests.rs @@ -58,6 +58,16 @@ async fn notification_works() { .unwrap(); } +#[tokio::test] +async fn response_with_string_id_works() { + let result = run_request_with_response(ok_response("hello".into(), Id::Str("0".to_string()))) + .with_default_timeout() + .await + .unwrap() + .unwrap(); + assert_eq!(JsonValue::String("hello".into()), result); +} + #[tokio::test] async fn response_with_wrong_id() { let err = run_request_with_response(ok_response("hello".into(), Id::Num(99))) @@ -68,6 +78,16 @@ async fn response_with_wrong_id() { assert!(matches!(err, Error::InvalidRequestId)); } +#[tokio::test] +async fn response_with_wrong_string_id() { + let err = run_request_with_response(ok_response("hello".into(), Id::Str("1".to_string()))) + .with_default_timeout() + .await + .unwrap() + .unwrap_err(); + assert!(matches!(err, Error::InvalidRequestId)); +} + #[tokio::test] async fn response_method_not_found() { let err = @@ -113,7 +133,7 @@ async fn subscription_response_to_request() { async fn batch_request_works() { let batch_request = vec![("say_hello", rpc_params![]), ("say_goodbye", rpc_params![0_u64, 1, 2]), ("get_swag", None)]; - let server_response = r#"[{"jsonrpc":"2.0","result":"hello","id":0}, {"jsonrpc":"2.0","result":"goodbye","id":1}, {"jsonrpc":"2.0","result":"here's your swag","id":2}]"#.to_string(); + let server_response = r#"[{"jsonrpc":"2.0","result":"hello","id":0}, {"jsonrpc":"2.0","result":"goodbye","id":"1"}, {"jsonrpc":"2.0","result":"here's your swag","id":2}]"#.to_string(); let response = run_batch_request_with_response(batch_request, server_response).with_default_timeout().await.unwrap().unwrap(); assert_eq!(response, vec!["hello".to_string(), "goodbye".to_string(), "here's your swag".to_string()]);