blob: cc2e2d521677cd7099a0d9bff673ff18506ad0e3 [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
Andy Green6d1fcb72013-01-18 01:55:48 +080024unsigned char lextable[] = {
Andy Greencc13c6f2013-11-09 10:09:09 +080025 #include "lextable.h"
Andy Green6d1fcb72013-01-18 01:55:48 +080026};
27
Andy Greenbbc5c072014-03-09 11:49:21 +080028#define FAIL_CHAR 0x08
29
Andy Green6d1fcb72013-01-18 01:55:48 +080030int lextable_decode(int pos, char c)
31{
Andy Greenbbc5c072014-03-09 11:49:21 +080032
33 c = tolower(c);
34
35 while (1) {
36 if (lextable[pos] & (1 << 7)) { /* 1-byte, fail on mismatch */
37 if ((lextable[pos] & 0x7f) != c)
38 return -1;
39 /* fall thru */
40 pos++;
41 if (lextable[pos] == FAIL_CHAR)
42 return -1;
Andy Green6d1fcb72013-01-18 01:55:48 +080043 return pos;
Andy Greenbbc5c072014-03-09 11:49:21 +080044 }
Andy Greenf012f752014-08-22 19:38:17 +080045
46 if (lextable[pos] == FAIL_CHAR)
47 return -1;
48
Andy Green2c24ec02014-04-02 19:45:42 +080049 /* b7 = 0, end or 3-byte */
50 if (lextable[pos] < FAIL_CHAR) /* terminal marker */
51 return pos;
52
53 if (lextable[pos] == c) /* goto */
54 return pos + (lextable[pos + 1]) +
55 (lextable[pos + 2] << 8);
56 /* fall thru goto */
57 pos += 3;
58 /* continue */
Andy Green6d1fcb72013-01-18 01:55:48 +080059 }
Andy Green6d1fcb72013-01-18 01:55:48 +080060}
61
Andy Green16ab3182013-02-10 18:02:31 +080062int lws_allocate_header_table(struct libwebsocket *wsi)
63{
Andrew Canaday03f0cea2014-11-07 15:28:35 -050064 /* Be sure to free any existing header data to avoid mem leak: */
65 lws_free_header_table(wsi);
Alejandro Mery6ff28242014-12-04 23:59:35 +010066 wsi->u.hdr.ah = lws_malloc(sizeof(*wsi->u.hdr.ah));
Andy Green16ab3182013-02-10 18:02:31 +080067 if (wsi->u.hdr.ah == NULL) {
68 lwsl_err("Out of memory\n");
69 return -1;
70 }
Andy Greenb5b23192013-02-11 17:13:32 +080071 memset(wsi->u.hdr.ah->frag_index, 0, sizeof(wsi->u.hdr.ah->frag_index));
Andy Green16ab3182013-02-10 18:02:31 +080072 wsi->u.hdr.ah->next_frag_index = 0;
73 wsi->u.hdr.ah->pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +080074
Andy Green16ab3182013-02-10 18:02:31 +080075 return 0;
76}
77
Andrew Canaday37718812014-11-07 11:20:59 +080078int lws_free_header_table(struct libwebsocket *wsi)
79{
Alejandro Meryac3ec392014-12-05 00:09:20 +010080 lws_free2(wsi->u.hdr.ah);
81 wsi->u.hdr.ah = NULL;
Alejandro Mery6ff28242014-12-04 23:59:35 +010082 return 0;
Andrew Canaday37718812014-11-07 11:20:59 +080083};
84
Peter Pentchev9a4fef72013-03-30 09:52:21 +080085LWS_VISIBLE int lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +080086{
87 int n;
88 int len = 0;
89
90 n = wsi->u.hdr.ah->frag_index[h];
Andy Green2c24ec02014-04-02 19:45:42 +080091 if (!n)
Andy Green16ab3182013-02-10 18:02:31 +080092 return 0;
Andy Green16ab3182013-02-10 18:02:31 +080093 do {
94 len += wsi->u.hdr.ah->frags[n].len;
95 n = wsi->u.hdr.ah->frags[n].next_frag_index;
96 } while (n);
97
98 return len;
99}
100
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800101LWS_VISIBLE int lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len,
Andy Greenb5b23192013-02-11 17:13:32 +0800102 enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800103{
104 int toklen = lws_hdr_total_length(wsi, h);
105 int n;
106
107 if (toklen >= len)
108 return -1;
109
110 n = wsi->u.hdr.ah->frag_index[h];
Andy Green2c24ec02014-04-02 19:45:42 +0800111 if (!n)
Andy Green16ab3182013-02-10 18:02:31 +0800112 return 0;
113
114 do {
Andy Greenb5b23192013-02-11 17:13:32 +0800115 strcpy(dest,
116 &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]);
Andy Green16ab3182013-02-10 18:02:31 +0800117 dest += wsi->u.hdr.ah->frags[n].len;
118 n = wsi->u.hdr.ah->frags[n].next_frag_index;
119 } while (n);
120
121 return toklen;
122}
123
Andy Greenb5b23192013-02-11 17:13:32 +0800124char *lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800125{
126 int n;
127
128 n = wsi->u.hdr.ah->frag_index[h];
129 if (!n)
130 return NULL;
131
132 return &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset];
133}
Andy Green6d1fcb72013-01-18 01:55:48 +0800134
Andy Greenb5b23192013-02-11 17:13:32 +0800135int lws_hdr_simple_create(struct libwebsocket *wsi,
136 enum lws_token_indexes h, const char *s)
Andy Greene77fb802013-02-11 13:04:45 +0800137{
138 wsi->u.hdr.ah->next_frag_index++;
Andy Greenb5b23192013-02-11 17:13:32 +0800139 if (wsi->u.hdr.ah->next_frag_index ==
140 sizeof(wsi->u.hdr.ah->frags) / sizeof(wsi->u.hdr.ah->frags[0])) {
141 lwsl_warn("More hdr frags than we can deal with, dropping\n");
Andy Greene77fb802013-02-11 13:04:45 +0800142 return -1;
143 }
144
145 wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->next_frag_index;
146
Andy Greenb5b23192013-02-11 17:13:32 +0800147 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
148 wsi->u.hdr.ah->pos;
Andy Greene77fb802013-02-11 13:04:45 +0800149 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
Andy Greenb5b23192013-02-11 17:13:32 +0800150 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].next_frag_index =
151 0;
Andy Greene77fb802013-02-11 13:04:45 +0800152
153 do {
Andy Greenb5b23192013-02-11 17:13:32 +0800154 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
Andy Greene77fb802013-02-11 13:04:45 +0800155 lwsl_err("Ran out of header data space\n");
156 return -1;
157 }
158 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s;
159 if (*s)
Andy Greenb5b23192013-02-11 17:13:32 +0800160 wsi->u.hdr.ah->frags[
161 wsi->u.hdr.ah->next_frag_index].len++;
Andy Greene77fb802013-02-11 13:04:45 +0800162 } while (*s++);
163
164 return 0;
165}
166
Andy Green2a5774e2015-03-30 18:56:52 +0800167static signed char char_to_hex(const char c)
Andy Greenb1a9e502013-11-10 15:15:21 +0800168{
169 if (c >= '0' && c <= '9')
170 return c - '0';
171
172 if (c >= 'a' && c <= 'f')
173 return c - 'a' + 10;
174
175 if (c >= 'A' && c <= 'F')
176 return c - 'A' + 10;
177
178 return -1;
179}
180
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400181static int issue_char(struct libwebsocket *wsi, unsigned char c)
Andy Greenb1a9e502013-11-10 15:15:21 +0800182{
183 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
184 lwsl_warn("excessive header content\n");
185 return -1;
186 }
Andrew Canaday74b4a652014-06-29 00:25:19 -0400187
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400188 if( wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len >=
189 wsi->u.hdr.current_token_limit) {
Andrew Canaday74b4a652014-06-29 00:25:19 -0400190 lwsl_warn("header %i exceeds limit\n", wsi->u.hdr.parser_state);
191 return 1;
192 };
193
Andy Greenb1a9e502013-11-10 15:15:21 +0800194 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c;
195 if (c)
196 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
197
198 return 0;
199}
200
Andrew Canaday74b4a652014-06-29 00:25:19 -0400201int libwebsocket_parse(
202 struct libwebsocket_context *context,
203 struct libwebsocket *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000204{
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800205 static const unsigned char methods[] = {
206 WSI_TOKEN_GET_URI,
207 WSI_TOKEN_POST_URI,
208 WSI_TOKEN_OPTIONS_URI,
209 WSI_TOKEN_PUT_URI,
210 WSI_TOKEN_PATCH_URI,
211 WSI_TOKEN_DELETE_URI,
212 };
213 int n, m;
Andy Green7c212cc2010-11-08 20:20:42 +0000214
Andy Green623a98d2013-01-21 11:04:23 +0800215 switch (wsi->u.hdr.parser_state) {
Andy Greenb08cb502014-09-30 16:33:56 +0800216 default:
Andy Greena41314f2011-05-23 10:00:03 +0100217
Andy Greenb5b23192013-02-11 17:13:32 +0800218 lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c);
Andy Green7c212cc2010-11-08 20:20:42 +0000219
220 /* collect into malloc'd buffers */
Andy Green16ab3182013-02-10 18:02:31 +0800221 /* optional initial space swallow */
Andy Greenb5b23192013-02-11 17:13:32 +0800222 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->frag_index[
223 wsi->u.hdr.parser_state]].len && c == ' ')
Andy Green7c212cc2010-11-08 20:20:42 +0000224 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000225
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800226 for (m = 0; m < ARRAY_SIZE(methods); m++)
227 if (wsi->u.hdr.parser_state == methods[m])
228 break;
229 if (m == ARRAY_SIZE(methods))
230 /* it was not any of the methods */
Andy Greenb1a9e502013-11-10 15:15:21 +0800231 goto check_eol;
232
233 /* special URI processing... end at space */
234
235 if (c == ' ') {
236 /* enforce starting with / */
237 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len)
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400238 if (issue_char(wsi, '/') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800239 return -1;
Andrew Canadayafe26cf2014-07-13 01:07:36 -0400240
241 /* begin parsing HTTP version: */
242 if (issue_char(wsi, '\0') < 0)
243 return -1;
244 wsi->u.hdr.parser_state = WSI_TOKEN_HTTP;
245 goto start_fragment;
Andy Green7c212cc2010-11-08 20:20:42 +0000246 }
247
Andy Greenb1a9e502013-11-10 15:15:21 +0800248 /* special URI processing... convert %xx */
249
250 switch (wsi->u.hdr.ues) {
251 case URIES_IDLE:
252 if (c == '%') {
253 wsi->u.hdr.ues = URIES_SEEN_PERCENT;
254 goto swallow;
255 }
256 break;
257 case URIES_SEEN_PERCENT:
258 if (char_to_hex(c) < 0) {
259 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400260 if (issue_char(wsi, '%') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800261 return -1;
262 wsi->u.hdr.ues = URIES_IDLE;
263 /* continue on to assess c */
264 break;
265 }
266 wsi->u.hdr.esc_stash = c;
267 wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
Andy Green6f429102013-11-11 06:14:52 +0800268 goto swallow;
Andy Greenb1a9e502013-11-10 15:15:21 +0800269
270 case URIES_SEEN_PERCENT_H1:
271 if (char_to_hex(c) < 0) {
272 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400273 issue_char(wsi, '%');
Andy Greenb1a9e502013-11-10 15:15:21 +0800274 wsi->u.hdr.ues = URIES_IDLE;
275 /* regurgitate + assess */
Andrew Canaday74b4a652014-06-29 00:25:19 -0400276 if (libwebsocket_parse(context, wsi, wsi->u.hdr.esc_stash) < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800277 return -1;
278 /* continue on to assess c */
279 break;
280 }
281 c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
282 char_to_hex(c);
Andy Green6f429102013-11-11 06:14:52 +0800283 wsi->u.hdr.ues = URIES_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800284 break;
285 }
286
287 /*
288 * special URI processing...
Andy Green6f429102013-11-11 06:14:52 +0800289 * convert /.. or /... or /../ etc to /
290 * convert /./ to /
Andy Greenb1a9e502013-11-10 15:15:21 +0800291 * convert // or /// etc to /
292 * leave /.dir or whatever alone
293 */
294
295 switch (wsi->u.hdr.ups) {
296 case URIPS_IDLE:
297 /* issue the first / always */
298 if (c == '/')
299 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
300 break;
301 case URIPS_SEEN_SLASH:
302 /* swallow subsequent slashes */
303 if (c == '/')
304 goto swallow;
305 /* track and swallow the first . after / */
306 if (c == '.') {
307 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT;
308 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800309 }
310 wsi->u.hdr.ups = URIPS_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800311 break;
312 case URIPS_SEEN_SLASH_DOT:
313 /* swallow second . */
314 if (c == '.') {
Andy Greend3f68732013-11-13 06:53:21 +0800315 /*
316 * back up one dir level if possible
317 * safe against header fragmentation because
318 * the method URI can only be in 1 fragment
319 */
320 if (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 2) {
321 wsi->u.hdr.ah->pos--;
322 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
323 do {
324 wsi->u.hdr.ah->pos--;
325 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
326 } while (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 1 &&
327 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos] != '/');
328 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800329 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
330 goto swallow;
331 }
Andy Green6f429102013-11-11 06:14:52 +0800332 /* change /./ to / */
333 if (c == '/') {
334 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
335 goto swallow;
336 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800337 /* it was like /.dir ... regurgitate the . */
338 wsi->u.hdr.ups = URIPS_IDLE;
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400339 issue_char(wsi, '.');
Andy Greenb1a9e502013-11-10 15:15:21 +0800340 break;
341
342 case URIPS_SEEN_SLASH_DOT_DOT:
343 /* swallow prior .. chars and any subsequent . */
344 if (c == '.')
345 goto swallow;
Andy Green6f429102013-11-11 06:14:52 +0800346 /* last issued was /, so another / == // */
347 if (c == '/')
348 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800349 /* last we issued was / so SEEN_SLASH */
350 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
Andy Greenb1a9e502013-11-10 15:15:21 +0800351 break;
Andy Green1e3f7b82013-11-13 07:45:17 +0800352 case URIPS_ARGUMENTS:
353 /* leave them alone */
354 break;
Andy Greenb1a9e502013-11-10 15:15:21 +0800355 }
356
Andy Green1e3f7b82013-11-13 07:45:17 +0800357 if (c == '?') { /* start of URI arguments */
358 /* seal off uri header */
359 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0';
360
361 /* move to using WSI_TOKEN_HTTP_URI_ARGS */
362 wsi->u.hdr.ah->next_frag_index++;
363 wsi->u.hdr.ah->frags[
364 wsi->u.hdr.ah->next_frag_index].offset =
365 wsi->u.hdr.ah->pos;
366 wsi->u.hdr.ah->frags[
367 wsi->u.hdr.ah->next_frag_index].len = 0;
368 wsi->u.hdr.ah->frags[
369 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
370
371 wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] =
372 wsi->u.hdr.ah->next_frag_index;
373
374 /* defeat normal uri path processing */
375 wsi->u.hdr.ups = URIPS_ARGUMENTS;
376 goto swallow;
377 }
378
Andrew Canaday991f1cd2014-07-19 06:58:53 +0800379check_eol:
380
381 /* bail at EOL */
382 if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
383 c == '\x0d') {
384 c = '\0';
385 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
386 lwsl_parser("*\n");
387 }
388
Andy Green4b812fe2014-08-19 18:34:31 +0800389 n = issue_char(wsi, c);
390 if (n < 0)
391 return -1;
392 if (n > 0)
393 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
394
Andy Greenb1a9e502013-11-10 15:15:21 +0800395swallow:
Andy Greend1b11e32011-01-18 15:39:02 +0000396 /* per-protocol end of headers management */
Andy Greene77ddd82010-11-13 10:03:47 +0000397
Andy Green16ab3182013-02-10 18:02:31 +0800398 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
399 goto set_parsing_complete;
Andy Greena41314f2011-05-23 10:00:03 +0100400 break;
401
Andy Green7c212cc2010-11-08 20:20:42 +0000402 /* collecting and checking a name part */
403 case WSI_TOKEN_NAME_PART:
Andy Green8fb338f2015-04-07 08:19:30 +0800404 lwsl_parser("WSI_TOKEN_NAME_PART '%c' (mode=%d)\n", c, wsi->mode);
Andy Green7c212cc2010-11-08 20:20:42 +0000405
Andy Greenb5b23192013-02-11 17:13:32 +0800406 wsi->u.hdr.lextable_pos =
407 lextable_decode(wsi->u.hdr.lextable_pos, c);
Andy Green8fb338f2015-04-07 08:19:30 +0800408 /*
409 * Server needs to look out for unknown methods...
410 */
411 if (wsi->u.hdr.lextable_pos < 0 &&
412 wsi->mode == LWS_CONNMODE_HTTP_SERVING) {
Andy Greene4dffc92013-02-04 09:24:18 +0800413 /* this is not a header we know about */
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800414 for (m = 0; m < ARRAY_SIZE(methods); m++)
415 if (wsi->u.hdr.ah->frag_index[methods[m]]) {
416 /*
417 * already had the method, no idea what
Andy Green8fb338f2015-04-07 08:19:30 +0800418 * this crap from the client is, ignore
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800419 */
420 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
421 break;
422 }
Andy Green3ee9b312013-02-12 12:52:39 +0800423 /*
Andy Green8fb338f2015-04-07 08:19:30 +0800424 * hm it's an unknown http method from a client in fact,
Andy Green3ee9b312013-02-12 12:52:39 +0800425 * treat as dangerous
426 */
Drew Noakes2121e8a2015-01-30 12:04:43 +0000427 if (m == ARRAY_SIZE(methods)) {
428 lwsl_info("Unknown method - dropping\n");
429 return -1;
430 }
431 break;
Andy Greene4dffc92013-02-04 09:24:18 +0800432 }
Andy Green8fb338f2015-04-07 08:19:30 +0800433 /*
434 * ...otherwise for a client, let him ignore unknown headers
435 * coming from the server
436 */
437 if (wsi->u.hdr.lextable_pos < 0) {
438 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
439 break;
440 }
441
Andy Greenbbc5c072014-03-09 11:49:21 +0800442 if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) {
Andy Greene4dffc92013-02-04 09:24:18 +0800443 /* terminal state */
444
Andy Green59800b72014-11-30 12:36:09 +0800445 n = ((unsigned int)lextable[wsi->u.hdr.lextable_pos] << 8) |
446 lextable[wsi->u.hdr.lextable_pos + 1];
Andy Green6d1fcb72013-01-18 01:55:48 +0800447
Andy Greencc7cb682013-02-18 10:22:42 +0800448 lwsl_parser("known hdr %d\n", n);
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800449 for (m = 0; m < ARRAY_SIZE(methods); m++)
450 if (n == methods[m] &&
451 wsi->u.hdr.ah->frag_index[
452 methods[m]]) {
453 lwsl_warn("Duplicated method\n");
454 return -1;
455 }
Andy Green94f94652013-02-12 13:10:19 +0800456
Andy Greenfd963302012-04-03 17:02:20 +0200457 /*
458 * WSORIGIN is protocol equiv to ORIGIN,
459 * JWebSocket likes to send it, map to ORIGIN
460 */
461 if (n == WSI_TOKEN_SWORIGIN)
462 n = WSI_TOKEN_ORIGIN;
463
Andy Green16ab3182013-02-10 18:02:31 +0800464 wsi->u.hdr.parser_state = (enum lws_token_indexes)
465 (WSI_TOKEN_GET_URI + n);
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400466
Andy Greenf012f752014-08-22 19:38:17 +0800467 if (context->token_limits)
468 wsi->u.hdr.current_token_limit =
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400469 context->token_limits->token_limit[wsi->u.hdr.parser_state];
Andy Greenf012f752014-08-22 19:38:17 +0800470 else
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400471 wsi->u.hdr.current_token_limit = sizeof(wsi->u.hdr.ah->data);
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400472
Andy Green16ab3182013-02-10 18:02:31 +0800473 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
474 goto set_parsing_complete;
Andy Green6964bb52011-01-23 16:50:33 +0000475
Andy Green16ab3182013-02-10 18:02:31 +0800476 goto start_fragment;
477 }
478 break;
Nick Dowell30592632012-04-05 10:31:48 +0800479
Andy Green16ab3182013-02-10 18:02:31 +0800480start_fragment:
481 wsi->u.hdr.ah->next_frag_index++;
Andy Greenb5b23192013-02-11 17:13:32 +0800482 if (wsi->u.hdr.ah->next_frag_index ==
483 sizeof(wsi->u.hdr.ah->frags) /
484 sizeof(wsi->u.hdr.ah->frags[0])) {
485 lwsl_warn("More hdr frags than we can deal with\n");
Andy Green16ab3182013-02-10 18:02:31 +0800486 return -1;
Andy Green7c212cc2010-11-08 20:20:42 +0000487 }
488
Andy Greenb5b23192013-02-11 17:13:32 +0800489 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
490 wsi->u.hdr.ah->pos;
Andy Green16ab3182013-02-10 18:02:31 +0800491 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
Andy Greenb5b23192013-02-11 17:13:32 +0800492 wsi->u.hdr.ah->frags[
493 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800494
495 n = wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state];
496 if (!n) { /* first fragment */
497 wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state] =
498 wsi->u.hdr.ah->next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800499 break;
500 }
501 /* continuation */
502 while (wsi->u.hdr.ah->frags[n].next_frag_index)
Andy Green16ab3182013-02-10 18:02:31 +0800503 n = wsi->u.hdr.ah->frags[n].next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800504 wsi->u.hdr.ah->frags[n].next_frag_index =
Andy Green16ab3182013-02-10 18:02:31 +0800505 wsi->u.hdr.ah->next_frag_index;
506
Andy Greencc13c6f2013-11-09 10:09:09 +0800507 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
508 lwsl_warn("excessive header content\n");
509 return -1;
Andy Green2b57a342013-02-06 15:15:25 +0900510 }
Andy Green7c212cc2010-11-08 20:20:42 +0000511
Andy Greencc13c6f2013-11-09 10:09:09 +0800512 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = ' ';
513 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
Andy Greene4dffc92013-02-04 09:24:18 +0800514 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000515
Andy Green7c212cc2010-11-08 20:20:42 +0000516 /* skipping arg part of a name we didn't recognize */
517 case WSI_TOKEN_SKIPPING:
Andy Green43db0452013-01-10 19:50:35 +0800518 lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
kapejodce64fb02013-11-19 13:38:16 +0100519
Andy Green7c212cc2010-11-08 20:20:42 +0000520 if (c == '\x0d')
Andy Green623a98d2013-01-21 11:04:23 +0800521 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
Andy Green7c212cc2010-11-08 20:20:42 +0000522 break;
Andy Green177ca782013-02-04 09:09:19 +0800523
Andy Green7c212cc2010-11-08 20:20:42 +0000524 case WSI_TOKEN_SKIPPING_SAW_CR:
Andy Green43db0452013-01-10 19:50:35 +0800525 lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
Andy Green6d1fcb72013-01-18 01:55:48 +0800526 if (c == '\x0a') {
Andy Green623a98d2013-01-21 11:04:23 +0800527 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
528 wsi->u.hdr.lextable_pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +0800529 } else
Andy Green623a98d2013-01-21 11:04:23 +0800530 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
Andy Green7c212cc2010-11-08 20:20:42 +0000531 break;
532 /* we're done, ignore anything else */
kapejodce64fb02013-11-19 13:38:16 +0100533
Andy Green7c212cc2010-11-08 20:20:42 +0000534 case WSI_PARSING_COMPLETE:
Andy Green43db0452013-01-10 19:50:35 +0800535 lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000536 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000537 }
Andy Greene77ddd82010-11-13 10:03:47 +0000538
Andy Green7c212cc2010-11-08 20:20:42 +0000539 return 0;
Andy Green177ca782013-02-04 09:09:19 +0800540
541set_parsing_complete:
542
Andy Green16ab3182013-02-10 18:02:31 +0800543 if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800544 if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
Andy Green2b57a342013-02-06 15:15:25 +0900545 wsi->ietf_spec_revision =
Andy Green16ab3182013-02-10 18:02:31 +0800546 atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
Andy Green177ca782013-02-04 09:09:19 +0800547
Andy Greenb5b23192013-02-11 17:13:32 +0800548 lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision);
Andy Green2b57a342013-02-06 15:15:25 +0900549 }
Andy Green177ca782013-02-04 09:09:19 +0800550 wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE;
Andy Green224149a2013-02-11 21:43:41 +0800551 wsi->hdr_parsing_completed = 1;
Andy Green177ca782013-02-04 09:09:19 +0800552
553 return 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000554}
555
Andy Greenbfb051f2011-02-09 08:49:14 +0000556
Andy Green2fd3f2f2013-01-18 09:49:20 +0800557/**
558 * lws_frame_is_binary: true if the current frame was sent in binary mode
559 *
560 * @wsi: the connection we are inquiring about
561 *
562 * This is intended to be called from the LWS_CALLBACK_RECEIVE callback if
563 * it's interested to see if the frame it's dealing with was sent in binary
564 * mode.
565 */
566
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800567LWS_VISIBLE int lws_frame_is_binary(struct libwebsocket *wsi)
Andy Green2fd3f2f2013-01-18 09:49:20 +0800568{
Andy Green623a98d2013-01-21 11:04:23 +0800569 return wsi->u.ws.frame_is_binary;
Andy Green2fd3f2f2013-01-18 09:49:20 +0800570}
Andy Greenbfb051f2011-02-09 08:49:14 +0000571
Andy Greena41314f2011-05-23 10:00:03 +0100572int
573libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000574{
Andy Greena41314f2011-05-23 10:00:03 +0100575 struct lws_tokens eff_buf;
Andy Greenaedc9532013-02-10 21:21:24 +0800576 int ret = 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000577
578 switch (wsi->lws_rx_parse_state) {
579 case LWS_RXPS_NEW:
Andy Greene77ddd82010-11-13 10:03:47 +0000580
Andy Green7c212cc2010-11-08 20:20:42 +0000581 switch (wsi->ietf_spec_revision) {
Andy Greend85cb202011-09-25 09:32:54 +0100582 case 13:
Andy Green283d0a22011-04-24 05:46:23 +0100583 /*
584 * no prepended frame key any more
585 */
Andy Green623a98d2013-01-21 11:04:23 +0800586 wsi->u.ws.all_zero_nonce = 1;
Andy Green283d0a22011-04-24 05:46:23 +0100587 goto handle_first;
588
Andy Greenbfb051f2011-02-09 08:49:14 +0000589 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800590 lwsl_warn("lws_rx_sm: unknown spec version %d\n",
591 wsi->ietf_spec_revision);
Andy Greenbfb051f2011-02-09 08:49:14 +0000592 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000593 }
Andy Green6452f1e2010-11-11 09:22:22 +0000594 break;
Andy Green3e5eb782011-01-18 18:14:26 +0000595 case LWS_RXPS_04_MASK_NONCE_1:
Andy Green623a98d2013-01-21 11:04:23 +0800596 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000597 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800598 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000599 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2;
600 break;
601 case LWS_RXPS_04_MASK_NONCE_2:
Andy Green623a98d2013-01-21 11:04:23 +0800602 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000603 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800604 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000605 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3;
606 break;
607 case LWS_RXPS_04_MASK_NONCE_3:
Andy Green623a98d2013-01-21 11:04:23 +0800608 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000609 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800610 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000611
Andy Green3e5eb782011-01-18 18:14:26 +0000612 /*
613 * start from the zero'th byte in the XOR key buffer since
614 * this is the start of a frame with a new key
615 */
616
Andy Green623a98d2013-01-21 11:04:23 +0800617 wsi->u.ws.frame_mask_index = 0;
Andy Green6964bb52011-01-23 16:50:33 +0000618
Andy Green3e5eb782011-01-18 18:14:26 +0000619 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
620 break;
Andy Green38e57bb2011-01-19 12:20:27 +0000621
622 /*
623 * 04 logical framing from the spec (all this is masked when incoming
624 * and has to be unmasked)
625 *
626 * We ignore the possibility of extension data because we don't
627 * negotiate any extensions at the moment.
Andy Green6964bb52011-01-23 16:50:33 +0000628 *
Andy Green38e57bb2011-01-19 12:20:27 +0000629 * 0 1 2 3
630 * 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
631 * +-+-+-+-+-------+-+-------------+-------------------------------+
632 * |F|R|R|R| opcode|R| Payload len | Extended payload length |
633 * |I|S|S|S| (4) |S| (7) | (16/63) |
634 * |N|V|V|V| |V| | (if payload len==126/127) |
635 * | |1|2|3| |4| | |
636 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
637 * | Extended payload length continued, if payload len == 127 |
638 * + - - - - - - - - - - - - - - - +-------------------------------+
639 * | | Extension data |
640 * +-------------------------------+ - - - - - - - - - - - - - - - +
641 * : :
642 * +---------------------------------------------------------------+
643 * : Application data :
644 * +---------------------------------------------------------------+
645 *
646 * We pass payload through to userland as soon as we get it, ignoring
647 * FIN. It's up to userland to buffer it up if it wants to see a
648 * whole unfragmented block of the original size (which may be up to
649 * 2^63 long!)
650 */
651
652 case LWS_RXPS_04_FRAME_HDR_1:
Andy Green283d0a22011-04-24 05:46:23 +0100653handle_first:
654
Andy Green623a98d2013-01-21 11:04:23 +0800655 wsi->u.ws.opcode = c & 0xf;
656 wsi->u.ws.rsv = c & 0x70;
657 wsi->u.ws.final = !!((c >> 7) & 1);
Andy Green1bc12f92013-02-28 17:11:29 +0800658
Andy Green623a98d2013-01-21 11:04:23 +0800659 switch (wsi->u.ws.opcode) {
Andy Green10601c12013-01-19 10:39:35 +0800660 case LWS_WS_OPCODE_07__TEXT_FRAME:
Andy Green10601c12013-01-19 10:39:35 +0800661 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Greenb5b23192013-02-11 17:13:32 +0800662 wsi->u.ws.frame_is_binary =
663 wsi->u.ws.opcode == LWS_WS_OPCODE_07__BINARY_FRAME;
Andy Green10601c12013-01-19 10:39:35 +0800664 break;
665 }
Andy Green38e57bb2011-01-19 12:20:27 +0000666 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
667 break;
668
669 case LWS_RXPS_04_FRAME_HDR_LEN:
Andy Green38e57bb2011-01-19 12:20:27 +0000670
Andy Green623a98d2013-01-21 11:04:23 +0800671 wsi->u.ws.this_frame_masked = !!(c & 0x80);
Andy Green283d0a22011-04-24 05:46:23 +0100672
Andy Green5bf65782011-09-25 10:46:31 +0100673 switch (c & 0x7f) {
Andy Green38e57bb2011-01-19 12:20:27 +0000674 case 126:
675 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800676 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100677 goto illegal_ctl_length;
678
Andy Green38e57bb2011-01-19 12:20:27 +0000679 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
680 break;
681 case 127:
682 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800683 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100684 goto illegal_ctl_length;
685
Andy Green38e57bb2011-01-19 12:20:27 +0000686 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
687 break;
688 default:
Andy Green623a98d2013-01-21 11:04:23 +0800689 wsi->u.ws.rx_packet_length = c & 0x7f;
690 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100691 wsi->lws_rx_parse_state =
692 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
693 else
Andy Green8ea19552014-02-15 16:00:37 +0800694 if (wsi->u.ws.rx_packet_length)
695 wsi->lws_rx_parse_state =
Andy Green38e57bb2011-01-19 12:20:27 +0000696 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green8ea19552014-02-15 16:00:37 +0800697 else {
698 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
699 goto spill;
700 }
Andy Green38e57bb2011-01-19 12:20:27 +0000701 break;
702 }
703 break;
704
705 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
Andy Green623a98d2013-01-21 11:04:23 +0800706 wsi->u.ws.rx_packet_length = c << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000707 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
708 break;
709
710 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
Andy Green623a98d2013-01-21 11:04:23 +0800711 wsi->u.ws.rx_packet_length |= c;
712 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100713 wsi->lws_rx_parse_state =
714 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
715 else
716 wsi->lws_rx_parse_state =
717 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000718 break;
719
720 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
Andy Green38e57bb2011-01-19 12:20:27 +0000721 if (c & 0x80) {
Andy Green43db0452013-01-10 19:50:35 +0800722 lwsl_warn("b63 of length must be zero\n");
Andy Green38e57bb2011-01-19 12:20:27 +0000723 /* kill the connection */
724 return -1;
725 }
Andy Greenf55830d2011-01-27 06:45:53 +0000726#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800727 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
Andy Greenf55830d2011-01-27 06:45:53 +0000728#else
Andy Green623a98d2013-01-21 11:04:23 +0800729 wsi->u.ws.rx_packet_length = 0;
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_7;
732 break;
733
734 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
Andy Greenf55830d2011-01-27 06:45:53 +0000735#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800736 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
Andy Greenf55830d2011-01-27 06:45:53 +0000737#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000738 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
739 break;
740
741 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
Andy Greenf55830d2011-01-27 06:45:53 +0000742#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800743 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
Andy Greenf55830d2011-01-27 06:45:53 +0000744#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000745 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
746 break;
747
748 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
Andy Greenf55830d2011-01-27 06:45:53 +0000749#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800750 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
Andy Greenf55830d2011-01-27 06:45:53 +0000751#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000752 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
753 break;
754
755 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
Andy Green623a98d2013-01-21 11:04:23 +0800756 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
Andy Green38e57bb2011-01-19 12:20:27 +0000757 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
758 break;
759
760 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
Andy Green623a98d2013-01-21 11:04:23 +0800761 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
Andy Green38e57bb2011-01-19 12:20:27 +0000762 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
763 break;
764
765 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
Andy Green623a98d2013-01-21 11:04:23 +0800766 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000767 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
768 break;
769
770 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
Andy Green623a98d2013-01-21 11:04:23 +0800771 wsi->u.ws.rx_packet_length |= ((size_t)c);
772 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100773 wsi->lws_rx_parse_state =
774 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
775 else
776 wsi->lws_rx_parse_state =
777 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000778 break;
779
Andy Green283d0a22011-04-24 05:46:23 +0100780 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
Andy Green623a98d2013-01-21 11:04:23 +0800781 wsi->u.ws.frame_masking_nonce_04[0] = 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 = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
785 break;
786
787 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
Andy Green623a98d2013-01-21 11:04:23 +0800788 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100789 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800790 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100791 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
792 break;
793
794 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
Andy Green623a98d2013-01-21 11:04:23 +0800795 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100796 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800797 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100798 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
799 break;
800
801 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
Andy Green623a98d2013-01-21 11:04:23 +0800802 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100803 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800804 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100805 wsi->lws_rx_parse_state =
806 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green623a98d2013-01-21 11:04:23 +0800807 wsi->u.ws.frame_mask_index = 0;
Andy Green8ea19552014-02-15 16:00:37 +0800808 if (wsi->u.ws.rx_packet_length == 0) {
809 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
Andy Green1bc12f92013-02-28 17:11:29 +0800810 goto spill;
Andy Green8ea19552014-02-15 16:00:37 +0800811 }
Andy Green283d0a22011-04-24 05:46:23 +0100812 break;
813
814
Andy Green7c212cc2010-11-08 20:20:42 +0000815 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
Andy Green3182ece2013-01-20 17:08:31 +0800816
Andy Greencd838502014-11-30 12:53:27 +0800817 if (!wsi->u.ws.rx_user_buffer) {
Andy Green54495112013-02-06 21:10:16 +0900818 lwsl_err("NULL user buffer...\n");
Andy Greencd838502014-11-30 12:53:27 +0800819 return 1;
820 }
Andy Green54495112013-02-06 21:10:16 +0900821
Andy Green623a98d2013-01-21 11:04:23 +0800822 if (wsi->u.ws.all_zero_nonce)
823 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
824 (wsi->u.ws.rx_user_buffer_head++)] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000825 else
Andy Green623a98d2013-01-21 11:04:23 +0800826 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
827 (wsi->u.ws.rx_user_buffer_head++)] =
Andy Greenb5b23192013-02-11 17:13:32 +0800828 c ^ wsi->u.ws.frame_masking_nonce_04[
829 (wsi->u.ws.frame_mask_index++) & 3];
Andy Green4739e5c2011-01-22 12:51:57 +0000830
Andy Green623a98d2013-01-21 11:04:23 +0800831 if (--wsi->u.ws.rx_packet_length == 0) {
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800832 /* spill because we have the whole frame */
Andy Green4739e5c2011-01-22 12:51:57 +0000833 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
834 goto spill;
835 }
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800836
837 /*
838 * if there's no protocol max frame size given, we are
839 * supposed to default to LWS_MAX_SOCKET_IO_BUF
840 */
841
842 if (!wsi->protocol->rx_buffer_size &&
843 wsi->u.ws.rx_user_buffer_head !=
844 LWS_MAX_SOCKET_IO_BUF)
Andy Green4739e5c2011-01-22 12:51:57 +0000845 break;
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800846 else
847 if (wsi->protocol->rx_buffer_size &&
848 wsi->u.ws.rx_user_buffer_head !=
849 wsi->protocol->rx_buffer_size)
850 break;
851
852 /* spill because we filled our rx buffer */
Andy Green4739e5c2011-01-22 12:51:57 +0000853spill:
854 /*
855 * is this frame a control packet we should take care of at this
856 * layer? If so service it and hide it from the user callback
857 */
858
Andy Green43db0452013-01-10 19:50:35 +0800859 lwsl_parser("spill on %s\n", wsi->protocol->name);
Andy Greena41314f2011-05-23 10:00:03 +0100860
Andy Green623a98d2013-01-21 11:04:23 +0800861 switch (wsi->u.ws.opcode) {
Andy Green23545db2011-04-24 06:19:22 +0100862 case LWS_WS_OPCODE_07__CLOSE:
Andy Greenda527df2011-03-07 07:08:12 +0000863 /* is this an acknowledgement of our close? */
864 if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
865 /*
866 * fine he has told us he is closing too, let's
867 * finish our close
868 */
Andy Green43db0452013-01-10 19:50:35 +0800869 lwsl_parser("seen client close ack\n");
Andy Greenda527df2011-03-07 07:08:12 +0000870 return -1;
871 }
Andy Green40d5abc2015-04-17 20:29:58 +0800872 if (wsi->state == WSI_STATE_RETURNED_CLOSE_ALREADY)
873 /* if he sends us 2 CLOSE, kill him */
874 return -1;
875
Andy Green43db0452013-01-10 19:50:35 +0800876 lwsl_parser("server sees client close packet\n");
Andy Green5e1fa172011-02-10 09:07:05 +0000877 wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
Andy Green40d5abc2015-04-17 20:29:58 +0800878 /* deal with the close packet contents as a PONG */
879 wsi->u.ws.payload_is_close = 1;
880 goto process_as_ping;
Andy Green4739e5c2011-01-22 12:51:57 +0000881
Andy Green23545db2011-04-24 06:19:22 +0100882 case LWS_WS_OPCODE_07__PING:
Andy Greenb5b23192013-02-11 17:13:32 +0800883 lwsl_info("received %d byte ping, sending pong\n",
884 wsi->u.ws.rx_user_buffer_head);
Andy Green82bac6b2014-08-24 14:39:19 +0800885
Andy Green2fd6e6f2015-03-24 21:07:01 +0800886 if (wsi->u.ws.ping_pending_flag) {
Andy Green82bac6b2014-08-24 14:39:19 +0800887 /*
888 * there is already a pending ping payload
889 * we should just log and drop
890 */
891 lwsl_parser("DROP PING since one pending\n");
892 goto ping_drop;
893 }
Andy Green40d5abc2015-04-17 20:29:58 +0800894process_as_ping:
Andy Green82bac6b2014-08-24 14:39:19 +0800895 /* control packets can only be < 128 bytes long */
Andy Green106d4a82015-03-24 21:22:52 +0800896 if (wsi->u.ws.rx_user_buffer_head > 128 - 4) {
Andy Green82bac6b2014-08-24 14:39:19 +0800897 lwsl_parser("DROP PING payload too large\n");
898 goto ping_drop;
899 }
900
901 /* if existing buffer is too small, drop it */
902 if (wsi->u.ws.ping_payload_buf &&
903 wsi->u.ws.ping_payload_alloc < wsi->u.ws.rx_user_buffer_head) {
Alejandro Meryac3ec392014-12-05 00:09:20 +0100904 lws_free2(wsi->u.ws.ping_payload_buf);
Andy Green82bac6b2014-08-24 14:39:19 +0800905 }
906
907 /* if no buffer, allocate it */
908 if (!wsi->u.ws.ping_payload_buf) {
Alejandro Mery6ff28242014-12-04 23:59:35 +0100909 wsi->u.ws.ping_payload_buf = lws_malloc(wsi->u.ws.rx_user_buffer_head
910 + LWS_SEND_BUFFER_PRE_PADDING);
Andy Green82bac6b2014-08-24 14:39:19 +0800911 wsi->u.ws.ping_payload_alloc = wsi->u.ws.rx_user_buffer_head;
912 }
913
914 /* stash the pong payload */
915 memcpy(wsi->u.ws.ping_payload_buf + LWS_SEND_BUFFER_PRE_PADDING,
916 &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
917 wsi->u.ws.rx_user_buffer_head);
918
919 wsi->u.ws.ping_payload_len = wsi->u.ws.rx_user_buffer_head;
Andy Green2fd6e6f2015-03-24 21:07:01 +0800920 wsi->u.ws.ping_pending_flag = 1;
Andy Green82bac6b2014-08-24 14:39:19 +0800921
922 /* get it sent as soon as possible */
923 libwebsocket_callback_on_writable(wsi->protocol->owning_server, wsi);
924ping_drop:
Andy Green623a98d2013-01-21 11:04:23 +0800925 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena6cbece2011-01-27 20:06:03 +0000926 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000927
Andy Green23545db2011-04-24 06:19:22 +0100928 case LWS_WS_OPCODE_07__PONG:
Andy Green4739e5c2011-01-22 12:51:57 +0000929 /* ... then just drop it */
Andy Green623a98d2013-01-21 11:04:23 +0800930 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000931 return 0;
932
Andy Greena41314f2011-05-23 10:00:03 +0100933 case LWS_WS_OPCODE_07__TEXT_FRAME:
934 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Green2fd3f2f2013-01-18 09:49:20 +0800935 case LWS_WS_OPCODE_07__CONTINUATION:
Andy Green4739e5c2011-01-22 12:51:57 +0000936 break;
Andy Greena41314f2011-05-23 10:00:03 +0100937
938 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800939 lwsl_parser("passing opc %x up to exts\n",
940 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100941 /*
942 * It's something special we can't understand here.
943 * Pass the payload up to the extension's parsing
944 * state machine.
945 */
946
Andy Green623a98d2013-01-21 11:04:23 +0800947 eff_buf.token = &wsi->u.ws.rx_user_buffer[
Andy Greena41314f2011-05-23 10:00:03 +0100948 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800949 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Greena41314f2011-05-23 10:00:03 +0100950
Andy Green2c24ec02014-04-02 19:45:42 +0800951 if (lws_ext_callback_for_each_active(wsi,
952 LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
953 &eff_buf, 0) <= 0) /* not handle or fail */
Andy Greenb5b23192013-02-11 17:13:32 +0800954 lwsl_ext("ext opc opcode 0x%x unknown\n",
955 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100956
Andy Green623a98d2013-01-21 11:04:23 +0800957 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena41314f2011-05-23 10:00:03 +0100958 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000959 }
960
961 /*
962 * No it's real payload, pass it up to the user callback.
963 * It's nicely buffered with the pre-padding taken care of
964 * so it can be sent straight out again using libwebsocket_write
965 */
966
Andy Green623a98d2013-01-21 11:04:23 +0800967 eff_buf.token = &wsi->u.ws.rx_user_buffer[
David Galeanoe2cf9922013-01-09 18:06:55 +0800968 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800969 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Green2c24ec02014-04-02 19:45:42 +0800970
971 if (lws_ext_callback_for_each_active(wsi,
972 LWS_EXT_CALLBACK_PAYLOAD_RX, &eff_buf, 0) < 0)
973 return -1;
974
David Galeanoe2cf9922013-01-09 18:06:55 +0800975 if (eff_buf.token_len > 0) {
Andy Greenaedc9532013-02-10 21:21:24 +0800976 eff_buf.token[eff_buf.token_len] = '\0';
David Galeanoe2cf9922013-01-09 18:06:55 +0800977
Andy Greenaedc9532013-02-10 21:21:24 +0800978 if (wsi->protocol->callback)
Andy Greenb5b23192013-02-11 17:13:32 +0800979 ret = user_callback_handle_rxflow(
980 wsi->protocol->callback,
981 wsi->protocol->owning_server,
982 wsi, LWS_CALLBACK_RECEIVE,
983 wsi->user_space,
984 eff_buf.token,
985 eff_buf.token_len);
David Galeanoe2cf9922013-01-09 18:06:55 +0800986 else
Andy Greenf7609e92013-01-14 13:10:55 +0800987 lwsl_err("No callback on payload spill!\n");
David Galeanoe2cf9922013-01-09 18:06:55 +0800988 }
Andy Greena41314f2011-05-23 10:00:03 +0100989
Andy Green623a98d2013-01-21 11:04:23 +0800990 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000991 break;
992 }
993
Andy Greenaedc9532013-02-10 21:21:24 +0800994 return ret;
Andy Green23545db2011-04-24 06:19:22 +0100995
996illegal_ctl_length:
997
Andy Greenb5b23192013-02-11 17:13:32 +0800998 lwsl_warn("Control frame with xtended length is illegal\n");
Andy Green23545db2011-04-24 06:19:22 +0100999 /* kill the connection */
1000 return -1;
Andy Green4739e5c2011-01-22 12:51:57 +00001001}
1002
1003
Andy Green38e57bb2011-01-19 12:20:27 +00001004/**
1005 * libwebsockets_remaining_packet_payload() - Bytes to come before "overall"
Andy Green6964bb52011-01-23 16:50:33 +00001006 * rx packet is complete
Andy Green38e57bb2011-01-19 12:20:27 +00001007 * @wsi: Websocket instance (available from user callback)
1008 *
1009 * This function is intended to be called from the callback if the
1010 * user code is interested in "complete packets" from the client.
1011 * libwebsockets just passes through payload as it comes and issues a buffer
1012 * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE
1013 * callback handler can use this API to find out if the buffer it has just
1014 * been given is the last piece of a "complete packet" from the client --
1015 * when that is the case libwebsockets_remaining_packet_payload() will return
1016 * 0.
1017 *
1018 * Many protocols won't care becuse their packets are always small.
1019 */
1020
Peter Pentchev9a4fef72013-03-30 09:52:21 +08001021LWS_VISIBLE size_t
Andy Green38e57bb2011-01-19 12:20:27 +00001022libwebsockets_remaining_packet_payload(struct libwebsocket *wsi)
1023{
Andy Green623a98d2013-01-21 11:04:23 +08001024 return wsi->u.ws.rx_packet_length;
Andy Green38e57bb2011-01-19 12:20:27 +00001025}