1use common::{Header, HTTPVersion, StatusCode, HTTPDate};
2
3use std::cmp::Ordering;
4use std::sync::mpsc::Receiver;
5
6use std::io::{self, Read, Write, Cursor};
7use std::io::Result as IoResult;
8
9use std::fs::File;
10
11use std::str::FromStr;
12
13pub struct Response<R> where R: Read {
37 reader: R,
38 status_code: StatusCode,
39 headers: Vec<Header>,
40 data_length: Option<usize>,
41 chunked_threshold: Option<usize>
42}
43
44pub type ResponseBox = Response<Box<Read + Send>>;
46
47#[derive(Copy, Clone)]
50enum TransferEncoding {
51 Identity,
52 Chunked,
53}
54
55impl FromStr for TransferEncoding {
56 type Err = ();
57
58 fn from_str(input: &str) -> Result<TransferEncoding, ()> {
59 if input.eq_ignore_ascii_case("identity") {
60 Ok(TransferEncoding::Identity)
61 } else if input.eq_ignore_ascii_case("chunked") {
62 Ok(TransferEncoding::Chunked)
63 } else {
64 Err(())
65 }
66 }
67}
68
69fn build_date_header() -> Header {
71 let d = HTTPDate::new();
72 Header::from_bytes(&b"Date"[..], &d.to_string().into_bytes()[..]).unwrap()
73}
74
75fn write_message_header<W>(mut writer: W, http_version: &HTTPVersion,
76 status_code: &StatusCode, headers: &[Header])
77 -> IoResult<()> where W: Write
78{
79 try!(write!(&mut writer, "HTTP/{}.{} {} {}\r\n",
81 http_version.0,
82 http_version.1,
83 status_code.0,
84 status_code.default_reason_phrase()
85 ));
86
87 for header in headers.iter() {
89 try!(writer.write_all(header.field.as_str().as_ref()));
90 try!(write!(&mut writer, ": "));
91 try!(writer.write_all(header.value.as_str().as_ref()));
92 try!(write!(&mut writer, "\r\n"));
93 }
94
95 try!(write!(&mut writer, "\r\n"));
97
98 Ok(())
99}
100
101fn choose_transfer_encoding(request_headers: &[Header], http_version: &HTTPVersion,
102 entity_length: &Option<usize>, has_additional_headers: bool,
103 chunked_threshold: usize)
104 -> TransferEncoding
105{
106 use util;
107
108 if *http_version <= (1, 0) {
110 return TransferEncoding::Identity;
111 }
112
113 let user_request = request_headers.iter()
115 .find(|h| h.field.equiv(&"TE"))
117
118 .map(|h| h.value.clone())
120
121 .and_then(|value| {
123 let mut parse = util::parse_header_value(value.as_str()); parse.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(Ordering::Equal));
128
129 for value in parse.iter() {
131 if value.1 <= 0.0 { continue }
133
134 match <TransferEncoding as FromStr>::from_str(value.0) {
135 Ok(te) => return Some(te),
136 _ => () };
138 }
139
140 None
142 });
143
144 if let Some(user_request) = user_request {
146 return user_request;
147 }
148
149 if has_additional_headers {
151 return TransferEncoding::Chunked;
152 }
153
154 if entity_length.as_ref().map_or(true, |val| *val >= chunked_threshold) {
156 return TransferEncoding::Chunked;
157 }
158
159 TransferEncoding::Identity
161}
162
163impl<R> Response<R> where R: Read {
164 pub fn new(status_code: StatusCode, headers: Vec<Header>,
171 data: R, data_length: Option<usize>,
172 additional_headers: Option<Receiver<Header>>)
173 -> Response<R>
174 {
175 let mut response = Response {
176 reader: data,
177 status_code: status_code,
178 headers: Vec::with_capacity(16),
179 data_length: data_length,
180 chunked_threshold: None,
181 };
182
183 for h in headers {
184 response.add_header(h)
185 }
186
187 if let Some(additional_headers) = additional_headers {
189 for h in additional_headers.iter() {
190 response.add_header(h)
191 }
192 }
193
194 response
195 }
196
197 pub fn with_chunked_threshold(mut self, length: usize) -> Response<R>{
202 self.chunked_threshold = Some(length);
203 self
204 }
205
206 pub fn chunked_threshold(&self) -> usize {
211 self.chunked_threshold.unwrap_or(32768)
212 }
213
214 pub fn add_header<H>(&mut self, header: H) where H: Into<Header> {
217 let header = header.into();
218
219 if header.field.equiv(&"Accept-Ranges") ||
221 header.field.equiv(&"Connection") ||
222 header.field.equiv(&"Content-Range") ||
223 header.field.equiv(&"Trailer") ||
224 header.field.equiv(&"Transfer-Encoding") ||
225 header.field.equiv(&"Upgrade")
226 {
227 return;
228 }
229
230 if header.field.equiv(&"Content-Length") {
232 match <usize as FromStr>::from_str(header.value.as_str()) {
233 Ok(val) => self.data_length = Some(val),
234 Err(_) => () };
236
237 return;
238 }
239
240 self.headers.push(header);
241 }
242
243 #[inline]
248 pub fn with_header<H>(mut self, header: H) -> Response<R> where H: Into<Header> {
249 self.add_header(header.into());
250 self
251 }
252
253 #[inline]
255 pub fn with_status_code<S>(mut self, code: S) -> Response<R> where S: Into<StatusCode> {
256 self.status_code = code.into();
257 self
258 }
259
260 pub fn with_data<S>(self, reader: S, data_length: Option<usize>) -> Response<S> where S: Read {
262 Response {
263 reader: reader,
264 headers: self.headers,
265 status_code: self.status_code,
266 data_length: data_length,
267 chunked_threshold: None,
268 }
269 }
270
271 pub fn raw_print<W: Write>(mut self, mut writer: W, http_version: HTTPVersion,
281 request_headers: &[Header], do_not_send_body: bool,
282 upgrade: Option<&str>)
283 -> IoResult<()>
284 {
285 let mut transfer_encoding = Some(choose_transfer_encoding(request_headers,
286 &http_version, &self.data_length, false ,
287 self.chunked_threshold()));
288
289 if self.headers.iter().find(|h| h.field.equiv(&"Date")).is_none() {
291 self.headers.insert(0, build_date_header());
292 }
293
294 if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
296 self.headers.insert(0,
297 Header::from_bytes(&b"Server"[..], &b"tiny-http (Rust)"[..]).unwrap()
298 );
299 }
300
301 if let Some(upgrade) = upgrade {
303 self.headers.insert(0, Header::from_bytes(&b"Upgrade"[..], upgrade.as_bytes()).unwrap());
304 self.headers.insert(0, Header::from_bytes(&b"Connection"[..], &b"upgrade"[..]).unwrap());
305 transfer_encoding = None;
306 }
307
308 let (mut reader, data_length) = match (self.data_length, transfer_encoding) {
312 (Some(l), _) => (Box::new(self.reader) as Box<Read>, Some(l)),
313 (None, Some(TransferEncoding::Identity)) => {
314 let mut buf = Vec::new();
315 try!(self.reader.read_to_end(&mut buf));
316 let l = buf.len();
317 (Box::new(Cursor::new(buf)) as Box<Read>, Some(l))
318 },
319 _ => (Box::new(self.reader) as Box<Read>, None),
320 };
321
322 let do_not_send_body = do_not_send_body ||
324 match self.status_code.0 {
325 100...199 | 204 | 304 => true,
327 _ => false
328 };
329
330 match transfer_encoding {
332 Some(TransferEncoding::Chunked) => {
333 self.headers.push(
334 Header::from_bytes(&b"Transfer-Encoding"[..], &b"chunked"[..]).unwrap()
335 )
336 },
337
338 Some(TransferEncoding::Identity) => {
339 assert!(data_length.is_some());
340 let data_length = data_length.unwrap();
341
342 self.headers.push(
343 Header::from_bytes(&b"Content-Length"[..], format!("{}", data_length).as_bytes()).unwrap()
344 )
345 },
346
347 _ => ()
348 };
349
350 try!(write_message_header(writer.by_ref(), &http_version,
352 &self.status_code, &self.headers));
353
354 if !do_not_send_body {
356 match transfer_encoding {
357
358 Some(TransferEncoding::Chunked) => {
359 use chunked_transfer::Encoder;
360
361 let mut writer = Encoder::new(writer);
362 try!(io::copy(&mut reader, &mut writer));
363 },
364
365 Some(TransferEncoding::Identity) => {
366 use util::EqualReader;
367
368 assert!(data_length.is_some());
369 let data_length = data_length.unwrap();
370
371 if data_length >= 1 {
372 let (mut equ_reader, _) =
373 EqualReader::new(reader.by_ref(), data_length);
374 try!(io::copy(&mut equ_reader, &mut writer));
375 }
376 },
377
378 _ => ()
379
380 }
381 }
382
383 Ok(())
384 }
385}
386
387impl<R> Response<R> where R: Read + Send + 'static {
388 pub fn boxed(self) -> ResponseBox {
390 Response {
391 reader: Box::new(self.reader) as Box<Read + Send>,
392 status_code: self.status_code,
393 headers: self.headers,
394 data_length: self.data_length,
395 chunked_threshold: None,
396 }
397 }
398}
399
400impl Response<File> {
401 pub fn from_file(file: File) -> Response<File> {
406 let file_size = file.metadata().ok().map(|v| v.len() as usize);
407
408 Response::new(
409 StatusCode(200),
410 Vec::with_capacity(0),
411 file,
412 file_size,
413 None,
414 )
415 }
416}
417
418impl Response<Cursor<Vec<u8>>> {
419 pub fn from_data<D>(data: D) -> Response<Cursor<Vec<u8>>> where D: Into<Vec<u8>> {
420 let data = data.into();
421 let data_len = data.len();
422
423 Response::new(
424 StatusCode(200),
425 Vec::with_capacity(0),
426 Cursor::new(data),
427 Some(data_len),
428 None,
429 )
430 }
431
432 pub fn from_string<S>(data: S) -> Response<Cursor<Vec<u8>>> where S: Into<String> {
433 let data = data.into();
434 let data_len = data.len();
435
436 Response::new(
437 StatusCode(200),
438 vec![
439 Header::from_bytes(&b"Content-Type"[..], &b"text/plain; charset=UTF-8"[..]).unwrap()
440 ],
441 Cursor::new(data.into_bytes()),
442 Some(data_len),
443 None,
444 )
445 }
446}
447
448impl Response<io::Empty> {
449 pub fn empty<S>(status_code: S) -> Response<io::Empty> where S: Into<StatusCode> {
451 Response::new(
452 status_code.into(),
453 Vec::with_capacity(0),
454 io::empty(),
455 Some(0),
456 None,
457 )
458 }
459
460 pub fn new_empty(status_code: StatusCode) -> Response<io::Empty> {
462 Response::empty(status_code)
463 }
464}
465
466impl Clone for Response<io::Empty> {
467 fn clone(&self) -> Response<io::Empty> {
468 Response {
469 reader: io::empty(),
470 status_code: self.status_code.clone(),
471 headers: self.headers.clone(),
472 data_length: self.data_length.clone(),
473 chunked_threshold: self.chunked_threshold.clone(),
474 }
475 }
476}