diff --git a/src/WebSocket.h b/src/WebSocket.h index ed9c508..0c5aaf2 100644 --- a/src/WebSocket.h +++ b/src/WebSocket.h @@ -73,9 +73,23 @@ public: DROPPED }; + /* Sending fragmented messages puts a bit of effort on the user; you must not interleave regular sends + * with fragmented sends and you must sendFirstFragment, [sendFragment], then finally sendLastFragment. */ + SendStatus sendFirstFragment(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false) { + return send(message, opCode, compress, false); + } + + SendStatus sendFragment(std::string_view message, bool compress = false) { + return send(message, CONTINUATION, compress, false); + } + + SendStatus sendLastFragment(std::string_view message, bool compress = false) { + return send(message, CONTINUATION, compress, true); + } + /* Send or buffer a WebSocket frame, compressed or not. Returns BACKPRESSURE on increased user space backpressure, * DROPPED on dropped message (due to backpressure) or SUCCCESS if you are free to send even more now. */ - SendStatus send(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false) { + SendStatus send(std::string_view message, OpCode opCode = OpCode::BINARY, bool compress = false, bool fin = true) { WebSocketContextData *webSocketContextData = (WebSocketContextData *) us_socket_context_ext(SSL, (us_socket_context_t *) us_socket_context(SSL, (us_socket_t *) this) ); @@ -117,7 +131,7 @@ public: /* Get size, allocate size, write if needed */ size_t messageFrameSize = protocol::messageFrameSize(message.length()); auto [sendBuffer, sendBufferAttribute] = Super::getSendBuffer(messageFrameSize); - protocol::formatMessage(sendBuffer, message.data(), message.length(), opCode, message.length(), compress); + protocol::formatMessage(sendBuffer, message.data(), message.length(), opCode, message.length(), compress, fin); /* Depending on size of message we have different paths */ if (sendBufferAttribute == SendBufferAttribute::NEEDS_DRAIN) { diff --git a/src/WebSocketProtocol.h b/src/WebSocketProtocol.h index 0d8790f..4c5d8e9 100644 --- a/src/WebSocketProtocol.h +++ b/src/WebSocketProtocol.h @@ -35,6 +35,7 @@ const std::string_view ERR_TOO_BIG_MESSAGE_INFLATION("Received too big message, const std::string_view ERR_INVALID_CLOSE_PAYLOAD("Received invalid close payload"); enum OpCode : unsigned char { + CONTINUATION = 0, TEXT = 1, BINARY = 2, CLOSE = 8, @@ -205,7 +206,7 @@ enum { }; template -static inline size_t formatMessage(char *dst, const char *src, size_t length, OpCode opCode, size_t reportedLength, bool compressed) { +static inline size_t formatMessage(char *dst, const char *src, size_t length, OpCode opCode, size_t reportedLength, bool compressed, bool fin) { size_t messageLength; size_t headerLength; if (reportedLength < 126) { @@ -223,11 +224,9 @@ static inline size_t formatMessage(char *dst, const char *src, size_t length, Op memcpy(&dst[2], &tmp, sizeof(uint64_t)); } - int flags = 0; - dst[0] = (char) ((flags & SND_NO_FIN ? 0 : 128) | (compressed ? SND_COMPRESSED : 0)); - if (!(flags & SND_CONTINUATION)) { - dst[0] |= (char) opCode; - } + dst[0] = (char) ((fin ? 128 : 0) | ((compressed && opCode) ? SND_COMPRESSED : 0) | (char) opCode); + + //printf("%d\n", (int)dst[0]); char mask[4]; if (!isServer) {