Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: hyperium/http
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.2.0
Choose a base ref
...
head repository: hyperium/http
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.3.0
Choose a head ref
  • 7 commits
  • 10 files changed
  • 7 contributors

Commits on Dec 20, 2024

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    091ee9a View commit details

Commits on Dec 27, 2024

  1. refactor(header): remove BytesMut inline optimization when creating (#…

    …738)
    
    `HeaderValue` from integers
    
    `::bytes::BytesMut >= 1` has no inline optimization
    ADD-SP authored Dec 27, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    4e02046 View commit details

Commits on Jan 10, 2025

  1. fix: HeaderMap::reserve allocates insufficient capacity (#741)

    This bug caused additional allocation when attempted to insert
    the requested number of entries.
    This commit fix that by converting capacity to raw capacity before
    allocation.
    kawaemon authored Jan 10, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    68845bd View commit details

Commits on Jan 27, 2025

  1. chore(ci): use yq to get rust-version in manifest (#746)

    tottoto authored Jan 27, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    a463fb5 View commit details

Commits on Mar 3, 2025

  1. chore: use range.contains in StatusCode methods (#748)

    Small change for readability, alongside some minor documentation
    touchups for consistency.
    DaniPopes authored Mar 3, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    b03ed6a View commit details
  2. docs: Fixed encryption/compression typo for 'accept-encoding: identit…

    …y'. (#695)
    jpds authored Mar 3, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    64bd92b View commit details

Commits on Mar 11, 2025

  1. v1.3.0

    seanmonstar committed Mar 11, 2025
    Copy the full SHA
    d0dd91e View commit details
Showing with 64 additions and 45 deletions.
  1. +1 −3 .github/workflows/ci.yml
  2. +5 −0 CHANGELOG.md
  3. +1 −1 Cargo.toml
  4. +9 −7 src/header/map.rs
  5. +1 −1 src/header/name.rs
  6. +2 −22 src/header/value.rs
  7. +8 −8 src/status.rs
  8. +12 −2 src/uri/path.rs
  9. +24 −0 tests/header_map.rs
  10. +1 −1 util/src/main.rs
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -78,9 +78,7 @@ jobs:

- name: Get MSRV from package metadata
id: metadata
run: |
cargo metadata --no-deps --format-version 1 |
jq -r '"msrv=" + (.packages[] | select(.name == "http")).rust_version' >> $GITHUB_OUTPUT
run: echo "msrv=$(yq '.package.rust-version' Cargo.toml)" >> $GITHUB_OUTPUT

- name: Install Rust (${{ steps.metadata.outputs.msrv }})
uses: dtolnay/rust-toolchain@master
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 1.3.0 (March 11, 2025)

* Allow most UTF-8 characters in URI path and query.
* Fix `HeaderMap::reserve()` to allocate sufficient capacity.

# 1.2.0 (December 3, 2024)

* Add `StatusCode::TOO_EARLY` constant for 425 status.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ name = "http"
# - Update html_root_url in lib.rs.
# - Update CHANGELOG.md.
# - Create git tag
version = "1.2.0"
version = "1.3.0"
readme = "README.md"
documentation = "https://docs.rs/http"
repository = "https://github.com/hyperium/http"
16 changes: 9 additions & 7 deletions src/header/map.rs
Original file line number Diff line number Diff line change
@@ -707,20 +707,22 @@ impl<T> HeaderMap<T> {
.checked_add(additional)
.ok_or_else(MaxSizeReached::new)?;

if cap > self.indices.len() {
let cap = cap
let raw_cap = to_raw_capacity(cap);

if raw_cap > self.indices.len() {
let raw_cap = raw_cap
.checked_next_power_of_two()
.ok_or_else(MaxSizeReached::new)?;
if cap > MAX_SIZE {
if raw_cap > MAX_SIZE {
return Err(MaxSizeReached::new());
}

if self.entries.is_empty() {
self.mask = cap as Size - 1;
self.indices = vec![Pos::none(); cap].into_boxed_slice();
self.entries = Vec::with_capacity(usable_capacity(cap));
self.mask = raw_cap as Size - 1;
self.indices = vec![Pos::none(); raw_cap].into_boxed_slice();
self.entries = Vec::with_capacity(usable_capacity(raw_cap));
} else {
self.try_grow(cap)?;
self.try_grow(raw_cap)?;
}
}

2 changes: 1 addition & 1 deletion src/header/name.rs
Original file line number Diff line number Diff line change
@@ -203,7 +203,7 @@ standard_headers! {
/// not to compress if a server use more than 80 % of its computational
/// power.
///
/// As long as the identity value, meaning no encryption, is not explicitly
/// As long as the identity value, meaning no compression, is not explicitly
/// forbidden, by an identity;q=0 or a *;q=0 without another explicitly set
/// value for identity, the server must never send back a 406 Not Acceptable
/// error.
24 changes: 2 additions & 22 deletions src/header/value.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use std::error::Error;
use std::fmt::Write;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use std::{cmp, fmt, mem, str};
use std::{cmp, fmt, str};

use crate::header::name::HeaderName;

@@ -424,27 +424,7 @@ macro_rules! from_integers {
($($name:ident: $t:ident => $max_len:expr),*) => {$(
impl From<$t> for HeaderValue {
fn from(num: $t) -> HeaderValue {
let mut buf = if mem::size_of::<BytesMut>() - 1 < $max_len {
// On 32bit platforms, BytesMut max inline size
// is 15 bytes, but the $max_len could be bigger.
//
// The likelihood of the number *actually* being
// that big is very small, so only allocate
// if the number needs that space.
//
// The largest decimal number in 15 digits:
// It wold be 10.pow(15) - 1, but this is a constant
// version.
if num as u64 > 999_999_999_999_999_999 {
BytesMut::with_capacity($max_len)
} else {
// fits inline...
BytesMut::new()
}
} else {
// full value fits inline, so don't allocate!
BytesMut::new()
};
let mut buf = BytesMut::with_capacity($max_len);
let _ = buf.write_str(::itoa::Buffer::new().format(num));
HeaderValue {
inner: buf.freeze(),
16 changes: 8 additions & 8 deletions src/status.rs
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ use std::str::FromStr;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StatusCode(NonZeroU16);

/// A possible error value when converting a `StatusCode` from a `u16` or `&str`
/// A possible error value when converting a `StatusCode` from a `u16` or `&str`.
///
/// This error indicates that the supplied input was not a valid number, was less
/// than 100, or was greater than 999.
@@ -80,7 +80,7 @@ impl StatusCode {
.ok_or_else(InvalidStatusCode::new)
}

/// Converts a &[u8] to a status code
/// Converts a `&[u8]` to a status code.
pub fn from_bytes(src: &[u8]) -> Result<StatusCode, InvalidStatusCode> {
if src.len() != 3 {
return Err(InvalidStatusCode::new());
@@ -117,7 +117,7 @@ impl StatusCode {
/// ```
#[inline]
pub const fn as_u16(&self) -> u16 {
(*self).0.get()
self.0.get()
}

/// Returns a &str representation of the `StatusCode`
@@ -175,31 +175,31 @@ impl StatusCode {
/// Check if status is within 100-199.
#[inline]
pub fn is_informational(&self) -> bool {
200 > self.0.get() && self.0.get() >= 100
(100..200).contains(&self.0.get())
}

/// Check if status is within 200-299.
#[inline]
pub fn is_success(&self) -> bool {
300 > self.0.get() && self.0.get() >= 200
(200..300).contains(&self.0.get())
}

/// Check if status is within 300-399.
#[inline]
pub fn is_redirection(&self) -> bool {
400 > self.0.get() && self.0.get() >= 300
(300..400).contains(&self.0.get())
}

/// Check if status is within 400-499.
#[inline]
pub fn is_client_error(&self) -> bool {
500 > self.0.get() && self.0.get() >= 400
(400..500).contains(&self.0.get())
}

/// Check if status is within 500-599.
#[inline]
pub fn is_server_error(&self) -> bool {
600 > self.0.get() && self.0.get() >= 500
(500..600).contains(&self.0.get())
}
}

14 changes: 12 additions & 2 deletions src/uri/path.rs
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ impl PathAndQuery {
0x40..=0x5F |
0x61..=0x7A |
0x7C |
0x7E => {}
0x7E..=0xFF => {}

// These are code points that are supposed to be
// percent-encoded in the path but there are clients
@@ -82,7 +82,7 @@ impl PathAndQuery {
0x21 |
0x24..=0x3B |
0x3D |
0x3F..=0x7E => {}
0x3F..=0xFF => {}

b'#' => {
fragment = Some(i);
@@ -556,6 +556,16 @@ mod tests {
assert_eq!("qr=%3", pq("/a/b?qr=%3").query().unwrap());
}

#[test]
fn allow_utf8_in_path() {
assert_eq!("/🍕", pq("/🍕").path());
}

#[test]
fn allow_utf8_in_query() {
assert_eq!(Some("pizza=🍕"), pq("/test?pizza=🍕").query());
}

#[test]
fn json_is_fine() {
assert_eq!(
24 changes: 24 additions & 0 deletions tests/header_map.rs
Original file line number Diff line number Diff line change
@@ -63,6 +63,30 @@ fn reserve_overflow() {
headers.reserve(std::usize::MAX); // next_power_of_two overflows
}

#[test]
fn reserve() {
let mut headers = HeaderMap::<usize>::default();
assert_eq!(headers.capacity(), 0);

let requested_cap = 8;
headers.reserve(requested_cap);

let reserved_cap = headers.capacity();
assert!(
reserved_cap >= requested_cap,
"requested {} capacity, but it reserved only {} entries",
requested_cap,
reserved_cap,
);

for i in 0..requested_cap {
let name = format!("h{i}").parse::<HeaderName>().unwrap();
headers.insert(name, i);
}

assert_eq!(headers.capacity(), reserved_cap, "unexpected reallocation");
}

#[test]
fn drain() {
let mut headers = HeaderMap::new();
2 changes: 1 addition & 1 deletion util/src/main.rs
Original file line number Diff line number Diff line change
@@ -68,7 +68,7 @@ standard_headers! {
/// not to compress if a server use more than 80 % of its computational
/// power.
///
/// As long as the identity value, meaning no encryption, is not explicitly
/// As long as the identity value, meaning no compression, is not explicitly
/// forbidden, by an identity;q=0 or a *;q=0 without another explicitly set
/// value for identity, the server must never send back a 406 Not Acceptable
/// error.