Skip to content

Commit c384ad5

Browse files
authored
Remove MAX_CONTENT_LENGTH, validate content-length with body length (payjoin#770)
This PR partially addresses issue payjoin#756 by removing the `MAX_CONTENT_LENGTH` check from the v1 receive path. Instead, the code now validates that the request body length matches the Content-Length header, returning a specific error if there is a mismatch. This change assumes the body is already allocated and within application limits, simplifying validation and improving error reporting. - Removes `MAX_CONTENT_LENGTH` check from `validate_body` - Adds a `ContentLengthMismatch` error variant - Updates test and error handling accordingly
2 parents fec74d7 + 788abfd commit c384ad5

File tree

2 files changed

+22
-18
lines changed

2 files changed

+22
-18
lines changed

payjoin/src/receive/v1/exclusive/error.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ pub(crate) enum InternalRequestError {
2424
InvalidContentType(String),
2525
/// The Content-Length header could not be parsed as a number
2626
InvalidContentLength(std::num::ParseIntError),
27-
/// The Content-Length value exceeds the maximum allowed size
28-
ContentLengthTooLarge(usize),
27+
/// The Content-Length value does not match the actual body length
28+
ContentLengthMismatch { expected: usize, actual: usize },
2929
}
3030

3131
impl From<InternalRequestError> for RequestError {
@@ -44,7 +44,7 @@ impl From<&RequestError> for JsonReply {
4444
MissingHeader(_)
4545
| InvalidContentType(_)
4646
| InvalidContentLength(_)
47-
| ContentLengthTooLarge(_) =>
47+
| ContentLengthMismatch { .. } =>
4848
JsonReply::new(crate::error_codes::ErrorCode::OriginalPsbtRejected, e),
4949
}
5050
}
@@ -57,8 +57,8 @@ impl fmt::Display for RequestError {
5757
InternalRequestError::InvalidContentType(content_type) =>
5858
write!(f, "Invalid content type: {content_type}"),
5959
InternalRequestError::InvalidContentLength(e) => write!(f, "{e}"),
60-
InternalRequestError::ContentLengthTooLarge(length) =>
61-
write!(f, "Content length too large: {length}."),
60+
InternalRequestError::ContentLengthMismatch { expected, actual } =>
61+
write!(f, "Content length mismatch: expected {expected}, got {actual}."),
6262
}
6363
}
6464
}
@@ -69,7 +69,7 @@ impl error::Error for RequestError {
6969
InternalRequestError::InvalidContentLength(e) => Some(e),
7070
InternalRequestError::MissingHeader(_) => None,
7171
InternalRequestError::InvalidContentType(_) => None,
72-
InternalRequestError::ContentLengthTooLarge(_) => None,
72+
InternalRequestError::ContentLengthMismatch { .. } => None,
7373
}
7474
}
7575
}

payjoin/src/receive/v1/exclusive/mod.rs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub use error::RequestError;
44

55
use super::*;
66
use crate::into_url::IntoUrl;
7-
use crate::{Version, MAX_CONTENT_LENGTH};
7+
use crate::Version;
88

99
const SUPPORTED_VERSIONS: &[Version] = &[Version::One];
1010

@@ -54,11 +54,15 @@ fn validate_body(headers: impl Headers, body: &[u8]) -> Result<&[u8], RequestErr
5454
.ok_or(InternalRequestError::MissingHeader("Content-Length"))?
5555
.parse::<usize>()
5656
.map_err(InternalRequestError::InvalidContentLength)?;
57-
if content_length > MAX_CONTENT_LENGTH {
58-
return Err(InternalRequestError::ContentLengthTooLarge(content_length).into());
57+
if body.len() != content_length {
58+
return Err(InternalRequestError::ContentLengthMismatch {
59+
expected: content_length,
60+
actual: body.len(),
61+
}
62+
.into());
5963
}
6064

61-
Ok(&body[..content_length])
65+
Ok(body)
6266
}
6367

6468
#[cfg(test)]
@@ -89,21 +93,21 @@ mod tests {
8993

9094
#[test]
9195
fn test_parse_body() {
92-
let mut padded_body = ORIGINAL_PSBT.as_bytes().to_vec();
93-
assert_eq!(MAX_CONTENT_LENGTH, 5333333_usize);
94-
padded_body.resize(MAX_CONTENT_LENGTH + 1, 0);
95-
let headers = MockHeaders::new(padded_body.len() as u64);
96+
let body = ORIGINAL_PSBT.as_bytes().to_vec();
97+
let headers = MockHeaders::new((body.len() + 1) as u64);
9698

97-
let validated_request = validate_body(headers.clone(), padded_body.as_slice());
99+
let validated_request = validate_body(headers.clone(), body.as_slice());
98100
assert!(validated_request.is_err());
101+
99102
match validated_request {
100103
Ok(_) => panic!("Expected error, got success"),
101104
Err(error) => {
102105
assert_eq!(
103106
error.to_string(),
104-
RequestError::from(InternalRequestError::ContentLengthTooLarge(
105-
padded_body.len()
106-
))
107+
RequestError::from(InternalRequestError::ContentLengthMismatch {
108+
expected: body.len() + 1,
109+
actual: body.len(),
110+
})
107111
.to_string()
108112
);
109113
}

0 commit comments

Comments
 (0)