jsonrpsee_server/transport/
http.rs1use crate::{server::handle_rpc_call, BatchRequestConfig, HttpRequest, HttpResponse, LOG_TARGET};
2use http::Method;
3use hyper::body::Bytes;
4use jsonrpsee_core::{
5 http_helpers::{read_body, HttpError},
6 middleware::RpcServiceT,
7 BoxError,
8};
9
10fn is_json(content_type: Option<&hyper::header::HeaderValue>) -> bool {
12 content_type.and_then(|val| val.to_str().ok()).is_some_and(|content| {
13 content.eq_ignore_ascii_case("application/json") ||
14 content.eq_ignore_ascii_case("application/json; charset=utf-8") ||
15 content.eq_ignore_ascii_case("application/json;charset=utf-8") ||
16 content.eq_ignore_ascii_case("application/json-rpc") ||
17 content.eq_ignore_ascii_case("application/json-rpc;charset=utf-8") ||
18 content.eq_ignore_ascii_case("application/json-rpc; charset=utf-8")
19 })
20}
21
22pub async fn call_with_service<S, B>(
26 request: HttpRequest<B>,
27 batch_config: BatchRequestConfig,
28 max_request_size: u32,
29 rpc_service: S,
30) -> HttpResponse
31where
32 B: http_body::Body<Data = Bytes> + Send + 'static,
33 B::Data: Send,
34 B::Error: Into<BoxError>,
35 S: RpcServiceT + Send,
36{
37 match *request.method() {
39 Method::POST if is_json(request.headers().get(hyper::header::CONTENT_TYPE)) => {
40 let (parts, body) = request.into_parts();
41
42 let (body, is_single) = match read_body(&parts.headers, body, max_request_size).await {
43 Ok(r) => r,
44 Err(HttpError::TooLarge) => return response::too_large(max_request_size),
45 Err(HttpError::Malformed) => return response::malformed(),
46 Err(HttpError::Stream(e)) => {
47 tracing::warn!(target: LOG_TARGET, "Internal error reading request body: {}", e);
48 return response::internal_error();
49 }
50 };
51
52 let rp = handle_rpc_call(&body, is_single, batch_config, &rpc_service).await;
53
54 response::from_method_response(rp)
57 }
58 Method::POST => response::unsupported_content_type(),
60 _ => response::method_not_allowed(),
61 }
62}
63
64pub mod response {
66 use jsonrpsee_core::server::MethodResponse;
67 use jsonrpsee_types::{
68 error::{reject_too_big_request, ErrorCode},
69 ErrorObjectOwned, Id, Response, ResponsePayload,
70 };
71
72 use crate::{HttpBody, HttpResponse};
73
74 const JSON: &str = "application/json; charset=utf-8";
75 const TEXT: &str = "text/plain";
76
77 pub fn internal_error() -> HttpResponse {
79 let err = ResponsePayload::<()>::error(ErrorObjectOwned::from(ErrorCode::InternalError));
80 let rp = Response::new(err, Id::Null);
81 let error = serde_json::to_string(&rp).expect("built from known-good data; qed");
82
83 from_template(hyper::StatusCode::INTERNAL_SERVER_ERROR, error, JSON)
84 }
85
86 pub fn method_not_allowed() -> HttpResponse {
88 from_template(
89 hyper::StatusCode::METHOD_NOT_ALLOWED,
90 "Used HTTP Method is not allowed. POST is required\n",
91 TEXT,
92 )
93 }
94
95 pub fn too_large(limit: u32) -> HttpResponse {
97 let err = ResponsePayload::<()>::error(reject_too_big_request(limit));
98 let rp = Response::new(err, Id::Null);
99 let error = serde_json::to_string(&rp).expect("JSON serialization infallible; qed");
100
101 from_template(hyper::StatusCode::PAYLOAD_TOO_LARGE, error, JSON)
102 }
103
104 pub fn malformed() -> HttpResponse {
106 let rp = Response::new(ResponsePayload::<()>::error(ErrorCode::ParseError), Id::Null);
107 let error = serde_json::to_string(&rp).expect("JSON serialization infallible; qed");
108
109 from_template(hyper::StatusCode::BAD_REQUEST, error, JSON)
110 }
111
112 pub(crate) fn from_template(
114 status: hyper::StatusCode,
115 body: impl Into<HttpBody>,
116 content_type: &'static str,
117 ) -> HttpResponse {
118 HttpResponse::builder()
119 .status(status)
120 .header("content-type", hyper::header::HeaderValue::from_static(content_type))
121 .body(body.into())
122 .expect("Unable to parse response body for type conversion")
125 }
126
127 pub fn from_method_response(rp: MethodResponse) -> HttpResponse {
129 let body = rp.into_json();
130 from_template(hyper::StatusCode::OK, body, JSON)
131 }
132
133 pub fn unsupported_content_type() -> HttpResponse {
135 from_template(
136 hyper::StatusCode::UNSUPPORTED_MEDIA_TYPE,
137 "Supplied content type is not allowed. Content-Type: application/json is required\n",
138 TEXT,
139 )
140 }
141
142 pub fn too_many_requests() -> HttpResponse {
144 from_template(
145 hyper::StatusCode::TOO_MANY_REQUESTS,
146 "Too many connections. Please try again later.",
147 TEXT,
148 )
149 }
150
151 pub fn denied() -> HttpResponse {
153 from_template(hyper::StatusCode::FORBIDDEN, HttpBody::default(), TEXT)
154 }
155}