Skip to content

Commit c9b612f

Browse files
authored
Merge pull request #60 from yoshuawuyts/trailers
Trailers
2 parents 8de3fee + dcebb68 commit c9b612f

File tree

4 files changed

+97
-11
lines changed

4 files changed

+97
-11
lines changed

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ mod method;
120120
mod request;
121121
mod response;
122122
mod status_code;
123-
mod trailers;
124123
mod version;
125124

126125
pub use body::Body;
@@ -144,5 +143,8 @@ pub use crate::url::Url;
144143
#[doc(inline)]
145144
pub use crate::cookies::Cookie;
146145

146+
#[doc(inline)]
147+
pub mod trailers;
148+
147149
#[cfg(feature = "hyperium_http")]
148150
mod hyperium_http;

src/request.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use crate::headers::{
99
self, HeaderName, HeaderValue, Headers, Names, ToHeaderValues, Values, CONTENT_TYPE,
1010
};
1111
use crate::mime::Mime;
12+
use crate::trailers::{Trailers, TrailersSender};
1213
use crate::Cookie;
13-
use crate::Trailers;
1414
use crate::{Body, Method, Url, Version};
1515

1616
pin_project_lite::pin_project! {
@@ -30,7 +30,7 @@ pin_project_lite::pin_project! {
3030
url: Url,
3131
headers: Headers,
3232
version: Option<Version>,
33-
sender: sync::Sender<io::Result<Trailers>>,
33+
sender: Option<sync::Sender<io::Result<Trailers>>>,
3434
receiver: sync::Receiver<io::Result<Trailers>>,
3535
#[pin]
3636
body: Body,
@@ -47,7 +47,7 @@ impl Request {
4747
headers: Headers::new(),
4848
version: None,
4949
body: Body::empty(),
50-
sender,
50+
sender: Some(sender),
5151
receiver,
5252
}
5353
}
@@ -376,8 +376,12 @@ impl Request {
376376
}
377377

378378
/// Sends trailers to the a receiver.
379-
pub async fn send_trailers(&self, trailers: io::Result<Trailers>) {
380-
self.sender.send(trailers).await;
379+
pub fn send_trailers(&mut self) -> TrailersSender {
380+
let sender = self
381+
.sender
382+
.take()
383+
.expect("Trailers sender can only be constructed once");
384+
TrailersSender::new(sender)
381385
}
382386

383387
/// Receive trailers from a sender.

src/response.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::headers::{
99
self, HeaderName, HeaderValue, Headers, Names, ToHeaderValues, Values, CONTENT_TYPE,
1010
};
1111
use crate::mime::Mime;
12-
use crate::Trailers;
12+
use crate::trailers::{Trailers, TrailersSender};
1313
use crate::{Body, Cookie, StatusCode, Version};
1414

1515
pin_project_lite::pin_project! {
@@ -32,7 +32,7 @@ pin_project_lite::pin_project! {
3232
status: StatusCode,
3333
headers: Headers,
3434
version: Option<Version>,
35-
sender: sync::Sender<io::Result<Trailers>>,
35+
sender: Option<sync::Sender<io::Result<Trailers>>>,
3636
receiver: sync::Receiver<io::Result<Trailers>>,
3737
#[pin]
3838
body: Body,
@@ -48,7 +48,7 @@ impl Response {
4848
headers: Headers::new(),
4949
version: None,
5050
body: Body::empty(),
51-
sender,
51+
sender: Some(sender),
5252
receiver,
5353
}
5454
}
@@ -329,8 +329,12 @@ impl Response {
329329
}
330330

331331
/// Sends trailers to the a receiver.
332-
pub async fn send_trailers(&self, trailers: io::Result<Trailers>) {
333-
self.sender.send(trailers).await;
332+
pub fn send_trailers(&mut self) -> TrailersSender {
333+
let sender = self
334+
.sender
335+
.take()
336+
.expect("Trailers sender can only be constructed once");
337+
TrailersSender::new(sender)
334338
}
335339

336340
/// Receive trailers from a sender.

src/trailers.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,58 @@
1+
//! HTTP trailing headers.
2+
//!
3+
//! Trailing headers are headers that are send *after* the body payload has
4+
//! been sent. This is for example useful for sending integrity checks of
5+
//! streamed payloads that are computed on the fly.
6+
//!
7+
//! The way trailing headers are sent over the wire varies per protocol. But in
8+
//! `http-types` we provide a `Trailers` struct that's used to contain the headers.
9+
//!
10+
//! To send trailing headers, see `Request::{`[`send_trailers, `][req_send]
11+
//! [`recv_trailers`][req_recv]`}` and
12+
//! `Response::{`[`send_trailers, `][res_send][`recv_trailers`][res_recv]`}`.
13+
//!
14+
//! [req_send]: ../struct.Request.html#method.send_trailers
15+
//! [req_recv]: ../struct.Request.html#method.recv_trailers
16+
//! [res_send]: ../struct.Response.html#method.send_trailers
17+
//! [res_recv]: ../struct.Response.html#method.recv_trailers
18+
//!
19+
//! ## Example
20+
//!
21+
//! ```
22+
//! # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
23+
//! # async_std::task::block_on(async {
24+
//! #
25+
//! use http_types::{Url, Method, Request, Trailers};
26+
//! use http_types::headers::{HeaderName, HeaderValue};
27+
//! use async_std::task;
28+
//! use std::str::FromStr;
29+
//!
30+
//! let mut req = Request::new(Method::Get, Url::parse("https://example.com").unwrap());
31+
//!
32+
//! let sender = req.send_trailers();
33+
//! let mut trailers = Trailers::new();
34+
//! trailers.insert(
35+
//! HeaderName::from_str("Content-Type")?,
36+
//! "text/plain",
37+
//! );
38+
//!
39+
//! task::spawn(async move {
40+
//! let _trailers = req.recv_trailers().await;
41+
//! });
42+
//!
43+
//! sender.send(Ok(trailers)).await;
44+
//! #
45+
//! # Ok(()) })}
46+
//! ```
47+
//!
48+
//! ## See Also
49+
//! - [MDN HTTP Headers: Trailer](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Trailer)
50+
//! - [HTTP/2 spec: HTTP Sequence](https://http2.github.io/http2-spec/#HttpSequence)
51+
152
use crate::headers::{
253
HeaderName, HeaderValue, Headers, Iter, IterMut, Names, ToHeaderValues, Values,
354
};
55+
use async_std::sync::Sender;
456

557
use std::io;
658
use std::ops::{Deref, DerefMut};
@@ -96,3 +148,27 @@ impl DerefMut for Trailers {
96148
&mut self.headers
97149
}
98150
}
151+
152+
/// The sending half of a channel to send trailers.
153+
///
154+
/// Unlike `async_std::sync::channel` the `send` method on this type can only be
155+
/// called once, and cannot be cloned. That's because only a single instance of
156+
/// `Trailers` should be created.
157+
#[derive(Debug)]
158+
pub struct TrailersSender {
159+
sender: Sender<io::Result<Trailers>>,
160+
}
161+
162+
impl TrailersSender {
163+
/// Create a new instance of `TrailersSender`.
164+
pub(crate) fn new(sender: Sender<io::Result<Trailers>>) -> Self {
165+
Self { sender }
166+
}
167+
168+
/// Send a `Trailer`.
169+
///
170+
/// The channel will be consumed after having sent trailers.
171+
pub async fn send(self, trailers: io::Result<Trailers>) {
172+
self.sender.send(trailers).await
173+
}
174+
}

0 commit comments

Comments
 (0)