diff --git a/zebra-rpc/src/server/compatibility.rs b/zebra-rpc/src/server/compatibility.rs index 8344d386e..e717b794e 100644 --- a/zebra-rpc/src/server/compatibility.rs +++ b/zebra-rpc/src/server/compatibility.rs @@ -9,13 +9,23 @@ use jsonrpc_http_server::RequestMiddleware; /// /// This middleware makes the following changes to requests: /// -/// ## JSON RPC 1.0 `jsonrpc` field +/// ## Remove `jsonrpc` field in JSON RPC 1.0 /// /// Removes "jsonrpc: 1.0" fields from requests, /// because the "jsonrpc" field was only added in JSON-RPC 2.0. /// /// /// +/// ## Add missing `content-type` HTTP header +/// +/// Some RPC clients don't include a `content-type` HTTP header. +/// But unlike web browsers, [`jsonrpc_http_server`] does not do content sniffing. +/// +/// If there is no `content-type` header, we assume the content is JSON, +/// and let the parser error if we are incorrect. +/// +/// This enables compatibility with `zcash-cli`. +/// /// ## Security /// /// Any user-specified data in RPC requests is hex or base58check encoded. @@ -27,8 +37,14 @@ pub struct FixHttpRequestMiddleware; impl RequestMiddleware for FixHttpRequestMiddleware { fn on_request( &self, - request: hyper::Request, + mut request: hyper::Request, ) -> jsonrpc_http_server::RequestMiddlewareAction { + tracing::trace!(?request, "original HTTP request"); + + // Fix the request headers + FixHttpRequestMiddleware::add_missing_content_type_header(request.headers_mut()); + + // Fix the request body let request = request.map(|body| { let body = body.map_ok(|data| { // To simplify data handling, we assume that any search strings won't be split @@ -54,6 +70,8 @@ impl RequestMiddleware for FixHttpRequestMiddleware { Body::wrap_stream(body) }); + tracing::trace!(?request, "modified HTTP request"); + jsonrpc_http_server::RequestMiddlewareAction::Proceed { // TODO: disable this security check if we see errors from lightwalletd. should_continue_on_invalid_cors: false, @@ -82,4 +100,12 @@ impl FixHttpRequestMiddleware { .replace(",\"jsonrpc\":\"1.0\"", "") .replace(", \"jsonrpc\": \"1.0\"", "") } + + /// If the `content-type` HTTP header is not present, + /// add an `application/json` content type header. + pub fn add_missing_content_type_header(headers: &mut hyper::header::HeaderMap) { + headers + .entry(hyper::header::CONTENT_TYPE) + .or_insert(hyper::header::HeaderValue::from_static("application/json")); + } }