1use std::convert::TryFrom;
3use std::fmt::Write as FmtWrite;
4use std::io::{self, Read, Write};
5use std::pin::Pin;
6use std::str::FromStr;
7use std::task::{Context, Poll};
8
9use actori_codec::{AsyncRead, AsyncWrite};
10use bytes::{Bytes, BytesMut};
11use http::header::{self, HeaderName, HeaderValue};
12use http::{Error as HttpError, Method, Uri, Version};
13use percent_encoding::percent_encode;
14
15use crate::cookie::{Cookie, CookieJar, USERINFO};
16use crate::header::HeaderMap;
17use crate::header::{Header, IntoHeaderValue};
18use crate::payload::Payload;
19use crate::Request;
20
21pub struct TestRequest(Option<Inner>);
45
46struct Inner {
47 version: Version,
48 method: Method,
49 uri: Uri,
50 headers: HeaderMap,
51 cookies: CookieJar,
52 payload: Option<Payload>,
53}
54
55impl Default for TestRequest {
56 fn default() -> TestRequest {
57 TestRequest(Some(Inner {
58 method: Method::GET,
59 uri: Uri::from_str("/").unwrap(),
60 version: Version::HTTP_11,
61 headers: HeaderMap::new(),
62 cookies: CookieJar::new(),
63 payload: None,
64 }))
65 }
66}
67
68impl TestRequest {
69 pub fn with_uri(path: &str) -> TestRequest {
71 TestRequest::default().uri(path).take()
72 }
73
74 pub fn with_hdr<H: Header>(hdr: H) -> TestRequest {
76 TestRequest::default().set(hdr).take()
77 }
78
79 pub fn with_header<K, V>(key: K, value: V) -> TestRequest
81 where
82 HeaderName: TryFrom<K>,
83 <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
84 V: IntoHeaderValue,
85 {
86 TestRequest::default().header(key, value).take()
87 }
88
89 pub fn version(&mut self, ver: Version) -> &mut Self {
91 parts(&mut self.0).version = ver;
92 self
93 }
94
95 pub fn method(&mut self, meth: Method) -> &mut Self {
97 parts(&mut self.0).method = meth;
98 self
99 }
100
101 pub fn uri(&mut self, path: &str) -> &mut Self {
103 parts(&mut self.0).uri = Uri::from_str(path).unwrap();
104 self
105 }
106
107 pub fn set<H: Header>(&mut self, hdr: H) -> &mut Self {
109 if let Ok(value) = hdr.try_into() {
110 parts(&mut self.0).headers.append(H::name(), value);
111 return self;
112 }
113 panic!("Can not set header");
114 }
115
116 pub fn header<K, V>(&mut self, key: K, value: V) -> &mut Self
118 where
119 HeaderName: TryFrom<K>,
120 <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
121 V: IntoHeaderValue,
122 {
123 if let Ok(key) = HeaderName::try_from(key) {
124 if let Ok(value) = value.try_into() {
125 parts(&mut self.0).headers.append(key, value);
126 return self;
127 }
128 }
129 panic!("Can not create header");
130 }
131
132 pub fn cookie<'a>(&mut self, cookie: Cookie<'a>) -> &mut Self {
134 parts(&mut self.0).cookies.add(cookie.into_owned());
135 self
136 }
137
138 pub fn set_payload<B: Into<Bytes>>(&mut self, data: B) -> &mut Self {
140 let mut payload = crate::h1::Payload::empty();
141 payload.unread_data(data.into());
142 parts(&mut self.0).payload = Some(payload.into());
143 self
144 }
145
146 pub fn take(&mut self) -> TestRequest {
147 TestRequest(self.0.take())
148 }
149
150 pub fn finish(&mut self) -> Request {
152 let inner = self.0.take().expect("cannot reuse test request builder");
153
154 let mut req = if let Some(pl) = inner.payload {
155 Request::with_payload(pl)
156 } else {
157 Request::with_payload(crate::h1::Payload::empty().into())
158 };
159
160 let head = req.head_mut();
161 head.uri = inner.uri;
162 head.method = inner.method;
163 head.version = inner.version;
164 head.headers = inner.headers;
165
166 let mut cookie = String::new();
167 for c in inner.cookies.delta() {
168 let name = percent_encode(c.name().as_bytes(), USERINFO);
169 let value = percent_encode(c.value().as_bytes(), USERINFO);
170 let _ = write!(&mut cookie, "; {}={}", name, value);
171 }
172 if !cookie.is_empty() {
173 head.headers.insert(
174 header::COOKIE,
175 HeaderValue::from_str(&cookie.as_str()[2..]).unwrap(),
176 );
177 }
178
179 req
180 }
181}
182
183#[inline]
184fn parts(parts: &mut Option<Inner>) -> &mut Inner {
185 parts.as_mut().expect("cannot reuse test request builder")
186}
187
188pub struct TestBuffer {
190 pub read_buf: BytesMut,
191 pub write_buf: BytesMut,
192 pub err: Option<io::Error>,
193}
194
195impl TestBuffer {
196 pub fn new<T>(data: T) -> TestBuffer
198 where
199 BytesMut: From<T>,
200 {
201 TestBuffer {
202 read_buf: BytesMut::from(data),
203 write_buf: BytesMut::new(),
204 err: None,
205 }
206 }
207
208 pub fn empty() -> TestBuffer {
210 TestBuffer::new("")
211 }
212
213 pub fn extend_read_buf<T: AsRef<[u8]>>(&mut self, data: T) {
215 self.read_buf.extend_from_slice(data.as_ref())
216 }
217}
218
219impl io::Read for TestBuffer {
220 fn read(&mut self, dst: &mut [u8]) -> Result<usize, io::Error> {
221 if self.read_buf.is_empty() {
222 if self.err.is_some() {
223 Err(self.err.take().unwrap())
224 } else {
225 Err(io::Error::new(io::ErrorKind::WouldBlock, ""))
226 }
227 } else {
228 let size = std::cmp::min(self.read_buf.len(), dst.len());
229 let b = self.read_buf.split_to(size);
230 dst[..size].copy_from_slice(&b);
231 Ok(size)
232 }
233 }
234}
235
236impl io::Write for TestBuffer {
237 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
238 self.write_buf.extend(buf);
239 Ok(buf.len())
240 }
241 fn flush(&mut self) -> io::Result<()> {
242 Ok(())
243 }
244}
245
246impl AsyncRead for TestBuffer {
247 fn poll_read(
248 self: Pin<&mut Self>,
249 _: &mut Context<'_>,
250 buf: &mut [u8],
251 ) -> Poll<io::Result<usize>> {
252 Poll::Ready(self.get_mut().read(buf))
253 }
254}
255
256impl AsyncWrite for TestBuffer {
257 fn poll_write(
258 self: Pin<&mut Self>,
259 _: &mut Context<'_>,
260 buf: &[u8],
261 ) -> Poll<io::Result<usize>> {
262 Poll::Ready(self.get_mut().write(buf))
263 }
264
265 fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
266 Poll::Ready(Ok(()))
267 }
268
269 fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
270 Poll::Ready(Ok(()))
271 }
272}