diff --git a/Cargo.lock b/Cargo.lock index 4a38d292..c0066c67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,6 +129,15 @@ version = "2.4.1" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "brotli" version = "3.4.0" @@ -187,6 +196,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -205,6 +223,16 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "deranged" version = "0.3.9" @@ -214,6 +242,16 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -368,6 +406,16 @@ dependencies = [ "windows", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.11" @@ -410,6 +458,30 @@ version = "0.14.2" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + [[package]] name = "hermit-abi" version = "0.3.3" @@ -805,6 +877,7 @@ name = "rama" version = "0.2.0" dependencies = [ "futures", + "headers", "http", "http-body", "http-body-util", @@ -1027,6 +1100,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1377,6 +1461,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicase" version = "2.7.0" diff --git a/rama/Cargo.toml b/rama/Cargo.toml index eaaeecf3..b6f5adb8 100644 --- a/rama/Cargo.toml +++ b/rama/Cargo.toml @@ -11,6 +11,7 @@ license = "MIT OR Apache-2.0" repository = "/~https://github.com/plabayo/rama" [dependencies] +headers = "0.4" http = "1" http-body = "1" http-body-util = "0.1" diff --git a/rama/src/net/http/headers.rs b/rama/src/net/http/headers.rs new file mode 100644 index 00000000..0389104a --- /dev/null +++ b/rama/src/net/http/headers.rs @@ -0,0 +1,83 @@ +//! typed http headers +//! +//! rama has the opinion that headers should be strongly-typed, +//! because that’s why we’re using Rust in the first place. To set or get any header, +//! an object must implement the Header trait from this module. +//! Several common headers are already provided, such as Host, ContentType, UserAgent, and others. +//! +//! ## Why typed? +//! +//! Or, why not stringly-typed? Types give the following advantages: +//! - More difficult to typo, since typos in types should be caught by the compiler +//! - Parsing to a proper type by default +//! +//! ## Defining Custom Headers +//! +//! ### Implementing the [`Header`] trait +//! +//! Consider a Do Not Track header. It can be true or false, +//! but it represents that via the numerals 1 and 0. +//! +//! ```rust +//! use rama::net::http::{headers::Header, HeaderName, HeaderValue}; +//! struct Dnt(bool); +//! +//! impl Header for Dnt { +//! fn name() -> &'static HeaderName { +//! &http::header::DNT +//! } +//! +//! fn decode<'i, I>(values: &mut I) -> Result +//! where +//! I: Iterator, +//! { +//! let value = values +//! .next() +//! .ok_or_else(headers::Error::invalid)?; +//! +//! if value == "0" { +//! Ok(Dnt(false)) +//! } else if value == "1" { +//! Ok(Dnt(true)) +//! } else { +//! Err(headers::Error::invalid()) +//! } +//! } +//! +//! fn encode(&self, values: &mut E) +//! where +//! E: Extend, +//! { +//! let s = if self.0 { +//! "1" +//! } else { +//! "0" +//! }; +//! +//! let value = HeaderValue::from_static(s); +//! +//! values.extend(std::iter::once(value)); +//! } +//! } +//! ``` + +pub use headers::{Header, HeaderMapExt}; + +pub use headers::{ + AcceptRanges, AccessControlAllowCredentials, AccessControlAllowHeaders, + AccessControlAllowMethods, AccessControlAllowOrigin, AccessControlExposeHeaders, + AccessControlMaxAge, AccessControlRequestHeaders, AccessControlRequestMethod, Age, Allow, + Authorization, CacheControl, Connection, ContentDisposition, ContentEncoding, ContentLength, + ContentLocation, ContentRange, Cookie, Date, ETag, Error, Expect, Expires, Host, IfMatch, + IfModifiedSince, IfNoneMatch, IfRange, IfUnmodifiedSince, LastModified, Location, Origin, + Pragma, ProxyAuthorization, Range, Referer, ReferrerPolicy, RetryAfter, SecWebsocketAccept, + SecWebsocketKey, SecWebsocketVersion, Server, SetCookie, StrictTransportSecurity, Te, + TransferEncoding, Upgrade, UserAgent, Vary, +}; + +pub mod authorization { + //! Authorization header and types. + + pub use headers::authorization::Credentials; + pub use headers::authorization::{Authorization, Basic, Bearer}; +} diff --git a/rama/src/net/http/mod.rs b/rama/src/net/http/mod.rs index 2317b5c8..200e911f 100644 --- a/rama/src/net/http/mod.rs +++ b/rama/src/net/http/mod.rs @@ -5,3 +5,5 @@ pub use http::{ header, request, response, HeaderMap, HeaderName, HeaderValue, Method, Request, Response, StatusCode, }; + +pub mod headers;