1+ #include "websocket_parser.h"
2+ #include <assert.h>
3+ #include <stddef.h>
4+ #include <stdlib.h>
5+ #include <string.h>
6+ #include <limits.h>
7+
8+
9+ #ifdef __GNUC__
10+ # define EXPECTED (X ) __builtin_expect(!!(X), 1)
11+ # define UNEXPECTED (X ) __builtin_expect(!!(X), 0)
12+ #else
13+ # define EXPECTED (X ) (X)
14+ # define UNEXPECTED (X ) (X)
15+ #endif
16+
17+ #define OPCODE_MASK 0xF
18+
19+ #define NOTIFY_CB (FOR ) \
20+ do { \
21+ if (settings->on_##FOR) { \
22+ if (settings->on_##FOR(parser) != 0) { \
23+ return i; \
24+ } \
25+ } \
26+ } while (0)
27+
28+ #define EMIT_DATA_CB (FOR , ptr , len ) \
29+ do { \
30+ if (settings->on_##FOR) { \
31+ if (settings->on_##FOR(parser, ptr, len) != 0) { \
32+ return i; \
33+ } \
34+ } \
35+ } while (0)
36+
37+ enum state {
38+ s_start ,
39+ s_head ,
40+ s_length ,
41+ s_mask ,
42+ s_body ,
43+ };
44+
45+ void websocket_parser_init (websocket_parser * parser ) {
46+ void * data = parser -> data ; /* preserve application data */
47+ memset (parser , 0 , sizeof (* parser ));
48+ parser -> data = data ;
49+ parser -> state = s_start ;
50+ parser -> error = 0 ;
51+ }
52+
53+ void websocket_parser_settings_init (websocket_parser_settings * settings ) {
54+ memset (settings , 0 , sizeof (* settings ));
55+ }
56+
57+ size_t websocket_parser_execute (websocket_parser * parser , const websocket_parser_settings * settings , const char * data , size_t len ) {
58+ size_t i = 0 ;
59+ size_t r = 0 ;
60+ char c ;
61+
62+ while (i < len ) {
63+ c = data [i ];
64+ switch (parser -> state ) {
65+ case s_start :
66+ parser -> length = 0 ;
67+ parser -> flags = (uint32_t ) (c & WS_OP_MASK );
68+ c >>= 7 ;
69+ if (c & 1 ) {
70+ parser -> flags |= WS_FIN ;
71+ }
72+ parser -> state = s_head ;
73+ break ;
74+ case s_head :
75+ parser -> length = (size_t )c & 0x7F ;
76+ if (c & 0x80 ) {
77+ parser -> flags |= WS_HAS_MASK ;
78+ }
79+ if (EXPECTED (parser -> length >= 126 )) {
80+ if (EXPECTED (parser -> length == 127 )) {
81+ if (EXPECTED (len - i > 8 )) {
82+ parser -> length = (uint16_t )data [i + 1 ];
83+ i += 8 ;
84+ } else {
85+ parser -> require = 8 ;
86+ parser -> state = s_length ;
87+ }
88+ } else {
89+ if (EXPECTED (len - i >= 2 )) {
90+ parser -> length = (uint16_t )data [i + 1 ];
91+ i += 2 ;
92+ } else {
93+ parser -> require = 2 ;
94+ }
95+ }
96+ } else {
97+ }
98+ if (EXPECTED (parser -> require )) {
99+ parser -> state = s_length ;
100+ } else {
101+ if (EXPECTED (parser -> flags & WS_HAS_MASK )) {
102+ parser -> state = s_mask ;
103+ parser -> require = 4 ;
104+ } else if (parser -> length ) {
105+ parser -> require = parser -> length ;
106+ NOTIFY_CB (frame_header );
107+ parser -> state = s_body ;
108+ } else {
109+ NOTIFY_CB (frame_header );
110+ NOTIFY_CB (frame_end );
111+ parser -> state = s_start ;
112+ }
113+ }
114+ break ;
115+ case s_length :
116+ for (; i < len , parser -> require ; i ++ , parser -> require -- ) {
117+ parser -> length <<= 8 ;
118+ parser -> length |= (unsigned char )data [i ];
119+ }
120+ if (!UNEXPECTED (parser -> require )) {
121+ parser -> require = parser -> length ;
122+ NOTIFY_CB (frame_header );
123+ parser -> state = s_body ;
124+ }
125+ break ;
126+ case s_mask :
127+ for (; i < len , parser -> require ; i ++ , parser -> require -- ) {
128+ parser -> mask [4 - parser -> require ] = data [i ];
129+ }
130+ i -- ;
131+ if (!UNEXPECTED (parser -> require )) {
132+ if (parser -> length ) {
133+ parser -> require = parser -> length ;
134+ NOTIFY_CB (frame_header );
135+ parser -> state = s_body ;
136+ } else {
137+ NOTIFY_CB (frame_header );
138+ NOTIFY_CB (frame_end );
139+ parser -> state = s_start ;
140+ }
141+ }
142+ break ;
143+ case s_body :
144+ if (parser -> require ) {
145+ r = parser -> require ;
146+ parser -> require -= len - i ;
147+ EMIT_DATA_CB (frame_body , & data [i ], len - i );
148+ parser -> offset = len - parser -> require ;
149+ i += r ;
150+ }
151+ if (!UNEXPECTED (parser -> require )) {
152+ NOTIFY_CB (frame_end );
153+ parser -> state = s_start ;
154+ }
155+ break ;
156+ default :
157+ parser -> error = ERR_UNKNOWN_STATE ;
158+ return i ;
159+ }
160+ i ++ ;
161+ }
162+
163+ return i ;
164+ }
165+
166+ void websocket_parser_copy_masked (char * dst , const char * src , size_t len , websocket_parser * parser ) {
167+ size_t i = 0 ;
168+ for (; i < len ; i ++ ) {
169+ dst [i ] = src [i ] ^ parser -> mask [(i + parser -> mask_offset ) % 4 ];
170+ }
171+
172+ parser -> mask_offset = (uint8_t ) ((i + parser -> mask_offset + 1 ) % 4 );
173+ }
0 commit comments