mirror of
https://github.com/tokio-rs/axum.git
synced 2024-12-29 15:49:16 +01:00
Add HTTP/1 and HTTP/2 to axum::serve
(#2241)
This commit is contained in:
parent
17993c5717
commit
8854e660e9
5 changed files with 13 additions and 173 deletions
|
@ -22,7 +22,7 @@ matched-path = []
|
||||||
multipart = ["dep:multer"]
|
multipart = ["dep:multer"]
|
||||||
original-uri = []
|
original-uri = []
|
||||||
query = ["dep:serde_urlencoded"]
|
query = ["dep:serde_urlencoded"]
|
||||||
tokio = ["dep:tokio", "hyper/server", "hyper/tcp", "hyper/runtime", "tower/make"]
|
tokio = ["dep:tokio", "dep:hyper-util", "hyper/server", "hyper/tcp", "hyper/runtime", "tower/make"]
|
||||||
tower-log = ["tower/log"]
|
tower-log = ["tower/log"]
|
||||||
tracing = ["dep:tracing", "axum-core/tracing"]
|
tracing = ["dep:tracing", "axum-core/tracing"]
|
||||||
ws = ["tokio", "dep:tokio-tungstenite", "dep:sha1", "dep:base64"]
|
ws = ["tokio", "dep:tokio-tungstenite", "dep:sha1", "dep:base64"]
|
||||||
|
@ -51,12 +51,13 @@ tower-layer = "0.3.2"
|
||||||
tower-service = "0.3"
|
tower-service = "0.3"
|
||||||
|
|
||||||
# wont need this when axum uses http-body 1.0
|
# wont need this when axum uses http-body 1.0
|
||||||
hyper1 = { package = "hyper", version = "=1.0.0-rc.4", features = ["server", "http1"] }
|
hyper1 = { package = "hyper", version = "=1.0.0-rc.4", features = ["server", "http1", "http2"] }
|
||||||
tower-hyper-http-body-compat = { version = "0.2", features = ["server", "http1"] }
|
tower-hyper-http-body-compat = { version = "0.2", features = ["server", "http1"] }
|
||||||
|
|
||||||
# optional dependencies
|
# optional dependencies
|
||||||
axum-macros = { path = "../axum-macros", version = "0.3.7", optional = true }
|
axum-macros = { path = "../axum-macros", version = "0.3.7", optional = true }
|
||||||
base64 = { version = "0.21.0", optional = true }
|
base64 = { version = "0.21.0", optional = true }
|
||||||
|
hyper-util = { git = "https://github.com/hyperium/hyper-util", rev = "d97181a", features = ["auto"], optional = true }
|
||||||
multer = { version = "2.0.0", optional = true }
|
multer = { version = "2.0.0", optional = true }
|
||||||
serde_json = { version = "1.0", features = ["raw_value"], optional = true }
|
serde_json = { version = "1.0", features = ["raw_value"], optional = true }
|
||||||
serde_path_to_error = { version = "0.1.8", optional = true }
|
serde_path_to_error = { version = "0.1.8", optional = true }
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
|
|
||||||
use self::rejection::*;
|
use self::rejection::*;
|
||||||
use super::FromRequestParts;
|
use super::FromRequestParts;
|
||||||
use crate::{body::Bytes, hyper1_tokio_io::TokioIo, response::Response, Error};
|
use crate::{body::Bytes, response::Response, Error};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use axum_core::body::Body;
|
use axum_core::body::Body;
|
||||||
use futures_util::{
|
use futures_util::{
|
||||||
|
@ -104,6 +104,7 @@ use http::{
|
||||||
request::Parts,
|
request::Parts,
|
||||||
Method, StatusCode,
|
Method, StatusCode,
|
||||||
};
|
};
|
||||||
|
use hyper_util::rt::TokioIo;
|
||||||
use sha1::{Digest, Sha1};
|
use sha1::{Digest, Sha1};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
|
|
|
@ -1,161 +0,0 @@
|
||||||
// Copied from https://github.com/hyperium/hyper-util/blob/master/src/rt/tokio_io.rs
|
|
||||||
|
|
||||||
#![allow(unsafe_code)]
|
|
||||||
|
|
||||||
//! Tokio IO integration for hyper
|
|
||||||
use hyper1 as hyper;
|
|
||||||
use std::{
|
|
||||||
pin::Pin,
|
|
||||||
task::{Context, Poll},
|
|
||||||
};
|
|
||||||
|
|
||||||
use pin_project_lite::pin_project;
|
|
||||||
|
|
||||||
pin_project! {
|
|
||||||
/// A wrapping implementing hyper IO traits for a type that
|
|
||||||
/// implements Tokio's IO traits.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct TokioIo<T> {
|
|
||||||
#[pin]
|
|
||||||
inner: T,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> TokioIo<T> {
|
|
||||||
/// Wrap a type implementing Tokio's IO traits.
|
|
||||||
pub(crate) fn new(inner: T) -> Self {
|
|
||||||
Self { inner }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Borrow the inner type.
|
|
||||||
pub(crate) fn inner(&self) -> &T {
|
|
||||||
&self.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> hyper::rt::Read for TokioIo<T>
|
|
||||||
where
|
|
||||||
T: tokio::io::AsyncRead,
|
|
||||||
{
|
|
||||||
fn poll_read(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
mut buf: hyper::rt::ReadBufCursor<'_>,
|
|
||||||
) -> Poll<Result<(), std::io::Error>> {
|
|
||||||
let n = unsafe {
|
|
||||||
let mut tbuf = tokio::io::ReadBuf::uninit(buf.as_mut());
|
|
||||||
match tokio::io::AsyncRead::poll_read(self.project().inner, cx, &mut tbuf) {
|
|
||||||
Poll::Ready(Ok(())) => tbuf.filled().len(),
|
|
||||||
other => return other,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
buf.advance(n);
|
|
||||||
}
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> hyper::rt::Write for TokioIo<T>
|
|
||||||
where
|
|
||||||
T: tokio::io::AsyncWrite,
|
|
||||||
{
|
|
||||||
fn poll_write(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
buf: &[u8],
|
|
||||||
) -> Poll<Result<usize, std::io::Error>> {
|
|
||||||
tokio::io::AsyncWrite::poll_write(self.project().inner, cx, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
|
|
||||||
tokio::io::AsyncWrite::poll_flush(self.project().inner, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_shutdown(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Result<(), std::io::Error>> {
|
|
||||||
tokio::io::AsyncWrite::poll_shutdown(self.project().inner, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_write_vectored(&self) -> bool {
|
|
||||||
tokio::io::AsyncWrite::is_write_vectored(&self.inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_write_vectored(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
bufs: &[std::io::IoSlice<'_>],
|
|
||||||
) -> Poll<Result<usize, std::io::Error>> {
|
|
||||||
tokio::io::AsyncWrite::poll_write_vectored(self.project().inner, cx, bufs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> tokio::io::AsyncRead for TokioIo<T>
|
|
||||||
where
|
|
||||||
T: hyper::rt::Read,
|
|
||||||
{
|
|
||||||
fn poll_read(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
tbuf: &mut tokio::io::ReadBuf<'_>,
|
|
||||||
) -> Poll<Result<(), std::io::Error>> {
|
|
||||||
let filled = tbuf.filled().len();
|
|
||||||
let sub_filled = unsafe {
|
|
||||||
let mut buf = hyper::rt::ReadBuf::uninit(tbuf.unfilled_mut());
|
|
||||||
|
|
||||||
match hyper::rt::Read::poll_read(self.project().inner, cx, buf.unfilled()) {
|
|
||||||
Poll::Ready(Ok(())) => buf.filled().len(),
|
|
||||||
other => return other,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let n_filled = filled + sub_filled;
|
|
||||||
// At least sub_filled bytes had to have been initialized.
|
|
||||||
let n_init = sub_filled;
|
|
||||||
unsafe {
|
|
||||||
tbuf.assume_init(n_init);
|
|
||||||
tbuf.set_filled(n_filled);
|
|
||||||
}
|
|
||||||
|
|
||||||
Poll::Ready(Ok(()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> tokio::io::AsyncWrite for TokioIo<T>
|
|
||||||
where
|
|
||||||
T: hyper::rt::Write,
|
|
||||||
{
|
|
||||||
fn poll_write(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
buf: &[u8],
|
|
||||||
) -> Poll<Result<usize, std::io::Error>> {
|
|
||||||
hyper::rt::Write::poll_write(self.project().inner, cx, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
|
|
||||||
hyper::rt::Write::poll_flush(self.project().inner, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_shutdown(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Result<(), std::io::Error>> {
|
|
||||||
hyper::rt::Write::poll_shutdown(self.project().inner, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_write_vectored(&self) -> bool {
|
|
||||||
hyper::rt::Write::is_write_vectored(&self.inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_write_vectored(
|
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
bufs: &[std::io::IoSlice<'_>],
|
|
||||||
) -> Poll<Result<usize, std::io::Error>> {
|
|
||||||
hyper::rt::Write::poll_write_vectored(self.project().inner, cx, bufs)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -432,8 +432,6 @@ mod boxed;
|
||||||
mod extension;
|
mod extension;
|
||||||
#[cfg(feature = "form")]
|
#[cfg(feature = "form")]
|
||||||
mod form;
|
mod form;
|
||||||
#[cfg(feature = "tokio")]
|
|
||||||
mod hyper1_tokio_io;
|
|
||||||
#[cfg(feature = "json")]
|
#[cfg(feature = "json")]
|
||||||
mod json;
|
mod json;
|
||||||
mod service_ext;
|
mod service_ext;
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
|
|
||||||
use std::{convert::Infallible, io, net::SocketAddr};
|
use std::{convert::Infallible, io, net::SocketAddr};
|
||||||
|
|
||||||
use crate::hyper1_tokio_io::TokioIo;
|
|
||||||
use axum_core::{body::Body, extract::Request, response::Response};
|
use axum_core::{body::Body, extract::Request, response::Response};
|
||||||
use futures_util::{future::poll_fn, FutureExt};
|
use futures_util::{future::poll_fn, FutureExt};
|
||||||
use hyper1::server::conn::http1;
|
use hyper_util::{
|
||||||
|
rt::{TokioExecutor, TokioIo},
|
||||||
|
server::conn::auto::Builder,
|
||||||
|
};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use tower_hyper_http_body_compat::{HttpBody04ToHttpBody1, HttpBody1ToHttpBody04};
|
use tower_hyper_http_body_compat::{HttpBody04ToHttpBody1, HttpBody1ToHttpBody04};
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
@ -15,7 +17,7 @@ use tower_service::Service;
|
||||||
/// This method of running a service is intentionally simple and doesn't support any configuration.
|
/// This method of running a service is intentionally simple and doesn't support any configuration.
|
||||||
/// Use hyper or hyper-util if you need configuration.
|
/// Use hyper or hyper-util if you need configuration.
|
||||||
///
|
///
|
||||||
/// It only supports HTTP/1.
|
/// It supports both HTTP/1 as well as HTTP/2.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -138,10 +140,9 @@ where
|
||||||
});
|
});
|
||||||
|
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
match http1::Builder::new()
|
match Builder::new(TokioExecutor::new())
|
||||||
.serve_connection(tcp_stream, service)
|
// upgrades needed for websockets
|
||||||
// for websockets
|
.serve_connection_with_upgrades(tcp_stream.into_inner(), service)
|
||||||
.with_upgrades()
|
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
|
|
Loading…
Reference in a new issue