blob: 3d67099fba2d94a6fe1c38c0792fd66bcc9c3097 [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 Green2c24ec02014-04-02 19:45:42 +080045 /* b7 = 0, end or 3-byte */
46 if (lextable[pos] < FAIL_CHAR) /* terminal marker */
47 return pos;
48
49 if (lextable[pos] == c) /* goto */
50 return pos + (lextable[pos + 1]) +
51 (lextable[pos + 2] << 8);
52 /* fall thru goto */
53 pos += 3;
54 /* continue */
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];
Andy Green2c24ec02014-04-02 19:45:42 +080078 if (!n)
Andy Green16ab3182013-02-10 18:02:31 +080079 return 0;
Andy Green16ab3182013-02-10 18:02:31 +080080 do {
81 len += wsi->u.hdr.ah->frags[n].len;
82 n = wsi->u.hdr.ah->frags[n].next_frag_index;
83 } while (n);
84
85 return len;
86}
87
Peter Pentchev9a4fef72013-03-30 09:52:21 +080088LWS_VISIBLE int lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len,
Andy Greenb5b23192013-02-11 17:13:32 +080089 enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +080090{
91 int toklen = lws_hdr_total_length(wsi, h);
92 int n;
93
94 if (toklen >= len)
95 return -1;
96
97 n = wsi->u.hdr.ah->frag_index[h];
Andy Green2c24ec02014-04-02 19:45:42 +080098 if (!n)
Andy Green16ab3182013-02-10 18:02:31 +080099 return 0;
100
101 do {
Andy Greenb5b23192013-02-11 17:13:32 +0800102 strcpy(dest,
103 &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]);
Andy Green16ab3182013-02-10 18:02:31 +0800104 dest += wsi->u.hdr.ah->frags[n].len;
105 n = wsi->u.hdr.ah->frags[n].next_frag_index;
106 } while (n);
107
108 return toklen;
109}
110
Andy Greenb5b23192013-02-11 17:13:32 +0800111char *lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800112{
113 int n;
114
115 n = wsi->u.hdr.ah->frag_index[h];
116 if (!n)
117 return NULL;
118
119 return &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset];
120}
Andy Green6d1fcb72013-01-18 01:55:48 +0800121
Andy Greenb5b23192013-02-11 17:13:32 +0800122int lws_hdr_simple_create(struct libwebsocket *wsi,
123 enum lws_token_indexes h, const char *s)
Andy Greene77fb802013-02-11 13:04:45 +0800124{
125 wsi->u.hdr.ah->next_frag_index++;
Andy Greenb5b23192013-02-11 17:13:32 +0800126 if (wsi->u.hdr.ah->next_frag_index ==
127 sizeof(wsi->u.hdr.ah->frags) / sizeof(wsi->u.hdr.ah->frags[0])) {
128 lwsl_warn("More hdr frags than we can deal with, dropping\n");
Andy Greene77fb802013-02-11 13:04:45 +0800129 return -1;
130 }
131
132 wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->next_frag_index;
133
Andy Greenb5b23192013-02-11 17:13:32 +0800134 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
135 wsi->u.hdr.ah->pos;
Andy Greene77fb802013-02-11 13:04:45 +0800136 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
Andy Greenb5b23192013-02-11 17:13:32 +0800137 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].next_frag_index =
138 0;
Andy Greene77fb802013-02-11 13:04:45 +0800139
140 do {
Andy Greenb5b23192013-02-11 17:13:32 +0800141 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
Andy Greene77fb802013-02-11 13:04:45 +0800142 lwsl_err("Ran out of header data space\n");
143 return -1;
144 }
145 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s;
146 if (*s)
Andy Greenb5b23192013-02-11 17:13:32 +0800147 wsi->u.hdr.ah->frags[
148 wsi->u.hdr.ah->next_frag_index].len++;
Andy Greene77fb802013-02-11 13:04:45 +0800149 } while (*s++);
150
151 return 0;
152}
153
Andy Greenb1a9e502013-11-10 15:15:21 +0800154static char char_to_hex(const char c)
155{
156 if (c >= '0' && c <= '9')
157 return c - '0';
158
159 if (c >= 'a' && c <= 'f')
160 return c - 'a' + 10;
161
162 if (c >= 'A' && c <= 'F')
163 return c - 'A' + 10;
164
165 return -1;
166}
167
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400168static int issue_char(struct libwebsocket *wsi, unsigned char c)
Andy Greenb1a9e502013-11-10 15:15:21 +0800169{
170 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
171 lwsl_warn("excessive header content\n");
172 return -1;
173 }
Andrew Canaday74b4a652014-06-29 00:25:19 -0400174
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400175 if( wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len >=
176 wsi->u.hdr.current_token_limit) {
Andrew Canaday74b4a652014-06-29 00:25:19 -0400177 lwsl_warn("header %i exceeds limit\n", wsi->u.hdr.parser_state);
178 return 1;
179 };
180
Andy Greenb1a9e502013-11-10 15:15:21 +0800181 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c;
182 if (c)
183 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
184
185 return 0;
186}
187
Andrew Canaday74b4a652014-06-29 00:25:19 -0400188int libwebsocket_parse(
189 struct libwebsocket_context *context,
190 struct libwebsocket *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000191{
192 int n;
193
Andy Green623a98d2013-01-21 11:04:23 +0800194 switch (wsi->u.hdr.parser_state) {
Andy Green7c212cc2010-11-08 20:20:42 +0000195 case WSI_TOKEN_GET_URI:
kapejodce64fb02013-11-19 13:38:16 +0100196 case WSI_TOKEN_POST_URI:
Andrew Canadayda55fb52014-07-05 10:04:19 +0800197 case WSI_TOKEN_OPTIONS_URI:
Andy Green7c212cc2010-11-08 20:20:42 +0000198 case WSI_TOKEN_HOST:
199 case WSI_TOKEN_CONNECTION:
200 case WSI_TOKEN_KEY1:
201 case WSI_TOKEN_KEY2:
202 case WSI_TOKEN_PROTOCOL:
203 case WSI_TOKEN_UPGRADE:
204 case WSI_TOKEN_ORIGIN:
Andy Green4739e5c2011-01-22 12:51:57 +0000205 case WSI_TOKEN_SWORIGIN:
Andy Greence510c62010-11-11 12:48:13 +0000206 case WSI_TOKEN_DRAFT:
Andy Green7c212cc2010-11-08 20:20:42 +0000207 case WSI_TOKEN_CHALLENGE:
Andy Greend1b11e32011-01-18 15:39:02 +0000208 case WSI_TOKEN_KEY:
209 case WSI_TOKEN_VERSION:
Andy Green4739e5c2011-01-22 12:51:57 +0000210 case WSI_TOKEN_ACCEPT:
211 case WSI_TOKEN_NONCE:
Andy Green18910c52011-02-09 08:58:42 +0000212 case WSI_TOKEN_EXTENSIONS:
Andy Green4739e5c2011-01-22 12:51:57 +0000213 case WSI_TOKEN_HTTP:
Andy Greencc13c6f2013-11-09 10:09:09 +0800214 case WSI_TOKEN_HTTP_ACCEPT:
Andrew Canaday42203272014-06-28 20:19:57 -0400215 case WSI_TOKEN_HTTP_AC_REQUEST_HEADERS:
Andy Greencc13c6f2013-11-09 10:09:09 +0800216 case WSI_TOKEN_HTTP_IF_MODIFIED_SINCE:
Andrew Canaday42203272014-06-28 20:19:57 -0400217 case WSI_TOKEN_HTTP_IF_NONE_MATCH:
Andy Greencc13c6f2013-11-09 10:09:09 +0800218 case WSI_TOKEN_HTTP_ACCEPT_ENCODING:
219 case WSI_TOKEN_HTTP_ACCEPT_LANGUAGE:
220 case WSI_TOKEN_HTTP_PRAGMA:
221 case WSI_TOKEN_HTTP_CACHE_CONTROL:
222 case WSI_TOKEN_HTTP_AUTHORIZATION:
223 case WSI_TOKEN_HTTP_COOKIE:
kapejodce64fb02013-11-19 13:38:16 +0100224 case WSI_TOKEN_HTTP_CONTENT_LENGTH:
Andy Greencc13c6f2013-11-09 10:09:09 +0800225 case WSI_TOKEN_HTTP_CONTENT_TYPE:
226 case WSI_TOKEN_HTTP_DATE:
227 case WSI_TOKEN_HTTP_RANGE:
228 case WSI_TOKEN_HTTP_REFERER:
229
Andy Greena41314f2011-05-23 10:00:03 +0100230
Andy Greenb5b23192013-02-11 17:13:32 +0800231 lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c);
Andy Green7c212cc2010-11-08 20:20:42 +0000232
233 /* collect into malloc'd buffers */
Andy Green16ab3182013-02-10 18:02:31 +0800234 /* optional initial space swallow */
Andy Greenb5b23192013-02-11 17:13:32 +0800235 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->frag_index[
236 wsi->u.hdr.parser_state]].len && c == ' ')
Andy Green7c212cc2010-11-08 20:20:42 +0000237 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000238
Andrew Canadayda55fb52014-07-05 10:04:19 +0800239 if ((wsi->u.hdr.parser_state != WSI_TOKEN_GET_URI) &&
240 (wsi->u.hdr.parser_state != WSI_TOKEN_POST_URI) &&
241 (wsi->u.hdr.parser_state != WSI_TOKEN_OPTIONS_URI))
Andy Greenb1a9e502013-11-10 15:15:21 +0800242 goto check_eol;
243
244 /* special URI processing... end at space */
245
246 if (c == ' ') {
247 /* enforce starting with / */
248 if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len)
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400249 if (issue_char(wsi, '/') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800250 return -1;
Andrew Canadayafe26cf2014-07-13 01:07:36 -0400251
252 /* begin parsing HTTP version: */
253 if (issue_char(wsi, '\0') < 0)
254 return -1;
255 wsi->u.hdr.parser_state = WSI_TOKEN_HTTP;
256 goto start_fragment;
Andy Green7c212cc2010-11-08 20:20:42 +0000257 }
258
Andy Greenb1a9e502013-11-10 15:15:21 +0800259 /* special URI processing... convert %xx */
260
261 switch (wsi->u.hdr.ues) {
262 case URIES_IDLE:
263 if (c == '%') {
264 wsi->u.hdr.ues = URIES_SEEN_PERCENT;
265 goto swallow;
266 }
267 break;
268 case URIES_SEEN_PERCENT:
269 if (char_to_hex(c) < 0) {
270 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400271 if (issue_char(wsi, '%') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800272 return -1;
273 wsi->u.hdr.ues = URIES_IDLE;
274 /* continue on to assess c */
275 break;
276 }
277 wsi->u.hdr.esc_stash = c;
278 wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
Andy Green6f429102013-11-11 06:14:52 +0800279 goto swallow;
Andy Greenb1a9e502013-11-10 15:15:21 +0800280
281 case URIES_SEEN_PERCENT_H1:
282 if (char_to_hex(c) < 0) {
283 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400284 issue_char(wsi, '%');
Andy Greenb1a9e502013-11-10 15:15:21 +0800285 wsi->u.hdr.ues = URIES_IDLE;
286 /* regurgitate + assess */
Andrew Canaday74b4a652014-06-29 00:25:19 -0400287 if (libwebsocket_parse(context, wsi, wsi->u.hdr.esc_stash) < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800288 return -1;
289 /* continue on to assess c */
290 break;
291 }
292 c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
293 char_to_hex(c);
Andy Green6f429102013-11-11 06:14:52 +0800294 wsi->u.hdr.ues = URIES_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800295 break;
296 }
297
298 /*
299 * special URI processing...
Andy Green6f429102013-11-11 06:14:52 +0800300 * convert /.. or /... or /../ etc to /
301 * convert /./ to /
Andy Greenb1a9e502013-11-10 15:15:21 +0800302 * convert // or /// etc to /
303 * leave /.dir or whatever alone
304 */
305
306 switch (wsi->u.hdr.ups) {
307 case URIPS_IDLE:
308 /* issue the first / always */
309 if (c == '/')
310 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
311 break;
312 case URIPS_SEEN_SLASH:
313 /* swallow subsequent slashes */
314 if (c == '/')
315 goto swallow;
316 /* track and swallow the first . after / */
317 if (c == '.') {
318 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT;
319 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800320 }
321 wsi->u.hdr.ups = URIPS_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800322 break;
323 case URIPS_SEEN_SLASH_DOT:
324 /* swallow second . */
325 if (c == '.') {
Andy Greend3f68732013-11-13 06:53:21 +0800326 /*
327 * back up one dir level if possible
328 * safe against header fragmentation because
329 * the method URI can only be in 1 fragment
330 */
331 if (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 2) {
332 wsi->u.hdr.ah->pos--;
333 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
334 do {
335 wsi->u.hdr.ah->pos--;
336 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
337 } while (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 1 &&
338 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos] != '/');
339 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800340 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
341 goto swallow;
342 }
Andy Green6f429102013-11-11 06:14:52 +0800343 /* change /./ to / */
344 if (c == '/') {
345 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
346 goto swallow;
347 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800348 /* it was like /.dir ... regurgitate the . */
349 wsi->u.hdr.ups = URIPS_IDLE;
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400350 issue_char(wsi, '.');
Andy Greenb1a9e502013-11-10 15:15:21 +0800351 break;
352
353 case URIPS_SEEN_SLASH_DOT_DOT:
354 /* swallow prior .. chars and any subsequent . */
355 if (c == '.')
356 goto swallow;
Andy Green6f429102013-11-11 06:14:52 +0800357 /* last issued was /, so another / == // */
358 if (c == '/')
359 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800360 /* last we issued was / so SEEN_SLASH */
361 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
Andy Greenb1a9e502013-11-10 15:15:21 +0800362 break;
Andy Green1e3f7b82013-11-13 07:45:17 +0800363 case URIPS_ARGUMENTS:
364 /* leave them alone */
365 break;
Andy Greenb1a9e502013-11-10 15:15:21 +0800366 }
367
Andy Green1e3f7b82013-11-13 07:45:17 +0800368 if (c == '?') { /* start of URI arguments */
369 /* seal off uri header */
370 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0';
371
372 /* move to using WSI_TOKEN_HTTP_URI_ARGS */
373 wsi->u.hdr.ah->next_frag_index++;
374 wsi->u.hdr.ah->frags[
375 wsi->u.hdr.ah->next_frag_index].offset =
376 wsi->u.hdr.ah->pos;
377 wsi->u.hdr.ah->frags[
378 wsi->u.hdr.ah->next_frag_index].len = 0;
379 wsi->u.hdr.ah->frags[
380 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
381
382 wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] =
383 wsi->u.hdr.ah->next_frag_index;
384
385 /* defeat normal uri path processing */
386 wsi->u.hdr.ups = URIPS_ARGUMENTS;
387 goto swallow;
388 }
389
Andrew Canaday991f1cd2014-07-19 06:58:53 +0800390check_eol:
391
392 /* bail at EOL */
393 if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
394 c == '\x0d') {
395 c = '\0';
396 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
397 lwsl_parser("*\n");
398 }
399
Andy Green4b812fe2014-08-19 18:34:31 +0800400 n = issue_char(wsi, c);
401 if (n < 0)
402 return -1;
403 if (n > 0)
404 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
405
Andy Greenb1a9e502013-11-10 15:15:21 +0800406swallow:
Andy Greend1b11e32011-01-18 15:39:02 +0000407 /* per-protocol end of headers management */
Andy Greene77ddd82010-11-13 10:03:47 +0000408
Andy Green16ab3182013-02-10 18:02:31 +0800409 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
410 goto set_parsing_complete;
Andy Greena41314f2011-05-23 10:00:03 +0100411 break;
412
Andy Green7c212cc2010-11-08 20:20:42 +0000413 /* collecting and checking a name part */
414 case WSI_TOKEN_NAME_PART:
Andy Green43db0452013-01-10 19:50:35 +0800415 lwsl_parser("WSI_TOKEN_NAME_PART '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000416
Andy Greenb5b23192013-02-11 17:13:32 +0800417 wsi->u.hdr.lextable_pos =
418 lextable_decode(wsi->u.hdr.lextable_pos, c);
Andy Green16ab3182013-02-10 18:02:31 +0800419
Andy Greene4dffc92013-02-04 09:24:18 +0800420 if (wsi->u.hdr.lextable_pos < 0) {
421 /* this is not a header we know about */
Andrew Canadayda55fb52014-07-05 10:04:19 +0800422 if (wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI] ||
423 wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI] ||
424 wsi->u.hdr.ah->frag_index[WSI_TOKEN_OPTIONS_URI] ||
425 wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP]) {
Andy Greenb5b23192013-02-11 17:13:32 +0800426 /*
427 * altready had the method, no idea what
428 * this crap is, ignore
429 */
Andy Greene4dffc92013-02-04 09:24:18 +0800430 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
431 break;
432 }
Andy Green3ee9b312013-02-12 12:52:39 +0800433 /*
434 * hm it's an unknown http method in fact,
435 * treat as dangerous
436 */
437
438 lwsl_info("Unknown method - dropping\n");
439 return -1;
Andy Greene4dffc92013-02-04 09:24:18 +0800440 }
Andy Greenbbc5c072014-03-09 11:49:21 +0800441 if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) {
Andy Green6d1fcb72013-01-18 01:55:48 +0800442
Andy Greene4dffc92013-02-04 09:24:18 +0800443 /* terminal state */
444
Andy Greenbbc5c072014-03-09 11:49:21 +0800445 n = (lextable[wsi->u.hdr.lextable_pos] << 8) | lextable[wsi->u.hdr.lextable_pos + 1];
Andy Green6d1fcb72013-01-18 01:55:48 +0800446
Andy Greencc7cb682013-02-18 10:22:42 +0800447 lwsl_parser("known hdr %d\n", n);
Andy Green94f94652013-02-12 13:10:19 +0800448 if (n == WSI_TOKEN_GET_URI &&
449 wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI]) {
450 lwsl_warn("Duplicated GET\n");
451 return -1;
kapejodce64fb02013-11-19 13:38:16 +0100452 } else if (n == WSI_TOKEN_POST_URI &&
453 wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI]) {
454 lwsl_warn("Duplicated POST\n");
455 return -1;
Andrew Canadayda55fb52014-07-05 10:04:19 +0800456 } else if (n == WSI_TOKEN_OPTIONS_URI &&
457 wsi->u.hdr.ah->frag_index[WSI_TOKEN_OPTIONS_URI]) {
458 lwsl_warn("Duplicated OPTIONS\n");
459 return -1;
Andy Green94f94652013-02-12 13:10:19 +0800460 }
461
Andy Greenfd963302012-04-03 17:02:20 +0200462 /*
463 * WSORIGIN is protocol equiv to ORIGIN,
464 * JWebSocket likes to send it, map to ORIGIN
465 */
466 if (n == WSI_TOKEN_SWORIGIN)
467 n = WSI_TOKEN_ORIGIN;
468
Andy Green16ab3182013-02-10 18:02:31 +0800469 wsi->u.hdr.parser_state = (enum lws_token_indexes)
470 (WSI_TOKEN_GET_URI + n);
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400471
472 if( context->token_limits ) {
473 wsi->u.hdr.current_token_limit = \
474 context->token_limits->token_limit[wsi->u.hdr.parser_state];
475 }
476 else {
477 wsi->u.hdr.current_token_limit = sizeof(wsi->u.hdr.ah->data);
478 };
479
Andy Green16ab3182013-02-10 18:02:31 +0800480 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
481 goto set_parsing_complete;
Andy Green6964bb52011-01-23 16:50:33 +0000482
Andy Green16ab3182013-02-10 18:02:31 +0800483 goto start_fragment;
484 }
485 break;
Nick Dowell30592632012-04-05 10:31:48 +0800486
Andy Green16ab3182013-02-10 18:02:31 +0800487start_fragment:
488 wsi->u.hdr.ah->next_frag_index++;
Andy Greenb5b23192013-02-11 17:13:32 +0800489 if (wsi->u.hdr.ah->next_frag_index ==
490 sizeof(wsi->u.hdr.ah->frags) /
491 sizeof(wsi->u.hdr.ah->frags[0])) {
492 lwsl_warn("More hdr frags than we can deal with\n");
Andy Green16ab3182013-02-10 18:02:31 +0800493 return -1;
Andy Green7c212cc2010-11-08 20:20:42 +0000494 }
495
Andy Greenb5b23192013-02-11 17:13:32 +0800496 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
497 wsi->u.hdr.ah->pos;
Andy Green16ab3182013-02-10 18:02:31 +0800498 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
Andy Greenb5b23192013-02-11 17:13:32 +0800499 wsi->u.hdr.ah->frags[
500 wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800501
502 n = wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state];
503 if (!n) { /* first fragment */
504 wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state] =
505 wsi->u.hdr.ah->next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800506 break;
507 }
508 /* continuation */
509 while (wsi->u.hdr.ah->frags[n].next_frag_index)
Andy Green16ab3182013-02-10 18:02:31 +0800510 n = wsi->u.hdr.ah->frags[n].next_frag_index;
Andy Greencc13c6f2013-11-09 10:09:09 +0800511 wsi->u.hdr.ah->frags[n].next_frag_index =
Andy Green16ab3182013-02-10 18:02:31 +0800512 wsi->u.hdr.ah->next_frag_index;
513
Andy Greencc13c6f2013-11-09 10:09:09 +0800514 if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
515 lwsl_warn("excessive header content\n");
516 return -1;
Andy Green2b57a342013-02-06 15:15:25 +0900517 }
Andy Green7c212cc2010-11-08 20:20:42 +0000518
Andy Greencc13c6f2013-11-09 10:09:09 +0800519 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = ' ';
520 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
Andy Greene4dffc92013-02-04 09:24:18 +0800521 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000522
Andy Green7c212cc2010-11-08 20:20:42 +0000523 /* skipping arg part of a name we didn't recognize */
524 case WSI_TOKEN_SKIPPING:
Andy Green43db0452013-01-10 19:50:35 +0800525 lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
kapejodce64fb02013-11-19 13:38:16 +0100526
Andy Green7c212cc2010-11-08 20:20:42 +0000527 if (c == '\x0d')
Andy Green623a98d2013-01-21 11:04:23 +0800528 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
Andy Green7c212cc2010-11-08 20:20:42 +0000529 break;
Andy Green177ca782013-02-04 09:09:19 +0800530
Andy Green7c212cc2010-11-08 20:20:42 +0000531 case WSI_TOKEN_SKIPPING_SAW_CR:
Andy Green43db0452013-01-10 19:50:35 +0800532 lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
Andy Green6d1fcb72013-01-18 01:55:48 +0800533 if (c == '\x0a') {
Andy Green623a98d2013-01-21 11:04:23 +0800534 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
535 wsi->u.hdr.lextable_pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +0800536 } else
Andy Green623a98d2013-01-21 11:04:23 +0800537 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
Andy Green7c212cc2010-11-08 20:20:42 +0000538 break;
539 /* we're done, ignore anything else */
kapejodce64fb02013-11-19 13:38:16 +0100540
Andy Green7c212cc2010-11-08 20:20:42 +0000541 case WSI_PARSING_COMPLETE:
Andy Green43db0452013-01-10 19:50:35 +0800542 lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000543 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000544
Andy Green7c212cc2010-11-08 20:20:42 +0000545 default: /* keep gcc happy */
546 break;
547 }
Andy Greene77ddd82010-11-13 10:03:47 +0000548
Andy Green7c212cc2010-11-08 20:20:42 +0000549 return 0;
Andy Green177ca782013-02-04 09:09:19 +0800550
551set_parsing_complete:
552
Andy Green16ab3182013-02-10 18:02:31 +0800553 if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800554 if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
Andy Green2b57a342013-02-06 15:15:25 +0900555 wsi->ietf_spec_revision =
Andy Green16ab3182013-02-10 18:02:31 +0800556 atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
Andy Green177ca782013-02-04 09:09:19 +0800557
Andy Greenb5b23192013-02-11 17:13:32 +0800558 lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision);
Andy Green2b57a342013-02-06 15:15:25 +0900559 }
Andy Green177ca782013-02-04 09:09:19 +0800560 wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE;
Andy Green224149a2013-02-11 21:43:41 +0800561 wsi->hdr_parsing_completed = 1;
Andy Green177ca782013-02-04 09:09:19 +0800562
563 return 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000564}
565
Andy Greenbfb051f2011-02-09 08:49:14 +0000566
Andy Green2fd3f2f2013-01-18 09:49:20 +0800567/**
568 * lws_frame_is_binary: true if the current frame was sent in binary mode
569 *
570 * @wsi: the connection we are inquiring about
571 *
572 * This is intended to be called from the LWS_CALLBACK_RECEIVE callback if
573 * it's interested to see if the frame it's dealing with was sent in binary
574 * mode.
575 */
576
Peter Pentchev9a4fef72013-03-30 09:52:21 +0800577LWS_VISIBLE int lws_frame_is_binary(struct libwebsocket *wsi)
Andy Green2fd3f2f2013-01-18 09:49:20 +0800578{
Andy Green623a98d2013-01-21 11:04:23 +0800579 return wsi->u.ws.frame_is_binary;
Andy Green2fd3f2f2013-01-18 09:49:20 +0800580}
Andy Greenbfb051f2011-02-09 08:49:14 +0000581
Andy Greena41314f2011-05-23 10:00:03 +0100582int
583libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000584{
585 int n;
Andy Greena41314f2011-05-23 10:00:03 +0100586 struct lws_tokens eff_buf;
Andy Greenaedc9532013-02-10 21:21:24 +0800587 int ret = 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000588
589 switch (wsi->lws_rx_parse_state) {
590 case LWS_RXPS_NEW:
Andy Greene77ddd82010-11-13 10:03:47 +0000591
Andy Green7c212cc2010-11-08 20:20:42 +0000592 switch (wsi->ietf_spec_revision) {
Andy Greend85cb202011-09-25 09:32:54 +0100593 case 13:
Andy Green283d0a22011-04-24 05:46:23 +0100594 /*
595 * no prepended frame key any more
596 */
Andy Green623a98d2013-01-21 11:04:23 +0800597 wsi->u.ws.all_zero_nonce = 1;
Andy Green283d0a22011-04-24 05:46:23 +0100598 goto handle_first;
599
Andy Greenbfb051f2011-02-09 08:49:14 +0000600 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800601 lwsl_warn("lws_rx_sm: unknown spec version %d\n",
602 wsi->ietf_spec_revision);
Andy Greenbfb051f2011-02-09 08:49:14 +0000603 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000604 }
Andy Green6452f1e2010-11-11 09:22:22 +0000605 break;
Andy Green3e5eb782011-01-18 18:14:26 +0000606 case LWS_RXPS_04_MASK_NONCE_1:
Andy Green623a98d2013-01-21 11:04:23 +0800607 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000608 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800609 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000610 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2;
611 break;
612 case LWS_RXPS_04_MASK_NONCE_2:
Andy Green623a98d2013-01-21 11:04:23 +0800613 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000614 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800615 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000616 wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3;
617 break;
618 case LWS_RXPS_04_MASK_NONCE_3:
Andy Green623a98d2013-01-21 11:04:23 +0800619 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000620 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800621 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000622
Andy Green3e5eb782011-01-18 18:14:26 +0000623 /*
624 * start from the zero'th byte in the XOR key buffer since
625 * this is the start of a frame with a new key
626 */
627
Andy Green623a98d2013-01-21 11:04:23 +0800628 wsi->u.ws.frame_mask_index = 0;
Andy Green6964bb52011-01-23 16:50:33 +0000629
Andy Green3e5eb782011-01-18 18:14:26 +0000630 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
631 break;
Andy Green38e57bb2011-01-19 12:20:27 +0000632
633 /*
634 * 04 logical framing from the spec (all this is masked when incoming
635 * and has to be unmasked)
636 *
637 * We ignore the possibility of extension data because we don't
638 * negotiate any extensions at the moment.
Andy Green6964bb52011-01-23 16:50:33 +0000639 *
Andy Green38e57bb2011-01-19 12:20:27 +0000640 * 0 1 2 3
641 * 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
642 * +-+-+-+-+-------+-+-------------+-------------------------------+
643 * |F|R|R|R| opcode|R| Payload len | Extended payload length |
644 * |I|S|S|S| (4) |S| (7) | (16/63) |
645 * |N|V|V|V| |V| | (if payload len==126/127) |
646 * | |1|2|3| |4| | |
647 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
648 * | Extended payload length continued, if payload len == 127 |
649 * + - - - - - - - - - - - - - - - +-------------------------------+
650 * | | Extension data |
651 * +-------------------------------+ - - - - - - - - - - - - - - - +
652 * : :
653 * +---------------------------------------------------------------+
654 * : Application data :
655 * +---------------------------------------------------------------+
656 *
657 * We pass payload through to userland as soon as we get it, ignoring
658 * FIN. It's up to userland to buffer it up if it wants to see a
659 * whole unfragmented block of the original size (which may be up to
660 * 2^63 long!)
661 */
662
663 case LWS_RXPS_04_FRAME_HDR_1:
Andy Green283d0a22011-04-24 05:46:23 +0100664handle_first:
665
Andy Green623a98d2013-01-21 11:04:23 +0800666 wsi->u.ws.opcode = c & 0xf;
667 wsi->u.ws.rsv = c & 0x70;
668 wsi->u.ws.final = !!((c >> 7) & 1);
Andy Green1bc12f92013-02-28 17:11:29 +0800669
Andy Green623a98d2013-01-21 11:04:23 +0800670 switch (wsi->u.ws.opcode) {
Andy Green10601c12013-01-19 10:39:35 +0800671 case LWS_WS_OPCODE_07__TEXT_FRAME:
Andy Green10601c12013-01-19 10:39:35 +0800672 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Greenb5b23192013-02-11 17:13:32 +0800673 wsi->u.ws.frame_is_binary =
674 wsi->u.ws.opcode == LWS_WS_OPCODE_07__BINARY_FRAME;
Andy Green10601c12013-01-19 10:39:35 +0800675 break;
676 }
Andy Green38e57bb2011-01-19 12:20:27 +0000677 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
678 break;
679
680 case LWS_RXPS_04_FRAME_HDR_LEN:
Andy Green38e57bb2011-01-19 12:20:27 +0000681
Andy Green623a98d2013-01-21 11:04:23 +0800682 wsi->u.ws.this_frame_masked = !!(c & 0x80);
Andy Green283d0a22011-04-24 05:46:23 +0100683
Andy Green5bf65782011-09-25 10:46:31 +0100684 switch (c & 0x7f) {
Andy Green38e57bb2011-01-19 12:20:27 +0000685 case 126:
686 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800687 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100688 goto illegal_ctl_length;
689
Andy Green38e57bb2011-01-19 12:20:27 +0000690 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
691 break;
692 case 127:
693 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800694 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100695 goto illegal_ctl_length;
696
Andy Green38e57bb2011-01-19 12:20:27 +0000697 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
698 break;
699 default:
Andy Green623a98d2013-01-21 11:04:23 +0800700 wsi->u.ws.rx_packet_length = c & 0x7f;
701 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100702 wsi->lws_rx_parse_state =
703 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
704 else
Andy Green8ea19552014-02-15 16:00:37 +0800705 if (wsi->u.ws.rx_packet_length)
706 wsi->lws_rx_parse_state =
Andy Green38e57bb2011-01-19 12:20:27 +0000707 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green8ea19552014-02-15 16:00:37 +0800708 else {
709 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
710 goto spill;
711 }
Andy Green38e57bb2011-01-19 12:20:27 +0000712 break;
713 }
714 break;
715
716 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
Andy Green623a98d2013-01-21 11:04:23 +0800717 wsi->u.ws.rx_packet_length = c << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000718 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
719 break;
720
721 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
Andy Green623a98d2013-01-21 11:04:23 +0800722 wsi->u.ws.rx_packet_length |= c;
723 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100724 wsi->lws_rx_parse_state =
725 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
726 else
727 wsi->lws_rx_parse_state =
728 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000729 break;
730
731 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
Andy Green38e57bb2011-01-19 12:20:27 +0000732 if (c & 0x80) {
Andy Green43db0452013-01-10 19:50:35 +0800733 lwsl_warn("b63 of length must be zero\n");
Andy Green38e57bb2011-01-19 12:20:27 +0000734 /* kill the connection */
735 return -1;
736 }
Andy Greenf55830d2011-01-27 06:45:53 +0000737#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800738 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
Andy Greenf55830d2011-01-27 06:45:53 +0000739#else
Andy Green623a98d2013-01-21 11:04:23 +0800740 wsi->u.ws.rx_packet_length = 0;
Andy Greenf55830d2011-01-27 06:45:53 +0000741#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000742 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
743 break;
744
745 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
Andy Greenf55830d2011-01-27 06:45:53 +0000746#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800747 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
Andy Greenf55830d2011-01-27 06:45:53 +0000748#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000749 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
750 break;
751
752 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
Andy Greenf55830d2011-01-27 06:45:53 +0000753#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800754 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
Andy Greenf55830d2011-01-27 06:45:53 +0000755#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000756 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
757 break;
758
759 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
Andy Greenf55830d2011-01-27 06:45:53 +0000760#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800761 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
Andy Greenf55830d2011-01-27 06:45:53 +0000762#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000763 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
764 break;
765
766 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
Andy Green623a98d2013-01-21 11:04:23 +0800767 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
Andy Green38e57bb2011-01-19 12:20:27 +0000768 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
769 break;
770
771 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
Andy Green623a98d2013-01-21 11:04:23 +0800772 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
Andy Green38e57bb2011-01-19 12:20:27 +0000773 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
774 break;
775
776 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
Andy Green623a98d2013-01-21 11:04:23 +0800777 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000778 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
779 break;
780
781 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
Andy Green623a98d2013-01-21 11:04:23 +0800782 wsi->u.ws.rx_packet_length |= ((size_t)c);
783 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100784 wsi->lws_rx_parse_state =
785 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
786 else
787 wsi->lws_rx_parse_state =
788 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000789 break;
790
Andy Green283d0a22011-04-24 05:46:23 +0100791 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
Andy Green623a98d2013-01-21 11:04:23 +0800792 wsi->u.ws.frame_masking_nonce_04[0] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100793 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800794 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100795 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
796 break;
797
798 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
Andy Green623a98d2013-01-21 11:04:23 +0800799 wsi->u.ws.frame_masking_nonce_04[1] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100800 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800801 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100802 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
803 break;
804
805 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
Andy Green623a98d2013-01-21 11:04:23 +0800806 wsi->u.ws.frame_masking_nonce_04[2] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100807 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800808 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100809 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
810 break;
811
812 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
Andy Green623a98d2013-01-21 11:04:23 +0800813 wsi->u.ws.frame_masking_nonce_04[3] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100814 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800815 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100816 wsi->lws_rx_parse_state =
817 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green623a98d2013-01-21 11:04:23 +0800818 wsi->u.ws.frame_mask_index = 0;
Andy Green8ea19552014-02-15 16:00:37 +0800819 if (wsi->u.ws.rx_packet_length == 0) {
820 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
Andy Green1bc12f92013-02-28 17:11:29 +0800821 goto spill;
Andy Green8ea19552014-02-15 16:00:37 +0800822 }
Andy Green283d0a22011-04-24 05:46:23 +0100823 break;
824
825
Andy Green7c212cc2010-11-08 20:20:42 +0000826 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
Andy Green3182ece2013-01-20 17:08:31 +0800827
Andy Green54495112013-02-06 21:10:16 +0900828 if (!wsi->u.ws.rx_user_buffer)
829 lwsl_err("NULL user buffer...\n");
830
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 Green43db0452013-01-10 19:50:35 +0800881 lwsl_parser("server sees client close packet\n");
Andy Green4739e5c2011-01-22 12:51:57 +0000882 /* parrot the close packet payload back */
883 n = libwebsocket_write(wsi, (unsigned char *)
Andy Greenb5b23192013-02-11 17:13:32 +0800884 &wsi->u.ws.rx_user_buffer[
885 LWS_SEND_BUFFER_PRE_PADDING],
886 wsi->u.ws.rx_user_buffer_head,
887 LWS_WRITE_CLOSE);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800888 if (n < 0)
Andy Green0303db42013-01-17 14:46:43 +0800889 lwsl_info("write of close ack failed %d\n", n);
Andy Green5e1fa172011-02-10 09:07:05 +0000890 wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
Andy Green4739e5c2011-01-22 12:51:57 +0000891 /* close the connection */
892 return -1;
893
Andy Green23545db2011-04-24 06:19:22 +0100894 case LWS_WS_OPCODE_07__PING:
Andy Greenb5b23192013-02-11 17:13:32 +0800895 lwsl_info("received %d byte ping, sending pong\n",
896 wsi->u.ws.rx_user_buffer_head);
897 lwsl_hexdump(&wsi->u.ws.rx_user_buffer[
898 LWS_SEND_BUFFER_PRE_PADDING],
899 wsi->u.ws.rx_user_buffer_head);
Andy Green5e1fa172011-02-10 09:07:05 +0000900 /* parrot the ping packet payload back as a pong */
Andy Green4739e5c2011-01-22 12:51:57 +0000901 n = libwebsocket_write(wsi, (unsigned char *)
Andy Greenb5b23192013-02-11 17:13:32 +0800902 &wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
903 wsi->u.ws.rx_user_buffer_head, LWS_WRITE_PONG);
Andy Greenfc7c5e42013-02-23 10:50:10 +0800904 if (n < 0)
905 return -1;
Andy Greena6cbece2011-01-27 20:06:03 +0000906 /* ... then just drop it */
Andy Green623a98d2013-01-21 11:04:23 +0800907 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena6cbece2011-01-27 20:06:03 +0000908 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000909
Andy Green23545db2011-04-24 06:19:22 +0100910 case LWS_WS_OPCODE_07__PONG:
Andy Green4739e5c2011-01-22 12:51:57 +0000911 /* ... then just drop it */
Andy Green623a98d2013-01-21 11:04:23 +0800912 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000913 return 0;
914
Andy Greena41314f2011-05-23 10:00:03 +0100915 case LWS_WS_OPCODE_07__TEXT_FRAME:
916 case LWS_WS_OPCODE_07__BINARY_FRAME:
Andy Green2fd3f2f2013-01-18 09:49:20 +0800917 case LWS_WS_OPCODE_07__CONTINUATION:
Andy Green4739e5c2011-01-22 12:51:57 +0000918 break;
Andy Greena41314f2011-05-23 10:00:03 +0100919
920 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800921 lwsl_parser("passing opc %x up to exts\n",
922 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100923 /*
924 * It's something special we can't understand here.
925 * Pass the payload up to the extension's parsing
926 * state machine.
927 */
928
Andy Green623a98d2013-01-21 11:04:23 +0800929 eff_buf.token = &wsi->u.ws.rx_user_buffer[
Andy Greena41314f2011-05-23 10:00:03 +0100930 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800931 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Greena41314f2011-05-23 10:00:03 +0100932
Andy Green2c24ec02014-04-02 19:45:42 +0800933 if (lws_ext_callback_for_each_active(wsi,
934 LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
935 &eff_buf, 0) <= 0) /* not handle or fail */
Andy Greenb5b23192013-02-11 17:13:32 +0800936 lwsl_ext("ext opc opcode 0x%x unknown\n",
937 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +0100938
Andy Green623a98d2013-01-21 11:04:23 +0800939 wsi->u.ws.rx_user_buffer_head = 0;
Andy Greena41314f2011-05-23 10:00:03 +0100940 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000941 }
942
943 /*
944 * No it's real payload, pass it up to the user callback.
945 * It's nicely buffered with the pre-padding taken care of
946 * so it can be sent straight out again using libwebsocket_write
947 */
948
Andy Green623a98d2013-01-21 11:04:23 +0800949 eff_buf.token = &wsi->u.ws.rx_user_buffer[
David Galeanoe2cf9922013-01-09 18:06:55 +0800950 LWS_SEND_BUFFER_PRE_PADDING];
Andy Green623a98d2013-01-21 11:04:23 +0800951 eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
Andy Green2c24ec02014-04-02 19:45:42 +0800952
953 if (lws_ext_callback_for_each_active(wsi,
954 LWS_EXT_CALLBACK_PAYLOAD_RX, &eff_buf, 0) < 0)
955 return -1;
956
David Galeanoe2cf9922013-01-09 18:06:55 +0800957 if (eff_buf.token_len > 0) {
Andy Greenaedc9532013-02-10 21:21:24 +0800958 eff_buf.token[eff_buf.token_len] = '\0';
David Galeanoe2cf9922013-01-09 18:06:55 +0800959
Andy Greenaedc9532013-02-10 21:21:24 +0800960 if (wsi->protocol->callback)
Andy Greenb5b23192013-02-11 17:13:32 +0800961 ret = user_callback_handle_rxflow(
962 wsi->protocol->callback,
963 wsi->protocol->owning_server,
964 wsi, LWS_CALLBACK_RECEIVE,
965 wsi->user_space,
966 eff_buf.token,
967 eff_buf.token_len);
David Galeanoe2cf9922013-01-09 18:06:55 +0800968 else
Andy Greenf7609e92013-01-14 13:10:55 +0800969 lwsl_err("No callback on payload spill!\n");
David Galeanoe2cf9922013-01-09 18:06:55 +0800970 }
Andy Greena41314f2011-05-23 10:00:03 +0100971
Andy Green623a98d2013-01-21 11:04:23 +0800972 wsi->u.ws.rx_user_buffer_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +0000973 break;
974 }
975
Andy Greenaedc9532013-02-10 21:21:24 +0800976 return ret;
Andy Green23545db2011-04-24 06:19:22 +0100977
978illegal_ctl_length:
979
Andy Greenb5b23192013-02-11 17:13:32 +0800980 lwsl_warn("Control frame with xtended length is illegal\n");
Andy Green23545db2011-04-24 06:19:22 +0100981 /* kill the connection */
982 return -1;
Andy Green4739e5c2011-01-22 12:51:57 +0000983}
984
985
Andy Green38e57bb2011-01-19 12:20:27 +0000986/**
987 * libwebsockets_remaining_packet_payload() - Bytes to come before "overall"
Andy Green6964bb52011-01-23 16:50:33 +0000988 * rx packet is complete
Andy Green38e57bb2011-01-19 12:20:27 +0000989 * @wsi: Websocket instance (available from user callback)
990 *
991 * This function is intended to be called from the callback if the
992 * user code is interested in "complete packets" from the client.
993 * libwebsockets just passes through payload as it comes and issues a buffer
994 * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE
995 * callback handler can use this API to find out if the buffer it has just
996 * been given is the last piece of a "complete packet" from the client --
997 * when that is the case libwebsockets_remaining_packet_payload() will return
998 * 0.
999 *
1000 * Many protocols won't care becuse their packets are always small.
1001 */
1002
Peter Pentchev9a4fef72013-03-30 09:52:21 +08001003LWS_VISIBLE size_t
Andy Green38e57bb2011-01-19 12:20:27 +00001004libwebsockets_remaining_packet_payload(struct libwebsocket *wsi)
1005{
Andy Green623a98d2013-01-21 11:04:23 +08001006 return wsi->u.ws.rx_packet_length;
Andy Green38e57bb2011-01-19 12:20:27 +00001007}