diff --git a/Cargo.toml b/Cargo.toml index 68329409a06..2b0d6a2a808 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,3 +24,7 @@ include = ["src/**/*.rs", "README.md"] license = "ISC" repository = "https://github.com/twilight-rs/twilight.git" rust-version = "1.67" + +[patch.crates-io] +# Needed for hyper 1.0 compatibility +hyper-rustls = { git = "https://github.com/Gelbpunkt/hyper-rustls.git", branch = "hyper-v1" } diff --git a/twilight-gateway/Cargo.toml b/twilight-gateway/Cargo.toml index b14047e49ef..ebe7f23f840 100644 --- a/twilight-gateway/Cargo.toml +++ b/twilight-gateway/Cargo.toml @@ -15,6 +15,7 @@ version = "0.15.4" [dependencies] bitflags = { default-features = false, version = "2" } +bytes = { default-features = false, features = ["std"], version = "1" } fastrand = { default-features = false, features = ["std"], version = "2" } futures-util = { default-features = false, features = ["sink", "std"], version = "0.3" } serde = { default-features = false, features = ["derive"], version = "1" } diff --git a/twilight-http/Cargo.toml b/twilight-http/Cargo.toml index 0d372e64d01..0bc60b0010f 100644 --- a/twilight-http/Cargo.toml +++ b/twilight-http/Cargo.toml @@ -15,9 +15,12 @@ version = "0.15.4" [dependencies] fastrand = { default-features = false, features = ["std"], version = "2" } -hyper = { default-features = false, features = ["client", "http1", "http2", "runtime"], version = "0.14" } -hyper-rustls = { default-features = false, optional = true, features = ["http1", "http2"], version = "0.24" } -hyper-tls = { default-features = false, optional = true, version = "0.5" } +http = { default-features = false, version = "1" } +http-body-util = { default-features = false, version = "0.1" } +hyper = { default-features = false, version = "1" } +hyper-util = { default-features = false, features = ["client-legacy", "http1", "http2", "tokio"], version = "0.1.2" } +hyper-rustls = { default-features = false, optional = true, features = ["http1", "http2", "ring"], version = "0.25" } +hyper-tls = { default-features = false, optional = true, version = "0.6" } hyper-hickory = { default-features = false, optional = true, features = ["tokio"], version = "0.6" } percent-encoding = { default-features = false, version = "2" } serde = { default-features = false, features = ["derive"], version = "1" } diff --git a/twilight-http/src/client/builder.rs b/twilight-http/src/client/builder.rs index b74d7617be8..db0f937128a 100644 --- a/twilight-http/src/client/builder.rs +++ b/twilight-http/src/client/builder.rs @@ -1,6 +1,7 @@ use super::Token; use crate::{client::connector, Client}; -use hyper::header::HeaderMap; +use http::header::HeaderMap; +use hyper_util::rt::TokioExecutor; use std::{ sync::{atomic::AtomicBool, Arc}, time::Duration, @@ -32,7 +33,8 @@ impl ClientBuilder { pub fn build(self) -> Client { let connector = connector::create(); - let http = hyper::Client::builder().build(connector); + let http = + hyper_util::client::legacy::Client::builder(TokioExecutor::new()).build(connector); let token_invalidated = if self.remember_invalid_token { Some(Arc::new(AtomicBool::new(false))) diff --git a/twilight-http/src/client/connector.rs b/twilight-http/src/client/connector.rs index 12a6fb2d8ce..96d1752bf4a 100644 --- a/twilight-http/src/client/connector.rs +++ b/twilight-http/src/client/connector.rs @@ -15,7 +15,7 @@ type HttpsConnector = hyper_tls::HttpsConnector; type HttpConnector = hyper_hickory::TokioHickoryHttpConnector; /// HTTP connector. #[cfg(not(feature = "hickory"))] -type HttpConnector = hyper::client::HttpConnector; +type HttpConnector = hyper_util::client::legacy::connect::HttpConnector; /// Re-exported generic connector for use in the client. #[cfg(any( @@ -35,7 +35,7 @@ pub type Connector = HttpConnector; /// Create a connector with the specified features. pub fn create() -> Connector { #[cfg(not(feature = "hickory"))] - let mut connector = hyper::client::HttpConnector::new(); + let mut connector = HttpConnector::new(); #[cfg(feature = "hickory")] let mut connector = hyper_hickory::TokioHickoryResolver::default().into_http_connector(); @@ -44,6 +44,7 @@ pub fn create() -> Connector { #[cfg(feature = "rustls-native-roots")] let connector = hyper_rustls::HttpsConnectorBuilder::new() .with_native_roots() + .expect("no native root certificates found") .https_or_http() .enable_http1() .enable_http2() diff --git a/twilight-http/src/client/mod.rs b/twilight-http/src/client/mod.rs index a707f4a2bbc..7c522844169 100644 --- a/twilight-http/src/client/mod.rs +++ b/twilight-http/src/client/mod.rs @@ -89,11 +89,12 @@ use crate::{ response::ResponseFuture, API_VERSION, }; -use hyper::{ - client::Client as HyperClient, - header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, USER_AGENT}, - Body, +use http::header::{ + HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_LENGTH, CONTENT_TYPE, USER_AGENT, }; +use http_body_util::Full; +use hyper::body::Bytes; +use hyper_util::client::legacy::Client as HyperClient; use std::{ fmt::{Debug, Formatter, Result as FmtResult}, ops::Deref, @@ -231,7 +232,7 @@ impl Deref for Token { pub struct Client { pub(crate) default_allowed_mentions: Option, default_headers: Option, - http: HyperClient, + http: HyperClient>, proxy: Option>, ratelimiter: Option>, timeout: Duration, @@ -2659,11 +2660,11 @@ impl Client { } let try_req = if let Some(form) = form { - builder.body(Body::from(form.build())) + builder.body(Full::from(form.build())) } else if let Some(bytes) = body { - builder.body(Body::from(bytes)) + builder.body(Full::from(bytes)) } else { - builder.body(Body::empty()) + builder.body(Full::default()) }; let inner = self.http.request(try_req.map_err(|source| Error { diff --git a/twilight-http/src/error.rs b/twilight-http/src/error.rs index be1b98a2779..0dc86cf0987 100644 --- a/twilight-http/src/error.rs +++ b/twilight-http/src/error.rs @@ -1,5 +1,6 @@ use crate::{api_error::ApiError, json::JsonError, response::StatusCode}; -use hyper::{Body, Response}; +use http::Response; +use hyper::body::Incoming; use std::{ error::Error as StdError, fmt::{Debug, Display, Formatter, Result as FmtResult}, @@ -125,7 +126,7 @@ pub enum ErrorType { /// /// This may occur during Discord API stability incidents. ServiceUnavailable { - response: Response, + response: Response, }, /// Token in use has become revoked or is otherwise invalid. /// diff --git a/twilight-http/src/request/base.rs b/twilight-http/src/request/base.rs index b68fe99c993..020fb096cfa 100644 --- a/twilight-http/src/request/base.rs +++ b/twilight-http/src/request/base.rs @@ -3,7 +3,7 @@ use crate::{ error::Error, routing::{Path, Route}, }; -use hyper::header::{HeaderMap, HeaderName, HeaderValue}; +use http::header::{HeaderMap, HeaderName, HeaderValue}; use serde::Serialize; /// Builder to create a customized request. diff --git a/twilight-http/src/request/guild/ban/create_ban.rs b/twilight-http/src/request/guild/ban/create_ban.rs index 6d32418e685..d2b99cc828a 100644 --- a/twilight-http/src/request/guild/ban/create_ban.rs +++ b/twilight-http/src/request/guild/ban/create_ban.rs @@ -142,7 +142,7 @@ mod tests { client::Client, request::{AuditLogReason, TryIntoRequest, REASON_HEADER_NAME}, }; - use hyper::header::HeaderValue; + use http::header::HeaderValue; use std::error::Error; use twilight_http_ratelimiting::Method; use twilight_model::id::{ diff --git a/twilight-http/src/request/mod.rs b/twilight-http/src/request/mod.rs index acc8e091429..6bebb8058c3 100644 --- a/twilight-http/src/request/mod.rs +++ b/twilight-http/src/request/mod.rs @@ -73,7 +73,7 @@ pub use self::{ pub use twilight_http_ratelimiting::request::Method; use crate::error::{Error, ErrorType}; -use hyper::header::{HeaderName, HeaderValue}; +use http::header::{HeaderName, HeaderValue}; use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; use serde::Serialize; use std::iter; diff --git a/twilight-http/src/response/future.rs b/twilight-http/src/response/future.rs index a8a24bf9734..74f63d3c11e 100644 --- a/twilight-http/src/response/future.rs +++ b/twilight-http/src/response/future.rs @@ -3,7 +3,8 @@ use crate::{ api_error::ApiError, error::{Error, ErrorType}, }; -use hyper::{client::ResponseFuture as HyperResponseFuture, StatusCode as HyperStatusCode}; +use http::StatusCode as HyperStatusCode; +use hyper_util::client::legacy::ResponseFuture as HyperResponseFuture; use std::{ future::Future, marker::PhantomData, @@ -130,7 +131,7 @@ impl InFlight { let mut resp = resp; // Inaccurate since end-users can only access the decompressed body. #[cfg(feature = "decompression")] - resp.headers_mut().remove(hyper::header::CONTENT_LENGTH); + resp.headers_mut().remove(http::header::CONTENT_LENGTH); return InnerPoll::Ready(Ok(Response::new(resp))); } diff --git a/twilight-http/src/response/mod.rs b/twilight-http/src/response/mod.rs index 0818319f2c7..bd355eba106 100644 --- a/twilight-http/src/response/mod.rs +++ b/twilight-http/src/response/mod.rs @@ -53,11 +53,12 @@ mod status_code; pub use self::{future::ResponseFuture, status_code::StatusCode}; use self::marker::ListBody; -use hyper::{ - body::{self, Bytes}, +use http::{ header::{HeaderValue, Iter as HeaderMapIter}, - Body, Response as HyperResponse, + Response as HyperResponse, }; +use http_body_util::BodyExt; +use hyper::body::{Bytes, Incoming}; use serde::de::DeserializeOwned; use std::{ error::Error, @@ -174,12 +175,12 @@ pub enum DeserializeBodyErrorType { /// ``` #[derive(Debug)] pub struct Response { - inner: HyperResponse, + inner: HyperResponse, phantom: PhantomData, } impl Response { - pub(crate) const fn new(inner: HyperResponse) -> Self { + pub(crate) const fn new(inner: HyperResponse) -> Self { Self { inner, phantom: PhantomData, @@ -237,7 +238,7 @@ impl Response { let compressed = self .inner .headers() - .get(hyper::header::CONTENT_ENCODING) + .get(http::header::CONTENT_ENCODING) .is_some(); let body = self.inner.into_body(); @@ -249,12 +250,14 @@ impl Response { return decompress(body).await; } - body::to_bytes(body) + Ok(body + .collect() .await .map_err(|source| DeserializeBodyError { kind: DeserializeBodyErrorType::Chunking, source: Some(Box::new(source)), - }) + })? + .to_bytes()) } }; @@ -573,17 +576,22 @@ impl Future for TextFuture { } #[cfg(feature = "decompression")] -async fn decompress(body: Body) -> Result { +async fn decompress(body: B) -> Result +where + ::Error: Send + Sync + Error + 'static, +{ use brotli::Decompressor; use hyper::body::Buf; use std::io::Read; - let aggregate = body::aggregate(body) + let aggregate = body + .collect() .await .map_err(|source| DeserializeBodyError { kind: DeserializeBodyErrorType::Chunking, source: Some(Box::new(source)), - })?; + })? + .aggregate(); // Determine the size of the entire buffer, in order to create the // decompressed and compressed buffers. @@ -628,7 +636,7 @@ mod tests { #[tokio::test] async fn test_decompression() -> Result<(), Box> { use super::decompress; - use hyper::Body; + use http_body_util::Full; use twilight_model::guild::invite::Invite; const COMPRESSED: [u8; 685] = [ @@ -671,7 +679,7 @@ mod tests { 3, ]; - let decompressed = decompress(Body::from(COMPRESSED.as_ref())).await?; + let decompressed = decompress(Full::new(COMPRESSED.as_slice())).await?; let deserialized = serde_json::from_slice::(&decompressed)?;