1 use self::hyper::http::h1::Incoming;
2 use self::hyper::method::Method;
3 use self::hyper::uri::RequestUri;
4 use self::hyper::uri::RequestUri::AbsolutePath;
5 use super::hyper;
6 
7 use futures::future::Future;
8 use std::fs::File;
9 use std::rc::Rc;
10 
11 use crate::options::StaticFile;
12 use crate::trivial_peer::get_literal_peer_now;
13 use crate::Peer;
14 
15 use crate::my_copy::{copy, CopyOptions};
16 
17 const BAD_REQUEST :&[u8] = b"HTTP/1.1 400 Bad Request\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nOnly WebSocket connections are welcome here\n";
18 
19 const NOT_FOUND: &[u8] = b"HTTP/1.1 404 Not Found\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nURI does not match any -F option and is not a WebSocket connection.\n";
20 
21 const NOT_FOUND2: &[u8] = b"HTTP/1.1 500 Not Found\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nFailed to open the file on server side.\n";
22 
23 const BAD_METHOD :&[u8] = b"HTTP/1.1 400 Bad Request\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nHTTP method should be GET\n";
24 
25 const BAD_URI_FORMAT :&[u8] = b"HTTP/1.1 400 Bad Request\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nURI should be an absolute path\n";
26 
get_static_file_reply(len: Option<u64>, ct: &str) -> Vec<u8>27 fn get_static_file_reply(len: Option<u64>, ct: &str) -> Vec<u8> {
28     let mut q = Vec::with_capacity(256);
29     q.extend_from_slice(b"HTTP/1.1 200 OK\r\nServer: websocat\r\nContent-Type: ");
30     q.extend_from_slice(ct.as_bytes());
31     q.extend_from_slice(b"\r\n");
32     if let Some(x) = len {
33         q.extend_from_slice(b"Content-Length: ");
34         q.extend_from_slice(format!("{}", x).as_bytes());
35         q.extend_from_slice(b"\r\n");
36     }
37     q.extend_from_slice(b"\r\n");
38     q
39 }
40 
41 #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
http_serve( p: Peer, incoming: Option<Incoming<(Method, RequestUri)>>, serve_static_files: Rc<Vec<StaticFile>>, ) -> Box<dyn Future<Item = (), Error = ()>>42 pub fn http_serve(
43     p: Peer,
44     incoming: Option<Incoming<(Method, RequestUri)>>,
45     serve_static_files: Rc<Vec<StaticFile>>,
46 ) -> Box<dyn Future<Item = (), Error = ()>> {
47     let mut serve_file = None;
48     let content = if serve_static_files.is_empty() {
49         BAD_REQUEST.to_vec()
50     } else if let Some(inc) = incoming {
51         info!("HTTP-serving {:?}", inc.subject);
52         if inc.subject.0 == Method::Get {
53             match inc.subject.1 {
54                 AbsolutePath(x) => {
55                     let mut reply = None;
56                     for sf in &*serve_static_files {
57                         if sf.uri == x {
58                             match File::open(&sf.file) {
59                                 Ok(f) => {
60                                     let fs = match f.metadata() {
61                                         Err(_) => None,
62                                         Ok(x) => Some(x.len()),
63                                     };
64                                     reply = Some(get_static_file_reply(fs, &sf.content_type));
65                                     serve_file = Some(f);
66                                 }
67                                 Err(_) => {
68                                     reply = Some(NOT_FOUND2.to_vec());
69                                 }
70                             }
71                         }
72                     }
73                     reply.unwrap_or_else(|| NOT_FOUND.to_vec())
74                 }
75                 _ => BAD_URI_FORMAT.to_vec(),
76             }
77         } else {
78             BAD_METHOD.to_vec()
79         }
80     } else {
81         BAD_REQUEST.to_vec()
82     };
83     let reply = get_literal_peer_now(content);
84 
85     let co = CopyOptions {
86         buffer_size: 1024,
87         once: false,
88         stop_on_reader_zero_read: true,
89         skip: false,
90         max_ops: None,
91     };
92 
93     if let Some(f) = serve_file {
94         Box::new(
95             copy(reply, p.1, co)
96                 .map_err(drop)
97                 .and_then(move |(_len, _, conn)| {
98                     let co2 = CopyOptions {
99                         buffer_size: 65536,
100                         once: false,
101                         stop_on_reader_zero_read: true,
102                         skip: false,
103                         max_ops: None,
104                     };
105                     let wr = crate::file_peer::ReadFileWrapper(f);
106                     copy(wr, conn, co2).map(|_| ()).map_err(drop)
107                 }),
108         )
109     } else {
110         Box::new(copy(reply, p.1, co).map(|_| ()).map_err(drop))
111     }
112 }
113