File Coverage

src/panda/protocol/websocket/FrameHeader.cc
Criterion Covered Total %
statement 77 77 100.0
branch 46 56 82.1
condition n/a
subroutine n/a
pod n/a
total 123 133 92.4


line stmt bran cond sub pod time code
1             #include "FrameHeader.h"
2             #include "utils.h"
3             #include
4             #include
5             #include
6             #include
7              
8             namespace panda { namespace protocol { namespace websocket {
9              
10             using std::cout;
11             using std::endl;
12              
13             static const int MAX_SIZE = 14; // 2 bytes required + 8-byte length + 4-byte mask
14              
15             #pragma pack(push,1)
16             struct BinaryFirst {
17             uint8_t opcode : 4;
18             bool rsv3 : 1;
19             bool rsv2 : 1;
20             bool rsv1 : 1;
21             bool fin : 1;
22             };
23             struct BinarySecond {
24             uint8_t slen : 7;
25             bool mask : 1;
26             };
27             #pragma pack(pop)
28              
29 1030           bool FrameHeader::parse (string& buf) {
30 1030 50         assert(_state != State::DONE);
31              
32 1030           auto data = buf.data();
33 1030           auto end = data + buf.length();
34              
35 1030 100         if (_state == State::FIRST) {
36 465 50         if (data == end) return false;
37 465           auto first = *((BinaryFirst*)data++);
38 465           fin = first.fin;
39 465           rsv1 = first.rsv1;
40 465           rsv2 = first.rsv2;
41 465           rsv3 = first.rsv3;
42 465           opcode = (Opcode)first.opcode;
43 465           _state = State::SECOND;
44             }
45              
46 1030 100         if (_state == State::SECOND) {
47 576 100         if (data == end) return false;
48 465           auto second = *((BinarySecond*)data++);
49 465           has_mask = second.mask;
50 465           _slen = second.slen;
51 465           _state = State::LENGTH;
52             //cout << "FrameHeader[parse]: HASMASK=" << has_mask << ", SLEN=" << (int)_slen << endl;
53             }
54              
55 919 100         if (_state == State::LENGTH) {
56 495 100         if (_slen < 126) {
57 335           length = _slen;
58 335           _state = State::MASK;
59             //cout << "FrameHeader[parse]: LENGTH(7)=" << length << endl;
60             }
61 160 100         else if (data == end) return false;
62 148 100         else if (_slen == 126) {
63 139 100         if (!parse_binary_number(_len16, data, end - data)) return false;
64 128           length = be2h16(_len16);
65 128           _state = State::MASK;
66             //cout << "FrameHeader[parse]: LENGTH(16)=" << length << endl;
67             }
68             else { // 127
69 9 100         if (!parse_binary_number(length, data, end - data)) return false;
70 2           length = be2h64(length);
71 465           _state = State::MASK;
72             //cout << "FrameHeader[parse]: LENGTH(64)=" << length << endl;
73             }
74             }
75              
76 889 50         if (_state == State::MASK) {
77 889 100         if (!has_mask) _state = State::DONE;
78 827 100         else if (data == end) return false;
79             else {
80 721 100         if (!parse_binary_number(mask, data, end - data)) return false;
81 465           _state = State::DONE;
82             //cout << "FrameHeader[parse]: MASK=" << mask << endl;
83             }
84             }
85              
86 465 100         if (data == end) buf.clear(); // no extra data after the end of frame
87 330 50         else buf.offset(data - buf.data()); // leave rest in buffer
88              
89 1030           return true;
90             }
91              
92 234           string FrameHeader::compile (size_t plen) const {
93 234           string ret(MAX_SIZE);
94 234 50         char* ptr = ret.buf();
95 234           const char*const begin = ptr;
96              
97 234           *((BinaryFirst*)ptr++) = BinaryFirst{(uint8_t)opcode, rsv3, rsv2, rsv1, fin};
98              
99 234 100         if (plen < 126) {
100 118           *((BinarySecond*)ptr++) = BinarySecond{(uint8_t)plen, has_mask};
101 116 100         } else if (plen < 65536) {
102 114           *((BinarySecond*)ptr++) = BinarySecond{126, has_mask};
103 114           *((uint16_t*)ptr) = h2be16(plen);
104 114           ptr += sizeof(uint16_t);
105             } else {
106 2           *((BinarySecond*)ptr++) = BinarySecond{127, has_mask};
107 2           *((uint64_t*)ptr) = h2be64(plen);
108 2           ptr += sizeof(uint64_t);
109             }
110              
111 234 100         if (has_mask) {
112 122           *((uint32_t*)ptr) = mask;
113 122           ptr += sizeof(uint32_t);
114             }
115              
116 234           ret.length(ptr - begin);
117 234           return ret;
118             }
119              
120 31           bool FrameHeader::parse_close_payload (const string& payload, uint16_t& code, string& message) {
121 31 50         if (!payload) code = (uint16_t)CloseCode::UNKNOWN;
122 31 100         else if (payload.length() < sizeof(code)) {
123 6           code = (uint16_t)CloseCode::UNKNOWN;
124 6           return false;
125             }
126 25           auto ptr = payload.data();
127 25           code = be2h16(*((uint16_t*)ptr));
128 25 50         message = payload.substr(sizeof(code));
129             // check for invalid close codes
130 31           return !CloseCode::is_sending_forbidden(code);
131             }
132              
133 3           string FrameHeader::compile_close_payload (uint16_t code, const string& message) {
134 3           size_t sz = sizeof(code) + message.length();
135 3           string ret(sz);
136 3 50         char* buf = ret.buf();
137 3           *((uint16_t*)buf) = h2be16(code);
138 3           buf += sizeof(code);
139 3 100         if (message.length()) std::memcpy(buf, message.data(), message.length());
140 3           ret.length(sz);
141 3           return ret;
142             }
143              
144 72 50         }}}
    50