actix_http/
test.rs

1//! Various testing helpers for use in internal and app tests.
2
3use std::{
4    cell::{Ref, RefCell, RefMut},
5    io::{self, Read, Write},
6    pin::Pin,
7    rc::Rc,
8    str::FromStr,
9    task::{Context, Poll},
10};
11
12use actix_codec::{AsyncRead, AsyncWrite, ReadBuf};
13use bytes::{Bytes, BytesMut};
14use http::{Method, Uri, Version};
15
16use crate::{
17    header::{HeaderMap, TryIntoHeaderPair},
18    payload::Payload,
19    Request,
20};
21
22/// Test `Request` builder.
23pub struct TestRequest(Option<Inner>);
24
25struct Inner {
26    version: Version,
27    method: Method,
28    uri: Uri,
29    headers: HeaderMap,
30    payload: Option<Payload>,
31}
32
33impl Default for TestRequest {
34    fn default() -> TestRequest {
35        TestRequest(Some(Inner {
36            method: Method::GET,
37            uri: Uri::from_str("/").unwrap(),
38            version: Version::HTTP_11,
39            headers: HeaderMap::new(),
40            payload: None,
41        }))
42    }
43}
44
45impl TestRequest {
46    /// Create a default TestRequest and then set its URI.
47    pub fn with_uri(path: &str) -> TestRequest {
48        TestRequest::default().uri(path).take()
49    }
50
51    /// Set HTTP version of this request.
52    pub fn version(&mut self, ver: Version) -> &mut Self {
53        parts(&mut self.0).version = ver;
54        self
55    }
56
57    /// Set HTTP method of this request.
58    pub fn method(&mut self, meth: Method) -> &mut Self {
59        parts(&mut self.0).method = meth;
60        self
61    }
62
63    /// Set URI of this request.
64    ///
65    /// # Panics
66    /// If provided URI is invalid.
67    pub fn uri(&mut self, path: &str) -> &mut Self {
68        parts(&mut self.0).uri = Uri::from_str(path).unwrap();
69        self
70    }
71
72    /// Insert a header, replacing any that were set with an equivalent field name.
73    pub fn insert_header(&mut self, header: impl TryIntoHeaderPair) -> &mut Self {
74        match header.try_into_pair() {
75            Ok((key, value)) => {
76                parts(&mut self.0).headers.insert(key, value);
77            }
78            Err(err) => {
79                panic!("Error inserting test header: {}.", err.into());
80            }
81        }
82
83        self
84    }
85
86    /// Append a header, keeping any that were set with an equivalent field name.
87    pub fn append_header(&mut self, header: impl TryIntoHeaderPair) -> &mut Self {
88        match header.try_into_pair() {
89            Ok((key, value)) => {
90                parts(&mut self.0).headers.append(key, value);
91            }
92            Err(err) => {
93                panic!("Error inserting test header: {}.", err.into());
94            }
95        }
96
97        self
98    }
99
100    /// Set request payload.
101    pub fn set_payload(&mut self, data: impl Into<Bytes>) -> &mut Self {
102        let mut payload = crate::h1::Payload::empty();
103        payload.unread_data(data.into());
104        parts(&mut self.0).payload = Some(payload.into());
105        self
106    }
107
108    pub fn take(&mut self) -> TestRequest {
109        TestRequest(self.0.take())
110    }
111
112    /// Complete request creation and generate `Request` instance.
113    pub fn finish(&mut self) -> Request {
114        let inner = self.0.take().expect("cannot reuse test request builder");
115
116        let mut req = if let Some(pl) = inner.payload {
117            Request::with_payload(pl)
118        } else {
119            Request::with_payload(crate::h1::Payload::empty().into())
120        };
121
122        let head = req.head_mut();
123        head.uri = inner.uri;
124        head.method = inner.method;
125        head.version = inner.version;
126        head.headers = inner.headers;
127
128        req
129    }
130}
131
132#[inline]
133fn parts(parts: &mut Option<Inner>) -> &mut Inner {
134    parts.as_mut().expect("cannot reuse test request builder")
135}
136
137/// Async I/O test buffer.
138#[derive(Debug)]
139pub struct TestBuffer {
140    pub read_buf: Rc<RefCell<BytesMut>>,
141    pub write_buf: Rc<RefCell<BytesMut>>,
142    pub err: Option<Rc<io::Error>>,
143}
144
145impl TestBuffer {
146    /// Create new `TestBuffer` instance with initial read buffer.
147    pub fn new<T>(data: T) -> Self
148    where
149        T: Into<BytesMut>,
150    {
151        Self {
152            read_buf: Rc::new(RefCell::new(data.into())),
153            write_buf: Rc::new(RefCell::new(BytesMut::new())),
154            err: None,
155        }
156    }
157
158    // intentionally not using Clone trait
159    #[allow(dead_code)]
160    pub(crate) fn clone(&self) -> Self {
161        Self {
162            read_buf: Rc::clone(&self.read_buf),
163            write_buf: Rc::clone(&self.write_buf),
164            err: self.err.clone(),
165        }
166    }
167
168    /// Create new empty `TestBuffer` instance.
169    pub fn empty() -> Self {
170        Self::new("")
171    }
172
173    #[allow(dead_code)]
174    pub(crate) fn read_buf_slice(&self) -> Ref<'_, [u8]> {
175        Ref::map(self.read_buf.borrow(), |b| b.as_ref())
176    }
177
178    #[allow(dead_code)]
179    pub(crate) fn read_buf_slice_mut(&self) -> RefMut<'_, [u8]> {
180        RefMut::map(self.read_buf.borrow_mut(), |b| b.as_mut())
181    }
182
183    #[allow(dead_code)]
184    pub(crate) fn write_buf_slice(&self) -> Ref<'_, [u8]> {
185        Ref::map(self.write_buf.borrow(), |b| b.as_ref())
186    }
187
188    #[allow(dead_code)]
189    pub(crate) fn write_buf_slice_mut(&self) -> RefMut<'_, [u8]> {
190        RefMut::map(self.write_buf.borrow_mut(), |b| b.as_mut())
191    }
192
193    #[allow(dead_code)]
194    pub(crate) fn take_write_buf(&self) -> Bytes {
195        self.write_buf.borrow_mut().split().freeze()
196    }
197
198    /// Add data to read buffer.
199    pub fn extend_read_buf<T: AsRef<[u8]>>(&mut self, data: T) {
200        self.read_buf.borrow_mut().extend_from_slice(data.as_ref())
201    }
202}
203
204impl io::Read for TestBuffer {
205    fn read(&mut self, dst: &mut [u8]) -> Result<usize, io::Error> {
206        if self.read_buf.borrow().is_empty() {
207            if self.err.is_some() {
208                Err(Rc::try_unwrap(self.err.take().unwrap()).unwrap())
209            } else {
210                Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
211            }
212        } else {
213            let size = std::cmp::min(self.read_buf.borrow().len(), dst.len());
214            let b = self.read_buf.borrow_mut().split_to(size);
215            dst[..size].copy_from_slice(&b);
216            Ok(size)
217        }
218    }
219}
220
221impl io::Write for TestBuffer {
222    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
223        self.write_buf.borrow_mut().extend(buf);
224        Ok(buf.len())
225    }
226
227    fn flush(&mut self) -> io::Result<()> {
228        Ok(())
229    }
230}
231
232impl AsyncRead for TestBuffer {
233    fn poll_read(
234        self: Pin<&mut Self>,
235        _: &mut Context<'_>,
236        buf: &mut ReadBuf<'_>,
237    ) -> Poll<io::Result<()>> {
238        let dst = buf.initialize_unfilled();
239        let res = self.get_mut().read(dst).map(|n| buf.advance(n));
240        Poll::Ready(res)
241    }
242}
243
244impl AsyncWrite for TestBuffer {
245    fn poll_write(
246        self: Pin<&mut Self>,
247        _: &mut Context<'_>,
248        buf: &[u8],
249    ) -> Poll<io::Result<usize>> {
250        Poll::Ready(self.get_mut().write(buf))
251    }
252
253    fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
254        Poll::Ready(Ok(()))
255    }
256
257    fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
258        Poll::Ready(Ok(()))
259    }
260}
261
262/// Async I/O test buffer with ability to incrementally add to the read buffer.
263#[derive(Clone)]
264pub struct TestSeqBuffer(Rc<RefCell<TestSeqInner>>);
265
266impl TestSeqBuffer {
267    /// Create new `TestBuffer` instance with initial read buffer.
268    pub fn new<T>(data: T) -> Self
269    where
270        T: Into<BytesMut>,
271    {
272        Self(Rc::new(RefCell::new(TestSeqInner {
273            read_buf: data.into(),
274            write_buf: BytesMut::new(),
275            err: None,
276        })))
277    }
278
279    /// Create new empty `TestBuffer` instance.
280    pub fn empty() -> Self {
281        Self::new(BytesMut::new())
282    }
283
284    pub fn read_buf(&self) -> Ref<'_, BytesMut> {
285        Ref::map(self.0.borrow(), |inner| &inner.read_buf)
286    }
287
288    pub fn write_buf(&self) -> Ref<'_, BytesMut> {
289        Ref::map(self.0.borrow(), |inner| &inner.write_buf)
290    }
291
292    pub fn err(&self) -> Ref<'_, Option<io::Error>> {
293        Ref::map(self.0.borrow(), |inner| &inner.err)
294    }
295
296    /// Add data to read buffer.
297    pub fn extend_read_buf<T: AsRef<[u8]>>(&mut self, data: T) {
298        self.0
299            .borrow_mut()
300            .read_buf
301            .extend_from_slice(data.as_ref())
302    }
303}
304
305pub struct TestSeqInner {
306    read_buf: BytesMut,
307    write_buf: BytesMut,
308    err: Option<io::Error>,
309}
310
311impl io::Read for TestSeqBuffer {
312    fn read(&mut self, dst: &mut [u8]) -> Result<usize, io::Error> {
313        if self.0.borrow().read_buf.is_empty() {
314            if self.0.borrow().err.is_some() {
315                Err(self.0.borrow_mut().err.take().unwrap())
316            } else {
317                Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
318            }
319        } else {
320            let size = std::cmp::min(self.0.borrow().read_buf.len(), dst.len());
321            let b = self.0.borrow_mut().read_buf.split_to(size);
322            dst[..size].copy_from_slice(&b);
323            Ok(size)
324        }
325    }
326}
327
328impl io::Write for TestSeqBuffer {
329    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
330        self.0.borrow_mut().write_buf.extend(buf);
331        Ok(buf.len())
332    }
333
334    fn flush(&mut self) -> io::Result<()> {
335        Ok(())
336    }
337}
338
339impl AsyncRead for TestSeqBuffer {
340    fn poll_read(
341        self: Pin<&mut Self>,
342        _: &mut Context<'_>,
343        buf: &mut ReadBuf<'_>,
344    ) -> Poll<io::Result<()>> {
345        let dst = buf.initialize_unfilled();
346        let r = self.get_mut().read(dst);
347        match r {
348            Ok(n) => {
349                buf.advance(n);
350                Poll::Ready(Ok(()))
351            }
352            Err(err) if err.kind() == io::ErrorKind::WouldBlock => Poll::Pending,
353            Err(err) => Poll::Ready(Err(err)),
354        }
355    }
356}
357
358impl AsyncWrite for TestSeqBuffer {
359    fn poll_write(
360        self: Pin<&mut Self>,
361        _: &mut Context<'_>,
362        buf: &[u8],
363    ) -> Poll<io::Result<usize>> {
364        Poll::Ready(self.get_mut().write(buf))
365    }
366
367    fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
368        Poll::Ready(Ok(()))
369    }
370
371    fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
372        Poll::Ready(Ok(()))
373    }
374}