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