use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};
use bytes::Bytes;
use http_body::Frame;
use jsonrpsee::{
core::BoxError,
server::{HttpBody, HttpRequest, HttpResponse},
};
use tower::Service;
use crate::server::http_request_compatibility::HttpRequestMiddleware;
struct ErrorBody;
impl http_body::Body for ErrorBody {
type Data = Bytes;
type Error = BoxError;
fn poll_frame(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
Poll::Ready(Some(Err("connection reset".into())))
}
}
#[derive(Clone)]
struct MockRpcService;
impl Service<HttpRequest> for MockRpcService {
type Response = HttpResponse;
type Error = BoxError;
type Future = Pin<Box<dyn Future<Output = Result<HttpResponse, BoxError>> + Send>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _req: HttpRequest) -> Self::Future {
let body = r#"{"jsonrpc":"2.0","id":1,"result":null}"#;
let response = HttpResponse::new(HttpBody::from(body.to_string()));
Box::pin(async { Ok(response) })
}
}
#[tokio::test]
async fn request_body_error_returns_err_instead_of_panic() {
let error_body = HttpBody::new(ErrorBody);
let request = HttpRequest::builder()
.method("POST")
.header("content-type", "appliion/json")
.body(error_body)
.expect("valid request");
let mut middleware = HttpRequestMiddleware::new(MockRpcService, None, 2_097_152);
let result = middleware.call(request).await;
assert!(
result.is_err(),
"body collection error should return Err, not panic"
);
}
#[tokio::test]
async fn oversized_request_body_is_rejected() {
let limit = 64;
let oversized = vec![b'x'; limit + 1];
let body = HttpBody::from(oversized);
let request = HttpRequest::builder()
.method("POST")
.header("content-type", "application/json")
.body(body)
.expect("valid request");
let mut middleware = HttpRequestMiddleware::new(MockRpcService, None, limit);
let result = middleware.call(request).await;
assert!(result.is_err(), "oversized request body should be rejected");
}