From 5f2a89d00bd9a34fd6e661bc597d69d94d8cf93e Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Sun, 1 Dec 2024 10:58:56 -0500 Subject: [PATCH 1/5] remove std --- Cargo.toml | 2 +- benches/src/header_map/basic.rs | 2 +- src/byte_str.rs | 2 -- src/error.rs | 4 ---- src/extensions.rs | 5 ----- src/header/map.rs | 8 -------- src/header/name.rs | 8 -------- src/header/value.rs | 7 ------- src/lib.rs | 7 ++++--- src/method.rs | 6 ------ src/request.rs | 4 ---- src/response.rs | 4 ---- src/status.rs | 6 ------ src/uri/authority.rs | 5 ----- src/uri/builder.rs | 2 -- src/uri/mod.rs | 6 ------ src/uri/path.rs | 4 ---- src/uri/port.rs | 2 -- src/uri/scheme.rs | 5 ----- src/uri/tests.rs | 2 -- src/version.rs | 2 -- tests/header_map_fuzz.rs | 2 -- 22 files changed, 6 insertions(+), 89 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 487507f0..826f39a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ exclude = [ ] [features] -default = ["std"] +default = [] std = [] [dependencies] diff --git a/benches/src/header_map/basic.rs b/benches/src/header_map/basic.rs index 8c198a02..ccd8ee9f 100644 --- a/benches/src/header_map/basic.rs +++ b/benches/src/header_map/basic.rs @@ -6,7 +6,7 @@ macro_rules! bench { use fnv::FnvHasher; use http::header::*; use seahash::SeaHasher; - use std::hash::BuildHasherDefault; + #[allow(unused_imports)] use test::{self, Bencher}; diff --git a/src/byte_str.rs b/src/byte_str.rs index 90872ecb..406285f6 100644 --- a/src/byte_str.rs +++ b/src/byte_str.rs @@ -1,7 +1,5 @@ use bytes::Bytes; -use std::{ops, str}; - #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub(crate) struct ByteStr { // Invariant: bytes contains valid UTF-8 diff --git a/src/error.rs b/src/error.rs index 762ee1c2..69b8d01e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,7 +1,3 @@ -use std::error; -use std::fmt; -use std::result; - use crate::header; use crate::header::MaxSizeReached; use crate::method; diff --git a/src/extensions.rs b/src/extensions.rs index c41bbfc3..df196fab 100644 --- a/src/extensions.rs +++ b/src/extensions.rs @@ -1,8 +1,3 @@ -use std::any::{Any, TypeId}; -use std::collections::HashMap; -use std::fmt; -use std::hash::{BuildHasherDefault, Hasher}; - type AnyMap = HashMap, BuildHasherDefault>; // With TypeIds as keys, there's no need to hash them. They are already hashes diff --git a/src/header/map.rs b/src/header/map.rs index 7610175b..6b5ea52e 100644 --- a/src/header/map.rs +++ b/src/header/map.rs @@ -1,11 +1,3 @@ -use std::collections::hash_map::RandomState; -use std::collections::HashMap; -use std::convert::TryFrom; -use std::hash::{BuildHasher, Hash, Hasher}; -use std::iter::{FromIterator, FusedIterator}; -use std::marker::PhantomData; -use std::{fmt, mem, ops, ptr, vec}; - use crate::Error; use super::name::{HdrName, HeaderName, InvalidHeaderName}; diff --git a/src/header/name.rs b/src/header/name.rs index 3d563f4e..25635678 100644 --- a/src/header/name.rs +++ b/src/header/name.rs @@ -1,14 +1,6 @@ use crate::byte_str::ByteStr; use bytes::{Bytes, BytesMut}; -use std::borrow::Borrow; -use std::convert::TryFrom; -use std::error::Error; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::mem::MaybeUninit; -use std::str::FromStr; - /// Represents an HTTP header field name /// /// Header field names identify the header. Header sets may include multiple diff --git a/src/header/value.rs b/src/header/value.rs index 4813f6fd..7c1b4151 100644 --- a/src/header/value.rs +++ b/src/header/value.rs @@ -1,12 +1,5 @@ use bytes::{Bytes, BytesMut}; -use std::convert::TryFrom; -use std::error::Error; -use std::fmt::Write; -use std::hash::{Hash, Hasher}; -use std::str::FromStr; -use std::{cmp, fmt, mem, str}; - use crate::header::name::HeaderName; /// Represents an HTTP header field value. diff --git a/src/lib.rs b/src/lib.rs index 0ab5bdfd..1cce5c8c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,9 +155,10 @@ #![deny(warnings, missing_docs, missing_debug_implementations)] -//#![cfg_attr(not(feature = "std"), no_std)] -#[cfg(not(feature = "std"))] -compile_error!("`std` feature currently required, support for `no_std` may be added later"); +#![cfg_attr(not(feature = "std"), no_std)] + +#![cfg(not(feature = "std"))] +extern crate alloc; #[cfg(test)] #[macro_use] diff --git a/src/method.rs b/src/method.rs index 3d45ef9f..240ba063 100644 --- a/src/method.rs +++ b/src/method.rs @@ -18,11 +18,6 @@ use self::extension::{AllocatedExtension, InlineExtension}; use self::Inner::*; -use std::convert::TryFrom; -use std::error::Error; -use std::str::FromStr; -use std::{fmt, str}; - /// The Request Method (VERB) /// /// This type also contains constants for a number of common HTTP methods such @@ -306,7 +301,6 @@ impl Error for InvalidMethod {} mod extension { use super::InvalidMethod; - use std::str; #[derive(Clone, PartialEq, Eq, Hash)] // Invariant: the first self.1 bytes of self.0 are valid UTF-8. diff --git a/src/request.rs b/src/request.rs index 324b676c..40a796bc 100644 --- a/src/request.rs +++ b/src/request.rs @@ -52,10 +52,6 @@ //! } //! ``` -use std::any::Any; -use std::convert::TryInto; -use std::fmt; - use crate::header::{HeaderMap, HeaderName, HeaderValue}; use crate::method::Method; use crate::version::Version; diff --git a/src/response.rs b/src/response.rs index ab9e49bc..0c328d8d 100644 --- a/src/response.rs +++ b/src/response.rs @@ -61,10 +61,6 @@ //! // ... //! ``` -use std::any::Any; -use std::convert::TryInto; -use std::fmt; - use crate::header::{HeaderMap, HeaderName, HeaderValue}; use crate::status::StatusCode; use crate::version::Version; diff --git a/src/status.rs b/src/status.rs index 16896e4a..bbc18d0e 100644 --- a/src/status.rs +++ b/src/status.rs @@ -14,12 +14,6 @@ //! assert!(StatusCode::OK.is_success()); //! ``` -use std::convert::TryFrom; -use std::error::Error; -use std::fmt; -use std::num::NonZeroU16; -use std::str::FromStr; - /// An HTTP status code (`status-code` in RFC 9110 et al.). /// /// Constants are provided for known status codes, including those in the IANA diff --git a/src/uri/authority.rs b/src/uri/authority.rs index 07aa6795..1bd5eacb 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -1,8 +1,3 @@ -use std::convert::TryFrom; -use std::hash::{Hash, Hasher}; -use std::str::FromStr; -use std::{cmp, fmt, str}; - use bytes::Bytes; use super::{ErrorKind, InvalidUri, Port, URI_CHARS}; diff --git a/src/uri/builder.rs b/src/uri/builder.rs index d5f7f49b..35685c7a 100644 --- a/src/uri/builder.rs +++ b/src/uri/builder.rs @@ -1,5 +1,3 @@ -use std::convert::TryInto; - use super::{Authority, Parts, PathAndQuery, Scheme}; use crate::Uri; diff --git a/src/uri/mod.rs b/src/uri/mod.rs index 767f0743..e11980a0 100644 --- a/src/uri/mod.rs +++ b/src/uri/mod.rs @@ -23,15 +23,9 @@ //! ``` use crate::byte_str::ByteStr; -use std::convert::TryFrom; use bytes::Bytes; -use std::error::Error; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::str::{self, FromStr}; - use self::scheme::Scheme2; pub use self::authority::Authority; diff --git a/src/uri/path.rs b/src/uri/path.rs index 6a2f1e1e..806148fe 100644 --- a/src/uri/path.rs +++ b/src/uri/path.rs @@ -1,7 +1,3 @@ -use std::convert::TryFrom; -use std::str::FromStr; -use std::{cmp, fmt, hash, str}; - use bytes::Bytes; use super::{ErrorKind, InvalidUri}; diff --git a/src/uri/port.rs b/src/uri/port.rs index 8f5c5f3f..62a82fd8 100644 --- a/src/uri/port.rs +++ b/src/uri/port.rs @@ -1,5 +1,3 @@ -use std::fmt; - use super::{ErrorKind, InvalidUri}; /// The port component of a URI. diff --git a/src/uri/scheme.rs b/src/uri/scheme.rs index dbcc8c3f..9603875a 100644 --- a/src/uri/scheme.rs +++ b/src/uri/scheme.rs @@ -1,8 +1,3 @@ -use std::convert::TryFrom; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::str::FromStr; - use bytes::Bytes; use super::{ErrorKind, InvalidUri}; diff --git a/src/uri/tests.rs b/src/uri/tests.rs index 719cb94e..a9331efb 100644 --- a/src/uri/tests.rs +++ b/src/uri/tests.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use super::{ErrorKind, InvalidUri, Port, Uri, URI_CHARS}; #[test] diff --git a/src/version.rs b/src/version.rs index d8b71306..cf66bca5 100644 --- a/src/version.rs +++ b/src/version.rs @@ -19,8 +19,6 @@ //! println!("{:?}", http2); //! ``` -use std::fmt; - /// Represents a version of the HTTP spec. #[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)] pub struct Version(Http); diff --git a/tests/header_map_fuzz.rs b/tests/header_map_fuzz.rs index 40db0494..926fa8a5 100644 --- a/tests/header_map_fuzz.rs +++ b/tests/header_map_fuzz.rs @@ -6,8 +6,6 @@ use rand::rngs::StdRng; use rand::seq::SliceRandom; use rand::{Rng, SeedableRng}; -use std::collections::HashMap; - #[cfg(not(miri))] #[test] fn header_map_fuzz() { From 3dcd1e837a9c5f7e290e91846abf757dbc12771b Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Sun, 1 Dec 2024 11:18:39 -0500 Subject: [PATCH 2/5] fix usings --- Cargo.toml | 1 + src/byte_str.rs | 3 +++ src/convert.rs | 4 ++-- src/error.rs | 9 +++++++-- src/extensions.rs | 5 +++++ src/header/map.rs | 22 ++++++++++++++++++---- src/header/name.rs | 21 ++++++++++++++------- src/header/value.rs | 24 +++++++++++++++++------- src/method.rs | 11 +++++++++-- src/request.rs | 4 ++++ src/response.rs | 4 ++++ src/status.rs | 5 ++++- src/uri/authority.rs | 8 ++++++++ src/uri/builder.rs | 10 ++++++---- src/uri/mod.rs | 14 ++++++++++++-- src/uri/path.rs | 9 ++++++--- src/uri/port.rs | 4 ++++ src/uri/scheme.rs | 6 +++++- src/uri/tests.rs | 16 +++++++++------- src/version.rs | 2 ++ 20 files changed, 140 insertions(+), 42 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 826f39a8..af8928d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ std = [] [dependencies] bytes = "1" fnv = "1.0.5" +hashbrown = "0.12.0" itoa = "1" [dev-dependencies] diff --git a/src/byte_str.rs b/src/byte_str.rs index 406285f6..f2c64de2 100644 --- a/src/byte_str.rs +++ b/src/byte_str.rs @@ -1,3 +1,6 @@ +use core::ops; + +use alloc::string::String; use bytes::Bytes; #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] diff --git a/src/convert.rs b/src/convert.rs index 682e0ed5..633c0568 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -1,11 +1,11 @@ macro_rules! if_downcast_into { ($in_ty:ty, $out_ty:ty, $val:ident, $body:expr) => {{ - if std::any::TypeId::of::<$in_ty>() == std::any::TypeId::of::<$out_ty>() { + if core::any::TypeId::of::<$in_ty>() == core::any::TypeId::of::<$out_ty>() { // Store the value in an `Option` so we can `take` // it after casting to `&mut dyn Any`. let mut slot = Some($val); // Re-write the `$val` ident with the downcasted value. - let $val = (&mut slot as &mut dyn std::any::Any) + let $val = (&mut slot as &mut dyn core::any::Any) .downcast_mut::>() .unwrap() .take() diff --git a/src/error.rs b/src/error.rs index 69b8d01e..c75cad1b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,8 @@ +use core::convert; +use core::error; +use core::fmt; +use core::result; + use crate::header; use crate::header::MaxSizeReached; use crate::method; @@ -128,8 +133,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: std::convert::Infallible) -> Error { +impl From for Error { + fn from(err: convert::Infallible) -> Error { match err {} } } diff --git a/src/extensions.rs b/src/extensions.rs index df196fab..0ba79c81 100644 --- a/src/extensions.rs +++ b/src/extensions.rs @@ -1,3 +1,8 @@ +use core::{any::{Any, TypeId}, fmt, hash::{BuildHasherDefault, Hasher}}; + +use alloc::boxed::Box; +use hashbrown::HashMap; + type AnyMap = HashMap, BuildHasherDefault>; // With TypeIds as keys, there's no need to hash them. They are already hashes diff --git a/src/header/map.rs b/src/header/map.rs index 6b5ea52e..26db61ee 100644 --- a/src/header/map.rs +++ b/src/header/map.rs @@ -1,3 +1,14 @@ +use core::convert::TryFrom; +use core::iter::{FromIterator, FusedIterator}; +use core::marker::PhantomData; +use core::{fmt, mem, ops, ptr, slice}; +use core::hash::Hash; + +use alloc::boxed::Box; +use alloc::vec; +use alloc::vec::Vec; +use hashbrown::HashMap; + use crate::Error; use super::name::{HdrName, HeaderName, InvalidHeaderName}; @@ -108,7 +119,7 @@ pub struct IntoIter { /// associated value. #[derive(Debug)] pub struct Keys<'a, T> { - inner: ::std::slice::Iter<'a, Bucket>, + inner: slice::Iter<'a, Bucket>, } /// `HeaderMap` value iterator. @@ -201,7 +212,7 @@ pub struct ValueIterMut<'a, T> { #[derive(Debug)] pub struct ValueDrain<'a, T> { first: Option, - next: Option<::std::vec::IntoIter>, + next: Option>, lt: PhantomData<&'a mut HeaderMap>, } @@ -308,7 +319,7 @@ enum Link { enum Danger { Green, Yellow, - Red(RandomState), + Red(RandomState), // TODO: no_std? } // Constants related to detecting DOS attacks. @@ -512,7 +523,7 @@ impl HeaderMap { Ok(HeaderMap { mask: (raw_cap - 1) as Size, - indices: vec![Pos::none(); raw_cap].into_boxed_slice(), + indices: alloc::vec![Pos::none(); raw_cap].into_boxed_slice(), entries: Vec::with_capacity(raw_cap), extra_values: Vec::new(), danger: Danger::Green, @@ -3564,6 +3575,7 @@ impl fmt::Display for MaxSizeReached { } } +#[cfg(feature = "std")] impl std::error::Error for MaxSizeReached {} // ===== impl Utils ===== @@ -3725,6 +3737,8 @@ mod into_header_name { } mod as_header_name { + use alloc::string::String; + use super::{Entry, HdrName, HeaderMap, HeaderName, InvalidHeaderName, MaxSizeReached}; /// A marker trait used to identify values that can be used as search keys diff --git a/src/header/name.rs b/src/header/name.rs index 25635678..08ab0ab9 100644 --- a/src/header/name.rs +++ b/src/header/name.rs @@ -1,4 +1,8 @@ +use core::{borrow::Borrow, convert::TryFrom, fmt, mem::MaybeUninit, str::FromStr}; +use core::hash::{Hash, Hasher}; + use crate::byte_str::ByteStr; +use alloc::{string::String, vec::Vec}; use bytes::{Bytes, BytesMut}; /// Represents an HTTP header field name @@ -81,7 +85,7 @@ macro_rules! standard_headers { match *self { // Safety: test_parse_standard_headers ensures these &[u8]s are &str-safe. $( - StandardHeader::$konst => unsafe { std::str::from_utf8_unchecked( $name_bytes ) }, + StandardHeader::$konst => unsafe { str::from_utf8_unchecked( $name_bytes ) }, )+ } } @@ -110,7 +114,7 @@ macro_rules! standard_headers { assert_eq!(HeaderName::from_bytes(name_bytes).unwrap(), HeaderName::from(std)); // Test upper case - let upper = std::str::from_utf8(name_bytes).expect("byte string constants are all utf-8").to_uppercase(); + let upper = str::from_utf8(name_bytes).expect("byte string constants are all utf-8").to_uppercase(); assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(), HeaderName::from(std)); } } @@ -118,7 +122,7 @@ macro_rules! standard_headers { #[test] fn test_standard_headers_into_bytes() { for &(std, name_bytes) in TEST_HEADERS { - let name = std::str::from_utf8(name_bytes).unwrap(); + let name = str::from_utf8(name_bytes).unwrap(); let std = HeaderName::from(std); // Test lower case let bytes: Bytes = @@ -1508,7 +1512,8 @@ impl fmt::Display for InvalidHeaderName { } } -impl Error for InvalidHeaderName {} +#[cfg(feature = "std")] +impl std::error::Error for InvalidHeaderName {} // ===== HdrName ===== @@ -1660,11 +1665,13 @@ fn uninit_u8_array() -> [MaybeUninit; SCRATCH_BUF_SIZE] { // Safety: All elements of `slice` must be initialized to prevent // undefined behavior. unsafe fn slice_assume_init(slice: &[MaybeUninit]) -> &[T] { - &*(slice as *const [MaybeUninit] as *const [T]) + unsafe { &*(slice as *const [MaybeUninit] as *const [T]) } } #[cfg(test)] mod tests { + use alloc::vec; + use self::StandardHeader::Vary; use super::*; @@ -1697,7 +1704,7 @@ mod tests { let long = &ONE_TOO_LONG[0..super::super::MAX_HEADER_NAME_LEN]; - let long_str = std::str::from_utf8(long).unwrap(); + let long_str = str::from_utf8(long).unwrap(); assert_eq!(HeaderName::from_static(long_str), long_str); // shouldn't panic! assert!( @@ -1714,7 +1721,7 @@ mod tests { #[should_panic] fn test_static_invalid_name_lengths() { // Safety: ONE_TOO_LONG contains only the UTF-8 safe, single-byte codepoint b'a'. - let _ = HeaderName::from_static(unsafe { std::str::from_utf8_unchecked(ONE_TOO_LONG) }); + let _ = HeaderName::from_static(unsafe { str::from_utf8_unchecked(ONE_TOO_LONG) }); } #[test] diff --git a/src/header/value.rs b/src/header/value.rs index 7c1b4151..b697dc11 100644 --- a/src/header/value.rs +++ b/src/header/value.rs @@ -1,3 +1,11 @@ +use core::convert::TryFrom; +use core::{cmp, fmt}; +use core::hash::{Hash, Hasher}; +use core::mem; +use core::str::FromStr; + +use alloc::string::String; +use alloc::vec::Vec; use bytes::{Bytes, BytesMut}; use crate::header::name::HeaderName; @@ -227,7 +235,7 @@ impl HeaderValue { } fn from_shared(src: Bytes) -> Result { - HeaderValue::try_from_generic(src, std::convert::identity) + HeaderValue::try_from_generic(src, core::convert::identity) } fn try_from_generic, F: FnOnce(T) -> Bytes>( @@ -452,7 +460,7 @@ macro_rules! from_integers { let val = HeaderValue::from(n); assert_eq!(val, &n.to_string()); - let n = ::std::$t::MAX; + let n = ::core::primitive::$t::MAX; let val = HeaderValue::from(n); assert_eq!(val, &n.to_string()); } @@ -613,7 +621,8 @@ impl fmt::Display for InvalidHeaderValue { } } -impl Error for InvalidHeaderValue {} +#[cfg(feature = "std")] +impl std::error::Error for InvalidHeaderValue {} impl fmt::Display for ToStrError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -621,7 +630,8 @@ impl fmt::Display for ToStrError { } } -impl Error for ToStrError {} +#[cfg(feature = "std")] +impl std::error::Error for ToStrError {} // ===== PartialEq / PartialOrd ===== @@ -788,7 +798,7 @@ impl<'a> PartialOrd for &'a str { #[test] fn test_try_from() { - HeaderValue::try_from(vec![127]).unwrap_err(); + HeaderValue::try_from(alloc::vec![127]).unwrap_err(); } #[test] @@ -801,11 +811,11 @@ fn test_debug() { for &(value, expected) in cases { let val = HeaderValue::from_bytes(value.as_bytes()).unwrap(); - let actual = format!("{:?}", val); + let actual = alloc::format!("{:?}", val); assert_eq!(expected, actual); } let mut sensitive = HeaderValue::from_static("password"); sensitive.set_sensitive(true); - assert_eq!("Sensitive", format!("{:?}", sensitive)); + assert_eq!("Sensitive", alloc::format!("{:?}", sensitive)); } diff --git a/src/method.rs b/src/method.rs index 240ba063..7a4e4c34 100644 --- a/src/method.rs +++ b/src/method.rs @@ -15,6 +15,10 @@ //! assert_eq!(Method::POST.as_str(), "POST"); //! ``` +use core::convert::TryFrom; +use core::fmt; +use core::str::FromStr; + use self::extension::{AllocatedExtension, InlineExtension}; use self::Inner::*; @@ -297,9 +301,12 @@ impl fmt::Display for InvalidMethod { } } -impl Error for InvalidMethod {} +#[cfg(feature = "std")] +impl std::error::Error for InvalidMethod {} mod extension { + use alloc::{boxed::Box, vec::Vec}; + use super::InvalidMethod; #[derive(Clone, PartialEq, Eq, Hash)] @@ -334,7 +341,7 @@ mod extension { impl AllocatedExtension { pub fn new(src: &[u8]) -> Result { - let mut data: Vec = vec![0; src.len()]; + let mut data: Vec = alloc::vec![0; src.len()]; write_checked(src, &mut data)?; diff --git a/src/request.rs b/src/request.rs index 40a796bc..be58fde9 100644 --- a/src/request.rs +++ b/src/request.rs @@ -52,6 +52,10 @@ //! } //! ``` +use core::any::Any; +use core::convert::TryInto; +use core::fmt; + use crate::header::{HeaderMap, HeaderName, HeaderValue}; use crate::method::Method; use crate::version::Version; diff --git a/src/response.rs b/src/response.rs index 0c328d8d..17f5d7f1 100644 --- a/src/response.rs +++ b/src/response.rs @@ -61,6 +61,10 @@ //! // ... //! ``` +use core::any::Any; +use core::convert::TryInto; +use core::fmt; + use crate::header::{HeaderMap, HeaderName, HeaderValue}; use crate::status::StatusCode; use crate::version::Version; diff --git a/src/status.rs b/src/status.rs index bbc18d0e..9ecc7bd0 100644 --- a/src/status.rs +++ b/src/status.rs @@ -14,6 +14,8 @@ //! assert!(StatusCode::OK.is_success()); //! ``` +use core::{convert::TryFrom, fmt, num::NonZeroU16, str::FromStr}; + /// An HTTP status code (`status-code` in RFC 9110 et al.). /// /// Constants are provided for known status codes, including those in the IANA @@ -536,7 +538,8 @@ impl fmt::Display for InvalidStatusCode { } } -impl Error for InvalidStatusCode {} +#[cfg(feature = "std")] +impl std::error::Error for InvalidStatusCode {} // A string of packed 3-ASCII-digit status code values for the supported range // of [100, 999] (900 codes, 2700 bytes). diff --git a/src/uri/authority.rs b/src/uri/authority.rs index 1bd5eacb..db436657 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -1,3 +1,11 @@ +use core::convert::TryFrom; +use core::fmt; +use core::str::FromStr; +use core::{cmp, hash::Hasher}; +use core::hash::Hash; + +use alloc::string::String; +use alloc::vec::Vec; use bytes::Bytes; use super::{ErrorKind, InvalidUri, Port, URI_CHARS}; diff --git a/src/uri/builder.rs b/src/uri/builder.rs index 35685c7a..c69e1437 100644 --- a/src/uri/builder.rs +++ b/src/uri/builder.rs @@ -1,3 +1,5 @@ +use core::convert::TryInto; + use super::{Authority, Parts, PathAndQuery, Scheme}; use crate::Uri; @@ -180,10 +182,10 @@ mod tests { fn build_from_string() { for i in 1..10 { let uri = Builder::new() - .path_and_query(format!("/foo?a={}", i)) + .path_and_query(alloc::format!("/foo?a={}", i)) .build() .unwrap(); - let expected_query = format!("a={}", i); + let expected_query = alloc::format!("a={}", i); assert_eq!(uri.path(), "/foo"); assert_eq!(uri.query(), Some(expected_query.as_str())); } @@ -192,9 +194,9 @@ mod tests { #[test] fn build_from_string_ref() { for i in 1..10 { - let p_a_q = format!("/foo?a={}", i); + let p_a_q = alloc::format!("/foo?a={}", i); let uri = Builder::new().path_and_query(&p_a_q).build().unwrap(); - let expected_query = format!("a={}", i); + let expected_query = alloc::format!("a={}", i); assert_eq!(uri.path(), "/foo"); assert_eq!(uri.query(), Some(expected_query.as_str())); } diff --git a/src/uri/mod.rs b/src/uri/mod.rs index e11980a0..cd1f2e9f 100644 --- a/src/uri/mod.rs +++ b/src/uri/mod.rs @@ -22,8 +22,16 @@ //! assert_eq!(uri.path(), "/install.html"); //! ``` +use core::convert::TryFrom; +use core::fmt; +use core::str::FromStr; +use core::hash::{Hash, Hasher}; + use crate::byte_str::ByteStr; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; use bytes::Bytes; use self::scheme::Scheme2; @@ -1077,7 +1085,8 @@ impl fmt::Display for InvalidUri { } } -impl Error for InvalidUri {} +#[cfg(feature = "std")] +impl std::error::Error for InvalidUri {} impl fmt::Display for InvalidUriParts { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1085,7 +1094,8 @@ impl fmt::Display for InvalidUriParts { } } -impl Error for InvalidUriParts {} +#[cfg(feature = "std")] +impl std::error::Error for InvalidUriParts {} impl Hash for Uri { fn hash(&self, state: &mut H) diff --git a/src/uri/path.rs b/src/uri/path.rs index 806148fe..bdac5cc4 100644 --- a/src/uri/path.rs +++ b/src/uri/path.rs @@ -1,3 +1,6 @@ +use core::{cmp, convert::TryFrom, fmt, hash::{Hash, Hasher}, str::FromStr}; + +use alloc::{string::String, vec::Vec}; use bytes::Bytes; use super::{ErrorKind, InvalidUri}; @@ -341,8 +344,8 @@ impl fmt::Display for PathAndQuery { } } -impl hash::Hash for PathAndQuery { - fn hash(&self, state: &mut H) { +impl Hash for PathAndQuery { + fn hash(&self, state: &mut H) { self.data.hash(state); } } @@ -561,6 +564,6 @@ mod tests { } fn pq(s: &str) -> PathAndQuery { - s.parse().expect(&format!("parsing {}", s)) + s.parse().expect(&alloc::format!("parsing {}", s)) } } diff --git a/src/uri/port.rs b/src/uri/port.rs index 62a82fd8..b695c550 100644 --- a/src/uri/port.rs +++ b/src/uri/port.rs @@ -1,3 +1,5 @@ +use core::fmt; + use super::{ErrorKind, InvalidUri}; /// The port component of a URI. @@ -110,6 +112,8 @@ impl PartialEq> for u16 { #[cfg(test)] mod tests { + use alloc::string::String; + use super::*; #[test] diff --git a/src/uri/scheme.rs b/src/uri/scheme.rs index 9603875a..c2d5624f 100644 --- a/src/uri/scheme.rs +++ b/src/uri/scheme.rs @@ -1,3 +1,7 @@ +use core::{convert::TryFrom, fmt, str::FromStr}; +use core::hash::{Hash, Hasher}; + +use alloc::boxed::Box; use bytes::Bytes; use super::{ErrorKind, InvalidUri}; @@ -351,6 +355,6 @@ mod test { } fn scheme(s: &str) -> Scheme { - s.parse().expect(&format!("Invalid scheme: {}", s)) + s.parse().expect(&alloc::format!("Invalid scheme: {}", s)) } } diff --git a/src/uri/tests.rs b/src/uri/tests.rs index a9331efb..dd5b5eac 100644 --- a/src/uri/tests.rs +++ b/src/uri/tests.rs @@ -1,3 +1,5 @@ +use alloc::string::String; + use super::{ErrorKind, InvalidUri, Port, Uri, URI_CHARS}; #[test] @@ -440,9 +442,9 @@ fn test_uri_parse_error() { #[test] fn test_max_uri_len() { - let mut uri = vec![]; + let mut uri = alloc::vec![]; uri.extend(b"http://localhost/"); - uri.extend(vec![b'a'; 70 * 1024]); + uri.extend(alloc::vec![b'a'; 70 * 1024]); let uri = String::from_utf8(uri).unwrap(); let res: Result = uri.parse(); @@ -452,8 +454,8 @@ fn test_max_uri_len() { #[test] fn test_overflowing_scheme() { - let mut uri = vec![]; - uri.extend(vec![b'a'; 256]); + let mut uri = alloc::vec![]; + uri.extend(alloc::vec![b'a'; 256]); uri.extend(b"://localhost/"); let uri = String::from_utf8(uri).unwrap(); @@ -464,8 +466,8 @@ fn test_overflowing_scheme() { #[test] fn test_max_length_scheme() { - let mut uri = vec![]; - uri.extend(vec![b'a'; 64]); + let mut uri = alloc::vec![]; + uri.extend(alloc::vec![b'a'; 64]); uri.extend(b"://localhost/"); let uri = String::from_utf8(uri).unwrap(); @@ -476,7 +478,7 @@ fn test_max_length_scheme() { #[test] fn test_uri_to_path_and_query() { - let cases = vec![ + let cases = alloc::vec![ ("/", "/"), ("/foo?bar", "/foo?bar"), ("/foo?bar#nope", "/foo?bar"), diff --git a/src/version.rs b/src/version.rs index cf66bca5..436ca7df 100644 --- a/src/version.rs +++ b/src/version.rs @@ -19,6 +19,8 @@ //! println!("{:?}", http2); //! ``` +use core::fmt; + /// Represents a version of the HTTP spec. #[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)] pub struct Version(Http); From 75139a0296c0eab4c550b361996d1f03da386b66 Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Sun, 1 Dec 2024 11:33:40 -0500 Subject: [PATCH 3/5] mark a lot of Error as std --- src/byte_str.rs | 4 ++-- src/error.rs | 22 +++++++++++++--------- src/header/map.rs | 2 +- src/header/name.rs | 10 +++++----- src/header/value.rs | 10 +++++++--- src/method.rs | 6 ++++-- src/status.rs | 2 ++ src/uri/authority.rs | 2 ++ src/uri/path.rs | 2 ++ src/uri/tests.rs | 4 +++- 10 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/byte_str.rs b/src/byte_str.rs index f2c64de2..f1c50ba3 100644 --- a/src/byte_str.rs +++ b/src/byte_str.rs @@ -35,7 +35,7 @@ impl ByteStr { /// behavior to call this with `bytes` that is not valid UTF-8. pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr { if cfg!(debug_assertions) { - match str::from_utf8(&bytes) { + match core::str::from_utf8(&bytes) { Ok(_) => (), Err(err) => panic!( "ByteStr::from_utf8_unchecked() with invalid bytes; error = {}, bytes = {:?}", @@ -55,7 +55,7 @@ impl ops::Deref for ByteStr { fn deref(&self) -> &str { let b: &[u8] = self.bytes.as_ref(); // Safety: the invariant of `bytes` is that it contains valid UTF-8. - unsafe { str::from_utf8_unchecked(b) } + unsafe { core::str::from_utf8_unchecked(b) } } } diff --git a/src/error.rs b/src/error.rs index c75cad1b..7bcce3e5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,4 @@ use core::convert; -use core::error; -use core::fmt; use core::result; use crate::header; @@ -15,6 +13,7 @@ use crate::uri; /// functions in this crate, but all other errors can be converted to this /// error. Consumers of this crate can typically consume and work with this form /// of error for conversions with the `?` operator. +#[derive(Debug)] pub struct Error { inner: ErrorKind, } @@ -22,6 +21,7 @@ pub struct Error { /// A `Result` typedef to use with the `http::Error` type pub type Result = result::Result; +#[derive(Debug)] enum ErrorKind { StatusCode(status::InvalidStatusCode), Method(method::InvalidMethod), @@ -32,7 +32,8 @@ enum ErrorKind { MaxSizeReached(MaxSizeReached), } -impl fmt::Debug for Error { +#[cfg(feature = "std")] +impl std::fmt::Debug for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("http::Error") // Skip the noise of the ErrorKind enum @@ -41,13 +42,15 @@ impl fmt::Debug for Error { } } -impl fmt::Display for Error { +#[cfg(feature = "std")] +impl std::fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self.get_ref(), f) } } -impl Error { +#[cfg(feature = "std")] +impl std::error::Error for Error { /// Return true if the underlying error has the same type as T. pub fn is(&self) -> bool { self.get_ref().is::() @@ -69,10 +72,11 @@ impl Error { } } -impl error::Error for Error { +#[cfg(feature = "std")] +impl std::error::Error for Error { // Return any available cause from the inner error. Note the inner error is // not itself the cause. - fn source(&self) -> Option<&(dyn error::Error + 'static)> { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { self.get_ref().source() } } @@ -139,7 +143,7 @@ impl From for Error { } } -#[cfg(test)] +/*#[cfg(test)] mod tests { use super::*; @@ -158,4 +162,4 @@ mod tests { panic!("Bad status allowed!"); } } -} +}*/ diff --git a/src/header/map.rs b/src/header/map.rs index 26db61ee..6b27a0b1 100644 --- a/src/header/map.rs +++ b/src/header/map.rs @@ -2,7 +2,7 @@ use core::convert::TryFrom; use core::iter::{FromIterator, FusedIterator}; use core::marker::PhantomData; use core::{fmt, mem, ops, ptr, slice}; -use core::hash::Hash; +use core::hash::{Hash, Hasher}; use alloc::boxed::Box; use alloc::vec; diff --git a/src/header/name.rs b/src/header/name.rs index 08ab0ab9..5d39e917 100644 --- a/src/header/name.rs +++ b/src/header/name.rs @@ -85,7 +85,7 @@ macro_rules! standard_headers { match *self { // Safety: test_parse_standard_headers ensures these &[u8]s are &str-safe. $( - StandardHeader::$konst => unsafe { str::from_utf8_unchecked( $name_bytes ) }, + StandardHeader::$konst => unsafe { core::str::from_utf8_unchecked( $name_bytes ) }, )+ } } @@ -114,7 +114,7 @@ macro_rules! standard_headers { assert_eq!(HeaderName::from_bytes(name_bytes).unwrap(), HeaderName::from(std)); // Test upper case - let upper = str::from_utf8(name_bytes).expect("byte string constants are all utf-8").to_uppercase(); + let upper = core::str::from_utf8(name_bytes).expect("byte string constants are all utf-8").to_uppercase(); assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(), HeaderName::from(std)); } } @@ -122,7 +122,7 @@ macro_rules! standard_headers { #[test] fn test_standard_headers_into_bytes() { for &(std, name_bytes) in TEST_HEADERS { - let name = str::from_utf8(name_bytes).unwrap(); + let name = core::str::from_utf8(name_bytes).unwrap(); let std = HeaderName::from(std); // Test lower case let bytes: Bytes = @@ -1704,7 +1704,7 @@ mod tests { let long = &ONE_TOO_LONG[0..super::super::MAX_HEADER_NAME_LEN]; - let long_str = str::from_utf8(long).unwrap(); + let long_str = core::str::from_utf8(long).unwrap(); assert_eq!(HeaderName::from_static(long_str), long_str); // shouldn't panic! assert!( @@ -1721,7 +1721,7 @@ mod tests { #[should_panic] fn test_static_invalid_name_lengths() { // Safety: ONE_TOO_LONG contains only the UTF-8 safe, single-byte codepoint b'a'. - let _ = HeaderName::from_static(unsafe { str::from_utf8_unchecked(ONE_TOO_LONG) }); + let _ = HeaderName::from_static(unsafe { core::str::from_utf8_unchecked(ONE_TOO_LONG) }); } #[test] diff --git a/src/header/value.rs b/src/header/value.rs index b697dc11..6adcacb2 100644 --- a/src/header/value.rs +++ b/src/header/value.rs @@ -275,7 +275,7 @@ impl HeaderValue { } } - unsafe { Ok(str::from_utf8_unchecked(bytes)) } + unsafe { Ok(core::str::from_utf8_unchecked(bytes)) } } /// Returns the length of `self`. @@ -394,7 +394,7 @@ impl fmt::Debug for HeaderValue { for (i, &b) in bytes.iter().enumerate() { if !is_visible_ascii(b) || b == b'"' { if from != i { - f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..i]) })?; + f.write_str(unsafe { core::str::from_utf8_unchecked(&bytes[from..i]) })?; } if b == b'"' { f.write_str("\\\"")?; @@ -405,7 +405,7 @@ impl fmt::Debug for HeaderValue { } } - f.write_str(unsafe { str::from_utf8_unchecked(&bytes[from..]) })?; + f.write_str(unsafe { core::str::from_utf8_unchecked(&bytes[from..]) })?; f.write_str("\"") } } @@ -425,6 +425,8 @@ macro_rules! from_integers { ($($name:ident: $t:ident => $max_len:expr),*) => {$( impl From<$t> for HeaderValue { fn from(num: $t) -> HeaderValue { + use core::fmt::Write; + let mut buf = if mem::size_of::() - 1 < $max_len { // On 32bit platforms, BytesMut max inline size // is 15 bytes, but the $max_len could be bigger. @@ -456,6 +458,8 @@ macro_rules! from_integers { #[test] fn $name() { + use alloc::string::ToString; + let n: $t = 55; let val = HeaderValue::from(n); assert_eq!(val, &n.to_string()); diff --git a/src/method.rs b/src/method.rs index 7a4e4c34..d2e40db0 100644 --- a/src/method.rs +++ b/src/method.rs @@ -335,7 +335,7 @@ mod extension { let InlineExtension(ref data, len) = self; // Safety: the invariant of InlineExtension ensures that the first // len bytes of data contain valid UTF-8. - unsafe { str::from_utf8_unchecked(&data[..*len as usize]) } + unsafe { core::str::from_utf8_unchecked(&data[..*len as usize]) } } } @@ -353,7 +353,7 @@ mod extension { pub fn as_str(&self) -> &str { // Safety: the invariant of AllocatedExtension ensures that self.0 // contains valid UTF-8. - unsafe { str::from_utf8_unchecked(&self.0) } + unsafe { core::str::from_utf8_unchecked(&self.0) } } } @@ -422,6 +422,8 @@ mod extension { #[cfg(test)] mod test { + use alloc::string::ToString; + use super::*; #[test] diff --git a/src/status.rs b/src/status.rs index 9ecc7bd0..20dd56cf 100644 --- a/src/status.rs +++ b/src/status.rs @@ -16,6 +16,8 @@ use core::{convert::TryFrom, fmt, num::NonZeroU16, str::FromStr}; +use alloc::borrow::ToOwned; + /// An HTTP status code (`status-code` in RFC 9110 et al.). /// /// Constants are provided for known status codes, including those in the IANA diff --git a/src/uri/authority.rs b/src/uri/authority.rs index db436657..b2bc8356 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -533,6 +533,8 @@ where #[cfg(test)] mod tests { + use alloc::string::ToString; + use super::*; #[test] diff --git a/src/uri/path.rs b/src/uri/path.rs index bdac5cc4..85427b6f 100644 --- a/src/uri/path.rs +++ b/src/uri/path.rs @@ -454,6 +454,8 @@ impl PartialOrd for String { #[cfg(test)] mod tests { + use alloc::string::ToString; + use super::*; #[test] diff --git a/src/uri/tests.rs b/src/uri/tests.rs index dd5b5eac..204a86f9 100644 --- a/src/uri/tests.rs +++ b/src/uri/tests.rs @@ -1,4 +1,6 @@ -use alloc::string::String; +use core::str::FromStr; + +use alloc::string::{String, ToString}; use super::{ErrorKind, InvalidUri, Port, Uri, URI_CHARS}; From 232ea5bc9502c4098cbb2adf0588cc310f9a1e06 Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Sun, 1 Dec 2024 11:38:27 -0500 Subject: [PATCH 4/5] it compiles --- src/error.rs | 2 ++ src/header/map.rs | 12 +++--------- tests/header_map_fuzz.rs | 1 + 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/error.rs b/src/error.rs index 7bcce3e5..adc66e47 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use core::convert; use core::result; diff --git a/src/header/map.rs b/src/header/map.rs index 6b27a0b1..09156106 100644 --- a/src/header/map.rs +++ b/src/header/map.rs @@ -319,7 +319,7 @@ enum Link { enum Danger { Green, Yellow, - Red(RandomState), // TODO: no_std? + Red, // TODO: no_std? } // Constants related to detecting DOS attacks. @@ -3529,12 +3529,12 @@ impl Pos { impl Danger { fn is_red(&self) -> bool { - matches!(*self, Danger::Red(_)) + matches!(*self, Danger::Red) } fn set_red(&mut self) { debug_assert!(self.is_yellow()); - *self = Danger::Red(RandomState::new()); + *self = Danger::Red; } fn is_yellow(&self) -> bool { @@ -3616,12 +3616,6 @@ where const MASK: u64 = (MAX_SIZE as u64) - 1; let hash = match *danger { - // Safe hash - Danger::Red(ref hasher) => { - let mut h = hasher.build_hasher(); - k.hash(&mut h); - h.finish() - } // Fast hash _ => { let mut h = FnvHasher::default(); diff --git a/tests/header_map_fuzz.rs b/tests/header_map_fuzz.rs index 926fa8a5..aae5a6c4 100644 --- a/tests/header_map_fuzz.rs +++ b/tests/header_map_fuzz.rs @@ -1,3 +1,4 @@ +use hashbrown::HashMap; use http::header::*; use http::*; From f2b5fc0c25404315182123e1009d87eabb185988 Mon Sep 17 00:00:00 2001 From: Brandon Ros Date: Sun, 1 Dec 2024 12:12:59 -0500 Subject: [PATCH 5/5] leave std as the default --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index af8928d0..7ae29358 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ exclude = [ ] [features] -default = [] +default = ["std"] std = [] [dependencies]