1use crate::{
2 HttpBody, WireRequest, WireResponse,
3 capability::Upstream,
4 codec::{self, CodecError, CodecErrorKind, CodecLimits},
5 transform::{TransformError, TransformErrorKind},
6 wire::DeclaredFields,
7};
8use serde::{Serialize, de::DeserializeOwned};
9
10#[derive(Debug)]
13pub enum JsonInvocation<T> {
14 Success(WireResponse<T>),
15 Rejected(WireResponse<HttpBody>),
16}
17
18pub async fn invoke_json<U, I, O>(
26 upstream: &U,
27 target: &U::Target,
28 request: WireRequest<I>,
29 limits: CodecLimits,
30) -> Result<JsonInvocation<O>, TransformError>
31where
32 U: Upstream,
33 I: Serialize + DeclaredFields,
34 O: DeserializeOwned + DeclaredFields,
35{
36 let WireRequest {
37 method,
38 path,
39 query,
40 mut headers,
41 body,
42 } = request;
43
44 let host_limits = upstream.limits();
45 let write_limits = bound_limits(limits, host_limits.write_bytes);
46 let body = codec::encode_json(&body.into_declared(), write_limits)
47 .map_err(|error| codec_error(error, false))?;
48 for name in [
50 http::header::CONTENT_LENGTH,
51 http::header::CONTENT_ENCODING,
52 http::header::TRANSFER_ENCODING,
53 ] {
54 headers.remove(name);
55 }
56 headers.insert(
57 http::header::CONTENT_TYPE,
58 http::HeaderValue::from_static("application/json"),
59 );
60 let response = upstream
61 .send(
62 target,
63 WireRequest {
64 method,
65 path,
66 query,
67 headers,
68 body: HttpBody::Bytes(body),
69 },
70 )
71 .await?;
72 receive_json(response, limits, host_limits.read_bytes).await
73}
74
75pub async fn invoke_empty<U, O>(
79 upstream: &U,
80 target: &U::Target,
81 request: WireRequest<()>,
82 limits: CodecLimits,
83) -> Result<JsonInvocation<O>, TransformError>
84where
85 U: Upstream,
86 O: DeserializeOwned + DeclaredFields,
87{
88 let WireRequest {
89 method,
90 path,
91 query,
92 mut headers,
93 body: (),
94 } = request;
95 for name in [
96 http::header::CONTENT_TYPE,
97 http::header::CONTENT_LENGTH,
98 http::header::CONTENT_ENCODING,
99 http::header::TRANSFER_ENCODING,
100 ] {
101 headers.remove(name);
102 }
103 let response = upstream
104 .send(
105 target,
106 WireRequest {
107 method,
108 path,
109 query,
110 headers,
111 body: HttpBody::Bytes(bytes::Bytes::new()),
112 },
113 )
114 .await?;
115 receive_json(response, limits, upstream.limits().read_bytes).await
116}
117
118async fn receive_json<O: DeserializeOwned + DeclaredFields>(
119 response: WireResponse<HttpBody>,
120 limits: CodecLimits,
121 read_bytes: u64,
122) -> Result<JsonInvocation<O>, TransformError> {
123 if !response.status.is_success() {
124 return Ok(JsonInvocation::Rejected(response));
125 }
126 let WireResponse {
127 status,
128 mut headers,
129 body,
130 } = response;
131 let limits = bound_limits(limits, read_bytes);
132 let bytes = codec::read_http_body(body, limits)
133 .await
134 .map_err(|error| codec_error(error, true))?;
135 let body: O = codec::decode_json(&bytes, limits).map_err(|error| codec_error(error, true))?;
136 for name in [
139 http::header::CONTENT_LENGTH,
140 http::header::CONTENT_ENCODING,
141 http::header::TRANSFER_ENCODING,
142 ] {
143 headers.remove(name);
144 }
145 headers.insert(
146 http::header::CONTENT_TYPE,
147 http::HeaderValue::from_static("application/json"),
148 );
149 Ok(JsonInvocation::Success(WireResponse {
150 status,
151 headers,
152 body: body.into_declared(),
153 }))
154}
155
156fn bound_limits(mut limits: CodecLimits, host_bytes: u64) -> CodecLimits {
157 limits.max_body_bytes = limits.max_body_bytes.min(host_bytes);
158 limits.max_buffer_bytes = limits.max_buffer_bytes.min(host_bytes);
159 limits.max_value_bytes = limits.max_value_bytes.min(host_bytes);
160 limits
161}
162
163fn codec_error(error: CodecError, response: bool) -> TransformError {
164 let kind = match error.kind() {
165 CodecErrorKind::Limit => TransformErrorKind::Limit,
166 CodecErrorKind::Transport => TransformErrorKind::Host,
167 CodecErrorKind::Invalid
168 | CodecErrorKind::UnexpectedEof
169 | CodecErrorKind::Utf8
170 | CodecErrorKind::Json
171 | CodecErrorKind::Multipart => {
172 if response {
173 TransformErrorKind::InvalidResult
174 } else {
175 TransformErrorKind::InvalidInput
176 }
177 }
178 };
179 let detail = error.to_string();
180 TransformError::with_source(
181 kind,
182 if response {
183 "upstream.response"
184 } else {
185 "upstream.request"
186 },
187 detail,
188 error,
189 )
190}