blob: 83124ffe282a1247d143ba9b9afe163a2b6ca326 [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{
Andrew Canadayffe64562015-11-29 19:26:01 +0800183 unsigned short frag_len;
Andy Greenb1a9e502013-11-10 15:15:21 +0800184 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
185 lwsl_warn("excessive header content\n");
186 return -1;
187 }
Andrew Canaday74b4a652014-06-29 00:25:19 -0400188
Andrew Canadayffe64562015-11-29 19:26:01 +0800189 frag_len = \
Andrew Canaday4cfc42c2015-11-29 19:24:04 +0800190 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len;
191 /* If we haven't hit the token limit, just copy the character into
192 * the header: */
193 if( frag_len < wsi->u.hdr.current_token_limit ) {
194 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 return 0;
198 }
199 else {
200 /* Insert a null character when we *hit* the limit: */
201 if( frag_len == wsi->u.hdr.current_token_limit ) {
202 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0';
203 lwsl_warn("header %i exceeds limit\n", wsi->u.hdr.parser_state);
204 };
Andrew Canaday74b4a652014-06-29 00:25:19 -0400205 };
Andrew Canaday4cfc42c2015-11-29 19:24:04 +0800206 return 1;
Andy Greenb1a9e502013-11-10 15:15:21 +0800207}
208
Andrew Canaday74b4a652014-06-29 00:25:19 -0400209int libwebsocket_parse(
210 struct libwebsocket_context *context,
211 struct libwebsocket *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000212{
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800213 static const unsigned char methods[] = {
214 WSI_TOKEN_GET_URI,
215 WSI_TOKEN_POST_URI,
216 WSI_TOKEN_OPTIONS_URI,
217 WSI_TOKEN_PUT_URI,
218 WSI_TOKEN_PATCH_URI,
219 WSI_TOKEN_DELETE_URI,
220 };
Andy Green2cd30742015-11-02 13:10:33 +0800221 unsigned int n, m;
Andy Green7c212cc2010-11-08 20:20:42 +0000222
Andy Green623a98d2013-01-21 11:04:23 +0800223 switch (wsi->u.hdr.parser_state) {
Andy Greenb08cb502014-09-30 16:33:56 +0800224 default:
Andy Greena41314f2011-05-23 10:00:03 +0100225
Andy Greenb5b23192013-02-11 17:13:32 +0800226 lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c);
Andy Green7c212cc2010-11-08 20:20:42 +0000227
228 /* collect into malloc'd buffers */
Andy Green16ab3182013-02-10 18:02:31 +0800229 /* optional initial space swallow */
Andy Greenb5b23192013-02-11 17:13:32 +0800230 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->frag_index[
231 wsi->u.hdr.parser_state]].len && c == ' ')
Andy Green7c212cc2010-11-08 20:20:42 +0000232 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000233
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800234 for (m = 0; m < ARRAY_SIZE(methods); m++)
235 if (wsi->u.hdr.parser_state == methods[m])
236 break;
237 if (m == ARRAY_SIZE(methods))
238 /* it was not any of the methods */
Andy Greenb1a9e502013-11-10 15:15:21 +0800239 goto check_eol;
240
241 /* special URI processing... end at space */
242
243 if (c == ' ') {
244 /* enforce starting with / */
245 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len)
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400246 if (issue_char(wsi, '/') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800247 return -1;
Andrew Canadayafe26cf2014-07-13 01:07:36 -0400248
249 /* begin parsing HTTP version: */
250 if (issue_char(wsi, '\0') < 0)
251 return -1;
252 wsi->u.hdr.parser_state = WSI_TOKEN_HTTP;
253 goto start_fragment;
Andy Green7c212cc2010-11-08 20:20:42 +0000254 }
255
Andy Greenb1a9e502013-11-10 15:15:21 +0800256 /* special URI processing... convert %xx */
257
258 switch (wsi->u.hdr.ues) {
259 case URIES_IDLE:
260 if (c == '%') {
261 wsi->u.hdr.ues = URIES_SEEN_PERCENT;
262 goto swallow;
263 }
264 break;
265 case URIES_SEEN_PERCENT:
266 if (char_to_hex(c) < 0) {
267 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400268 if (issue_char(wsi, '%') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800269 return -1;
270 wsi->u.hdr.ues = URIES_IDLE;
271 /* continue on to assess c */
272 break;
273 }
274 wsi->u.hdr.esc_stash = c;
275 wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
Andy Green6f429102013-11-11 06:14:52 +0800276 goto swallow;
Andy Greenb1a9e502013-11-10 15:15:21 +0800277
278 case URIES_SEEN_PERCENT_H1:
279 if (char_to_hex(c) < 0) {
280 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400281 issue_char(wsi, '%');
Andy Greenb1a9e502013-11-10 15:15:21 +0800282 wsi->u.hdr.ues = URIES_IDLE;
283 /* regurgitate + assess */
Andrew Canaday74b4a652014-06-29 00:25:19 -0400284 if (libwebsocket_parse(context, wsi, wsi->u.hdr.esc_stash) < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800285 return -1;
286 /* continue on to assess c */
287 break;
288 }
289 c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
290 char_to_hex(c);
Andy Green6f429102013-11-11 06:14:52 +0800291 wsi->u.hdr.ues = URIES_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800292 break;
293 }
294
295 /*
296 * special URI processing...
Andy Green6f429102013-11-11 06:14:52 +0800297 * convert /.. or /... or /../ etc to /
298 * convert /./ to /
Andy Greenb1a9e502013-11-10 15:15:21 +0800299 * convert // or /// etc to /
300 * leave /.dir or whatever alone
301 */
302
303 switch (wsi->u.hdr.ups) {
304 case URIPS_IDLE:
305 /* issue the first / always */
306 if (c == '/')
307 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
308 break;
309 case URIPS_SEEN_SLASH:
310 /* swallow subsequent slashes */
311 if (c == '/')
312 goto swallow;
313 /* track and swallow the first . after / */
314 if (c == '.') {
315 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT;
316 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800317 }
318 wsi->u.hdr.ups = URIPS_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800319 break;
320 case URIPS_SEEN_SLASH_DOT:
321 /* swallow second . */
322 if (c == '.') {
Andy Greend3f68732013-11-13 06:53:21 +0800323 /*
324 * back up one dir level if possible
325 * safe against header fragmentation because
326 * the method URI can only be in 1 fragment
327 */
328 if (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 2) {
329 wsi->u.hdr.ah->pos--;
330 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
331 do {
332 wsi->u.hdr.ah->pos--;
333 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
334 } while (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 1 &&
335 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos] != '/');
336 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800337 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
338 goto swallow;
339 }
Andy Green6f429102013-11-11 06:14:52 +0800340 /* change /./ to / */
341 if (c == '/') {
342 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
343 goto swallow;
344 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800345 /* it was like /.dir ... regurgitate the . */
346 wsi->u.hdr.ups = URIPS_IDLE;
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400347 issue_char(wsi, '.');
Andy Greenb1a9e502013-11-10 15:15:21 +0800348 break;
349
350 case URIPS_SEEN_SLASH_DOT_DOT:
351 /* swallow prior .. chars and any subsequent . */
352 if (c == '.')
353 goto swallow;
Andy Green6f429102013-11-11 06:14:52 +0800354 /* last issued was /, so another / == // */
355 if (c == '/')
356 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800357 /* last we issued was / so SEEN_SLASH */
358 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
Andy Greenb1a9e502013-11-10 15:15:21 +0800359 break;
Andy Green1e3f7b82013-11-13 07:45:17 +0800360 case URIPS_ARGUMENTS:
361 /* leave them alone */
362 break;
Andy Greenb1a9e502013-11-10 15:15:21 +0800363 }
364
Andy Green1e3f7b82013-11-13 07:45:17 +0800365 if (c == '?') { /* start of URI arguments */
366 /* seal off uri header */
367 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0';
368
369 /* move to using WSI_TOKEN_HTTP_URI_ARGS */
370 wsi->u.hdr.ah->next_frag_index++;
371 wsi->u.hdr.ah->frags[
372 wsi->u.hdr.ah->next_frag_index].offset =
373 wsi->u.hdr.ah->pos;
374 wsi->u.hdr.ah->frags[
375 wsi->u.hdr.ah->next_frag_index].len = 0;
376 wsi->u.hdr.ah->frags[
377 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
378
379 wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] =
380 wsi->u.hdr.ah->next_frag_index;
381
382 /* defeat normal uri path processing */
383 wsi->u.hdr.ups = URIPS_ARGUMENTS;
384 goto swallow;
385 }
386
Andrew Canaday991f1cd2014-07-19 06:58:53 +0800387check_eol:
388
389 /* bail at EOL */
390 if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
391 c == '\x0d') {
392 c = '\0';
393 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
394 lwsl_parser("*\n");
395 }
396
Andy Green4b812fe2014-08-19 18:34:31 +0800397 n = issue_char(wsi, c);
Andy Green2cd30742015-11-02 13:10:33 +0800398 if ((int)n < 0)
Andy Green4b812fe2014-08-19 18:34:31 +0800399 return -1;
400 if (n > 0)
401 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
402
Andy Greenb1a9e502013-11-10 15:15:21 +0800403swallow:
Andy Greend1b11e32011-01-18 15:39:02 +0000404 /* per-protocol end of headers management */
Andy Greene77ddd82010-11-13 10:03:47 +0000405
Andy Green16ab3182013-02-10 18:02:31 +0800406 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
407 goto set_parsing_complete;
Andy Greena41314f2011-05-23 10:00:03 +0100408 break;
409
Andy Green7c212cc2010-11-08 20:20:42 +0000410 /* collecting and checking a name part */
411 case WSI_TOKEN_NAME_PART:
Andy Green8fb338f2015-04-07 08:19:30 +0800412 lwsl_parser("WSI_TOKEN_NAME_PART '%c' (mode=%d)\n", c, wsi->mode);
Andy Green7c212cc2010-11-08 20:20:42 +0000413
Andy Greenb5b23192013-02-11 17:13:32 +0800414 wsi->u.hdr.lextable_pos =
415 lextable_decode(wsi->u.hdr.lextable_pos, c);
Andy Green8fb338f2015-04-07 08:19:30 +0800416 /*
417 * Server needs to look out for unknown methods...
418 */
419 if (wsi->u.hdr.lextable_pos < 0 &&
420 wsi->mode == LWS_CONNMODE_HTTP_SERVING) {
Andy Greene4dffc92013-02-04 09:24:18 +0800421 /* this is not a header we know about */
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800422 for (m = 0; m < ARRAY_SIZE(methods); m++)
423 if (wsi->u.hdr.ah->frag_index[methods[m]]) {
424 /*
425 * already had the method, no idea what
Andy Green8fb338f2015-04-07 08:19:30 +0800426 * this crap from the client is, ignore
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800427 */
428 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
429 break;
430 }
Andy Green3ee9b312013-02-12 12:52:39 +0800431 /*
Andy Green8fb338f2015-04-07 08:19:30 +0800432 * hm it's an unknown http method from a client in fact,
Andy Green3ee9b312013-02-12 12:52:39 +0800433 * treat as dangerous
434 */
Drew Noakes2121e8a2015-01-30 12:04:43 +0000435 if (m == ARRAY_SIZE(methods)) {
436 lwsl_info("Unknown method - dropping\n");
437 return -1;
438 }
439 break;
Andy Greene4dffc92013-02-04 09:24:18 +0800440 }
Andy Green8fb338f2015-04-07 08:19:30 +0800441 /*
442 * ...otherwise for a client, let him ignore unknown headers
443 * coming from the server
444 */
445 if (wsi->u.hdr.lextable_pos < 0) {
446 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
447 break;
448 }
449
Andy Greenbbc5c072014-03-09 11:49:21 +0800450 if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) {
Andy Greene4dffc92013-02-04 09:24:18 +0800451 /* terminal state */
452
Andy Green59800b72014-11-30 12:36:09 +0800453 n = ((unsigned int)lextable[wsi->u.hdr.lextable_pos] << 8) |
454 lextable[wsi->u.hdr.lextable_pos + 1];
Andy Green6d1fcb72013-01-18 01:55:48 +0800455
Andy Greencc7cb682013-02-18 10:22:42 +0800456 lwsl_parser("known hdr %d\n", n);
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800457 for (m = 0; m < ARRAY_SIZE(methods); m++)
458 if (n == methods[m] &&
459 wsi->u.hdr.ah->frag_index[
460 methods[m]]) {
461 lwsl_warn("Duplicated method\n");
462 return -1;
463 }
Andy Green94f94652013-02-12 13:10:19 +0800464
Andy Greenfd963302012-04-03 17:02:20 +0200465 /*
466 * WSORIGIN is protocol equiv to ORIGIN,
467 * JWebSocket likes to send it, map to ORIGIN
468 */
469 if (n == WSI_TOKEN_SWORIGIN)
470 n = WSI_TOKEN_ORIGIN;
471
Andy Green16ab3182013-02-10 18:02:31 +0800472 wsi->u.hdr.parser_state = (enum lws_token_indexes)
473 (WSI_TOKEN_GET_URI + n);
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400474
Andy Greenf012f752014-08-22 19:38:17 +0800475 if (context->token_limits)
476 wsi->u.hdr.current_token_limit =
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400477 context->token_limits->token_limit[wsi->u.hdr.parser_state];
Andy Greenf012f752014-08-22 19:38:17 +0800478 else
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400479 wsi->u.hdr.current_token_limit = sizeof(wsi->u.hdr.ah->data);
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400480
Andy Green16ab3182013-02-10 18:02:31 +0800481 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
482 goto set_parsing_complete;
Andy Green6964bb52011-01-23 16:50:33 +0000483
Andy Green16ab3182013-02-10 18:02:31 +0800484 goto start_fragment;
485 }
486 break;
Nick Dowell30592632012-04-05 10:31:48 +0800487
Andy Green16ab3182013-02-10 18:02:31 +0800488start_fragment:
489 wsi->u.hdr.ah->next_frag_index++;
Andy Greenb5b23192013-02-11 17:13:32 +0800490 if (wsi->u.hdr.ah->next_frag_index ==
491 sizeof(wsi->u.hdr.ah->frags) /
492 sizeof(wsi->u.hdr.ah->frags[0])) {
493 lwsl_warn("More hdr frags than we can deal with\n");
Andy Green16ab3182013-02-10 18:02:31 +0800494 return -1;
Andy Green7c212cc2010-11-08 20:20:42 +0000495 }
496
Andy Greenb5b23192013-02-11 17:13:32 +0800497 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
498 wsi->u.hdr.ah->pos;
Andy Green16ab3182013-02-10 18:02:31 +0800499 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
Andy Greenb5b23192013-02-11 17:13:32 +0800500 wsi->u.hdr.ah->frags[
501 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800502
503 n = wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state];
504 if (!n) { /* first fragment */
505 wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state] =
506 wsi->u.hdr.ah->next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800507 break;
508 }
509 /* continuation */
510 while (wsi->u.hdr.ah->frags[n].next_frag_index)
Andy Green16ab3182013-02-10 18:02:31 +0800511 n = wsi->u.hdr.ah->frags[n].next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800512 wsi->u.hdr.ah->frags[n].next_frag_index =
Andy Green16ab3182013-02-10 18:02:31 +0800513 wsi->u.hdr.ah->next_frag_index;
514
Andy Greencc13c6f2013-11-09 10:09:09 +0800515 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
516 lwsl_warn("excessive header content\n");
517 return -1;
Andy Green2b57a342013-02-06 15:15:25 +0900518 }
Andy Green7c212cc2010-11-08 20:20:42 +0000519
Andy Greencc13c6f2013-11-09 10:09:09 +0800520 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = ' ';
521 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
Andy Greene4dffc92013-02-04 09:24:18 +0800522 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000523
Andy Green7c212cc2010-11-08 20:20:42 +0000524 /* skipping arg part of a name we didn't recognize */
525 case WSI_TOKEN_SKIPPING:
Andy Green43db0452013-01-10 19:50:35 +0800526 lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
kapejodce64fb02013-11-19 13:38:16 +0100527
Andy Green7c212cc2010-11-08 20:20:42 +0000528 if (c == '\x0d')
Andy Green623a98d2013-01-21 11:04:23 +0800529 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
Andy Green7c212cc2010-11-08 20:20:42 +0000530 break;
Andy Green177ca782013-02-04 09:09:19 +0800531
Andy Green7c212cc2010-11-08 20:20:42 +0000532 case WSI_TOKEN_SKIPPING_SAW_CR:
Andy Green43db0452013-01-10 19:50:35 +0800533 lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
Andy Green6d1fcb72013-01-18 01:55:48 +0800534 if (c == '\x0a') {
Andy Green623a98d2013-01-21 11:04:23 +0800535 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
536 wsi->u.hdr.lextable_pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +0800537 } else
Andy Green623a98d2013-01-21 11:04:23 +0800538 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
Andy Green7c212cc2010-11-08 20:20:42 +0000539 break;
540 /* we're done, ignore anything else */
kapejodce64fb02013-11-19 13:38:16 +0100541
Andy Green7c212cc2010-11-08 20:20:42 +0000542 case WSI_PARSING_COMPLETE:
Andy Green43db0452013-01-10 19:50:35 +0800543 lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000544 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000545 }
Andy Greene77ddd82010-11-13 10:03:47 +0000546
Andy Green7c212cc2010-11-08 20:20:42 +0000547 return 0;
Andy Green177ca782013-02-04 09:09:19 +0800548
549set_parsing_complete:
550
Andy Green16ab3182013-02-10 18:02:31 +0800551 if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800552 if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
Andy Green2b57a342013-02-06 15:15:25 +0900553 wsi->ietf_spec_revision =
Andy Green16ab3182013-02-10 18:02:31 +0800554 atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
Andy Green177ca782013-02-04 09:09:19 +0800555
Andy Greenb5b23192013-02-11 17:13:32 +0800556 lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision);
Andy Green2b57a342013-02-06 15:15:25 +0900557 }
Andy Green177ca782013-02-04 09:09:19 +0800558 wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE;
Andy Green224149a2013-02-11 21:43:41 +0800559 wsi->hdr_parsing_completed = 1;
Andy Green177ca782013-02-04 09:09:19 +0800560
561 return 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000562}
563
Andy Greenbfb051f2011-02-09 08:49:14 +0000564
Andy Green2fd3f2f2013-01-18 09:49:20 +0800565/**
566 * lws_frame_is_binary: true if the current frame was sent in binary mode
567 *
568 * @wsi: the connection we are inquiring about
569 *
570 * This is intended to be called from the LWS_CALLBACK_RECEIVE callback if
571 * it's interested to see if the frame it's dealing with was sent in binary
572 * mode.
573 */
574
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800575LWS_VISIBLE int lws_frame_is_binary(struct libwebsocket *wsi)
Andy Green2fd3f2f2013-01-18 09:49:20 +0800576{
Andy Green623a98d2013-01-21 11:04:23 +0800577 return wsi->u.ws.frame_is_binary;
Andy Green2fd3f2f2013-01-18 09:49:20 +0800578}
Andy Greenbfb051f2011-02-09 08:49:14 +0000579
Andy Greena41314f2011-05-23 10:00:03 +0100580int
581libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000582{
Andy Greena41314f2011-05-23 10:00:03 +0100583 struct lws_tokens eff_buf;
Andy Greenaedc9532013-02-10 21:21:24 +0800584 int ret = 0;
John Tarlton05fc6ba2015-10-05 11:35:52 +0100585 int callback_action = LWS_CALLBACK_RECEIVE;
Andy Green7c212cc2010-11-08 20:20:42 +0000586
587 switch (wsi->lws_rx_parse_state) {
588 case LWS_RXPS_NEW:
Andy Greene77ddd82010-11-13 10:03:47 +0000589
Andy Green7c212cc2010-11-08 20:20:42 +0000590 switch (wsi->ietf_spec_revision) {
Andy Greend85cb202011-09-25 09:32:54 +0100591 case 13:
Andy Green283d0a22011-04-24 05:46:23 +0100592 /*
593 * no prepended frame key any more
594 */
Andy Green623a98d2013-01-21 11:04:23 +0800595 wsi->u.ws.all_zero_nonce = 1;
Andy Green283d0a22011-04-24 05:46:23 +0100596 goto handle_first;
597
Andy Greenbfb051f2011-02-09 08:49:14 +0000598 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800599 lwsl_warn("lws_rx_sm: unknown spec version %d\n",
600 wsi->ietf_spec_revision);
Andy Greenbfb051f2011-02-09 08:49:14 +0000601 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000602 }
Andy Green6452f1e2010-11-11 09:22:22 +0000603 break;
Andy Green3e5eb782011-01-18 18:14:26 +0000604 case LWS_RXPS_04_MASK_NONCE_1:
Andy Green623a98d2013-01-21 11:04:23 +0800605 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000606 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800607 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000608 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2;
609 break;
610 case LWS_RXPS_04_MASK_NONCE_2:
Andy Green623a98d2013-01-21 11:04:23 +0800611 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000612 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800613 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000614 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3;
615 break;
616 case LWS_RXPS_04_MASK_NONCE_3:
Andy Green623a98d2013-01-21 11:04:23 +0800617 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000618 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800619 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000620
Andy Green3e5eb782011-01-18 18:14:26 +0000621 /*
622 * start from the zero'th byte in the XOR key buffer since
623 * this is the start of a frame with a new key
624 */
625
Andy Green623a98d2013-01-21 11:04:23 +0800626 wsi->u.ws.frame_mask_index = 0;
Andy Green6964bb52011-01-23 16:50:33 +0000627
Andy Green3e5eb782011-01-18 18:14:26 +0000628 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
629 break;
Andy Green38e57bb2011-01-19 12:20:27 +0000630
631 /*
632 * 04 logical framing from the spec (all this is masked when incoming
633 * and has to be unmasked)
634 *
635 * We ignore the possibility of extension data because we don't
636 * negotiate any extensions at the moment.
Andy Green6964bb52011-01-23 16:50:33 +0000637 *
Andy Green38e57bb2011-01-19 12:20:27 +0000638 * 0 1 2 3
639 * 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
640 * +-+-+-+-+-------+-+-------------+-------------------------------+
641 * |F|R|R|R| opcode|R| Payload len | Extended payload length |
642 * |I|S|S|S| (4) |S| (7) | (16/63) |
643 * |N|V|V|V| |V| | (if payload len==126/127) |
644 * | |1|2|3| |4| | |
645 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
646 * | Extended payload length continued, if payload len == 127 |
647 * + - - - - - - - - - - - - - - - +-------------------------------+
648 * | | Extension data |
649 * +-------------------------------+ - - - - - - - - - - - - - - - +
650 * : :
651 * +---------------------------------------------------------------+
652 * : Application data :
653 * +---------------------------------------------------------------+
654 *
655 * We pass payload through to userland as soon as we get it, ignoring
656 * FIN. It's up to userland to buffer it up if it wants to see a
657 * whole unfragmented block of the original size (which may be up to
658 * 2^63 long!)
659 */
660
661 case LWS_RXPS_04_FRAME_HDR_1:
Andy Green283d0a22011-04-24 05:46:23 +0100662handle_first:
663
Andy Green623a98d2013-01-21 11:04:23 +0800664 wsi->u.ws.opcode = c & 0xf;
665 wsi->u.ws.rsv = c & 0x70;
666 wsi->u.ws.final = !!((c >> 7) & 1);
Andy Green1bc12f92013-02-28 17:11:29 +0800667
Andy Green623a98d2013-01-21 11:04:23 +0800668 switch (wsi->u.ws.opcode) {
Andy Green10601c12013-01-19 10:39:35 +0800669 case LWS_WS_OPCODE_07__TEXT_FRAME:
Andy Green10601c12013-01-19 10:39:35 +0800670 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Greenb5b23192013-02-11 17:13:32 +0800671 wsi->u.ws.frame_is_binary =
672 wsi->u.ws.opcode == LWS_WS_OPCODE_07__BINARY_FRAME;
Andy Green10601c12013-01-19 10:39:35 +0800673 break;
674 }
Andy Green38e57bb2011-01-19 12:20:27 +0000675 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
676 break;
677
678 case LWS_RXPS_04_FRAME_HDR_LEN:
Andy Green38e57bb2011-01-19 12:20:27 +0000679
Andy Green623a98d2013-01-21 11:04:23 +0800680 wsi->u.ws.this_frame_masked = !!(c & 0x80);
Andy Green283d0a22011-04-24 05:46:23 +0100681
Andy Green5bf65782011-09-25 10:46:31 +0100682 switch (c & 0x7f) {
Andy Green38e57bb2011-01-19 12:20:27 +0000683 case 126:
684 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800685 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100686 goto illegal_ctl_length;
687
Andy Green38e57bb2011-01-19 12:20:27 +0000688 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
689 break;
690 case 127:
691 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800692 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100693 goto illegal_ctl_length;
694
Andy Green38e57bb2011-01-19 12:20:27 +0000695 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
696 break;
697 default:
Andy Green623a98d2013-01-21 11:04:23 +0800698 wsi->u.ws.rx_packet_length = c & 0x7f;
699 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100700 wsi->lws_rx_parse_state =
701 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
702 else
Andy Green8ea19552014-02-15 16:00:37 +0800703 if (wsi->u.ws.rx_packet_length)
704 wsi->lws_rx_parse_state =
Andy Green38e57bb2011-01-19 12:20:27 +0000705 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green8ea19552014-02-15 16:00:37 +0800706 else {
707 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
708 goto spill;
709 }
Andy Green38e57bb2011-01-19 12:20:27 +0000710 break;
711 }
712 break;
713
714 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
Andy Green623a98d2013-01-21 11:04:23 +0800715 wsi->u.ws.rx_packet_length = c << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000716 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
717 break;
718
719 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
Andy Green623a98d2013-01-21 11:04:23 +0800720 wsi->u.ws.rx_packet_length |= c;
721 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100722 wsi->lws_rx_parse_state =
723 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
724 else
725 wsi->lws_rx_parse_state =
726 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000727 break;
728
729 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
Andy Green38e57bb2011-01-19 12:20:27 +0000730 if (c & 0x80) {
Andy Green43db0452013-01-10 19:50:35 +0800731 lwsl_warn("b63 of length must be zero\n");
Andy Green38e57bb2011-01-19 12:20:27 +0000732 /* kill the connection */
733 return -1;
734 }
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) << 56;
Andy Greenf55830d2011-01-27 06:45:53 +0000737#else
Andy Green623a98d2013-01-21 11:04:23 +0800738 wsi->u.ws.rx_packet_length = 0;
Andy Greenf55830d2011-01-27 06:45:53 +0000739#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000740 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
741 break;
742
743 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
Andy Greenf55830d2011-01-27 06:45:53 +0000744#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800745 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
Andy Greenf55830d2011-01-27 06:45:53 +0000746#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000747 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
748 break;
749
750 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
Andy Greenf55830d2011-01-27 06:45:53 +0000751#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800752 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
Andy Greenf55830d2011-01-27 06:45:53 +0000753#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000754 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
755 break;
756
757 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
Andy Greenf55830d2011-01-27 06:45:53 +0000758#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800759 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
Andy Greenf55830d2011-01-27 06:45:53 +0000760#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000761 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
762 break;
763
764 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
Andy Green623a98d2013-01-21 11:04:23 +0800765 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
Andy Green38e57bb2011-01-19 12:20:27 +0000766 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
767 break;
768
769 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
Andy Green623a98d2013-01-21 11:04:23 +0800770 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
Andy Green38e57bb2011-01-19 12:20:27 +0000771 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
772 break;
773
774 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
Andy Green623a98d2013-01-21 11:04:23 +0800775 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000776 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
777 break;
778
779 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
Andy Green623a98d2013-01-21 11:04:23 +0800780 wsi->u.ws.rx_packet_length |= ((size_t)c);
781 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100782 wsi->lws_rx_parse_state =
783 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
784 else
785 wsi->lws_rx_parse_state =
786 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000787 break;
788
Andy Green283d0a22011-04-24 05:46:23 +0100789 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
Andy Green623a98d2013-01-21 11:04:23 +0800790 wsi->u.ws.frame_masking_nonce_04[0] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100791 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800792 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100793 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
794 break;
795
796 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
Andy Green623a98d2013-01-21 11:04:23 +0800797 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100798 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800799 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100800 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
801 break;
802
803 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
Andy Green623a98d2013-01-21 11:04:23 +0800804 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100805 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800806 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100807 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
808 break;
809
810 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
Andy Green623a98d2013-01-21 11:04:23 +0800811 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100812 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800813 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100814 wsi->lws_rx_parse_state =
815 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green623a98d2013-01-21 11:04:23 +0800816 wsi->u.ws.frame_mask_index = 0;
Andy Green8ea19552014-02-15 16:00:37 +0800817 if (wsi->u.ws.rx_packet_length == 0) {
818 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
Andy Green1bc12f92013-02-28 17:11:29 +0800819 goto spill;
Andy Green8ea19552014-02-15 16:00:37 +0800820 }
Andy Green283d0a22011-04-24 05:46:23 +0100821 break;
822
823
Andy Green7c212cc2010-11-08 20:20:42 +0000824 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
Andy Green3182ece2013-01-20 17:08:31 +0800825
Andy Greencd838502014-11-30 12:53:27 +0800826 if (!wsi->u.ws.rx_user_buffer) {
Andy Green54495112013-02-06 21:10:16 +0900827 lwsl_err("NULL user buffer...\n");
Andy Greencd838502014-11-30 12:53:27 +0800828 return 1;
829 }
Andy Green54495112013-02-06 21:10:16 +0900830
Andy Green623a98d2013-01-21 11:04:23 +0800831 if (wsi->u.ws.all_zero_nonce)
832 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
833 (wsi->u.ws.rx_user_buffer_head++)] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000834 else
Andy Green623a98d2013-01-21 11:04:23 +0800835 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
836 (wsi->u.ws.rx_user_buffer_head++)] =
Andy Greenb5b23192013-02-11 17:13:32 +0800837 c ^ wsi->u.ws.frame_masking_nonce_04[
838 (wsi->u.ws.frame_mask_index++) & 3];
Andy Green4739e5c2011-01-22 12:51:57 +0000839
Andy Green623a98d2013-01-21 11:04:23 +0800840 if (--wsi->u.ws.rx_packet_length == 0) {
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800841 /* spill because we have the whole frame */
Andy Green4739e5c2011-01-22 12:51:57 +0000842 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
843 goto spill;
844 }
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800845
846 /*
847 * if there's no protocol max frame size given, we are
848 * supposed to default to LWS_MAX_SOCKET_IO_BUF
849 */
850
851 if (!wsi->protocol->rx_buffer_size &&
852 wsi->u.ws.rx_user_buffer_head !=
853 LWS_MAX_SOCKET_IO_BUF)
Andy Green4739e5c2011-01-22 12:51:57 +0000854 break;
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800855 else
856 if (wsi->protocol->rx_buffer_size &&
857 wsi->u.ws.rx_user_buffer_head !=
858 wsi->protocol->rx_buffer_size)
859 break;
860
861 /* spill because we filled our rx buffer */
Andy Green4739e5c2011-01-22 12:51:57 +0000862spill:
863 /*
864 * is this frame a control packet we should take care of at this
865 * layer? If so service it and hide it from the user callback
866 */
867
Andy Green43db0452013-01-10 19:50:35 +0800868 lwsl_parser("spill on %s\n", wsi->protocol->name);
Andy Greena41314f2011-05-23 10:00:03 +0100869
Andy Green623a98d2013-01-21 11:04:23 +0800870 switch (wsi->u.ws.opcode) {
Andy Green23545db2011-04-24 06:19:22 +0100871 case LWS_WS_OPCODE_07__CLOSE:
Andy Greenda527df2011-03-07 07:08:12 +0000872 /* is this an acknowledgement of our close? */
873 if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
874 /*
875 * fine he has told us he is closing too, let's
876 * finish our close
877 */
Andy Green43db0452013-01-10 19:50:35 +0800878 lwsl_parser("seen client close ack\n");
Andy Greenda527df2011-03-07 07:08:12 +0000879 return -1;
880 }
Andy Green40d5abc2015-04-17 20:29:58 +0800881 if (wsi->state == WSI_STATE_RETURNED_CLOSE_ALREADY)
882 /* if he sends us 2 CLOSE, kill him */
883 return -1;
884
Andy Green43db0452013-01-10 19:50:35 +0800885 lwsl_parser("server sees client close packet\n");
Andy Green5e1fa172011-02-10 09:07:05 +0000886 wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
Andy Green40d5abc2015-04-17 20:29:58 +0800887 /* deal with the close packet contents as a PONG */
888 wsi->u.ws.payload_is_close = 1;
889 goto process_as_ping;
Andy Green4739e5c2011-01-22 12:51:57 +0000890
Andy Green23545db2011-04-24 06:19:22 +0100891 case LWS_WS_OPCODE_07__PING:
Andy Greenb5b23192013-02-11 17:13:32 +0800892 lwsl_info("received %d byte ping, sending pong\n",
893 wsi->u.ws.rx_user_buffer_head);
Andy Green82bac6b2014-08-24 14:39:19 +0800894
Andy Green2fd6e6f2015-03-24 21:07:01 +0800895 if (wsi->u.ws.ping_pending_flag) {
Andy Green82bac6b2014-08-24 14:39:19 +0800896 /*
897 * there is already a pending ping payload
898 * we should just log and drop
899 */
900 lwsl_parser("DROP PING since one pending\n");
901 goto ping_drop;
902 }
Andy Green40d5abc2015-04-17 20:29:58 +0800903process_as_ping:
Andy Green82bac6b2014-08-24 14:39:19 +0800904 /* control packets can only be < 128 bytes long */
Andy Green106d4a82015-03-24 21:22:52 +0800905 if (wsi->u.ws.rx_user_buffer_head > 128 - 4) {
Andy Green82bac6b2014-08-24 14:39:19 +0800906 lwsl_parser("DROP PING payload too large\n");
907 goto ping_drop;
908 }
909
910 /* if existing buffer is too small, drop it */
911 if (wsi->u.ws.ping_payload_buf &&
912 wsi->u.ws.ping_payload_alloc < wsi->u.ws.rx_user_buffer_head) {
Alejandro Meryac3ec392014-12-05 00:09:20 +0100913 lws_free2(wsi->u.ws.ping_payload_buf);
Andy Green82bac6b2014-08-24 14:39:19 +0800914 }
915
916 /* if no buffer, allocate it */
917 if (!wsi->u.ws.ping_payload_buf) {
Alejandro Mery6ff28242014-12-04 23:59:35 +0100918 wsi->u.ws.ping_payload_buf = lws_malloc(wsi->u.ws.rx_user_buffer_head
919 + LWS_SEND_BUFFER_PRE_PADDING);
Andy Green82bac6b2014-08-24 14:39:19 +0800920 wsi->u.ws.ping_payload_alloc = wsi->u.ws.rx_user_buffer_head;
921 }
922
923 /* stash the pong payload */
924 memcpy(wsi->u.ws.ping_payload_buf + LWS_SEND_BUFFER_PRE_PADDING,
925 &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
926 wsi->u.ws.rx_user_buffer_head);
927
928 wsi->u.ws.ping_payload_len = wsi->u.ws.rx_user_buffer_head;
Andy Green2fd6e6f2015-03-24 21:07:01 +0800929 wsi->u.ws.ping_pending_flag = 1;
Andy Green82bac6b2014-08-24 14:39:19 +0800930
931 /* get it sent as soon as possible */
Andy Green62304762015-12-04 08:43:54 +0800932 lws_callback_on_writable(wsi->protocol->owning_server, wsi);
Andy Green82bac6b2014-08-24 14:39:19 +0800933ping_drop:
Andy Green623a98d2013-01-21 11:04:23 +0800934 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena6cbece2011-01-27 20:06:03 +0000935 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000936
Andy Green23545db2011-04-24 06:19:22 +0100937 case LWS_WS_OPCODE_07__PONG:
John Tarlton05fc6ba2015-10-05 11:35:52 +0100938 lwsl_info("received pong\n");
939 lwsl_hexdump(&wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
940 wsi->u.ws.rx_user_buffer_head);
941
942 /* issue it */
943 callback_action = LWS_CALLBACK_RECEIVE_PONG;
944 break;
Andy Green4739e5c2011-01-22 12:51:57 +0000945
Andy Greena41314f2011-05-23 10:00:03 +0100946 case LWS_WS_OPCODE_07__TEXT_FRAME:
947 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Green2fd3f2f2013-01-18 09:49:20 +0800948 case LWS_WS_OPCODE_07__CONTINUATION:
Andy Green4739e5c2011-01-22 12:51:57 +0000949 break;
Andy Greena41314f2011-05-23 10:00:03 +0100950
951 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800952 lwsl_parser("passing opc %x up to exts\n",
953 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100954 /*
955 * It's something special we can't understand here.
956 * Pass the payload up to the extension's parsing
957 * state machine.
958 */
959
Andy Green623a98d2013-01-21 11:04:23 +0800960 eff_buf.token = &wsi->u.ws.rx_user_buffer[
Andy Greena41314f2011-05-23 10:00:03 +0100961 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800962 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Greena41314f2011-05-23 10:00:03 +0100963
Andy Green2c24ec02014-04-02 19:45:42 +0800964 if (lws_ext_callback_for_each_active(wsi,
965 LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
966 &eff_buf, 0) <= 0) /* not handle or fail */
Andy Greenb5b23192013-02-11 17:13:32 +0800967 lwsl_ext("ext opc opcode 0x%x unknown\n",
968 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100969
Andy Green623a98d2013-01-21 11:04:23 +0800970 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena41314f2011-05-23 10:00:03 +0100971 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000972 }
973
974 /*
975 * No it's real payload, pass it up to the user callback.
976 * It's nicely buffered with the pre-padding taken care of
Andy Green62304762015-12-04 08:43:54 +0800977 * so it can be sent straight out again using lws_write
Andy Green4739e5c2011-01-22 12:51:57 +0000978 */
979
Andy Green623a98d2013-01-21 11:04:23 +0800980 eff_buf.token = &wsi->u.ws.rx_user_buffer[
David Galeanoe2cf9922013-01-09 18:06:55 +0800981 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800982 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Green2c24ec02014-04-02 19:45:42 +0800983
984 if (lws_ext_callback_for_each_active(wsi,
985 LWS_EXT_CALLBACK_PAYLOAD_RX, &eff_buf, 0) < 0)
986 return -1;
987
Andrejs Hanins765914c2015-12-01 14:44:33 +0200988 if (eff_buf.token_len > 0 ||
989 callback_action == LWS_CALLBACK_RECEIVE_PONG) {
Andy Greenaedc9532013-02-10 21:21:24 +0800990 eff_buf.token[eff_buf.token_len] = '\0';
David Galeanoe2cf9922013-01-09 18:06:55 +0800991
John Tarlton05fc6ba2015-10-05 11:35:52 +0100992 if (wsi->protocol->callback) {
993
994 if (callback_action == LWS_CALLBACK_RECEIVE_PONG)
995 lwsl_info("Doing pong callback\n");
996
Andy Greenb5b23192013-02-11 17:13:32 +0800997 ret = user_callback_handle_rxflow(
998 wsi->protocol->callback,
999 wsi->protocol->owning_server,
John Tarlton05fc6ba2015-10-05 11:35:52 +01001000 wsi,
1001 (enum libwebsocket_callback_reasons)callback_action,
Andy Greenb5b23192013-02-11 17:13:32 +08001002 wsi->user_space,
1003 eff_buf.token,
1004 eff_buf.token_len);
John Tarlton05fc6ba2015-10-05 11:35:52 +01001005 }
1006 else
1007 lwsl_err("No callback on payload spill!\n");
David Galeanoe2cf9922013-01-09 18:06:55 +08001008 }
Andy Greena41314f2011-05-23 10:00:03 +01001009
Andy Green623a98d2013-01-21 11:04:23 +08001010 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +00001011 break;
1012 }
1013
Andy Greenaedc9532013-02-10 21:21:24 +08001014 return ret;
Andy Green23545db2011-04-24 06:19:22 +01001015
1016illegal_ctl_length:
1017
Andy Greenb5b23192013-02-11 17:13:32 +08001018 lwsl_warn("Control frame with xtended length is illegal\n");
Andy Green23545db2011-04-24 06:19:22 +01001019 /* kill the connection */
1020 return -1;
Andy Green4739e5c2011-01-22 12:51:57 +00001021}
1022
1023
Andy Green38e57bb2011-01-19 12:20:27 +00001024/**
Andy Green62304762015-12-04 08:43:54 +08001025 * lws_remaining_packet_payload() - Bytes to come before "overall"
Andy Green6964bb52011-01-23 16:50:33 +00001026 * rx packet is complete
Andy Green38e57bb2011-01-19 12:20:27 +00001027 * @wsi: Websocket instance (available from user callback)
1028 *
1029 * This function is intended to be called from the callback if the
1030 * user code is interested in "complete packets" from the client.
1031 * libwebsockets just passes through payload as it comes and issues a buffer
1032 * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE
1033 * callback handler can use this API to find out if the buffer it has just
1034 * been given is the last piece of a "complete packet" from the client --
Andy Green62304762015-12-04 08:43:54 +08001035 * when that is the case lws_remaining_packet_payload() will return
Andy Green38e57bb2011-01-19 12:20:27 +00001036 * 0.
1037 *
1038 * Many protocols won't care becuse their packets are always small.
1039 */
1040
Peter Pentchev9a4fef72013-03-30 09:52:21 +08001041LWS_VISIBLE size_t
Andy Green62304762015-12-04 08:43:54 +08001042lws_remaining_packet_payload(struct libwebsocket *wsi)
Andy Green38e57bb2011-01-19 12:20:27 +00001043{
Andy Green623a98d2013-01-21 11:04:23 +08001044 return wsi->u.ws.rx_packet_length;
Andy Green38e57bb2011-01-19 12:20:27 +00001045}