1use crate::common::{HTTPVersion, Header, StatusCode};
2use httpdate::HttpDate;
3use std::cmp::Ordering;
4use std::sync::mpsc::Receiver;
5
6use std::io::Result as IoResult;
7use std::io::{self, Cursor, Read, Write};
8
9use std::fs::File;
10
11use std::str::FromStr;
12use std::time::SystemTime;
13
14pub struct Response<R> {
41 reader: R,
42 status_code: StatusCode,
43 headers: Vec<Header>,
44 data_length: Option<usize>,
45 chunked_threshold: Option<usize>,
46}
47
48pub type ResponseBox = Response<Box<dyn Read + Send>>;
50
51#[derive(Copy, Clone)]
54enum TransferEncoding {
55 Identity,
56 Chunked,
57}
58
59impl FromStr for TransferEncoding {
60 type Err = ();
61
62 fn from_str(input: &str) -> Result<TransferEncoding, ()> {
63 if input.eq_ignore_ascii_case("identity") {
64 Ok(TransferEncoding::Identity)
65 } else if input.eq_ignore_ascii_case("chunked") {
66 Ok(TransferEncoding::Chunked)
67 } else {
68 Err(())
69 }
70 }
71}
72
73fn build_date_header() -> Header {
75 let d = HttpDate::from(SystemTime::now());
76 Header::from_bytes(&b"Date"[..], &d.to_string().into_bytes()[..]).unwrap()
77}
78
79fn write_message_header<W>(
80 mut writer: W,
81 http_version: &HTTPVersion,
82 status_code: &StatusCode,
83 headers: &[Header],
84) -> IoResult<()>
85where
86 W: Write,
87{
88 write!(
90 &mut writer,
91 "HTTP/{}.{} {} {}\r\n",
92 http_version.0,
93 http_version.1,
94 status_code.0,
95 status_code.default_reason_phrase()
96 )?;
97
98 for header in headers.iter() {
100 writer.write_all(header.field.as_str().as_ref())?;
101 write!(&mut writer, ": ")?;
102 writer.write_all(header.value.as_str().as_ref())?;
103 write!(&mut writer, "\r\n")?;
104 }
105
106 write!(&mut writer, "\r\n")?;
108
109 Ok(())
110}
111
112fn choose_transfer_encoding(
113 status_code: StatusCode,
114 request_headers: &[Header],
115 http_version: &HTTPVersion,
116 entity_length: &Option<usize>,
117 has_additional_headers: bool,
118 chunked_threshold: usize,
119) -> TransferEncoding {
120 use crate::util;
121
122 if *http_version <= (1, 0) {
124 return TransferEncoding::Identity;
125 }
126
127 if status_code.0 < 200 || status_code.0 == 204 {
131 return TransferEncoding::Identity;
132 }
133
134 let user_request = request_headers
136 .iter()
137 .find(|h| h.field.equiv("TE"))
139 .map(|h| h.value.clone())
141 .and_then(|value| {
143 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));
148
149 for value in parse.iter() {
151 if value.1 <= 0.0 {
153 continue;
154 }
155
156 if let Ok(te) = TransferEncoding::from_str(value.0) {
157 return Some(te);
158 }
159 }
160
161 None
163 });
164
165 if let Some(user_request) = user_request {
166 return user_request;
167 }
168
169 if has_additional_headers {
171 return TransferEncoding::Chunked;
172 }
173
174 if entity_length
176 .as_ref()
177 .map_or(true, |val| *val >= chunked_threshold)
178 {
179 return TransferEncoding::Chunked;
180 }
181
182 TransferEncoding::Identity
184}
185
186impl<R> Response<R>
187where
188 R: Read,
189{
190 pub fn new(
197 status_code: StatusCode,
198 headers: Vec<Header>,
199 data: R,
200 data_length: Option<usize>,
201 additional_headers: Option<Receiver<Header>>,
202 ) -> Response<R> {
203 let mut response = Response {
204 reader: data,
205 status_code,
206 headers: Vec::with_capacity(16),
207 data_length,
208 chunked_threshold: None,
209 };
210
211 for h in headers {
212 response.add_header(h)
213 }
214
215 if let Some(additional_headers) = additional_headers {
217 for h in additional_headers.iter() {
218 response.add_header(h)
219 }
220 }
221
222 response
223 }
224
225 pub fn with_chunked_threshold(mut self, length: usize) -> Response<R> {
230 self.chunked_threshold = Some(length);
231 self
232 }
233
234 pub fn into_reader(self) -> R {
238 self.reader
239 }
240
241 pub fn chunked_threshold(&self) -> usize {
246 self.chunked_threshold.unwrap_or(32768)
247 }
248
249 pub fn add_header<H>(&mut self, header: H)
252 where
253 H: Into<Header>,
254 {
255 let header = header.into();
256
257 if header.field.equiv("Connection")
259 || header.field.equiv("Trailer")
260 || header.field.equiv("Transfer-Encoding")
261 || header.field.equiv("Upgrade")
262 {
263 return;
264 }
265
266 if header.field.equiv("Content-Length") {
268 if let Ok(val) = usize::from_str(header.value.as_str()) {
269 self.data_length = Some(val)
270 }
271
272 return;
273 } else if header.field.equiv("Content-Type") {
275 if let Some(content_type_header) = self
276 .headers
277 .iter_mut()
278 .find(|h| h.field.equiv("Content-Type"))
279 {
280 content_type_header.value = header.value;
281 return;
282 }
283 }
284
285 self.headers.push(header);
286 }
287
288 #[inline]
293 pub fn with_header<H>(mut self, header: H) -> Response<R>
294 where
295 H: Into<Header>,
296 {
297 self.add_header(header.into());
298 self
299 }
300
301 #[inline]
303 pub fn with_status_code<S>(mut self, code: S) -> Response<R>
304 where
305 S: Into<StatusCode>,
306 {
307 self.status_code = code.into();
308 self
309 }
310
311 pub fn with_data<S>(self, reader: S, data_length: Option<usize>) -> Response<S>
313 where
314 S: Read,
315 {
316 Response {
317 reader,
318 headers: self.headers,
319 status_code: self.status_code,
320 data_length,
321 chunked_threshold: self.chunked_threshold,
322 }
323 }
324
325 pub fn raw_print<W: Write>(
335 mut self,
336 mut writer: W,
337 http_version: HTTPVersion,
338 request_headers: &[Header],
339 do_not_send_body: bool,
340 upgrade: Option<&str>,
341 ) -> IoResult<()> {
342 let mut transfer_encoding = Some(choose_transfer_encoding(
343 self.status_code,
344 request_headers,
345 &http_version,
346 &self.data_length,
347 false, self.chunked_threshold(),
349 ));
350
351 if !self.headers.iter().any(|h| h.field.equiv("Date")) {
353 self.headers.insert(0, build_date_header());
354 }
355
356 if !self.headers.iter().any(|h| h.field.equiv("Server")) {
358 self.headers.insert(
359 0,
360 Header::from_bytes(&b"Server"[..], &b"tiny-http (Rust)"[..]).unwrap(),
361 );
362 }
363
364 if let Some(upgrade) = upgrade {
366 self.headers.insert(
367 0,
368 Header::from_bytes(&b"Upgrade"[..], upgrade.as_bytes()).unwrap(),
369 );
370 self.headers.insert(
371 0,
372 Header::from_bytes(&b"Connection"[..], &b"upgrade"[..]).unwrap(),
373 );
374 transfer_encoding = None;
375 }
376
377 let (mut reader, data_length): (Box<dyn Read>, _) =
381 match (self.data_length, transfer_encoding) {
382 (Some(l), _) => (Box::new(self.reader), Some(l)),
383 (None, Some(TransferEncoding::Identity)) => {
384 let mut buf = Vec::new();
385 self.reader.read_to_end(&mut buf)?;
386 let l = buf.len();
387 (Box::new(Cursor::new(buf)), Some(l))
388 }
389 _ => (Box::new(self.reader), None),
390 };
391
392 let do_not_send_body = do_not_send_body
394 || match self.status_code.0 {
395 100..=199 | 204 | 304 => true,
397 _ => false,
398 };
399
400 match transfer_encoding {
402 Some(TransferEncoding::Chunked) => self
403 .headers
404 .push(Header::from_bytes(&b"Transfer-Encoding"[..], &b"chunked"[..]).unwrap()),
405
406 Some(TransferEncoding::Identity) => {
407 assert!(data_length.is_some());
408 let data_length = data_length.unwrap();
409
410 self.headers.push(
411 Header::from_bytes(
412 &b"Content-Length"[..],
413 format!("{}", data_length).as_bytes(),
414 )
415 .unwrap(),
416 )
417 }
418
419 _ => (),
420 };
421
422 write_message_header(
424 writer.by_ref(),
425 &http_version,
426 &self.status_code,
427 &self.headers,
428 )?;
429
430 if !do_not_send_body {
432 match transfer_encoding {
433 Some(TransferEncoding::Chunked) => {
434 use chunked_transfer::Encoder;
435
436 let mut writer = Encoder::new(writer);
437 io::copy(&mut reader, &mut writer)?;
438 }
439
440 Some(TransferEncoding::Identity) => {
441 assert!(data_length.is_some());
442 let data_length = data_length.unwrap();
443
444 if data_length >= 1 {
445 io::copy(&mut reader, &mut writer)?;
446 }
447 }
448
449 _ => (),
450 }
451 }
452
453 Ok(())
454 }
455
456 pub fn status_code(&self) -> StatusCode {
458 self.status_code
459 }
460
461 pub fn data_length(&self) -> Option<usize> {
463 self.data_length
464 }
465
466 pub fn headers(&self) -> &[Header] {
468 &self.headers
469 }
470}
471
472impl<R> Response<R>
473where
474 R: Read + Send + 'static,
475{
476 pub fn boxed(self) -> ResponseBox {
478 Response {
479 reader: Box::new(self.reader) as Box<dyn Read + Send>,
480 status_code: self.status_code,
481 headers: self.headers,
482 data_length: self.data_length,
483 chunked_threshold: self.chunked_threshold,
484 }
485 }
486}
487
488impl Response<File> {
489 pub fn from_file(file: File) -> Response<File> {
494 let file_size = file.metadata().ok().map(|v| v.len() as usize);
495
496 Response::new(
497 StatusCode(200),
498 Vec::with_capacity(0),
499 file,
500 file_size,
501 None,
502 )
503 }
504}
505
506impl Response<Cursor<Vec<u8>>> {
507 pub fn from_data<D>(data: D) -> Response<Cursor<Vec<u8>>>
508 where
509 D: Into<Vec<u8>>,
510 {
511 let data = data.into();
512 let data_len = data.len();
513
514 Response::new(
515 StatusCode(200),
516 Vec::with_capacity(0),
517 Cursor::new(data),
518 Some(data_len),
519 None,
520 )
521 }
522
523 pub fn from_string<S>(data: S) -> Response<Cursor<Vec<u8>>>
524 where
525 S: Into<String>,
526 {
527 let data = data.into();
528 let data_len = data.len();
529
530 Response::new(
531 StatusCode(200),
532 vec![
533 Header::from_bytes(&b"Content-Type"[..], &b"text/plain; charset=UTF-8"[..])
534 .unwrap(),
535 ],
536 Cursor::new(data.into_bytes()),
537 Some(data_len),
538 None,
539 )
540 }
541}
542
543impl Response<io::Empty> {
544 pub fn empty<S>(status_code: S) -> Response<io::Empty>
546 where
547 S: Into<StatusCode>,
548 {
549 Response::new(
550 status_code.into(),
551 Vec::with_capacity(0),
552 io::empty(),
553 Some(0),
554 None,
555 )
556 }
557
558 pub fn new_empty(status_code: StatusCode) -> Response<io::Empty> {
560 Response::empty(status_code)
561 }
562}
563
564impl Clone for Response<io::Empty> {
565 fn clone(&self) -> Response<io::Empty> {
566 Response {
567 reader: io::empty(),
568 status_code: self.status_code,
569 headers: self.headers.clone(),
570 data_length: self.data_length,
571 chunked_threshold: self.chunked_threshold,
572 }
573 }
574}