Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to hyper dependency to version 1 #50

Merged
merged 15 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ categories = ["web-programming", "api-bindings"]
default = ["hyper-rustls"]

[dependencies]
base64 = "0.21.0"
hyper = { version = "0.14.18", features = ["client", "http1", "http2"] }
hyper-rustls = { version = "0.24", default-features = false, features = ["http1", "http2", "native-tokio", "tls12"], optional = true }
base64 = "0.22.1"
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
hyper = { version = "1.3.1", features = ["client", "http1", "http2"] }
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "tls12", "rustls-native-certs", "webpki-roots", "ring"], optional = true }
hyper-util = { version = "0.1.5", features = ["client", "client-legacy", "http1", "http2", "tokio"]}
http-body-util = "0.1.2"
ring = { version = "0.17", features = ["std"] }
rustls-pki-types = "1.1.0"
serde = { version = "1.0.104", features = ["derive"] }
Expand All @@ -27,7 +29,7 @@ thiserror = "1.0.30"
[dev-dependencies]
anyhow = "1.0.66"
clap = { version = "4.0.29", features = ["derive"] }
rcgen = "0.12"
rcgen = "0.12.1"
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
tokio = { version = "1.22.0", features = ["macros", "rt", "rt-multi-thread", "time"] }
tracing = "0.1.37"
tracing-subscriber = "0.3.16"
Expand Down
126 changes: 90 additions & 36 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ use std::pin::Pin;
use std::sync::Arc;

use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD};
use hyper::client::connect::Connect;
#[cfg(feature = "hyper-rustls")]
use hyper::client::HttpConnector;
use http_body_util::combinators::BoxBody;
use http_body_util::BodyExt;
use hyper::body::{Bytes, Incoming};
use hyper::header::{CONTENT_TYPE, LOCATION};
use hyper::{Body, Method, Request, Response, StatusCode};
use hyper::{Method, Request, Response, StatusCode};
use hyper_util::client::legacy::connect::Connect;
#[cfg(feature = "hyper-rustls")]
use hyper_util::client::legacy::connect::HttpConnector;
use ring::digest::{digest, SHA256};
use ring::rand::SystemRandom;
use ring::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING};
Expand Down Expand Up @@ -134,9 +137,13 @@ impl Order {
.await?;

self.nonce = nonce_from_response(&rsp);
let body = hyper::body::to_bytes(Problem::from_response(rsp).await?).await?;
let body_bytes = Problem::from_response(rsp)
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
.await?
.collect()
.await?
.to_bytes();
Ok(Some(
String::from_utf8(body.to_vec())
String::from_utf8(body_bytes.to_vec())
.map_err(|_| "unable to decode certificate as UTF-8")?,
))
}
Expand Down Expand Up @@ -419,7 +426,7 @@ impl AccountInner {
payload: Option<&impl Serialize>,
nonce: Option<String>,
url: &str,
) -> Result<Response<Body>, Error> {
) -> Result<Response<Incoming>, Error> {
self.client.post(payload, nonce, self, url).await
}
}
Expand Down Expand Up @@ -448,16 +455,20 @@ struct Client {
}

impl Client {
async fn new(server_url: &str, http: Box<dyn HttpClient>) -> Result<Self, Error> {
async fn new(directory_url: &str, http: Box<dyn HttpClient>) -> Result<Self, Error> {
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
let req = Request::builder()
.uri(server_url)
.body(Body::empty())
.unwrap();
.uri(directory_url)
.body(
http_body_util::Empty::new()
.map_err::<_, Error>(|_| unreachable!("Should be Infallible"))
.boxed(),
)
.expect("Infallible error should not occur");
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
let rsp = http.request(req).await?;
let body = hyper::body::to_bytes(rsp.into_body()).await?;
let body_bytes = rsp.into_body().collect().await?.to_bytes();
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
Ok(Client {
http,
urls: serde_json::from_slice(&body)?,
urls: serde_json::from_slice(&body_bytes)?,
})
}

Expand All @@ -467,15 +478,18 @@ impl Client {
nonce: Option<String>,
signer: &impl Signer,
url: &str,
) -> Result<Response<Body>, Error> {
) -> Result<Response<hyper::body::Incoming>, Error> {
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
let nonce = self.nonce(nonce).await?;
let body = JoseJson::new(payload, signer.header(Some(&nonce), url), signer)?;
let request = Request::builder()
.method(Method::POST)
.uri(url)
.header(CONTENT_TYPE, JOSE_JSON)
.body(Body::from(serde_json::to_vec(&body)?))
.unwrap();
.body(
http_body_util::Full::from(serde_json::to_vec(&body)?)
.map_err::<_, Error>(|_| unreachable!("Should be Infallible"))
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
.boxed(),
)?;

Ok(self.http.request(request).await?)
}
Expand All @@ -488,8 +502,12 @@ impl Client {
let request = Request::builder()
.method(Method::HEAD)
.uri(&self.urls.new_nonce)
.body(Body::empty())
.unwrap();
.body(
http_body_util::Empty::new()
.map_err::<_, Error>(|_| unreachable!("Should be Infallible"))
.boxed(),
)
.expect("Should be Infallible");
kellpossible marked this conversation as resolved.
Show resolved Hide resolved

let rsp = self.http.request(request).await?;
// https://datatracker.ietf.org/doc/html/rfc8555#section-7.2
Expand Down Expand Up @@ -650,21 +668,35 @@ impl Signer for ExternalAccountKey {
}
}

fn nonce_from_response(rsp: &Response<Body>) -> Option<String> {
fn nonce_from_response(rsp: &Response<Incoming>) -> Option<String> {
rsp.headers()
.get(REPLAY_NONCE)
.and_then(|hv| String::from_utf8(hv.as_ref().to_vec()).ok())
}

#[cfg(feature = "hyper-rustls")]
struct DefaultClient(hyper::Client<hyper_rustls::HttpsConnector<HttpConnector>>);
struct DefaultClient(
hyper_util::client::legacy::Client<
hyper_rustls::HttpsConnector<HttpConnector>,
BoxBody<Bytes, Error>,
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
>,
);

#[cfg(feature = "hyper-rustls")]
impl HttpClient for DefaultClient {
fn request(
&self,
req: Request<Body>,
) -> Pin<Box<dyn Future<Output = hyper::Result<Response<Body>>> + Send>> {
req: Request<BoxBody<Bytes, Error>>,
) -> Pin<
Box<
dyn Future<
Output = Result<
Response<hyper::body::Incoming>,
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
hyper_util::client::legacy::Error,
>,
> + Send,
>,
> {
Box::pin(self.0.request(req))
}
}
Expand All @@ -673,14 +705,18 @@ impl HttpClient for DefaultClient {
impl Default for DefaultClient {
fn default() -> Self {
Self(
hyper::Client::builder().build(
hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()
.https_only()
.enable_http1()
.enable_http2()
.build(),
),
hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new())
.build(
hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()
.unwrap_or_else(|_| {
hyper_rustls::HttpsConnectorBuilder::new().with_webpki_roots()
})
.https_only()
.enable_http1()
.enable_http2()
.build(),
),
)
}
}
Expand All @@ -690,19 +726,37 @@ pub trait HttpClient: Send + Sync + 'static {
/// Send the given request and return the response
fn request(
&self,
req: Request<Body>,
) -> Pin<Box<dyn Future<Output = hyper::Result<Response<Body>>> + Send>>;
req: Request<BoxBody<Bytes, Error>>,
) -> Pin<
Box<
dyn Future<
Output = Result<
Response<hyper::body::Incoming>,
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
hyper_util::client::legacy::Error,
>,
> + Send,
>,
>;
}

impl<C> HttpClient for hyper::Client<C>
impl<C> HttpClient for hyper_util::client::legacy::Client<C, BoxBody<Bytes, Error>>
where
C: Connect + Clone + Send + Sync + 'static,
{
fn request(
&self,
req: Request<Body>,
) -> Pin<Box<dyn Future<Output = hyper::Result<Response<Body>>> + Send>> {
Box::pin(<hyper::Client<C>>::request(self, req))
req: Request<BoxBody<Bytes, Error>>,
) -> Pin<
Box<
dyn Future<
Output = Result<
Response<hyper::body::Incoming>,
hyper_util::client::legacy::Error,
>,
> + Send,
>,
> {
Box::pin(<hyper_util::client::legacy::Client<C, BoxBody<Bytes, Error>>>::request(self, req))
}
}

Expand Down
25 changes: 18 additions & 7 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::fmt;

use base64::prelude::{Engine, BASE64_URL_SAFE_NO_PAD};
use hyper::{Body, Response};
use http_body_util::combinators::BoxBody;
use http_body_util::BodyExt;
use hyper::body::{Bytes, Incoming};
use hyper::Response;
use ring::digest::{digest, Digest, SHA256};
use ring::signature::{EcdsaKeyPair, KeyPair};
use rustls_pki_types::CertificateDer;
Expand Down Expand Up @@ -30,6 +33,12 @@ pub enum Error {
/// HTTP request failure
#[error("HTTP request failure: {0}")]
Http(#[from] hyper::Error),
/// HTTP request failure
#[error("HTTP request failure: {0}")]
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
HttpHttp(#[from] hyper::http::Error),
djc marked this conversation as resolved.
Show resolved Hide resolved
/// HTTP client request failure
#[error("HTTP request failure: {0}")]
HttpClient(#[from] hyper_util::client::legacy::Error),
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
/// Invalid ACME server URL
#[error("invalid URI: {0}")]
InvalidUri(#[from] hyper::http::uri::InvalidUri),
Expand Down Expand Up @@ -119,21 +128,23 @@ pub struct Problem {
}

impl Problem {
pub(crate) async fn check<T: DeserializeOwned>(rsp: Response<Body>) -> Result<T, Error> {
pub(crate) async fn check<T: DeserializeOwned>(rsp: Response<Incoming>) -> Result<T, Error> {
Ok(serde_json::from_slice(
&hyper::body::to_bytes(Self::from_response(rsp).await?).await?,
&Self::from_response(rsp).await?.collect().await?.to_bytes(),
)?)
}

pub(crate) async fn from_response(rsp: Response<Body>) -> Result<Body, Error> {
pub(crate) async fn from_response(
rsp: Response<Incoming>,
) -> Result<BoxBody<Bytes, Error>, Error> {
let status = rsp.status();
let body = rsp.into_body();
if status.is_informational() || status.is_success() || status.is_redirection() {
return Ok(body);
return Ok(body.map_err::<_, Error>(|_| unreachable!()).boxed());
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
}

let body = hyper::body::to_bytes(body).await?;
Err(serde_json::from_slice::<Problem>(&body)?.into())
let body_bytes = body.collect().await?.to_bytes();
kellpossible marked this conversation as resolved.
Show resolved Hide resolved
Err(serde_json::from_slice::<Problem>(&body_bytes)?.into())
}
}

Expand Down
Loading