1use std::any::{Any, TypeId};
6use std::marker::PhantomData;
7use std::mem;
8use std::io::{self, Write};
9use std::ptr;
10use std::thread;
11
12use time::now_utc;
13
14use crate::header;
15use crate::http::h1::{LINE_ENDING, HttpWriter};
16use crate::http::h1::HttpWriter::{ThroughWriter, ChunkedWriter, SizedWriter, EmptyWriter};
17use crate::status;
18use crate::net::{Fresh, Streaming};
19use crate::version;
20
21
22#[derive(Debug)]
30pub struct Response<'a, W: Any = Fresh> {
31 pub version: version::HttpVersion,
33 pub body: HttpWriter<&'a mut (dyn Write + 'a)>,
35 pub status: status::StatusCode,
37 pub headers: &'a mut header::Headers,
39
40 _writing: PhantomData<W>
41}
42
43impl<'a, W: Any> Response<'a, W> {
44 #[inline]
46 pub fn status(&self) -> status::StatusCode { self.status }
47
48 #[inline]
50 pub fn headers(&self) -> &header::Headers { &*self.headers }
51
52 #[inline]
54 pub fn construct(version: version::HttpVersion,
55 body: HttpWriter<&'a mut (dyn Write + 'a)>,
56 status: status::StatusCode,
57 headers: &'a mut header::Headers) -> Response<'a, Fresh> {
58 Response {
59 status: status,
60 version: version,
61 body: body,
62 headers: headers,
63 _writing: PhantomData,
64 }
65 }
66
67 #[inline]
69 pub fn deconstruct(self) -> (version::HttpVersion, HttpWriter<&'a mut (dyn Write + 'a)>,
70 status::StatusCode, &'a mut header::Headers) {
71 unsafe {
72 let parts = (
73 self.version,
74 ptr::read(&self.body),
75 self.status,
76 ptr::read(&self.headers)
77 );
78 mem::forget(self);
79 parts
80 }
81 }
82
83 fn write_head(&mut self) -> io::Result<Body> {
84 debug!("writing head: {:?} {:?}", self.version, self.status);
85 r#try!(write!(&mut self.body, "{} {}\r\n", self.version, self.status));
86
87 if !self.headers.has::<header::Date>() {
88 let date = httpdate::HttpDate::from(std::time::SystemTime::now()).to_string();
89 self.headers.set_raw("Date",vec![date.into_bytes()]);
90 }
91
92 let body_type = match self.status {
93 status::StatusCode::NoContent | status::StatusCode::NotModified => Body::Empty,
94 c if c.class() == status::StatusClass::Informational => Body::Empty,
95 _ => if let Some(cl) = self.headers.get::<header::ContentLength>() {
96 Body::Sized(**cl)
97 } else {
98 Body::Chunked
99 }
100 };
101
102 if body_type == Body::Chunked {
104 let encodings = match self.headers.get_mut::<header::TransferEncoding>() {
105 Some(&mut header::TransferEncoding(ref mut encodings)) => {
106 encodings.push(header::Encoding::Chunked);
108 false
109 },
110 None => true
111 };
112
113 if encodings {
114 self.headers.set::<header::TransferEncoding>(
115 header::TransferEncoding(vec![header::Encoding::Chunked]))
116 }
117 }
118
119
120 debug!("headers [\n{:?}]", self.headers);
121 r#try!(write!(&mut self.body, "{}", self.headers));
122 r#try!(write!(&mut self.body, "{}", LINE_ENDING));
123
124 Ok(body_type)
125 }
126}
127
128impl<'a> Response<'a, Fresh> {
129 #[inline]
131 pub fn new(stream: &'a mut (dyn Write + 'a), headers: &'a mut header::Headers) ->
132 Response<'a, Fresh> {
133 Response {
134 status: status::StatusCode::Ok,
135 version: version::HttpVersion::Http11,
136 headers: headers,
137 body: ThroughWriter(stream),
138 _writing: PhantomData,
139 }
140 }
141
142 #[inline]
170 pub fn send(self, body: &[u8]) -> io::Result<()> {
171 self.headers.set(header::ContentLength(body.len() as u64));
172 let mut stream = r#try!(self.start());
173 r#try!(stream.write_all(body));
174 stream.end()
175 }
176
177 pub fn start(mut self) -> io::Result<Response<'a, Streaming>> {
180 let body_type = r#try!(self.write_head());
181 let (version, body, status, headers) = self.deconstruct();
182 let stream = match body_type {
183 Body::Chunked => ChunkedWriter(body.into_inner()),
184 Body::Sized(len) => SizedWriter(body.into_inner(), len),
185 Body::Empty => EmptyWriter(body.into_inner()),
186 };
187
188 Ok(Response {
190 version: version,
191 body: stream,
192 status: status,
193 headers: headers,
194 _writing: PhantomData,
195 })
196 }
197 #[inline]
199 pub fn status_mut(&mut self) -> &mut status::StatusCode { &mut self.status }
200
201 #[inline]
203 pub fn headers_mut(&mut self) -> &mut header::Headers { self.headers }
204}
205
206
207impl<'a> Response<'a, Streaming> {
208 #[inline]
210 pub fn end(self) -> io::Result<()> {
211 trace!("ending");
212 let (_, body, _, _) = self.deconstruct();
213 r#try!(body.end());
214 Ok(())
215 }
216}
217
218impl<'a> Write for Response<'a, Streaming> {
219 #[inline]
220 fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
221 debug!("write {:?} bytes", msg.len());
222 self.body.write(msg)
223 }
224
225 #[inline]
226 fn flush(&mut self) -> io::Result<()> {
227 self.body.flush()
228 }
229}
230
231#[derive(PartialEq)]
232enum Body {
233 Chunked,
234 Sized(u64),
235 Empty,
236}
237
238impl<'a, T: Any> Drop for Response<'a, T> {
239 fn drop(&mut self) {
240 if TypeId::of::<T>() == TypeId::of::<Fresh>() {
241 if thread::panicking() {
242 self.status = status::StatusCode::InternalServerError;
243 }
244
245 let mut body = match self.write_head() {
246 Ok(Body::Chunked) => ChunkedWriter(self.body.get_mut()),
247 Ok(Body::Sized(len)) => SizedWriter(self.body.get_mut(), len),
248 Ok(Body::Empty) => EmptyWriter(self.body.get_mut()),
249 Err(e) => {
250 debug!("error dropping request: {:?}", e);
251 return;
252 }
253 };
254 end(&mut body);
255 } else {
256 end(&mut self.body);
257 };
258
259
260 #[inline]
261 fn end<W: Write>(w: &mut W) {
262 match w.write(&[]) {
263 Ok(_) => match w.flush() {
264 Ok(_) => debug!("drop successful"),
265 Err(e) => debug!("error dropping request: {:?}", e)
266 },
267 Err(e) => debug!("error dropping request: {:?}", e)
268 }
269 }
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use crate::header::Headers;
276 use crate::mock::MockStream;
277 use crate::runtime;
278 use crate::status::StatusCode;
279 use super::Response;
280
281 macro_rules! lines {
282 ($s:ident = $($line:pat),+) => ({
283 let s = String::from_utf8($s.write).unwrap();
284 let mut lines = s.split_terminator("\r\n");
285
286 $(
287 match lines.next() {
288 Some($line) => (),
289 other => panic!("line mismatch: {:?} != {:?}", other, stringify!($line))
290 }
291 )+
292
293 assert_eq!(lines.next(), None);
294 })
295 }
296
297 #[test]
298 fn test_fresh_start() {
299 let mut headers = Headers::new();
300 let mut stream = MockStream::new();
301 {
302 let res = Response::new(&mut stream, &mut headers);
303 res.start().unwrap().deconstruct();
304 }
305
306 lines! { stream =
307 "HTTP/1.1 200 OK",
308 _date,
309 _transfer_encoding,
310 ""
311 }
312 }
313
314 #[test]
315 fn test_streaming_end() {
316 let mut headers = Headers::new();
317 let mut stream = MockStream::new();
318 {
319 let res = Response::new(&mut stream, &mut headers);
320 res.start().unwrap().end().unwrap();
321 }
322
323 lines! { stream =
324 "HTTP/1.1 200 OK",
325 _date,
326 _transfer_encoding,
327 "",
328 "0",
329 "" }
331 }
332
333 #[test]
334 fn test_fresh_drop() {
335 use crate::status::StatusCode;
336 let mut headers = Headers::new();
337 let mut stream = MockStream::new();
338 {
339 let mut res = Response::new(&mut stream, &mut headers);
340 *res.status_mut() = StatusCode::NotFound;
341 }
342
343 lines! { stream =
344 "HTTP/1.1 404 Not Found",
345 _date,
346 _transfer_encoding,
347 "",
348 "0",
349 "" }
351 }
352
353 #[cfg(not(all(windows, target_arch="x86", target_env="msvc")))]
356 #[test]
357 fn test_fresh_drop_panicing() {
358 use std::thread;
359 use std::sync::{Arc, Mutex};
360
361 use crate::status::StatusCode;
362
363 let stream = MockStream::new();
364 let stream = Arc::new(Mutex::new(stream));
365 let inner_stream = stream.clone();
366 let join_handle = runtime::spawn(move || {
367 let mut headers = Headers::new();
368 let mut stream = inner_stream.lock().unwrap();
369 let mut res = Response::new(&mut *stream, &mut headers);
370 *res.status_mut() = StatusCode::NotFound;
371
372 panic!("inside")
373 });
374
375 assert!(join_handle.join().is_err());
376
377 let stream = match stream.lock() {
378 Err(poisoned) => poisoned.into_inner().clone(),
379 Ok(_) => unreachable!()
380 };
381
382 lines! { stream =
383 "HTTP/1.1 500 Internal Server Error",
384 _date,
385 _transfer_encoding,
386 "",
387 "0",
388 "" }
390 }
391
392
393 #[test]
394 fn test_streaming_drop() {
395 use std::io::Write;
396 use crate::status::StatusCode;
397 let mut headers = Headers::new();
398 let mut stream = MockStream::new();
399 {
400 let mut res = Response::new(&mut stream, &mut headers);
401 *res.status_mut() = StatusCode::NotFound;
402 let mut stream = res.start().unwrap();
403 stream.write_all(b"foo").unwrap();
404 }
405
406 lines! { stream =
407 "HTTP/1.1 404 Not Found",
408 _date,
409 _transfer_encoding,
410 "",
411 "3",
412 "foo",
413 "0",
414 "" }
416 }
417
418 #[test]
419 fn test_no_content() {
420 let mut headers = Headers::new();
421 let mut stream = MockStream::new();
422 {
423 let mut res = Response::new(&mut stream, &mut headers);
424 *res.status_mut() = StatusCode::NoContent;
425 res.start().unwrap();
426 }
427
428 lines! { stream =
429 "HTTP/1.1 204 No Content",
430 _date,
431 ""
432 }
433 }
434}