Skip to content

Commit aee2e80

Browse files
committed
Avoid http-body-util in public API
1 parent 313f13b commit aee2e80

File tree

4 files changed

+57
-24
lines changed

4 files changed

+57
-24
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ allowed_external_types = [
7474
"bytes::*",
7575
"http::*",
7676
"http_body::*",
77-
"http_body_util::*",
7877
"hyper::*",
7978
"rustls_pki_types::*",
8079
"serde::*",

src/account.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,22 @@ use base64::prelude::{BASE64_URL_SAFE_NO_PAD, Engine};
66
use http::header::LOCATION;
77
#[cfg(feature = "time")]
88
use http::{Method, Request};
9-
#[cfg(feature = "time")]
10-
use http_body_util::Full;
119
use rustls_pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
1210
use serde::de::DeserializeOwned;
1311
use serde::{Deserialize, Serialize};
1412

1513
#[cfg(feature = "hyper-rustls")]
1614
use crate::DefaultClient;
1715
use crate::order::Order;
18-
#[cfg(feature = "time")]
19-
use crate::retry_after;
2016
use crate::types::{
2117
AccountCredentials, AuthorizationStatus, Empty, Header, JoseJson, Jwk, KeyOrKeyId, NewAccount,
2218
NewAccountPayload, NewOrder, OrderState, Problem, ProfileMeta, RevocationRequest, Signer,
2319
SigningAlgorithm,
2420
};
2521
#[cfg(feature = "time")]
2622
use crate::types::{CertificateIdentifier, RenewalInfo};
23+
#[cfg(feature = "time")]
24+
use crate::{BodyWrapper, retry_after};
2725
use crate::{BytesResponse, Client, Error, HttpClient, crypto, nonce_from_response};
2826

2927
/// An ACME account as described in RFC 8555 (section 7.1.2)
@@ -169,10 +167,9 @@ impl Account {
169167
let request = Request::builder()
170168
.method(Method::GET)
171169
.uri(format!("{renewal_info_url}/{certificate_id}"))
172-
.body(Full::default())?;
170+
.body(BodyWrapper::default())?;
173171

174172
let rsp = self.inner.client.http.request(request).await?;
175-
176173
let Some(retry_after) = retry_after(&rsp) else {
177174
return Err(Error::Str("missing Retry-After header"));
178175
};

src/lib.rs

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,21 @@
44
#![warn(missing_docs)]
55
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
66

7+
use std::convert::Infallible;
78
use std::error::Error as StdError;
89
use std::fmt;
910
use std::future::Future;
1011
use std::pin::Pin;
1112
use std::str::FromStr;
13+
use std::task::{Context, Poll};
1214
use std::time::{Duration, SystemTime};
1315

1416
use async_trait::async_trait;
15-
use bytes::Bytes;
17+
use bytes::{Buf, Bytes};
1618
use http::header::{CONTENT_TYPE, RETRY_AFTER};
1719
use http::{Method, Request, Response, StatusCode};
18-
use http_body_util::{BodyExt, Full};
20+
use http_body::{Frame, SizeHint};
21+
use http_body_util::BodyExt;
1922
use httpdate::HttpDate;
2023
#[cfg(feature = "hyper-rustls")]
2124
use hyper::body::Incoming;
@@ -56,7 +59,7 @@ impl Client {
5659
async fn new(directory_url: String, http: Box<dyn HttpClient>) -> Result<Self, Error> {
5760
let req = Request::builder()
5861
.uri(&directory_url)
59-
.body(Full::default())
62+
.body(BodyWrapper::default())
6063
.expect("infallible error should not occur");
6164
let rsp = http.request(req).await?;
6265
let body = rsp.body().await.map_err(Error::Other)?;
@@ -117,7 +120,7 @@ impl Client {
117120
.method(Method::POST)
118121
.uri(url)
119122
.header(CONTENT_TYPE, JOSE_JSON)
120-
.body(Full::from(serde_json::to_vec(&body)?))?;
123+
.body(BodyWrapper::from(serde_json::to_vec(&body)?))?;
121124

122125
self.http.request(request).await
123126
}
@@ -130,7 +133,7 @@ impl Client {
130133
let request = Request::builder()
131134
.method(Method::HEAD)
132135
.uri(&self.directory.new_nonce)
133-
.body(Full::default())
136+
.body(BodyWrapper::default())
134137
.expect("infallible error should not occur");
135138

136139
let rsp = self.http.request(request).await?;
@@ -187,7 +190,7 @@ fn retry_after(rsp: &BytesResponse) -> Option<SystemTime> {
187190
}
188191

189192
#[cfg(feature = "hyper-rustls")]
190-
struct DefaultClient(HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, Full<Bytes>>);
193+
struct DefaultClient(HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, BodyWrapper<Bytes>>);
191194

192195
#[cfg(feature = "hyper-rustls")]
193196
impl DefaultClient {
@@ -210,7 +213,7 @@ impl DefaultClient {
210213
impl HttpClient for DefaultClient {
211214
fn request(
212215
&self,
213-
req: Request<Full<Bytes>>,
216+
req: Request<BodyWrapper<Bytes>>,
214217
) -> Pin<Box<dyn Future<Output = Result<BytesResponse, Error>> + Send>> {
215218
let fut = self.0.request(req);
216219
Box::pin(async move { BytesResponse::try_from(fut.await) })
@@ -222,15 +225,15 @@ pub trait HttpClient: Send + Sync + 'static {
222225
/// Send the given request and return the response
223226
fn request(
224227
&self,
225-
req: Request<Full<Bytes>>,
228+
req: Request<BodyWrapper<Bytes>>,
226229
) -> Pin<Box<dyn Future<Output = Result<BytesResponse, Error>> + Send>>;
227230
}
228231

229232
#[cfg(feature = "hyper-rustls")]
230-
impl<C: Connect + Clone + Send + Sync + 'static> HttpClient for HyperClient<C, Full<Bytes>> {
233+
impl<C: Connect + Clone + Send + Sync + 'static> HttpClient for HyperClient<C, BodyWrapper<Bytes>> {
231234
fn request(
232235
&self,
233-
req: Request<Full<Bytes>>,
236+
req: Request<BodyWrapper<Bytes>>,
234237
) -> Pin<Box<dyn Future<Output = Result<BytesResponse, Error>> + Send>> {
235238
let fut = self.request(req);
236239
Box::pin(async move { BytesResponse::try_from(fut.await) })
@@ -276,7 +279,9 @@ where
276279
}
277280
}
278281

279-
struct BodyWrapper<B> {
282+
/// A simple HTTP body wrapper type
283+
#[derive(Default)]
284+
pub struct BodyWrapper<B> {
280285
inner: Option<B>,
281286
}
282287

@@ -299,6 +304,37 @@ where
299304
}
300305
}
301306

307+
impl http_body::Body for BodyWrapper<Bytes> {
308+
type Data = Bytes;
309+
type Error = Infallible;
310+
311+
fn poll_frame(
312+
mut self: Pin<&mut Self>,
313+
_cx: &mut Context<'_>,
314+
) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
315+
Poll::Ready(self.inner.take().map(|d| Ok(Frame::data(d))))
316+
}
317+
318+
fn is_end_stream(&self) -> bool {
319+
self.inner.is_none()
320+
}
321+
322+
fn size_hint(&self) -> SizeHint {
323+
match self.inner.as_ref() {
324+
Some(data) => SizeHint::with_exact(u64::try_from(data.remaining()).unwrap()),
325+
None => SizeHint::with_exact(0),
326+
}
327+
}
328+
}
329+
330+
impl From<Vec<u8>> for BodyWrapper<Bytes> {
331+
fn from(data: Vec<u8>) -> Self {
332+
BodyWrapper {
333+
inner: Some(Bytes::from(data)),
334+
}
335+
}
336+
}
337+
302338
#[async_trait]
303339
impl BytesBody for Bytes {
304340
async fn into_bytes(&mut self) -> Result<Bytes, Box<dyn StdError + Send + Sync + 'static>> {

tests/pebble.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ use base64::prelude::BASE64_URL_SAFE_NO_PAD;
1919
use bytes::{Buf, Bytes};
2020
use http::header::CONTENT_TYPE;
2121
use http::{Method, Request};
22-
use http_body_util::{BodyExt, Full};
22+
use http_body_util::BodyExt;
2323
use hyper_util::client::legacy::Client as HyperClient;
2424
use hyper_util::client::legacy::connect::HttpConnector;
2525
use hyper_util::rt::TokioExecutor;
2626
use instant_acme::{
27-
Account, AuthorizationStatus, ChallengeHandle, ChallengeType, Error, ExternalAccountKey,
28-
Identifier, Key, KeyAuthorization, NewAccount, NewOrder, Order, OrderStatus, RetryPolicy,
27+
Account, AuthorizationStatus, BodyWrapper, ChallengeHandle, ChallengeType, Error,
28+
ExternalAccountKey, Identifier, Key, KeyAuthorization, NewAccount, NewOrder, Order,
29+
OrderStatus, RetryPolicy,
2930
};
3031
#[cfg(all(feature = "time", feature = "x509-parser"))]
3132
use instant_acme::{CertificateIdentifier, RevocationRequest};
@@ -469,7 +470,7 @@ struct Environment {
469470
pebble: Subprocess,
470471
#[allow(dead_code)] // Held for the lifetime of the environment.
471472
challtestsrv: Subprocess,
472-
client: HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, Full<Bytes>>,
473+
client: HyperClient<hyper_rustls::HttpsConnector<HttpConnector>, BodyWrapper<Bytes>>,
473474
}
474475

475476
impl Environment {
@@ -681,7 +682,7 @@ impl Environment {
681682
&self.config.pebble.management_listen_address
682683
))
683684
.header(CONTENT_TYPE, "application/json")
684-
.body(Full::default())?;
685+
.body(BodyWrapper::default())?;
685686

686687
let resp = self.client.request(req).await?;
687688
if resp.status() != 200 {
@@ -712,7 +713,7 @@ impl Environment {
712713
.method(Method::POST)
713714
.uri(url)
714715
.header(CONTENT_TYPE, "application/json")
715-
.body(Full::from(body))?,
716+
.body(BodyWrapper::from(body))?,
716717
)
717718
.await?;
718719
Ok(())

0 commit comments

Comments
 (0)