convex-rust 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +137 -2
  3. package/dist/cli/bin.d.ts +2 -0
  4. package/dist/cli/bin.js +200 -0
  5. package/dist/cli/build.d.ts +146 -0
  6. package/dist/cli/build.js +902 -0
  7. package/dist/cli/demangle.d.ts +7 -0
  8. package/dist/cli/demangle.js +328 -0
  9. package/dist/cli/diagnostics.d.ts +34 -0
  10. package/dist/cli/diagnostics.js +296 -0
  11. package/dist/cli/generate.d.ts +29 -0
  12. package/dist/cli/generate.js +82 -0
  13. package/dist/cli/manifest.d.ts +24 -0
  14. package/dist/cli/manifest.js +75 -0
  15. package/dist/cli/rustApi.d.ts +78 -0
  16. package/dist/cli/rustApi.js +609 -0
  17. package/dist/cli/scaffold.d.ts +22 -0
  18. package/dist/cli/scaffold.js +114 -0
  19. package/dist/cli/shim.d.ts +30 -0
  20. package/dist/cli/shim.js +140 -0
  21. package/dist/cli/size.d.ts +17 -0
  22. package/dist/cli/size.js +73 -0
  23. package/dist/cli/split.d.ts +20 -0
  24. package/dist/cli/split.js +140 -0
  25. package/dist/cli/symbols.d.ts +30 -0
  26. package/dist/cli/symbols.js +133 -0
  27. package/dist/cli/toolchain.d.ts +53 -0
  28. package/dist/cli/toolchain.js +167 -0
  29. package/dist/cli/validators.d.ts +6 -0
  30. package/dist/cli/validators.js +66 -0
  31. package/dist/cli/wasisdk.d.ts +82 -0
  32. package/dist/cli/wasisdk.js +220 -0
  33. package/dist/cli/wasmHints.d.ts +29 -0
  34. package/dist/cli/wasmHints.js +172 -0
  35. package/dist/runtime/base64.d.ts +4 -0
  36. package/dist/runtime/base64.js +77 -0
  37. package/dist/runtime/crypto.d.ts +7 -0
  38. package/dist/runtime/crypto.js +421 -0
  39. package/dist/runtime/fastjson.d.ts +3 -0
  40. package/dist/runtime/fastjson.js +170 -0
  41. package/dist/runtime/host.d.ts +73 -0
  42. package/dist/runtime/host.js +1230 -0
  43. package/dist/runtime/http.d.ts +40 -0
  44. package/dist/runtime/http.js +157 -0
  45. package/dist/runtime/index.d.ts +2 -0
  46. package/dist/runtime/index.js +1 -0
  47. package/dist/runtime/intl.d.ts +5 -0
  48. package/dist/runtime/intl.js +69 -0
  49. package/dist/runtime/tmpfs.d.ts +129 -0
  50. package/dist/runtime/tmpfs.js +624 -0
  51. package/dist/runtime/wasi.d.ts +33 -0
  52. package/dist/runtime/wasi.js +216 -0
  53. package/package.json +57 -4
  54. package/rust/convex_fn/Cargo.toml +32 -0
  55. package/rust/convex_fn/LICENSE +201 -0
  56. package/rust/convex_fn/build.rs +3 -0
  57. package/rust/convex_fn/src/args.rs +416 -0
  58. package/rust/convex_fn/src/crypto.rs +237 -0
  59. package/rust/convex_fn/src/ctx.rs +1044 -0
  60. package/rust/convex_fn/src/dns.rs +356 -0
  61. package/rust/convex_fn/src/error.rs +179 -0
  62. package/rust/convex_fn/src/executor.rs +577 -0
  63. package/rust/convex_fn/src/fanout.rs +106 -0
  64. package/rust/convex_fn/src/fs.rs +19 -0
  65. package/rust/convex_fn/src/function_ref.rs +219 -0
  66. package/rust/convex_fn/src/http.rs +441 -0
  67. package/rust/convex_fn/src/intl.rs +75 -0
  68. package/rust/convex_fn/src/lib.rs +242 -0
  69. package/rust/convex_fn/src/logging.rs +222 -0
  70. package/rust/convex_fn/src/native.rs +360 -0
  71. package/rust/convex_fn/src/net.rs +122 -0
  72. package/rust/convex_fn/src/sys.rs +178 -0
  73. package/rust/convex_fn/src/values.rs +121 -0
  74. package/rust/convex_fn/src/wire.rs +579 -0
  75. package/rust/convex_fn_macros/Cargo.toml +13 -0
  76. package/rust/convex_fn_macros/LICENSE +201 -0
  77. package/rust/convex_fn_macros/src/derive.rs +632 -0
  78. package/rust/convex_fn_macros/src/lib.rs +338 -0
  79. package/rust/convex_reqwest/Cargo.toml +69 -0
  80. package/rust/convex_reqwest/LICENSE +201 -0
  81. package/rust/convex_reqwest/src/blocking.rs +287 -0
  82. package/rust/convex_reqwest/src/body.rs +152 -0
  83. package/rust/convex_reqwest/src/client.rs +359 -0
  84. package/rust/convex_reqwest/src/config_types.rs +150 -0
  85. package/rust/convex_reqwest/src/error.rs +241 -0
  86. package/rust/convex_reqwest/src/into_url.rs +57 -0
  87. package/rust/convex_reqwest/src/lib.rs +42 -0
  88. package/rust/convex_reqwest/src/multipart.rs +140 -0
  89. package/rust/convex_reqwest/src/request.rs +358 -0
  90. package/rust/convex_reqwest/src/response.rs +310 -0
@@ -0,0 +1,358 @@
1
+ use std::{fmt, future::Future, time::Duration};
2
+
3
+ use base64::Engine;
4
+ use http::{
5
+ header::{HeaderMap, HeaderName, HeaderValue, AUTHORIZATION, CONTENT_TYPE},
6
+ Method, Version,
7
+ };
8
+ use serde::Serialize;
9
+ use url::Url;
10
+
11
+ use crate::{
12
+ body::Body,
13
+ client::Client,
14
+ error::{Error, Result},
15
+ multipart,
16
+ response::Response,
17
+ };
18
+
19
+ /// A request which can be executed with `Client::execute()`.
20
+ pub struct Request {
21
+ method: Method,
22
+ url: Url,
23
+ headers: HeaderMap,
24
+ body: Option<Body>,
25
+ timeout: Option<Duration>,
26
+ version: Version,
27
+ }
28
+
29
+ impl Request {
30
+ /// Constructs a new request.
31
+ pub fn new(method: Method, url: Url) -> Self {
32
+ Request {
33
+ method,
34
+ url,
35
+ headers: HeaderMap::new(),
36
+ body: None,
37
+ timeout: None,
38
+ version: Version::default(),
39
+ }
40
+ }
41
+
42
+ pub fn method(&self) -> &Method {
43
+ &self.method
44
+ }
45
+ pub fn method_mut(&mut self) -> &mut Method {
46
+ &mut self.method
47
+ }
48
+ pub fn url(&self) -> &Url {
49
+ &self.url
50
+ }
51
+ pub fn url_mut(&mut self) -> &mut Url {
52
+ &mut self.url
53
+ }
54
+ pub fn headers(&self) -> &HeaderMap {
55
+ &self.headers
56
+ }
57
+ pub fn headers_mut(&mut self) -> &mut HeaderMap {
58
+ &mut self.headers
59
+ }
60
+ pub fn body(&self) -> Option<&Body> {
61
+ self.body.as_ref()
62
+ }
63
+ pub fn body_mut(&mut self) -> &mut Option<Body> {
64
+ &mut self.body
65
+ }
66
+ pub fn timeout(&self) -> Option<&Duration> {
67
+ self.timeout.as_ref()
68
+ }
69
+ pub fn timeout_mut(&mut self) -> &mut Option<Duration> {
70
+ &mut self.timeout
71
+ }
72
+ pub fn version(&self) -> Version {
73
+ self.version
74
+ }
75
+ pub fn version_mut(&mut self) -> &mut Version {
76
+ &mut self.version
77
+ }
78
+
79
+ /// Attempts to clone the request; `None` if the body is a stream.
80
+ pub fn try_clone(&self) -> Option<Request> {
81
+ let body = match &self.body {
82
+ Some(b) => Some(b.try_clone()?),
83
+ None => None,
84
+ };
85
+ Some(Request {
86
+ method: self.method.clone(),
87
+ url: self.url.clone(),
88
+ headers: self.headers.clone(),
89
+ body,
90
+ timeout: self.timeout,
91
+ version: self.version,
92
+ })
93
+ }
94
+
95
+ pub(crate) fn into_parts(self) -> (Method, Url, HeaderMap, Option<Body>, Option<Duration>) {
96
+ (self.method, self.url, self.headers, self.body, self.timeout)
97
+ }
98
+ }
99
+
100
+ impl fmt::Debug for Request {
101
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102
+ f.debug_struct("Request")
103
+ .field("method", &self.method)
104
+ .field("url", &self.url.as_str())
105
+ .field("headers", &self.headers)
106
+ .finish()
107
+ }
108
+ }
109
+
110
+ impl<T: Into<Body>> TryFrom<http::Request<T>> for Request {
111
+ type Error = Error;
112
+
113
+ fn try_from(req: http::Request<T>) -> Result<Self> {
114
+ let (parts, body) = req.into_parts();
115
+ let url = Url::parse(&parts.uri.to_string()).map_err(Error::builder)?;
116
+ let mut r = Request::new(parts.method, url);
117
+ r.headers = parts.headers;
118
+ r.version = parts.version;
119
+ r.body = Some(body.into());
120
+ Ok(r)
121
+ }
122
+ }
123
+
124
+ impl From<Request> for http::Request<Body> {
125
+ fn from(req: Request) -> Self {
126
+ let mut r = http::Request::new(req.body.unwrap_or_default());
127
+ *r.method_mut() = req.method;
128
+ *r.uri_mut() = req.url.as_str().parse().expect("url is a valid uri");
129
+ *r.headers_mut() = req.headers;
130
+ *r.version_mut() = req.version;
131
+ r
132
+ }
133
+ }
134
+
135
+ /// A builder to construct the properties of a `Request`.
136
+ #[must_use = "RequestBuilder does nothing until you 'send' it"]
137
+ pub struct RequestBuilder {
138
+ client: Client,
139
+ request: Result<Request>,
140
+ }
141
+
142
+ impl RequestBuilder {
143
+ pub(crate) fn new(client: Client, request: Result<Request>) -> RequestBuilder {
144
+ RequestBuilder { client, request }
145
+ }
146
+
147
+ /// Assemble a builder starting from an existing `Client` and a `Request`.
148
+ pub fn from_parts(client: Client, request: Request) -> RequestBuilder {
149
+ RequestBuilder {
150
+ client,
151
+ request: Ok(request),
152
+ }
153
+ }
154
+
155
+ /// Add a `Header` to this Request.
156
+ pub fn header<K, V>(self, key: K, value: V) -> RequestBuilder
157
+ where
158
+ HeaderName: TryFrom<K>,
159
+ <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
160
+ HeaderValue: TryFrom<V>,
161
+ <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
162
+ {
163
+ self.header_sensitive(key, value, false)
164
+ }
165
+
166
+ fn header_sensitive<K, V>(mut self, key: K, value: V, sensitive: bool) -> RequestBuilder
167
+ where
168
+ HeaderName: TryFrom<K>,
169
+ <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
170
+ HeaderValue: TryFrom<V>,
171
+ <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
172
+ {
173
+ let mut error = None;
174
+ if let Ok(req) = &mut self.request {
175
+ match <HeaderName as TryFrom<K>>::try_from(key) {
176
+ Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
177
+ Ok(mut value) => {
178
+ value.set_sensitive(sensitive);
179
+ req.headers_mut().append(key, value);
180
+ }
181
+ Err(e) => error = Some(Error::builder(e.into())),
182
+ },
183
+ Err(e) => error = Some(Error::builder(e.into())),
184
+ }
185
+ }
186
+ if let Some(e) = error {
187
+ self.request = Err(e);
188
+ }
189
+ self
190
+ }
191
+
192
+ /// Add a set of Headers to the existing ones on this Request.
193
+ pub fn headers(mut self, headers: HeaderMap) -> RequestBuilder {
194
+ if let Ok(req) = &mut self.request {
195
+ for (k, v) in headers.iter() {
196
+ req.headers_mut().insert(k.clone(), v.clone());
197
+ }
198
+ }
199
+ self
200
+ }
201
+
202
+ /// Enable HTTP basic authentication.
203
+ pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder
204
+ where
205
+ U: fmt::Display,
206
+ P: fmt::Display,
207
+ {
208
+ let creds = match password {
209
+ Some(p) => format!("{username}:{p}"),
210
+ None => format!("{username}:"),
211
+ };
212
+ let value = format!(
213
+ "Basic {}",
214
+ base64::engine::general_purpose::STANDARD.encode(creds)
215
+ );
216
+ self.header_sensitive(AUTHORIZATION, value, true)
217
+ }
218
+
219
+ /// Enable HTTP bearer authentication.
220
+ pub fn bearer_auth<T: fmt::Display>(self, token: T) -> RequestBuilder {
221
+ self.header_sensitive(AUTHORIZATION, format!("Bearer {token}"), true)
222
+ }
223
+
224
+ /// Set the request body.
225
+ pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
226
+ if let Ok(req) = &mut self.request {
227
+ *req.body_mut() = Some(body.into());
228
+ }
229
+ self
230
+ }
231
+
232
+ /// Enables a request timeout (covers the response body too).
233
+ pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
234
+ if let Ok(req) = &mut self.request {
235
+ *req.timeout_mut() = Some(timeout);
236
+ }
237
+ self
238
+ }
239
+
240
+ /// Sends a multipart/form-data body.
241
+ pub fn multipart(self, form: multipart::Form) -> RequestBuilder {
242
+ let ct = format!("multipart/form-data; boundary={}", form.boundary());
243
+ let mut b = self.header(CONTENT_TYPE, ct);
244
+ if let Ok(req) = &mut b.request {
245
+ *req.body_mut() = Some(Body::from(form.into_bytes()));
246
+ }
247
+ b
248
+ }
249
+
250
+ /// Modify the query string of the URL.
251
+ pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
252
+ let mut error = None;
253
+ if let Ok(req) = &mut self.request {
254
+ let url = req.url_mut();
255
+ let mut pairs = url.query_pairs_mut();
256
+ let serializer = serde_urlencoded::Serializer::new(&mut pairs);
257
+ if let Err(err) = query.serialize(serializer) {
258
+ error = Some(Error::builder(err));
259
+ }
260
+ }
261
+ if let Ok(req) = &mut self.request {
262
+ if let Some("") = req.url().query() {
263
+ req.url_mut().set_query(None);
264
+ }
265
+ }
266
+ if let Some(e) = error {
267
+ self.request = Err(e);
268
+ }
269
+ self
270
+ }
271
+
272
+ /// Set HTTP version (accepted, ignored: the host decides).
273
+ pub fn version(mut self, version: Version) -> RequestBuilder {
274
+ if let Ok(req) = &mut self.request {
275
+ *req.version_mut() = version;
276
+ }
277
+ self
278
+ }
279
+
280
+ /// Send a form body (`application/x-www-form-urlencoded`).
281
+ pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
282
+ let mut error = None;
283
+ if let Ok(req) = &mut self.request {
284
+ match serde_urlencoded::to_string(form) {
285
+ Ok(body) => {
286
+ req.headers_mut().insert(
287
+ CONTENT_TYPE,
288
+ HeaderValue::from_static("application/x-www-form-urlencoded"),
289
+ );
290
+ *req.body_mut() = Some(body.into());
291
+ }
292
+ Err(err) => error = Some(Error::builder(err)),
293
+ }
294
+ }
295
+ if let Some(e) = error {
296
+ self.request = Err(e);
297
+ }
298
+ self
299
+ }
300
+
301
+ /// Send a JSON body.
302
+ pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
303
+ let mut error = None;
304
+ if let Ok(req) = &mut self.request {
305
+ match serde_json::to_vec(json) {
306
+ Ok(body) => {
307
+ if !req.headers().contains_key(CONTENT_TYPE) {
308
+ req.headers_mut()
309
+ .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
310
+ }
311
+ *req.body_mut() = Some(body.into());
312
+ }
313
+ Err(err) => error = Some(Error::builder(err)),
314
+ }
315
+ }
316
+ if let Some(e) = error {
317
+ self.request = Err(e);
318
+ }
319
+ self
320
+ }
321
+
322
+ /// Build a `Request`, which can be inspected, modified and executed.
323
+ pub fn build(self) -> Result<Request> {
324
+ self.request
325
+ }
326
+
327
+ /// Build a `Request`, returning the `Client` as well.
328
+ pub fn build_split(self) -> (Client, Result<Request>) {
329
+ (self.client, self.request)
330
+ }
331
+
332
+ /// Constructs the Request and sends it to the target URL.
333
+ pub fn send(self) -> impl Future<Output = Result<Response>> {
334
+ let client = self.client;
335
+ let request = self.request;
336
+ async move { client.execute(request?).await }
337
+ }
338
+
339
+ /// Attempt to clone the RequestBuilder; `None` for a streaming body.
340
+ pub fn try_clone(&self) -> Option<RequestBuilder> {
341
+ let req = self.request.as_ref().ok()?.try_clone()?;
342
+ Some(RequestBuilder {
343
+ client: self.client.clone(),
344
+ request: Ok(req),
345
+ })
346
+ }
347
+ }
348
+
349
+ impl fmt::Debug for RequestBuilder {
350
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351
+ let mut d = f.debug_struct("RequestBuilder");
352
+ match &self.request {
353
+ Ok(r) => d.field("request", r),
354
+ Err(e) => d.field("error", e),
355
+ };
356
+ d.finish()
357
+ }
358
+ }
@@ -0,0 +1,310 @@
1
+ use std::{
2
+ fmt,
3
+ future::Future,
4
+ pin::Pin,
5
+ task::{Context, Poll},
6
+ time::{Duration, Instant},
7
+ };
8
+
9
+ use bytes::Bytes;
10
+ use convex_fn::{select, Ctx, Either, FetchStream};
11
+ use futures_core::Stream;
12
+ use http::{header::CONTENT_LENGTH, HeaderMap, StatusCode, Version};
13
+ use serde::de::DeserializeOwned;
14
+
15
+ use url::Url;
16
+
17
+ use crate::{
18
+ body::Body,
19
+ error::{Error, Kind, Result},
20
+ };
21
+
22
+ /// A Response to a submitted `Request`.
23
+ pub struct Response {
24
+ status: StatusCode,
25
+ headers: HeaderMap,
26
+ url: Box<Url>,
27
+ version: Version,
28
+ extensions: http::Extensions,
29
+ body: RespBody,
30
+ deadline: Option<Instant>,
31
+ }
32
+
33
+ enum RespBody {
34
+ Stream(FetchStream),
35
+ Bytes(Option<Bytes>),
36
+ /// Taken by `bytes_stream`.
37
+ Gone,
38
+ }
39
+
40
+ impl Response {
41
+ pub(crate) fn from_fetch(
42
+ stream: FetchStream,
43
+ status: StatusCode,
44
+ headers: HeaderMap,
45
+ url: Url,
46
+ timeout: Option<Duration>,
47
+ ) -> Response {
48
+ Response {
49
+ status,
50
+ headers,
51
+ url: Box::new(url),
52
+ version: Version::HTTP_11,
53
+ extensions: http::Extensions::new(),
54
+ body: RespBody::Stream(stream),
55
+ deadline: timeout.map(|t| Instant::now() + t),
56
+ }
57
+ }
58
+
59
+ /// Get the `StatusCode` of this `Response`.
60
+ pub fn status(&self) -> StatusCode {
61
+ self.status
62
+ }
63
+
64
+ /// Get the HTTP `Version` of this `Response`.
65
+ pub fn version(&self) -> Version {
66
+ self.version
67
+ }
68
+
69
+ /// Get the `Headers` of this `Response`.
70
+ pub fn headers(&self) -> &HeaderMap {
71
+ &self.headers
72
+ }
73
+
74
+ /// Get a mutable reference to the `Headers` of this `Response`.
75
+ pub fn headers_mut(&mut self) -> &mut HeaderMap {
76
+ &mut self.headers
77
+ }
78
+
79
+ /// Get the content length of the response, if the header says.
80
+ pub fn content_length(&self) -> Option<u64> {
81
+ self.headers
82
+ .get(CONTENT_LENGTH)?
83
+ .to_str()
84
+ .ok()?
85
+ .parse()
86
+ .ok()
87
+ }
88
+
89
+ /// Get the final `Url` of this `Response`.
90
+ pub fn url(&self) -> &Url {
91
+ &self.url
92
+ }
93
+
94
+ /// Get the remote address (never known: the host owns the socket).
95
+ pub fn remote_addr(&self) -> Option<std::net::SocketAddr> {
96
+ None
97
+ }
98
+
99
+ /// Returns a reference to the associated extensions.
100
+ pub fn extensions(&self) -> &http::Extensions {
101
+ &self.extensions
102
+ }
103
+
104
+ /// Returns a mutable reference to the associated extensions.
105
+ pub fn extensions_mut(&mut self) -> &mut http::Extensions {
106
+ &mut self.extensions
107
+ }
108
+
109
+ /// Get the full response text (lossy UTF-8).
110
+ pub async fn text(self) -> Result<String> {
111
+ self.text_with_charset("utf-8").await
112
+ }
113
+
114
+ /// Get the full response text; only UTF-8 (lossy) is decoded, other
115
+ /// charsets are read as UTF-8 too.
116
+ pub async fn text_with_charset(self, _default_encoding: &str) -> Result<String> {
117
+ let bytes = self.bytes().await?;
118
+ Ok(String::from_utf8_lossy(&bytes).into_owned())
119
+ }
120
+
121
+ /// Try to deserialize the response body as JSON.
122
+ pub async fn json<T: DeserializeOwned>(self) -> Result<T> {
123
+ let url = (*self.url).clone();
124
+ let full = self.bytes().await?;
125
+ serde_json::from_slice(&full).map_err(|e| Error::decode(e).with_url(url))
126
+ }
127
+
128
+ /// Get the full response body as `Bytes`.
129
+ pub async fn bytes(mut self) -> Result<Bytes> {
130
+ let mut out: Vec<u8> = Vec::new();
131
+ let mut first: Option<Bytes> = None;
132
+ while let Some(c) = self.chunk().await? {
133
+ if first.is_none() && out.is_empty() {
134
+ first = Some(c);
135
+ } else {
136
+ if let Some(f) = first.take() {
137
+ out.extend_from_slice(&f);
138
+ }
139
+ out.extend_from_slice(&c);
140
+ }
141
+ }
142
+ Ok(match first {
143
+ Some(f) => f,
144
+ None => Bytes::from(out),
145
+ })
146
+ }
147
+
148
+ /// Stream a chunk of the response body; `None` when the body ended.
149
+ pub async fn chunk(&mut self) -> Result<Option<Bytes>> {
150
+ let deadline = self.deadline;
151
+ let url = (*self.url).clone();
152
+ match &mut self.body {
153
+ RespBody::Gone => Ok(None),
154
+ RespBody::Bytes(b) => Ok(b.take().filter(|b| !b.is_empty())),
155
+ RespBody::Stream(s) => {
156
+ let r = match deadline {
157
+ Some(d) => {
158
+ let left = d.saturating_duration_since(Instant::now());
159
+ match select(s.chunk(), Ctx::default().sleep(crate::client::millis(left))).await {
160
+ Either::Left(r) => r,
161
+ Either::Right(_) => return Err(Error::timeout(Kind::Body).with_url(url)),
162
+ }
163
+ }
164
+ None => s.chunk().await,
165
+ };
166
+ match r {
167
+ Ok(c) => Ok(c.map(Bytes::from)),
168
+ Err(e) => Err(Error::body(e.to_string()).with_url(url)),
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ /// Convert the response into a `Stream` of `Bytes` from the body.
175
+ pub fn bytes_stream(mut self) -> impl Stream<Item = Result<Bytes>> {
176
+ let body = std::mem::replace(&mut self.body, RespBody::Gone);
177
+ BytesStream {
178
+ resp: Some(Box::new(Response { body, ..self })),
179
+ fut: None,
180
+ }
181
+ }
182
+
183
+ /// Turn a response into an error if the server returned an error.
184
+ pub fn error_for_status(self) -> Result<Self> {
185
+ let status = self.status;
186
+ if status.is_client_error() || status.is_server_error() {
187
+ Err(Error::status_code(*self.url, status))
188
+ } else {
189
+ Ok(self)
190
+ }
191
+ }
192
+
193
+ /// Turn a reference to a response into an error if the server returned an error.
194
+ pub fn error_for_status_ref(&self) -> Result<&Self> {
195
+ let status = self.status;
196
+ if status.is_client_error() || status.is_server_error() {
197
+ Err(Error::status_code((*self.url).clone(), status))
198
+ } else {
199
+ Ok(self)
200
+ }
201
+ }
202
+ }
203
+
204
+ type ChunkFut = Pin<Box<dyn Future<Output = (Box<Response>, Result<Option<Bytes>>)> + Send>>;
205
+
206
+ struct BytesStream {
207
+ resp: Option<Box<Response>>,
208
+ fut: Option<ChunkFut>,
209
+ }
210
+
211
+ impl Stream for BytesStream {
212
+ type Item = Result<Bytes>;
213
+
214
+ fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
215
+ if self.fut.is_none() {
216
+ let Some(mut resp) = self.resp.take() else {
217
+ return Poll::Ready(None);
218
+ };
219
+ self.fut = Some(Box::pin(async move {
220
+ let r = resp.chunk().await;
221
+ (resp, r)
222
+ }));
223
+ }
224
+ let fut = self.fut.as_mut().expect("set above");
225
+ match fut.as_mut().poll(cx) {
226
+ Poll::Pending => Poll::Pending,
227
+ Poll::Ready((resp, r)) => {
228
+ self.fut = None;
229
+ match r {
230
+ Ok(Some(c)) => {
231
+ self.resp = Some(resp);
232
+ Poll::Ready(Some(Ok(c)))
233
+ }
234
+ Ok(None) => Poll::Ready(None),
235
+ Err(e) => Poll::Ready(Some(Err(e))),
236
+ }
237
+ }
238
+ }
239
+ }
240
+ }
241
+
242
+ impl fmt::Debug for Response {
243
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244
+ f.debug_struct("Response")
245
+ .field("url", &self.url.as_str())
246
+ .field("status", &self.status)
247
+ .field("headers", &self.headers)
248
+ .finish()
249
+ }
250
+ }
251
+
252
+ impl<T: Into<Body>> From<http::Response<T>> for Response {
253
+ fn from(r: http::Response<T>) -> Response {
254
+ let (mut parts, body) = r.into_parts();
255
+ let body: Body = body.into();
256
+ let bytes = match body.as_bytes() {
257
+ Some(b) => Bytes::copy_from_slice(b),
258
+ None => Bytes::new(),
259
+ };
260
+ let url = parts
261
+ .extensions
262
+ .remove::<Url>()
263
+ .unwrap_or_else(|| Url::parse("http://no.url.provided.local").expect("static url"));
264
+ Response {
265
+ status: parts.status,
266
+ headers: parts.headers,
267
+ url: Box::new(url),
268
+ version: parts.version,
269
+ extensions: parts.extensions,
270
+ body: RespBody::Bytes(Some(bytes)),
271
+ deadline: None,
272
+ }
273
+ }
274
+ }
275
+
276
+ impl From<Response> for http::Response<Body> {
277
+ fn from(r: Response) -> http::Response<Body> {
278
+ let (status, headers, url, version, extensions) = (
279
+ r.status,
280
+ r.headers.clone(),
281
+ (*r.url).clone(),
282
+ r.version,
283
+ r.extensions.clone(),
284
+ );
285
+ let body = match &r.body {
286
+ RespBody::Bytes(Some(b)) => Body::from(b.clone()),
287
+ _ => Body::wrap_stream(r.bytes_stream()),
288
+ };
289
+ let mut out = http::Response::new(body);
290
+ *out.status_mut() = status;
291
+ *out.headers_mut() = headers;
292
+ *out.version_mut() = version;
293
+ *out.extensions_mut() = extensions;
294
+ out.extensions_mut().insert(url);
295
+ out
296
+ }
297
+ }
298
+
299
+ /// Extension trait for `http::response::Builder` objects: records the final
300
+ /// URL so `Response::from(http::Response)` keeps it.
301
+ pub trait ResponseBuilderExt {
302
+ /// Adds a `Url` to the `http::Response` being built.
303
+ fn url(self, url: Url) -> Self;
304
+ }
305
+
306
+ impl ResponseBuilderExt for http::response::Builder {
307
+ fn url(self, url: Url) -> Self {
308
+ self.extension(url)
309
+ }
310
+ }