http: Allow fragmented data for WebSocket.
This commit is contained in:
parent
b75b6801c8
commit
8b094f8c6f
2 changed files with 51 additions and 1 deletions
|
@ -96,6 +96,7 @@ WebSocketServer *WebSocketServer::CreateAsUpgrade(const http::Request &request)
|
||||||
|
|
||||||
void WebSocketServer::Send(const std::string &str) {
|
void WebSocketServer::Send(const std::string &str) {
|
||||||
assert(open_);
|
assert(open_);
|
||||||
|
assert(fragmentOpcode_ == -1);
|
||||||
SendHeader(true, (int)Opcode::TEXT, str.size());
|
SendHeader(true, (int)Opcode::TEXT, str.size());
|
||||||
// TODO: For long strings, this will block. Possibly not ideal.
|
// TODO: For long strings, this will block. Possibly not ideal.
|
||||||
if (!out_->Push(str.c_str(), str.size())) {
|
if (!out_->Push(str.c_str(), str.size())) {
|
||||||
|
@ -107,6 +108,7 @@ void WebSocketServer::Send(const std::string &str) {
|
||||||
|
|
||||||
void WebSocketServer::Send(const std::vector<uint8_t> &payload) {
|
void WebSocketServer::Send(const std::vector<uint8_t> &payload) {
|
||||||
assert(open_);
|
assert(open_);
|
||||||
|
assert(fragmentOpcode_ == -1);
|
||||||
SendHeader(true, (int)Opcode::BINARY, payload.size());
|
SendHeader(true, (int)Opcode::BINARY, payload.size());
|
||||||
// TODO: For long strings, this will block. Possibly not ideal.
|
// TODO: For long strings, this will block. Possibly not ideal.
|
||||||
if (!out_->Push((const char *)&payload[0], payload.size())) {
|
if (!out_->Push((const char *)&payload[0], payload.size())) {
|
||||||
|
@ -116,6 +118,48 @@ void WebSocketServer::Send(const std::vector<uint8_t> &payload) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebSocketServer::AddFragment(bool finish, const std::string &str) {
|
||||||
|
assert(open_);
|
||||||
|
if (fragmentOpcode_ == -1) {
|
||||||
|
SendHeader(finish, (int)Opcode::TEXT, str.size());
|
||||||
|
fragmentOpcode_ = (int)Opcode::TEXT;
|
||||||
|
} else if (fragmentOpcode_ == (int)Opcode::TEXT) {
|
||||||
|
SendHeader(finish, (int)Opcode::CONTINUE, str.size());
|
||||||
|
} else {
|
||||||
|
assert(fragmentOpcode_ == (int)Opcode::TEXT || fragmentOpcode_ == -1);
|
||||||
|
}
|
||||||
|
// TODO: For long strings, this will block. Possibly not ideal.
|
||||||
|
if (!out_->Push(str.c_str(), str.size())) {
|
||||||
|
assert(false);
|
||||||
|
open_ = false;
|
||||||
|
closeReason_ = WebSocketClose::ABNORMAL;
|
||||||
|
}
|
||||||
|
if (finish) {
|
||||||
|
fragmentOpcode_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebSocketServer::AddFragment(bool finish, const std::vector<uint8_t> &payload) {
|
||||||
|
assert(open_);
|
||||||
|
if (fragmentOpcode_ == -1) {
|
||||||
|
SendHeader(finish, (int)Opcode::BINARY, payload.size());
|
||||||
|
fragmentOpcode_ = (int)Opcode::BINARY;
|
||||||
|
} else if (fragmentOpcode_ == (int)Opcode::BINARY) {
|
||||||
|
SendHeader(finish, (int)Opcode::CONTINUE, payload.size());
|
||||||
|
} else {
|
||||||
|
assert(fragmentOpcode_ == (int)Opcode::BINARY || fragmentOpcode_ == -1);
|
||||||
|
}
|
||||||
|
// TODO: For long strings, this will block. Possibly not ideal.
|
||||||
|
if (!out_->Push((const char *)&payload[0], payload.size())) {
|
||||||
|
assert(false);
|
||||||
|
open_ = false;
|
||||||
|
closeReason_ = WebSocketClose::ABNORMAL;
|
||||||
|
}
|
||||||
|
if (finish) {
|
||||||
|
fragmentOpcode_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WebSocketServer::Ping(const std::vector<uint8_t> &payload) {
|
void WebSocketServer::Ping(const std::vector<uint8_t> &payload) {
|
||||||
assert(open_);
|
assert(open_);
|
||||||
assert(payload.size() <= 125);
|
assert(payload.size() <= 125);
|
||||||
|
|
|
@ -30,9 +30,14 @@ class WebSocketServer {
|
||||||
public:
|
public:
|
||||||
static WebSocketServer *CreateAsUpgrade(const http::Request &request);
|
static WebSocketServer *CreateAsUpgrade(const http::Request &request);
|
||||||
|
|
||||||
// TODO: Doesn't support fragmented data yet.
|
|
||||||
void Send(const std::string &str);
|
void Send(const std::string &str);
|
||||||
void Send(const std::vector<uint8_t> &payload);
|
void Send(const std::vector<uint8_t> &payload);
|
||||||
|
|
||||||
|
// Call with finish = false to start and continue, then finally with finish = true to complete.
|
||||||
|
// Note: Fragmented data cannot be interleaved, per protocol.
|
||||||
|
void AddFragment(bool finish, const std::string &str);
|
||||||
|
void AddFragment(bool finish, const std::vector<uint8_t> &payload);
|
||||||
|
|
||||||
void Ping(const std::vector<uint8_t> &payload = {});
|
void Ping(const std::vector<uint8_t> &payload = {});
|
||||||
void Pong(const std::vector<uint8_t> &payload = {});
|
void Pong(const std::vector<uint8_t> &payload = {});
|
||||||
void Close(WebSocketClose reason = WebSocketClose::GOING_AWAY);
|
void Close(WebSocketClose reason = WebSocketClose::GOING_AWAY);
|
||||||
|
@ -73,6 +78,7 @@ protected:
|
||||||
|
|
||||||
bool open_ = true;
|
bool open_ = true;
|
||||||
bool sentClose_ = false;
|
bool sentClose_ = false;
|
||||||
|
int fragmentOpcode_ = -1;
|
||||||
size_t fd_ = 0;
|
size_t fd_ = 0;
|
||||||
InputSink *in_ = nullptr;
|
InputSink *in_ = nullptr;
|
||||||
OutputSink *out_ = nullptr;
|
OutputSink *out_ = nullptr;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue