diff --git a/src/handle_client.rs b/src/handle_client.rs
new file mode 100644
index 0000000..b95dc7a
--- /dev/null
+++ b/src/handle_client.rs
@@ -0,0 +1,50 @@
+use base64::{Engine as _, engine::general_purpose::STANDARD};
+use sha1::{Digest, Sha1};
+use std::io::{Read, Result, Write};
+use std::net::TcpStream;
+
+
+use crate::read_header::read_header;
+
+pub fn handle_client(mut stream: TcpStream) -> Result<()> {
+ let mut buffer = [0; 512];
+
+ let bytes_read = stream.read(&mut buffer).expect("Failed to read stream");
+
+ let request = String::from_utf8_lossy(&buffer[..bytes_read]);
+
+ if request.contains("Upgrade: websocket") {
+ let mut websocket_key = String::new();
+ for line in request.lines() {
+ if line.starts_with("Sec-WebSocket-Key:") {
+ websocket_key = Some(line.split(":").nth(1).unwrap().trim().to_string()).unwrap();
+ }
+ }
+
+ let mut hasher = Sha1::new();
+ hasher.update(format!(
+ "{}258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
+ websocket_key
+ ));
+ let hashed_key = hasher.finalize();
+ let accepted_key = STANDARD.encode(hashed_key);
+
+ stream.write_all(
+ format!(
+ "HTTP/1.1 101 Switching Protocols\r\n\
+ Upgrade: websocket\r\n\
+ Connection: Upgrade\r\n\
+ Sec-WebSocket-Accept: {}\r\n\r\n",
+ accepted_key
+ )
+ .as_bytes(),
+ )?;
+
+ loop {
+ let _read_frame = read_header(&mut stream);
+ }
+ }
+ stream.write_all(b"HTTP/1.1 200 OK\r\n")?;
+ stream.write_all(b"Content-Type: text/html\r\n")?;
+ Ok(())
+}
\ No newline at end of file
diff --git a/src/index.html b/src/index.html
deleted file mode 100644
index cd480f4..0000000
--- a/src/index.html
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
- Rust Custom Server
-
-
- Hello from the Rust Server!
- This page was served by a custom HTTP server written in Rust.
- nice hello
-
-
-
-
-
-
diff --git a/src/main.rs b/src/main.rs
index 61004dd..4b7d9dd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,192 +1,12 @@
-use base64::{Engine as _, engine::general_purpose::STANDARD};
-use sha1::{Digest, Sha1};
-use std::io::{Read, Result, Write};
-use std::net::{TcpListener, TcpStream};
-use std::str::FromStr;
-use std::{fs, thread};
+use std::io::Result;
+use std::net::TcpListener;
+use std::thread;
-struct FrameHeader {
- fin: bool,
- opcode: u8,
- payload_len: u64,
- mask: bool,
- masking_key: Option<[u8; 4]>,
- message:Option,
-}
-
-enum Message {
- Text(String),
- Binary(Vec),
- Ping(String),
- Pong(String),
- Close(String),
- Continue(String),
-}
-
-
-fn send_message(stream: &mut TcpStream, msg: &str) -> Result<()> {
- let payload = msg.as_bytes();
-
- let mut frame = Vec::new();
-
- //first byte
- let fin = 1 << 7;
- let opcode = 0x1;
- frame.push(fin | opcode);
-
- //second byte
- let mask = 0x0;
- let payload_length = payload.len() as u8;
- frame.push(mask | payload_length);
-
- frame.extend_from_slice(payload);
-
- let _ = stream.write_all(&frame);
- Ok(())
-}
-
-fn read_header(stream: &mut TcpStream) -> Result {
- //read the first two bytes which will contain FIN and OPCODE flags and its size will be u8
- let mut first_two = [0u8; 2];
- let _ = stream.read_exact(&mut first_two);
-
- let byte_one = first_two[0];
- let byte_two = first_two[1];
-
- //here we are doing AND operation and extraction from the first byte only
- //1 & 0 = 0,1 & 1 =1
- //if fin =1 final frame, else continuous
- let fin = (byte_one & 0b1000_0000) != 0;
-
- //opcode tells us about type of the message being sent by the client
- let opcode = byte_one & 0b0000_1111;
-
- // here we will extract from the 2nd byte it will contain if the payload is masked or not and payload
- // if mask = 1 masked else not
- let mask = (byte_two & 0b1000_0000) != 0;
- let mut payload_len = (byte_two & 0b0111_1111) as u64;
-
- // here we are putting the checks for the payload len
- // normally payload len is 125
- // if it is 126 means the msg is larger and maybe in continuation
- // 127 is the larget len for a payload and takes 8 bytes of the space
- if payload_len == 126 {
- let mut next_two = [0u8; 2];
- let _ = stream.read_exact(&mut next_two);
- payload_len = u16::from_le_bytes(next_two) as u64;
- } else if payload_len == 127 {
- let mut next_eight = [0u8; 8];
- let _ = stream.read_exact(&mut next_eight);
- payload_len = u64::from_le_bytes(next_eight) as u64;
- }
-
- //here we will get the masking key if the payload is mask
- // this is rule from client to server it should be mask
- // from server to client it shouldn't
- let masking_key = if mask {
- let mut key = [0u8; 4];
- let _ = stream.read_exact(&mut key);
- Some(key)
- } else {
- None
- };
-
- //now we are converting the masked data to unmasked data
- let mut masked_data = vec![0u8;payload_len as usize];
- let _ = stream.read_exact(&mut masked_data);
- let key = masking_key.unwrap();
- let mut decoded_data = vec![0u8;payload_len as usize];
-
-
- if mask {
- for i in 0..payload_len {
- let idx:usize = i.try_into().unwrap();
- decoded_data[idx] = masked_data[idx] ^ key[idx % 4];
- }
- }
+mod read_header;
+mod send_message;
+mod handle_client;
- // here we will match all the types opcode can send and accordingly respond back
- let message : Option = match opcode {
- 0x1 => {
- Some(Message::Text(String::from_utf8(decoded_data).expect("undefined byte")))
- }
- 0x2 => {
- Some(Message::Binary(decoded_data))
- }
- 0x9 => {
- Some(Message::Ping(String::from_str("recieved ping").expect("undefined msg")))
- }
- 0xA => {
- Some(Message::Pong(String::from_str("client's pong").expect("undefined msg")))
- }
- 0x8 => {
- Some(Message::Close(String::from_str("client's close").expect("undefined msg")))
- }
- 0x0 => {
- Some(Message::Continue((String::from_str("Continuation").expect("undefined msg"))))
- }
- _=>None
- };
-
-
- Ok(FrameHeader {
- fin,
- opcode,
- payload_len,
- mask,
- masking_key,
- message
- })
-}
-
-fn handle_client(mut stream: TcpStream) -> Result<()> {
- let mut buffer = [0; 512];
-
- let bytes_read = stream.read(&mut buffer).expect("Failed to read stream");
-
- let request = String::from_utf8_lossy(&buffer[..bytes_read]);
-
- if request.contains("Upgrade: websocket") {
- let mut websocket_key = String::new();
- for line in request.lines() {
- if line.starts_with("Sec-WebSocket-Key:") {
- websocket_key = Some(line.split(":").nth(1).unwrap().trim().to_string()).unwrap();
- }
- }
-
- let mut hasher = Sha1::new();
- hasher.update(format!(
- "{}258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
- websocket_key
- ));
- let hashed_key = hasher.finalize();
- let accepted_key = STANDARD.encode(hashed_key);
-
- stream.write_all(
- format!(
- "HTTP/1.1 101 Switching Protocols\r\n\
- Upgrade: websocket\r\n\
- Connection: Upgrade\r\n\
- Sec-WebSocket-Accept: {}\r\n\r\n",
- accepted_key
- )
- .as_bytes(),
- )?;
- loop {
- let read_header = read_header(&mut stream);
- send_message(&mut stream, "hola");
- }
- }
-
- let contents = fs::read("src/index.html").unwrap();
-
- stream.write_all(b"HTTP/1.1 200 OK\r\n")?;
- stream.write_all(b"Content-Type: text/html\r\n")?;
- stream.write_all(format!("Content-Length: {}\r\n\r\n", contents.len()).as_bytes())?;
- stream.write_all(&contents)?;
-
- Ok(())
-}
+use handle_client::handle_client;
pub fn main() -> Result<()> {
let listener = TcpListener::bind("127.0.0.1:8080")?;
diff --git a/src/read_header.rs b/src/read_header.rs
new file mode 100644
index 0000000..c0c3af4
--- /dev/null
+++ b/src/read_header.rs
@@ -0,0 +1,111 @@
+use std::io::{Read, Result};
+use std::net::TcpStream;
+use std::str::FromStr;
+
+pub struct FrameHeader {
+ fin: bool,
+ opcode: u8,
+ payload_len: u64,
+ mask: bool,
+ masking_key: Option<[u8; 4]>,
+ message: Option,
+}
+
+pub enum Message {
+ Text(String),
+ Binary(Vec),
+ Ping(String),
+ Pong(String),
+ Close(String),
+ Continue(String),
+}
+
+pub fn read_header(stream: &mut TcpStream) -> Result {
+ //read the first two bytes which will contain FIN and OPCODE flags and its size will be u8
+ let mut first_two = [0u8; 2];
+ let _ = stream.read_exact(&mut first_two);
+
+ let byte_one = first_two[0];
+ let byte_two = first_two[1];
+
+ //here we are doing AND operation and extraction from the first byte only
+ //1 & 0 = 0,1 & 1 =1
+ //if fin =1 final frame, else continuous
+ let fin = (byte_one & 0b1000_0000) != 0;
+
+ //opcode tells us about type of the message being sent by the client
+ let opcode = byte_one & 0b0000_1111;
+
+ // here we will extract from the 2nd byte it will contain if the payload is masked or not and payload
+ // if mask = 1 masked else not
+ let mask = (byte_two & 0b1000_0000) != 0;
+ let mut payload_len = (byte_two & 0b0111_1111) as u64;
+
+ // here we are putting the checks for the payload len
+ // normally payload len is 125
+ // if it is 126 means the msg is larger and maybe in continuation
+ // 127 is the larget len for a payload and takes 8 bytes of the space
+ if payload_len == 126 {
+ let mut next_two = [0u8; 2];
+ let _ = stream.read_exact(&mut next_two);
+ payload_len = u16::from_le_bytes(next_two) as u64;
+ } else if payload_len == 127 {
+ let mut next_eight = [0u8; 8];
+ let _ = stream.read_exact(&mut next_eight);
+ payload_len = u64::from_le_bytes(next_eight) as u64;
+ }
+
+ //here we will get the masking key if the payload is mask
+ // this is rule from client to server it should be mask
+ // from server to client it shouldn't
+ let masking_key = if mask {
+ let mut key = [0u8; 4];
+ let _ = stream.read_exact(&mut key);
+ Some(key)
+ } else {
+ None
+ };
+
+ //now we are converting the masked data to unmasked data
+ let mut masked_data = vec![0u8; payload_len as usize];
+ let _ = stream.read_exact(&mut masked_data);
+ let key = masking_key.unwrap();
+ let mut decoded_data = vec![0u8; payload_len as usize];
+
+ if mask {
+ for i in 0..payload_len {
+ let idx: usize = i.try_into().unwrap();
+ decoded_data[idx] = masked_data[idx] ^ key[idx % 4];
+ }
+ }
+
+ // here we will match all the types opcode can send and accordingly respond back
+ let message: Option = match opcode {
+ 0x1 => Some(Message::Text(
+ String::from_utf8(decoded_data).expect("undefined byte"),
+ )),
+ 0x2 => Some(Message::Binary(decoded_data)),
+ 0x9 => Some(Message::Ping(
+ String::from_str("recieved ping").expect("undefined msg"),
+ )),
+ 0xA => Some(Message::Pong(
+ String::from_str("client's pong").expect("undefined msg"),
+ )),
+ 0x8 => Some(Message::Close(
+ String::from_str("client's close").expect("undefined msg"),
+ )),
+ 0x0 => Some(Message::Continue(
+ String::from_str("Continuation").expect("undefined msg"),
+ )),
+ _ => None,
+ };
+
+ Ok(FrameHeader {
+ fin,
+ opcode,
+ payload_len,
+ mask,
+ masking_key,
+ message,
+ })
+}
diff --git a/src/send_message.rs b/src/send_message.rs
new file mode 100644
index 0000000..61f64ef
--- /dev/null
+++ b/src/send_message.rs
@@ -0,0 +1,23 @@
+use std::io::{Result, Write};
+use std::net::TcpStream;
+
+pub fn send_message(stream: &mut TcpStream, msg: &str) -> Result<()> {
+ let payload = msg.as_bytes();
+
+ let mut frame = Vec::new();
+
+ //first byte
+ let fin = 1 << 7;
+ let opcode = 0x1;
+ frame.push(fin | opcode);
+
+ //second byte
+ let mask = 0x0;
+ let payload_length = payload.len() as u8;
+ frame.push(mask | payload_length);
+
+ frame.extend_from_slice(payload);
+
+ let _ = stream.write_all(&frame);
+ Ok(())
+}
\ No newline at end of file