blob: 423bd21bc5ed92b9079bf9789bca756b8c9aa530 [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 } else { /* b7 = 0, end or 3-byte */
45 if (lextable[pos] < FAIL_CHAR) /* terminal marker */
46 return pos;
Andy Green6d1fcb72013-01-18 01:55:48 +080047
Andy Greenbbc5c072014-03-09 11:49:21 +080048 if (lextable[pos] == c) /* goto */
49 return pos + (lextable[pos + 1]) +
50 (lextable[pos + 2] << 8);
51 /* fall thru goto */
52 pos += 3;
53 /* continue */
54 }
Andy Green6d1fcb72013-01-18 01:55:48 +080055 }
Andy Green6d1fcb72013-01-18 01:55:48 +080056}
57
Andy Green16ab3182013-02-10 18:02:31 +080058int lws_allocate_header_table(struct libwebsocket *wsi)
59{
Andy Greenb5b23192013-02-11 17:13:32 +080060 wsi->u.hdr.ah = malloc(sizeof(*wsi->u.hdr.ah));
Andy Green16ab3182013-02-10 18:02:31 +080061 if (wsi->u.hdr.ah == NULL) {
62 lwsl_err("Out of memory\n");
63 return -1;
64 }
Andy Greenb5b23192013-02-11 17:13:32 +080065 memset(wsi->u.hdr.ah->frag_index, 0, sizeof(wsi->u.hdr.ah->frag_index));
Andy Green16ab3182013-02-10 18:02:31 +080066 wsi->u.hdr.ah->next_frag_index = 0;
67 wsi->u.hdr.ah->pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +080068
Andy Green16ab3182013-02-10 18:02:31 +080069 return 0;
70}
71
Peter Pentchev9a4fef72013-03-30 09:52:21 +080072LWS_VISIBLE int lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +080073{
74 int n;
75 int len = 0;
76
77 n = wsi->u.hdr.ah->frag_index[h];
78 if (n == 0)
79 return 0;
80
81 do {
82 len += wsi->u.hdr.ah->frags[n].len;
83 n = wsi->u.hdr.ah->frags[n].next_frag_index;
84 } while (n);
85
86 return len;
87}
88
Peter Pentchev9a4fef72013-03-30 09:52:21 +080089LWS_VISIBLE int lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len,
Andy Greenb5b23192013-02-11 17:13:32 +080090 enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +080091{
92 int toklen = lws_hdr_total_length(wsi, h);
93 int n;
94
95 if (toklen >= len)
96 return -1;
97
98 n = wsi->u.hdr.ah->frag_index[h];
99 if (n == 0)
100 return 0;
101
102 do {
Andy Greenb5b23192013-02-11 17:13:32 +0800103 strcpy(dest,
104 &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]);
Andy Green16ab3182013-02-10 18:02:31 +0800105 dest += wsi->u.hdr.ah->frags[n].len;
106 n = wsi->u.hdr.ah->frags[n].next_frag_index;
107 } while (n);
108
109 return toklen;
110}
111
Andy Greenb5b23192013-02-11 17:13:32 +0800112char *lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800113{
114 int n;
115
116 n = wsi->u.hdr.ah->frag_index[h];
117 if (!n)
118 return NULL;
119
120 return &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset];
121}
Andy Green6d1fcb72013-01-18 01:55:48 +0800122
Andy Greenb5b23192013-02-11 17:13:32 +0800123int lws_hdr_simple_create(struct libwebsocket *wsi,
124 enum lws_token_indexes h, const char *s)
Andy Greene77fb802013-02-11 13:04:45 +0800125{
126 wsi->u.hdr.ah->next_frag_index++;
Andy Greenb5b23192013-02-11 17:13:32 +0800127 if (wsi->u.hdr.ah->next_frag_index ==
128 sizeof(wsi->u.hdr.ah->frags) / sizeof(wsi->u.hdr.ah->frags[0])) {
129 lwsl_warn("More hdr frags than we can deal with, dropping\n");
Andy Greene77fb802013-02-11 13:04:45 +0800130 return -1;
131 }
132
133 wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->next_frag_index;
134
Andy Greenb5b23192013-02-11 17:13:32 +0800135 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
136 wsi->u.hdr.ah->pos;
Andy Greene77fb802013-02-11 13:04:45 +0800137 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
Andy Greenb5b23192013-02-11 17:13:32 +0800138 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].next_frag_index =
139 0;
Andy Greene77fb802013-02-11 13:04:45 +0800140
141 do {
Andy Greenb5b23192013-02-11 17:13:32 +0800142 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
Andy Greene77fb802013-02-11 13:04:45 +0800143 lwsl_err("Ran out of header data space\n");
144 return -1;
145 }
146 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s;
147 if (*s)
Andy Greenb5b23192013-02-11 17:13:32 +0800148 wsi->u.hdr.ah->frags[
149 wsi->u.hdr.ah->next_frag_index].len++;
Andy Greene77fb802013-02-11 13:04:45 +0800150 } while (*s++);
151
152 return 0;
153}
154
Andy Greenb1a9e502013-11-10 15:15:21 +0800155static char char_to_hex(const char c)
156{
157 if (c >= '0' && c <= '9')
158 return c - '0';
159
160 if (c >= 'a' && c <= 'f')
161 return c - 'a' + 10;
162
163 if (c >= 'A' && c <= 'F')
164 return c - 'A' + 10;
165
166 return -1;
167}
168
169static int issue_char(struct libwebsocket *wsi, unsigned char c)
170{
171 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
172 lwsl_warn("excessive header content\n");
173 return -1;
174 }
175 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c;
176 if (c)
177 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
178
179 return 0;
180}
181
Andy Green7c212cc2010-11-08 20:20:42 +0000182int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
183{
184 int n;
185
Andy Green623a98d2013-01-21 11:04:23 +0800186 switch (wsi->u.hdr.parser_state) {
Andy Green7c212cc2010-11-08 20:20:42 +0000187 case WSI_TOKEN_GET_URI:
kapejodce64fb02013-11-19 13:38:16 +0100188 case WSI_TOKEN_POST_URI:
Andy Green7c212cc2010-11-08 20:20:42 +0000189 case WSI_TOKEN_HOST:
190 case WSI_TOKEN_CONNECTION:
191 case WSI_TOKEN_KEY1:
192 case WSI_TOKEN_KEY2:
193 case WSI_TOKEN_PROTOCOL:
194 case WSI_TOKEN_UPGRADE:
195 case WSI_TOKEN_ORIGIN:
Andy Green4739e5c2011-01-22 12:51:57 +0000196 case WSI_TOKEN_SWORIGIN:
Andy Greence510c62010-11-11 12:48:13 +0000197 case WSI_TOKEN_DRAFT:
Andy Green7c212cc2010-11-08 20:20:42 +0000198 case WSI_TOKEN_CHALLENGE:
Andy Greend1b11e32011-01-18 15:39:02 +0000199 case WSI_TOKEN_KEY:
200 case WSI_TOKEN_VERSION:
Andy Green4739e5c2011-01-22 12:51:57 +0000201 case WSI_TOKEN_ACCEPT:
202 case WSI_TOKEN_NONCE:
Andy Green18910c52011-02-09 08:58:42 +0000203 case WSI_TOKEN_EXTENSIONS:
Andy Green4739e5c2011-01-22 12:51:57 +0000204 case WSI_TOKEN_HTTP:
Andy Greencc13c6f2013-11-09 10:09:09 +0800205 case WSI_TOKEN_HTTP_ACCEPT:
206 case WSI_TOKEN_HTTP_IF_MODIFIED_SINCE:
207 case WSI_TOKEN_HTTP_ACCEPT_ENCODING:
208 case WSI_TOKEN_HTTP_ACCEPT_LANGUAGE:
209 case WSI_TOKEN_HTTP_PRAGMA:
210 case WSI_TOKEN_HTTP_CACHE_CONTROL:
211 case WSI_TOKEN_HTTP_AUTHORIZATION:
212 case WSI_TOKEN_HTTP_COOKIE:
kapejodce64fb02013-11-19 13:38:16 +0100213 case WSI_TOKEN_HTTP_CONTENT_LENGTH:
Andy Greencc13c6f2013-11-09 10:09:09 +0800214 case WSI_TOKEN_HTTP_CONTENT_TYPE:
215 case WSI_TOKEN_HTTP_DATE:
216 case WSI_TOKEN_HTTP_RANGE:
217 case WSI_TOKEN_HTTP_REFERER:
218
Andy Greena41314f2011-05-23 10:00:03 +0100219
Andy Greenb5b23192013-02-11 17:13:32 +0800220 lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c);
Andy Green7c212cc2010-11-08 20:20:42 +0000221
222 /* collect into malloc'd buffers */
Andy Green16ab3182013-02-10 18:02:31 +0800223 /* optional initial space swallow */
Andy Greenb5b23192013-02-11 17:13:32 +0800224 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->frag_index[
225 wsi->u.hdr.parser_state]].len && c == ' ')
Andy Green7c212cc2010-11-08 20:20:42 +0000226 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000227
kapejodce64fb02013-11-19 13:38:16 +0100228 if ((wsi->u.hdr.parser_state != WSI_TOKEN_GET_URI) && (wsi->u.hdr.parser_state != WSI_TOKEN_POST_URI))
Andy Greenb1a9e502013-11-10 15:15:21 +0800229 goto check_eol;
230
231 /* special URI processing... end at space */
232
233 if (c == ' ') {
234 /* enforce starting with / */
235 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len)
236 if (issue_char(wsi, '/') < 0)
237 return -1;
Andy Green16ab3182013-02-10 18:02:31 +0800238 c = '\0';
Andy Green623a98d2013-01-21 11:04:23 +0800239 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
Andy Greenb1a9e502013-11-10 15:15:21 +0800240 goto spill;
Andy Green7c212cc2010-11-08 20:20:42 +0000241 }
242
Andy Greenb1a9e502013-11-10 15:15:21 +0800243 /* special URI processing... convert %xx */
244
245 switch (wsi->u.hdr.ues) {
246 case URIES_IDLE:
247 if (c == '%') {
248 wsi->u.hdr.ues = URIES_SEEN_PERCENT;
249 goto swallow;
250 }
251 break;
252 case URIES_SEEN_PERCENT:
253 if (char_to_hex(c) < 0) {
254 /* regurgitate */
255 if (issue_char(wsi, '%') < 0)
256 return -1;
257 wsi->u.hdr.ues = URIES_IDLE;
258 /* continue on to assess c */
259 break;
260 }
261 wsi->u.hdr.esc_stash = c;
262 wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
Andy Green6f429102013-11-11 06:14:52 +0800263 goto swallow;
Andy Greenb1a9e502013-11-10 15:15:21 +0800264
265 case URIES_SEEN_PERCENT_H1:
266 if (char_to_hex(c) < 0) {
267 /* regurgitate */
268 issue_char(wsi, '%');
269 wsi->u.hdr.ues = URIES_IDLE;
270 /* regurgitate + assess */
271 if (libwebsocket_parse(wsi, wsi->u.hdr.esc_stash) < 0)
272 return -1;
273 /* continue on to assess c */
274 break;
275 }
276 c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
277 char_to_hex(c);
Andy Green6f429102013-11-11 06:14:52 +0800278 wsi->u.hdr.ues = URIES_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800279 break;
280 }
281
282 /*
283 * special URI processing...
Andy Green6f429102013-11-11 06:14:52 +0800284 * convert /.. or /... or /../ etc to /
285 * convert /./ to /
Andy Greenb1a9e502013-11-10 15:15:21 +0800286 * convert // or /// etc to /
287 * leave /.dir or whatever alone
288 */
289
290 switch (wsi->u.hdr.ups) {
291 case URIPS_IDLE:
292 /* issue the first / always */
293 if (c == '/')
294 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
295 break;
296 case URIPS_SEEN_SLASH:
297 /* swallow subsequent slashes */
298 if (c == '/')
299 goto swallow;
300 /* track and swallow the first . after / */
301 if (c == '.') {
302 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT;
303 goto swallow;
304 } else
305 wsi->u.hdr.ups = URIPS_IDLE;
306 break;
307 case URIPS_SEEN_SLASH_DOT:
308 /* swallow second . */
309 if (c == '.') {
Andy Greend3f68732013-11-13 06:53:21 +0800310 /*
311 * back up one dir level if possible
312 * safe against header fragmentation because
313 * the method URI can only be in 1 fragment
314 */
315 if (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 2) {
316 wsi->u.hdr.ah->pos--;
317 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
318 do {
319 wsi->u.hdr.ah->pos--;
320 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
321 } while (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 1 &&
322 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos] != '/');
323 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800324 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
325 goto swallow;
326 }
Andy Green6f429102013-11-11 06:14:52 +0800327 /* change /./ to / */
328 if (c == '/') {
329 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
330 goto swallow;
331 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800332 /* it was like /.dir ... regurgitate the . */
333 wsi->u.hdr.ups = URIPS_IDLE;
334 issue_char(wsi, '.');
335 break;
336
337 case URIPS_SEEN_SLASH_DOT_DOT:
338 /* swallow prior .. chars and any subsequent . */
339 if (c == '.')
340 goto swallow;
Andy Green6f429102013-11-11 06:14:52 +0800341 /* last issued was /, so another / == // */
342 if (c == '/')
343 goto swallow;
Andy Greenb1a9e502013-11-10 15:15:21 +0800344 else /* last we issued was / so SEEN_SLASH */
345 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
346 break;
Andy Green1e3f7b82013-11-13 07:45:17 +0800347 case URIPS_ARGUMENTS:
348 /* leave them alone */
349 break;
Andy Greenb1a9e502013-11-10 15:15:21 +0800350 }
351
352check_eol:
353
Andy Green7c212cc2010-11-08 20:20:42 +0000354 /* bail at EOL */
Andy Greenb5b23192013-02-11 17:13:32 +0800355 if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
356 c == '\x0d') {
Andy Green16ab3182013-02-10 18:02:31 +0800357 c = '\0';
Andy Green623a98d2013-01-21 11:04:23 +0800358 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
Andy Green43db0452013-01-10 19:50:35 +0800359 lwsl_parser("*\n");
Andy Green7c212cc2010-11-08 20:20:42 +0000360 }
361
Andy Green1e3f7b82013-11-13 07:45:17 +0800362 if (c == '?') { /* start of URI arguments */
363 /* seal off uri header */
364 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0';
365
366 /* move to using WSI_TOKEN_HTTP_URI_ARGS */
367 wsi->u.hdr.ah->next_frag_index++;
368 wsi->u.hdr.ah->frags[
369 wsi->u.hdr.ah->next_frag_index].offset =
370 wsi->u.hdr.ah->pos;
371 wsi->u.hdr.ah->frags[
372 wsi->u.hdr.ah->next_frag_index].len = 0;
373 wsi->u.hdr.ah->frags[
374 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
375
376 wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] =
377 wsi->u.hdr.ah->next_frag_index;
378
379 /* defeat normal uri path processing */
380 wsi->u.hdr.ups = URIPS_ARGUMENTS;
381 goto swallow;
382 }
383
Andy Greenb1a9e502013-11-10 15:15:21 +0800384spill:
385 if (issue_char(wsi, c) < 0)
Andy Green16ab3182013-02-10 18:02:31 +0800386 return -1;
Andy Greenb1a9e502013-11-10 15:15:21 +0800387swallow:
Andy Greend1b11e32011-01-18 15:39:02 +0000388 /* per-protocol end of headers management */
Andy Greene77ddd82010-11-13 10:03:47 +0000389
Andy Green16ab3182013-02-10 18:02:31 +0800390 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
391 goto set_parsing_complete;
Andy Greena41314f2011-05-23 10:00:03 +0100392 break;
393
Andy Green7c212cc2010-11-08 20:20:42 +0000394 /* collecting and checking a name part */
395 case WSI_TOKEN_NAME_PART:
Andy Green43db0452013-01-10 19:50:35 +0800396 lwsl_parser("WSI_TOKEN_NAME_PART '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000397
Andy Greenb5b23192013-02-11 17:13:32 +0800398 wsi->u.hdr.lextable_pos =
399 lextable_decode(wsi->u.hdr.lextable_pos, c);
Andy Green16ab3182013-02-10 18:02:31 +0800400
Andy Greene4dffc92013-02-04 09:24:18 +0800401 if (wsi->u.hdr.lextable_pos < 0) {
402 /* this is not a header we know about */
kapejodce64fb02013-11-19 13:38:16 +0100403 if (wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI] || wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI] ||
Andy Green646c98a2013-03-09 09:09:05 +0800404 wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP]) {
Andy Greenb5b23192013-02-11 17:13:32 +0800405 /*
406 * altready had the method, no idea what
407 * this crap is, ignore
408 */
Andy Greene4dffc92013-02-04 09:24:18 +0800409 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
410 break;
411 }
Andy Green3ee9b312013-02-12 12:52:39 +0800412 /*
413 * hm it's an unknown http method in fact,
414 * treat as dangerous
415 */
416
417 lwsl_info("Unknown method - dropping\n");
418 return -1;
Andy Greene4dffc92013-02-04 09:24:18 +0800419 }
Andy Greenbbc5c072014-03-09 11:49:21 +0800420 if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) {
Andy Green6d1fcb72013-01-18 01:55:48 +0800421
Andy Greene4dffc92013-02-04 09:24:18 +0800422 /* terminal state */
423
Andy Greenbbc5c072014-03-09 11:49:21 +0800424 n = (lextable[wsi->u.hdr.lextable_pos] << 8) | lextable[wsi->u.hdr.lextable_pos + 1];
Andy Green6d1fcb72013-01-18 01:55:48 +0800425
Andy Greencc7cb682013-02-18 10:22:42 +0800426 lwsl_parser("known hdr %d\n", n);
Andy Greenfd963302012-04-03 17:02:20 +0200427
Andy Green94f94652013-02-12 13:10:19 +0800428 if (n == WSI_TOKEN_GET_URI &&
429 wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI]) {
430 lwsl_warn("Duplicated GET\n");
431 return -1;
kapejodce64fb02013-11-19 13:38:16 +0100432 } else if (n == WSI_TOKEN_POST_URI &&
433 wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI]) {
434 lwsl_warn("Duplicated POST\n");
435 return -1;
Andy Green94f94652013-02-12 13:10:19 +0800436 }
437
Andy Greenfd963302012-04-03 17:02:20 +0200438 /*
439 * WSORIGIN is protocol equiv to ORIGIN,
440 * JWebSocket likes to send it, map to ORIGIN
441 */
442 if (n == WSI_TOKEN_SWORIGIN)
443 n = WSI_TOKEN_ORIGIN;
444
Andy Green16ab3182013-02-10 18:02:31 +0800445 wsi->u.hdr.parser_state = (enum lws_token_indexes)
446 (WSI_TOKEN_GET_URI + n);
447 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
448 goto set_parsing_complete;
Andy Green6964bb52011-01-23 16:50:33 +0000449
Andy Green16ab3182013-02-10 18:02:31 +0800450 goto start_fragment;
451 }
452 break;
Nick Dowell30592632012-04-05 10:31:48 +0800453
Andy Green16ab3182013-02-10 18:02:31 +0800454start_fragment:
455 wsi->u.hdr.ah->next_frag_index++;
Andy Greenb5b23192013-02-11 17:13:32 +0800456 if (wsi->u.hdr.ah->next_frag_index ==
457 sizeof(wsi->u.hdr.ah->frags) /
458 sizeof(wsi->u.hdr.ah->frags[0])) {
459 lwsl_warn("More hdr frags than we can deal with\n");
Andy Green16ab3182013-02-10 18:02:31 +0800460 return -1;
Andy Green7c212cc2010-11-08 20:20:42 +0000461 }
462
Andy Greenb5b23192013-02-11 17:13:32 +0800463 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
464 wsi->u.hdr.ah->pos;
Andy Green16ab3182013-02-10 18:02:31 +0800465 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
Andy Greenb5b23192013-02-11 17:13:32 +0800466 wsi->u.hdr.ah->frags[
467 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800468
469 n = wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state];
470 if (!n) { /* first fragment */
471 wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state] =
472 wsi->u.hdr.ah->next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800473 break;
474 }
475 /* continuation */
476 while (wsi->u.hdr.ah->frags[n].next_frag_index)
Andy Green16ab3182013-02-10 18:02:31 +0800477 n = wsi->u.hdr.ah->frags[n].next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800478 wsi->u.hdr.ah->frags[n].next_frag_index =
Andy Green16ab3182013-02-10 18:02:31 +0800479 wsi->u.hdr.ah->next_frag_index;
480
Andy Greencc13c6f2013-11-09 10:09:09 +0800481 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
482 lwsl_warn("excessive header content\n");
483 return -1;
Andy Green2b57a342013-02-06 15:15:25 +0900484 }
Andy Green7c212cc2010-11-08 20:20:42 +0000485
Andy Greencc13c6f2013-11-09 10:09:09 +0800486 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = ' ';
487 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
Andy Greene4dffc92013-02-04 09:24:18 +0800488 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000489
Andy Green7c212cc2010-11-08 20:20:42 +0000490 /* skipping arg part of a name we didn't recognize */
491 case WSI_TOKEN_SKIPPING:
Andy Green43db0452013-01-10 19:50:35 +0800492 lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
kapejodce64fb02013-11-19 13:38:16 +0100493
Andy Green7c212cc2010-11-08 20:20:42 +0000494 if (c == '\x0d')
Andy Green623a98d2013-01-21 11:04:23 +0800495 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
Andy Green7c212cc2010-11-08 20:20:42 +0000496 break;
Andy Green177ca782013-02-04 09:09:19 +0800497
Andy Green7c212cc2010-11-08 20:20:42 +0000498 case WSI_TOKEN_SKIPPING_SAW_CR:
Andy Green43db0452013-01-10 19:50:35 +0800499 lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
Andy Green6d1fcb72013-01-18 01:55:48 +0800500 if (c == '\x0a') {
Andy Green623a98d2013-01-21 11:04:23 +0800501 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
502 wsi->u.hdr.lextable_pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +0800503 } else
Andy Green623a98d2013-01-21 11:04:23 +0800504 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
Andy Green7c212cc2010-11-08 20:20:42 +0000505 break;
506 /* we're done, ignore anything else */
kapejodce64fb02013-11-19 13:38:16 +0100507
Andy Green7c212cc2010-11-08 20:20:42 +0000508 case WSI_PARSING_COMPLETE:
Andy Green43db0452013-01-10 19:50:35 +0800509 lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000510 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000511
Andy Green7c212cc2010-11-08 20:20:42 +0000512 default: /* keep gcc happy */
513 break;
514 }
Andy Greene77ddd82010-11-13 10:03:47 +0000515
Andy Green7c212cc2010-11-08 20:20:42 +0000516 return 0;
Andy Green177ca782013-02-04 09:09:19 +0800517
518set_parsing_complete:
519
Andy Green16ab3182013-02-10 18:02:31 +0800520 if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800521 if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
Andy Green2b57a342013-02-06 15:15:25 +0900522 wsi->ietf_spec_revision =
Andy Green16ab3182013-02-10 18:02:31 +0800523 atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
Andy Green177ca782013-02-04 09:09:19 +0800524
Andy Greenb5b23192013-02-11 17:13:32 +0800525 lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision);
Andy Green2b57a342013-02-06 15:15:25 +0900526 }
Andy Green177ca782013-02-04 09:09:19 +0800527 wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE;
Andy Green224149a2013-02-11 21:43:41 +0800528 wsi->hdr_parsing_completed = 1;
Andy Green177ca782013-02-04 09:09:19 +0800529
530 return 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000531}
532
Andy Greenbfb051f2011-02-09 08:49:14 +0000533
Andy Green2fd3f2f2013-01-18 09:49:20 +0800534/**
535 * lws_frame_is_binary: true if the current frame was sent in binary mode
536 *
537 * @wsi: the connection we are inquiring about
538 *
539 * This is intended to be called from the LWS_CALLBACK_RECEIVE callback if
540 * it's interested to see if the frame it's dealing with was sent in binary
541 * mode.
542 */
543
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800544LWS_VISIBLE int lws_frame_is_binary(struct libwebsocket *wsi)
Andy Green2fd3f2f2013-01-18 09:49:20 +0800545{
Andy Green623a98d2013-01-21 11:04:23 +0800546 return wsi->u.ws.frame_is_binary;
Andy Green2fd3f2f2013-01-18 09:49:20 +0800547}
Andy Greenbfb051f2011-02-09 08:49:14 +0000548
Andy Greena41314f2011-05-23 10:00:03 +0100549int
550libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000551{
552 int n;
Andy Greena41314f2011-05-23 10:00:03 +0100553 struct lws_tokens eff_buf;
Andy Greenaedc9532013-02-10 21:21:24 +0800554 int ret = 0;
Andy Green3182ece2013-01-20 17:08:31 +0800555#ifndef LWS_NO_EXTENSIONS
Andy Greena41314f2011-05-23 10:00:03 +0100556 int handled;
557 int m;
Andy Green3182ece2013-01-20 17:08:31 +0800558#endif
Andy Greena41314f2011-05-23 10:00:03 +0100559
Andy Green6ee372f2012-04-09 15:09:01 +0800560#if 0
Andy Green43db0452013-01-10 19:50:35 +0800561 lwsl_debug("RX: %02X ", c);
Andy Green6ee372f2012-04-09 15:09:01 +0800562#endif
Andy Green7c212cc2010-11-08 20:20:42 +0000563
564 switch (wsi->lws_rx_parse_state) {
565 case LWS_RXPS_NEW:
Andy Greene77ddd82010-11-13 10:03:47 +0000566
Andy Green7c212cc2010-11-08 20:20:42 +0000567 switch (wsi->ietf_spec_revision) {
Andy Greend85cb202011-09-25 09:32:54 +0100568 case 13:
Andy Green283d0a22011-04-24 05:46:23 +0100569 /*
570 * no prepended frame key any more
571 */
Andy Green623a98d2013-01-21 11:04:23 +0800572 wsi->u.ws.all_zero_nonce = 1;
Andy Green283d0a22011-04-24 05:46:23 +0100573 goto handle_first;
574
Andy Greenbfb051f2011-02-09 08:49:14 +0000575 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800576 lwsl_warn("lws_rx_sm: unknown spec version %d\n",
577 wsi->ietf_spec_revision);
Andy Greenbfb051f2011-02-09 08:49:14 +0000578 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000579 }
Andy Green6452f1e2010-11-11 09:22:22 +0000580 break;
Andy Green3e5eb782011-01-18 18:14:26 +0000581 case LWS_RXPS_04_MASK_NONCE_1:
Andy Green623a98d2013-01-21 11:04:23 +0800582 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000583 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800584 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000585 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2;
586 break;
587 case LWS_RXPS_04_MASK_NONCE_2:
Andy Green623a98d2013-01-21 11:04:23 +0800588 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000589 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800590 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000591 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3;
592 break;
593 case LWS_RXPS_04_MASK_NONCE_3:
Andy Green623a98d2013-01-21 11:04:23 +0800594 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000595 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800596 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000597
Andy Green3e5eb782011-01-18 18:14:26 +0000598 /*
599 * start from the zero'th byte in the XOR key buffer since
600 * this is the start of a frame with a new key
601 */
602
Andy Green623a98d2013-01-21 11:04:23 +0800603 wsi->u.ws.frame_mask_index = 0;
Andy Green6964bb52011-01-23 16:50:33 +0000604
Andy Green3e5eb782011-01-18 18:14:26 +0000605 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
606 break;
Andy Green38e57bb2011-01-19 12:20:27 +0000607
608 /*
609 * 04 logical framing from the spec (all this is masked when incoming
610 * and has to be unmasked)
611 *
612 * We ignore the possibility of extension data because we don't
613 * negotiate any extensions at the moment.
Andy Green6964bb52011-01-23 16:50:33 +0000614 *
Andy Green38e57bb2011-01-19 12:20:27 +0000615 * 0 1 2 3
616 * 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
617 * +-+-+-+-+-------+-+-------------+-------------------------------+
618 * |F|R|R|R| opcode|R| Payload len | Extended payload length |
619 * |I|S|S|S| (4) |S| (7) | (16/63) |
620 * |N|V|V|V| |V| | (if payload len==126/127) |
621 * | |1|2|3| |4| | |
622 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
623 * | Extended payload length continued, if payload len == 127 |
624 * + - - - - - - - - - - - - - - - +-------------------------------+
625 * | | Extension data |
626 * +-------------------------------+ - - - - - - - - - - - - - - - +
627 * : :
628 * +---------------------------------------------------------------+
629 * : Application data :
630 * +---------------------------------------------------------------+
631 *
632 * We pass payload through to userland as soon as we get it, ignoring
633 * FIN. It's up to userland to buffer it up if it wants to see a
634 * whole unfragmented block of the original size (which may be up to
635 * 2^63 long!)
636 */
637
638 case LWS_RXPS_04_FRAME_HDR_1:
Andy Green283d0a22011-04-24 05:46:23 +0100639handle_first:
640
Andy Green623a98d2013-01-21 11:04:23 +0800641 wsi->u.ws.opcode = c & 0xf;
642 wsi->u.ws.rsv = c & 0x70;
643 wsi->u.ws.final = !!((c >> 7) & 1);
Andy Green1bc12f92013-02-28 17:11:29 +0800644
Andy Green623a98d2013-01-21 11:04:23 +0800645 switch (wsi->u.ws.opcode) {
Andy Green10601c12013-01-19 10:39:35 +0800646 case LWS_WS_OPCODE_07__TEXT_FRAME:
Andy Green10601c12013-01-19 10:39:35 +0800647 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Greenb5b23192013-02-11 17:13:32 +0800648 wsi->u.ws.frame_is_binary =
649 wsi->u.ws.opcode == LWS_WS_OPCODE_07__BINARY_FRAME;
Andy Green10601c12013-01-19 10:39:35 +0800650 break;
651 }
Andy Green38e57bb2011-01-19 12:20:27 +0000652 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
653 break;
654
655 case LWS_RXPS_04_FRAME_HDR_LEN:
Andy Green38e57bb2011-01-19 12:20:27 +0000656
Andy Green623a98d2013-01-21 11:04:23 +0800657 wsi->u.ws.this_frame_masked = !!(c & 0x80);
Andy Green283d0a22011-04-24 05:46:23 +0100658
Andy Green5bf65782011-09-25 10:46:31 +0100659 switch (c & 0x7f) {
Andy Green38e57bb2011-01-19 12:20:27 +0000660 case 126:
661 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800662 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100663 goto illegal_ctl_length;
664
Andy Green38e57bb2011-01-19 12:20:27 +0000665 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
666 break;
667 case 127:
668 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800669 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100670 goto illegal_ctl_length;
671
Andy Green38e57bb2011-01-19 12:20:27 +0000672 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
673 break;
674 default:
Andy Green623a98d2013-01-21 11:04:23 +0800675 wsi->u.ws.rx_packet_length = c & 0x7f;
676 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100677 wsi->lws_rx_parse_state =
678 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
679 else
Andy Green8ea19552014-02-15 16:00:37 +0800680 if (wsi->u.ws.rx_packet_length)
681 wsi->lws_rx_parse_state =
Andy Green38e57bb2011-01-19 12:20:27 +0000682 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green8ea19552014-02-15 16:00:37 +0800683 else {
684 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
685 goto spill;
686 }
Andy Green38e57bb2011-01-19 12:20:27 +0000687 break;
688 }
689 break;
690
691 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
Andy Green623a98d2013-01-21 11:04:23 +0800692 wsi->u.ws.rx_packet_length = c << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000693 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
694 break;
695
696 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
Andy Green623a98d2013-01-21 11:04:23 +0800697 wsi->u.ws.rx_packet_length |= c;
698 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100699 wsi->lws_rx_parse_state =
700 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
701 else
702 wsi->lws_rx_parse_state =
703 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000704 break;
705
706 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
Andy Green38e57bb2011-01-19 12:20:27 +0000707 if (c & 0x80) {
Andy Green43db0452013-01-10 19:50:35 +0800708 lwsl_warn("b63 of length must be zero\n");
Andy Green38e57bb2011-01-19 12:20:27 +0000709 /* kill the connection */
710 return -1;
711 }
Andy Greenf55830d2011-01-27 06:45:53 +0000712#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800713 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
Andy Greenf55830d2011-01-27 06:45:53 +0000714#else
Andy Green623a98d2013-01-21 11:04:23 +0800715 wsi->u.ws.rx_packet_length = 0;
Andy Greenf55830d2011-01-27 06:45:53 +0000716#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000717 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
718 break;
719
720 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
Andy Greenf55830d2011-01-27 06:45:53 +0000721#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800722 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
Andy Greenf55830d2011-01-27 06:45:53 +0000723#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000724 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
725 break;
726
727 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
Andy Greenf55830d2011-01-27 06:45:53 +0000728#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800729 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
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_5;
732 break;
733
734 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
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) << 32;
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_4;
739 break;
740
741 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
Andy Green623a98d2013-01-21 11:04:23 +0800742 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
Andy Green38e57bb2011-01-19 12:20:27 +0000743 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
744 break;
745
746 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
Andy Green623a98d2013-01-21 11:04:23 +0800747 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
Andy Green38e57bb2011-01-19 12:20:27 +0000748 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
749 break;
750
751 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
Andy Green623a98d2013-01-21 11:04:23 +0800752 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000753 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
754 break;
755
756 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
Andy Green623a98d2013-01-21 11:04:23 +0800757 wsi->u.ws.rx_packet_length |= ((size_t)c);
758 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100759 wsi->lws_rx_parse_state =
760 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
761 else
762 wsi->lws_rx_parse_state =
763 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000764 break;
765
Andy Green283d0a22011-04-24 05:46:23 +0100766 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
Andy Green623a98d2013-01-21 11:04:23 +0800767 wsi->u.ws.frame_masking_nonce_04[0] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100768 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800769 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100770 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
771 break;
772
773 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
Andy Green623a98d2013-01-21 11:04:23 +0800774 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100775 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800776 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100777 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
778 break;
779
780 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
Andy Green623a98d2013-01-21 11:04:23 +0800781 wsi->u.ws.frame_masking_nonce_04[2] = 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_4;
785 break;
786
787 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
Andy Green623a98d2013-01-21 11:04:23 +0800788 wsi->u.ws.frame_masking_nonce_04[3] = 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 =
792 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green623a98d2013-01-21 11:04:23 +0800793 wsi->u.ws.frame_mask_index = 0;
Andy Green8ea19552014-02-15 16:00:37 +0800794 if (wsi->u.ws.rx_packet_length == 0) {
795 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
Andy Green1bc12f92013-02-28 17:11:29 +0800796 goto spill;
Andy Green8ea19552014-02-15 16:00:37 +0800797 }
Andy Green283d0a22011-04-24 05:46:23 +0100798 break;
799
800
Andy Green7c212cc2010-11-08 20:20:42 +0000801 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
Andy Green3182ece2013-01-20 17:08:31 +0800802
Andy Green54495112013-02-06 21:10:16 +0900803 if (!wsi->u.ws.rx_user_buffer)
804 lwsl_err("NULL user buffer...\n");
805
Andy Green623a98d2013-01-21 11:04:23 +0800806 if (wsi->u.ws.all_zero_nonce)
807 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
808 (wsi->u.ws.rx_user_buffer_head++)] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000809 else
Andy Green623a98d2013-01-21 11:04:23 +0800810 wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
811 (wsi->u.ws.rx_user_buffer_head++)] =
Andy Greenb5b23192013-02-11 17:13:32 +0800812 c ^ wsi->u.ws.frame_masking_nonce_04[
813 (wsi->u.ws.frame_mask_index++) & 3];
Andy Green4739e5c2011-01-22 12:51:57 +0000814
Andy Green623a98d2013-01-21 11:04:23 +0800815 if (--wsi->u.ws.rx_packet_length == 0) {
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800816 /* spill because we have the whole frame */
Andy Green4739e5c2011-01-22 12:51:57 +0000817 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
818 goto spill;
819 }
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800820
821 /*
822 * if there's no protocol max frame size given, we are
823 * supposed to default to LWS_MAX_SOCKET_IO_BUF
824 */
825
826 if (!wsi->protocol->rx_buffer_size &&
827 wsi->u.ws.rx_user_buffer_head !=
828 LWS_MAX_SOCKET_IO_BUF)
Andy Green4739e5c2011-01-22 12:51:57 +0000829 break;
Andy Greenc2bb3dc2013-02-14 11:25:44 +0800830 else
831 if (wsi->protocol->rx_buffer_size &&
832 wsi->u.ws.rx_user_buffer_head !=
833 wsi->protocol->rx_buffer_size)
834 break;
835
836 /* spill because we filled our rx buffer */
Andy Green4739e5c2011-01-22 12:51:57 +0000837spill:
838 /*
839 * is this frame a control packet we should take care of at this
840 * layer? If so service it and hide it from the user callback
841 */
842
Andy Green43db0452013-01-10 19:50:35 +0800843 lwsl_parser("spill on %s\n", wsi->protocol->name);
Andy Greena41314f2011-05-23 10:00:03 +0100844
Andy Green623a98d2013-01-21 11:04:23 +0800845 switch (wsi->u.ws.opcode) {
Andy Green23545db2011-04-24 06:19:22 +0100846 case LWS_WS_OPCODE_07__CLOSE:
Andy Greenda527df2011-03-07 07:08:12 +0000847 /* is this an acknowledgement of our close? */
848 if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
849 /*
850 * fine he has told us he is closing too, let's
851 * finish our close
852 */
Andy Green43db0452013-01-10 19:50:35 +0800853 lwsl_parser("seen client close ack\n");
Andy Greenda527df2011-03-07 07:08:12 +0000854 return -1;
855 }
Andy Green43db0452013-01-10 19:50:35 +0800856 lwsl_parser("server sees client close packet\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000857 /* parrot the close packet payload back */
858 n = libwebsocket_write(wsi, (unsigned char *)
Andy Greenb5b23192013-02-11 17:13:32 +0800859 &wsi->u.ws.rx_user_buffer[
860 LWS_SEND_BUFFER_PRE_PADDING],
861 wsi->u.ws.rx_user_buffer_head,
862 LWS_WRITE_CLOSE);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800863 if (n < 0)
Andy Green0303db42013-01-17 14:46:43 +0800864 lwsl_info("write of close ack failed %d\n", n);
Andy Green5e1fa172011-02-10 09:07:05 +0000865 wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
Andy Green4739e5c2011-01-22 12:51:57 +0000866 /* close the connection */
867 return -1;
868
Andy Green23545db2011-04-24 06:19:22 +0100869 case LWS_WS_OPCODE_07__PING:
Andy Greenb5b23192013-02-11 17:13:32 +0800870 lwsl_info("received %d byte ping, sending pong\n",
871 wsi->u.ws.rx_user_buffer_head);
872 lwsl_hexdump(&wsi->u.ws.rx_user_buffer[
873 LWS_SEND_BUFFER_PRE_PADDING],
874 wsi->u.ws.rx_user_buffer_head);
Andy Green5e1fa172011-02-10 09:07:05 +0000875 /* parrot the ping packet payload back as a pong */
Andy Green4739e5c2011-01-22 12:51:57 +0000876 n = libwebsocket_write(wsi, (unsigned char *)
Andy Greenb5b23192013-02-11 17:13:32 +0800877 &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
878 wsi->u.ws.rx_user_buffer_head, LWS_WRITE_PONG);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800879 if (n < 0)
880 return -1;
Andy Greena6cbece2011-01-27 20:06:03 +0000881 /* ... then just drop it */
Andy Green623a98d2013-01-21 11:04:23 +0800882 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena6cbece2011-01-27 20:06:03 +0000883 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000884
Andy Green23545db2011-04-24 06:19:22 +0100885 case LWS_WS_OPCODE_07__PONG:
Andy Green4739e5c2011-01-22 12:51:57 +0000886 /* ... then just drop it */
Andy Green623a98d2013-01-21 11:04:23 +0800887 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000888 return 0;
889
Andy Greena41314f2011-05-23 10:00:03 +0100890 case LWS_WS_OPCODE_07__TEXT_FRAME:
891 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Green2fd3f2f2013-01-18 09:49:20 +0800892 case LWS_WS_OPCODE_07__CONTINUATION:
Andy Green4739e5c2011-01-22 12:51:57 +0000893 break;
Andy Greena41314f2011-05-23 10:00:03 +0100894
895 default:
Andy Green3182ece2013-01-20 17:08:31 +0800896#ifndef LWS_NO_EXTENSIONS
Andy Greenb5b23192013-02-11 17:13:32 +0800897 lwsl_parser("passing opc %x up to exts\n",
898 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100899
900 /*
901 * It's something special we can't understand here.
902 * Pass the payload up to the extension's parsing
903 * state machine.
904 */
905
Andy Green623a98d2013-01-21 11:04:23 +0800906 eff_buf.token = &wsi->u.ws.rx_user_buffer[
Andy Greena41314f2011-05-23 10:00:03 +0100907 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800908 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Greena41314f2011-05-23 10:00:03 +0100909
910 handled = 0;
911 for (n = 0; n < wsi->count_active_extensions; n++) {
912 m = wsi->active_extensions[n]->callback(
913 wsi->protocol->owning_server,
914 wsi->active_extensions[n], wsi,
915 LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
916 wsi->active_extensions_user[n],
917 &eff_buf, 0);
918 if (m)
919 handled = 1;
920 }
921
Andy Green25a56b02011-09-25 08:47:57 +0100922 if (!handled)
Andy Green3182ece2013-01-20 17:08:31 +0800923#endif
Andy Greenb5b23192013-02-11 17:13:32 +0800924 lwsl_ext("ext opc opcode 0x%x unknown\n",
925 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100926
Andy Green623a98d2013-01-21 11:04:23 +0800927 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena41314f2011-05-23 10:00:03 +0100928 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000929 }
930
931 /*
932 * No it's real payload, pass it up to the user callback.
933 * It's nicely buffered with the pre-padding taken care of
934 * so it can be sent straight out again using libwebsocket_write
935 */
936
Andy Green623a98d2013-01-21 11:04:23 +0800937 eff_buf.token = &wsi->u.ws.rx_user_buffer[
David Galeanoe2cf9922013-01-09 18:06:55 +0800938 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800939 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Green3182ece2013-01-20 17:08:31 +0800940#ifndef LWS_NO_EXTENSIONS
David Galeanoe2cf9922013-01-09 18:06:55 +0800941 for (n = 0; n < wsi->count_active_extensions; n++) {
942 m = wsi->active_extensions[n]->callback(
943 wsi->protocol->owning_server,
944 wsi->active_extensions[n], wsi,
945 LWS_EXT_CALLBACK_PAYLOAD_RX,
946 wsi->active_extensions_user[n],
947 &eff_buf, 0);
948 if (m < 0) {
Andy Green43db0452013-01-10 19:50:35 +0800949 lwsl_ext(
Andy Greenb5b23192013-02-11 17:13:32 +0800950 "Extension '%s' failed to handle payload!\n",
951 wsi->active_extensions[n]->name);
David Galeanoe2cf9922013-01-09 18:06:55 +0800952 return -1;
953 }
954 }
Andy Green3182ece2013-01-20 17:08:31 +0800955#endif
David Galeanoe2cf9922013-01-09 18:06:55 +0800956 if (eff_buf.token_len > 0) {
Andy Greenaedc9532013-02-10 21:21:24 +0800957 eff_buf.token[eff_buf.token_len] = '\0';
David Galeanoe2cf9922013-01-09 18:06:55 +0800958
Andy Greenaedc9532013-02-10 21:21:24 +0800959 if (wsi->protocol->callback)
Andy Greenb5b23192013-02-11 17:13:32 +0800960 ret = user_callback_handle_rxflow(
961 wsi->protocol->callback,
962 wsi->protocol->owning_server,
963 wsi, LWS_CALLBACK_RECEIVE,
964 wsi->user_space,
965 eff_buf.token,
966 eff_buf.token_len);
David Galeanoe2cf9922013-01-09 18:06:55 +0800967 else
Andy Greenf7609e92013-01-14 13:10:55 +0800968 lwsl_err("No callback on payload spill!\n");
David Galeanoe2cf9922013-01-09 18:06:55 +0800969 }
Andy Greena41314f2011-05-23 10:00:03 +0100970
Andy Green623a98d2013-01-21 11:04:23 +0800971 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000972 break;
973 }
974
Andy Greenaedc9532013-02-10 21:21:24 +0800975 return ret;
Andy Green23545db2011-04-24 06:19:22 +0100976
977illegal_ctl_length:
978
Andy Greenb5b23192013-02-11 17:13:32 +0800979 lwsl_warn("Control frame with xtended length is illegal\n");
Andy Green23545db2011-04-24 06:19:22 +0100980 /* kill the connection */
981 return -1;
Andy Green4739e5c2011-01-22 12:51:57 +0000982}
983
984
Andy Green7c212cc2010-11-08 20:20:42 +0000985int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
986 unsigned char *buf, size_t len)
987{
Andy Greenca0a1292013-03-16 11:24:23 +0800988 size_t n = 0;
Andy Green706961d2013-01-17 16:50:35 +0800989 int m;
Andy Green7c212cc2010-11-08 20:20:42 +0000990
Andy Green3182ece2013-01-20 17:08:31 +0800991#if 0
Andy Green43db0452013-01-10 19:50:35 +0800992 lwsl_parser("received %d byte packet\n", (int)len);
Andy Green0303db42013-01-17 14:46:43 +0800993 lwsl_hexdump(buf, len);
Andy Greenab7d9332010-11-11 13:19:19 +0000994#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000995
Andy Green7c212cc2010-11-08 20:20:42 +0000996 /* let the rx protocol state machine have as much as it needs */
Andy Greene77ddd82010-11-13 10:03:47 +0000997
Andy Green706961d2013-01-17 16:50:35 +0800998 while (n < len) {
Andy Greenca0a1292013-03-16 11:24:23 +0800999 /*
1000 * we were accepting input but now we stopped doing so
1001 */
1002 if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) {
1003 /* his RX is flowcontrolled, don't send remaining now */
Andy Greenb5b23192013-02-11 17:13:32 +08001004 if (!wsi->u.ws.rxflow_buffer) {
1005 /* a new rxflow, buffer it and warn caller */
1006 lwsl_info("new rxflow input buffer len %d\n",
1007 len - n);
1008 wsi->u.ws.rxflow_buffer =
1009 (unsigned char *)malloc(len - n);
Andy Green623a98d2013-01-21 11:04:23 +08001010 wsi->u.ws.rxflow_len = len - n;
1011 wsi->u.ws.rxflow_pos = 0;
Andy Greenb5b23192013-02-11 17:13:32 +08001012 memcpy(wsi->u.ws.rxflow_buffer,
1013 buf + n, len - n);
Andy Greenca0a1292013-03-16 11:24:23 +08001014 } else
Andy Greenb5b23192013-02-11 17:13:32 +08001015 /* rxflow while we were spilling prev rxflow */
Andy Green98ba9e02013-03-23 09:44:47 +08001016 lwsl_info("stalling in existing rxflow buf\n");
Andy Greenca0a1292013-03-16 11:24:23 +08001017
Andy Green706961d2013-01-17 16:50:35 +08001018 return 1;
1019 }
Andy Greenca0a1292013-03-16 11:24:23 +08001020
1021 /* account for what we're using in rxflow buffer */
1022 if (wsi->u.ws.rxflow_buffer)
1023 wsi->u.ws.rxflow_pos++;
1024
1025 /* process the byte */
1026 m = libwebsocket_rx_sm(wsi, buf[n++]);
Andy Green706961d2013-01-17 16:50:35 +08001027 if (m < 0)
Andy Green7c212cc2010-11-08 20:20:42 +00001028 return -1;
Andy Green706961d2013-01-17 16:50:35 +08001029 }
Andy Greene77ddd82010-11-13 10:03:47 +00001030
Andy Green4739e5c2011-01-22 12:51:57 +00001031 return 0;
Andy Green7c212cc2010-11-08 20:20:42 +00001032}
1033
1034
Andy Green38e57bb2011-01-19 12:20:27 +00001035/**
1036 * libwebsockets_remaining_packet_payload() - Bytes to come before "overall"
Andy Green6964bb52011-01-23 16:50:33 +00001037 * rx packet is complete
Andy Green38e57bb2011-01-19 12:20:27 +00001038 * @wsi: Websocket instance (available from user callback)
1039 *
1040 * This function is intended to be called from the callback if the
1041 * user code is interested in "complete packets" from the client.
1042 * libwebsockets just passes through payload as it comes and issues a buffer
1043 * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE
1044 * callback handler can use this API to find out if the buffer it has just
1045 * been given is the last piece of a "complete packet" from the client --
1046 * when that is the case libwebsockets_remaining_packet_payload() will return
1047 * 0.
1048 *
1049 * Many protocols won't care becuse their packets are always small.
1050 */
1051
Peter Pentchev9a4fef72013-03-30 09:52:21 +08001052LWS_VISIBLE size_t
Andy Green38e57bb2011-01-19 12:20:27 +00001053libwebsockets_remaining_packet_payload(struct libwebsocket *wsi)
1054{
Andy Green623a98d2013-01-21 11:04:23 +08001055 return wsi->u.ws.rx_packet_length;
Andy Green38e57bb2011-01-19 12:20:27 +00001056}