X Tutup
#include "WebsocketHandler.hpp" namespace httpsserver { /** * @brief Dump the content of the WebSocket frame for debugging. * @param [in] frame The frame to dump. */ static void dumpFrame(WebsocketFrame frame) { std::ostringstream oss; oss << "Fin: " << (int)frame.fin << ", OpCode: " << (int)frame.opCode; switch(frame.opCode) { case WebsocketHandler::OPCODE_BINARY: { oss << " BINARY"; break; } case WebsocketHandler::OPCODE_CONTINUE: { oss << " CONTINUE"; break; } case WebsocketHandler::OPCODE_CLOSE: { oss << " CLOSE"; break; } case WebsocketHandler::OPCODE_PING: { oss << " PING"; break; } case WebsocketHandler::OPCODE_PONG: { oss << " PONG"; break; } case WebsocketHandler::OPCODE_TEXT: { oss << " TEXT"; break; } default: { oss << " Unknown"; break; } } oss << ", Mask: " << (int)frame.mask << ", len: " << (int)frame.len; std::string s = "[Frm] " + oss.str(); HTTPS_DLOG(s.c_str()); } // dumpFrame WebsocketHandler::WebsocketHandler() { _con = nullptr; _receivedClose = false; _sentClose = false; } WebsocketHandler::~WebsocketHandler() { } // ~WebSocketHandler() /** * @brief The default onClose handler. * If no over-riding handler is provided for the "close" event, this method is called. */ void WebsocketHandler::onClose() { HTTPS_DLOG("[ ] WebsocketHandler close()"); } // onClose /** * @brief The default onData handler. * If no over-riding handler is provided for the "message" event, this method is called. * A particularly useful pattern for using onMessage is: * ``` * std::stringstream buffer; * buffer << pWebSocketInputRecordStreambuf; * ``` * This will read the whole message into the string stream. */ void WebsocketHandler::onMessage(WebsocketInputStreambuf* pWebsocketInputStreambuf) { //, Websocket *pWebSocket) { HTTPS_DLOG("[ ] WebsocketHandler onMessage()"); } // onData /** * @brief The default onError handler. * If no over-riding handler is provided for the "error" event, this method is called. */ void WebsocketHandler::onError(std::string error) { HTTPS_DLOG("[ ] WebsocketHandler onError()"); } // onError void WebsocketHandler::initialize(ConnectionContext * con) { _con = con; } void WebsocketHandler::loop() { if(read() < 0) { close(); } } int WebsocketHandler::read() { WebsocketFrame frame; int length = _con->readBuffer((uint8_t*)&frame, sizeof(frame)); HTTPS_DLOGHEX("[ ] read bytes:", length); if(length == 0) return 0; else if (length != sizeof(frame)) { HTTPS_DLOG("[ERR] Websocket read error"); //_con->closeConnection(); return -1; } dumpFrame(frame); // The following section parses the WebSocket frame. uint32_t payloadLen = 0; uint8_t mask[4]; if (frame.len < 126) { payloadLen = frame.len; } else if (frame.len == 126) { uint16_t tempLen; _con->readBuffer((uint8_t*)&tempLen, sizeof(tempLen)); payloadLen = ntohs(tempLen); } else if (frame.len == 127) { uint64_t tempLen; _con->readBuffer((uint8_t*)&tempLen, sizeof(tempLen)); payloadLen = ntohl((uint32_t)tempLen); } if (frame.mask == 1) { _con->readBuffer(mask, sizeof(mask)); } if (payloadLen == 0) { HTTPS_DLOG("[WRN] Web socket payload is not present"); } else { HTTPS_DLOGHEX("[ ] Web socket payload, length=%d:", payloadLen); } switch(frame.opCode) { case OPCODE_TEXT: case OPCODE_BINARY: { HTTPS_DLOG("[ ] Creating Streambuf"); WebsocketInputStreambuf streambuf(_con, payloadLen, frame.mask==1?mask:nullptr); HTTPS_DLOG("[ ] Calling onMessage"); onMessage(&streambuf); HTTPS_DLOG("[ ] Discarding Streambuf"); streambuf.discard(); break; } case OPCODE_CLOSE: { // If the WebSocket operation code is close then we are closing the connection. _receivedClose = true; onClose(); //close(); // Close the websocket. return -1; break; } case OPCODE_CONTINUE: { break; } case OPCODE_PING: { break; } case OPCODE_PONG: { break; } default: { HTTPS_DLOGHEX("[ ] WebSocketReader: Unknown opcode: ", frame.opCode); break; } } // Switch opCode return 0; } // Websocket::read /** * @brief Close the Web socket * @param [in] status The code passed in the close request. * @param [in] message A clarification message on the close request. */ void WebsocketHandler::close(uint16_t status, std::string message) { HTTPS_DLOG("[ ] >> Websocket close()"); _sentClose = true; // Flag that we have sent a close request. WebsocketFrame frame; // Build the web socket frame indicating a close request. frame.fin = 1; frame.rsv1 = 0; frame.rsv2 = 0; frame.rsv3 = 0; frame.opCode = OPCODE_CLOSE; frame.mask = 0; frame.len = message.length() + 2; int rc = _con->writeBuffer((uint8_t *)&frame, sizeof(frame)); if (rc > 0) { rc = _con->writeBuffer((byte *) &status, 2); } if (rc > 0) { _con->writeBuffer((byte *) message.data(), message.length()); } } // Websocket::close /** * @brief Send data down the web socket * See the WebSocket spec (RFC6455) section "6.1 Sending Data". * We build a WebSocket frame, send the frame followed by the data. * @param [in] data The data to send down the WebSocket. * @param [in] sendType The type of payload. Either SEND_TYPE_TEXT or SEND_TYPE_BINARY. */ void WebsocketHandler::send(std::string data, uint8_t sendType) { HTTPS_DLOGHEX(">> Websocket.send: Length: ", data.length()); WebsocketFrame frame; frame.fin = 1; frame.rsv1 = 0; frame.rsv2 = 0; frame.rsv3 = 0; frame.opCode = sendType==SEND_TYPE_TEXT?OPCODE_TEXT:OPCODE_BINARY; frame.mask = 0; if (data.length() < 126) { frame.len = data.length(); _con->writeBuffer((uint8_t *)&frame, sizeof(frame)); } else { frame.len = 126; _con->writeBuffer((uint8_t *)&frame, sizeof(frame)); uint16_t net_len = htons((uint16_t)data.length()); _con->writeBuffer((uint8_t *)&net_len, sizeof(uint16_t)); // Convert to network byte order from host byte order } _con->writeBuffer((uint8_t*)data.data(), data.length()); HTTPS_DLOG("[ ] << Websocket.send"); } // Websocket::send /** * @brief Send data down the web socket * See the WebSocket spec (RFC6455) section "6.1 Sending Data". * We build a WebSocket frame, send the frame followed by the data. * @param [in] data The data to send down the WebSocket. * @param [in] sendType The type of payload. Either SEND_TYPE_TEXT or SEND_TYPE_BINARY. */ void WebsocketHandler::send(uint8_t* data, uint16_t length, uint8_t sendType) { HTTPS_DLOGHEX("[ ] >> Websocket.send: Length: ", length); WebsocketFrame frame; frame.fin = 1; frame.rsv1 = 0; frame.rsv2 = 0; frame.rsv3 = 0; frame.opCode = sendType==SEND_TYPE_TEXT?OPCODE_TEXT:OPCODE_BINARY; frame.mask = 0; if (length < 126) { frame.len = length; _con->writeBuffer((uint8_t *)&frame, sizeof(frame)); } else { frame.len = 126; _con->writeBuffer((uint8_t *)&frame, sizeof(frame)); uint16_t net_len = htons(length); _con->writeBuffer((uint8_t *) net_len, sizeof(uint16_t)); // Convert to network byte order from host byte order } _con->writeBuffer(data, length); HTTPS_DLOG("[ ] << Websocket.send"); } // Websocket::send /** * Returns true if the connection has been closed, either by client or server */ bool WebsocketHandler::closed() { return _receivedClose || _sentClose; } }
X Tutup