Parse RPC errors as JSON content

Bitcoin Core's JSON RPC server returns errors as HTTP error responses
with JSON content in the body. Parse this content as JSON to give a more
meaningful error. Otherwise, "binary" is given because the content
contains ASCII control characters.
This commit is contained in:
Jeffrey Czyz 2021-05-26 10:57:39 -07:00
parent 61648fc804
commit b2f16ad821
No known key found for this signature in database
GPG key ID: 3A4E08275D5E96D2

View file

@ -2,7 +2,7 @@
//! endpoint.
use crate::{BlockHeaderData, BlockSource, AsyncBlockSourceResult};
use crate::http::{HttpClient, HttpEndpoint, JsonResponse};
use crate::http::{HttpClient, HttpEndpoint, HttpError, JsonResponse};
use bitcoin::blockdata::block::Block;
use bitcoin::hash_types::BlockHash;
@ -47,8 +47,20 @@ impl RpcClient {
"id": &self.id.fetch_add(1, Ordering::AcqRel).to_string()
});
let mut response = self.client.post::<JsonResponse>(&uri, &host, &self.basic_auth, content)
.await?.0;
let mut response = match self.client.post::<JsonResponse>(&uri, &host, &self.basic_auth, content).await {
Ok(JsonResponse(response)) => response,
Err(e) if e.kind() == std::io::ErrorKind::Other => {
match e.get_ref().unwrap().downcast_ref::<HttpError>() {
Some(http_error) => match JsonResponse::try_from(http_error.contents.clone()) {
Ok(JsonResponse(response)) => response,
Err(_) => Err(e)?,
},
None => Err(e)?,
}
},
Err(e) => Err(e)?,
};
if !response.is_object() {
return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "expected JSON object"));
}
@ -143,7 +155,7 @@ mod tests {
let response = serde_json::json!({
"error": { "code": -8, "message": "invalid parameter" },
});
let server = HttpServer::responding_with_ok(MessageBody::Content(response));
let server = HttpServer::responding_with_server_error(response);
let mut client = RpcClient::new(CREDENTIALS, server.endpoint()).unwrap();
let invalid_block_hash = serde_json::json!("foo");