Permalink
Browse files

http: Allow fragmented data for WebSocket.

  • Loading branch information...
unknownbrackets committed Apr 12, 2018
1 parent b75b680 commit 8b094f8c6f992f5a044b005f2f1a7797db2bb33b
Showing with 51 additions and 1 deletion.
  1. +44 −0 ext/native/net/websocket_server.cpp
  2. +7 −1 ext/native/net/websocket_server.h
@@ -96,6 +96,7 @@ WebSocketServer *WebSocketServer::CreateAsUpgrade(const http::Request &request)
void WebSocketServer::Send(const std::string &str) {
assert(open_);
assert(fragmentOpcode_ == -1);
SendHeader(true, (int)Opcode::TEXT, str.size());
// TODO: For long strings, this will block. Possibly not ideal.
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) {
assert(open_);
assert(fragmentOpcode_ == -1);
SendHeader(true, (int)Opcode::BINARY, payload.size());
// TODO: For long strings, this will block. Possibly not ideal.
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) {
assert(open_);
assert(payload.size() <= 125);
@@ -30,9 +30,14 @@ class WebSocketServer {
public:
static WebSocketServer *CreateAsUpgrade(const http::Request &request);
// TODO: Doesn't support fragmented data yet.
void Send(const std::string &str);
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 Pong(const std::vector<uint8_t> &payload = {});
void Close(WebSocketClose reason = WebSocketClose::GOING_AWAY);
@@ -73,6 +78,7 @@ class WebSocketServer {
bool open_ = true;
bool sentClose_ = false;
int fragmentOpcode_ = -1;
size_t fd_ = 0;
InputSink *in_ = nullptr;
OutputSink *out_ = nullptr;

0 comments on commit 8b094f8

Please sign in to comment.