blob: dcf1cdceb88e6973254f51b30ed3aef560a7a44c [file] [log] [blame]
Andy Green7c212cc2010-11-08 20:20:42 +00001/*
2 * libwebsockets - small server side websockets and web server implementation
Andy Greene77ddd82010-11-13 10:03:47 +00003 *
Andy Greena1ce6be2013-01-18 11:43:21 +08004 * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
Andy Green7c212cc2010-11-08 20:20:42 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22#include "private-libwebsockets.h"
23
Andreas Pakulat68bd4bd2013-10-28 15:18:04 +010024#if defined(WIN32) || defined(_WIN32)
David Galeanoaeb57482013-01-09 15:25:05 +080025#include <io.h>
26#endif
27
Andy Green7c212cc2010-11-08 20:20:42 +000028
Andy Green6d1fcb72013-01-18 01:55:48 +080029unsigned char lextable[] = {
Andy Greencc13c6f2013-11-09 10:09:09 +080030 #include "lextable.h"
Andy Green6d1fcb72013-01-18 01:55:48 +080031};
32
33int lextable_decode(int pos, char c)
34{
35 while (pos >= 0) {
Andy Greenb5b23192013-02-11 17:13:32 +080036 if (lextable[pos + 1] == 0) /* terminal marker */
Andy Green6d1fcb72013-01-18 01:55:48 +080037 return pos;
38
Andy Green909a3722013-11-13 08:03:05 +080039 /* case insensitive - RFC2616 */
40 if ((lextable[pos] & 0x7f) == tolower(c))
Andy Green6d1fcb72013-01-18 01:55:48 +080041 return pos + (lextable[pos + 1] << 1);
42
43 if (lextable[pos] & 0x80)
44 return -1;
45
46 pos += 2;
47 }
48 return pos;
49}
50
Andy Green16ab3182013-02-10 18:02:31 +080051int lws_allocate_header_table(struct libwebsocket *wsi)
52{
Andy Greenb5b23192013-02-11 17:13:32 +080053 wsi->u.hdr.ah = malloc(sizeof(*wsi->u.hdr.ah));
Andy Green16ab3182013-02-10 18:02:31 +080054 if (wsi->u.hdr.ah == NULL) {
55 lwsl_err("Out of memory\n");
56 return -1;
57 }
Andy Greenb5b23192013-02-11 17:13:32 +080058 memset(wsi->u.hdr.ah->frag_index, 0, sizeof(wsi->u.hdr.ah->frag_index));
Andy Green16ab3182013-02-10 18:02:31 +080059 wsi->u.hdr.ah->next_frag_index = 0;
60 wsi->u.hdr.ah->pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +080061
Andy Green16ab3182013-02-10 18:02:31 +080062 return 0;
63}
64
Peter Pentchev9a4fef72013-03-30 09:52:21 +080065LWS_VISIBLE int lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +080066{
67 int n;
68 int len = 0;
69
70 n = wsi->u.hdr.ah->frag_index[h];
71 if (n == 0)
72 return 0;
73
74 do {
75 len += wsi->u.hdr.ah->frags[n].len;
76 n = wsi->u.hdr.ah->frags[n].next_frag_index;
77 } while (n);
78
79 return len;
80}
81
Peter Pentchev9a4fef72013-03-30 09:52:21 +080082LWS_VISIBLE int lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len,
Andy Greenb5b23192013-02-11 17:13:32 +080083 enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +080084{
85 int toklen = lws_hdr_total_length(wsi, h);
86 int n;
87
88 if (toklen >= len)
89 return -1;
90
91 n = wsi->u.hdr.ah->frag_index[h];
92 if (n == 0)
93 return 0;
94
95 do {
Andy Greenb5b23192013-02-11 17:13:32 +080096 strcpy(dest,
97 &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]);
Andy Green16ab3182013-02-10 18:02:31 +080098 dest += wsi->u.hdr.ah->frags[n].len;
99 n = wsi->u.hdr.ah->frags[n].next_frag_index;
100 } while (n);
101
102 return toklen;
103}
104
Andy Greenb5b23192013-02-11 17:13:32 +0800105char *lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800106{
107 int n;
108
109 n = wsi->u.hdr.ah->frag_index[h];
110 if (!n)
111 return NULL;
112
113 return &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset];
114}
Andy Green6d1fcb72013-01-18 01:55:48 +0800115
Andy Greenb5b23192013-02-11 17:13:32 +0800116int lws_hdr_simple_create(struct libwebsocket *wsi,
117 enum lws_token_indexes h, const char *s)
Andy Greene77fb802013-02-11 13:04:45 +0800118{
119 wsi->u.hdr.ah->next_frag_index++;
Andy Greenb5b23192013-02-11 17:13:32 +0800120 if (wsi->u.hdr.ah->next_frag_index ==
121 sizeof(wsi->u.hdr.ah->frags) / sizeof(wsi->u.hdr.ah->frags[0])) {
122 lwsl_warn("More hdr frags than we can deal with, dropping\n");
Andy Greene77fb802013-02-11 13:04:45 +0800123 return -1;
124 }
125
126 wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->next_frag_index;
127
Andy Greenb5b23192013-02-11 17:13:32 +0800128 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
129 wsi->u.hdr.ah->pos;
Andy Greene77fb802013-02-11 13:04:45 +0800130 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
Andy Greenb5b23192013-02-11 17:13:32 +0800131 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].next_frag_index =
132 0;
Andy Greene77fb802013-02-11 13:04:45 +0800133
134 do {
Andy Greenb5b23192013-02-11 17:13:32 +0800135 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
Andy Greene77fb802013-02-11 13:04:45 +0800136 lwsl_err("Ran out of header data space\n");
137 return -1;
138 }
139 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s;
140 if (*s)
Andy Greenb5b23192013-02-11 17:13:32 +0800141 wsi->u.hdr.ah->frags[
142 wsi->u.hdr.ah->next_frag_index].len++;
Andy Greene77fb802013-02-11 13:04:45 +0800143 } while (*s++);
144
145 return 0;
146}
147
Andy Greenb1a9e502013-11-10 15:15:21 +0800148static char char_to_hex(const char c)
149{
150 if (c >= '0' && c <= '9')
151 return c - '0';
152
153 if (c >= 'a' && c <= 'f')
154 return c - 'a' + 10;
155
156 if (c >= 'A' && c <= 'F')
157 return c - 'A' + 10;
158
159 return -1;
160}
161
162static int issue_char(struct libwebsocket *wsi, unsigned char c)
163{
164 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
165 lwsl_warn("excessive header content\n");
166 return -1;
167 }
168 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c;
169 if (c)
170 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
171
172 return 0;
173}
174
Andy Green7c212cc2010-11-08 20:20:42 +0000175int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
176{
177 int n;
178
Andy Green623a98d2013-01-21 11:04:23 +0800179 switch (wsi->u.hdr.parser_state) {
Andy Green7c212cc2010-11-08 20:20:42 +0000180 case WSI_TOKEN_GET_URI:
kapejodce64fb02013-11-19 13:38:16 +0100181 case WSI_TOKEN_POST_URI:
Andy Green7c212cc2010-11-08 20:20:42 +0000182 case WSI_TOKEN_HOST:
183 case WSI_TOKEN_CONNECTION:
184 case WSI_TOKEN_KEY1:
185 case WSI_TOKEN_KEY2:
186 case WSI_TOKEN_PROTOCOL:
187 case WSI_TOKEN_UPGRADE:
188 case WSI_TOKEN_ORIGIN:
Andy Green4739e5c2011-01-22 12:51:57 +0000189 case WSI_TOKEN_SWORIGIN:
Andy Greence510c62010-11-11 12:48:13 +0000190 case WSI_TOKEN_DRAFT:
Andy Green7c212cc2010-11-08 20:20:42 +0000191 case WSI_TOKEN_CHALLENGE:
Andy Greend1b11e32011-01-18 15:39:02 +0000192 case WSI_TOKEN_KEY:
193 case WSI_TOKEN_VERSION:
Andy Green4739e5c2011-01-22 12:51:57 +0000194 case WSI_TOKEN_ACCEPT:
195 case WSI_TOKEN_NONCE:
Andy Green18910c52011-02-09 08:58:42 +0000196 case WSI_TOKEN_EXTENSIONS:
Andy Green4739e5c2011-01-22 12:51:57 +0000197 case WSI_TOKEN_HTTP:
Andy Greencc13c6f2013-11-09 10:09:09 +0800198 case WSI_TOKEN_HTTP_ACCEPT:
199 case WSI_TOKEN_HTTP_IF_MODIFIED_SINCE:
200 case WSI_TOKEN_HTTP_ACCEPT_ENCODING:
201 case WSI_TOKEN_HTTP_ACCEPT_LANGUAGE:
202 case WSI_TOKEN_HTTP_PRAGMA:
203 case WSI_TOKEN_HTTP_CACHE_CONTROL:
204 case WSI_TOKEN_HTTP_AUTHORIZATION:
205 case WSI_TOKEN_HTTP_COOKIE:
kapejodce64fb02013-11-19 13:38:16 +0100206 case WSI_TOKEN_HTTP_CONTENT_LENGTH:
Andy Greencc13c6f2013-11-09 10:09:09 +0800207 case WSI_TOKEN_HTTP_CONTENT_TYPE:
208 case WSI_TOKEN_HTTP_DATE:
209 case WSI_TOKEN_HTTP_RANGE:
210 case WSI_TOKEN_HTTP_REFERER:
211
Andy Greena41314f2011-05-23 10:00:03 +0100212
Andy Greenb5b23192013-02-11 17:13:32 +0800213 lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c);
Andy Green7c212cc2010-11-08 20:20:42 +0000214
215 /* collect into malloc'd buffers */
Andy Green16ab3182013-02-10 18:02:31 +0800216 /* optional initial space swallow */
Andy Greenb5b23192013-02-11 17:13:32 +0800217 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->frag_index[
218 wsi->u.hdr.parser_state]].len && c == ' ')
Andy Green7c212cc2010-11-08 20:20:42 +0000219 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000220
kapejodce64fb02013-11-19 13:38:16 +0100221 if ((wsi->u.hdr.parser_state != WSI_TOKEN_GET_URI) && (wsi->u.hdr.parser_state != WSI_TOKEN_POST_URI))
Andy Greenb1a9e502013-11-10 15:15:21 +0800222 goto check_eol;
223
224 /* special URI processing... end at space */
225
226 if (c == ' ') {
227 /* enforce starting with / */
228 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len)
229 if (issue_char(wsi, '/') < 0)
230 return -1;
Andy Green16ab3182013-02-10 18:02:31 +0800231 c = '\0';
Andy Green623a98d2013-01-21 11:04:23 +0800232 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
Andy Greenb1a9e502013-11-10 15:15:21 +0800233 goto spill;
Andy Green7c212cc2010-11-08 20:20:42 +0000234 }
235
Andy Greenb1a9e502013-11-10 15:15:21 +0800236 /* special URI processing... convert %xx */
237
238 switch (wsi->u.hdr.ues) {
239 case URIES_IDLE:
240 if (c == '%') {
241 wsi->u.hdr.ues = URIES_SEEN_PERCENT;
242 goto swallow;
243 }
244 break;
245 case URIES_SEEN_PERCENT:
246 if (char_to_hex(c) < 0) {
247 /* regurgitate */
248 if (issue_char(wsi, '%') < 0)
249 return -1;
250 wsi->u.hdr.ues = URIES_IDLE;
251 /* continue on to assess c */
252 break;
253 }
254 wsi->u.hdr.esc_stash = c;
255 wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
Andy Green6f429102013-11-11 06:14:52 +0800256 goto swallow;
Andy Greenb1a9e502013-11-10 15:15:21 +0800257
258 case URIES_SEEN_PERCENT_H1:
259 if (char_to_hex(c) < 0) {
260 /* regurgitate */
261 issue_char(wsi, '%');
262 wsi->u.hdr.ues = URIES_IDLE;
263 /* regurgitate + assess */
264 if (libwebsocket_parse(wsi, wsi->u.hdr.esc_stash) < 0)
265 return -1;
266 /* continue on to assess c */
267 break;
268 }
269 c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
270 char_to_hex(c);
Andy Green6f429102013-11-11 06:14:52 +0800271 wsi->u.hdr.ues = URIES_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800272 break;
273 }
274
275 /*
276 * special URI processing...
Andy Green6f429102013-11-11 06:14:52 +0800277 * convert /.. or /... or /../ etc to /
278 * convert /./ to /
Andy Greenb1a9e502013-11-10 15:15:21 +0800279 * convert // or /// etc to /
280 * leave /.dir or whatever alone
281 */
282
283 switch (wsi->u.hdr.ups) {
284 case URIPS_IDLE:
285 /* issue the first / always */
286 if (c == '/')
287 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
288 break;
289 case URIPS_SEEN_SLASH:
290 /* swallow subsequent slashes */
291 if (c == '/')
292 goto swallow;
293 /* track and swallow the first . after / */
294 if (c == '.') {
295 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT;
296 goto swallow;
297 } else
298 wsi->u.hdr.ups = URIPS_IDLE;
299 break;
300 case URIPS_SEEN_SLASH_DOT:
301 /* swallow second . */
302 if (c == '.') {
Andy Greend3f68732013-11-13 06:53:21 +0800303 /*
304 * back up one dir level if possible
305 * safe against header fragmentation because
306 * the method URI can only be in 1 fragment
307 */
308 if (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 2) {
309 wsi->u.hdr.ah->pos--;
310 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
311 do {
312 wsi->u.hdr.ah->pos--;
313 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
314 } while (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 1 &&
315 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos] != '/');
316 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800317 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
318 goto swallow;
319 }
Andy Green6f429102013-11-11 06:14:52 +0800320 /* change /./ to / */
321 if (c == '/') {
322 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
323 goto swallow;
324 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800325 /* it was like /.dir ... regurgitate the . */
326 wsi->u.hdr.ups = URIPS_IDLE;
327 issue_char(wsi, '.');
328 break;
329
330 case URIPS_SEEN_SLASH_DOT_DOT:
331 /* swallow prior .. chars and any subsequent . */
332 if (c == '.')
333 goto swallow;
Andy Green6f429102013-11-11 06:14:52 +0800334 /* last issued was /, so another / == // */
335 if (c == '/')
336 goto swallow;
Andy Greenb1a9e502013-11-10 15:15:21 +0800337 else /* last we issued was / so SEEN_SLASH */
338 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
339 break;
Andy Green1e3f7b82013-11-13 07:45:17 +0800340 case URIPS_ARGUMENTS:
341 /* leave them alone */
342 break;
Andy Greenb1a9e502013-11-10 15:15:21 +0800343 }
344
345check_eol:
346
Andy Green7c212cc2010-11-08 20:20:42 +0000347 /* bail at EOL */
Andy Greenb5b23192013-02-11 17:13:32 +0800348 if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
349 c == '\x0d') {
Andy Green16ab3182013-02-10 18:02:31 +0800350 c = '\0';
Andy Green623a98d2013-01-21 11:04:23 +0800351 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
Andy Green43db0452013-01-10 19:50:35 +0800352 lwsl_parser("*\n");
Andy Green7c212cc2010-11-08 20:20:42 +0000353 }
354
Andy Green1e3f7b82013-11-13 07:45:17 +0800355 if (c == '?') { /* start of URI arguments */
356 /* seal off uri header */
357 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0';
358
359 /* move to using WSI_TOKEN_HTTP_URI_ARGS */
360 wsi->u.hdr.ah->next_frag_index++;
361 wsi->u.hdr.ah->frags[
362 wsi->u.hdr.ah->next_frag_index].offset =
363 wsi->u.hdr.ah->pos;
364 wsi->u.hdr.ah->frags[
365 wsi->u.hdr.ah->next_frag_index].len = 0;
366 wsi->u.hdr.ah->frags[
367 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
368
369 wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] =
370 wsi->u.hdr.ah->next_frag_index;
371
372 /* defeat normal uri path processing */
373 wsi->u.hdr.ups = URIPS_ARGUMENTS;
374 goto swallow;
375 }
376
Andy Greenb1a9e502013-11-10 15:15:21 +0800377spill:
378 if (issue_char(wsi, c) < 0)
Andy Green16ab3182013-02-10 18:02:31 +0800379 return -1;
Andy Greenb1a9e502013-11-10 15:15:21 +0800380swallow:
Andy Greend1b11e32011-01-18 15:39:02 +0000381 /* per-protocol end of headers management */
Andy Greene77ddd82010-11-13 10:03:47 +0000382
Andy Green16ab3182013-02-10 18:02:31 +0800383 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
384 goto set_parsing_complete;
Andy Greena41314f2011-05-23 10:00:03 +0100385 break;
386
Andy Green7c212cc2010-11-08 20:20:42 +0000387 /* collecting and checking a name part */
388 case WSI_TOKEN_NAME_PART:
Andy Green43db0452013-01-10 19:50:35 +0800389 lwsl_parser("WSI_TOKEN_NAME_PART '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000390
Andy Greenb5b23192013-02-11 17:13:32 +0800391 wsi->u.hdr.lextable_pos =
392 lextable_decode(wsi->u.hdr.lextable_pos, c);
Andy Green16ab3182013-02-10 18:02:31 +0800393
Andy Greene4dffc92013-02-04 09:24:18 +0800394 if (wsi->u.hdr.lextable_pos < 0) {
395 /* this is not a header we know about */
kapejodce64fb02013-11-19 13:38:16 +0100396 if (wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI] || wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI] ||
Andy Green646c98a2013-03-09 09:09:05 +0800397 wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP]) {
Andy Greenb5b23192013-02-11 17:13:32 +0800398 /*
399 * altready had the method, no idea what
400 * this crap is, ignore
401 */
Andy Greene4dffc92013-02-04 09:24:18 +0800402 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
403 break;
404 }
Andy Green3ee9b312013-02-12 12:52:39 +0800405 /*
406 * hm it's an unknown http method in fact,
407 * treat as dangerous
408 */
409
410 lwsl_info("Unknown method - dropping\n");
411 return -1;
Andy Greene4dffc92013-02-04 09:24:18 +0800412 }
Andy Green623a98d2013-01-21 11:04:23 +0800413 if (lextable[wsi->u.hdr.lextable_pos + 1] == 0) {
Andy Green6d1fcb72013-01-18 01:55:48 +0800414
Andy Greene4dffc92013-02-04 09:24:18 +0800415 /* terminal state */
416
Andy Green623a98d2013-01-21 11:04:23 +0800417 n = lextable[wsi->u.hdr.lextable_pos] & 0x7f;
Andy Green6d1fcb72013-01-18 01:55:48 +0800418
Andy Greencc7cb682013-02-18 10:22:42 +0800419 lwsl_parser("known hdr %d\n", n);
Andy Greenfd963302012-04-03 17:02:20 +0200420
Andy Green94f94652013-02-12 13:10:19 +0800421 if (n == WSI_TOKEN_GET_URI &&
422 wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI]) {
423 lwsl_warn("Duplicated GET\n");
424 return -1;
kapejodce64fb02013-11-19 13:38:16 +0100425 } else if (n == WSI_TOKEN_POST_URI &&
426 wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI]) {
427 lwsl_warn("Duplicated POST\n");
428 return -1;
Andy Green94f94652013-02-12 13:10:19 +0800429 }
430
Andy Greenfd963302012-04-03 17:02:20 +0200431 /*
432 * WSORIGIN is protocol equiv to ORIGIN,
433 * JWebSocket likes to send it, map to ORIGIN
434 */
435 if (n == WSI_TOKEN_SWORIGIN)
436 n = WSI_TOKEN_ORIGIN;
437
Andy Green16ab3182013-02-10 18:02:31 +0800438 wsi->u.hdr.parser_state = (enum lws_token_indexes)
439 (WSI_TOKEN_GET_URI + n);
440 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
441 goto set_parsing_complete;
Andy Green6964bb52011-01-23 16:50:33 +0000442
Andy Green16ab3182013-02-10 18:02:31 +0800443 goto start_fragment;
444 }
445 break;
Nick Dowell30592632012-04-05 10:31:48 +0800446
Andy Green16ab3182013-02-10 18:02:31 +0800447start_fragment:
448 wsi->u.hdr.ah->next_frag_index++;
Andy Greenb5b23192013-02-11 17:13:32 +0800449 if (wsi->u.hdr.ah->next_frag_index ==
450 sizeof(wsi->u.hdr.ah->frags) /
451 sizeof(wsi->u.hdr.ah->frags[0])) {
452 lwsl_warn("More hdr frags than we can deal with\n");
Andy Green16ab3182013-02-10 18:02:31 +0800453 return -1;
Andy Green7c212cc2010-11-08 20:20:42 +0000454 }
455
Andy Greenb5b23192013-02-11 17:13:32 +0800456 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
457 wsi->u.hdr.ah->pos;
Andy Green16ab3182013-02-10 18:02:31 +0800458 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
Andy Greenb5b23192013-02-11 17:13:32 +0800459 wsi->u.hdr.ah->frags[
460 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800461
462 n = wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state];
463 if (!n) { /* first fragment */
464 wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state] =
465 wsi->u.hdr.ah->next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800466 break;
467 }
468 /* continuation */
469 while (wsi->u.hdr.ah->frags[n].next_frag_index)
Andy Green16ab3182013-02-10 18:02:31 +0800470 n = wsi->u.hdr.ah->frags[n].next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800471 wsi->u.hdr.ah->frags[n].next_frag_index =
Andy Green16ab3182013-02-10 18:02:31 +0800472 wsi->u.hdr.ah->next_frag_index;
473
Andy Greencc13c6f2013-11-09 10:09:09 +0800474 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
475 lwsl_warn("excessive header content\n");
476 return -1;
Andy Green2b57a342013-02-06 15:15:25 +0900477 }
Andy Green7c212cc2010-11-08 20:20:42 +0000478
Andy Greencc13c6f2013-11-09 10:09:09 +0800479 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = ' ';
480 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
Andy Greene4dffc92013-02-04 09:24:18 +0800481 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000482
Andy Green7c212cc2010-11-08 20:20:42 +0000483 /* skipping arg part of a name we didn't recognize */
484 case WSI_TOKEN_SKIPPING:
Andy Green43db0452013-01-10 19:50:35 +0800485 lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
kapejodce64fb02013-11-19 13:38:16 +0100486
Andy Green7c212cc2010-11-08 20:20:42 +0000487 if (c == '\x0d')
Andy Green623a98d2013-01-21 11:04:23 +0800488 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
Andy Green7c212cc2010-11-08 20:20:42 +0000489 break;
Andy Green177ca782013-02-04 09:09:19 +0800490
Andy Green7c212cc2010-11-08 20:20:42 +0000491 case WSI_TOKEN_SKIPPING_SAW_CR:
Andy Green43db0452013-01-10 19:50:35 +0800492 lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
Andy Green6d1fcb72013-01-18 01:55:48 +0800493 if (c == '\x0a') {
Andy Green623a98d2013-01-21 11:04:23 +0800494 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
495 wsi->u.hdr.lextable_pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +0800496 } else
Andy Green623a98d2013-01-21 11:04:23 +0800497 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
Andy Green7c212cc2010-11-08 20:20:42 +0000498 break;
499 /* we're done, ignore anything else */
kapejodce64fb02013-11-19 13:38:16 +0100500
Andy Green7c212cc2010-11-08 20:20:42 +0000501 case WSI_PARSING_COMPLETE:
Andy Green43db0452013-01-10 19:50:35 +0800502 lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000503 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000504
Andy Green7c212cc2010-11-08 20:20:42 +0000505 default: /* keep gcc happy */
506 break;
507 }
Andy Greene77ddd82010-11-13 10:03:47 +0000508
Andy Green7c212cc2010-11-08 20:20:42 +0000509 return 0;
Andy Green177ca782013-02-04 09:09:19 +0800510
511set_parsing_complete:
512
Andy Green16ab3182013-02-10 18:02:31 +0800513 if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800514 if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
Andy Green2b57a342013-02-06 15:15:25 +0900515 wsi->ietf_spec_revision =
Andy Green16ab3182013-02-10 18:02:31 +0800516 atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
Andy Green177ca782013-02-04 09:09:19 +0800517
Andy Greenb5b23192013-02-11 17:13:32 +0800518 lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision);
Andy Green2b57a342013-02-06 15:15:25 +0900519 }
Andy Green177ca782013-02-04 09:09:19 +0800520 wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE;
Andy Green224149a2013-02-11 21:43:41 +0800521 wsi->hdr_parsing_completed = 1;
Andy Green177ca782013-02-04 09:09:19 +0800522
523 return 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000524}
525
Andy Greenbfb051f2011-02-09 08:49:14 +0000526
Andy Green2fd3f2f2013-01-18 09:49:20 +0800527/**
528 * lws_frame_is_binary: true if the current frame was sent in binary mode
529 *
530 * @wsi: the connection we are inquiring about
531 *
532 * This is intended to be called from the LWS_CALLBACK_RECEIVE callback if
533 * it's interested to see if the frame it's dealing with was sent in binary
534 * mode.
535 */
536
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800537LWS_VISIBLE int lws_frame_is_binary(struct libwebsocket *wsi)
Andy Green2fd3f2f2013-01-18 09:49:20 +0800538{
Andy Green623a98d2013-01-21 11:04:23 +0800539 return wsi->u.ws.frame_is_binary;
Andy Green2fd3f2f2013-01-18 09:49:20 +0800540}
Andy Greenbfb051f2011-02-09 08:49:14 +0000541
Andy Greena41314f2011-05-23 10:00:03 +0100542int
543libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000544{
545 int n;
Andy Greena41314f2011-05-23 10:00:03 +0100546 struct lws_tokens eff_buf;
Andy Greenaedc9532013-02-10 21:21:24 +0800547 int ret = 0;
Andy Green3182ece2013-01-20 17:08:31 +0800548#ifndef LWS_NO_EXTENSIONS
Andy Greena41314f2011-05-23 10:00:03 +0100549 int handled;
550 int m;
Andy Green3182ece2013-01-20 17:08:31 +0800551#endif
Andy Greena41314f2011-05-23 10:00:03 +0100552
Andy Green6ee372f2012-04-09 15:09:01 +0800553#if 0
Andy Green43db0452013-01-10 19:50:35 +0800554 lwsl_debug("RX: %02X ", c);
Andy Green6ee372f2012-04-09 15:09:01 +0800555#endif
Andy Green7c212cc2010-11-08 20:20:42 +0000556
557 switch (wsi->lws_rx_parse_state) {
558 case LWS_RXPS_NEW:
Andy Greene77ddd82010-11-13 10:03:47 +0000559
Andy Green7c212cc2010-11-08 20:20:42 +0000560 switch (wsi->ietf_spec_revision) {
Andy Greend85cb202011-09-25 09:32:54 +0100561 case 13:
Andy Green283d0a22011-04-24 05:46:23 +0100562 /*
563 * no prepended frame key any more
564 */
Andy Green623a98d2013-01-21 11:04:23 +0800565 wsi->u.ws.all_zero_nonce = 1;
Andy Green283d0a22011-04-24 05:46:23 +0100566 goto handle_first;
567
Andy Greenbfb051f2011-02-09 08:49:14 +0000568 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800569 lwsl_warn("lws_rx_sm: unknown spec version %d\n",
570 wsi->ietf_spec_revision);
Andy Greenbfb051f2011-02-09 08:49:14 +0000571 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000572 }
Andy Green6452f1e2010-11-11 09:22:22 +0000573 break;
Andy Green3e5eb782011-01-18 18:14:26 +0000574 case LWS_RXPS_04_MASK_NONCE_1:
Andy Green623a98d2013-01-21 11:04:23 +0800575 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000576 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800577 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000578 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2;
579 break;
580 case LWS_RXPS_04_MASK_NONCE_2:
Andy Green623a98d2013-01-21 11:04:23 +0800581 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000582 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800583 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000584 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3;
585 break;
586 case LWS_RXPS_04_MASK_NONCE_3:
Andy Green623a98d2013-01-21 11:04:23 +0800587 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000588 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800589 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000590
Andy Green3e5eb782011-01-18 18:14:26 +0000591 /*
592 * start from the zero'th byte in the XOR key buffer since
593 * this is the start of a frame with a new key
594 */
595
Andy Green623a98d2013-01-21 11:04:23 +0800596 wsi->u.ws.frame_mask_index = 0;
Andy Green6964bb52011-01-23 16:50:33 +0000597
Andy Green3e5eb782011-01-18 18:14:26 +0000598 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
599 break;
Andy Green38e57bb2011-01-19 12:20:27 +0000600
601 /*
602 * 04 logical framing from the spec (all this is masked when incoming
603 * and has to be unmasked)
604 *
605 * We ignore the possibility of extension data because we don't
606 * negotiate any extensions at the moment.
Andy Green6964bb52011-01-23 16:50:33 +0000607 *
Andy Green38e57bb2011-01-19 12:20:27 +0000608 * 0 1 2 3
609 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
610 * +-+-+-+-+-------+-+-------------+-------------------------------+
611 * |F|R|R|R| opcode|R| Payload len | Extended payload length |
612 * |I|S|S|S| (4) |S| (7) | (16/63) |
613 * |N|V|V|V| |V| | (if payload len==126/127) |
614 * | |1|2|3| |4| | |
615 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
616 * | Extended payload length continued, if payload len == 127 |
617 * + - - - - - - - - - - - - - - - +-------------------------------+
618 * | | Extension data |
619 * +-------------------------------+ - - - - - - - - - - - - - - - +
620 * : :
621 * +---------------------------------------------------------------+
622 * : Application data :
623 * +---------------------------------------------------------------+
624 *
625 * We pass payload through to userland as soon as we get it, ignoring
626 * FIN. It's up to userland to buffer it up if it wants to see a
627 * whole unfragmented block of the original size (which may be up to
628 * 2^63 long!)
629 */
630
631 case LWS_RXPS_04_FRAME_HDR_1:
Andy Green283d0a22011-04-24 05:46:23 +0100632handle_first:
633
Andy Green623a98d2013-01-21 11:04:23 +0800634 wsi->u.ws.opcode = c & 0xf;
635 wsi->u.ws.rsv = c & 0x70;
636 wsi->u.ws.final = !!((c >> 7) & 1);
Andy Green1bc12f92013-02-28 17:11:29 +0800637
Andy Green623a98d2013-01-21 11:04:23 +0800638 switch (wsi->u.ws.opcode) {
Andy Green10601c12013-01-19 10:39:35 +0800639 case LWS_WS_OPCODE_07__TEXT_FRAME:
Andy Green10601c12013-01-19 10:39:35 +0800640 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Greenb5b23192013-02-11 17:13:32 +0800641 wsi->u.ws.frame_is_binary =
642 wsi->u.ws.opcode == LWS_WS_OPCODE_07__BINARY_FRAME;
Andy Green10601c12013-01-19 10:39:35 +0800643 break;
644 }
Andy Green38e57bb2011-01-19 12:20:27 +0000645 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
646 break;
647
648 case LWS_RXPS_04_FRAME_HDR_LEN:
Andy Green38e57bb2011-01-19 12:20:27 +0000649
Andy Green623a98d2013-01-21 11:04:23 +0800650 wsi->u.ws.this_frame_masked = !!(c & 0x80);
Andy Green283d0a22011-04-24 05:46:23 +0100651
Andy Green5bf65782011-09-25 10:46:31 +0100652 switch (c & 0x7f) {
Andy Green38e57bb2011-01-19 12:20:27 +0000653 case 126:
654 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800655 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100656 goto illegal_ctl_length;
657
Andy Green38e57bb2011-01-19 12:20:27 +0000658 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
659 break;
660 case 127:
661 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800662 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100663 goto illegal_ctl_length;
664
Andy Green38e57bb2011-01-19 12:20:27 +0000665 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
666 break;
667 default:
Andy Green623a98d2013-01-21 11:04:23 +0800668 wsi->u.ws.rx_packet_length = c & 0x7f;
669 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100670 wsi->lws_rx_parse_state =
671 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
672 else
Andy Green8ea19552014-02-15 16:00:37 +0800673 if (wsi->u.ws.rx_packet_length)
674 wsi->lws_rx_parse_state =
Andy Green38e57bb2011-01-19 12:20:27 +0000675 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green8ea19552014-02-15 16:00:37 +0800676 else {
677 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
678 goto spill;
679 }
Andy Green38e57bb2011-01-19 12:20:27 +0000680 break;
681 }
682 break;
683
684 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
Andy Green623a98d2013-01-21 11:04:23 +0800685 wsi->u.ws.rx_packet_length = c << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000686 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
687 break;
688
689 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
Andy Green623a98d2013-01-21 11:04:23 +0800690 wsi->u.ws.rx_packet_length |= c;
691 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100692 wsi->lws_rx_parse_state =
693 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
694 else
695 wsi->lws_rx_parse_state =
696 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000697 break;
698
699 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
Andy Green38e57bb2011-01-19 12:20:27 +0000700 if (c & 0x80) {
Andy Green43db0452013-01-10 19:50:35 +0800701 lwsl_warn("b63 of length must be zero\n");
Andy Green38e57bb2011-01-19 12:20:27 +0000702 /* kill the connection */
703 return -1;
704 }
Andy Greenf55830d2011-01-27 06:45:53 +0000705#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800706 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
Andy Greenf55830d2011-01-27 06:45:53 +0000707#else
Andy Green623a98d2013-01-21 11:04:23 +0800708 wsi->u.ws.rx_packet_length = 0;
Andy Greenf55830d2011-01-27 06:45:53 +0000709#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000710 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
711 break;
712
713 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
Andy Greenf55830d2011-01-27 06:45:53 +0000714#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800715 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
Andy Greenf55830d2011-01-27 06:45:53 +0000716#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000717 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
718 break;
719
720 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
Andy Greenf55830d2011-01-27 06:45:53 +0000721#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800722 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
Andy Greenf55830d2011-01-27 06:45:53 +0000723#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000724 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
725 break;
726
727 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
Andy Greenf55830d2011-01-27 06:45:53 +0000728#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800729 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
Andy Greenf55830d2011-01-27 06:45:53 +0000730#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000731 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
732 break;
733
734 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
Andy Green623a98d2013-01-21 11:04:23 +0800735 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
Andy Green38e57bb2011-01-19 12:20:27 +0000736 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
737 break;
738
739 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
Andy Green623a98d2013-01-21 11:04:23 +0800740 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
Andy Green38e57bb2011-01-19 12:20:27 +0000741 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
742 break;
743
744 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
Andy Green623a98d2013-01-21 11:04:23 +0800745 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000746 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
747 break;
748
749 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
Andy Green623a98d2013-01-21 11:04:23 +0800750 wsi->u.ws.rx_packet_length |= ((size_t)c);
751 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100752 wsi->lws_rx_parse_state =
753 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
754 else
755 wsi->lws_rx_parse_state =
756 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000757 break;
758
Andy Green283d0a22011-04-24 05:46:23 +0100759 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
Andy Green623a98d2013-01-21 11:04:23 +0800760 wsi->u.ws.frame_masking_nonce_04[0] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100761 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800762 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100763 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
764 break;
765
766 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
Andy Green623a98d2013-01-21 11:04:23 +0800767 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100768 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800769 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100770 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
771 break;
772
773 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
Andy Green623a98d2013-01-21 11:04:23 +0800774 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100775 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800776 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100777 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
778 break;
779
780 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
Andy Green623a98d2013-01-21 11:04:23 +0800781 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100782 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800783 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100784 wsi->lws_rx_parse_state =
785 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green623a98d2013-01-21 11:04:23 +0800786 wsi->u.ws.frame_mask_index = 0;
Andy Green8ea19552014-02-15 16:00:37 +0800787 if (wsi->u.ws.rx_packet_length == 0) {
788 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
Andy Green1bc12f92013-02-28 17:11:29 +0800789 goto spill;
Andy Green8ea19552014-02-15 16:00:37 +0800790 }
Andy Green283d0a22011-04-24 05:46:23 +0100791 break;
792
793
Andy Green7c212cc2010-11-08 20:20:42 +0000794 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
Andy Green3182ece2013-01-20 17:08:31 +0800795
Andy Green54495112013-02-06 21:10:16 +0900796 if (!wsi->u.ws.rx_user_buffer)
797 lwsl_err("NULL user buffer...\n");
798
Andy Green623a98d2013-01-21 11:04:23 +0800799 if (wsi->u.ws.all_zero_nonce)
800 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
801 (wsi->u.ws.rx_user_buffer_head++)] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000802 else
Andy Green623a98d2013-01-21 11:04:23 +0800803 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
804 (wsi->u.ws.rx_user_buffer_head++)] =
Andy Greenb5b23192013-02-11 17:13:32 +0800805 c ^ wsi->u.ws.frame_masking_nonce_04[
806 (wsi->u.ws.frame_mask_index++) & 3];
Andy Green4739e5c2011-01-22 12:51:57 +0000807
Andy Green623a98d2013-01-21 11:04:23 +0800808 if (--wsi->u.ws.rx_packet_length == 0) {
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800809 /* spill because we have the whole frame */
Andy Green4739e5c2011-01-22 12:51:57 +0000810 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
811 goto spill;
812 }
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800813
814 /*
815 * if there's no protocol max frame size given, we are
816 * supposed to default to LWS_MAX_SOCKET_IO_BUF
817 */
818
819 if (!wsi->protocol->rx_buffer_size &&
820 wsi->u.ws.rx_user_buffer_head !=
821 LWS_MAX_SOCKET_IO_BUF)
Andy Green4739e5c2011-01-22 12:51:57 +0000822 break;
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800823 else
824 if (wsi->protocol->rx_buffer_size &&
825 wsi->u.ws.rx_user_buffer_head !=
826 wsi->protocol->rx_buffer_size)
827 break;
828
829 /* spill because we filled our rx buffer */
Andy Green4739e5c2011-01-22 12:51:57 +0000830spill:
831 /*
832 * is this frame a control packet we should take care of at this
833 * layer? If so service it and hide it from the user callback
834 */
835
Andy Green43db0452013-01-10 19:50:35 +0800836 lwsl_parser("spill on %s\n", wsi->protocol->name);
Andy Greena41314f2011-05-23 10:00:03 +0100837
Andy Green623a98d2013-01-21 11:04:23 +0800838 switch (wsi->u.ws.opcode) {
Andy Green23545db2011-04-24 06:19:22 +0100839 case LWS_WS_OPCODE_07__CLOSE:
Andy Greenda527df2011-03-07 07:08:12 +0000840 /* is this an acknowledgement of our close? */
841 if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
842 /*
843 * fine he has told us he is closing too, let's
844 * finish our close
845 */
Andy Green43db0452013-01-10 19:50:35 +0800846 lwsl_parser("seen client close ack\n");
Andy Greenda527df2011-03-07 07:08:12 +0000847 return -1;
848 }
Andy Green43db0452013-01-10 19:50:35 +0800849 lwsl_parser("server sees client close packet\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000850 /* parrot the close packet payload back */
851 n = libwebsocket_write(wsi, (unsigned char *)
Andy Greenb5b23192013-02-11 17:13:32 +0800852 &wsi->u.ws.rx_user_buffer[
853 LWS_SEND_BUFFER_PRE_PADDING],
854 wsi->u.ws.rx_user_buffer_head,
855 LWS_WRITE_CLOSE);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800856 if (n < 0)
Andy Green0303db42013-01-17 14:46:43 +0800857 lwsl_info("write of close ack failed %d\n", n);
Andy Green5e1fa172011-02-10 09:07:05 +0000858 wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
Andy Green4739e5c2011-01-22 12:51:57 +0000859 /* close the connection */
860 return -1;
861
Andy Green23545db2011-04-24 06:19:22 +0100862 case LWS_WS_OPCODE_07__PING:
Andy Greenb5b23192013-02-11 17:13:32 +0800863 lwsl_info("received %d byte ping, sending pong\n",
864 wsi->u.ws.rx_user_buffer_head);
865 lwsl_hexdump(&wsi->u.ws.rx_user_buffer[
866 LWS_SEND_BUFFER_PRE_PADDING],
867 wsi->u.ws.rx_user_buffer_head);
Andy Green5e1fa172011-02-10 09:07:05 +0000868 /* parrot the ping packet payload back as a pong */
Andy Green4739e5c2011-01-22 12:51:57 +0000869 n = libwebsocket_write(wsi, (unsigned char *)
Andy Greenb5b23192013-02-11 17:13:32 +0800870 &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
871 wsi->u.ws.rx_user_buffer_head, LWS_WRITE_PONG);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800872 if (n < 0)
873 return -1;
Andy Greena6cbece2011-01-27 20:06:03 +0000874 /* ... then just drop it */
Andy Green623a98d2013-01-21 11:04:23 +0800875 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena6cbece2011-01-27 20:06:03 +0000876 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000877
Andy Green23545db2011-04-24 06:19:22 +0100878 case LWS_WS_OPCODE_07__PONG:
Andy Green4739e5c2011-01-22 12:51:57 +0000879 /* ... then just drop it */
Andy Green623a98d2013-01-21 11:04:23 +0800880 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000881 return 0;
882
Andy Greena41314f2011-05-23 10:00:03 +0100883 case LWS_WS_OPCODE_07__TEXT_FRAME:
884 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Green2fd3f2f2013-01-18 09:49:20 +0800885 case LWS_WS_OPCODE_07__CONTINUATION:
Andy Green4739e5c2011-01-22 12:51:57 +0000886 break;
Andy Greena41314f2011-05-23 10:00:03 +0100887
888 default:
Andy Green3182ece2013-01-20 17:08:31 +0800889#ifndef LWS_NO_EXTENSIONS
Andy Greenb5b23192013-02-11 17:13:32 +0800890 lwsl_parser("passing opc %x up to exts\n",
891 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100892
893 /*
894 * It's something special we can't understand here.
895 * Pass the payload up to the extension's parsing
896 * state machine.
897 */
898
Andy Green623a98d2013-01-21 11:04:23 +0800899 eff_buf.token = &wsi->u.ws.rx_user_buffer[
Andy Greena41314f2011-05-23 10:00:03 +0100900 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800901 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Greena41314f2011-05-23 10:00:03 +0100902
903 handled = 0;
904 for (n = 0; n < wsi->count_active_extensions; n++) {
905 m = wsi->active_extensions[n]->callback(
906 wsi->protocol->owning_server,
907 wsi->active_extensions[n], wsi,
908 LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
909 wsi->active_extensions_user[n],
910 &eff_buf, 0);
911 if (m)
912 handled = 1;
913 }
914
Andy Green25a56b02011-09-25 08:47:57 +0100915 if (!handled)
Andy Green3182ece2013-01-20 17:08:31 +0800916#endif
Andy Greenb5b23192013-02-11 17:13:32 +0800917 lwsl_ext("ext opc opcode 0x%x unknown\n",
918 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100919
Andy Green623a98d2013-01-21 11:04:23 +0800920 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena41314f2011-05-23 10:00:03 +0100921 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000922 }
923
924 /*
925 * No it's real payload, pass it up to the user callback.
926 * It's nicely buffered with the pre-padding taken care of
927 * so it can be sent straight out again using libwebsocket_write
928 */
929
Andy Green623a98d2013-01-21 11:04:23 +0800930 eff_buf.token = &wsi->u.ws.rx_user_buffer[
David Galeanoe2cf9922013-01-09 18:06:55 +0800931 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800932 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Green3182ece2013-01-20 17:08:31 +0800933#ifndef LWS_NO_EXTENSIONS
David Galeanoe2cf9922013-01-09 18:06:55 +0800934 for (n = 0; n < wsi->count_active_extensions; n++) {
935 m = wsi->active_extensions[n]->callback(
936 wsi->protocol->owning_server,
937 wsi->active_extensions[n], wsi,
938 LWS_EXT_CALLBACK_PAYLOAD_RX,
939 wsi->active_extensions_user[n],
940 &eff_buf, 0);
941 if (m < 0) {
Andy Green43db0452013-01-10 19:50:35 +0800942 lwsl_ext(
Andy Greenb5b23192013-02-11 17:13:32 +0800943 "Extension '%s' failed to handle payload!\n",
944 wsi->active_extensions[n]->name);
David Galeanoe2cf9922013-01-09 18:06:55 +0800945 return -1;
946 }
947 }
Andy Green3182ece2013-01-20 17:08:31 +0800948#endif
David Galeanoe2cf9922013-01-09 18:06:55 +0800949 if (eff_buf.token_len > 0) {
Andy Greenaedc9532013-02-10 21:21:24 +0800950 eff_buf.token[eff_buf.token_len] = '\0';
David Galeanoe2cf9922013-01-09 18:06:55 +0800951
Andy Greenaedc9532013-02-10 21:21:24 +0800952 if (wsi->protocol->callback)
Andy Greenb5b23192013-02-11 17:13:32 +0800953 ret = user_callback_handle_rxflow(
954 wsi->protocol->callback,
955 wsi->protocol->owning_server,
956 wsi, LWS_CALLBACK_RECEIVE,
957 wsi->user_space,
958 eff_buf.token,
959 eff_buf.token_len);
David Galeanoe2cf9922013-01-09 18:06:55 +0800960 else
Andy Greenf7609e92013-01-14 13:10:55 +0800961 lwsl_err("No callback on payload spill!\n");
David Galeanoe2cf9922013-01-09 18:06:55 +0800962 }
Andy Greena41314f2011-05-23 10:00:03 +0100963
Andy Green623a98d2013-01-21 11:04:23 +0800964 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000965 break;
966 }
967
Andy Greenaedc9532013-02-10 21:21:24 +0800968 return ret;
Andy Green23545db2011-04-24 06:19:22 +0100969
970illegal_ctl_length:
971
Andy Greenb5b23192013-02-11 17:13:32 +0800972 lwsl_warn("Control frame with xtended length is illegal\n");
Andy Green23545db2011-04-24 06:19:22 +0100973 /* kill the connection */
974 return -1;
Andy Green4739e5c2011-01-22 12:51:57 +0000975}
976
977
Andy Green7c212cc2010-11-08 20:20:42 +0000978int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
979 unsigned char *buf, size_t len)
980{
Andy Greenca0a1292013-03-16 11:24:23 +0800981 size_t n = 0;
Andy Green706961d2013-01-17 16:50:35 +0800982 int m;
Andy Green7c212cc2010-11-08 20:20:42 +0000983
Andy Green3182ece2013-01-20 17:08:31 +0800984#if 0
Andy Green43db0452013-01-10 19:50:35 +0800985 lwsl_parser("received %d byte packet\n", (int)len);
Andy Green0303db42013-01-17 14:46:43 +0800986 lwsl_hexdump(buf, len);
Andy Greenab7d9332010-11-11 13:19:19 +0000987#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000988
Andy Green7c212cc2010-11-08 20:20:42 +0000989 /* let the rx protocol state machine have as much as it needs */
Andy Greene77ddd82010-11-13 10:03:47 +0000990
Andy Green706961d2013-01-17 16:50:35 +0800991 while (n < len) {
Andy Greenca0a1292013-03-16 11:24:23 +0800992 /*
993 * we were accepting input but now we stopped doing so
994 */
995 if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) {
996 /* his RX is flowcontrolled, don't send remaining now */
Andy Greenb5b23192013-02-11 17:13:32 +0800997 if (!wsi->u.ws.rxflow_buffer) {
998 /* a new rxflow, buffer it and warn caller */
999 lwsl_info("new rxflow input buffer len %d\n",
1000 len - n);
1001 wsi->u.ws.rxflow_buffer =
1002 (unsigned char *)malloc(len - n);
Andy Green623a98d2013-01-21 11:04:23 +08001003 wsi->u.ws.rxflow_len = len - n;
1004 wsi->u.ws.rxflow_pos = 0;
Andy Greenb5b23192013-02-11 17:13:32 +08001005 memcpy(wsi->u.ws.rxflow_buffer,
1006 buf + n, len - n);
Andy Greenca0a1292013-03-16 11:24:23 +08001007 } else
Andy Greenb5b23192013-02-11 17:13:32 +08001008 /* rxflow while we were spilling prev rxflow */
Andy Green98ba9e02013-03-23 09:44:47 +08001009 lwsl_info("stalling in existing rxflow buf\n");
Andy Greenca0a1292013-03-16 11:24:23 +08001010
Andy Green706961d2013-01-17 16:50:35 +08001011 return 1;
1012 }
Andy Greenca0a1292013-03-16 11:24:23 +08001013
1014 /* account for what we're using in rxflow buffer */
1015 if (wsi->u.ws.rxflow_buffer)
1016 wsi->u.ws.rxflow_pos++;
1017
1018 /* process the byte */
1019 m = libwebsocket_rx_sm(wsi, buf[n++]);
Andy Green706961d2013-01-17 16:50:35 +08001020 if (m < 0)
Andy Green7c212cc2010-11-08 20:20:42 +00001021 return -1;
Andy Green706961d2013-01-17 16:50:35 +08001022 }
Andy Greene77ddd82010-11-13 10:03:47 +00001023
Andy Green4739e5c2011-01-22 12:51:57 +00001024 return 0;
Andy Green7c212cc2010-11-08 20:20:42 +00001025}
1026
1027
Andy Green38e57bb2011-01-19 12:20:27 +00001028/**
1029 * libwebsockets_remaining_packet_payload() - Bytes to come before "overall"
Andy Green6964bb52011-01-23 16:50:33 +00001030 * rx packet is complete
Andy Green38e57bb2011-01-19 12:20:27 +00001031 * @wsi: Websocket instance (available from user callback)
1032 *
1033 * This function is intended to be called from the callback if the
1034 * user code is interested in "complete packets" from the client.
1035 * libwebsockets just passes through payload as it comes and issues a buffer
1036 * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE
1037 * callback handler can use this API to find out if the buffer it has just
1038 * been given is the last piece of a "complete packet" from the client --
1039 * when that is the case libwebsockets_remaining_packet_payload() will return
1040 * 0.
1041 *
1042 * Many protocols won't care becuse their packets are always small.
1043 */
1044
Peter Pentchev9a4fef72013-03-30 09:52:21 +08001045LWS_VISIBLE size_t
Andy Green38e57bb2011-01-19 12:20:27 +00001046libwebsockets_remaining_packet_payload(struct libwebsocket *wsi)
1047{
Andy Green623a98d2013-01-21 11:04:23 +08001048 return wsi->u.ws.rx_packet_length;
Andy Green38e57bb2011-01-19 12:20:27 +00001049}