Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 91 additions & 8 deletions src/handle_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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\
Expand All @@ -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(())
}
}
13 changes: 4 additions & 9 deletions src/read_header.rs
Original file line number Diff line number Diff line change
@@ -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<u8>,
pub fin: bool,
pub opcode: u8,
pub decoded_data : Vec<u8>,
}

pub fn read_header(stream: &mut TcpStream) -> Result<FrameHeader> {
Expand Down Expand Up @@ -73,9 +71,6 @@ pub fn read_header(stream: &mut TcpStream) -> Result<FrameHeader> {
Ok(FrameHeader {
fin,
opcode,
payload_len,
mask,
masking_key,
decoded_data,
})
}
28 changes: 15 additions & 13 deletions src/send_message.rs
Original file line number Diff line number Diff line change
@@ -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)

}