WebSocket Firefox
This commit is contained in:
@ -24,14 +24,13 @@ pub fn connection_handler(client: super::Stream) {
|
|||||||
fn request_handler(client: &mut super::HttpStream) {
|
fn request_handler(client: &mut super::HttpStream) {
|
||||||
let mut res = super::Response::new();
|
let mut res = super::Response::new();
|
||||||
|
|
||||||
if let Some(conn) = res.find_header("Connection") {
|
|
||||||
client.client_keep_alive = client.client_keep_alive && conn.eq_ignore_ascii_case("keep-alive");
|
|
||||||
}
|
|
||||||
|
|
||||||
match super::parser::parse_request(&mut client.stream) {
|
match super::parser::parse_request(&mut client.stream) {
|
||||||
Ok(Some(req)) => {
|
Ok(Some(req)) => {
|
||||||
println!("{} {}", req.method, req.uri);
|
println!("{} {}", req.method, req.uri);
|
||||||
|
|
||||||
|
client.client_keep_alive =
|
||||||
|
client.client_keep_alive && req.header.field_has_value("Connection", "keep-alive");
|
||||||
|
|
||||||
if !req.uri.starts_with("/")
|
if !req.uri.starts_with("/")
|
||||||
|| req.uri.contains("/./")
|
|| req.uri.contains("/./")
|
||||||
|| req.uri.contains("/../")
|
|| req.uri.contains("/../")
|
||||||
@ -43,8 +42,8 @@ fn request_handler(client: &mut super::HttpStream) {
|
|||||||
} else if req.uri.eq("/") {
|
} else if req.uri.eq("/") {
|
||||||
res.status(200);
|
res.status(200);
|
||||||
} else if req.uri.starts_with("/_usimp/") {
|
} else if req.uri.starts_with("/_usimp/") {
|
||||||
res.add_header("Cache-Control", "no-store");
|
res.header.add_field("Cache-Control", "no-store");
|
||||||
res.add_header("Access-Control-Allow-Origin", "*");
|
res.header.add_field("Access-Control-Allow-Origin", "*");
|
||||||
|
|
||||||
if req.uri.eq("/_usimp/websocket") {
|
if req.uri.eq("/_usimp/websocket") {
|
||||||
return websocket::connection_handler(client, &req, res);
|
return websocket::connection_handler(client, &req, res);
|
||||||
@ -62,7 +61,7 @@ fn request_handler(client: &mut super::HttpStream) {
|
|||||||
Method::POST => return endpoint_handler(client, &req, res, endpoint),
|
Method::POST => return endpoint_handler(client, &req, res, endpoint),
|
||||||
_ => {
|
_ => {
|
||||||
res.status(405);
|
res.status(405);
|
||||||
res.add_header("Allow", "POST");
|
res.header.add_field("Allow", "POST");
|
||||||
error = Some(Error::new(Kind::UsimpProtocolError, Class::ClientError))
|
error = Some(Error::new(Kind::UsimpProtocolError, Class::ClientError))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -119,8 +118,10 @@ pub fn error_handler(client: &mut super::HttpStream, mut res: super::Response, e
|
|||||||
let buf = obj.to_string() + "\r\n";
|
let buf = obj.to_string() + "\r\n";
|
||||||
|
|
||||||
let length = buf.as_bytes().len();
|
let length = buf.as_bytes().len();
|
||||||
res.add_header("Content-Length", length.to_string().as_str());
|
res.header
|
||||||
res.add_header("Content-Type", "application/json; charset=utf-8");
|
.add_field("Content-Length", length.to_string().as_str());
|
||||||
|
res.header
|
||||||
|
.add_field("Content-Type", "application/json; charset=utf-8");
|
||||||
|
|
||||||
if let Err(e) = client.respond(&mut res) {
|
if let Err(e) = client.respond(&mut res) {
|
||||||
println!("Unable to send: {}", e);
|
println!("Unable to send: {}", e);
|
||||||
@ -136,7 +137,7 @@ fn endpoint_handler(
|
|||||||
mut res: super::Response,
|
mut res: super::Response,
|
||||||
endpoint: &str,
|
endpoint: &str,
|
||||||
) {
|
) {
|
||||||
let length = req.find_header("Content-Length");
|
let length = req.header.find_field("Content-Length");
|
||||||
let length: usize = match match length {
|
let length: usize = match match length {
|
||||||
Some(length) => length,
|
Some(length) => length,
|
||||||
None => {
|
None => {
|
||||||
@ -178,8 +179,10 @@ fn endpoint_handler(
|
|||||||
|
|
||||||
// TODO compress
|
// TODO compress
|
||||||
let length = buf.as_bytes().len();
|
let length = buf.as_bytes().len();
|
||||||
res.add_header("Content-Length", length.to_string().as_str());
|
res.header
|
||||||
res.add_header("Content-Type", "application/json; charset=utf-8");
|
.add_field("Content-Length", length.to_string().as_str());
|
||||||
|
res.header
|
||||||
|
.add_field("Content-Type", "application/json; charset=utf-8");
|
||||||
|
|
||||||
res.status(200);
|
res.status(200);
|
||||||
client.respond(&mut res).unwrap();
|
client.respond(&mut res).unwrap();
|
||||||
|
@ -66,13 +66,13 @@ pub struct Request {
|
|||||||
version: String,
|
version: String,
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
pub uri: String,
|
pub uri: String,
|
||||||
header: Header,
|
pub header: Header,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
version: String,
|
version: String,
|
||||||
status: Status,
|
status: Status,
|
||||||
header: Header,
|
pub header: Header,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Method {
|
impl Method {
|
||||||
@ -200,15 +200,17 @@ impl Header {
|
|||||||
value: String::from(value),
|
value: String::from(value),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Request {
|
pub fn field_has_value(&self, field_name: &str, value: &str) -> bool {
|
||||||
pub fn find_header(&self, name: &str) -> Option<&str> {
|
if let Some(field) = self.find_field(field_name) {
|
||||||
self.header.find_field(name)
|
let value = value.to_lowercase();
|
||||||
}
|
field
|
||||||
|
.to_lowercase()
|
||||||
pub fn add_header(&mut self, name: &str, value: &str) {
|
.split(",")
|
||||||
self.header.add_field(name, value)
|
.any(|mut s| s.trim().eq(value.as_str()))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,8 +221,8 @@ impl Response {
|
|||||||
status: Status::from_code(200).unwrap(),
|
status: Status::from_code(200).unwrap(),
|
||||||
header: Header::new(),
|
header: Header::new(),
|
||||||
};
|
};
|
||||||
res.add_header("Server", "Locutus");
|
res.header.add_field("Server", "Locutus");
|
||||||
res.add_header(
|
res.header.add_field(
|
||||||
"Date",
|
"Date",
|
||||||
chrono::Utc::now()
|
chrono::Utc::now()
|
||||||
.format("%a, %d %b %Y %H:%M:%S GMT")
|
.format("%a, %d %b %Y %H:%M:%S GMT")
|
||||||
@ -230,14 +232,6 @@ impl Response {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_header(&self, name: &str) -> Option<&str> {
|
|
||||||
self.header.find_field(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_header(&mut self, name: &str, value: &str) {
|
|
||||||
self.header.add_field(name, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn status(&mut self, status_code: u16) {
|
pub fn status(&mut self, status_code: u16) {
|
||||||
self.status = Status::from_code(status_code).unwrap()
|
self.status = Status::from_code(status_code).unwrap()
|
||||||
}
|
}
|
||||||
@ -261,13 +255,14 @@ impl Response {
|
|||||||
|
|
||||||
pub fn send_default(&mut self, stream: &mut Stream) -> Result<(), std::io::Error> {
|
pub fn send_default(&mut self, stream: &mut Stream) -> Result<(), std::io::Error> {
|
||||||
let mut buf = None;
|
let mut buf = None;
|
||||||
if let None = self.find_header("Content-Length") {
|
if let None = self.header.find_field("Content-Length") {
|
||||||
let new_buf = self.format_default_response();
|
let new_buf = self.format_default_response();
|
||||||
self.add_header(
|
self.header.add_field(
|
||||||
"Content-Length",
|
"Content-Length",
|
||||||
new_buf.as_bytes().len().to_string().as_str(),
|
new_buf.as_bytes().len().to_string().as_str(),
|
||||||
);
|
);
|
||||||
self.add_header("Content-Type", "text/html; charset=utf-8");
|
self.header
|
||||||
|
.add_field("Content-Type", "text/html; charset=utf-8");
|
||||||
buf = Some(new_buf);
|
buf = Some(new_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,8 +319,8 @@ impl HttpStream {
|
|||||||
|
|
||||||
fn keep_alive(&mut self, res: &mut Response) {
|
fn keep_alive(&mut self, res: &mut Response) {
|
||||||
if self.client_keep_alive && self.server_keep_alive {
|
if self.client_keep_alive && self.server_keep_alive {
|
||||||
res.add_header("Connection", "keep-alive");
|
res.header.add_field("Connection", "keep-alive");
|
||||||
res.add_header("Keep-Alive", "timeout=3600, max=200");
|
res.header.add_field("Keep-Alive", "timeout=3600, max=200");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ pub fn connection_handler(
|
|||||||
if let http::Method::GET = req.method {
|
if let http::Method::GET = req.method {
|
||||||
} else {
|
} else {
|
||||||
res.status(405);
|
res.status(405);
|
||||||
res.add_header("Allow", "GET");
|
res.header.add_field("Allow", "GET");
|
||||||
return http::error_handler(
|
return http::error_handler(
|
||||||
client,
|
client,
|
||||||
res,
|
res,
|
||||||
@ -23,8 +23,8 @@ pub fn connection_handler(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(connection) = req.find_header("Connection") {
|
if let Some(_) = req.header.find_field("Connection") {
|
||||||
if !connection.eq_ignore_ascii_case("upgrade") {
|
if !req.header.field_has_value("Connection", "upgrade") {
|
||||||
return http::error_handler(
|
return http::error_handler(
|
||||||
client,
|
client,
|
||||||
res,
|
res,
|
||||||
@ -41,7 +41,7 @@ pub fn connection_handler(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(upgrade) = req.find_header("Upgrade") {
|
if let Some(upgrade) = req.header.find_field("Upgrade") {
|
||||||
if !upgrade.eq_ignore_ascii_case("websocket") {
|
if !upgrade.eq_ignore_ascii_case("websocket") {
|
||||||
return http::error_handler(
|
return http::error_handler(
|
||||||
client,
|
client,
|
||||||
@ -59,7 +59,7 @@ pub fn connection_handler(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(version) = req.find_header("Sec-WebSocket-Version") {
|
if let Some(version) = req.header.find_field("Sec-WebSocket-Version") {
|
||||||
if !version.eq("13") {
|
if !version.eq("13") {
|
||||||
return http::error_handler(
|
return http::error_handler(
|
||||||
client,
|
client,
|
||||||
@ -77,7 +77,7 @@ pub fn connection_handler(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(key) = req.find_header("Sec-WebSocket-Key") {
|
if let Some(key) = req.header.find_field("Sec-WebSocket-Key") {
|
||||||
let mut hasher = crypto::sha1::Sha1::new();
|
let mut hasher = crypto::sha1::Sha1::new();
|
||||||
hasher.input_str(key);
|
hasher.input_str(key);
|
||||||
hasher.input_str("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
hasher.input_str("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||||
@ -85,7 +85,7 @@ pub fn connection_handler(
|
|||||||
let mut result = [0u8; 160 / 8];
|
let mut result = [0u8; 160 / 8];
|
||||||
hasher.result(&mut result);
|
hasher.result(&mut result);
|
||||||
let key = base64::encode(result);
|
let key = base64::encode(result);
|
||||||
res.add_header("Sec-WebSocket-Accept", key.as_str());
|
res.header.add_field("Sec-WebSocket-Accept", key.as_str());
|
||||||
} else {
|
} else {
|
||||||
return http::error_handler(
|
return http::error_handler(
|
||||||
client,
|
client,
|
||||||
@ -96,8 +96,8 @@ pub fn connection_handler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
client.server_keep_alive = false;
|
client.server_keep_alive = false;
|
||||||
res.add_header("Connection", "Upgrade");
|
res.header.add_field("Connection", "Upgrade");
|
||||||
res.add_header("Upgrade", "websocket");
|
res.header.add_field("Upgrade", "websocket");
|
||||||
|
|
||||||
res.status(101);
|
res.status(101);
|
||||||
res.send(&mut client.stream).unwrap();
|
res.send(&mut client.stream).unwrap();
|
||||||
|
Reference in New Issue
Block a user