From ff4c530c929ce10683392c37ee6e20043634c601 Mon Sep 17 00:00:00 2001 From: Shivendra Mishra Date: Sat, 24 Jan 2026 02:33:24 +0530 Subject: [PATCH 1/2] feat(ws frames): handles all types of flags and response from the client --- src/handle_client.rs | 99 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 8 deletions(-) diff --git a/src/handle_client.rs b/src/handle_client.rs index b95dc7a..37c8b74 100644 --- a/src/handle_client.rs +++ b/src/handle_client.rs @@ -3,24 +3,48 @@ use sha1::{Digest, Sha1}; use std::io::{Read, Result, Write}; use std::net::TcpStream; - use crate::read_header::read_header; +use crate::send_message::send_message; pub fn handle_client(mut stream: TcpStream) -> Result<()> { - let mut buffer = [0; 512]; + // these variable are here to read all the buffer sent from the client + let mut buffer = Vec::new(); + let mut temp = [0u8;1024]; + + loop{ + let bytes_read = stream.read(&mut temp).expect("failed to read stream"); + //break the connection here if no bytes read + if bytes_read == 0{ + break; + } - let bytes_read = stream.read(&mut buffer).expect("Failed to read stream"); + //merge the bytes read in the buffer + buffer.extend_from_slice(&temp[..bytes_read]); - let request = String::from_utf8_lossy(&buffer[..bytes_read]); + //if we find any bytes \r\n\r\n , stop reading more frames + // \r\n\r\n = CR LF CR LF + // CR = Carriage Line = \r = ASCII 13 + // LF = Line feed = \n = ASCII 10 + // in HTTP protocol this is considered to use when we have to end any message. + if buffer.windows(4).any(|w| w == b"\r\n\r\n"){ + break; + } + } + //convert the buffer byte to string + let request = String::from_utf8_lossy(&buffer); + + //check if the request contains the upgrade websocket if request.contains("Upgrade: websocket") { let mut websocket_key = String::new(); + //get the key to upgrade the protocol for line in request.lines() { if line.starts_with("Sec-WebSocket-Key:") { websocket_key = Some(line.split(":").nth(1).unwrap().trim().to_string()).unwrap(); } } + // use sha1 to encrypt the key and send it back to the client let mut hasher = Sha1::new(); hasher.update(format!( "{}258EAFA5-E914-47DA-95CA-C5AB0DC85B11", @@ -29,6 +53,7 @@ pub fn handle_client(mut stream: TcpStream) -> Result<()> { let hashed_key = hasher.finalize(); let accepted_key = STANDARD.encode(hashed_key); + // use the 101 status code to upgrade the connection stream.write_all( format!( "HTTP/1.1 101 Switching Protocols\r\n\ @@ -40,11 +65,69 @@ pub fn handle_client(mut stream: TcpStream) -> Result<()> { .as_bytes(), )?; + //open the loop to read the streams in websocket protocol loop { - let _read_frame = read_header(&mut stream); + let fin_code = 0b1000_0000; + let mut final_message = Vec::new(); + let mut is_first = true; + let mut opcode: u8 = 0; + + loop { + //read each from coming from the the client + let frame = read_header(&mut stream).unwrap(); + let cont_opcode = frame.opcode; + + //close frame from the client + if cont_opcode == 0b0000_1000 { + let byte1 = fin_code | 0b0000_1000; + send_message(&mut stream, byte1, &frame.decoded_data)?; + return Ok(()); + } + + //ping from the client + if cont_opcode == 0b0000_1001 { + let byte1 = fin_code | 0b0000_1010; + send_message(&mut stream, byte1, &frame.decoded_data)?; + continue; + } + + //pong from the client + if cont_opcode == 0b0000_1010 { + continue; + } + + //set opcode from the first frame as it changes from the current form to another as new frame comes + //1st frame tells the type , 2nd frame 0 untill fin flag become 1 + if is_first { + opcode = cont_opcode; + is_first = false; + } + + final_message.extend(frame.decoded_data); //extend the final message untill the final frame comes + if frame.fin { + break; //break the loop when final frame comes + } + } + + //handle the TEXT and BINARY opcode types + //TEXT type opcode = 1 (0b0000_0001) + //BINARY type opcode = 2 (0b0000_0010) + if opcode == 0b0000_0001 { + if let Ok(text) = String::from_utf8(final_message.clone()){ + println!("Text recieved : {}",text); + + let byte1 = fin_code | opcode; + send_message(&mut stream, byte1, text.as_bytes())?; + continue; + } + } else { + println!("Recieved {} of binary message",final_message.len()); + + let byte1 = fin_code | opcode; + send_message(&mut stream, byte1, &final_message)?; + continue; + } } } - 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 +} From 03b81e6cfe40323f5e295e46ac927044af513307 Mon Sep 17 00:00:00 2001 From: Shivendra Mishra Date: Sat, 24 Jan 2026 02:37:21 +0530 Subject: [PATCH 2/2] feat(response) : stream the data and frames to the client with all the flags and payload --- src/read_header.rs | 13 ++++--------- src/send_message.rs | 28 +++++++++++++++------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/read_header.rs b/src/read_header.rs index 6161220..d6cc056 100644 --- a/src/read_header.rs +++ b/src/read_header.rs @@ -1,13 +1,11 @@ use std::io::{Read, Result}; use std::net::TcpStream; +#[derive(Debug,Clone)] pub struct FrameHeader { - fin: bool, - opcode: u8, - payload_len: u64, - mask: bool, - masking_key: Option<[u8; 4]>, - decoded_data : Vec, + pub fin: bool, + pub opcode: u8, + pub decoded_data : Vec, } pub fn read_header(stream: &mut TcpStream) -> Result { @@ -73,9 +71,6 @@ pub fn read_header(stream: &mut TcpStream) -> Result { Ok(FrameHeader { fin, opcode, - payload_len, - mask, - masking_key, decoded_data, }) } diff --git a/src/send_message.rs b/src/send_message.rs index 61f64ef..4d318ef 100644 --- a/src/send_message.rs +++ b/src/send_message.rs @@ -1,23 +1,25 @@ use std::io::{Result, Write}; use std::net::TcpStream; -pub fn send_message(stream: &mut TcpStream, msg: &str) -> Result<()> { - let payload = msg.as_bytes(); - +pub fn send_message(stream: &mut TcpStream, byte1:u8,payload:&[u8]) -> Result<()> { let mut frame = Vec::new(); - //first byte - let fin = 1 << 7; - let opcode = 0x1; - frame.push(fin | opcode); + frame.push(byte1); + + let payload_len = payload.len(); - //second byte - let mask = 0x0; - let payload_length = payload.len() as u8; - frame.push(mask | payload_length); + if payload_len <126 { + frame.push(payload_len as u8); + } else if payload_len <= 65535 { + frame.push(126); + frame.extend_from_slice(&(payload_len as u16).to_be_bytes()); + } else { + frame.push(127); + frame.extend_from_slice(&(payload_len as u64).to_be_bytes()); + } frame.extend_from_slice(payload); - let _ = stream.write_all(&frame); - Ok(()) + stream.write_all(&frame) + } \ No newline at end of file