/*
|
|
|
|
WebSocketIncommingBuffer
|
|
|
|
Code by Hermann Kraus (https://bitbucket.org/hermr2d2/)
|
|
and slightly modified.
|
|
|
|
https://bitbucket.org/xoseperez/espurna/pull-requests/30/safer-buffer-handling-for-websocket-data
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#define MAX_WS_MSG_SIZE 4000
|
|
typedef std::function<void(AsyncWebSocketClient *client, uint8_t *data, size_t len)> AwsMessageHandler;
|
|
|
|
class WebSocketIncommingBuffer {
|
|
|
|
public:
|
|
WebSocketIncommingBuffer(AwsMessageHandler cb, bool terminate_string = true, bool cb_on_fragments = false) :
|
|
_cb(cb),
|
|
_cb_on_fragments(cb_on_fragments),
|
|
_terminate_string(terminate_string),
|
|
_buffer(0)
|
|
{}
|
|
|
|
~WebSocketIncommingBuffer() {
|
|
if (_buffer) delete _buffer;
|
|
}
|
|
|
|
void data_event(AsyncWebSocketClient *client, AwsFrameInfo *info, uint8_t *data, size_t len) {
|
|
|
|
if((info->final || _cb_on_fragments) &&
|
|
!_terminate_string && info->index == 0 && info->len == len) {
|
|
/* The whole message is in a single frame and we got all of it's
|
|
data therefore we can parse it without copying the data first.*/
|
|
_cb(client, data, len);
|
|
} else {
|
|
if (info->len > MAX_WS_MSG_SIZE) return;
|
|
/* Check if previous fragment was discarded because it was too long. */
|
|
if (!_cb_on_fragments && info->num > 0 && !_buffer) return;
|
|
|
|
if (!_buffer) {
|
|
_buffer = new std::vector<uint8_t>();
|
|
}
|
|
if (info->index == 0) {
|
|
//New frame => preallocate memory
|
|
if (_cb_on_fragments) {
|
|
_buffer->reserve(info->len + 1);
|
|
} else {
|
|
/* The current fragment would lead to a message which is
|
|
too long. So discard everything received so far. */
|
|
if (info->len + _buffer->size() > MAX_WS_MSG_SIZE) {
|
|
delete _buffer;
|
|
_buffer = 0;
|
|
return;
|
|
} else {
|
|
_buffer->reserve(info->len + _buffer->size() + 1);
|
|
}
|
|
}
|
|
}
|
|
//assert(_buffer->size() == info->index);
|
|
_buffer->insert(_buffer->end(), data, data+len);
|
|
if (info->index + len == info->len &&
|
|
(info->final || _cb_on_fragments)) {
|
|
// Frame/message complete
|
|
if (_terminate_string) {
|
|
_buffer->push_back(0);
|
|
}
|
|
_cb(client, _buffer->data(), _buffer->size());
|
|
_buffer->clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
AwsMessageHandler _cb;
|
|
bool _cb_on_fragments;
|
|
bool _terminate_string;
|
|
std::vector<uint8_t> *_buffer;
|
|
|
|
};
|