|
1 | 1 | use ldk_node::Node; |
2 | 2 |
|
3 | | -use http_body_util::{BodyExt, Full}; |
| 3 | +use http_body_util::{BodyExt, Full, Limited}; |
4 | 4 | use hyper::body::{Bytes, Incoming}; |
5 | 5 | use hyper::service::Service; |
6 | 6 | use hyper::{Request, Response, StatusCode}; |
@@ -39,6 +39,10 @@ use std::future::Future; |
39 | 39 | use std::pin::Pin; |
40 | 40 | use std::sync::Arc; |
41 | 41 |
|
| 42 | +// Maximum request body size: 10 MB |
| 43 | +// This prevents memory exhaustion from large requests |
| 44 | +const MAX_BODY_SIZE: usize = 10 * 1024 * 1024; |
| 45 | + |
42 | 46 | #[derive(Clone)] |
43 | 47 | pub struct NodeService { |
44 | 48 | node: Arc<Node>, |
@@ -127,8 +131,23 @@ async fn handle_request< |
127 | 131 | >( |
128 | 132 | context: Context, request: Request<Incoming>, handler: F, |
129 | 133 | ) -> Result<<NodeService as Service<Request<Incoming>>>::Response, hyper::Error> { |
130 | | - // TODO: we should bound the amount of data we read to avoid allocating too much memory. |
131 | | - let bytes = request.into_body().collect().await?.to_bytes(); |
| 134 | + // Limit the size of the request body to prevent abuse |
| 135 | + let limited_body = Limited::new(request.into_body(), MAX_BODY_SIZE); |
| 136 | + let bytes = match limited_body.collect().await { |
| 137 | + Ok(collected) => collected.to_bytes(), |
| 138 | + Err(_) => { |
| 139 | + let (error_response, status_code) = to_error_response(LdkServerError::new( |
| 140 | + InvalidRequestError, |
| 141 | + "Request body too large or failed to read.", |
| 142 | + )); |
| 143 | + return Ok(Response::builder() |
| 144 | + .status(status_code) |
| 145 | + .body(Full::new(Bytes::from(error_response.encode_to_vec()))) |
| 146 | + // unwrap safety: body only errors when previous chained calls failed. |
| 147 | + .unwrap()); |
| 148 | + }, |
| 149 | + }; |
| 150 | + |
132 | 151 | match T::decode(bytes) { |
133 | 152 | Ok(request) => match handler(context, request) { |
134 | 153 | Ok(response) => Ok(Response::builder() |
|
0 commit comments