Update http body
This commit is contained in:
@@ -25,7 +25,7 @@ pub fn client(attr: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> #service_ident <T>
|
impl<T> #service_ident <T>
|
||||||
where T: tonic::GrpcService<tonic::body::BoxAsyncBody>,
|
where T: tonic::GrpcService<tonic::body::BoxBody>,
|
||||||
T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static,
|
T::ResponseBody: tonic::body::Body + tonic::_codegen::HttpBody + Send + 'static,
|
||||||
<T::ResponseBody as tonic::_codegen::HttpBody>::Error: Into<tonic::error::Error> + Send,
|
<T::ResponseBody as tonic::_codegen::HttpBody>::Error: Into<tonic::error::Error> + Send,
|
||||||
<T::ResponseBody as tonic::_codegen::HttpBody>::Data: Send, {
|
<T::ResponseBody as tonic::_codegen::HttpBody>::Data: Send, {
|
||||||
@@ -36,6 +36,14 @@ pub fn client(attr: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
#methods
|
#methods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> Clone for #service_ident <T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TokenStream::from(output)
|
TokenStream::from(output)
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ pub(crate) fn generate(service: ServiceDef) -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Service<http::Request<tower_h2::RecvBody>> for #service_server {
|
impl Service<http::Request<tower_h2::RecvBody>> for #service_server {
|
||||||
type Response = http::Response<tonic::BoxAsyncBody>;
|
type Response = http::Response<tonic::BoxBody>;
|
||||||
type Error = tonic::error::Never;
|
type Error = tonic::error::Never;
|
||||||
type Future = BoxFuture<Self::Response, Self::Error>;
|
type Future = BoxFuture<Self::Response, Self::Error>;
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -19,7 +19,8 @@ percent-encoding = "1.0.1"
|
|||||||
tower-service = { git = "https://github.com/tower-rs/tower", branch = "std-future" }
|
tower-service = { git = "https://github.com/tower-rs/tower", branch = "std-future" }
|
||||||
tokio-codec = "=0.2.0-alpha.1"
|
tokio-codec = "=0.2.0-alpha.1"
|
||||||
async-stream = "0.1.0"
|
async-stream = "0.1.0"
|
||||||
http-body = { git = "https://github.com/hyperium/http-body", branch = "std-future" }
|
http-body = { git = "https://github.com/hyperium/http-body", branch = "lucio/pin" }
|
||||||
|
pin-project = "0.4.0-alpha.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = "=0.2.0-alpha.1"
|
tokio = "=0.2.0-alpha.1"
|
||||||
|
|||||||
+51
-77
@@ -1,9 +1,10 @@
|
|||||||
use crate::{Code, Error, Status};
|
use crate::{Code, Error, Status};
|
||||||
use bytes::{Buf, Bytes, IntoBuf};
|
use bytes::{Buf, Bytes, IntoBuf};
|
||||||
use futures_core::{Stream, TryStream};
|
use futures_core::Stream;
|
||||||
use futures_util::{ready, TryStreamExt};
|
use futures_util::{ready, TryStreamExt};
|
||||||
use http::HeaderMap;
|
use http::HeaderMap;
|
||||||
use http_body::Body as HttpBody;
|
use http_body::Body as HttpBody;
|
||||||
|
use pin_project::pin_project;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
@@ -13,12 +14,15 @@ pub trait Body: sealed::Sealed {
|
|||||||
type Data: Buf;
|
type Data: Buf;
|
||||||
type Error: Into<Error>;
|
type Error: Into<Error>;
|
||||||
|
|
||||||
fn is_end_stream(&self) -> bool;
|
fn is_end_stream(self: Pin<&mut Self>) -> bool;
|
||||||
|
|
||||||
fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>>;
|
fn poll_data(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Self::Data, Self::Error>>>;
|
||||||
|
|
||||||
fn poll_trailers(
|
fn poll_trailers(
|
||||||
&mut self,
|
self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>>;
|
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>>;
|
||||||
}
|
}
|
||||||
@@ -31,16 +35,19 @@ where
|
|||||||
type Data = T::Data;
|
type Data = T::Data;
|
||||||
type Error = T::Error;
|
type Error = T::Error;
|
||||||
|
|
||||||
fn is_end_stream(&self) -> bool {
|
fn is_end_stream(self: Pin<&mut Self>) -> bool {
|
||||||
HttpBody::is_end_stream(self)
|
HttpBody::is_end_stream(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
fn poll_data(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
||||||
HttpBody::poll_data(self, cx)
|
HttpBody::poll_data(self, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_trailers(
|
fn poll_trailers(
|
||||||
&mut self,
|
self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
|
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
|
||||||
HttpBody::poll_trailers(self, cx)
|
HttpBody::poll_trailers(self, cx)
|
||||||
@@ -59,17 +66,25 @@ mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct BoxBody {
|
pub struct BoxBody {
|
||||||
inner: Box<dyn Body<Data = BytesBuf, Error = Status> + Send>,
|
inner: Pin<Box<dyn HttpBody<Data = BytesBuf, Error = Status> + Send + 'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxBody {
|
impl BoxBody {
|
||||||
|
pub fn from_stream<S>(s: S) -> Self
|
||||||
|
where
|
||||||
|
S: Stream<Item = Result<crate::body::BytesBuf, Status>> + Send + 'static,
|
||||||
|
{
|
||||||
|
let body = AsyncBody::new(s);
|
||||||
|
Self::map_from(body)
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new `BoxBody` mapping item and error to the default types.
|
/// Create a new `BoxBody` mapping item and error to the default types.
|
||||||
pub fn map_from<B>(inner: B) -> Self
|
pub fn map_from<B>(inner: B) -> Self
|
||||||
where
|
where
|
||||||
B: Body<Data = BytesBuf, Error = Status> + Send + 'static,
|
B: HttpBody<Data = BytesBuf, Error = Status> + Send + 'static,
|
||||||
{
|
{
|
||||||
BoxBody {
|
BoxBody {
|
||||||
inner: Box::new(inner),
|
inner: Box::pin(inner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,85 +93,36 @@ impl HttpBody for BoxBody {
|
|||||||
type Data = BytesBuf;
|
type Data = BytesBuf;
|
||||||
type Error = Status;
|
type Error = Status;
|
||||||
|
|
||||||
fn is_end_stream(&self) -> bool {
|
fn is_end_stream(mut self: Pin<&mut Self>) -> bool {
|
||||||
self.inner.is_end_stream()
|
HttpBody::is_end_stream(self.inner.as_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
fn poll_data(
|
||||||
self.inner.poll_data(cx)
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
||||||
|
HttpBody::poll_data(self.inner.as_mut(), cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_trailers(
|
fn poll_trailers(
|
||||||
&mut self,
|
mut self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
|
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
|
||||||
self.inner.poll_trailers(cx)
|
HttpBody::poll_trailers(self.inner.as_mut(), cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BoxAsyncBody {
|
#[pin_project]
|
||||||
inner: Pin<Box<dyn Stream<Item = Result<BytesBuf, Status>> + Send>>,
|
|
||||||
error: Option<Status>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BoxAsyncBody {
|
|
||||||
// pub fn new<S>(inner: S) -> Self
|
|
||||||
// where
|
|
||||||
// S: Stream<Item = Result<crate::body::BytesBuf, Status>> + Send + 'static,
|
|
||||||
// {
|
|
||||||
// Self {
|
|
||||||
// inner: Box::pin(inner),
|
|
||||||
// error: None,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn new_try<S>(inner: S) -> Self
|
|
||||||
where
|
|
||||||
S: TryStream<Ok = BytesBuf, Error = Status> + Send + 'static,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
inner: Box::pin(inner.into_stream()),
|
|
||||||
error: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HttpBody for BoxAsyncBody {
|
|
||||||
type Data = BytesBuf;
|
|
||||||
type Error = Status;
|
|
||||||
|
|
||||||
fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
|
||||||
match ready!(self.inner.try_poll_next_unpin(cx)) {
|
|
||||||
Some(Ok(d)) => Some(Ok(d)).into(),
|
|
||||||
Some(Err(status)) => {
|
|
||||||
self.error = Some(status);
|
|
||||||
None.into()
|
|
||||||
}
|
|
||||||
None => None.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn poll_trailers(&mut self, _cx: &mut Context<'_>) -> Poll<Result<Option<HeaderMap>, Status>> {
|
|
||||||
let status = if let Some(status) = self.error.take() {
|
|
||||||
status
|
|
||||||
} else {
|
|
||||||
Status::new(Code::Ok, "")
|
|
||||||
};
|
|
||||||
|
|
||||||
Poll::Ready(Ok(Some(status.to_header_map()?)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: refactor this to accept an !Unpin stream
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct AsyncBody<S> {
|
pub struct AsyncBody<S> {
|
||||||
|
#[pin]
|
||||||
inner: S,
|
inner: S,
|
||||||
error: Option<Status>,
|
error: Option<Status>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> AsyncBody<S>
|
impl<S> AsyncBody<S>
|
||||||
where
|
where
|
||||||
S: Stream<Item = Result<crate::body::BytesBuf, Status>> + Unpin,
|
S: Stream<Item = Result<crate::body::BytesBuf, Status>>,
|
||||||
{
|
{
|
||||||
pub fn new(inner: S) -> Self {
|
pub fn new(inner: S) -> Self {
|
||||||
Self { inner, error: None }
|
Self { inner, error: None }
|
||||||
@@ -165,24 +131,32 @@ where
|
|||||||
|
|
||||||
impl<S> HttpBody for AsyncBody<S>
|
impl<S> HttpBody for AsyncBody<S>
|
||||||
where
|
where
|
||||||
S: Stream<Item = Result<crate::body::BytesBuf, Status>> + Unpin,
|
S: Stream<Item = Result<crate::body::BytesBuf, Status>>,
|
||||||
{
|
{
|
||||||
type Data = BytesBuf;
|
type Data = BytesBuf;
|
||||||
type Error = Status;
|
type Error = Status;
|
||||||
|
|
||||||
fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
fn poll_data(
|
||||||
match ready!(self.inner.try_poll_next_unpin(cx)) {
|
self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
||||||
|
let mut self_proj = self.project();
|
||||||
|
match ready!(self_proj.inner.try_poll_next_unpin(cx)) {
|
||||||
Some(Ok(d)) => Some(Ok(d)).into(),
|
Some(Ok(d)) => Some(Ok(d)).into(),
|
||||||
Some(Err(status)) => {
|
Some(Err(status)) => {
|
||||||
self.error = Some(status);
|
*self_proj.error = Some(status);
|
||||||
None.into()
|
None.into()
|
||||||
}
|
}
|
||||||
None => None.into(),
|
None => None.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_trailers(&mut self, _cx: &mut Context<'_>) -> Poll<Result<Option<HeaderMap>, Status>> {
|
fn poll_trailers(
|
||||||
let status = if let Some(status) = self.error.take() {
|
self: Pin<&mut Self>,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Result<Option<HeaderMap>, Status>> {
|
||||||
|
let self_proj = self.project();
|
||||||
|
let status = if let Some(status) = self_proj.error.take() {
|
||||||
status
|
status
|
||||||
} else {
|
} else {
|
||||||
Status::new(Code::Ok, "")
|
Status::new(Code::Ok, "")
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
body::{Body, BoxAsyncBody},
|
body::{Body, BoxBody},
|
||||||
codec::{decode, encode, Codec, Streaming},
|
codec::{decode, encode, Codec, Streaming},
|
||||||
Code, GrpcService, Request, Response, Status,
|
Code, GrpcService, Request, Response, Status,
|
||||||
};
|
};
|
||||||
@@ -27,7 +27,7 @@ impl<T> Grpc<T> {
|
|||||||
codec: C,
|
codec: C,
|
||||||
) -> Result<Response<M2>, Status>
|
) -> Result<Response<M2>, Status>
|
||||||
where
|
where
|
||||||
T: GrpcService<BoxAsyncBody>,
|
T: GrpcService<BoxBody>,
|
||||||
T::ResponseBody: Body + HttpBody + Send + 'static,
|
T::ResponseBody: Body + HttpBody + Send + 'static,
|
||||||
<T::ResponseBody as HttpBody>::Error: Into<crate::Error> + Send,
|
<T::ResponseBody as HttpBody>::Error: Into<crate::Error> + Send,
|
||||||
<T::ResponseBody as HttpBody>::Data: Send,
|
<T::ResponseBody as HttpBody>::Data: Send,
|
||||||
@@ -48,7 +48,7 @@ impl<T> Grpc<T> {
|
|||||||
codec: C,
|
codec: C,
|
||||||
) -> Result<Response<M2>, Status>
|
) -> Result<Response<M2>, Status>
|
||||||
where
|
where
|
||||||
T: GrpcService<BoxAsyncBody>,
|
T: GrpcService<BoxBody>,
|
||||||
T::ResponseBody: Body + HttpBody + Send + 'static,
|
T::ResponseBody: Body + HttpBody + Send + 'static,
|
||||||
<T::ResponseBody as HttpBody>::Error: Into<crate::Error> + Send,
|
<T::ResponseBody as HttpBody>::Error: Into<crate::Error> + Send,
|
||||||
<T::ResponseBody as HttpBody>::Data: Send,
|
<T::ResponseBody as HttpBody>::Data: Send,
|
||||||
@@ -78,7 +78,7 @@ impl<T> Grpc<T> {
|
|||||||
codec: C,
|
codec: C,
|
||||||
) -> Result<Response<Streaming<M2>>, Status>
|
) -> Result<Response<Streaming<M2>>, Status>
|
||||||
where
|
where
|
||||||
T: GrpcService<BoxAsyncBody>,
|
T: GrpcService<BoxBody>,
|
||||||
T::ResponseBody: Body + HttpBody + Send + 'static,
|
T::ResponseBody: Body + HttpBody + Send + 'static,
|
||||||
<T::ResponseBody as HttpBody>::Error: Into<crate::Error> + Send,
|
<T::ResponseBody as HttpBody>::Error: Into<crate::Error> + Send,
|
||||||
<T::ResponseBody as HttpBody>::Data: Send,
|
<T::ResponseBody as HttpBody>::Data: Send,
|
||||||
@@ -99,7 +99,7 @@ impl<T> Grpc<T> {
|
|||||||
mut codec: C,
|
mut codec: C,
|
||||||
) -> Result<Response<Streaming<M2>>, Status>
|
) -> Result<Response<Streaming<M2>>, Status>
|
||||||
where
|
where
|
||||||
T: GrpcService<BoxAsyncBody>,
|
T: GrpcService<BoxBody>,
|
||||||
T::ResponseBody: Body + HttpBody + Send + 'static,
|
T::ResponseBody: Body + HttpBody + Send + 'static,
|
||||||
<T::ResponseBody as HttpBody>::Error: Into<crate::Error> + Send,
|
<T::ResponseBody as HttpBody>::Error: Into<crate::Error> + Send,
|
||||||
<T::ResponseBody as HttpBody>::Data: Send,
|
<T::ResponseBody as HttpBody>::Data: Send,
|
||||||
@@ -116,8 +116,8 @@ impl<T> Grpc<T> {
|
|||||||
let uri = Uri::from_parts(parts).expect("path_and_query only is valid Uri");
|
let uri = Uri::from_parts(parts).expect("path_and_query only is valid Uri");
|
||||||
|
|
||||||
let request = request
|
let request = request
|
||||||
.map(|s| encode(codec.encoder(), Box::pin(s)))
|
.map(|s| encode(codec.encoder(), Box::pin(s)).into_stream())
|
||||||
.map(BoxAsyncBody::new_try);
|
.map(BoxBody::from_stream);
|
||||||
|
|
||||||
let mut request = request.into_http(uri);
|
let mut request = request.into_http(uri);
|
||||||
|
|
||||||
@@ -155,3 +155,11 @@ impl<T> Grpc<T> {
|
|||||||
Ok(Response::from_http(response))
|
Ok(Response::from_http(response))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Clone> Clone for Grpc<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ where
|
|||||||
yield Ok(item);
|
yield Ok(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
let chunk = match future::poll_fn(|cx| source.poll_data(cx)).await {
|
// FIXME: Figure out how to verify that this is safe
|
||||||
|
let chunk = match future::poll_fn(|cx| unsafe { std::pin::Pin::new_unchecked(&mut source) }.poll_data(cx)).await {
|
||||||
Some(Ok(d)) => Some(d),
|
Some(Ok(d)) => Some(d),
|
||||||
Some(Err(e)) => {
|
Some(Err(e)) => {
|
||||||
let err = e.into();
|
let err = e.into();
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ mod response;
|
|||||||
mod service;
|
mod service;
|
||||||
mod status;
|
mod status;
|
||||||
|
|
||||||
pub use body::{BoxAsyncBody, BoxBody};
|
pub use body::BoxBody;
|
||||||
pub use request::Request;
|
pub use request::Request;
|
||||||
pub use response::Response;
|
pub use response::Response;
|
||||||
pub use service::GrpcService;
|
pub use service::GrpcService;
|
||||||
|
|||||||
+11
-11
@@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
body::{BoxAsyncBody, BytesBuf},
|
body::{BytesBuf, BoxBody},
|
||||||
codec::{decode, encode, Codec, Streaming},
|
codec::{decode, encode, Codec, Streaming},
|
||||||
server::{ClientStreamingService, ServerStreamingService, StreamingService, UnaryService},
|
server::{ClientStreamingService, ServerStreamingService, StreamingService, UnaryService},
|
||||||
Code, Request, Response, Status,
|
Code, Request, Response, Status,
|
||||||
@@ -31,7 +31,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
mut service: S,
|
mut service: S,
|
||||||
req: http::Request<B>,
|
req: http::Request<B>,
|
||||||
) -> http::Response<BoxAsyncBody>
|
) -> http::Response<BoxBody>
|
||||||
where
|
where
|
||||||
S: UnaryService<T::Decode, Response = T::Encode>,
|
S: UnaryService<T::Decode, Response = T::Encode>,
|
||||||
B: Body + Send + 'static,
|
B: Body + Send + 'static,
|
||||||
@@ -45,7 +45,7 @@ where
|
|||||||
.map_response::<stream::Once<future::Ready<Result<T::Encode, Status>>>>(Err(
|
.map_response::<stream::Once<future::Ready<Result<T::Encode, Status>>>>(Err(
|
||||||
status,
|
status,
|
||||||
))
|
))
|
||||||
.map(BoxAsyncBody::new_try);
|
.map(BoxBody::from_stream);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,14 +54,14 @@ where
|
|||||||
.await
|
.await
|
||||||
.map(|r| r.map(|m| stream::once(future::ok(m))));
|
.map(|r| r.map(|m| stream::once(future::ok(m))));
|
||||||
|
|
||||||
self.map_response(response).map(BoxAsyncBody::new_try)
|
self.map_response(response).map(BoxBody::from_stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn server_streaming<S, B>(
|
pub async fn server_streaming<S, B>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut service: S,
|
mut service: S,
|
||||||
req: http::Request<B>,
|
req: http::Request<B>,
|
||||||
) -> http::Response<BoxAsyncBody>
|
) -> http::Response<BoxBody>
|
||||||
where
|
where
|
||||||
S: ServerStreamingService<T::Decode, Response = T::Encode>,
|
S: ServerStreamingService<T::Decode, Response = T::Encode>,
|
||||||
S::ResponseStream: Send + 'static,
|
S::ResponseStream: Send + 'static,
|
||||||
@@ -74,13 +74,13 @@ where
|
|||||||
Err(status) => {
|
Err(status) => {
|
||||||
return self
|
return self
|
||||||
.map_response::<S::ResponseStream>(Err(status))
|
.map_response::<S::ResponseStream>(Err(status))
|
||||||
.map(BoxAsyncBody::new_try);
|
.map(BoxBody::from_stream);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = service.call(request).await;
|
let response = service.call(request).await;
|
||||||
|
|
||||||
self.map_response(response).map(BoxAsyncBody::new_try)
|
self.map_response(response).map(BoxBody::from_stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
//BoxStream<T::Decode>,
|
//BoxStream<T::Decode>,
|
||||||
@@ -88,7 +88,7 @@ where
|
|||||||
&mut self,
|
&mut self,
|
||||||
mut service: S,
|
mut service: S,
|
||||||
req: http::Request<B>,
|
req: http::Request<B>,
|
||||||
) -> http::Response<BoxAsyncBody>
|
) -> http::Response<BoxBody>
|
||||||
where
|
where
|
||||||
S: ClientStreamingService<Streaming<T::Decode>, Response = T::Encode>,
|
S: ClientStreamingService<Streaming<T::Decode>, Response = T::Encode>,
|
||||||
T::Decode: Send + 'static,
|
T::Decode: Send + 'static,
|
||||||
@@ -102,14 +102,14 @@ where
|
|||||||
.call(request)
|
.call(request)
|
||||||
.await
|
.await
|
||||||
.map(|r| r.map(|m| stream::once(future::ok(m))));
|
.map(|r| r.map(|m| stream::once(future::ok(m))));
|
||||||
self.map_response(response).map(BoxAsyncBody::new_try)
|
self.map_response(response).map(BoxBody::from_stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn streaming<S, B>(
|
pub async fn streaming<S, B>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut service: S,
|
mut service: S,
|
||||||
req: http::Request<B>,
|
req: http::Request<B>,
|
||||||
) -> http::Response<BoxAsyncBody>
|
) -> http::Response<BoxBody>
|
||||||
where
|
where
|
||||||
S: StreamingService<Streaming<T::Decode>, Response = T::Encode> + Send,
|
S: StreamingService<Streaming<T::Decode>, Response = T::Encode> + Send,
|
||||||
S::ResponseStream: Send + 'static,
|
S::ResponseStream: Send + 'static,
|
||||||
@@ -119,7 +119,7 @@ where
|
|||||||
{
|
{
|
||||||
let request = self.map_request_streaming(req);
|
let request = self.map_request_streaming(req);
|
||||||
let response = service.call(request).await;
|
let response = service.call(request).await;
|
||||||
self.map_response(response).map(BoxAsyncBody::new_try)
|
self.map_response(response).map(BoxBody::from_stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn map_request_unary<B>(
|
async fn map_request_unary<B>(
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
#![feature(async_await, type_alias_impl_trait)]
|
|
||||||
|
|
||||||
use futures_core::Stream;
|
|
||||||
use futures_util::future;
|
|
||||||
use std::future::Future;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::task::{Context, Poll};
|
|
||||||
use tokio::net::TcpListener;
|
|
||||||
use tonic::{
|
|
||||||
body,
|
|
||||||
server::{ClientStreamingService, Grpc, UnaryService},
|
|
||||||
Request, Response, Status,
|
|
||||||
};
|
|
||||||
use tower_h2::{RecvBody, Server};
|
|
||||||
use tower_service::Service;
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, prost::Message)]
|
|
||||||
pub struct HelloRequest {
|
|
||||||
#[prost(string, tag = "1")]
|
|
||||||
pub name: std::string::String,
|
|
||||||
}
|
|
||||||
/// The response message containing the greetings
|
|
||||||
#[derive(Clone, PartialEq, prost::Message)]
|
|
||||||
pub struct HelloReply {
|
|
||||||
#[prost(string, tag = "1")]
|
|
||||||
pub message: std::string::String,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SayHello;
|
|
||||||
|
|
||||||
impl UnaryService<HelloRequest> for SayHello {
|
|
||||||
type Response = HelloReply;
|
|
||||||
type Future = impl Future<Output = Result<Response<Self::Response>, Status>>;
|
|
||||||
|
|
||||||
fn call(&mut self, request: Request<HelloRequest>) -> Self::Future {
|
|
||||||
async move {
|
|
||||||
println!("REQUEST = {:?}", request);
|
|
||||||
|
|
||||||
let reply = HelloReply {
|
|
||||||
message: "Zomg, it works!".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Response::new(reply))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SayHelloStream;
|
|
||||||
|
|
||||||
impl<S> ClientStreamingService<S> for SayHelloStream
|
|
||||||
where
|
|
||||||
S: Stream<Item = Result<HelloRequest, Status>> + Unpin + Send + 'static,
|
|
||||||
{
|
|
||||||
type Response = HelloReply;
|
|
||||||
// type Future = impl Future<Output = Result<Response<Self::Response>, Status>>;
|
|
||||||
type Future =
|
|
||||||
Pin<Box<dyn Future<Output = Result<Response<Self::Response>, Status>> + Send + 'static>>;
|
|
||||||
|
|
||||||
fn call(&mut self, _req: Request<S>) -> Self::Future {
|
|
||||||
let fut = async move {
|
|
||||||
Ok(Response::new(HelloReply {
|
|
||||||
message: "hello".into(),
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
Box::pin(fut)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn main() {
|
|
||||||
let addr = "[::1]:50051".parse().unwrap();
|
|
||||||
let mut bind = TcpListener::bind(&addr).unwrap();
|
|
||||||
|
|
||||||
let mut server = Server::new(MakeSvc, Default::default());
|
|
||||||
|
|
||||||
while let Ok((sock, _addr)) = bind.accept().await {
|
|
||||||
if let Err(e) = sock.set_nodelay(true) {
|
|
||||||
panic!("error: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = server.serve(sock).await {
|
|
||||||
println!("H2 ERROR: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Svc;
|
|
||||||
|
|
||||||
impl Service<http::Request<RecvBody>> for Svc {
|
|
||||||
type Response = http::Response<body::BoxAsyncBody>;
|
|
||||||
type Error = tonic::error::Never;
|
|
||||||
// type Future = impl Future<Output = Result<Self::Response, Self::Error>>;
|
|
||||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
|
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Ok(()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&mut self, req: http::Request<RecvBody>) -> Self::Future {
|
|
||||||
match req.uri().path() {
|
|
||||||
"/greeter.Helloworld/SayHello" => {
|
|
||||||
let fut = async move {
|
|
||||||
let codec = tonic::codec::ProstCodec::new();
|
|
||||||
let mut grpc = Grpc::new(codec);
|
|
||||||
let response = grpc.unary(SayHello, req).await;
|
|
||||||
Ok(response)
|
|
||||||
};
|
|
||||||
|
|
||||||
Box::pin(fut)
|
|
||||||
}
|
|
||||||
|
|
||||||
"/greeter.Helloworld/SayHelloStreaming" => {
|
|
||||||
let fut = async move {
|
|
||||||
let codec = tonic::codec::ProstCodec::new();
|
|
||||||
let mut grpc = Grpc::new(codec);
|
|
||||||
let response = grpc.client_streaming(SayHelloStream, req).await;
|
|
||||||
Ok(response)
|
|
||||||
};
|
|
||||||
|
|
||||||
Box::pin(fut)
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => unimplemented!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MakeSvc;
|
|
||||||
|
|
||||||
impl Service<()> for MakeSvc {
|
|
||||||
type Response = Svc;
|
|
||||||
type Error = std::io::Error;
|
|
||||||
type Future = future::Ready<Result<Self::Response, Self::Error>>;
|
|
||||||
|
|
||||||
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
||||||
Ok(()).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&mut self, _: ()) -> Self::Future {
|
|
||||||
future::ok(Svc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
#![feature(async_await, type_alias_impl_trait)]
|
|
||||||
|
|
||||||
use futures_core::Stream;
|
|
||||||
use std::future::Future;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::task::{Context, Poll};
|
|
||||||
use tokio_buf::BufStream;
|
|
||||||
use tonic::codec::ProstCodec;
|
|
||||||
use tonic::server::*;
|
|
||||||
use tonic::{Request, Response, Status};
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, prost::Message)]
|
|
||||||
pub struct HelloRequest {
|
|
||||||
#[prost(string, tag = "1")]
|
|
||||||
pub name: std::string::String,
|
|
||||||
}
|
|
||||||
/// The response message containing the greetings
|
|
||||||
#[derive(Clone, PartialEq, prost::Message)]
|
|
||||||
pub struct HelloReply {
|
|
||||||
#[prost(string, tag = "1")]
|
|
||||||
pub message: std::string::String,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SayHello;
|
|
||||||
|
|
||||||
impl UnaryService<HelloRequest> for SayHello {
|
|
||||||
type Response = HelloReply;
|
|
||||||
type Future = impl Future<Output = Result<Response<Self::Response>, Status>>;
|
|
||||||
|
|
||||||
fn call(&mut self, _request: Request<HelloRequest>) -> Self::Future {
|
|
||||||
async move {
|
|
||||||
Ok(Response::new(HelloReply {
|
|
||||||
message: "hello".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SayHelloStream;
|
|
||||||
|
|
||||||
impl<S> ClientStreamingService<S> for SayHelloStream
|
|
||||||
where
|
|
||||||
S: Stream<Item = Result<HelloRequest, Status>> + Unpin + Send + 'static,
|
|
||||||
{
|
|
||||||
type Response = HelloReply;
|
|
||||||
// type Future = impl Future<Output = Result<Response<Self::Response>, Status>>;
|
|
||||||
type Future =
|
|
||||||
Pin<Box<dyn Future<Output = Result<Response<Self::Response>, Status>> + Send + 'static>>;
|
|
||||||
|
|
||||||
fn call(&mut self, _: Request<S>) -> Self::Future {
|
|
||||||
let fut = async move {
|
|
||||||
Ok(Response::new(HelloReply {
|
|
||||||
message: "hello".into(),
|
|
||||||
}))
|
|
||||||
};
|
|
||||||
Box::pin(fut)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn say_hello() {
|
|
||||||
let codec = ProstCodec::new();
|
|
||||||
let mut grpc = Grpc::new(codec);
|
|
||||||
|
|
||||||
let request = http::Request::new(Body(Vec::new()));
|
|
||||||
grpc.unary(SayHello, request).await;
|
|
||||||
|
|
||||||
let request = http::Request::new(Body(Vec::new()));
|
|
||||||
grpc.client_streaming(SayHelloStream, request).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
|
||||||
struct Body(Vec<u8>);
|
|
||||||
|
|
||||||
impl From<Vec<u8>> for Body {
|
|
||||||
fn from(t: Vec<u8>) -> Self {
|
|
||||||
Body(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BufStream for Body {
|
|
||||||
type Item = std::io::Cursor<Vec<u8>>;
|
|
||||||
type Error = std::io::Error;
|
|
||||||
|
|
||||||
fn poll_buf(&mut self, _cx: &mut Context<'_>) -> Poll<Option<Result<Self::Item, Self::Error>>> {
|
|
||||||
if self.0.is_empty() {
|
|
||||||
return None.into();
|
|
||||||
}
|
|
||||||
|
|
||||||
use std::{io, mem};
|
|
||||||
|
|
||||||
let bytes = mem::replace(&mut self.0, Default::default());
|
|
||||||
let buf = io::Cursor::new(bytes);
|
|
||||||
|
|
||||||
Some(Ok(buf)).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -14,7 +14,7 @@ tower-service = { git = "http://github.com/tower-rs/tower", branch = "std-future
|
|||||||
tower-util = { git = "http://github.com/tower-rs/tower", branch = "std-future" }
|
tower-util = { git = "http://github.com/tower-rs/tower", branch = "std-future" }
|
||||||
h2 = { git = "https://github.com/LucioFranco/h2", branch = "lucio/tower-h2-hack" }
|
h2 = { git = "https://github.com/LucioFranco/h2", branch = "lucio/tower-h2-hack" }
|
||||||
http = "0.1"
|
http = "0.1"
|
||||||
http-body = { git = "https://github.com/hyperium/http-body", branch = "std-future" }
|
http-body = { git = "https://github.com/hyperium/http-body", branch = "lucio/pin" }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
use http::Request;
|
use http::Request;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio_buf::BufStream;
|
|
||||||
use tower_h2::Connection;
|
use tower_h2::Connection;
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
@@ -30,11 +30,14 @@ impl From<Vec<u8>> for Body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BufStream for Body {
|
impl http_body::Body for Body {
|
||||||
type Item = std::io::Cursor<Vec<u8>>;
|
type Data = std::io::Cursor<Vec<u8>>;
|
||||||
type Error = std::io::Error;
|
type Error = std::io::Error;
|
||||||
|
|
||||||
fn poll_buf(&mut self, _cx: &mut Context<'_>) -> Poll<Option<Result<Self::Item, Self::Error>>> {
|
fn poll_data(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
||||||
if self.0.is_empty() {
|
if self.0.is_empty() {
|
||||||
return None.into();
|
return None.into();
|
||||||
}
|
}
|
||||||
@@ -46,4 +49,11 @@ impl BufStream for Body {
|
|||||||
|
|
||||||
Some(Ok(buf)).into()
|
Some(Ok(buf)).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn poll_trailers(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
|
||||||
|
Ok(None).into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use futures_util::future;
|
|||||||
use http::{Request, Response};
|
use http::{Request, Response};
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
use tokio_buf::BufStream;
|
use std::pin::Pin;
|
||||||
use tower_h2::{RecvBody, Server};
|
use tower_h2::{RecvBody, Server};
|
||||||
use tower_service::Service;
|
use tower_service::Service;
|
||||||
|
|
||||||
@@ -84,11 +84,14 @@ impl From<Vec<u8>> for Body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BufStream for Body {
|
impl http_body::Body for Body {
|
||||||
type Item = std::io::Cursor<Vec<u8>>;
|
type Data = std::io::Cursor<Vec<u8>>;
|
||||||
type Error = std::io::Error;
|
type Error = std::io::Error;
|
||||||
|
|
||||||
fn poll_buf(&mut self, _cx: &mut Context<'_>) -> Poll<Option<Result<Self::Item, Self::Error>>> {
|
fn poll_data(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Self::Data, Self::Error>>> {
|
||||||
if self.0.is_empty() {
|
if self.0.is_empty() {
|
||||||
return None.into();
|
return None.into();
|
||||||
}
|
}
|
||||||
@@ -100,4 +103,11 @@ impl BufStream for Body {
|
|||||||
|
|
||||||
Some(Ok(buf)).into()
|
Some(Ok(buf)).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn poll_trailers(
|
||||||
|
self: Pin<&mut Self>,
|
||||||
|
_cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Result<Option<http::HeaderMap>, Self::Error>> {
|
||||||
|
Ok(None).into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,10 +57,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, request: Request<B>) -> Self::Future {
|
fn call(&mut self, request: Request<B>) -> Self::Future {
|
||||||
let (parts, body) = request.into_parts();
|
let (parts, mut body) = request.into_parts();
|
||||||
let request = Request::from_parts(parts, ());
|
let request = Request::from_parts(parts, ());
|
||||||
|
|
||||||
let eos = body.is_end_stream();
|
let eos = Pin::new(&mut body).is_end_stream();
|
||||||
|
|
||||||
let res = self.client.send_request(request, eos);
|
let res = self.client.send_request(request, eos);
|
||||||
|
|
||||||
|
|||||||
+14
-13
@@ -13,7 +13,7 @@ where
|
|||||||
S: Body,
|
S: Body,
|
||||||
{
|
{
|
||||||
h2: SendStream<SendBuf<S::Data>>,
|
h2: SendStream<SendBuf<S::Data>>,
|
||||||
body: S,
|
body: Pin<Box<dyn Body<Data = S::Data, Error = S::Error> + Send + 'static>>,
|
||||||
state: FlushState,
|
state: FlushState,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,13 +32,13 @@ enum DataOrTrailers<B> {
|
|||||||
|
|
||||||
impl<S> Flush<S>
|
impl<S> Flush<S>
|
||||||
where
|
where
|
||||||
S: Body,
|
S: Body + Send + 'static,
|
||||||
S::Error: Into<Box<dyn std::error::Error>>,
|
S::Error: Into<Box<dyn std::error::Error>>,
|
||||||
{
|
{
|
||||||
pub fn new(src: S, dst: SendStream<SendBuf<S::Data>>) -> Self {
|
pub fn new(src: S, dst: SendStream<SendBuf<S::Data>>) -> Self {
|
||||||
Flush {
|
Flush {
|
||||||
h2: dst,
|
h2: dst,
|
||||||
body: src,
|
body: Box::pin(src),
|
||||||
state: FlushState::Data,
|
state: FlushState::Data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@ where
|
|||||||
loop {
|
loop {
|
||||||
match ready!(self.poll_body(cx)) {
|
match ready!(self.poll_body(cx)) {
|
||||||
Some(Ok(Data(buf))) => {
|
Some(Ok(Data(buf))) => {
|
||||||
let eos = self.body.is_end_stream();
|
let eos = Pin::new(&mut self.body).is_end_stream();
|
||||||
|
|
||||||
self.h2.send_data(SendBuf::new(buf), eos)?;
|
self.h2.send_data(SendBuf::new(buf), eos)?;
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let item = match ready!(self.body.poll_data(cx)) {
|
let item = match ready!(Pin::new(&mut self.body).poll_data(cx)) {
|
||||||
Some(Ok(d)) => Some(d),
|
Some(Ok(d)) => Some(d),
|
||||||
Some(Err(err)) => {
|
Some(Err(err)) => {
|
||||||
let err = err.into();
|
let err = err.into();
|
||||||
@@ -162,13 +162,14 @@ where
|
|||||||
// before we get a RST_STREAM.
|
// before we get a RST_STREAM.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let trailers = ready!(self.body.poll_trailers(cx).map_err(|err| {
|
let trailers =
|
||||||
let err = err.into();
|
ready!(Pin::new(&mut self.body).poll_trailers(cx).map_err(|err| {
|
||||||
debug!("user body error from poll_trailers: {}", err);
|
let err = err.into();
|
||||||
let reason = crate::error::reason_from_dyn_error(&*err);
|
debug!("user body error from poll_trailers: {}", err);
|
||||||
self.h2.send_reset(reason);
|
let reason = crate::error::reason_from_dyn_error(&*err);
|
||||||
reason
|
self.h2.send_reset(reason);
|
||||||
}))?;
|
reason
|
||||||
|
}))?;
|
||||||
self.state = FlushState::Done;
|
self.state = FlushState::Done;
|
||||||
if let Some(trailers) = trailers {
|
if let Some(trailers) = trailers {
|
||||||
return Some(Ok(DataOrTrailers::Trailers(trailers))).into();
|
return Some(Ok(DataOrTrailers::Trailers(trailers))).into();
|
||||||
@@ -182,7 +183,7 @@ where
|
|||||||
|
|
||||||
impl<S> Future for Flush<S>
|
impl<S> Future for Flush<S>
|
||||||
where
|
where
|
||||||
S: Body + Unpin,
|
S: Body + Send + 'static,
|
||||||
S::Error: Into<Box<dyn std::error::Error>>,
|
S::Error: Into<Box<dyn std::error::Error>>,
|
||||||
{
|
{
|
||||||
type Output = Result<(), ()>;
|
type Output = Result<(), ()>;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use bytes::{Buf, Bytes, BytesMut};
|
use bytes::{Buf, Bytes, BytesMut};
|
||||||
use futures_util::TryStreamExt;
|
use futures_util::TryStreamExt;
|
||||||
use http_body::Body;
|
use http_body::Body;
|
||||||
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
/// Allows a stream to be read from the remote.
|
/// Allows a stream to be read from the remote.
|
||||||
@@ -33,11 +34,14 @@ impl Body for RecvBody {
|
|||||||
type Data = Data;
|
type Data = Data;
|
||||||
type Error = h2::Error;
|
type Error = h2::Error;
|
||||||
|
|
||||||
fn is_end_stream(&self) -> bool {
|
fn is_end_stream(self: Pin<&mut Self>) -> bool {
|
||||||
self.inner.is_end_stream()
|
self.inner.is_end_stream()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Self::Data, h2::Error>>> {
|
fn poll_data(
|
||||||
|
mut self: Pin<&mut Self>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> Poll<Option<Result<Self::Data, h2::Error>>> {
|
||||||
let data = match futures_util::ready!(self.inner.try_poll_next_unpin(cx)) {
|
let data = match futures_util::ready!(self.inner.try_poll_next_unpin(cx)) {
|
||||||
Some(Ok(bytes)) => {
|
Some(Ok(bytes)) => {
|
||||||
self.inner
|
self.inner
|
||||||
@@ -54,7 +58,7 @@ impl Body for RecvBody {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll_trailers(
|
fn poll_trailers(
|
||||||
&mut self,
|
mut self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
) -> Poll<Result<Option<http::HeaderMap>, h2::Error>> {
|
) -> Poll<Result<Option<http::HeaderMap>, h2::Error>> {
|
||||||
match futures_util::ready!(self.inner.poll_trailers(cx)) {
|
match futures_util::ready!(self.inner.poll_trailers(cx)) {
|
||||||
|
|||||||
@@ -86,10 +86,10 @@ pub async fn handle_request<B>(
|
|||||||
B::Data: Unpin,
|
B::Data: Unpin,
|
||||||
B::Error: Into<Box<dyn std::error::Error>>,
|
B::Error: Into<Box<dyn std::error::Error>>,
|
||||||
{
|
{
|
||||||
let (parts, body) = response.into_parts();
|
let (parts, mut body) = response.into_parts();
|
||||||
|
|
||||||
// Check if the response is imemdiately an end-of-stream.
|
// Check if the response is imemdiately an end-of-stream.
|
||||||
let eos = body.is_end_stream();
|
let eos = std::pin::Pin::new(&mut body).is_end_stream();
|
||||||
|
|
||||||
let response = Response::from_parts(parts, ());
|
let response = Response::from_parts(parts, ());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user