feat(http1): Make HTTP/1 support an optional feature
cc #2251 BREAKING CHANGE: This puts all HTTP/1 methods and support behind an `http1` cargo feature, which will not be enabled by default. To use HTTP/1, add `features = ["http1"]` to the hyper dependency in your `Cargo.toml`.
This commit is contained in:
		| @@ -21,6 +21,7 @@ impl<T: Buf> BufList<T> { | ||||
|     } | ||||
|  | ||||
|     #[inline] | ||||
|     #[cfg(feature = "http1")] | ||||
|     pub(crate) fn bufs_cnt(&self) -> usize { | ||||
|         self.bufs.len() | ||||
|     } | ||||
|   | ||||
							
								
								
									
										124
									
								
								src/common/date.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/common/date.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,124 @@ | ||||
| use std::cell::RefCell; | ||||
| use std::fmt::{self, Write}; | ||||
| use std::str; | ||||
| use std::time::{Duration, SystemTime}; | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| use http::header::HeaderValue; | ||||
| use httpdate::HttpDate; | ||||
|  | ||||
| // "Sun, 06 Nov 1994 08:49:37 GMT".len() | ||||
| pub const DATE_VALUE_LENGTH: usize = 29; | ||||
|  | ||||
| #[cfg(feature = "http1")] | ||||
| pub fn extend(dst: &mut Vec<u8>) { | ||||
|     CACHED.with(|cache| { | ||||
|         dst.extend_from_slice(cache.borrow().buffer()); | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http1")] | ||||
| pub fn update() { | ||||
|     CACHED.with(|cache| { | ||||
|         cache.borrow_mut().check(); | ||||
|     }) | ||||
| } | ||||
|  | ||||
| #[cfg(feature = "http2")] | ||||
| pub(crate) fn update_and_header_value() -> HeaderValue { | ||||
|     CACHED.with(|cache| { | ||||
|         let mut cache = cache.borrow_mut(); | ||||
|         cache.check(); | ||||
|         HeaderValue::from_bytes(cache.buffer()).expect("Date format should be valid HeaderValue") | ||||
|     }) | ||||
| } | ||||
|  | ||||
| struct CachedDate { | ||||
|     bytes: [u8; DATE_VALUE_LENGTH], | ||||
|     pos: usize, | ||||
|     next_update: SystemTime, | ||||
| } | ||||
|  | ||||
| thread_local!(static CACHED: RefCell<CachedDate> = RefCell::new(CachedDate::new())); | ||||
|  | ||||
| impl CachedDate { | ||||
|     fn new() -> Self { | ||||
|         let mut cache = CachedDate { | ||||
|             bytes: [0; DATE_VALUE_LENGTH], | ||||
|             pos: 0, | ||||
|             next_update: SystemTime::now(), | ||||
|         }; | ||||
|         cache.update(cache.next_update); | ||||
|         cache | ||||
|     } | ||||
|  | ||||
|     fn buffer(&self) -> &[u8] { | ||||
|         &self.bytes[..] | ||||
|     } | ||||
|  | ||||
|     fn check(&mut self) { | ||||
|         let now = SystemTime::now(); | ||||
|         if now > self.next_update { | ||||
|             self.update(now); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn update(&mut self, now: SystemTime) { | ||||
|         self.render(now); | ||||
|         self.next_update = now + Duration::new(1, 0); | ||||
|     } | ||||
|  | ||||
|     fn render(&mut self, now: SystemTime) { | ||||
|         self.pos = 0; | ||||
|         let _ = write!(self, "{}", HttpDate::from(now)); | ||||
|         debug_assert!(self.pos == DATE_VALUE_LENGTH); | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl fmt::Write for CachedDate { | ||||
|     fn write_str(&mut self, s: &str) -> fmt::Result { | ||||
|         let len = s.len(); | ||||
|         self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes()); | ||||
|         self.pos += len; | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
|  | ||||
|     #[cfg(feature = "nightly")] | ||||
|     use test::Bencher; | ||||
|  | ||||
|     #[test] | ||||
|     fn test_date_len() { | ||||
|         assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len()); | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "nightly")] | ||||
|     #[bench] | ||||
|     fn bench_date_check(b: &mut Bencher) { | ||||
|         let mut date = CachedDate::new(); | ||||
|         // cache the first update | ||||
|         date.check(); | ||||
|  | ||||
|         b.iter(|| { | ||||
|             date.check(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     #[cfg(feature = "nightly")] | ||||
|     #[bench] | ||||
|     fn bench_date_render(b: &mut Bencher) { | ||||
|         let mut date = CachedDate::new(); | ||||
|         let now = SystemTime::now(); | ||||
|         date.render(now); | ||||
|         b.bytes = date.buffer().len() as u64; | ||||
|  | ||||
|         b.iter(|| { | ||||
|             date.render(now); | ||||
|             test::black_box(&date); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| @@ -6,15 +6,10 @@ use std::sync::Arc; | ||||
| use crate::body::{Body, HttpBody}; | ||||
| #[cfg(feature = "http2")] | ||||
| use crate::proto::h2::server::H2Stream; | ||||
| use crate::rt::Executor; | ||||
| use crate::server::conn::spawn_all::{NewSvcTask, Watcher}; | ||||
| use crate::service::HttpService; | ||||
|  | ||||
| /// An executor of futures. | ||||
| pub trait Executor<Fut> { | ||||
|     /// Place the future into the executor to be run. | ||||
|     fn execute(&self, fut: Fut); | ||||
| } | ||||
|  | ||||
| pub trait ConnStreamExec<F, B: HttpBody>: Clone { | ||||
|     fn execute_h2stream(&mut self, fut: H2Stream<F, B>); | ||||
| } | ||||
|   | ||||
| @@ -29,7 +29,7 @@ impl<T> Rewind<T> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #[cfg(any(feature = "http2", test))] | ||||
|     #[cfg(any(all(feature = "http1", feature = "http2"), test))] | ||||
|     pub(crate) fn rewind(&mut self, bs: Bytes) { | ||||
|         debug_assert!(self.pre.is_none()); | ||||
|         self.pre = Some(bs); | ||||
|   | ||||
| @@ -8,9 +8,14 @@ macro_rules! ready { | ||||
| } | ||||
|  | ||||
| pub(crate) mod buf; | ||||
| #[cfg(any(feature = "http1", feature = "http2"))] | ||||
| pub(crate) mod date; | ||||
| #[cfg(any(feature = "http1", feature = "http2"))] | ||||
| pub(crate) mod drain; | ||||
| #[cfg(any(feature = "http1", feature = "http2"))] | ||||
| pub(crate) mod exec; | ||||
| pub(crate) mod io; | ||||
| #[cfg(any(feature = "http1", feature = "http2"))] | ||||
| mod lazy; | ||||
| mod never; | ||||
| #[cfg(feature = "stream")] | ||||
| @@ -18,11 +23,14 @@ pub(crate) mod sync_wrapper; | ||||
| pub(crate) mod task; | ||||
| pub(crate) mod watch; | ||||
|  | ||||
| pub use self::exec::Executor; | ||||
| #[cfg(any(feature = "http1", feature = "http2"))] | ||||
| pub(crate) use self::exec::{BoxSendFuture, Exec}; | ||||
| #[cfg(any(feature = "http1", feature = "http2"))] | ||||
| pub(crate) use self::lazy::{lazy, Started as Lazy}; | ||||
| pub use self::never::Never; | ||||
| pub(crate) use self::task::Poll; | ||||
|  | ||||
| // group up types normally needed for `Future` | ||||
| pub(crate) use std::{future::Future, marker::Unpin, pin::Pin}; | ||||
| #[cfg(any(feature = "http1", feature = "http2"))] | ||||
| pub(crate) use std::marker::Unpin; | ||||
| pub(crate) use std::{future::Future, pin::Pin}; | ||||
|   | ||||
| @@ -1,9 +1,11 @@ | ||||
| #[cfg(feature = "http1")] | ||||
| use super::Never; | ||||
| pub(crate) use std::task::{Context, Poll}; | ||||
|  | ||||
| /// A function to help "yield" a future, such that it is re-scheduled immediately. | ||||
| /// | ||||
| /// Useful for spin counts, so a future doesn't hog too much time. | ||||
| #[cfg(feature = "http1")] | ||||
| pub(crate) fn yield_now(cx: &mut Context<'_>) -> Poll<Never> { | ||||
|     cx.waker().wake_by_ref(); | ||||
|     Poll::Pending | ||||
|   | ||||
		Reference in New Issue
	
	Block a user