1
+ use async_std:: fs;
1
2
use async_std:: io:: prelude:: * ;
2
- use async_std:: io:: { self , BufRead , Read } ;
3
+ use async_std:: io:: { self , Cursor } ;
4
+ use serde:: { de:: DeserializeOwned , Serialize } ;
3
5
4
6
use std:: fmt:: { self , Debug } ;
7
+ use std:: path:: Path ;
5
8
use std:: pin:: Pin ;
6
9
use std:: task:: { Context , Poll } ;
7
10
@@ -110,6 +113,23 @@ impl Body {
110
113
}
111
114
}
112
115
116
+ /// Get the inner reader from the `Body`
117
+ ///
118
+ /// # Examples
119
+ ///
120
+ /// ```
121
+ /// # use std::io::prelude::*;
122
+ /// use http_types::Body;
123
+ /// use async_std::io::Cursor;
124
+ ///
125
+ /// let cursor = Cursor::new("Hello Nori");
126
+ /// let body = Body::from_reader(cursor, None);
127
+ /// let _ = body.into_reader();
128
+ /// ```
129
+ pub fn into_reader ( self ) -> Box < dyn BufRead + Unpin + Send + ' static > {
130
+ self . reader
131
+ }
132
+
113
133
/// Create a `Body` from a Vec of bytes.
114
134
///
115
135
/// The Mime type is set to `application/octet-stream` if no other mime type has been set or can
@@ -157,43 +177,30 @@ impl Body {
157
177
Ok ( buf)
158
178
}
159
179
160
- /// Get the length of the body in bytes.
161
- ///
162
- /// # Examples
163
- ///
164
- /// ```
165
- /// use http_types::Body;
166
- /// use async_std::io::Cursor;
180
+ /// Create a `Body` from a String
167
181
///
168
- /// let cursor = Cursor::new("Hello Nori");
169
- /// let len = 10;
170
- /// let body = Body::from_reader(cursor, Some(len));
171
- /// assert_eq!(body.len(), Some(10));
172
- /// ```
173
- pub fn len ( & self ) -> Option < usize > {
174
- self . length
175
- }
176
-
177
- /// Returns `true` if the body has a length of zero, and `false` otherwise.
178
- pub fn is_empty ( & self ) -> Option < bool > {
179
- self . length . map ( |length| length == 0 )
180
- }
181
-
182
- /// Get the inner reader from the `Body`
182
+ /// The Mime type is set to `text/plain` if no other mime type has been set or can
183
+ /// be sniffed. If a `Body` has no length, HTTP implementations will often switch over to
184
+ /// framed messages such as [Chunked
185
+ /// Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding).
183
186
///
184
187
/// # Examples
185
188
///
186
189
/// ```
187
- /// # use std::io::prelude::*;
188
- /// use http_types::Body;
190
+ /// use http_types::{Body, Response, StatusCode};
189
191
/// use async_std::io::Cursor;
190
192
///
191
- /// let cursor = Cursor::new("Hello Nori");
192
- /// let body = Body::from_reader(cursor, None);
193
- /// let _ = body.into_reader();
193
+ /// let mut req = Response::new(StatusCode::Ok);
194
+ ///
195
+ /// let input = String::from("hello Nori!");
196
+ /// req.set_body(Body::from_string(input));
194
197
/// ```
195
- pub fn into_reader ( self ) -> Box < dyn BufRead + Unpin + Send + ' static > {
196
- self . reader
198
+ pub fn from_string ( s : String ) -> Self {
199
+ Self {
200
+ mime : mime:: PLAIN ,
201
+ length : Some ( s. len ( ) ) ,
202
+ reader : Box :: new ( io:: Cursor :: new ( s. into_bytes ( ) ) ) ,
203
+ }
197
204
}
198
205
199
206
/// Read the body as a string
@@ -218,6 +225,169 @@ impl Body {
218
225
Ok ( result)
219
226
}
220
227
228
+ /// Creates a `Body` from a type, serializing it as JSON.
229
+ ///
230
+ /// # Mime
231
+ ///
232
+ /// The encoding is set to `application/json`.
233
+ ///
234
+ /// # Examples
235
+ ///
236
+ /// ```
237
+ /// use http_types::{Body, convert::json};
238
+ ///
239
+ /// let body = Body::from_json(&json!({ "name": "Chashu" }));
240
+ /// # drop(body);
241
+ /// ```
242
+ pub fn from_json ( json : & impl Serialize ) -> crate :: Result < Self > {
243
+ let bytes = serde_json:: to_vec ( & json) ?;
244
+ let body = Self {
245
+ length : Some ( bytes. len ( ) ) ,
246
+ reader : Box :: new ( Cursor :: new ( bytes) ) ,
247
+ mime : mime:: JSON ,
248
+ } ;
249
+ Ok ( body)
250
+ }
251
+
252
+ /// Parse the body as JSON, serializing it to a struct.
253
+ ///
254
+ /// # Examples
255
+ ///
256
+ /// ```
257
+ /// # fn main() -> Result<(), http_types::Error> { async_std::task::block_on(async {
258
+ /// use http_types::Body;
259
+ /// use http_types::convert::{Serialize, Deserialize};
260
+ ///
261
+ /// #[derive(Debug, Serialize, Deserialize)]
262
+ /// struct Cat { name: String }
263
+ ///
264
+ /// let cat = Cat { name: String::from("chashu") };
265
+ /// let body = Body::from_json(&cat)?;
266
+ ///
267
+ /// let cat: Cat = body.into_json().await?;
268
+ /// assert_eq!(&cat.name, "chashu");
269
+ /// # Ok(()) }) }
270
+ /// ```
271
+ pub async fn into_json < T : DeserializeOwned > ( mut self ) -> crate :: Result < T > {
272
+ let mut buf = Vec :: with_capacity ( 1024 ) ;
273
+ self . read_to_end ( & mut buf) . await ?;
274
+ Ok ( serde_json:: from_slice ( & buf) . map_err ( io:: Error :: from) ?)
275
+ }
276
+
277
+ /// Creates a `Body` from a type, serializing it using form encoding.
278
+ ///
279
+ /// # Mime
280
+ ///
281
+ /// The encoding is set to `application/x-www-form-urlencoded`.
282
+ ///
283
+ /// # Errors
284
+ ///
285
+ /// An error will be returned if the encoding failed.
286
+ ///
287
+ /// # Examples
288
+ ///
289
+ /// ```
290
+ /// # fn main() -> Result<(), http_types::Error> { async_std::task::block_on(async {
291
+ /// use http_types::Body;
292
+ /// use http_types::convert::{Serialize, Deserialize};
293
+ ///
294
+ /// #[derive(Debug, Serialize, Deserialize)]
295
+ /// struct Cat { name: String }
296
+ ///
297
+ /// let cat = Cat { name: String::from("chashu") };
298
+ /// let body = Body::from_form(&cat)?;
299
+ ///
300
+ /// let cat: Cat = body.into_form().await?;
301
+ /// assert_eq!(&cat.name, "chashu");
302
+ /// # Ok(()) }) }
303
+ /// ```
304
+ pub fn from_form ( form : & impl Serialize ) -> crate :: Result < Self > {
305
+ let query = serde_urlencoded:: to_string ( form) ?;
306
+ let bytes = query. into_bytes ( ) ;
307
+
308
+ let body = Self {
309
+ length : Some ( bytes. len ( ) ) ,
310
+ reader : Box :: new ( Cursor :: new ( bytes) ) ,
311
+ mime : mime:: FORM ,
312
+ } ;
313
+ Ok ( body)
314
+ }
315
+
316
+ /// Parse the body from form encoding into a type.
317
+ ///
318
+ /// # Errors
319
+ ///
320
+ /// An error is returned if the underlying IO stream errors, or if the body
321
+ /// could not be deserialized into the type.
322
+ ///
323
+ /// # Examples
324
+ ///
325
+ /// ```
326
+ /// # fn main() -> Result<(), http_types::Error> { async_std::task::block_on(async {
327
+ /// use http_types::Body;
328
+ /// use http_types::convert::{Serialize, Deserialize};
329
+ ///
330
+ /// #[derive(Debug, Serialize, Deserialize)]
331
+ /// struct Cat { name: String }
332
+ ///
333
+ /// let cat = Cat { name: String::from("chashu") };
334
+ /// let body = Body::from_form(&cat)?;
335
+ ///
336
+ /// let cat: Cat = body.into_form().await?;
337
+ /// assert_eq!(&cat.name, "chashu");
338
+ /// # Ok(()) }) }
339
+ /// ```
340
+ pub async fn into_form < T : DeserializeOwned > ( self ) -> crate :: Result < T > {
341
+ let s = self . into_string ( ) . await ?;
342
+ Ok ( serde_urlencoded:: from_str ( & s) ?)
343
+ }
344
+
345
+ /// Create a `Body` from a file.
346
+ ///
347
+ /// The Mime type set to `application/octet-stream` if no other mime type has
348
+ /// been set or can be sniffed.
349
+ ///
350
+ /// # Examples
351
+ ///
352
+ /// ```no_run
353
+ /// # fn main() -> Result<(), http_types::Error> { async_std::task::block_on(async {
354
+ /// use http_types::{Body, Response, StatusCode};
355
+ ///
356
+ /// let mut res = Response::new(StatusCode::Ok);
357
+ /// res.set_body(Body::from_file("/path/to/file").await?);
358
+ /// # Ok(()) }) }
359
+ /// ```
360
+ #[ cfg( feature = "async_std" ) ]
361
+ pub async fn from_file < P > ( file : P ) -> io:: Result < Self >
362
+ where
363
+ P : AsRef < Path > ,
364
+ {
365
+ let file = fs:: read ( file. as_ref ( ) ) . await ?;
366
+ Ok ( file. into ( ) )
367
+ }
368
+
369
+ /// Get the length of the body in bytes.
370
+ ///
371
+ /// # Examples
372
+ ///
373
+ /// ```
374
+ /// use http_types::Body;
375
+ /// use async_std::io::Cursor;
376
+ ///
377
+ /// let cursor = Cursor::new("Hello Nori");
378
+ /// let len = 10;
379
+ /// let body = Body::from_reader(cursor, Some(len));
380
+ /// assert_eq!(body.len(), Some(10));
381
+ /// ```
382
+ pub fn len ( & self ) -> Option < usize > {
383
+ self . length
384
+ }
385
+
386
+ /// Returns `true` if the body has a length of zero, and `false` otherwise.
387
+ pub fn is_empty ( & self ) -> Option < bool > {
388
+ self . length . map ( |length| length == 0 )
389
+ }
390
+
221
391
pub ( crate ) fn mime ( & self ) -> & Mime {
222
392
& self . mime
223
393
}
@@ -234,41 +404,25 @@ impl Debug for Body {
234
404
235
405
impl From < String > for Body {
236
406
fn from ( s : String ) -> Self {
237
- Self {
238
- length : Some ( s. len ( ) ) ,
239
- reader : Box :: new ( io:: Cursor :: new ( s. into_bytes ( ) ) ) ,
240
- mime : mime:: PLAIN ,
241
- }
407
+ Self :: from_string ( s)
242
408
}
243
409
}
244
410
245
411
impl < ' a > From < & ' a str > for Body {
246
412
fn from ( s : & ' a str ) -> Self {
247
- Self {
248
- length : Some ( s. len ( ) ) ,
249
- reader : Box :: new ( io:: Cursor :: new ( s. to_owned ( ) . into_bytes ( ) ) ) ,
250
- mime : mime:: PLAIN ,
251
- }
413
+ Self :: from_string ( s. to_owned ( ) )
252
414
}
253
415
}
254
416
255
417
impl From < Vec < u8 > > for Body {
256
418
fn from ( b : Vec < u8 > ) -> Self {
257
- Self {
258
- length : Some ( b. len ( ) ) ,
259
- reader : Box :: new ( io:: Cursor :: new ( b) ) ,
260
- mime : mime:: BYTE_STREAM ,
261
- }
419
+ Self :: from_bytes ( b. to_owned ( ) )
262
420
}
263
421
}
264
422
265
423
impl < ' a > From < & ' a [ u8 ] > for Body {
266
424
fn from ( b : & ' a [ u8 ] ) -> Self {
267
- Self {
268
- length : Some ( b. len ( ) ) ,
269
- reader : Box :: new ( io:: Cursor :: new ( b. to_owned ( ) ) ) ,
270
- mime : mime:: BYTE_STREAM ,
271
- }
425
+ Self :: from_bytes ( b. to_owned ( ) )
272
426
}
273
427
}
274
428
0 commit comments