Skip to content

Commit

Permalink
fix(rpc): remove non-standard "jsonrpc: 1.0" from lightwalletd
Browse files Browse the repository at this point in the history
  • Loading branch information
teor2345 committed Feb 21, 2022
1 parent 722e248 commit 423f9b0
Showing 1 changed file with 77 additions and 2 deletions.
79 changes: 77 additions & 2 deletions zebrad/src/components/rpc.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! An RPC endpoint.
use futures::TryStreamExt;
use hyper::{body::Bytes, Body};
use jsonrpc_core;

use jsonrpc_http_server::ServerBuilder;
use jsonrpc_http_server::{DomainsValidation, RequestMiddleware, ServerBuilder};

use zebra_rpc::rpc::{Rpc, RpcImpl};

Expand All @@ -24,7 +25,12 @@ impl RpcServer {
io.extend_with(RpcImpl.to_delegate());

let server = ServerBuilder::new(io)
// TODO: use the same tokio executor as the rest of Zebra
//.event_loop_executor(tokio::runtime::Handle::current())
.threads(1)
// TODO: if we enable this security check, does lightwalletd still work?
.allowed_hosts(DomainsValidation::Disabled)
.request_middleware(FixHttpRequestMiddleware)
.start_http(&config.listen_addr)
.expect("Unable to start RPC server");

Expand All @@ -35,3 +41,72 @@ impl RpcServer {
RpcServer {}
}
}

/// HTTP [`RequestMiddleware`] with compatibility wrokarounds.
///
/// This middleware makes the following changes to requests:
///
/// ## JSON RPC 1.0 `jsonrpc` field
///
/// Removes "jsonrpc: 1.0" fields from requests,
/// because the "jsonrpc" field was only added in JSON-RPC 2.0.
///
/// <http://www.simple-is-better.org/rpc/#differences-between-1-0-and-2-0>
//
// TODO: put this HTTP middleware in a separate module
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct FixHttpRequestMiddleware;

impl RequestMiddleware for FixHttpRequestMiddleware {
fn on_request(
&self,
request: hyper::Request<hyper::Body>,
) -> jsonrpc_http_server::RequestMiddlewareAction {
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
// across multiple `Bytes` data buffers.
//
// To simplify error handling, Zebra only supports valid UTF-8 requests,
// and uses lossy UTF-8 conversion.
//
// JSON-RPC requires all requests to be valid UTF-8.
// The lower layers should reject invalid requests with lossy changes.
// But if they accept some lossy changes, that's ok,
// because the request was non-standard anyway.
//
// We're not concerned about performance here, so we just clone the Cow<str>
let data = String::from_utf8_lossy(data.as_ref()).to_string();

// Fix up the request.
let data = Self::remove_json_1_fields(data);

Bytes::from(data)
});

Body::wrap_stream(body)
});

jsonrpc_http_server::RequestMiddlewareAction::Proceed {
// TODO: if we enable this security check, does lightwalletd still work?
should_continue_on_invalid_cors: true,
request,
}
}
}

impl FixHttpRequestMiddleware {
/// Remove any "jsonrpc: 1.0" fields in `data`, and return the resulting string.
pub fn remove_json_1_fields(data: String) -> String {
// Replace "jsonrpc = 1.0":
// - at the start or middle of a list, and
// - at the end of a list;
// with no spaces (lightwalletd format), and spaces after separators (example format).
//
// TODO: replace this with a regular expression if we see errors from lightwalletd.
data.replace("\"jsonrpc\":\"1.0\",", "")
.replace("\"jsonrpc\": \"1.0\",", "")
.replace(",\"jsonrpc\":\"1.0\"", "")
.replace(", \"jsonrpc\": \"1.0\"", "")
}
}

0 comments on commit 423f9b0

Please sign in to comment.