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