From 1336d8400624e5ce2eeee87fe6b0679b239d7e3a Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Thu, 23 Jan 2025 13:34:38 -0600 Subject: [PATCH] Add mbed helpers --- CMakeLists.txt | 1 + .../TessesFramework/Crypto/MbedHelpers.hpp | 56 +++ include/TessesFramework/Http/HttpServer.hpp | 33 ++ include/TessesFramework/Http/HttpUtils.hpp | 14 +- .../TessesFramework/Streams/NetworkStream.hpp | 1 + include/TessesFramework/TessesFramework.hpp | 1 + src/Crypto/MbedHelpers.cpp | 323 ++++++++++++++++++ src/Http/HttpServer.cpp | 321 ++++++++++++++++- src/Http/HttpUtils.cpp | 8 +- src/Http/MountableServer.cpp | 2 +- src/Streams/NetworkStream.cpp | 7 + 11 files changed, 763 insertions(+), 4 deletions(-) create mode 100644 include/TessesFramework/Crypto/MbedHelpers.hpp create mode 100644 src/Crypto/MbedHelpers.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6798824..244d736 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ src/Filesystem/SubdirFilesystem.cpp src/Filesystem/NullFilesystem.cpp src/Filesystem/MountableFilesystem.cpp src/Crypto/ClientTLSStream.cpp +src/Crypto/MbedHelpers.cpp src/TF_Init.cpp src/wrapper.cpp ) diff --git a/include/TessesFramework/Crypto/MbedHelpers.hpp b/include/TessesFramework/Crypto/MbedHelpers.hpp new file mode 100644 index 0000000..e2fd44d --- /dev/null +++ b/include/TessesFramework/Crypto/MbedHelpers.hpp @@ -0,0 +1,56 @@ +#pragma once +#include "../Streams/Stream.hpp" +namespace Tesses::Framework::Crypto +{ + bool HaveCrypto(); + std::string Base64_Encode(std::vector data); + std::vector Base64_Decode(std::string str); + class Sha1 { + void* inner; + public: + Sha1(); + bool Start(); + bool Update(const uint8_t* buffer, size_t sz); + bool Update(Tesses::Framework::Streams::Stream* strm); + bool Update(Tesses::Framework::Streams::Stream& strm); + std::vector Finish(); + ~Sha1(); + static std::vector ComputeHash(const uint8_t* buffer, size_t len); + static std::vector ComputeHash(Tesses::Framework::Streams::Stream* strm); + static std::vector ComputeHash(Tesses::Framework::Streams::Stream& strm); + }; + class Sha256 { + void* inner; + bool is224; + public: + Sha256(); + bool Start(bool is224=false); + bool Is224(); + bool Update(const uint8_t* buffer, size_t sz); + bool Update(Tesses::Framework::Streams::Stream* strm); + bool Update(Tesses::Framework::Streams::Stream& strm); + std::vector Finish(); + ~Sha256(); + static std::vector ComputeHash(const uint8_t* buffer, size_t len,bool is224=false); + static std::vector ComputeHash(Tesses::Framework::Streams::Stream* strm,bool is224=false); + static std::vector ComputeHash(Tesses::Framework::Streams::Stream& strm,bool is224=false); + + }; + class Sha512 { + void* inner; + bool is384; + public: + Sha512(); + bool Start(bool is384=false); + bool Is384(); + bool Update(const uint8_t* buffer, size_t sz); + bool Update(Tesses::Framework::Streams::Stream* strm); + bool Update(Tesses::Framework::Streams::Stream& strm); + std::vector Finish(); + ~Sha512(); + + static std::vector ComputeHash(const uint8_t* buffer, size_t len,bool is384=false); + static std::vector ComputeHash(Tesses::Framework::Streams::Stream* strm,bool is384=false); + static std::vector ComputeHash(Tesses::Framework::Streams::Stream& strm,bool is384=false); + }; +} \ No newline at end of file diff --git a/include/TessesFramework/Http/HttpServer.hpp b/include/TessesFramework/Http/HttpServer.hpp index 19f7325..35073e5 100644 --- a/include/TessesFramework/Http/HttpServer.hpp +++ b/include/TessesFramework/Http/HttpServer.hpp @@ -11,6 +11,37 @@ namespace Tesses::Framework::Http virtual ~ServerContextData(); }; + class WebSocketMessage { + public: + std::vector data; + bool isBinary; + WebSocketMessage(); + WebSocketMessage(std::vector data); + WebSocketMessage(const void* data, size_t len); + WebSocketMessage(std::string message); + std::string ToString(); + }; + + class WebSocketConnection { + public: + virtual void OnOpen(std::function sendMessage, std::function ping)=0; + virtual void OnReceive(WebSocketMessage& message)=0; + virtual void OnClose(bool clean)=0; + virtual ~WebSocketConnection(); + }; + class CallbackWebSocketConnection : public WebSocketConnection { + public: + std::function,std::function)> onOpen; + std::function onReceive; + std::function onClose; + CallbackWebSocketConnection(); + CallbackWebSocketConnection(std::function,std::function)> onOpen, std::function onReceive, std::function onClose); + + void OnOpen(std::function sendMessage, std::function ping); + void OnReceive(WebSocketMessage& message); + void OnClose(bool clean); + }; + class ServerContext { bool sent; Tesses::Framework::Streams::Stream* strm; @@ -53,6 +84,8 @@ namespace Tesses::Framework::Http ServerContext& WithMimeType(std::string mime); ServerContext& WithContentDisposition(std::string filename, bool isInline); ServerContext& WriteHeaders(); + void StartWebSocketSession(std::function,std::function)> onOpen, std::function onReceive, std::function onClose); + void StartWebSocketSession(WebSocketConnection& connection); template T* GetServerContentData(std::string tag) diff --git a/include/TessesFramework/Http/HttpUtils.hpp b/include/TessesFramework/Http/HttpUtils.hpp index 8cc2b5a..0cdb7ca 100644 --- a/include/TessesFramework/Http/HttpUtils.hpp +++ b/include/TessesFramework/Http/HttpUtils.hpp @@ -1,5 +1,6 @@ #pragma once #include "../Common.hpp" +#include namespace Tesses::Framework::Http { @@ -67,9 +68,18 @@ namespace Tesses::Framework::Http NotExtended=510, NetworkAuthenticationRequired=511 } StatusCode; +struct CaseInsensitiveLess { + bool operator() (const std::string& s1, const std::string& s2) const { + std::string str1(s1.length(),' '); + std::string str2(s2.length(),' '); + std::transform(s1.begin(), s1.end(), str1.begin(), tolower); + std::transform(s2.begin(), s2.end(), str2.begin(), tolower); + return str1 < str2; + } +}; class HttpDictionary { public: - std::map> kvp; + std::map,CaseInsensitiveLess> kvp; void Clear(); void Clear(std::string key, bool kvpExistsAfter); void SetValue(std::string key, std::string value); @@ -97,6 +107,8 @@ namespace Tesses::Framework::Http bool TryGetFirstDouble(std::string key, double& value); bool GetFirstBoolean(std::string key); + + bool AnyEquals(std::string key, std::string value); }; class Uri { diff --git a/include/TessesFramework/Streams/NetworkStream.hpp b/include/TessesFramework/Streams/NetworkStream.hpp index 49045d0..3ead39d 100644 --- a/include/TessesFramework/Streams/NetworkStream.hpp +++ b/include/TessesFramework/Streams/NetworkStream.hpp @@ -39,5 +39,6 @@ namespace Tesses::Framework::Streams size_t WriteTo(const uint8_t* buff, size_t sz, std::string ip, uint16_t port); static std::vector> GetIPs(bool ipV6=false); ~NetworkStream(); + void SetNoDelay(bool noDelay); }; } \ No newline at end of file diff --git a/include/TessesFramework/TessesFramework.hpp b/include/TessesFramework/TessesFramework.hpp index 211e207..34e4b7b 100644 --- a/include/TessesFramework/TessesFramework.hpp +++ b/include/TessesFramework/TessesFramework.hpp @@ -20,4 +20,5 @@ #include "Filesystem/MountableFilesystem.hpp" #include "Filesystem/MemoryFilesystem.hpp" #include "Crypto/ClientTLSStream.hpp" +#include "Crypto/MbedHelpers.hpp" #include "Lazy.hpp" \ No newline at end of file diff --git a/src/Crypto/MbedHelpers.cpp b/src/Crypto/MbedHelpers.cpp new file mode 100644 index 0000000..077c9f5 --- /dev/null +++ b/src/Crypto/MbedHelpers.cpp @@ -0,0 +1,323 @@ +#include "TessesFramework/Crypto/MbedHelpers.hpp" + +#if defined(TESSESFRAMEWORK_ENABLE_MBED) +#include +#include +#include +#include +#endif +namespace Tesses::Framework::Crypto +{ + bool HaveCrypto() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + return true; + #else + return false; + #endif + } + std::string Base64_Encode(std::vector data) + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + std::string str={}; + size_t olen=0; + mbedtls_base64_encode((uint8_t*)str.data(), 0, &olen, data.data(),data.size()); + str.resize(olen-1); + + + if(mbedtls_base64_encode((uint8_t*)str.data(), olen, &olen, data.data(),data.size())==0) + { + return str; + } + + #endif + return ""; + } + std::vector Base64_Decode(std::string str) + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + size_t olen; + + std::vector data; + + + mbedtls_base64_decode(data.data(), 0, &olen, (const uint8_t*)str.data(),str.size()); + data.resize(olen); + + + if(mbedtls_base64_decode(data.data(), olen, &olen, (const uint8_t*)str.data(),str.size())==0) + { + return data; + } + #endif + return {}; + } + Sha1::Sha1() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + mbedtls_sha1_context* ctx = new mbedtls_sha1_context(); + this->inner = ctx; + mbedtls_sha1_init(ctx); + + #endif + } + bool Sha1::Start() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + if(mbedtls_sha1_starts_ret(ctx) != 0) return false; + return true; + #endif + return false; + } + bool Sha1::Update(const uint8_t* buffer, size_t sz) + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + if(mbedtls_sha1_update_ret(ctx,buffer,sz) != 0) return false; + return true; + #endif + return false; + } + bool Sha1::Update(Tesses::Framework::Streams::Stream* strm) + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + if(strm == nullptr) return false; + uint8_t buffer[1024]; + size_t read; + do { + read = strm->Read(buffer,sizeof(buffer)); + if(!Update(buffer,read)) return false; + } while(read != 0); + return true; + #endif + return false; + } + bool Sha1::Update(Tesses::Framework::Streams::Stream& strm) + { + return Update(&strm); + } + std::vector Sha1::Finish() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + std::vector hash; + hash.resize(20); + if(mbedtls_sha1_finish_ret(ctx,hash.data()) != 0) return {}; + return hash; + #endif + return {}; + } + Sha1::~Sha1() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + mbedtls_sha1_free(ctx); + delete ctx; + #endif + } + std::vector Sha1::ComputeHash(const uint8_t* buffer, size_t len) + { + Sha1 sha1; + if(!sha1.Start()) return {}; + if(!sha1.Update(buffer,len)) return {}; + return sha1.Finish(); + } + std::vector Sha1::ComputeHash(Tesses::Framework::Streams::Stream* strm) + { + Sha1 sha1; + if(!sha1.Start()) return {}; + if(!sha1.Update(strm)) return {}; + return sha1.Finish(); + } + std::vector Sha1::ComputeHash(Tesses::Framework::Streams::Stream& strm) + { + Sha1 sha1; + if(!sha1.Start()) return {}; + if(!sha1.Update(strm)) return {}; + return sha1.Finish(); + } + + Sha256::Sha256() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + mbedtls_sha256_context* ctx = new mbedtls_sha256_context(); + this->inner = ctx; + mbedtls_sha256_init(ctx); + + #endif + } + bool Sha256::Start(bool is224) + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + this->is224=is224; + if(mbedtls_sha256_starts_ret(ctx,is224) != 0) return false; + return true; + #endif + return false; + } + bool Sha256::Is224() + { + return this->is224; + } + bool Sha256::Update(const uint8_t* buffer, size_t sz) + { + + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + if(mbedtls_sha256_update_ret(ctx,buffer,sz) != 0) return false; + return true; + #endif + return false; + } + bool Sha256::Update(Tesses::Framework::Streams::Stream* strm) + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + if(strm == nullptr) return false; + uint8_t buffer[1024]; + size_t read; + do { + read = strm->Read(buffer,sizeof(buffer)); + if(!Update(buffer,read)) return false; + } while(read != 0); + return true; + #endif + return false; + } + bool Sha256::Update(Tesses::Framework::Streams::Stream& strm) + { + return Update(&strm); + } + std::vector Sha256::Finish() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + std::vector hash; + hash.resize(32); + if(mbedtls_sha256_finish_ret(ctx,hash.data()) != 0) return {}; + return hash; + #endif + return {}; + } + Sha256::~Sha256() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + mbedtls_sha256_free(ctx); + delete ctx; + #endif + } + std::vector Sha256::ComputeHash(const uint8_t* buffer, size_t len,bool is224) + { + Sha256 sha256; + if(!sha256.Start(is224)) return {}; + if(!sha256.Update(buffer,len)) return {}; + return sha256.Finish(); + } + std::vector Sha256::ComputeHash(Tesses::Framework::Streams::Stream* strm,bool is224) + { + Sha256 sha256; + if(!sha256.Start(is224)) return {}; + if(!sha256.Update(strm)) return {}; + return sha256.Finish(); + } + std::vector Sha256::ComputeHash(Tesses::Framework::Streams::Stream& strm,bool is224) + { + Sha256 sha256; + if(!sha256.Start(is224)) return {}; + if(!sha256.Update(strm)) return {}; + return sha256.Finish(); + } + + Sha512::Sha512() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + mbedtls_sha512_context* ctx = new mbedtls_sha512_context(); + this->inner = ctx; + mbedtls_sha512_init(ctx); + #endif + } + bool Sha512::Start(bool is384) + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + this->is384=is384; + if(mbedtls_sha512_starts_ret(ctx,is384) != 0) return false; + return true; + #endif + return false; + } + bool Sha512::Is384() + { + return this->is384; + } + bool Sha512::Update(const uint8_t* buffer, size_t sz) + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + if(mbedtls_sha512_update_ret(ctx,buffer,sz) != 0) return false; + return true; + #endif + return false; + } + bool Sha512::Update(Tesses::Framework::Streams::Stream* strm) + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + if(strm == nullptr) return false; + uint8_t buffer[1024]; + size_t read; + do { + read = strm->Read(buffer,sizeof(buffer)); + if(!Update(buffer,read)) return false; + } while(read != 0); + return true; + #endif + return false; + } + bool Sha512::Update(Tesses::Framework::Streams::Stream& strm) + { + return Update(&strm); + } + std::vector Sha512::Finish() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + std::vector hash; + hash.resize(64); + if(mbedtls_sha512_finish_ret(ctx,hash.data()) != 0) return {}; + return hash; + #endif + return {}; + } + Sha512::~Sha512() + { + #if defined(TESSESFRAMEWORK_ENABLE_MBED) + auto ctx = static_cast(this->inner); + mbedtls_sha512_free(ctx); + delete ctx; + #endif + } + + std::vector Sha512::ComputeHash(const uint8_t* buffer, size_t len,bool is384) + { + Sha512 sha512; + if(!sha512.Start(is384)) return {}; + if(!sha512.Update(buffer,len)) return {}; + return sha512.Finish(); + } + std::vector Sha512::ComputeHash(Tesses::Framework::Streams::Stream* strm,bool is384) + { + Sha512 sha512; + if(!sha512.Start(is384)) return {}; + if(!sha512.Update(strm)) return {}; + return sha512.Finish(); + } + std::vector Sha512::ComputeHash(Tesses::Framework::Streams::Stream& strm,bool is384) + { + Sha512 sha512; + if(!sha512.Start(is384)) return {}; + if(!sha512.Update(strm)) return {}; + return sha512.Finish(); + } +} diff --git a/src/Http/HttpServer.cpp b/src/Http/HttpServer.cpp index 285b202..848e318 100644 --- a/src/Http/HttpServer.cpp +++ b/src/Http/HttpServer.cpp @@ -6,6 +6,8 @@ #include "TessesFramework/Http/ContentDisposition.hpp" #include "TessesFramework/Streams/BufferedStream.hpp" #include "TessesFramework/Http/HttpStream.hpp" +#include "TessesFramework/Crypto/MbedHelpers.hpp" +#include "TessesFramework/Threading/Mutex.hpp" #include using FileStream = Tesses::Framework::Streams::FileStream; @@ -22,7 +24,237 @@ using BufferedStream = Tesses::Framework::Streams::BufferedStream; namespace Tesses::Framework::Http { - + class WSServer + { + public: + Threading::Mutex mtx; + ServerContext* ctx; + WebSocketConnection* conn; + Stream* strm; + std::atomic_bool hasInit; + void write_len_bytes(uint64_t len) + { + if(len < 126) + { + strm->WriteByte((uint8_t)len); + } + else if(len < 65535) + { + uint8_t b[3]; + b[0] = 126; + b[1] = (uint8_t)(len >> 8); + b[2] = (uint8_t)len; + + strm->WriteBlock(b,sizeof(b)); + } + else { + + uint8_t b[9]; + b[0] = 127; + + b[1] = (uint8_t)(len >> 56); + b[2] = (uint8_t)(len >> 48); + b[3] = (uint8_t)(len >> 40); + b[4] = (uint8_t)(len >> 32); + b[5] = (uint8_t)(len >> 24); + b[6] = (uint8_t)(len >> 16); + b[7] = (uint8_t)(len >> 8); + b[8] = (uint8_t)len; + + strm->WriteBlock(b,sizeof(b)); + } + } + uint64_t get_long() + { + uint8_t buff[8]; + if(strm->ReadBlock(buff,sizeof(buff)) != sizeof(buff)) return 0; + + uint64_t v = 0; + v |= (uint64_t)buff[0] << 56; + v |= (uint64_t)buff[1] << 48; + v |= (uint64_t)buff[2] << 40; + v |= (uint64_t)buff[3] << 32; + v |= (uint64_t)buff[4] << 24; + v |= (uint64_t)buff[5] << 16; + v |= (uint64_t)buff[6] << 8; + v |= (uint64_t)buff[7]; + return v; + } + uint16_t get_short() + { + uint8_t buff[2]; + if(strm->ReadBlock(buff,sizeof(buff)) != sizeof(buff)) return 0; + + uint16_t v = 0; + v |= (uint16_t)buff[0] << 8; + v |= (uint16_t)buff[1]; + return v; + } + void send_msg(WebSocketMessage* msg) + { + while(!hasInit); + mtx.Lock(); + uint8_t opcode = msg->isBinary ? 0x2 : 0x1; + + size_t lengthLastByte = msg->data.size() % 4096; + size_t fullPackets = (msg->data.size() - lengthLastByte) / 4096; + size_t noPackets = lengthLastByte > 0 ? fullPackets+1 : fullPackets; + size_t offset = 0; + for(size_t i = 0; i < noPackets; i++) + { + bool fin = i == noPackets - 1; + uint8_t finField = fin ? 0b10000000 : 0; + uint8_t opcode2 = i == 0 ? opcode : 0; + uint8_t firstByte = finField | (opcode2 & 0xF); + size_t len = std::min((size_t)4096,msg->data.size()- offset); + strm->WriteByte(firstByte); + write_len_bytes((uint64_t)len); + strm->WriteBlock(msg->data.data() + offset,len); + offset += len; + } + mtx.Unlock(); + } + void ping_send(std::vector& pData) + { + mtx.Lock(); + uint8_t finField = 0b10000000 ; + uint8_t firstByte= finField | 0x9; + strm->WriteByte(firstByte); + write_len_bytes((uint64_t)pData.size()); + strm->WriteBlock(pData.data(),pData.size()); + mtx.Unlock(); + } + void pong_send(std::vector& pData) + { + mtx.Lock(); + uint8_t finField = 0b10000000 ; + uint8_t firstByte= finField | 0xA; + strm->WriteByte(firstByte); + write_len_bytes((uint64_t)pData.size()); + strm->WriteBlock(pData.data(),pData.size()); + mtx.Unlock(); + } + bool read_packet(uint8_t len,std::vector& data) + { + uint8_t realLen=len & 127; + bool masked=(len & 0b10000000) > 0; + uint64_t reallen2 = realLen >= 126 ? realLen > 126 ? get_long() : get_short() : realLen; + uint8_t mask[4]; + if(masked) + { + if(strm->ReadBlock(mask,sizeof(mask)) != sizeof(mask)) return false; + } + size_t offset = data.size(); + data.resize(offset+(size_t)reallen2); + if(data.size() < ((uint64_t)offset+reallen2)) return false; + if(strm->ReadBlock(data.data()+offset,(size_t)reallen2) != (size_t)reallen2) return false; + if(masked) + { + for(size_t i = 0; i < (size_t)reallen2; i++) + { + data[i+offset] ^= mask[i%4]; + } + } + return true; + } + + WSServer(ServerContext* ctx,WebSocketConnection* conn) + { + this->ctx = ctx; + this->conn = conn; + this->strm = &this->ctx->GetStream(); + this->hasInit=false; + + + } + void Start() + { + std::string key; + if(ctx->requestHeaders.TryGetFirst("Sec-WebSocket-Key", key) && !key.empty()) + { + key.append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); + auto res = Crypto::Sha1::ComputeHash((const uint8_t*)key.c_str(),key.size()); + + if(res.empty()) return; + key = Crypto::Base64_Encode(res); + + }else { + + return; + } + + if(!ctx->requestHeaders.AnyEquals("Upgrade","websocket")) + { + + return; + } + if(!ctx->requestHeaders.AnyEquals("Sec-WebSocket-Version","13")) + { + + return; + } + ctx->statusCode = StatusCode::SwitchingProtocols; + ctx->responseHeaders.SetValue("Connection","Upgrade"); + ctx->responseHeaders.SetValue("Upgrade","websocket"); + ctx->responseHeaders.SetValue("Sec-WebSocket-Accept",key); + + ctx->WriteHeaders(); + bool hasMessage =false; + + WebSocketMessage message; + message.isBinary=false; + message.data={}; + hasInit=true; + + while(!strm->EndOfStream()) + { + + uint8_t frame_start[2]; + if(strm->ReadBlock(frame_start,2) != 2) return; + + + uint8_t opcode = frame_start[0] & 0xF; + bool fin = (frame_start[0] & 0b10000000) > 0; + switch(opcode) + { + case 0x0: + if(!hasMessage) break; + read_packet(frame_start[1], message.data); + break; + case 0x1: + case 0x2: + hasMessage=true; + message.data = {}; + message.isBinary = opcode == 0x2; + + read_packet(frame_start[1], message.data); + break; + case 0x8: + this->conn->OnClose(true); + return; + case 0x9: + { + std::vector b; + read_packet(frame_start[1],b); + pong_send(b); + } + break; + case 0xA: + { + std::vector b; + read_packet(frame_start[1],b); + } + } + if(fin && hasMessage) + { + hasMessage=false; + this->conn->OnReceive(message); + message.data={}; + } + } + this->conn->OnClose(false); + } + }; /* static int _header_field(multipart_parser* p, const char *at, size_t length) { @@ -701,4 +933,91 @@ namespace Tesses::Framework::Http if(bStrm.EndOfStream()) return; } } + + WebSocketConnection::~WebSocketConnection() + { + + } + void ServerContext::StartWebSocketSession(std::function,std::function)> onOpen, std::function onReceive, std::function onClose) + { + CallbackWebSocketConnection wsc(onOpen,onReceive,onClose); + StartWebSocketSession(wsc); + } + + void ServerContext::StartWebSocketSession(WebSocketConnection& connection) + { + WSServer svr(this,&connection); + Threading::Thread thrd([&svr,&connection]()->void{ + try { + connection.OnOpen([&svr](WebSocketMessage& msg)->void { + svr.send_msg(&msg); + },[&svr]()->void { + std::vector p = {(uint8_t)'p',(uint8_t)'i',(uint8_t)'n',(uint8_t)'g'}; + svr.ping_send(p); + }); + }catch(...) { + + } + }); + + svr.Start(); + thrd.Join(); + } + + CallbackWebSocketConnection::CallbackWebSocketConnection() + { + + } + CallbackWebSocketConnection::CallbackWebSocketConnection(std::function,std::function)> onOpen, std::function onReceive, std::function onClose) + { + this->onOpen = onOpen; + this->onReceive = onReceive; + this->onClose = onClose; + } + + void CallbackWebSocketConnection::OnOpen(std::function sendMessage, std::function ping) + { + if(this->onOpen) + this->onOpen(sendMessage,ping); + } + void CallbackWebSocketConnection::OnReceive(WebSocketMessage& message) + { + if(this->onReceive) + this->onReceive(message); + } + void CallbackWebSocketConnection::OnClose(bool clean) + { + if(this->onClose) + this->onClose(clean); + } + + + WebSocketMessage::WebSocketMessage() + { + this->isBinary=false; + this->data={}; + } + WebSocketMessage::WebSocketMessage(std::vector data) + { + this->isBinary = true; + this->data = data; + } + WebSocketMessage::WebSocketMessage(const void* data, size_t len) + { + this->isBinary=true; + this->data={}; + this->data.insert(this->data.end(),(uint8_t*)data,((uint8_t*)data)+len); + } + WebSocketMessage::WebSocketMessage(std::string message) + { + this->isBinary=false; + this->data={}; + this->data.insert(this->data.end(),message.begin(), message.end()); + } + std::string WebSocketMessage::ToString() + { + std::string str = {}; + str.insert(str.end(),this->data.begin(),this->data.end()); + return str; + } } diff --git a/src/Http/HttpUtils.cpp b/src/Http/HttpUtils.cpp index 8874d67..ceff92a 100644 --- a/src/Http/HttpUtils.cpp +++ b/src/Http/HttpUtils.cpp @@ -642,7 +642,13 @@ namespace Tesses::Framework::Http { } } - + bool HttpDictionary::AnyEquals(std::string key, std::string value) + { + if(this->kvp.count(key) > 0) + for(auto v : this->kvp[key]) if(v == value) return true; + // for(auto v : item.second) if(v == value) return true; + return false; + } void HttpDictionary::Clear() { diff --git a/src/Http/MountableServer.cpp b/src/Http/MountableServer.cpp index dc9318b..af7ffb0 100644 --- a/src/Http/MountableServer.cpp +++ b/src/Http/MountableServer.cpp @@ -82,4 +82,4 @@ MountableServer::~MountableServer() if(this->owns) delete this->root; for(auto svr : this->servers) if(svr.second.first) delete svr.second.second; } -} \ No newline at end of file +} diff --git a/src/Streams/NetworkStream.cpp b/src/Streams/NetworkStream.cpp index 7bd80f0..530f0d3 100644 --- a/src/Streams/NetworkStream.cpp +++ b/src/Streams/NetworkStream.cpp @@ -22,6 +22,7 @@ using HttpUtils = Tesses::Framework::Http::HttpUtils; #else extern "C" { #include +#include #include #include #include @@ -553,4 +554,10 @@ namespace Tesses::Framework::Streams { if(this->owns && this->success) NETWORK_CLOSE(this->sock); } + void NetworkStream::SetNoDelay(bool noDelay) + { + + int noDelay2 = noDelay; + NETWORK_SETSOCKOPT(this->sock, SOL_SOCKET, TCP_NODELAY, (const char*)&noDelay2,(socklen_t)sizeof(noDelay2)); + } }