Skip to content

Commit

Permalink
Merge branch 'master' into fix-issue-353
Browse files Browse the repository at this point in the history
  • Loading branch information
seanmonstar authored Dec 3, 2024
2 parents 83319ed + 92d4148 commit 68a1ec6
Show file tree
Hide file tree
Showing 12 changed files with 108 additions and 73 deletions.
2 changes: 1 addition & 1 deletion src/byte_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl ByteStr {
///
/// ## Safety
/// `bytes` must contain valid UTF-8. In a release build it is undefined
/// behaviour to call this with `bytes` that is not valid UTF-8.
/// 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) {
Expand Down
2 changes: 1 addition & 1 deletion src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ impl Extensions {
self.map.as_ref().map_or(true, |map| map.is_empty())
}

/// Get the numer of extensions available.
/// Get the number of extensions available.
///
/// # Example
///
Expand Down
4 changes: 2 additions & 2 deletions src/header/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2020,7 +2020,7 @@ impl<T> FromIterator<(HeaderName, T)> for HeaderMap<T> {
/// let headers: HeaderMap = (&map).try_into().expect("valid headers");
/// assert_eq!(headers["X-Custom-Header"], "my value");
/// ```
impl<'a, K, V, T> TryFrom<&'a HashMap<K, V>> for HeaderMap<T>
impl<'a, K, V, S, T> TryFrom<&'a HashMap<K, V, S>> for HeaderMap<T>
where
K: Eq + Hash,
HeaderName: TryFrom<&'a K>,
Expand All @@ -2030,7 +2030,7 @@ where
{
type Error = Error;

fn try_from(c: &'a HashMap<K, V>) -> Result<Self, Self::Error> {
fn try_from(c: &'a HashMap<K, V, S>) -> Result<Self, Self::Error> {
c.iter()
.map(|(k, v)| -> crate::Result<(HeaderName, T)> {
let name = TryFrom::try_from(k).map_err(Into::into)?;
Expand Down
13 changes: 8 additions & 5 deletions src/header/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,10 @@ standard_headers! {
/// document.
(IfUnmodifiedSince, IF_UNMODIFIED_SINCE, b"if-unmodified-since");

/// Content-Types that are acceptable for the response.
/// The Last-Modified header contains the date and time when the origin believes
/// the resource was last modified.
///
/// The value is a valid Date/Time string defined in [RFC9910](https://datatracker.ietf.org/doc/html/rfc9110#section-5.6.7)
(LastModified, LAST_MODIFIED, b"last-modified");

/// Allows the server to point an interested client to another resource
Expand Down Expand Up @@ -1008,7 +1011,7 @@ const HEADER_CHARS: [u8; 256] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2x
0, 0, 0, b'!', b'"', b'#', b'$', b'%', b'&', b'\'', // 3x
0, 0, 0, b'!', 0, b'#', b'$', b'%', b'&', b'\'', // 3x
0, 0, b'*', b'+', 0, b'-', b'.', 0, b'0', b'1', // 4x
b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', 0, 0, // 5x
0, 0, 0, 0, 0, b'a', b'b', b'c', b'd', b'e', // 6x
Expand Down Expand Up @@ -1656,13 +1659,13 @@ const SCRATCH_BUF_OVERFLOW: usize = SCRATCH_BUF_SIZE + 1;
fn uninit_u8_array() -> [MaybeUninit<u8>; SCRATCH_BUF_SIZE] {
let arr = MaybeUninit::<[MaybeUninit<u8>; SCRATCH_BUF_SIZE]>::uninit();
// Safety: assume_init() is claiming that an array of MaybeUninit<>
// has been initilized, but MaybeUninit<>'s do not require initilizaton.
// has been initialized, but MaybeUninit<>'s do not require initialization.
unsafe { arr.assume_init() }
}

// Assuming all the elements are initilized, get a slice of them.
// Assuming all the elements are initialized, get a slice of them.
//
// Safety: All elements of `slice` must be initilized to prevent
// Safety: All elements of `slice` must be initialized to prevent
// undefined behavior.
unsafe fn slice_assume_init<T>(slice: &[MaybeUninit<T>]) -> &[T] {
&*(slice as *const [MaybeUninit<T>] as *const [T])
Expand Down
13 changes: 5 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,13 @@
//! Notably you'll find `Uri` for what a [`Request`] is requesting, a [`Method`]
//! for how it's being requested, a [`StatusCode`] for what sort of response came
//! back, a [`Version`] for how this was communicated, and
//! [`HeaderName`][header::HeaderName]/[`HeaderValue`][header::HeaderName] definitions to get grouped in a [`HeaderMap`] to
//! [`HeaderName`]/[`HeaderValue`] definitions to get grouped in a [`HeaderMap`] to
//! work with request/response headers.
//!
//! You will notably *not* find an implementation of sending requests or
//! spinning up a server in this crate. It's intended that this crate is the
//! "standard library" for HTTP clients and servers without dictating any
//! particular implementation. Note that this crate is still early on in its
//! lifecycle so the support libraries that integrate with the `http` crate are
//! a work in progress! Stay tuned and we'll be sure to highlight crates here
//! in the future.
//! particular implementation.
//!
//! ## Requests and Responses
//!
Expand Down Expand Up @@ -87,10 +84,10 @@
//! Accept: text/html
//! ```
//!
//! Then `"Accept"` is a [`HeaderName`][header::HeaderName] while `"text/html"` is a [`HeaderValue`][header::HeaderValue].
//! Then `"Accept"` is a [`HeaderName`] while `"text/html"` is a [`HeaderValue`].
//! Each of these is a dedicated type to allow for a number of interesting
//! optimizations and to also encode the static guarantees of each type. For
//! example a [`HeaderName`][header::HeaderName] is always a valid `&str`, but a [`HeaderValue`] may
//! example a [`HeaderName`] is always a valid `&str`, but a [`HeaderValue`] may
//! not be valid UTF-8.
//!
//! The most common header names are already defined for you as constant values
Expand Down Expand Up @@ -134,7 +131,7 @@
//! Most HTTP requests and responses tend to come with more than one header, so
//! it's not too useful to just work with names and values only! This crate also
//! provides a [`HeaderMap`] type which is a specialized hash map for keys as
//! [`HeaderName`][header::HeaderName] and generic values. This type, like header names, is optimized
//! [`HeaderName`] and generic values. This type, like header names, is optimized
//! for common usage but should continue to scale with your needs over time.
//!
//! # URIs
Expand Down
39 changes: 35 additions & 4 deletions src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl Method {
_ => Method::extension_inline(src),
},
_ => {
if src.len() < InlineExtension::MAX {
if src.len() <= InlineExtension::MAX {
Method::extension_inline(src)
} else {
let allocated = AllocatedExtension::new(src)?;
Expand Down Expand Up @@ -356,7 +356,7 @@ mod extension {
}
}

// From the HTTP spec section 5.1.1, the HTTP method is case-sensitive and can
// From the RFC 9110 HTTP Semantics, section 9.1, the HTTP method is case-sensitive and can
// contain the following characters:
//
// ```
Expand All @@ -366,7 +366,7 @@ mod extension {
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
// ```
//
// https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01#Method
// https://datatracker.ietf.org/doc/html/rfc9110#section-9.1
//
// Note that this definition means that any &[u8] that consists solely of valid
// characters is also valid UTF-8 because the valid method characters are a
Expand All @@ -377,7 +377,7 @@ mod extension {
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 1x
b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 2x
b'\0', b'\0', b'\0', b'!', b'\0', b'\0', b'\0', b'\0', b'\0', b'\0', // 3x
b'\0', b'\0', b'\0', b'!', b'\0', b'#', b'$', b'%', b'&', b'\'', // 3x
b'\0', b'\0', b'*', b'+', b'\0', b'-', b'.', b'\0', b'0', b'1', // 4x
b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'\0', b'\0', // 5x
b'\0', b'\0', b'\0', b'\0', b'\0', b'A', b'B', b'C', b'D', b'E', // 6x
Expand Down Expand Up @@ -465,5 +465,36 @@ mod test {

let long_method = "This_is_a_very_long_method.It_is_valid_but_unlikely.";
assert_eq!(Method::from_str(long_method).unwrap(), long_method);

let longest_inline_method = [b'A'; InlineExtension::MAX];
assert_eq!(
Method::from_bytes(&longest_inline_method).unwrap(),
Method(ExtensionInline(
InlineExtension::new(&longest_inline_method).unwrap()
))
);
let shortest_allocated_method = [b'A'; InlineExtension::MAX + 1];
assert_eq!(
Method::from_bytes(&shortest_allocated_method).unwrap(),
Method(ExtensionAllocated(
AllocatedExtension::new(&shortest_allocated_method).unwrap()
))
);
}

#[test]
fn test_extension_method_chars() {
const VALID_METHOD_CHARS: &str =
"!#$%&'*+-.^_`|~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

for c in VALID_METHOD_CHARS.chars() {
let c = c.to_string();

assert_eq!(
Method::from_str(&c).unwrap(),
c.as_str(),
"testing {c} is a valid method character"
);
}
}
}
62 changes: 31 additions & 31 deletions src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
//! ```
use std::any::Any;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::fmt;

use crate::header::{HeaderMap, HeaderName, HeaderValue};
Expand Down Expand Up @@ -231,8 +231,8 @@ impl Request<()> {
/// ```
pub fn get<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
Builder::new().method(Method::GET).uri(uri)
}
Expand All @@ -253,8 +253,8 @@ impl Request<()> {
/// ```
pub fn put<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
Builder::new().method(Method::PUT).uri(uri)
}
Expand All @@ -275,8 +275,8 @@ impl Request<()> {
/// ```
pub fn post<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
Builder::new().method(Method::POST).uri(uri)
}
Expand All @@ -297,8 +297,8 @@ impl Request<()> {
/// ```
pub fn delete<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
Builder::new().method(Method::DELETE).uri(uri)
}
Expand All @@ -320,8 +320,8 @@ impl Request<()> {
/// ```
pub fn options<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
Builder::new().method(Method::OPTIONS).uri(uri)
}
Expand All @@ -342,8 +342,8 @@ impl Request<()> {
/// ```
pub fn head<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
Builder::new().method(Method::HEAD).uri(uri)
}
Expand All @@ -364,8 +364,8 @@ impl Request<()> {
/// ```
pub fn connect<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
Builder::new().method(Method::CONNECT).uri(uri)
}
Expand All @@ -386,8 +386,8 @@ impl Request<()> {
/// ```
pub fn patch<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
Builder::new().method(Method::PATCH).uri(uri)
}
Expand All @@ -408,8 +408,8 @@ impl Request<()> {
/// ```
pub fn trace<T>(uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
Builder::new().method(Method::TRACE).uri(uri)
}
Expand Down Expand Up @@ -767,11 +767,11 @@ impl Builder {
/// ```
pub fn method<T>(self, method: T) -> Builder
where
Method: TryFrom<T>,
<Method as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Method>,
<T as TryInto<Method>>::Error: Into<crate::Error>,
{
self.and_then(move |mut head| {
let method = TryFrom::try_from(method).map_err(Into::into)?;
let method = method.try_into().map_err(Into::into)?;
head.method = method;
Ok(head)
})
Expand Down Expand Up @@ -812,11 +812,11 @@ impl Builder {
/// ```
pub fn uri<T>(self, uri: T) -> Builder
where
Uri: TryFrom<T>,
<Uri as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<Uri>,
<T as TryInto<Uri>>::Error: Into<crate::Error>,
{
self.and_then(move |mut head| {
head.uri = TryFrom::try_from(uri).map_err(Into::into)?;
head.uri = uri.try_into().map_err(Into::into)?;
Ok(head)
})
}
Expand Down Expand Up @@ -900,14 +900,14 @@ impl Builder {
/// ```
pub fn header<K, V>(self, key: K, value: V) -> Builder
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<crate::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<crate::Error>,
K: TryInto<HeaderName>,
<K as TryInto<HeaderName>>::Error: Into<crate::Error>,
V: TryInto<HeaderValue>,
<V as TryInto<HeaderValue>>::Error: Into<crate::Error>,
{
self.and_then(move |mut head| {
let name = <HeaderName as TryFrom<K>>::try_from(key).map_err(Into::into)?;
let value = <HeaderValue as TryFrom<V>>::try_from(value).map_err(Into::into)?;
let name = key.try_into().map_err(Into::into)?;
let value = value.try_into().map_err(Into::into)?;
head.headers.try_append(name, value)?;
Ok(head)
})
Expand Down
20 changes: 10 additions & 10 deletions src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
//! ```
use std::any::Any;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::fmt;

use crate::header::{HeaderMap, HeaderName, HeaderValue};
Expand Down Expand Up @@ -559,11 +559,11 @@ impl Builder {
/// ```
pub fn status<T>(self, status: T) -> Builder
where
StatusCode: TryFrom<T>,
<StatusCode as TryFrom<T>>::Error: Into<crate::Error>,
T: TryInto<StatusCode>,
<T as TryInto<StatusCode>>::Error: Into<crate::Error>,
{
self.and_then(move |mut head| {
head.status = TryFrom::try_from(status).map_err(Into::into)?;
head.status = status.try_into().map_err(Into::into)?;
Ok(head)
})
}
Expand Down Expand Up @@ -610,14 +610,14 @@ impl Builder {
/// ```
pub fn header<K, V>(self, key: K, value: V) -> Builder
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<crate::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<crate::Error>,
K: TryInto<HeaderName>,
<K as TryInto<HeaderName>>::Error: Into<crate::Error>,
V: TryInto<HeaderValue>,
<V as TryInto<HeaderValue>>::Error: Into<crate::Error>,
{
self.and_then(move |mut head| {
let name = <HeaderName as TryFrom<K>>::try_from(key).map_err(Into::into)?;
let value = <HeaderValue as TryFrom<V>>::try_from(value).map_err(Into::into)?;
let name = key.try_into().map_err(Into::into)?;
let value = value.try_into().map_err(Into::into)?;
head.headers.try_append(name, value)?;
Ok(head)
})
Expand Down
Loading

0 comments on commit 68a1ec6

Please sign in to comment.