http_types_2/
body.rs

1use futures_lite::{io, prelude::*, ready};
2#[cfg(feature = "serde")]
3use serde_crate::{de::DeserializeOwned, Serialize};
4
5use std::convert::TryFrom;
6use std::fmt::{self, Debug};
7use std::pin::Pin;
8use std::task::{Context, Poll};
9
10use crate::mime::{self, Mime};
11use crate::{Status, StatusCode};
12
13pin_project_lite::pin_project! {
14    /// A streaming HTTP body.
15    ///
16    /// `Body` represents the HTTP body of both `Request` and `Response`. It's completely
17    /// streaming, and implements `AsyncBufRead` to make reading from it both convenient and
18    /// performant.
19    ///
20    /// Both `Request` and `Response` take `Body` by `Into<Body>`, which means that passing string
21    /// literals, byte vectors, but also concrete `Body` instances are all valid. This makes it
22    /// easy to create both quick HTTP requests, but also have fine grained control over how bodies
23    /// are streamed out.
24    ///
25    /// # Examples
26    ///
27    /// ```
28    /// use http_types::{Body, Response, StatusCode};
29    /// use async_std::io::Cursor;
30    ///
31    /// let mut req = Response::new(StatusCode::Ok);
32    /// req.set_body("Hello Chashu");
33    ///
34    /// let mut req = Response::new(StatusCode::Ok);
35    /// let cursor = Cursor::new("Hello Nori");
36    /// let body = Body::from_reader(cursor, Some(10)); // set the body length
37    /// req.set_body(body);
38    /// ```
39    ///
40    /// # Length
41    ///
42    /// One of the details of `Body` to be aware of is the `length` parameter. The value of
43    /// `length` is used by HTTP implementations to determine how to treat the stream. If a length
44    /// is known ahead of time, it's _strongly_ recommended to pass it.
45    ///
46    /// Casting from `Vec<u8>`, `String`, or similar to `Body` will automatically set the value of
47    /// `length`.
48    ///
49    /// # Content Encoding
50    ///
51    /// By default `Body` will come with a fallback Mime type that is used by `Request` and
52    /// `Response` if no other type has been set, and no other Mime type can be inferred.
53    ///
54    /// It's _strongly_ recommended to always set a mime type on both the `Request` and `Response`,
55    /// and not rely on the fallback mechanisms. However, they're still there if you need them.
56    pub struct Body {
57        #[pin]
58        reader: Box<dyn AsyncBufRead + Unpin + Send + Sync + 'static>,
59        mime: Option<Mime>,
60        length: Option<u64>,
61        bytes_read: u64,
62    }
63}
64
65impl Body {
66    /// Create a new empty `Body`.
67    ///
68    /// The body will have a length of `0`, and the Mime type set to `application/octet-stream` if
69    /// no other mime type has been set or can be sniffed.
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use http_types::{Body, Response, StatusCode};
75    ///
76    /// let mut req = Response::new(StatusCode::Ok);
77    /// req.set_body(Body::empty());
78    /// ```
79    pub fn empty() -> Self {
80        Self {
81            reader: Box::new(io::empty()),
82            mime: Some(mime::BYTE_STREAM),
83            length: Some(0),
84            bytes_read: 0,
85        }
86    }
87
88    /// Create a `Body` from a reader with an optional length.
89    ///
90    /// The Mime type is set to `application/octet-stream` if no other mime type has been set or can
91    /// be sniffed. If a `Body` has no length, HTTP implementations will often switch over to
92    /// framed messages such as [Chunked
93    /// Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding).
94    ///
95    /// # Examples
96    ///
97    /// ```
98    /// use http_types::{Body, Response, StatusCode};
99    /// use async_std::io::Cursor;
100    ///
101    /// let mut req = Response::new(StatusCode::Ok);
102    ///
103    /// let cursor = Cursor::new("Hello Nori");
104    /// let len = 10;
105    /// req.set_body(Body::from_reader(cursor, Some(len)));
106    /// ```
107    pub fn from_reader(
108        reader: impl AsyncBufRead + Unpin + Send + Sync + 'static,
109        length: Option<u64>,
110    ) -> Self {
111        Self {
112            reader: Box::new(reader),
113            mime: Some(mime::BYTE_STREAM),
114            length,
115            bytes_read: 0,
116        }
117    }
118
119    /// Get the inner reader from the `Body`
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// # use std::io::prelude::*;
125    /// use http_types::Body;
126    /// use async_std::io::Cursor;
127    ///
128    /// let cursor = Cursor::new("Hello Nori");
129    /// let body = Body::from_reader(cursor, None);
130    /// let _ = body.into_reader();
131    /// ```
132    pub fn into_reader(self) -> Box<dyn AsyncBufRead + Unpin + Send + Sync + 'static> {
133        self.reader
134    }
135
136    /// Create a `Body` from a Vec of bytes.
137    ///
138    /// The Mime type is set to `application/octet-stream` if no other mime type has been set or can
139    /// be sniffed. If a `Body` has no length, HTTP implementations will often switch over to
140    /// framed messages such as [Chunked
141    /// Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding).
142    ///
143    /// # Examples
144    ///
145    /// ```
146    /// use http_types::{Body, Response, StatusCode};
147    /// use async_std::io::Cursor;
148    ///
149    /// let mut req = Response::new(StatusCode::Ok);
150    ///
151    /// let input = vec![1, 2, 3];
152    /// req.set_body(Body::from_bytes(input));
153    /// ```
154    pub fn from_bytes(bytes: Vec<u8>) -> Self {
155        Self {
156            mime: Some(mime::BYTE_STREAM),
157            length: Some(bytes.len() as u64),
158            reader: Box::new(io::Cursor::new(bytes)),
159            bytes_read: 0,
160        }
161    }
162
163    /// Parse the body into a `Vec<u8>`.
164    ///
165    /// # Examples
166    ///
167    /// ```
168    /// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
169    /// use http_types::Body;
170    ///
171    /// let bytes = vec![1, 2, 3];
172    /// let body = Body::from_bytes(bytes);
173    ///
174    /// let bytes: Vec<u8> = body.into_bytes().await?;
175    /// assert_eq!(bytes, vec![1, 2, 3]);
176    /// # Ok(()) }) }
177    /// ```
178    pub async fn into_bytes(mut self) -> crate::Result<Vec<u8>> {
179        let mut buf = Vec::with_capacity(1024);
180        self.read_to_end(&mut buf)
181            .await
182            .status(StatusCode::UnprocessableEntity)?;
183        Ok(buf)
184    }
185
186    /// Create a `Body` from a String
187    ///
188    /// The Mime type is set to `text/plain` if no other mime type has been set or can
189    /// be sniffed. If a `Body` has no length, HTTP implementations will often switch over to
190    /// framed messages such as [Chunked
191    /// Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding).
192    ///
193    /// # Examples
194    ///
195    /// ```
196    /// use http_types::{Body, Response, StatusCode};
197    /// use async_std::io::Cursor;
198    ///
199    /// let mut req = Response::new(StatusCode::Ok);
200    ///
201    /// let input = String::from("hello Nori!");
202    /// req.set_body(Body::from_string(input));
203    /// ```
204    pub fn from_string(s: String) -> Self {
205        Self {
206            mime: Some(mime::PLAIN),
207            length: Some(s.len() as u64),
208            reader: Box::new(io::Cursor::new(s.into_bytes())),
209            bytes_read: 0,
210        }
211    }
212
213    /// Read the body as a string
214    ///
215    /// # Examples
216    ///
217    /// ```
218    /// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
219    /// use http_types::Body;
220    /// use async_std::io::Cursor;
221    ///
222    /// let cursor = Cursor::new("Hello Nori");
223    /// let body = Body::from_reader(cursor, None);
224    /// assert_eq!(&body.into_string().await.unwrap(), "Hello Nori");
225    /// # Ok(()) }) }
226    /// ```
227    pub async fn into_string(mut self) -> crate::Result<String> {
228        let len = usize::try_from(self.len().unwrap_or(0)).status(StatusCode::PayloadTooLarge)?;
229        let mut result = String::with_capacity(len);
230        self.read_to_string(&mut result)
231            .await
232            .status(StatusCode::UnprocessableEntity)?;
233        Ok(result)
234    }
235
236    /// Creates a `Body` from a type, serializing it as JSON.
237    ///
238    /// # Mime
239    ///
240    /// The encoding is set to `application/json`.
241    ///
242    /// # Examples
243    ///
244    /// ```
245    /// use http_types::{Body, convert::json};
246    ///
247    /// let body = Body::from_json(&json!({ "name": "Chashu" }));
248    /// # drop(body);
249    /// ```
250    #[cfg(feature = "serde")]
251    pub fn from_json(json: &impl Serialize) -> crate::Result<Self> {
252        let bytes = serde_json::to_vec(&json)?;
253        let body = Self {
254            length: Some(bytes.len() as u64),
255            reader: Box::new(io::Cursor::new(bytes)),
256            mime: Some(mime::JSON),
257            bytes_read: 0,
258        };
259        Ok(body)
260    }
261
262    /// Parse the body as JSON, serializing it to a struct.
263    ///
264    /// # Examples
265    ///
266    /// ```
267    /// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
268    /// use http_types::Body;
269    /// use http_types::convert::{Serialize, Deserialize};
270    ///
271    /// #[derive(Debug, Serialize, Deserialize)]
272    /// # #[serde(crate = "serde_crate")]
273    /// struct Cat { name: String }
274    ///
275    /// let cat = Cat { name: String::from("chashu") };
276    /// let body = Body::from_json(&cat)?;
277    ///
278    /// let cat: Cat = body.into_json().await?;
279    /// assert_eq!(&cat.name, "chashu");
280    /// # Ok(()) }) }
281    /// ```
282    #[cfg(feature = "serde")]
283    pub async fn into_json<T: DeserializeOwned>(mut self) -> crate::Result<T> {
284        let mut buf = Vec::with_capacity(1024);
285        self.read_to_end(&mut buf).await?;
286        serde_json::from_slice(&buf).status(StatusCode::UnprocessableEntity)
287    }
288
289    /// Creates a `Body` from a type, serializing it using form encoding.
290    ///
291    /// # Mime
292    ///
293    /// The encoding is set to `application/x-www-form-urlencoded`.
294    ///
295    /// # Errors
296    ///
297    /// An error will be returned if the encoding failed.
298    ///
299    /// # Examples
300    ///
301    /// ```
302    /// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
303    /// use http_types::Body;
304    /// use http_types::convert::{Serialize, Deserialize};
305    ///
306    /// #[derive(Debug, Serialize, Deserialize)]
307    /// # #[serde(crate = "serde_crate")]
308    /// struct Cat { name: String }
309    ///
310    /// let cat = Cat { name: String::from("chashu") };
311    /// let body = Body::from_form(&cat)?;
312    ///
313    /// let cat: Cat = body.into_form().await?;
314    /// assert_eq!(&cat.name, "chashu");
315    /// # Ok(()) }) }
316    /// ```
317    #[cfg(feature = "serde")]
318    pub fn from_form(form: &impl Serialize) -> crate::Result<Self> {
319        let query = serde_urlencoded::to_string(form)?;
320        let bytes = query.into_bytes();
321
322        let body = Self {
323            length: Some(bytes.len() as u64),
324            reader: Box::new(io::Cursor::new(bytes)),
325            mime: Some(mime::FORM),
326            bytes_read: 0,
327        };
328        Ok(body)
329    }
330
331    /// Parse the body from form encoding into a type.
332    ///
333    /// # Errors
334    ///
335    /// An error is returned if the underlying IO stream errors, or if the body
336    /// could not be deserialized into the type.
337    ///
338    /// # Examples
339    ///
340    /// ```
341    /// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
342    /// use http_types::Body;
343    /// use http_types::convert::{Serialize, Deserialize};
344    ///
345    /// #[derive(Debug, Serialize, Deserialize)]
346    /// # #[serde(crate = "serde_crate")]
347    /// struct Cat { name: String }
348    ///
349    /// let cat = Cat { name: String::from("chashu") };
350    /// let body = Body::from_form(&cat)?;
351    ///
352    /// let cat: Cat = body.into_form().await?;
353    /// assert_eq!(&cat.name, "chashu");
354    /// # Ok(()) }) }
355    /// ```
356    #[cfg(feature = "serde")]
357    pub async fn into_form<T: DeserializeOwned>(self) -> crate::Result<T> {
358        let s = self.into_string().await?;
359        serde_urlencoded::from_str(&s).status(StatusCode::UnprocessableEntity)
360    }
361
362    /// Create a `Body` from a file named by a path.
363    ///
364    /// The Mime type is sniffed from the file contents if possible, otherwise
365    /// it is inferred from the path's extension if possible, otherwise is set
366    /// to `application/octet-stream`.
367    ///
368    /// # Examples
369    ///
370    /// ```no_run
371    /// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
372    /// use http_types::{Body, Response, StatusCode};
373    ///
374    /// let mut res = Response::new(StatusCode::Ok);
375    /// res.set_body(Body::from_path("/path/to/file").await?);
376    /// # Ok(()) }) }
377    /// ```
378    #[cfg(all(feature = "fs", not(target_os = "unknown")))]
379    pub async fn from_path<P>(path: P) -> io::Result<Self>
380    where
381        P: AsRef<std::path::Path>,
382    {
383        let path = path.as_ref();
384        let file = async_std::fs::File::open(path).await?;
385        Self::from_file_with_path(file, path).await
386    }
387
388    /// Create a `Body` from an already-open file.
389    ///
390    /// The Mime type is sniffed from the file contents if possible, otherwise
391    /// is set to `application/octet-stream`.
392    ///
393    /// # Examples
394    ///
395    /// ```no_run
396    /// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
397    /// use http_types::{Body, Response, StatusCode};
398    ///
399    /// let mut res = Response::new(StatusCode::Ok);
400    /// let path = std::path::Path::new("/path/to/file");
401    /// let file = async_std::fs::File::open(path).await?;
402    /// res.set_body(Body::from_file(file).await?);
403    /// # Ok(()) }) }
404    /// ```
405    #[cfg(all(feature = "fs", not(target_os = "unknown")))]
406    #[inline]
407    pub async fn from_file(file: async_std::fs::File) -> io::Result<Self> {
408        Self::from_file_with_path(file, std::path::Path::new("")).await
409    }
410
411    /// Create a `Body` from an already-open file.
412    ///
413    /// The Mime type is sniffed from the file contents if possible, otherwise
414    /// it is inferred from the path's extension if possible, otherwise is set
415    /// to `application/octet-stream`.
416    ///
417    /// The path here is only used to provide an extension for guessing the Mime
418    /// type, and may be empty if the path is unknown.
419    ///
420    /// # Examples
421    ///
422    /// ```no_run
423    /// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
424    /// use http_types::{Body, Response, StatusCode};
425    ///
426    /// let mut res = Response::new(StatusCode::Ok);
427    /// let path = std::path::Path::new("/path/to/file");
428    /// let file = async_std::fs::File::open(path).await?;
429    /// res.set_body(Body::from_file_with_path(file, path).await?);
430    /// # Ok(()) }) }
431    /// ```
432    #[cfg(all(feature = "fs", not(target_os = "unknown")))]
433    pub async fn from_file_with_path(
434        mut file: async_std::fs::File,
435        path: &std::path::Path,
436    ) -> io::Result<Self> {
437        let len = file.metadata().await?.len();
438
439        // Look at magic bytes first, look at extension second, fall back to
440        // octet stream.
441        let mime = peek_mime(&mut file)
442            .await?
443            .or_else(|| guess_ext(path))
444            .unwrap_or(mime::BYTE_STREAM);
445
446        Ok(Self {
447            mime: Some(mime),
448            length: Some(len),
449            reader: Box::new(io::BufReader::new(file)),
450            bytes_read: 0,
451        })
452    }
453
454    /// Get the length of the body in bytes.
455    ///
456    /// # Examples
457    ///
458    /// ```
459    /// use http_types::Body;
460    /// use async_std::io::Cursor;
461    ///
462    /// let cursor = Cursor::new("Hello Nori");
463    /// let len = 10;
464    /// let body = Body::from_reader(cursor, Some(len));
465    /// assert_eq!(body.len(), Some(10));
466    /// ```
467    pub fn len(&self) -> Option<u64> {
468        self.length
469    }
470
471    /// Returns `true` if the body has a length of zero, and `false` otherwise.
472    pub fn is_empty(&self) -> Option<bool> {
473        self.length.map(|length| length == 0)
474    }
475
476    /// Returns the mime type of this Body.
477    pub fn mime(&self) -> Option<&Mime> {
478        self.mime.as_ref()
479    }
480
481    /// Sets the mime type of this Body.
482    ///
483    /// # Examples
484    /// ```
485    /// use http_types::Body;
486    /// use http_types::mime;
487    ///
488    /// let mut body = Body::empty();
489    /// body.set_mime(Some(mime::CSS));
490    /// assert_eq!(body.mime(), Some(&mime::CSS));
491    ///
492    /// body.set_mime(None);
493    /// assert_eq!(body.mime(), None);
494    /// ```
495    pub fn set_mime(&mut self, mime: Option<Mime>) {
496        self.mime = mime;
497    }
498
499    /// Create a Body by chaining another Body after this one, consuming both.
500    ///
501    /// If both Body instances have a length, and their sum does not overflow,
502    /// the resulting Body will have a length.
503    ///
504    /// If both Body instances have the same fallback MIME type, the resulting
505    /// Body will have the same fallback MIME type; otherwise, the resulting
506    /// Body will have the fallback MIME type `application/octet-stream`.
507    ///
508    /// # Examples
509    ///
510    /// ```
511    /// # fn main() -> http_types::Result<()> { async_std::task::block_on(async {
512    /// use http_types::Body;
513    /// use async_std::io::Cursor;
514    ///
515    /// let cursor = Cursor::new("Hello ");
516    /// let body = Body::from_reader(cursor, None).chain(Body::from("Nori"));
517    /// assert_eq!(&body.into_string().await.unwrap(), "Hello Nori");
518    /// # Ok(()) }) }
519    /// ```
520    pub fn chain(self, other: Body) -> Self {
521        let mime = if self.mime == other.mime {
522            self.mime.clone()
523        } else {
524            Some(mime::BYTE_STREAM)
525        };
526        let length = match (self.length, other.length) {
527            (Some(l1), Some(l2)) => (l1 - self.bytes_read).checked_add(l2 - other.bytes_read),
528            _ => None,
529        };
530        Self {
531            mime,
532            length,
533            reader: Box::new(futures_lite::io::AsyncReadExt::chain(self, other)),
534            bytes_read: 0,
535        }
536    }
537}
538
539impl Debug for Body {
540    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541        f.debug_struct("Body")
542            .field("reader", &"<hidden>")
543            .field("length", &self.length)
544            .field("bytes_read", &self.bytes_read)
545            .finish()
546    }
547}
548
549#[cfg(feature = "serde")]
550impl From<serde_json::Value> for Body {
551    fn from(json_value: serde_json::Value) -> Self {
552        Self::from_json(&json_value).unwrap()
553    }
554}
555
556impl From<String> for Body {
557    fn from(s: String) -> Self {
558        Self::from_string(s)
559    }
560}
561
562impl<'a> From<&'a str> for Body {
563    fn from(s: &'a str) -> Self {
564        Self::from_string(s.to_owned())
565    }
566}
567
568impl From<Vec<u8>> for Body {
569    fn from(b: Vec<u8>) -> Self {
570        Self::from_bytes(b)
571    }
572}
573
574impl<'a> From<&'a [u8]> for Body {
575    fn from(b: &'a [u8]) -> Self {
576        Self::from_bytes(b.to_owned())
577    }
578}
579
580impl AsyncRead for Body {
581    #[allow(rustdoc::missing_doc_code_examples)]
582    fn poll_read(
583        mut self: Pin<&mut Self>,
584        cx: &mut Context<'_>,
585        buf: &mut [u8],
586    ) -> Poll<io::Result<usize>> {
587        let buf = match self.length {
588            None => buf,
589            Some(length) if length == self.bytes_read => return Poll::Ready(Ok(0)),
590            Some(length) => {
591                // Compute `min` using u64, then truncate back to usize. Since
592                // buf.len() is a usize, this can never overflow.
593                let max_len = (length - self.bytes_read).min(buf.len() as u64) as usize;
594                &mut buf[0..max_len]
595            }
596        };
597
598        let bytes = ready!(Pin::new(&mut self.reader).poll_read(cx, buf))?;
599        self.bytes_read += bytes as u64;
600        Poll::Ready(Ok(bytes))
601    }
602}
603
604impl AsyncBufRead for Body {
605    #[allow(rustdoc::missing_doc_code_examples)]
606    fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&'_ [u8]>> {
607        self.project().reader.poll_fill_buf(cx)
608    }
609
610    fn consume(mut self: Pin<&mut Self>, amt: usize) {
611        Pin::new(&mut self.reader).consume(amt)
612    }
613}
614
615/// Look at first few bytes of a file to determine the mime type.
616/// This is used for various binary formats such as images and videos.
617#[cfg(all(feature = "fs", not(target_os = "unknown")))]
618async fn peek_mime(file: &mut async_std::fs::File) -> io::Result<Option<Mime>> {
619    // We need to read the first 300 bytes to correctly infer formats such as tar.
620    let mut buf = [0_u8; 300];
621    file.read(&mut buf).await?;
622    let mime = Mime::sniff(&buf).ok();
623
624    // Reset the file cursor back to the start.
625    file.seek(io::SeekFrom::Start(0)).await?;
626    Ok(mime)
627}
628
629/// Look at the extension of a file to determine the mime type.
630/// This is useful for plain-text formats such as HTML and CSS.
631#[cfg(all(feature = "fs", not(target_os = "unknown")))]
632fn guess_ext(path: &std::path::Path) -> Option<Mime> {
633    let ext = path.extension().and_then(|p| p.to_str());
634    ext.and_then(Mime::from_extension)
635}
636
637#[cfg(test)]
638mod test {
639    use super::*;
640    use async_std::io::Cursor;
641    use serde_crate::Deserialize;
642
643    #[async_std::test]
644    async fn json_status() {
645        #[derive(Debug, Deserialize)]
646        #[serde(crate = "serde_crate")]
647        struct Foo {
648            #[allow(dead_code)]
649            inner: String,
650        }
651        let body = Body::empty();
652        let res = body.into_json::<Foo>().await;
653        assert_eq!(res.unwrap_err().status(), 422);
654    }
655
656    #[async_std::test]
657    async fn form_status() {
658        #[derive(Debug, Deserialize)]
659        #[serde(crate = "serde_crate")]
660        struct Foo {
661            #[allow(dead_code)]
662            inner: String,
663        }
664        let body = Body::empty();
665        let res = body.into_form::<Foo>().await;
666        assert_eq!(res.unwrap_err().status(), 422);
667    }
668
669    async fn read_with_buffers_of_size<R>(reader: &mut R, size: usize) -> crate::Result<String>
670    where
671        R: AsyncRead + Unpin,
672    {
673        let mut return_buffer = vec![];
674        loop {
675            let mut buf = vec![0; size];
676            match reader.read(&mut buf).await? {
677                0 => break Ok(String::from_utf8(return_buffer)?),
678                bytes_read => return_buffer.extend_from_slice(&buf[..bytes_read]),
679            }
680        }
681    }
682
683    #[async_std::test]
684    async fn attempting_to_read_past_length() -> crate::Result<()> {
685        for buf_len in 1..13 {
686            let mut body = Body::from_reader(Cursor::new("hello world"), Some(5));
687            assert_eq!(
688                read_with_buffers_of_size(&mut body, buf_len).await?,
689                "hello"
690            );
691            assert_eq!(body.bytes_read, 5);
692        }
693
694        Ok(())
695    }
696
697    #[async_std::test]
698    async fn attempting_to_read_when_length_is_greater_than_content() -> crate::Result<()> {
699        for buf_len in 1..13 {
700            let mut body = Body::from_reader(Cursor::new("hello world"), Some(15));
701            assert_eq!(
702                read_with_buffers_of_size(&mut body, buf_len).await?,
703                "hello world"
704            );
705            assert_eq!(body.bytes_read, 11);
706        }
707
708        Ok(())
709    }
710
711    #[async_std::test]
712    async fn attempting_to_read_when_length_is_exactly_right() -> crate::Result<()> {
713        for buf_len in 1..13 {
714            let mut body = Body::from_reader(Cursor::new("hello world"), Some(11));
715            assert_eq!(
716                read_with_buffers_of_size(&mut body, buf_len).await?,
717                "hello world"
718            );
719            assert_eq!(body.bytes_read, 11);
720        }
721
722        Ok(())
723    }
724
725    #[async_std::test]
726    async fn reading_in_various_buffer_lengths_when_there_is_no_length() -> crate::Result<()> {
727        for buf_len in 1..13 {
728            let mut body = Body::from_reader(Cursor::new("hello world"), None);
729            assert_eq!(
730                read_with_buffers_of_size(&mut body, buf_len).await?,
731                "hello world"
732            );
733            assert_eq!(body.bytes_read, 11);
734        }
735
736        Ok(())
737    }
738
739    #[async_std::test]
740    async fn chain_strings() -> crate::Result<()> {
741        for buf_len in 1..13 {
742            let mut body = Body::from("hello ").chain(Body::from("world"));
743            assert_eq!(body.len(), Some(11));
744            assert_eq!(body.mime(), Some(&mime::PLAIN));
745            assert_eq!(
746                read_with_buffers_of_size(&mut body, buf_len).await?,
747                "hello world"
748            );
749            assert_eq!(body.bytes_read, 11);
750        }
751
752        Ok(())
753    }
754
755    #[async_std::test]
756    async fn chain_mixed_bytes_string() -> crate::Result<()> {
757        for buf_len in 1..13 {
758            let mut body = Body::from(&b"hello "[..]).chain(Body::from("world"));
759            assert_eq!(body.len(), Some(11));
760            assert_eq!(body.mime(), Some(&mime::BYTE_STREAM));
761            assert_eq!(
762                read_with_buffers_of_size(&mut body, buf_len).await?,
763                "hello world"
764            );
765            assert_eq!(body.bytes_read, 11);
766        }
767
768        Ok(())
769    }
770
771    #[async_std::test]
772    async fn chain_mixed_reader_string() -> crate::Result<()> {
773        for buf_len in 1..13 {
774            let mut body =
775                Body::from_reader(Cursor::new("hello "), Some(6)).chain(Body::from("world"));
776            assert_eq!(body.len(), Some(11));
777            assert_eq!(body.mime(), Some(&mime::BYTE_STREAM));
778            assert_eq!(
779                read_with_buffers_of_size(&mut body, buf_len).await?,
780                "hello world"
781            );
782            assert_eq!(body.bytes_read, 11);
783        }
784
785        Ok(())
786    }
787
788    #[async_std::test]
789    async fn chain_mixed_nolen_len() -> crate::Result<()> {
790        for buf_len in 1..13 {
791            let mut body =
792                Body::from_reader(Cursor::new("hello "), None).chain(Body::from("world"));
793            assert_eq!(body.len(), None);
794            assert_eq!(body.mime(), Some(&mime::BYTE_STREAM));
795            assert_eq!(
796                read_with_buffers_of_size(&mut body, buf_len).await?,
797                "hello world"
798            );
799            assert_eq!(body.bytes_read, 11);
800        }
801
802        Ok(())
803    }
804
805    #[async_std::test]
806    async fn chain_mixed_len_nolen() -> crate::Result<()> {
807        for buf_len in 1..13 {
808            let mut body =
809                Body::from("hello ").chain(Body::from_reader(Cursor::new("world"), None));
810            assert_eq!(body.len(), None);
811            assert_eq!(body.mime(), Some(&mime::BYTE_STREAM));
812            assert_eq!(
813                read_with_buffers_of_size(&mut body, buf_len).await?,
814                "hello world"
815            );
816            assert_eq!(body.bytes_read, 11);
817        }
818
819        Ok(())
820    }
821
822    #[async_std::test]
823    async fn chain_short() -> crate::Result<()> {
824        for buf_len in 1..26 {
825            let mut body = Body::from_reader(Cursor::new("hello xyz"), Some(6))
826                .chain(Body::from_reader(Cursor::new("world abc"), Some(5)));
827            assert_eq!(body.len(), Some(11));
828            assert_eq!(body.mime(), Some(&mime::BYTE_STREAM));
829            assert_eq!(
830                read_with_buffers_of_size(&mut body, buf_len).await?,
831                "hello world"
832            );
833            assert_eq!(body.bytes_read, 11);
834        }
835
836        Ok(())
837    }
838
839    #[async_std::test]
840    async fn chain_many() -> crate::Result<()> {
841        for buf_len in 1..13 {
842            let mut body = Body::from("hello")
843                .chain(Body::from(&b" "[..]))
844                .chain(Body::from("world"));
845            assert_eq!(body.len(), Some(11));
846            assert_eq!(body.mime(), Some(&mime::BYTE_STREAM));
847            assert_eq!(
848                read_with_buffers_of_size(&mut body, buf_len).await?,
849                "hello world"
850            );
851            assert_eq!(body.bytes_read, 11);
852        }
853
854        Ok(())
855    }
856
857    #[async_std::test]
858    async fn chain_skip_start() -> crate::Result<()> {
859        for buf_len in 1..26 {
860            let mut body1 = Body::from_reader(Cursor::new("1234 hello xyz"), Some(11));
861            let mut buf = vec![0; 5];
862            body1.read(&mut buf).await?;
863            assert_eq!(buf, b"1234 ");
864
865            let mut body2 = Body::from_reader(Cursor::new("321 world abc"), Some(9));
866            let mut buf = vec![0; 4];
867            body2.read(&mut buf).await?;
868            assert_eq!(buf, b"321 ");
869
870            let mut body = body1.chain(body2);
871            assert_eq!(body.len(), Some(11));
872            assert_eq!(body.mime(), Some(&mime::BYTE_STREAM));
873            assert_eq!(
874                read_with_buffers_of_size(&mut body, buf_len).await?,
875                "hello world"
876            );
877            assert_eq!(body.bytes_read, 11);
878        }
879
880        Ok(())
881    }
882}