Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec55b4a82a | ||
|
|
5d58982f77 | ||
|
|
57665ca825 |
@@ -1 +1 @@
|
||||
5.1.6
|
||||
5.1.7
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [5.1.7] - 2019-09-03
|
||||
|
||||
- Receiving invalid UTF-8 TEXT message should fail and close the connection (fix remaining autobahn test: 6.X UTF-8 Handling)
|
||||
|
||||
## [5.1.6] - 2019-09-03
|
||||
|
||||
- Sending invalid UTF-8 TEXT message should fail and close the connection (fix remaining autobahn test: 6.X UTF-8 Handling)
|
||||
- Fix failing unittest which was sending binary data in text mode with WebSocket::send to call properly call WebSocket::sendBinary instead.
|
||||
- Validate that the reason is proper utf-8. (fix autobahn test 7.5.1)
|
||||
- Validate close codes. Autobahn 7.9.*
|
||||
|
||||
## [5.1.5] - 2019-09-03
|
||||
|
||||
|
||||
@@ -27,4 +27,5 @@ namespace ix
|
||||
const std::string WebSocketCloseConstants::kProtocolErrorCodeDataOpcodeOutOfSequence("Fragmentation: data message out of sequence");
|
||||
const std::string WebSocketCloseConstants::kProtocolErrorCodeContinuationOpCodeOutOfSequence("Fragmentation: continuation opcode out of sequence");
|
||||
const std::string WebSocketCloseConstants::kInvalidFramePayloadDataMessage("Invalid frame payload data");
|
||||
const std::string WebSocketCloseConstants::kInvalidCloseCodeMessage("Invalid close code");
|
||||
}
|
||||
|
||||
@@ -32,5 +32,6 @@ namespace ix
|
||||
static const std::string kProtocolErrorCodeDataOpcodeOutOfSequence;
|
||||
static const std::string kProtocolErrorCodeContinuationOpCodeOutOfSequence;
|
||||
static const std::string kInvalidFramePayloadDataMessage;
|
||||
static const std::string kInvalidCloseCodeMessage;
|
||||
};
|
||||
} // namespace ix
|
||||
|
||||
@@ -558,13 +558,16 @@ namespace ix
|
||||
return;
|
||||
}
|
||||
|
||||
unmaskReceiveBuffer(ws);
|
||||
std::string frameData(_rxbuf.begin()+ws.header_size,
|
||||
_rxbuf.begin()+ws.header_size+(size_t) ws.N);
|
||||
|
||||
// We got a whole message, now do something with it:
|
||||
if (
|
||||
ws.opcode == wsheader_type::TEXT_FRAME
|
||||
|| ws.opcode == wsheader_type::BINARY_FRAME
|
||||
|| ws.opcode == wsheader_type::CONTINUATION
|
||||
) {
|
||||
unmaskReceiveBuffer(ws);
|
||||
|
||||
if (ws.opcode != wsheader_type::CONTINUATION)
|
||||
{
|
||||
@@ -593,8 +596,7 @@ namespace ix
|
||||
if (ws.fin && _chunks.empty())
|
||||
{
|
||||
emitMessage(_fragmentedMessageKind,
|
||||
std::string(_rxbuf.begin()+ws.header_size,
|
||||
_rxbuf.begin()+ws.header_size+(size_t) ws.N),
|
||||
frameData,
|
||||
ws,
|
||||
onMessageCallback);
|
||||
}
|
||||
@@ -607,9 +609,8 @@ namespace ix
|
||||
// the internal buffer which is slow and can let the internal OS
|
||||
// receive buffer fill out.
|
||||
//
|
||||
_chunks.emplace_back(
|
||||
std::vector<uint8_t>(_rxbuf.begin()+ws.header_size,
|
||||
_rxbuf.begin()+ws.header_size+(size_t)ws.N));
|
||||
_chunks.emplace_back(frameData);
|
||||
|
||||
if (ws.fin)
|
||||
{
|
||||
emitMessage(_fragmentedMessageKind, getMergedChunks(),
|
||||
@@ -624,13 +625,8 @@ namespace ix
|
||||
}
|
||||
else if (ws.opcode == wsheader_type::PING)
|
||||
{
|
||||
unmaskReceiveBuffer(ws);
|
||||
|
||||
std::string pingData(_rxbuf.begin()+ws.header_size,
|
||||
_rxbuf.begin()+ws.header_size + (size_t) ws.N);
|
||||
|
||||
// too large
|
||||
if (pingData.size() > 125)
|
||||
if (frameData.size() > 125)
|
||||
{
|
||||
// Unexpected frame type
|
||||
close(WebSocketCloseConstants::kProtocolErrorCode,
|
||||
@@ -642,29 +638,23 @@ namespace ix
|
||||
{
|
||||
// Reply back right away
|
||||
bool compress = false;
|
||||
sendData(wsheader_type::PONG, pingData, compress);
|
||||
sendData(wsheader_type::PONG, frameData, compress);
|
||||
}
|
||||
|
||||
emitMessage(MessageKind::PING, pingData, ws, onMessageCallback);
|
||||
emitMessage(MessageKind::PING, frameData, ws, onMessageCallback);
|
||||
}
|
||||
else if (ws.opcode == wsheader_type::PONG)
|
||||
{
|
||||
unmaskReceiveBuffer(ws);
|
||||
std::string pongData(_rxbuf.begin()+ws.header_size,
|
||||
_rxbuf.begin()+ws.header_size + (size_t) ws.N);
|
||||
|
||||
std::lock_guard<std::mutex> lck(_lastReceivePongTimePointMutex);
|
||||
_lastReceivePongTimePoint = std::chrono::steady_clock::now();
|
||||
|
||||
emitMessage(MessageKind::PONG, pongData, ws, onMessageCallback);
|
||||
emitMessage(MessageKind::PONG, frameData, ws, onMessageCallback);
|
||||
}
|
||||
else if (ws.opcode == wsheader_type::CLOSE)
|
||||
{
|
||||
std::string reason;
|
||||
uint16_t code = 0;
|
||||
|
||||
unmaskReceiveBuffer(ws);
|
||||
|
||||
if (ws.N >= 2)
|
||||
{
|
||||
// Extract the close code first, available as the first 2 bytes
|
||||
@@ -674,8 +664,7 @@ namespace ix
|
||||
// Get the reason.
|
||||
if (ws.N > 2)
|
||||
{
|
||||
reason.assign(_rxbuf.begin()+ws.header_size + 2,
|
||||
_rxbuf.begin()+ws.header_size + (size_t) ws.N);
|
||||
reason = frameData.substr(2, frameData.size());
|
||||
}
|
||||
|
||||
// Validate that the reason is proper utf-8. Autobahn 7.5.1
|
||||
@@ -684,6 +673,20 @@ namespace ix
|
||||
code = WebSocketCloseConstants::kInvalidFramePayloadData;
|
||||
reason = WebSocketCloseConstants::kInvalidFramePayloadDataMessage;
|
||||
}
|
||||
|
||||
// Validate close codes. Autobahn 7.9.*
|
||||
// 1014, 1015 are debattable. The firefox MSDN has a description for them
|
||||
if (code < 1000 || code == 1004 || code == 1006 ||
|
||||
(code > 1013 && code < 3000))
|
||||
{
|
||||
// build up an error message containing the bad error code
|
||||
std::stringstream ss;
|
||||
ss << WebSocketCloseConstants::kInvalidCloseCodeMessage
|
||||
<< ": " << code;
|
||||
reason = ss.str();
|
||||
|
||||
code = WebSocketCloseConstants::kProtocolErrorCode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -768,8 +771,7 @@ namespace ix
|
||||
|
||||
for (auto&& chunk : _chunks)
|
||||
{
|
||||
std::string str(chunk.begin(), chunk.end());
|
||||
msg += str;
|
||||
msg += chunk;
|
||||
}
|
||||
|
||||
return msg;
|
||||
@@ -787,11 +789,28 @@ namespace ix
|
||||
{
|
||||
std::string decompressedMessage;
|
||||
bool success = _perMessageDeflate.decompress(message, decompressedMessage);
|
||||
onMessageCallback(decompressedMessage, wireSize, !success, messageKind);
|
||||
|
||||
if (messageKind == MessageKind::MSG_TEXT && !validateUtf8(decompressedMessage))
|
||||
{
|
||||
close(WebSocketCloseConstants::kInvalidFramePayloadData,
|
||||
WebSocketCloseConstants::kInvalidFramePayloadDataMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
onMessageCallback(decompressedMessage, wireSize, !success, messageKind);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
onMessageCallback(message, wireSize, false, messageKind);
|
||||
if (messageKind == MessageKind::MSG_TEXT && !validateUtf8(message))
|
||||
{
|
||||
close(WebSocketCloseConstants::kInvalidFramePayloadData,
|
||||
WebSocketCloseConstants::kInvalidFramePayloadDataMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
onMessageCallback(message, wireSize, false, messageKind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace ix
|
||||
// messages (tested messages up to 700M) and we cannot put them in a single
|
||||
// buffer that is resized, as this operation can be slow when a buffer has its
|
||||
// size increased 2 fold, while appending to a list has a fixed cost.
|
||||
std::list<std::vector<uint8_t>> _chunks;
|
||||
std::list<std::string> _chunks;
|
||||
|
||||
// Record the message kind (will be TEXT or BINARY) for a fragmented
|
||||
// message, present in the first chunk, since the final chunk will be a
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define IX_WEBSOCKET_VERSION "5.1.6"
|
||||
#define IX_WEBSOCKET_VERSION "5.1.7"
|
||||
|
||||
Reference in New Issue
Block a user