[DEV] clean interface and add protocol management
This commit is contained in:
parent
07323386b7
commit
d16c4b130d
@ -87,7 +87,7 @@ static std::string generateCheckKey(const std::string& _key) {
|
||||
return algue::base64::encode(keyData);
|
||||
}
|
||||
|
||||
void enet::WebSocket::start(const std::string& _uri) {
|
||||
void enet::WebSocket::start(const std::string& _uri, const std::vector<std::string>& _listProtocols) {
|
||||
if (m_interface == nullptr) {
|
||||
ENET_ERROR("Nullptr interface ...");
|
||||
return;
|
||||
@ -105,6 +105,19 @@ void enet::WebSocket::start(const std::string& _uri) {
|
||||
req.setKey("Sec-WebSocket-Version", "13");
|
||||
req.setKey("Pragma", "no-cache");
|
||||
req.setKey("Cache-Control", "no-cache");
|
||||
std::string protocolList;
|
||||
for (auto &it : _listProtocols) {
|
||||
if (it == "") {
|
||||
continue;
|
||||
}
|
||||
if (protocolList != "") {
|
||||
protocolList += ", ";
|
||||
}
|
||||
protocolList += it;
|
||||
}
|
||||
if (protocolList != "") {
|
||||
req.setKey("Sec-WebSocket-Protocol", protocolList);
|
||||
}
|
||||
ememory::SharedPtr<enet::HttpClient> interface = std::dynamic_pointer_cast<enet::HttpClient>(m_interface);
|
||||
if (interface!=nullptr) {
|
||||
interface->setHeader(req);
|
||||
@ -118,11 +131,10 @@ void enet::WebSocket::stop(bool _inThread) {
|
||||
return;
|
||||
}
|
||||
m_interface->stop(_inThread);
|
||||
m_interface.reset();
|
||||
// deadlock ... m_interface.reset();
|
||||
}
|
||||
|
||||
void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
||||
ENET_VERBOSE("Read Binary [START]");
|
||||
uint8_t opcode = 0;
|
||||
int32_t len = _connection.read(&opcode, sizeof(uint8_t));
|
||||
if (len <= 0) {
|
||||
@ -139,7 +151,6 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
||||
return;
|
||||
}
|
||||
m_lastReceive = std::chrono::steady_clock::now();
|
||||
ENET_VERBOSE("Read opcode : " << uint32_t(opcode));
|
||||
if ((opcode & 0x80) == 0) {
|
||||
ENET_ERROR("Multiple frames ... NOT managed ...");
|
||||
m_interface->stop(true);
|
||||
@ -147,7 +158,6 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
||||
}
|
||||
int8_t size1 = 0;
|
||||
len = _connection.read(&size1, sizeof(uint8_t));
|
||||
ENET_VERBOSE("Read payload : " << uint32_t(size1));
|
||||
if (len <= 0) {
|
||||
if (len < 0) {
|
||||
if (_connection.getConnectionStatus() == enet::Tcp::status::link) {
|
||||
@ -244,13 +254,13 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
||||
}
|
||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PING) {
|
||||
// Close the conection by remote:
|
||||
ENET_INFO("Receive a ping (send a pong)");
|
||||
ENET_DEBUG("Receive a ping (send a pong)");
|
||||
controlPong();
|
||||
return;
|
||||
}
|
||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_PONG) {
|
||||
// Close the conection by remote:
|
||||
ENET_INFO("Receive a pong");
|
||||
ENET_DEBUG("Receive a pong");
|
||||
return;
|
||||
}
|
||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_TEXT) {
|
||||
@ -263,14 +273,31 @@ void enet::WebSocket::onReceiveData(enet::Tcp& _connection) {
|
||||
}
|
||||
if ((opcode & 0x0F) == enet::websocket::OPCODE_FRAME_BINARY) {
|
||||
// Close the conection by remote:
|
||||
ENET_DEBUG("Receive a binary data " << m_buffer.size() << " Bytes");
|
||||
if (m_observer != nullptr) {
|
||||
m_observer(m_buffer, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ENET_ERROR("ReadRaw [STOP] (no opcode manage ... " << int32_t(opcode & 0x0F));
|
||||
}
|
||||
|
||||
static std::string removeStartAndStopSpace(const std::string& _value) {
|
||||
std::string out;
|
||||
out.reserve(_value.size());
|
||||
bool findSpace = false;
|
||||
for (auto &it : _value) {
|
||||
if (it != ' ') {
|
||||
if ( findSpace == true
|
||||
&& out.size() != 0) {
|
||||
out += ' ';
|
||||
}
|
||||
out += it;
|
||||
findSpace = false;
|
||||
} else {
|
||||
findSpace = true;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
||||
@ -312,8 +339,17 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
||||
interface->stop(true);
|
||||
return;
|
||||
}
|
||||
// parse all protocols:
|
||||
std::vector<std::string> listProtocol;
|
||||
if (_data.getKey("Sec-WebSocket-Protocol") != "") {
|
||||
listProtocol = etk::split(_data.getKey("Sec-WebSocket-Protocol"),',');
|
||||
for (size_t iii=0; iii<listProtocol.size(); ++iii) {
|
||||
listProtocol[iii] = removeStartAndStopSpace(listProtocol[iii]);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_observerUriCheck != nullptr) {
|
||||
if (m_observerUriCheck(_data.getUri()) == false) {
|
||||
if (m_observerUriCheck(_data.getUri(), listProtocol) == false) {
|
||||
enet::HttpAnswer answer(enet::HTTPAnswerCode::c404_notFound);
|
||||
answer.setProtocol(enet::HTTPProtocol::http_1_1);
|
||||
answer.setKey("Connection", "close");
|
||||
@ -328,6 +364,9 @@ void enet::WebSocket::onReceiveRequest(const enet::HttpRequest& _data) {
|
||||
answer.setKey("Connection", "Upgrade");
|
||||
std::string answerKey = generateCheckKey(_data.getKey("Sec-WebSocket-Key"));
|
||||
answer.setKey("Sec-WebSocket-Accept", answerKey);
|
||||
if (m_protocol != "") {
|
||||
answer.setKey("Sec-WebSocket-Protocol", m_protocol);
|
||||
}
|
||||
interface->setHeader(answer);
|
||||
}
|
||||
|
||||
@ -358,7 +397,8 @@ void enet::WebSocket::onReceiveAnswer(const enet::HttpAnswer& _data) {
|
||||
m_interface->stop(true);
|
||||
return;
|
||||
}
|
||||
|
||||
setProtocol(_data.getKey("Sec-WebSocket-Protocol"));
|
||||
// TODO : Create a methode to check the current protocol ...
|
||||
}
|
||||
|
||||
bool enet::WebSocket::writeHeader(int32_t _len, bool _isString, bool _mask) {
|
||||
@ -378,24 +418,18 @@ bool enet::WebSocket::writeHeader(int32_t _len, bool _isString, bool _mask) {
|
||||
}
|
||||
m_lastSend = std::chrono::steady_clock::now();
|
||||
m_interface->write(&header, sizeof(uint8_t));
|
||||
ENET_VERBOSE("write opcode : " << int32_t(header));
|
||||
if (_len < 126) {
|
||||
uint8_t size = _len | mask;
|
||||
ENET_VERBOSE("write payload : " << int32_t(size));
|
||||
m_interface->write(&size, sizeof(uint8_t));
|
||||
} else if (_len < 65338) {
|
||||
uint8_t payload = 126 | mask;
|
||||
ENET_VERBOSE("write payload : " << int32_t(payload));
|
||||
m_interface->write(&payload, sizeof(uint8_t));
|
||||
uint16_t size = _len;
|
||||
ENET_VERBOSE("write size : " << int32_t(size));
|
||||
m_interface->write(&size, sizeof(uint16_t));
|
||||
} else {
|
||||
uint8_t payload = 127 | mask;
|
||||
ENET_VERBOSE("write payload : " << int32_t(payload));
|
||||
m_interface->write(&payload, sizeof(uint8_t));
|
||||
uint64_t size = _len;
|
||||
ENET_VERBOSE("write size : " << size);
|
||||
m_interface->write(&size, sizeof(uint64_t));
|
||||
}
|
||||
if (mask != 0 ) {
|
||||
|
@ -30,7 +30,7 @@ namespace enet {
|
||||
WebSocket(enet::Tcp _connection, bool _isServer=false);
|
||||
void setInterface(enet::Tcp _connection, bool _isServer=false);
|
||||
virtual ~WebSocket();
|
||||
void start(const std::string& _uri="");
|
||||
void start(const std::string& _uri="", const std::vector<std::string>& _listProtocols=std::vector<std::string>());
|
||||
void stop(bool _inThread=false);
|
||||
bool isAlive() const {
|
||||
if (m_interface == nullptr) {
|
||||
@ -41,6 +41,12 @@ namespace enet {
|
||||
void onReceiveData(enet::Tcp& _data);
|
||||
void onReceiveRequest(const enet::HttpRequest& _data);
|
||||
void onReceiveAnswer(const enet::HttpAnswer& _data);
|
||||
protected:
|
||||
std::string m_protocol;
|
||||
public:
|
||||
void setProtocol(const std::string& _protocol) {
|
||||
m_protocol = _protocol;
|
||||
}
|
||||
public:
|
||||
using Observer = std::function<void(std::vector<uint8_t>&, bool)>; //!< Define an Observer: function pointer
|
||||
protected:
|
||||
@ -63,7 +69,7 @@ namespace enet {
|
||||
}
|
||||
// Only server:
|
||||
public:
|
||||
using ObserverUriCheck = std::function<bool(const std::string&)>; //!< Define an Observer: function pointer
|
||||
using ObserverUriCheck = std::function<bool(const std::string&, const std::vector<std::string>&)>; //!< Define an Observer: function pointer
|
||||
protected:
|
||||
ObserverUriCheck m_observerUriCheck;
|
||||
public:
|
||||
@ -74,9 +80,9 @@ namespace enet {
|
||||
* @param[in] _args Argument optinnal the user want to add.
|
||||
*/
|
||||
template<class CLASS_TYPE>
|
||||
void connectUri(CLASS_TYPE* _class, bool (CLASS_TYPE::*_func)(const std::string&)) {
|
||||
m_observerUriCheck = [=](const std::string& _value){
|
||||
return (*_class.*_func)(_value);
|
||||
void connectUri(CLASS_TYPE* _class, bool (CLASS_TYPE::*_func)(const std::string&, const std::vector<std::string>&)) {
|
||||
m_observerUriCheck = [=](const std::string& _value, const std::vector<std::string>& _protocols){
|
||||
return (*_class.*_func)(_value, _protocols);
|
||||
};
|
||||
}
|
||||
void connectUri(ObserverUriCheck _func) {
|
||||
|
@ -53,7 +53,11 @@ int main(int _argc, const char *_argv[]) {
|
||||
connection.connect(appl::onReceiveData);
|
||||
|
||||
// start http connection (the actual state is just TCP start ...)
|
||||
connection.start("/plop.txt");
|
||||
std::vector<std::string> protocols;
|
||||
protocols.push_back("test1526/1.0");
|
||||
protocols.push_back("test1526/1.5");
|
||||
protocols.push_back("Hello");
|
||||
connection.start("/plop.txt", protocols);
|
||||
|
||||
// send some data to play ...
|
||||
connection.write("coucou comment ca vas ???");
|
||||
|
@ -25,8 +25,14 @@ namespace appl {
|
||||
TEST_INFO("binary data: ... ");
|
||||
}
|
||||
}
|
||||
bool onReceiveUri(enet::WebSocket* _interface, const std::string& _uri) {
|
||||
bool onReceiveUri(enet::WebSocket* _interface, const std::string& _uri, const std::vector<std::string>& _protocols) {
|
||||
TEST_INFO("Receive Header uri: " << _uri);
|
||||
for (auto &it : _protocols) {
|
||||
if (it == "test1526/1.5") {
|
||||
_interface->setProtocol(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_uri == "/plop.txt") {
|
||||
return true;
|
||||
}
|
||||
@ -70,8 +76,8 @@ int main(int _argc, const char *_argv[]) {
|
||||
connection.connect([=](std::vector<uint8_t>& _value, bool _isString){
|
||||
appl::onReceiveData(tmp, _value, _isString);
|
||||
});
|
||||
connection.connectUri([=](const std::string& _value){
|
||||
return appl::onReceiveUri(tmp, _value);
|
||||
connection.connectUri([=](const std::string& _value, const std::vector<std::string>& _protocols){
|
||||
return appl::onReceiveUri(tmp, _value, _protocols);
|
||||
});
|
||||
|
||||
// start http connection (the actual state is just TCP start ...)
|
||||
|
Loading…
x
Reference in New Issue
Block a user