[go: up one dir, main page]

ureq/
send_body.rs

1use std::fs::File;
2use std::io::{self, Read, Stdin};
3use std::net::TcpStream;
4
5use crate::body::{Body, BodyReader};
6use crate::util::private::Private;
7use crate::{http, Error};
8
9/// Request body for sending data via POST, PUT and PATCH.
10///
11/// Typically not interacted with directly since the trait [`AsSendBody`] is implemented
12/// for the majority of the types of data a user might want to send to a remote server.
13/// That means if you want to send things like `String`, `&str` or `[u8]`, they can be
14/// used directly. See documentation for [`AsSendBody`].
15///
16/// The exception is when using [`Read`] trait bodies, in which case we wrap the request
17/// body directly. See below [`SendBody::from_reader`].
18///
19pub struct SendBody<'a> {
20    inner: BodyInner<'a>,
21    size: Option<Result<u64, Error>>,
22    ended: bool,
23    content_type: Option<HeaderValue>,
24}
25
26impl<'a> SendBody<'a> {
27    /// Creates an empty body.
28    pub fn none() -> SendBody<'static> {
29        (None, BodyInner::None).into()
30    }
31
32    /// Creates a body from a shared [`Read`] impl.
33    pub fn from_reader(reader: &'a mut dyn Read) -> SendBody<'a> {
34        (None, BodyInner::Reader(reader)).into()
35    }
36
37    /// Creates a body from an owned [`Read`] impl.
38    pub fn from_owned_reader(reader: impl Read + 'static) -> SendBody<'static> {
39        (None, BodyInner::OwnedReader(Box::new(reader))).into()
40    }
41
42    #[cfg(feature = "multipart")]
43    pub(crate) fn from_file(file: File) -> SendBody<'static> {
44        let size = lazy_file_size(&file);
45        SendBody {
46            inner: BodyInner::OwnedReader(Box::new(file)),
47            size: Some(size),
48            ended: false,
49            content_type: None,
50        }
51    }
52
53    /// Creates a body to send as JSON from any [`Serialize`](serde::ser::Serialize) value.
54    #[cfg(feature = "json")]
55    pub fn from_json(
56        value: &impl serde::ser::Serialize,
57    ) -> Result<SendBody<'static>, crate::Error> {
58        let json = serde_json::to_vec_pretty(value)?;
59        let len = json.len() as u64;
60        let body: SendBody = (Some(len), BodyInner::ByteVec(io::Cursor::new(json))).into();
61        let body =
62            body.with_content_type(HeaderValue::from_static("application/json; charset=utf-8"));
63        Ok(body)
64    }
65
66    pub(crate) fn with_content_type(mut self, content_type: HeaderValue) -> Self {
67        self.content_type = Some(content_type);
68        self
69    }
70
71    pub(crate) fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
72        let n = match &mut self.inner {
73            BodyInner::None => {
74                return Ok(0);
75            }
76            BodyInner::ByteSlice(v) => {
77                let max = v.len().min(buf.len());
78
79                buf[..max].copy_from_slice(&v[..max]);
80                *v = &v[max..];
81
82                Ok(max)
83            }
84            #[cfg(feature = "json")]
85            BodyInner::ByteVec(v) => v.read(buf),
86            BodyInner::Reader(v) => v.read(buf),
87            BodyInner::OwnedReader(v) => v.read(buf),
88            BodyInner::Body(v) => v.read(buf),
89        }?;
90
91        if n == 0 {
92            self.ended = true;
93        }
94
95        Ok(n)
96    }
97
98    pub(crate) fn body_mode(&mut self) -> Result<BodyMode, Error> {
99        // Lazily surface a potential error now.
100        let size = match self.size {
101            None => None,
102            Some(Ok(v)) => Some(v),
103            Some(Err(_)) => {
104                // unwraps here are ok because we matched exactly this
105                return Err(self.size.take().unwrap().unwrap_err());
106            }
107        };
108
109        match &self.inner {
110            BodyInner::None => return Ok(BodyMode::NoBody),
111            BodyInner::Body(v) => return Ok(v.body_mode()),
112
113            // The others fall through
114            BodyInner::ByteSlice(_) => {}
115            #[cfg(feature = "json")]
116            BodyInner::ByteVec(_) => {}
117            BodyInner::Reader(_) => {}
118            BodyInner::OwnedReader(_) => {}
119        };
120
121        // Any other body mode could be LengthDelimited depending on whether
122        // we have got a size set.
123        let mode = if let Some(size) = size {
124            BodyMode::LengthDelimited(size)
125        } else {
126            BodyMode::Chunked
127        };
128
129        Ok(mode)
130    }
131
132    /// Turn this `SendBody` into a reader.
133    ///
134    /// This is useful in [`Middleware`][crate::middleware::Middleware] to make changes to the
135    /// body before sending it.
136    ///
137    /// ```
138    /// use ureq::{SendBody, Body};
139    /// use ureq::middleware::MiddlewareNext;
140    /// use ureq::http::{Request, Response, header::HeaderValue};
141    /// use std::io::Read;
142    ///
143    /// fn my_middleware(req: Request<SendBody>, next: MiddlewareNext)
144    ///     -> Result<Response<Body>, ureq::Error> {
145    ///
146    ///     // Take apart the request.
147    ///     let (parts, body) = req.into_parts();
148    ///
149    ///     // Take the first 100 bytes of the incoming send body.
150    ///     let mut reader = body.into_reader().take(100);
151    ///
152    ///     // Create a new SendBody.
153    ///     let new_body = SendBody::from_reader(&mut reader);
154    ///
155    ///     // Reconstitute the request.
156    ///     let req = Request::from_parts(parts, new_body);
157    ///
158    ///     // set my bespoke header and continue the chain
159    ///     next.handle(req)
160    /// }
161    /// ```
162    pub fn into_reader(self) -> impl Sized + io::Read + 'a {
163        ReadAdapter(self)
164    }
165
166    #[cfg(feature = "multipart")]
167    pub(crate) fn from_bytes<'b>(bytes: &'b [u8]) -> SendBody<'b> {
168        SendBody {
169            inner: BodyInner::ByteSlice(bytes),
170            size: Some(Ok(bytes.len() as u64)),
171            ended: false,
172            content_type: None,
173        }
174    }
175
176    #[cfg(feature = "multipart")]
177    pub(crate) fn size(&self) -> Option<u64> {
178        self.size.as_ref().and_then(|r| r.as_ref().ok()).copied()
179    }
180
181    /// Get the content type for this body, if any.
182    pub(crate) fn take_content_type(&mut self) -> Option<HeaderValue> {
183        self.content_type.take()
184    }
185}
186
187struct ReadAdapter<'a>(SendBody<'a>);
188
189impl<'a> io::Read for ReadAdapter<'a> {
190    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
191        self.0.read(buf)
192    }
193}
194
195use http::Response;
196use ureq_proto::http::HeaderValue;
197use ureq_proto::BodyMode;
198
199/// Trait for common types to send in POST, PUT or PATCH.
200///
201/// Sending common data types such as `String`, `&str` or `&[u8]` require no further wrapping
202/// and can be sent either by [`RequestBuilder::send()`][crate::RequestBuilder::send] or using the
203/// `http` crate [`Request`][http::Request] directly (see example below).
204///
205/// Implemented for:
206///
207/// * `&str`
208/// * `&String`
209/// * `&Vec<u8>`
210/// * `&File`
211/// * `&TcpStream`
212/// * `&[u8]`
213/// * `Response<Body>`
214/// * `String`
215/// * `Vec<u8>`
216/// * `File`
217/// * `Stdin`
218/// * `TcpStream`
219/// * `UnixStream` (not on windows)
220/// * `&[u8; N]`
221/// * `()`
222///
223/// # Example
224///
225/// These two examples are equivalent.
226///
227/// ```
228/// let data: &[u8] = b"My special request body data";
229///
230/// let response = ureq::post("https://httpbin.org/post")
231///     .send(data)?;
232/// # Ok::<_, ureq::Error>(())
233/// ```
234///
235/// Using `http` crate API
236///
237/// ```
238/// use ureq::http;
239///
240/// let data: &[u8] = b"My special request body data";
241///
242/// let request = http::Request::post("https://httpbin.org/post")
243///     .body(data)?;
244///
245/// let response = ureq::run(request)?;
246/// # Ok::<_, ureq::Error>(())
247/// ```
248pub trait AsSendBody: Private {
249    #[doc(hidden)]
250    fn as_body(&mut self) -> SendBody;
251}
252
253impl<'a> Private for SendBody<'a> {}
254impl<'a> AsSendBody for SendBody<'a> {
255    fn as_body(&mut self) -> SendBody {
256        SendBody {
257            inner: match &mut self.inner {
258                BodyInner::None => BodyInner::None,
259                BodyInner::ByteSlice(v) => BodyInner::ByteSlice(v),
260                #[cfg(feature = "json")]
261                BodyInner::ByteVec(v) => BodyInner::ByteSlice(v.get_ref()),
262                BodyInner::Reader(v) => BodyInner::Reader(v),
263                BodyInner::Body(v) => BodyInner::Reader(v),
264                BodyInner::OwnedReader(v) => BodyInner::Reader(v),
265            },
266            size: self.size.take(),
267            ended: self.ended,
268            content_type: self.content_type.take(),
269        }
270    }
271}
272
273pub(crate) enum BodyInner<'a> {
274    None,
275    ByteSlice(&'a [u8]),
276    #[cfg(feature = "json")]
277    ByteVec(io::Cursor<Vec<u8>>),
278    Body(Box<BodyReader<'a>>),
279    Reader(&'a mut dyn Read),
280    OwnedReader(Box<dyn Read>),
281}
282
283impl Private for &[u8] {}
284impl AsSendBody for &[u8] {
285    fn as_body(&mut self) -> SendBody {
286        let inner = BodyInner::ByteSlice(self);
287        (Some(self.len() as u64), inner).into()
288    }
289}
290
291impl Private for &str {}
292impl AsSendBody for &str {
293    fn as_body(&mut self) -> SendBody {
294        let inner = BodyInner::ByteSlice((*self).as_ref());
295        (Some(self.len() as u64), inner).into()
296    }
297}
298
299impl Private for String {}
300impl AsSendBody for String {
301    fn as_body(&mut self) -> SendBody {
302        let inner = BodyInner::ByteSlice((*self).as_ref());
303        (Some(self.len() as u64), inner).into()
304    }
305}
306
307impl Private for Vec<u8> {}
308impl AsSendBody for Vec<u8> {
309    fn as_body(&mut self) -> SendBody {
310        let inner = BodyInner::ByteSlice((*self).as_ref());
311        (Some(self.len() as u64), inner).into()
312    }
313}
314
315impl Private for &String {}
316impl AsSendBody for &String {
317    fn as_body(&mut self) -> SendBody {
318        let inner = BodyInner::ByteSlice((*self).as_ref());
319        (Some(self.len() as u64), inner).into()
320    }
321}
322
323impl Private for &Vec<u8> {}
324impl AsSendBody for &Vec<u8> {
325    fn as_body(&mut self) -> SendBody {
326        let inner = BodyInner::ByteSlice((*self).as_ref());
327        (Some(self.len() as u64), inner).into()
328    }
329}
330
331impl Private for &File {}
332impl AsSendBody for &File {
333    fn as_body(&mut self) -> SendBody {
334        let size = lazy_file_size(self);
335        SendBody {
336            inner: BodyInner::Reader(self),
337            size: Some(size),
338            ended: false,
339            content_type: None,
340        }
341    }
342}
343
344impl Private for File {}
345impl AsSendBody for File {
346    fn as_body(&mut self) -> SendBody {
347        let size = lazy_file_size(self);
348        SendBody {
349            inner: BodyInner::Reader(self),
350            size: Some(size),
351            ended: false,
352            content_type: None,
353        }
354    }
355}
356
357fn lazy_file_size(file: &File) -> Result<u64, Error> {
358    match file.metadata() {
359        Ok(v) => Ok(v.len()),
360        Err(e) => Err(e.into()),
361    }
362}
363
364impl Private for &TcpStream {}
365impl AsSendBody for &TcpStream {
366    fn as_body(&mut self) -> SendBody {
367        (None, BodyInner::Reader(self)).into()
368    }
369}
370
371impl Private for TcpStream {}
372impl AsSendBody for TcpStream {
373    fn as_body(&mut self) -> SendBody {
374        (None, BodyInner::Reader(self)).into()
375    }
376}
377
378impl Private for Stdin {}
379impl AsSendBody for Stdin {
380    fn as_body(&mut self) -> SendBody {
381        (None, BodyInner::Reader(self)).into()
382    }
383}
384
385// MSRV 1.78
386// impl_into_body!(&Stdin, Reader);
387
388#[cfg(target_family = "unix")]
389use std::os::unix::net::UnixStream;
390
391#[cfg(target_family = "unix")]
392impl Private for UnixStream {}
393#[cfg(target_family = "unix")]
394impl AsSendBody for UnixStream {
395    fn as_body(&mut self) -> SendBody {
396        (None, BodyInner::Reader(self)).into()
397    }
398}
399
400impl<'a> From<(Option<u64>, BodyInner<'a>)> for SendBody<'a> {
401    fn from((size, inner): (Option<u64>, BodyInner<'a>)) -> Self {
402        SendBody {
403            inner,
404            size: size.map(Ok),
405            ended: false,
406            content_type: None,
407        }
408    }
409}
410
411impl Private for Body {}
412impl AsSendBody for Body {
413    fn as_body(&mut self) -> SendBody {
414        let size = self.content_length();
415        (size, BodyInner::Body(Box::new(self.as_reader()))).into()
416    }
417}
418
419impl Private for Response<Body> {}
420impl AsSendBody for Response<Body> {
421    fn as_body(&mut self) -> SendBody {
422        let size = self.body().content_length();
423        (size, BodyInner::Body(Box::new(self.body_mut().as_reader()))).into()
424    }
425}
426
427impl<const N: usize> Private for &[u8; N] {}
428impl<const N: usize> AsSendBody for &[u8; N] {
429    fn as_body(&mut self) -> SendBody {
430        let inner = BodyInner::ByteSlice((*self).as_ref());
431        (Some(self.len() as u64), inner).into()
432    }
433}
434
435impl Private for () {}
436impl AsSendBody for () {
437    fn as_body(&mut self) -> SendBody {
438        (None, BodyInner::None).into()
439    }
440}