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