1use http::header::CONTENT_TYPE;
26use http::{Request, Response, Version};
27use pin_project::pin_project;
28use std::fmt;
29use std::future::Future;
30use std::pin::Pin;
31use std::task::{Context, Poll, ready};
32use tower_layer::Layer;
33use tower_service::Service;
34use tracing::debug;
35
36use crate::call::GrpcWebCall;
37use crate::call::content_types::GRPC_WEB;
38
39#[derive(Debug, Default, Clone)]
41pub struct GrpcWebClientLayer {
42 _priv: (),
43}
44
45impl GrpcWebClientLayer {
46 pub fn new() -> GrpcWebClientLayer {
48 Self::default()
49 }
50}
51
52impl<S> Layer<S> for GrpcWebClientLayer {
53 type Service = GrpcWebClientService<S>;
54
55 fn layer(&self, inner: S) -> Self::Service {
56 GrpcWebClientService::new(inner)
57 }
58}
59
60#[derive(Debug, Clone)]
64pub struct GrpcWebClientService<S> {
65 inner: S,
66}
67
68impl<S> GrpcWebClientService<S> {
69 pub fn new(inner: S) -> Self {
71 Self { inner }
72 }
73}
74
75impl<S, B1, B2> Service<Request<B1>> for GrpcWebClientService<S>
76where
77 S: Service<Request<GrpcWebCall<B1>>, Response = Response<B2>>,
78{
79 type Response = Response<GrpcWebCall<B2>>;
80 type Error = S::Error;
81 type Future = ResponseFuture<S::Future>;
82
83 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
84 self.inner.poll_ready(cx)
85 }
86
87 fn call(&mut self, mut req: Request<B1>) -> Self::Future {
88 if req.version() == Version::HTTP_2 {
89 debug!("coercing HTTP2 request to HTTP1.1");
90
91 *req.version_mut() = Version::HTTP_11;
92 }
93
94 req.headers_mut()
95 .insert(CONTENT_TYPE, GRPC_WEB.try_into().unwrap());
96
97 let req = req.map(GrpcWebCall::client_request);
98
99 let fut = self.inner.call(req);
100
101 ResponseFuture { inner: fut }
102 }
103}
104
105#[pin_project]
107#[must_use = "futures do nothing unless polled"]
108pub struct ResponseFuture<F> {
109 #[pin]
110 inner: F,
111}
112
113impl<F, B, E> Future for ResponseFuture<F>
114where
115 F: Future<Output = Result<Response<B>, E>>,
116{
117 type Output = Result<Response<GrpcWebCall<B>>, E>;
118
119 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
120 let res = ready!(self.project().inner.poll(cx));
121
122 Poll::Ready(res.map(|r| r.map(GrpcWebCall::client_response)))
123 }
124}
125
126impl<F> fmt::Debug for ResponseFuture<F> {
127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128 f.debug_struct("ResponseFuture").finish()
129 }
130}