Add mbed helpers
This commit is contained in:
@ -31,6 +31,7 @@ src/Filesystem/SubdirFilesystem.cpp
|
|||||||
src/Filesystem/NullFilesystem.cpp
|
src/Filesystem/NullFilesystem.cpp
|
||||||
src/Filesystem/MountableFilesystem.cpp
|
src/Filesystem/MountableFilesystem.cpp
|
||||||
src/Crypto/ClientTLSStream.cpp
|
src/Crypto/ClientTLSStream.cpp
|
||||||
|
src/Crypto/MbedHelpers.cpp
|
||||||
src/TF_Init.cpp
|
src/TF_Init.cpp
|
||||||
src/wrapper.cpp
|
src/wrapper.cpp
|
||||||
)
|
)
|
||||||
|
|||||||
56
include/TessesFramework/Crypto/MbedHelpers.hpp
Normal file
56
include/TessesFramework/Crypto/MbedHelpers.hpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../Streams/Stream.hpp"
|
||||||
|
namespace Tesses::Framework::Crypto
|
||||||
|
{
|
||||||
|
bool HaveCrypto();
|
||||||
|
std::string Base64_Encode(std::vector<uint8_t> data);
|
||||||
|
std::vector<uint8_t> 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<uint8_t> Finish();
|
||||||
|
~Sha1();
|
||||||
|
static std::vector<uint8_t> ComputeHash(const uint8_t* buffer, size_t len);
|
||||||
|
static std::vector<uint8_t> ComputeHash(Tesses::Framework::Streams::Stream* strm);
|
||||||
|
static std::vector<uint8_t> 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<uint8_t> Finish();
|
||||||
|
~Sha256();
|
||||||
|
static std::vector<uint8_t> ComputeHash(const uint8_t* buffer, size_t len,bool is224=false);
|
||||||
|
static std::vector<uint8_t> ComputeHash(Tesses::Framework::Streams::Stream* strm,bool is224=false);
|
||||||
|
static std::vector<uint8_t> 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<uint8_t> Finish();
|
||||||
|
~Sha512();
|
||||||
|
|
||||||
|
static std::vector<uint8_t> ComputeHash(const uint8_t* buffer, size_t len,bool is384=false);
|
||||||
|
static std::vector<uint8_t> ComputeHash(Tesses::Framework::Streams::Stream* strm,bool is384=false);
|
||||||
|
static std::vector<uint8_t> ComputeHash(Tesses::Framework::Streams::Stream& strm,bool is384=false);
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -11,6 +11,37 @@ namespace Tesses::Framework::Http
|
|||||||
virtual ~ServerContextData();
|
virtual ~ServerContextData();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WebSocketMessage {
|
||||||
|
public:
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
bool isBinary;
|
||||||
|
WebSocketMessage();
|
||||||
|
WebSocketMessage(std::vector<uint8_t> data);
|
||||||
|
WebSocketMessage(const void* data, size_t len);
|
||||||
|
WebSocketMessage(std::string message);
|
||||||
|
std::string ToString();
|
||||||
|
};
|
||||||
|
|
||||||
|
class WebSocketConnection {
|
||||||
|
public:
|
||||||
|
virtual void OnOpen(std::function<void(WebSocketMessage&)> sendMessage, std::function<void()> ping)=0;
|
||||||
|
virtual void OnReceive(WebSocketMessage& message)=0;
|
||||||
|
virtual void OnClose(bool clean)=0;
|
||||||
|
virtual ~WebSocketConnection();
|
||||||
|
};
|
||||||
|
class CallbackWebSocketConnection : public WebSocketConnection {
|
||||||
|
public:
|
||||||
|
std::function<void(std::function<void(WebSocketMessage&)>,std::function<void()>)> onOpen;
|
||||||
|
std::function<void(WebSocketMessage&)> onReceive;
|
||||||
|
std::function<void(bool)> onClose;
|
||||||
|
CallbackWebSocketConnection();
|
||||||
|
CallbackWebSocketConnection(std::function<void(std::function<void(WebSocketMessage&)>,std::function<void()>)> onOpen, std::function<void(WebSocketMessage&)> onReceive, std::function<void(bool)> onClose);
|
||||||
|
|
||||||
|
void OnOpen(std::function<void(WebSocketMessage&)> sendMessage, std::function<void()> ping);
|
||||||
|
void OnReceive(WebSocketMessage& message);
|
||||||
|
void OnClose(bool clean);
|
||||||
|
};
|
||||||
|
|
||||||
class ServerContext {
|
class ServerContext {
|
||||||
bool sent;
|
bool sent;
|
||||||
Tesses::Framework::Streams::Stream* strm;
|
Tesses::Framework::Streams::Stream* strm;
|
||||||
@ -53,6 +84,8 @@ namespace Tesses::Framework::Http
|
|||||||
ServerContext& WithMimeType(std::string mime);
|
ServerContext& WithMimeType(std::string mime);
|
||||||
ServerContext& WithContentDisposition(std::string filename, bool isInline);
|
ServerContext& WithContentDisposition(std::string filename, bool isInline);
|
||||||
ServerContext& WriteHeaders();
|
ServerContext& WriteHeaders();
|
||||||
|
void StartWebSocketSession(std::function<void(std::function<void(WebSocketMessage&)>,std::function<void()>)> onOpen, std::function<void(WebSocketMessage&)> onReceive, std::function<void(bool)> onClose);
|
||||||
|
void StartWebSocketSession(WebSocketConnection& connection);
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
T* GetServerContentData(std::string tag)
|
T* GetServerContentData(std::string tag)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../Common.hpp"
|
#include "../Common.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace Tesses::Framework::Http
|
namespace Tesses::Framework::Http
|
||||||
{
|
{
|
||||||
@ -67,9 +68,18 @@ namespace Tesses::Framework::Http
|
|||||||
NotExtended=510,
|
NotExtended=510,
|
||||||
NetworkAuthenticationRequired=511
|
NetworkAuthenticationRequired=511
|
||||||
} StatusCode;
|
} 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 {
|
class HttpDictionary {
|
||||||
public:
|
public:
|
||||||
std::map<std::string,std::vector<std::string>> kvp;
|
std::map<std::string,std::vector<std::string>,CaseInsensitiveLess> kvp;
|
||||||
void Clear();
|
void Clear();
|
||||||
void Clear(std::string key, bool kvpExistsAfter);
|
void Clear(std::string key, bool kvpExistsAfter);
|
||||||
void SetValue(std::string key, std::string value);
|
void SetValue(std::string key, std::string value);
|
||||||
@ -97,6 +107,8 @@ namespace Tesses::Framework::Http
|
|||||||
bool TryGetFirstDouble(std::string key, double& value);
|
bool TryGetFirstDouble(std::string key, double& value);
|
||||||
|
|
||||||
bool GetFirstBoolean(std::string key);
|
bool GetFirstBoolean(std::string key);
|
||||||
|
|
||||||
|
bool AnyEquals(std::string key, std::string value);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Uri {
|
class Uri {
|
||||||
|
|||||||
@ -39,5 +39,6 @@ namespace Tesses::Framework::Streams
|
|||||||
size_t WriteTo(const uint8_t* buff, size_t sz, std::string ip, uint16_t port);
|
size_t WriteTo(const uint8_t* buff, size_t sz, std::string ip, uint16_t port);
|
||||||
static std::vector<std::pair<std::string,std::string>> GetIPs(bool ipV6=false);
|
static std::vector<std::pair<std::string,std::string>> GetIPs(bool ipV6=false);
|
||||||
~NetworkStream();
|
~NetworkStream();
|
||||||
|
void SetNoDelay(bool noDelay);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -20,4 +20,5 @@
|
|||||||
#include "Filesystem/MountableFilesystem.hpp"
|
#include "Filesystem/MountableFilesystem.hpp"
|
||||||
#include "Filesystem/MemoryFilesystem.hpp"
|
#include "Filesystem/MemoryFilesystem.hpp"
|
||||||
#include "Crypto/ClientTLSStream.hpp"
|
#include "Crypto/ClientTLSStream.hpp"
|
||||||
|
#include "Crypto/MbedHelpers.hpp"
|
||||||
#include "Lazy.hpp"
|
#include "Lazy.hpp"
|
||||||
323
src/Crypto/MbedHelpers.cpp
Normal file
323
src/Crypto/MbedHelpers.cpp
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
#include "TessesFramework/Crypto/MbedHelpers.hpp"
|
||||||
|
|
||||||
|
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
|
||||||
|
#include <mbedtls/sha1.h>
|
||||||
|
#include <mbedtls/sha256.h>
|
||||||
|
#include <mbedtls/sha512.h>
|
||||||
|
#include <mbedtls/base64.h>
|
||||||
|
#endif
|
||||||
|
namespace Tesses::Framework::Crypto
|
||||||
|
{
|
||||||
|
bool HaveCrypto()
|
||||||
|
{
|
||||||
|
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
std::string Base64_Encode(std::vector<uint8_t> 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<uint8_t> Base64_Decode(std::string str)
|
||||||
|
{
|
||||||
|
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
|
||||||
|
size_t olen;
|
||||||
|
|
||||||
|
std::vector<uint8_t> 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<mbedtls_sha1_context*>(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<mbedtls_sha1_context*>(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<uint8_t> Sha1::Finish()
|
||||||
|
{
|
||||||
|
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
|
||||||
|
auto ctx = static_cast<mbedtls_sha1_context*>(this->inner);
|
||||||
|
std::vector<uint8_t> 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<mbedtls_sha1_context*>(this->inner);
|
||||||
|
mbedtls_sha1_free(ctx);
|
||||||
|
delete ctx;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> 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<uint8_t> Sha1::ComputeHash(Tesses::Framework::Streams::Stream* strm)
|
||||||
|
{
|
||||||
|
Sha1 sha1;
|
||||||
|
if(!sha1.Start()) return {};
|
||||||
|
if(!sha1.Update(strm)) return {};
|
||||||
|
return sha1.Finish();
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> 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<mbedtls_sha256_context*>(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<mbedtls_sha256_context*>(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<uint8_t> Sha256::Finish()
|
||||||
|
{
|
||||||
|
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
|
||||||
|
auto ctx = static_cast<mbedtls_sha256_context*>(this->inner);
|
||||||
|
std::vector<uint8_t> 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<mbedtls_sha256_context*>(this->inner);
|
||||||
|
mbedtls_sha256_free(ctx);
|
||||||
|
delete ctx;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> 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<mbedtls_sha512_context*>(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<mbedtls_sha512_context*>(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<uint8_t> Sha512::Finish()
|
||||||
|
{
|
||||||
|
#if defined(TESSESFRAMEWORK_ENABLE_MBED)
|
||||||
|
auto ctx = static_cast<mbedtls_sha512_context*>(this->inner);
|
||||||
|
std::vector<uint8_t> 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<mbedtls_sha512_context*>(this->inner);
|
||||||
|
mbedtls_sha512_free(ctx);
|
||||||
|
delete ctx;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> Sha512::ComputeHash(Tesses::Framework::Streams::Stream& strm,bool is384)
|
||||||
|
{
|
||||||
|
Sha512 sha512;
|
||||||
|
if(!sha512.Start(is384)) return {};
|
||||||
|
if(!sha512.Update(strm)) return {};
|
||||||
|
return sha512.Finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,6 +6,8 @@
|
|||||||
#include "TessesFramework/Http/ContentDisposition.hpp"
|
#include "TessesFramework/Http/ContentDisposition.hpp"
|
||||||
#include "TessesFramework/Streams/BufferedStream.hpp"
|
#include "TessesFramework/Streams/BufferedStream.hpp"
|
||||||
#include "TessesFramework/Http/HttpStream.hpp"
|
#include "TessesFramework/Http/HttpStream.hpp"
|
||||||
|
#include "TessesFramework/Crypto/MbedHelpers.hpp"
|
||||||
|
#include "TessesFramework/Threading/Mutex.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
using FileStream = Tesses::Framework::Streams::FileStream;
|
using FileStream = Tesses::Framework::Streams::FileStream;
|
||||||
@ -22,7 +24,237 @@ using BufferedStream = Tesses::Framework::Streams::BufferedStream;
|
|||||||
|
|
||||||
namespace Tesses::Framework::Http
|
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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<uint8_t> b;
|
||||||
|
read_packet(frame_start[1],b);
|
||||||
|
pong_send(b);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xA:
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> 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)
|
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;
|
if(bStrm.EndOfStream()) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebSocketConnection::~WebSocketConnection()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void ServerContext::StartWebSocketSession(std::function<void(std::function<void(WebSocketMessage&)>,std::function<void()>)> onOpen, std::function<void(WebSocketMessage&)> onReceive, std::function<void(bool)> 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<uint8_t> 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<void(std::function<void(WebSocketMessage&)>,std::function<void()>)> onOpen, std::function<void(WebSocketMessage&)> onReceive, std::function<void(bool)> onClose)
|
||||||
|
{
|
||||||
|
this->onOpen = onOpen;
|
||||||
|
this->onReceive = onReceive;
|
||||||
|
this->onClose = onClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallbackWebSocketConnection::OnOpen(std::function<void(WebSocketMessage&)> sendMessage, std::function<void()> 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<uint8_t> 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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()
|
void HttpDictionary::Clear()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -22,6 +22,7 @@ using HttpUtils = Tesses::Framework::Http::HttpUtils;
|
|||||||
#else
|
#else
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
@ -553,4 +554,10 @@ namespace Tesses::Framework::Streams {
|
|||||||
if(this->owns && this->success)
|
if(this->owns && this->success)
|
||||||
NETWORK_CLOSE(this->sock);
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user