mirror of https://github.com/fafhrd91/actix-web
fix: change ContentLength internal type from usize to u64
This fixes the test failure on 32-bit platforms where the large value test (u64::MAX) would fail because `usize` cannot hold values larger than 4GB on 32-bit systems. According to RFC 9110, Content-Length can be any valid unsigned 64-bit integer, and it's reasonable to have content larger than 4GB even on 32-bit systems (e.g., streaming large files). Changes: - Change ContentLength inner type from usize to u64 - Update into_inner() return type to u64 - Update FromStr to use u64 parsing - Add From<u64> implementation - Update From<usize> to convert to u64 - Add PartialEq/PartialOrd implementations for u64 - Update usize comparisons to properly convert - Fix test to use u64 literal suffix - Update json.rs to convert u64 to usize with try_from Fixes #3812 Co-Authored-By: Claude (claude-opus-4-5) <noreply@anthropic.com>
This commit is contained in:
parent
6efc4bdfb5
commit
15ea560863
|
|
@ -39,17 +39,17 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// [RFC 9110 §8.6]: https://www.rfc-editor.org/rfc/rfc9110#name-content-length
|
/// [RFC 9110 §8.6]: https://www.rfc-editor.org/rfc/rfc9110#name-content-length
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut)]
|
||||||
pub struct ContentLength(pub usize);
|
pub struct ContentLength(pub u64);
|
||||||
|
|
||||||
impl ContentLength {
|
impl ContentLength {
|
||||||
/// Returns Content-Length value.
|
/// Returns Content-Length value.
|
||||||
pub fn into_inner(&self) -> usize {
|
pub fn into_inner(&self) -> u64 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl str::FromStr for ContentLength {
|
impl str::FromStr for ContentLength {
|
||||||
type Err = <usize as str::FromStr>::Err;
|
type Err = <u64 as str::FromStr>::Err;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_str(val: &str) -> Result<Self, Self::Err> {
|
fn from_str(val: &str) -> Result<Self, Self::Err> {
|
||||||
|
|
@ -85,39 +85,69 @@ impl Header for ContentLength {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ContentLength> for usize {
|
impl From<ContentLength> for u64 {
|
||||||
fn from(ContentLength(len): ContentLength) -> Self {
|
fn from(ContentLength(len): ContentLength) -> Self {
|
||||||
len
|
len
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<usize> for ContentLength {
|
impl From<u64> for ContentLength {
|
||||||
fn from(len: usize) -> Self {
|
fn from(len: u64) -> Self {
|
||||||
ContentLength(len)
|
ContentLength(len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<usize> for ContentLength {
|
impl From<usize> for ContentLength {
|
||||||
fn eq(&self, other: &usize) -> bool {
|
fn from(len: usize) -> Self {
|
||||||
|
ContentLength(len as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<u64> for ContentLength {
|
||||||
|
fn eq(&self, other: &u64) -> bool {
|
||||||
self.0 == *other
|
self.0 == *other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<ContentLength> for usize {
|
impl PartialEq<ContentLength> for u64 {
|
||||||
fn eq(&self, other: &ContentLength) -> bool {
|
fn eq(&self, other: &ContentLength) -> bool {
|
||||||
*self == other.0
|
*self == other.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialOrd<u64> for ContentLength {
|
||||||
|
fn partial_cmp(&self, other: &u64) -> Option<std::cmp::Ordering> {
|
||||||
|
self.0.partial_cmp(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd<ContentLength> for u64 {
|
||||||
|
fn partial_cmp(&self, other: &ContentLength) -> Option<std::cmp::Ordering> {
|
||||||
|
self.partial_cmp(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<usize> for ContentLength {
|
||||||
|
fn eq(&self, other: &usize) -> bool {
|
||||||
|
self.0 == *other as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<ContentLength> for usize {
|
||||||
|
fn eq(&self, other: &ContentLength) -> bool {
|
||||||
|
(*self as u64) == other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialOrd<usize> for ContentLength {
|
impl PartialOrd<usize> for ContentLength {
|
||||||
fn partial_cmp(&self, other: &usize) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &usize) -> Option<std::cmp::Ordering> {
|
||||||
self.0.partial_cmp(other)
|
self.0.partial_cmp(&(*other as u64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd<ContentLength> for usize {
|
impl PartialOrd<ContentLength> for usize {
|
||||||
fn partial_cmp(&self, other: &ContentLength) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &ContentLength) -> Option<std::cmp::Ordering> {
|
||||||
self.partial_cmp(&other.0)
|
(*self as u64).partial_cmp(&other.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,10 +245,10 @@ mod tests {
|
||||||
assert_parse_eq::<ContentLength, _, _>(["0 "], ContentLength(0));
|
assert_parse_eq::<ContentLength, _, _>(["0 "], ContentLength(0));
|
||||||
assert_parse_eq::<ContentLength, _, _>([" 0 "], ContentLength(0));
|
assert_parse_eq::<ContentLength, _, _>([" 0 "], ContentLength(0));
|
||||||
|
|
||||||
// large value (2^64 - 1)
|
// large value (2^64 - 1), now works on 32-bit platforms too
|
||||||
assert_parse_eq::<ContentLength, _, _>(
|
assert_parse_eq::<ContentLength, _, _>(
|
||||||
["18446744073709551615"],
|
["18446744073709551615"],
|
||||||
ContentLength(18_446_744_073_709_551_615),
|
ContentLength(18_446_744_073_709_551_615_u64),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -347,7 +347,9 @@ impl<T: DeserializeOwned> JsonBody<T> {
|
||||||
return JsonBody::Error(Some(JsonPayloadError::ContentType));
|
return JsonBody::Error(Some(JsonPayloadError::ContentType));
|
||||||
}
|
}
|
||||||
|
|
||||||
let length = ContentLength::parse(req).ok().map(|x| x.0);
|
let length = ContentLength::parse(req)
|
||||||
|
.ok()
|
||||||
|
.and_then(|x| usize::try_from(x.0).ok());
|
||||||
|
|
||||||
// Notice the content-length is not checked against limit of json config here.
|
// Notice the content-length is not checked against limit of json config here.
|
||||||
// As the internal usage always call JsonBody::limit after JsonBody::new.
|
// As the internal usage always call JsonBody::limit after JsonBody::new.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue