Skip to content

Commit 81cff87

Browse files
committed
Share expected_len calc in read_limited_body
Deduplicate the sensitive MAX_CONTENT_LENGTH restriction and calculation based off of the Content-Length header.
1 parent c81a670 commit 81cff87

1 file changed

Lines changed: 15 additions & 30 deletions

File tree

payjoin-cli/src/app/v1.rs

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,7 @@ impl AppTrait for App {
9393
payjoin::bitcoin::consensus::encode::serialize_hex(&fallback_tx)
9494
);
9595

96-
let expected_length = response
97-
.headers()
98-
.get("Content-Length")
99-
.and_then(|val| val.to_str().ok())
100-
.and_then(|s| s.parse::<usize>().ok())
101-
.unwrap_or(MAX_CONTENT_LENGTH);
102-
103-
if expected_length > MAX_CONTENT_LENGTH {
104-
return Err(anyhow!("Response body is too large: {} bytes", expected_length));
105-
}
106-
107-
let body = read_limited_body(response.bytes_stream(), expected_length).await?;
96+
let body = read_limited_body(&response.headers().clone(), response.bytes_stream()).await?;
10897

10998
let psbt = ctx.process_response(&body).map_err(|e| {
11099
log::debug!("Error processing response: {e:?}");
@@ -312,26 +301,11 @@ impl App {
312301
req: Request<Incoming>,
313302
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, ReplyableError> {
314303
let (parts, body) = req.into_parts();
315-
let headers = Headers(&parts.headers);
316-
317-
let expected_length = headers
318-
.0
319-
.get("Content-Length")
320-
.and_then(|val| val.to_str().ok())
321-
.and_then(|s| s.parse::<usize>().ok())
322-
.unwrap_or(MAX_CONTENT_LENGTH);
323-
324-
if expected_length > MAX_CONTENT_LENGTH {
325-
log::error!("Error: Content length exceeds max allowed");
326-
return Err(Implementation(ImplementationError::from(
327-
anyhow!("Content length too large: {expected_length}").into_boxed_dyn_error(),
328-
)));
329-
}
330-
331-
let body = read_limited_body(body.into_data_stream(), expected_length)
304+
let body = read_limited_body(&parts.headers, body.into_data_stream())
332305
.await
333306
.map_err(|e| Implementation(ImplementationError::from(e.into_boxed_dyn_error())))?;
334307

308+
let headers = Headers(&parts.headers);
335309
let query_string = parts.uri.query().unwrap_or("");
336310
let proposal = UncheckedProposal::from_request(&body, query_string, headers)?;
337311

@@ -407,11 +381,22 @@ impl App {
407381
}
408382
}
409383

410-
pub async fn read_limited_body<S, E>(mut stream: S, expected_len: usize) -> Result<Vec<u8>>
384+
pub async fn read_limited_body<S, E>(headers: &hyper::HeaderMap, mut stream: S) -> Result<Vec<u8>>
411385
where
412386
S: Stream<Item = Result<Bytes, E>> + Unpin,
413387
E: std::error::Error + Send + Sync + 'static,
414388
{
389+
let expected_len = headers
390+
.get("Content-Length")
391+
.and_then(|val| val.to_str().ok())
392+
.and_then(|s| s.parse::<usize>().ok())
393+
.unwrap_or(MAX_CONTENT_LENGTH);
394+
395+
if expected_len > MAX_CONTENT_LENGTH {
396+
log::error!("Header-defined Content-Length exceeds max allowed: {expected_len}");
397+
return Err(anyhow!("Header-defined Content-Length exceeds max allowed: {expected_len}"));
398+
}
399+
415400
let mut body = Vec::with_capacity(expected_len);
416401

417402
while let Some(chunk) = stream.next().await {

0 commit comments

Comments
 (0)