File Coverage

src/panda/protocol/websocket/Parser.h
Criterion Covered Total %
statement 4 5 80.0
branch 3 8 37.5
condition n/a
subroutine n/a
pod n/a
total 7 13 53.8


line stmt bran cond sub pod time code
1             #pragma once
2             #include "Error.h"
3             #include "Frame.h"
4             #include "Message.h"
5             #include "iterator.h"
6             #include "DeflateExt.h"
7             #include "Utf8Checker.h"
8             #include
9             #include
10             #include
11             #include
12             #include
13             #include
14             #include
15              
16             namespace panda { namespace protocol { namespace websocket {
17              
18             using panda::string;
19             using panda::IteratorPair;
20              
21             enum class DeflateFlag { NO, DEFAULT, YES };
22              
23             struct Parser : virtual panda::Refcnt {
24             // include child classes to solve cross-dependencies without moving one-liners to *.cc files (to avoid performance loses)
25             #include "Parser-FrameSender.h"
26             #include "Parser-MessageBuilder.h"
27             #include "Parser-MessageIterator.h"
28              
29             using DeflateConfigOption = panda::optional;
30              
31             struct Config {
32             Config () {}
33             size_t max_frame_size = 0;
34             size_t max_message_size = 0;
35             size_t max_handshake_size = http::SIZE_UNLIMITED;
36             bool check_utf8 = false;
37             DeflateConfigOption deflate = DeflateExt::Config();
38             };
39              
40             void configure (const Config& cfg);
41              
42             size_t max_frame_size () const { return _max_frame_size; }
43             size_t max_message_size () const { return _max_message_size; }
44             size_t max_handshake_size () const { return _max_handshake_size; }
45              
46             bool established () const { return _flags[ESTABLISHED]; }
47             bool recv_closed () const { return _flags[RECV_CLOSED]; }
48             bool send_closed () const { return _flags[SEND_CLOSED]; }
49              
50             FrameIteratorPair get_frames () {
51             return FrameIteratorPair(FrameIterator(this, _get_frame()), FrameIterator(this, NULL));
52             }
53              
54             MessageIteratorPair get_messages () {
55             return MessageIteratorPair(MessageIterator(this, _get_message()), MessageIterator(this, NULL));
56             }
57              
58             FrameIteratorPair get_frames (string& buf) {
59             if (_buffer) _buffer += buf; // user has not iterated previous call to get_frames till the end or remainder after handshake on client side
60             else _buffer = buf;
61             return get_frames();
62             }
63              
64             MessageIteratorPair get_messages (string& buf) {
65             if (_buffer) _buffer += buf; // user has not iterated previous call to get_frames till the end or remainder after handshake on client side
66             else _buffer = buf;
67             return get_messages();
68             }
69              
70             FrameSender start_message (Opcode opcode = Opcode::BINARY, DeflateFlag deflate = DeflateFlag::NO) {
71             _check_send();
72             if (_flags[SEND_FRAME]) throw Error("can't start message: previous message wasn't finished");
73             _flags.set(SEND_FRAME);
74             _send_opcode = opcode;
75             if (_deflate_ext && deflate != DeflateFlag::NO) _flags.set(SEND_DEFLATE);
76             return FrameSender(*this);
77             }
78              
79             FrameSender start_message (DeflateFlag deflate) { return start_message(Opcode::BINARY, deflate); }
80              
81             string send_frame (bool final) {
82             bool deflate = _flags[SEND_DEFLATE];
83             auto header = _prepare_frame_header(final);
84             if (final && deflate) _deflate_ext->reset_tx();
85             return Frame::compile(header);
86             }
87              
88             StringPair send_frame(string& payload, bool final) {
89             bool deflate = _flags[SEND_DEFLATE];
90             auto header = _prepare_frame_header(final);
91             if (deflate) _deflate_ext->compress(payload, final);
92             string hbin = Frame::compile(header, payload);
93             return make_string_pair(hbin, payload);
94             }
95              
96             template
97             StringChain send_frame (It payload_begin, It payload_end, bool final) {
98             bool deflate = _flags[SEND_DEFLATE];
99             auto header = _prepare_frame_header(final);
100             if (deflate) {
101             if (payload_begin == payload_end) {
102             string trailer;
103             _deflate_ext->compress(trailer, final);
104             string hbin = Frame::compile(header, trailer);
105             if (trailer) hbin += trailer;
106             return make_string_pair(hbin, payload_begin, payload_end);
107             }
108             payload_end = _deflate_ext->compress(payload_begin, payload_end, final);
109             }
110             string hbin = Frame::compile(header, payload_begin, payload_end);
111             return make_string_pair(hbin, payload_begin, payload_end);
112             }
113              
114             MessageBuilder message () { return MessageBuilder(*this); }
115              
116             string send_control (Opcode opcode) { return Frame::compile(_prepare_control_header(opcode)); }
117              
118             StringPair send_control (Opcode opcode, string& payload) {
119             if (payload.length() > Frame::MAX_CONTROL_PAYLOAD) {
120             panda_log_critical("control frame payload is too long");
121             payload.offset(0, Frame::MAX_CONTROL_PAYLOAD);
122             }
123             auto header = _prepare_control_header(opcode);
124             string hbin = Frame::compile(header, payload);
125             return make_string_pair(hbin, payload);
126             }
127              
128             string send_ping () { return send_control(Opcode::PING); }
129             StringPair send_ping (string& payload) { return send_control(Opcode::PING, payload); }
130             string send_pong () { return send_control(Opcode::PONG); }
131             StringPair send_pong (string& payload) { return send_control(Opcode::PONG, payload); }
132             string send_close () { return send_control(Opcode::CLOSE); }
133              
134             StringPair send_close (uint16_t code, const string& payload = string()) {
135             string frpld = FrameHeader::compile_close_payload(code, payload);
136             return send_control(Opcode::CLOSE, frpld);
137             }
138              
139             uint16_t suggested_close_code () const { return _suggested_close_code; }
140              
141             virtual void reset ();
142              
143             bool is_deflate_active () const { return (bool)_deflate_ext; }
144              
145             const DeflateConfigOption& deflate_config () const { return _deflate_cfg; }
146              
147             DeflateConfigOption effective_deflate_config () const {
148             if (!_deflate_ext) return {};
149             return _deflate_ext->effective_config();
150             }
151              
152             void no_deflate () {
153             if (!_flags[ESTABLISHED]) _deflate_cfg = DeflateConfigOption();
154             }
155              
156 0 0         virtual ~Parser () {}
    0          
157              
158             protected:
159             using DeflateExtPtr = std::unique_ptr;
160              
161             static const int ESTABLISHED = 1; // connection has been established
162             static const int RECV_FRAME = 2; // frame mode receive
163             static const int RECV_MESSAGE = 3; // message mode receive
164             static const int RECV_INFLATE = 4; // receiving compressed message
165             static const int RECV_TEXT = 5; // receiving text message
166             static const int RECV_CLOSED = 6; // no more messages from peer (close packet received)
167             static const int SEND_FRAME = 7; // outgoing message started
168             static const int SEND_DEFLATE = 8; // sending compressed message
169             static const int SEND_CLOSED = 9; // no more messages from user (close packet sent)
170             static const int LAST_FLAG = SEND_CLOSED;
171              
172             size_t _max_frame_size;
173             size_t _max_message_size;
174             size_t _max_handshake_size;
175             DeflateConfigOption _deflate_cfg;
176             bool _check_utf8;
177             std::bitset<32> _flags = 0;
178             string _buffer;
179             DeflateExtPtr _deflate_ext;
180              
181             Parser (bool recv_mask_required, Config cfg = Config()) : _recv_mask_required(recv_mask_required), _message_frame(recv_mask_required, cfg.max_frame_size) {
182             configure(cfg);
183             }
184              
185             private:
186             bool _recv_mask_required;
187             FrameSP _frame; // current frame being received (frame mode)
188             int _frame_count = 0; // frame count for current message being received
189             MessageSP _message; // current message being received (message mode)
190             Frame _message_frame; // current frame being received (message mode)
191             int _sent_frame_count = 0; // frame count for current message being sent (frame mode)
192             Opcode _send_opcode; // opcode for first frame to be sent (frame mode)
193             uint16_t _suggested_close_code = 0; // suggested close code to send to peer after error or receiving close frame from peer
194             Utf8Checker _utf8_checker;
195              
196             std::deque _simple_payload_tmp;
197              
198             FrameSP _get_frame ();
199             MessageSP _get_message ();
200             bool _parse_frame (Frame&);
201              
202 210           void _check_send () const {
203 210 50         if (!_flags[ESTABLISHED]) throw Error("not established");
204 210 100         if (_flags[SEND_CLOSED]) throw Error("close sent, can't send anymore");
205 209           }
206              
207             FrameHeader _prepare_control_header (Opcode opcode);
208             FrameHeader _prepare_frame_header (bool final);
209              
210             friend struct FrameSender;
211             friend struct MessageBuilder;
212             };
213              
214             using FrameIteratorPair = Parser::FrameIteratorPair;
215             using FrameIterator = Parser::FrameIterator;
216             using MessageIteratorPair = Parser::MessageIteratorPair;
217             using MessageIterator = Parser::MessageIterator;
218             using FrameSender = Parser::FrameSender;
219             using MessageBuilder = Parser::MessageBuilder;
220             using ParserSP = iptr;
221              
222             }}}