Annotation of parser3/src/include/pa_websocket.h, revision 1.1
1.1 ! moko 1: /** @file
! 2: Parser: WebSocket (RFC 6455) support: handshake and frames.
! 3:
! 4: Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
! 5: Authors: Konstantin Morshnev <moko@design.ru>
! 6: */
! 7:
! 8: #ifndef PA_WEBSOCKET_H
! 9: #define PA_WEBSOCKET_H
! 10:
! 11: #define IDENT_PA_WEBSOCKET_H "$Id$"
! 12:
! 13: #include "pa_http.h"
! 14:
! 15: /// checks the request of the handshake, returns the value of the Sec-WebSocket-Accept header, throws websocket.handshake
! 16: const char* pa_websocket_accept_key(const char* method, const char* upgrade, const char* connection, const char* key, const char* version);
! 17:
! 18: /// messages are received and sent one at a time
! 19: class WebSocket : public PA_Allocated {
! 20: public:
! 21:
! 22: enum Opcode {
! 23: TEXT=0x1,
! 24: BINARY=0x2,
! 25: CLOSE=0x8,
! 26: PING=0x9,
! 27: PONG=0xA
! 28: };
! 29:
! 30: /// the status codes of the Close frame
! 31: enum Status {
! 32: NORMAL=1000,
! 33: PROTOCOL_ERROR=1002,
! 34: NO_STATUS=1005,
! 35: ABNORMAL=1006,
! 36: INVALID_DATA=1007,
! 37: TOO_BIG=1009,
! 38: INTERNAL_ERROR=1011
! 39: };
! 40:
! 41: struct Message {
! 42: Opcode opcode;
! 43: const char *data; /// the payload (the reason for CLOSE), valid until the next call
! 44: size_t size;
! 45: int code; /// the status of CLOSE
! 46:
! 47: void set(Opcode aopcode, const char *adata, size_t asize, int acode=0);
! 48: };
! 49:
! 50: /// the status codes that can be sent in Close
! 51: static bool valid_status(int code);
! 52:
! 53: /// the handshake is done
! 54: bool accepted;
! 55: /// the closing handshake is over: nothing can be received or sent
! 56: bool closed;
! 57:
! 58: WebSocket(HTTPD_Connection &aconnection);
! 59: /// sends Close with INTERNAL_ERROR if the connection is not closed: the request has ended with an exception
! 60: ~WebSocket();
! 61:
! 62: /// the handshake response is sent, messages up to max_message_size are received
! 63: void start(size_t amax_message_size);
! 64:
! 65: /// waits up to timeout_ms for the next message, false on timeout; the pings are answered here, the broken connection is the CLOSE message
! 66: bool receive(int timeout_ms, Message &message);
! 67:
! 68: void send(Opcode opcode, const char *data, size_t size);
! 69:
! 70: /// sends Close and waits for the answer
! 71: void close(int code=NORMAL, const char *reason="", size_t reason_size=0);
! 72:
! 73: private:
! 74:
! 75: struct Frame {
! 76: bool fin;
! 77: int opcode;
! 78: char *payload;
! 79: size_t size;
! 80: };
! 81:
! 82: enum Parsed { INCOMPLETE, PARSED, INVALID };
! 83:
! 84: /// the growing array of bytes, data[pos..size) are not processed yet
! 85: struct Buffer {
! 86: char *data;
! 87: size_t pos, size, allocated;
! 88:
! 89: Buffer(): data(0), pos(0), size(0), allocated(0) {}
! 90:
! 91: size_t unread() const { return size-pos; }
! 92: void fit(size_t room);
! 93: void append(const char *bytes, size_t length);
! 94: };
! 95:
! 96: HTTPD_Connection &connection;
! 97: size_t max_message_size;
! 98:
! 99: Buffer rbuf; /// received bytes
! 100: size_t need; /// bytes of the incomplete frame
! 101: bool eof;
! 102:
! 103: Buffer msg; /// the fragments of the message
! 104: int msg_opcode; /// 0 if there is no fragmented message
! 105:
! 106: bool close_sent;
! 107: int error_code;
! 108: const char *error_reason;
! 109:
! 110: bool fill(int timeout_ms);
! 111: Parsed parse(Frame &frame);
! 112: Parsed invalid(int code, const char *reason);
! 113: bool failed(int code, const char *reason, bool notify, Message &message);
! 114: void write_frame(int opcode, const char *data, size_t size);
! 115: void send_close(int code, const char *reason, size_t size);
! 116: };
! 117:
! 118: #endif
E-mail: