blob: d1e84ac2c4e103360d1ba2d398d9f74070ce78f9 [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 Greenf38ad332016-01-20 07:55:41 +080032 if (c >= 'A' && c <= 'Z')
33 c += 'a' - 'A';
Andy Greenbbc5c072014-03-09 11:49:21 +080034
35 while (1) {
36 if (lextable[pos] & (1 << 7)) { /* 1-byte, fail on mismatch */
37 if ((lextable[pos] & 0x7f) != c)
38 return -1;
39 /* fall thru */
40 pos++;
41 if (lextable[pos] == FAIL_CHAR)
42 return -1;
Andy Green6d1fcb72013-01-18 01:55:48 +080043 return pos;
Andy Greenbbc5c072014-03-09 11:49:21 +080044 }
Andy Greenf012f752014-08-22 19:38:17 +080045
46 if (lextable[pos] == FAIL_CHAR)
47 return -1;
48
Andy Green2c24ec02014-04-02 19:45:42 +080049 /* b7 = 0, end or 3-byte */
50 if (lextable[pos] < FAIL_CHAR) /* terminal marker */
51 return pos;
52
53 if (lextable[pos] == c) /* goto */
54 return pos + (lextable[pos + 1]) +
55 (lextable[pos + 2] << 8);
56 /* fall thru goto */
57 pos += 3;
58 /* continue */
Andy Green6d1fcb72013-01-18 01:55:48 +080059 }
Andy Green6d1fcb72013-01-18 01:55:48 +080060}
61
Andy Green4b85c1d2015-12-04 11:08:32 +080062int lws_allocate_header_table(struct lws *wsi)
Andy Green16ab3182013-02-10 18:02:31 +080063{
Andy Green3df58002015-12-25 12:44:12 +080064 struct lws_context *context = wsi->context;
65 int n;
66
67 lwsl_debug("%s: wsi %p: ah %p\n", __func__, (void *)wsi,
68 (void *)wsi->u.hdr.ah);
69
70 /* if we are already bound to one, just clear it down */
71 if (wsi->u.hdr.ah)
72 goto reset;
73 /*
74 * server should have suppressed the accept of a new wsi before this
75 * became the case. If initiating multiple client connects, make sure
76 * the ah pool is big enough to cope, or be prepared to retry
77 */
78 if (context->ah_count_in_use == context->max_http_header_pool) {
79 lwsl_err("No free ah\n");
Andy Green16ab3182013-02-10 18:02:31 +080080 return -1;
81 }
Andy Green3df58002015-12-25 12:44:12 +080082
83 for (n = 0; n < context->max_http_header_pool; n++)
84 if (!context->ah_pool[n].in_use)
85 break;
86
87 /* if the count of in use said something free... */
88 assert(n != context->max_http_header_pool);
89
90 wsi->u.hdr.ah = &context->ah_pool[n];
91 wsi->u.hdr.ah->in_use = 1;
92
93 context->ah_count_in_use++;
94 /* if we used up all the ah, defeat accepting new server connections */
95 if (context->ah_count_in_use == context->max_http_header_pool)
96 if (_lws_server_listen_accept_flow_control(context, 0))
97 return 1;
98
99 lwsl_debug("%s: wsi %p: ah %p: count %d (on exit)\n",
100 __func__, (void *)wsi, (void *)wsi->u.hdr.ah,
101 context->ah_count_in_use);
102
103reset:
104 /* init the ah to reflect no headers or data have appeared yet */
Andy Greenb5b23192013-02-11 17:13:32 +0800105 memset(wsi->u.hdr.ah->frag_index, 0, sizeof(wsi->u.hdr.ah->frag_index));
Andy Green6b5de702015-12-15 21:15:58 +0800106 wsi->u.hdr.ah->nfrag = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800107 wsi->u.hdr.ah->pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +0800108
Andy Green16ab3182013-02-10 18:02:31 +0800109 return 0;
110}
111
Andy Green4b85c1d2015-12-04 11:08:32 +0800112int lws_free_header_table(struct lws *wsi)
Andrew Canaday37718812014-11-07 11:20:59 +0800113{
Andy Green3df58002015-12-25 12:44:12 +0800114 struct lws_context *context = wsi->context;
115
116 lwsl_debug("%s: wsi %p: ah %p (count = %d)\n", __func__, (void *)wsi,
117 (void *)wsi->u.hdr.ah, context->ah_count_in_use);
118
119 assert(wsi->u.hdr.ah);
120 if (!wsi->u.hdr.ah)
121 return 0;
122
123 /* if we think we're freeing one, there should be one to free */
124 assert(context->ah_count_in_use > 0);
125
126 assert(wsi->u.hdr.ah->in_use);
127 wsi->u.hdr.ah->in_use = 0;
128
129 /* if we just freed up one ah, allow new server connection */
130 if (context->ah_count_in_use == context->max_http_header_pool)
131 if (_lws_server_listen_accept_flow_control(context, 1))
132 return 1;
133
134 context->ah_count_in_use--;
Alejandro Meryac3ec392014-12-05 00:09:20 +0100135 wsi->u.hdr.ah = NULL;
Andy Green3df58002015-12-25 12:44:12 +0800136
Alejandro Mery6ff28242014-12-04 23:59:35 +0100137 return 0;
Andy Green3df58002015-12-25 12:44:12 +0800138}
Andrew Canaday37718812014-11-07 11:20:59 +0800139
Andy Green0c7e5a92015-12-30 14:53:50 +0800140/**
141 * lws_hdr_fragment_length: report length of a single fragment of a header
142 * The returned length does not include the space for a
143 * terminating '\0'
144 *
145 * @wsi: websocket connection
146 * @h: which header index we are interested in
147 * @frag_idx: which fragment of @h we want to get the length of
148 */
149
Andy Greene974f0c2015-12-19 07:35:23 +0800150LWS_VISIBLE int
151lws_hdr_fragment_length(struct lws *wsi, enum lws_token_indexes h, int frag_idx)
152{
153 int n;
154
155 n = wsi->u.hdr.ah->frag_index[h];
156 if (!n)
157 return 0;
158 do {
159 if (!frag_idx)
160 return wsi->u.hdr.ah->frags[n].len;
161 n = wsi->u.hdr.ah->frags[n].nfrag;
162 } while (frag_idx-- && n);
163
164 return 0;
165}
166
Andy Green0c7e5a92015-12-30 14:53:50 +0800167/**
168 * lws_hdr_total_length: report length of all fragments of a header totalled up
169 * The returned length does not include the space for a
170 * terminating '\0'
171 *
172 * @wsi: websocket connection
173 * @h: which header index we are interested in
174 */
175
Andy Green4b85c1d2015-12-04 11:08:32 +0800176LWS_VISIBLE int lws_hdr_total_length(struct lws *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800177{
178 int n;
179 int len = 0;
180
181 n = wsi->u.hdr.ah->frag_index[h];
Andy Green2c24ec02014-04-02 19:45:42 +0800182 if (!n)
Andy Green16ab3182013-02-10 18:02:31 +0800183 return 0;
Andy Green16ab3182013-02-10 18:02:31 +0800184 do {
185 len += wsi->u.hdr.ah->frags[n].len;
Andy Green6b5de702015-12-15 21:15:58 +0800186 n = wsi->u.hdr.ah->frags[n].nfrag;
Andy Green16ab3182013-02-10 18:02:31 +0800187 } while (n);
188
189 return len;
190}
191
Andy Green0c7e5a92015-12-30 14:53:50 +0800192/**
193 * lws_hdr_copy_fragment: copy a single fragment of the given header to a buffer
194 * The buffer length @len must include space for an additional
195 * terminating '\0', or it will fail returning -1.
196 * If the requested fragment index is not present, it fails
197 * returning -1.
198 *
199 * @wsi: websocket connection
200 * @dst: destination buffer
201 * @len: length of destination buffer
202 * @h: which header index we are interested in
203 * @frag_index: which fragment of @h we want to copy
204 */
205
Andy Green566eb432015-12-15 22:59:23 +0800206LWS_VISIBLE int lws_hdr_copy_fragment(struct lws *wsi, char *dst, int len,
207 enum lws_token_indexes h, int frag_idx)
208{
209 int n = 0;
210 int f = wsi->u.hdr.ah->frag_index[h];
211
212 while (n < frag_idx) {
213 f = wsi->u.hdr.ah->frags[f].nfrag;
214 if (!f)
215 return -1;
216 n++;
217 }
218
Andy Green9f54c1f2015-12-18 16:40:02 +0800219 if (wsi->u.hdr.ah->frags[f].len >= len)
Andy Green566eb432015-12-15 22:59:23 +0800220 return -1;
221
Andy Green3df58002015-12-25 12:44:12 +0800222 memcpy(dst, wsi->u.hdr.ah->data + wsi->u.hdr.ah->frags[f].offset,
Andy Green566eb432015-12-15 22:59:23 +0800223 wsi->u.hdr.ah->frags[f].len);
224 dst[wsi->u.hdr.ah->frags[f].len] = '\0';
225
226 return wsi->u.hdr.ah->frags[f].len;
227}
228
Andy Green0c7e5a92015-12-30 14:53:50 +0800229/**
230 * lws_hdr_copy: copy a single fragment of the given header to a buffer
231 * The buffer length @len must include space for an additional
232 * terminating '\0', or it will fail returning -1.
233 *
234 * @wsi: websocket connection
235 * @dst: destination buffer
236 * @len: length of destination buffer
237 * @h: which header index we are interested in
238 */
239
Andy Green6b5de702015-12-15 21:15:58 +0800240LWS_VISIBLE int lws_hdr_copy(struct lws *wsi, char *dst, int len,
Andy Green5c9660d2015-12-04 11:30:53 +0800241 enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800242{
243 int toklen = lws_hdr_total_length(wsi, h);
244 int n;
245
246 if (toklen >= len)
247 return -1;
248
249 n = wsi->u.hdr.ah->frag_index[h];
Andy Green2c24ec02014-04-02 19:45:42 +0800250 if (!n)
Andy Green16ab3182013-02-10 18:02:31 +0800251 return 0;
252
253 do {
Andy Green6b5de702015-12-15 21:15:58 +0800254 strcpy(dst, &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]);
255 dst += wsi->u.hdr.ah->frags[n].len;
256 n = wsi->u.hdr.ah->frags[n].nfrag;
Andy Green16ab3182013-02-10 18:02:31 +0800257 } while (n);
258
259 return toklen;
260}
261
Andy Green4b85c1d2015-12-04 11:08:32 +0800262char *lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h)
Andy Green16ab3182013-02-10 18:02:31 +0800263{
264 int n;
265
266 n = wsi->u.hdr.ah->frag_index[h];
267 if (!n)
268 return NULL;
269
Andy Green3df58002015-12-25 12:44:12 +0800270 return wsi->u.hdr.ah->data + wsi->u.hdr.ah->frags[n].offset;
Andy Green16ab3182013-02-10 18:02:31 +0800271}
Andy Green6d1fcb72013-01-18 01:55:48 +0800272
Andy Green6b5de702015-12-15 21:15:58 +0800273int lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h,
274 const char *s)
Andy Greene77fb802013-02-11 13:04:45 +0800275{
Andy Green6b5de702015-12-15 21:15:58 +0800276 wsi->u.hdr.ah->nfrag++;
277 if (wsi->u.hdr.ah->nfrag == ARRAY_SIZE(wsi->u.hdr.ah->frags)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800278 lwsl_warn("More hdr frags than we can deal with, dropping\n");
Andy Greene77fb802013-02-11 13:04:45 +0800279 return -1;
280 }
281
Andy Green6b5de702015-12-15 21:15:58 +0800282 wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->nfrag;
Andy Greene77fb802013-02-11 13:04:45 +0800283
Andy Green6b5de702015-12-15 21:15:58 +0800284 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].offset = wsi->u.hdr.ah->pos;
285 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len = 0;
286 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].nfrag = 0;
Andy Greene77fb802013-02-11 13:04:45 +0800287
288 do {
Andy Green3df58002015-12-25 12:44:12 +0800289 if (wsi->u.hdr.ah->pos == wsi->context->max_http_header_data) {
Andy Greene77fb802013-02-11 13:04:45 +0800290 lwsl_err("Ran out of header data space\n");
291 return -1;
292 }
293 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s;
294 if (*s)
Andy Green6b5de702015-12-15 21:15:58 +0800295 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len++;
Andy Greene77fb802013-02-11 13:04:45 +0800296 } while (*s++);
297
298 return 0;
299}
300
Andy Green2a5774e2015-03-30 18:56:52 +0800301static signed char char_to_hex(const char c)
Andy Greenb1a9e502013-11-10 15:15:21 +0800302{
303 if (c >= '0' && c <= '9')
304 return c - '0';
305
306 if (c >= 'a' && c <= 'f')
307 return c - 'a' + 10;
308
309 if (c >= 'A' && c <= 'F')
310 return c - 'A' + 10;
311
312 return -1;
313}
314
Andy Green4b85c1d2015-12-04 11:08:32 +0800315static int issue_char(struct lws *wsi, unsigned char c)
Andy Greenb1a9e502013-11-10 15:15:21 +0800316{
Andrew Canadayffe64562015-11-29 19:26:01 +0800317 unsigned short frag_len;
Andy Green6b5de702015-12-15 21:15:58 +0800318
Andy Green3df58002015-12-25 12:44:12 +0800319 if (wsi->u.hdr.ah->pos == wsi->context->max_http_header_data) {
Andy Greenb1a9e502013-11-10 15:15:21 +0800320 lwsl_warn("excessive header content\n");
321 return -1;
322 }
Andrew Canaday74b4a652014-06-29 00:25:19 -0400323
Andy Green6b5de702015-12-15 21:15:58 +0800324 frag_len = wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len;
325 /*
326 * If we haven't hit the token limit, just copy the character into
327 * the header
328 */
329 if (frag_len < wsi->u.hdr.current_token_limit) {
Andrew Canaday4cfc42c2015-11-29 19:24:04 +0800330 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c;
331 if (c)
Andy Green6b5de702015-12-15 21:15:58 +0800332 wsi->u.hdr.ah->frags[wsi->u.hdr.ah->nfrag].len++;
Andrew Canaday4cfc42c2015-11-29 19:24:04 +0800333 return 0;
334 }
Andy Green6b5de702015-12-15 21:15:58 +0800335
336 /* Insert a null character when we *hit* the limit: */
337 if (frag_len == wsi->u.hdr.current_token_limit) {
Andy Greenbc401292016-01-20 07:40:13 +0800338 if (wsi->u.hdr.ah->pos == wsi->context->max_http_header_data) {
339 lwsl_warn("excessive header content 2\n");
340 return -1;
341 }
Andy Green6b5de702015-12-15 21:15:58 +0800342 wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0';
Andy Green3df58002015-12-25 12:44:12 +0800343 lwsl_warn("header %i exceeds limit %d\n",
344 wsi->u.hdr.parser_state, wsi->u.hdr.current_token_limit);
Andy Green6b5de702015-12-15 21:15:58 +0800345 }
346
Andrew Canaday4cfc42c2015-11-29 19:24:04 +0800347 return 1;
Andy Greenb1a9e502013-11-10 15:15:21 +0800348}
349
Andy Green6b5de702015-12-15 21:15:58 +0800350int lws_parse(struct lws *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000351{
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800352 static const unsigned char methods[] = {
353 WSI_TOKEN_GET_URI,
354 WSI_TOKEN_POST_URI,
355 WSI_TOKEN_OPTIONS_URI,
356 WSI_TOKEN_PUT_URI,
357 WSI_TOKEN_PATCH_URI,
358 WSI_TOKEN_DELETE_URI,
359 };
Andy Green6b5de702015-12-15 21:15:58 +0800360 struct allocated_headers *ah = wsi->u.hdr.ah;
361 struct lws_context *context = wsi->context;
Andy Green38f32252015-12-14 19:42:26 +0800362 unsigned int n, m, enc = 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000363
Andy Green623a98d2013-01-21 11:04:23 +0800364 switch (wsi->u.hdr.parser_state) {
Andy Greenb08cb502014-09-30 16:33:56 +0800365 default:
Andy Greena41314f2011-05-23 10:00:03 +0100366
Andy Greenb5b23192013-02-11 17:13:32 +0800367 lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c);
Andy Green7c212cc2010-11-08 20:20:42 +0000368
369 /* collect into malloc'd buffers */
Andy Green16ab3182013-02-10 18:02:31 +0800370 /* optional initial space swallow */
Andy Green6b5de702015-12-15 21:15:58 +0800371 if (!ah->frags[ah->frag_index[
Andy Greenb5b23192013-02-11 17:13:32 +0800372 wsi->u.hdr.parser_state]].len && c == ' ')
Andy Green7c212cc2010-11-08 20:20:42 +0000373 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000374
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800375 for (m = 0; m < ARRAY_SIZE(methods); m++)
376 if (wsi->u.hdr.parser_state == methods[m])
377 break;
378 if (m == ARRAY_SIZE(methods))
379 /* it was not any of the methods */
Andy Greenb1a9e502013-11-10 15:15:21 +0800380 goto check_eol;
381
382 /* special URI processing... end at space */
383
384 if (c == ' ') {
385 /* enforce starting with / */
Andy Green6b5de702015-12-15 21:15:58 +0800386 if (!ah->frags[ah->nfrag].len)
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400387 if (issue_char(wsi, '/') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800388 return -1;
Andrew Canadayafe26cf2014-07-13 01:07:36 -0400389
390 /* begin parsing HTTP version: */
391 if (issue_char(wsi, '\0') < 0)
392 return -1;
393 wsi->u.hdr.parser_state = WSI_TOKEN_HTTP;
394 goto start_fragment;
Andy Green7c212cc2010-11-08 20:20:42 +0000395 }
396
Andy Greenb1a9e502013-11-10 15:15:21 +0800397 /* special URI processing... convert %xx */
398
399 switch (wsi->u.hdr.ues) {
400 case URIES_IDLE:
401 if (c == '%') {
402 wsi->u.hdr.ues = URIES_SEEN_PERCENT;
403 goto swallow;
404 }
405 break;
406 case URIES_SEEN_PERCENT:
407 if (char_to_hex(c) < 0) {
408 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400409 if (issue_char(wsi, '%') < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800410 return -1;
411 wsi->u.hdr.ues = URIES_IDLE;
412 /* continue on to assess c */
413 break;
414 }
415 wsi->u.hdr.esc_stash = c;
416 wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
Andy Green6f429102013-11-11 06:14:52 +0800417 goto swallow;
Andy Green40110e82015-12-14 08:52:03 +0800418
Andy Greenb1a9e502013-11-10 15:15:21 +0800419 case URIES_SEEN_PERCENT_H1:
420 if (char_to_hex(c) < 0) {
421 /* regurgitate */
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400422 issue_char(wsi, '%');
Andy Greenb1a9e502013-11-10 15:15:21 +0800423 wsi->u.hdr.ues = URIES_IDLE;
424 /* regurgitate + assess */
Andy Green6b5de702015-12-15 21:15:58 +0800425 if (lws_parse(wsi, wsi->u.hdr.esc_stash) < 0)
Andy Greenb1a9e502013-11-10 15:15:21 +0800426 return -1;
427 /* continue on to assess c */
428 break;
429 }
430 c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
431 char_to_hex(c);
Andy Green38f32252015-12-14 19:42:26 +0800432 enc = 1;
Andy Green6f429102013-11-11 06:14:52 +0800433 wsi->u.hdr.ues = URIES_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800434 break;
435 }
436
437 /*
Andy Green40110e82015-12-14 08:52:03 +0800438 * special URI processing...
Andy Green6f429102013-11-11 06:14:52 +0800439 * convert /.. or /... or /../ etc to /
440 * convert /./ to /
Andy Greenb1a9e502013-11-10 15:15:21 +0800441 * convert // or /// etc to /
442 * leave /.dir or whatever alone
443 */
444
445 switch (wsi->u.hdr.ups) {
446 case URIPS_IDLE:
Andy Greenbc401292016-01-20 07:40:13 +0800447 if (!c)
448 return -1;
Andy Green4eb36372015-12-15 22:57:19 +0800449 /* genuine delimiter */
Andy Green03d7e9d2015-12-18 15:20:09 +0800450 if ((c == '&' || c == ';') && !enc) {
Andy Greenbc401292016-01-20 07:40:13 +0800451 if (issue_char(wsi, c) < 0)
452 return -1;
Andy Green4eb36372015-12-15 22:57:19 +0800453 /* swallow the terminator */
454 ah->frags[ah->nfrag].len--;
455 /* link to next fragment */
456 ah->frags[ah->nfrag].nfrag = ah->nfrag + 1;
457 ah->nfrag++;
458 if (ah->nfrag >= ARRAY_SIZE(ah->frags))
459 goto excessive;
460 /* start next fragment after the & */
Andy Green3ba035d2015-12-18 15:40:03 +0800461 wsi->u.hdr.post_literal_equal = 0;
Andy Green4eb36372015-12-15 22:57:19 +0800462 ah->frags[ah->nfrag].offset = ah->pos;
463 ah->frags[ah->nfrag].len = 0;
464 ah->frags[ah->nfrag].nfrag = 0;
465 goto swallow;
466 }
Andy Green3ba035d2015-12-18 15:40:03 +0800467 /* uriencoded = in the name part, disallow */
468 if (c == '=' && enc && !wsi->u.hdr.post_literal_equal)
469 c = '_';
470
471 /* after the real =, we don't care how many = */
472 if (c == '=' && !enc)
473 wsi->u.hdr.post_literal_equal = 1;
474
Andy Green8b9fe992015-12-18 15:23:31 +0800475 /* + to space */
476 if (c == '+' && !enc)
477 c = ' ';
Andy Greenb1a9e502013-11-10 15:15:21 +0800478 /* issue the first / always */
Andy Green4eb36372015-12-15 22:57:19 +0800479 if (c == '/' && !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS])
Andy Greenb1a9e502013-11-10 15:15:21 +0800480 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
481 break;
482 case URIPS_SEEN_SLASH:
483 /* swallow subsequent slashes */
484 if (c == '/')
485 goto swallow;
486 /* track and swallow the first . after / */
487 if (c == '.') {
488 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT;
489 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800490 }
491 wsi->u.hdr.ups = URIPS_IDLE;
Andy Greenb1a9e502013-11-10 15:15:21 +0800492 break;
493 case URIPS_SEEN_SLASH_DOT:
494 /* swallow second . */
495 if (c == '.') {
Andy Green40110e82015-12-14 08:52:03 +0800496 /*
Andy Greend3f68732013-11-13 06:53:21 +0800497 * back up one dir level if possible
498 * safe against header fragmentation because
499 * the method URI can only be in 1 fragment
500 */
Andy Green6b5de702015-12-15 21:15:58 +0800501 if (ah->frags[ah->nfrag].len > 2) {
502 ah->pos--;
503 ah->frags[ah->nfrag].len--;
Andy Greend3f68732013-11-13 06:53:21 +0800504 do {
Andy Green6b5de702015-12-15 21:15:58 +0800505 ah->pos--;
506 ah->frags[ah->nfrag].len--;
507 } while (ah->frags[ah->nfrag].len > 1 &&
508 ah->data[ah->pos] != '/');
Andy Greend3f68732013-11-13 06:53:21 +0800509 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800510 wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
511 goto swallow;
512 }
Andy Green6f429102013-11-11 06:14:52 +0800513 /* change /./ to / */
514 if (c == '/') {
515 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
516 goto swallow;
517 }
Andy Greenb1a9e502013-11-10 15:15:21 +0800518 /* it was like /.dir ... regurgitate the . */
519 wsi->u.hdr.ups = URIPS_IDLE;
Andy Green4eb36372015-12-15 22:57:19 +0800520 if (issue_char(wsi, '.') < 0)
521 return -1;
Andy Greenb1a9e502013-11-10 15:15:21 +0800522 break;
Andy Green40110e82015-12-14 08:52:03 +0800523
Andy Greenb1a9e502013-11-10 15:15:21 +0800524 case URIPS_SEEN_SLASH_DOT_DOT:
525 /* swallow prior .. chars and any subsequent . */
526 if (c == '.')
527 goto swallow;
Andy Green6f429102013-11-11 06:14:52 +0800528 /* last issued was /, so another / == // */
529 if (c == '/')
530 goto swallow;
Andy Green4b812fe2014-08-19 18:34:31 +0800531 /* last we issued was / so SEEN_SLASH */
532 wsi->u.hdr.ups = URIPS_SEEN_SLASH;
Andy Greenb1a9e502013-11-10 15:15:21 +0800533 break;
534 }
535
Andy Green4eb36372015-12-15 22:57:19 +0800536 if (c == '?' && !enc &&
537 !ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS]) { /* start of URI arguments */
Andy Green1e3f7b82013-11-13 07:45:17 +0800538 /* seal off uri header */
Andy Greenbc401292016-01-20 07:40:13 +0800539 if (issue_char(wsi, '\0') < 0)
540 return -1;
Andy Green1e3f7b82013-11-13 07:45:17 +0800541
542 /* move to using WSI_TOKEN_HTTP_URI_ARGS */
Andy Green6b5de702015-12-15 21:15:58 +0800543 ah->nfrag++;
Andy Green4eb36372015-12-15 22:57:19 +0800544 if (ah->nfrag >= ARRAY_SIZE(ah->frags))
545 goto excessive;
Andy Green6b5de702015-12-15 21:15:58 +0800546 ah->frags[ah->nfrag].offset = ah->pos;
547 ah->frags[ah->nfrag].len = 0;
548 ah->frags[ah->nfrag].nfrag = 0;
Andy Green1e3f7b82013-11-13 07:45:17 +0800549
Andy Green3ba035d2015-12-18 15:40:03 +0800550 wsi->u.hdr.post_literal_equal = 0;
Andy Green6b5de702015-12-15 21:15:58 +0800551 ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] = ah->nfrag;
Andy Greenf35801b2015-12-15 23:05:23 +0800552 wsi->u.hdr.ups = URIPS_IDLE;
Andy Green1e3f7b82013-11-13 07:45:17 +0800553 goto swallow;
554 }
555
Andrew Canaday991f1cd2014-07-19 06:58:53 +0800556check_eol:
557
558 /* bail at EOL */
559 if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
560 c == '\x0d') {
561 c = '\0';
562 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
563 lwsl_parser("*\n");
564 }
565
Andy Green4b812fe2014-08-19 18:34:31 +0800566 n = issue_char(wsi, c);
Andy Green2cd30742015-11-02 13:10:33 +0800567 if ((int)n < 0)
Andy Green4b812fe2014-08-19 18:34:31 +0800568 return -1;
569 if (n > 0)
570 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
571
Andy Greenb1a9e502013-11-10 15:15:21 +0800572swallow:
Andy Greend1b11e32011-01-18 15:39:02 +0000573 /* per-protocol end of headers management */
Andy Greene77ddd82010-11-13 10:03:47 +0000574
Andy Green16ab3182013-02-10 18:02:31 +0800575 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
576 goto set_parsing_complete;
Andy Greena41314f2011-05-23 10:00:03 +0100577 break;
578
Andy Green7c212cc2010-11-08 20:20:42 +0000579 /* collecting and checking a name part */
580 case WSI_TOKEN_NAME_PART:
Andy Green8fb338f2015-04-07 08:19:30 +0800581 lwsl_parser("WSI_TOKEN_NAME_PART '%c' (mode=%d)\n", c, wsi->mode);
Andy Green7c212cc2010-11-08 20:20:42 +0000582
Andy Greenb5b23192013-02-11 17:13:32 +0800583 wsi->u.hdr.lextable_pos =
584 lextable_decode(wsi->u.hdr.lextable_pos, c);
Andy Green8fb338f2015-04-07 08:19:30 +0800585 /*
586 * Server needs to look out for unknown methods...
587 */
588 if (wsi->u.hdr.lextable_pos < 0 &&
Andy Green54806b12015-12-17 17:03:59 +0800589 wsi->mode == LWSCM_HTTP_SERVING) {
Andy Greene4dffc92013-02-04 09:24:18 +0800590 /* this is not a header we know about */
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800591 for (m = 0; m < ARRAY_SIZE(methods); m++)
Andy Green6b5de702015-12-15 21:15:58 +0800592 if (ah->frag_index[methods[m]]) {
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800593 /*
594 * already had the method, no idea what
Andy Green8fb338f2015-04-07 08:19:30 +0800595 * this crap from the client is, ignore
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800596 */
597 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
598 break;
599 }
Andy Green3ee9b312013-02-12 12:52:39 +0800600 /*
Andy Green8fb338f2015-04-07 08:19:30 +0800601 * hm it's an unknown http method from a client in fact,
Andy Green3ee9b312013-02-12 12:52:39 +0800602 * treat as dangerous
603 */
Drew Noakes2121e8a2015-01-30 12:04:43 +0000604 if (m == ARRAY_SIZE(methods)) {
605 lwsl_info("Unknown method - dropping\n");
606 return -1;
607 }
608 break;
Andy Greene4dffc92013-02-04 09:24:18 +0800609 }
Andy Green8fb338f2015-04-07 08:19:30 +0800610 /*
611 * ...otherwise for a client, let him ignore unknown headers
612 * coming from the server
613 */
614 if (wsi->u.hdr.lextable_pos < 0) {
615 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
616 break;
617 }
618
Andy Greenbbc5c072014-03-09 11:49:21 +0800619 if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) {
Andy Greene4dffc92013-02-04 09:24:18 +0800620 /* terminal state */
621
Andy Green59800b72014-11-30 12:36:09 +0800622 n = ((unsigned int)lextable[wsi->u.hdr.lextable_pos] << 8) |
623 lextable[wsi->u.hdr.lextable_pos + 1];
Andy Green6d1fcb72013-01-18 01:55:48 +0800624
Andy Greencc7cb682013-02-18 10:22:42 +0800625 lwsl_parser("known hdr %d\n", n);
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800626 for (m = 0; m < ARRAY_SIZE(methods); m++)
627 if (n == methods[m] &&
Andy Green6b5de702015-12-15 21:15:58 +0800628 ah->frag_index[
Quinlan Pfiffer49f72aa2015-01-10 19:01:52 -0800629 methods[m]]) {
630 lwsl_warn("Duplicated method\n");
631 return -1;
632 }
Andy Green94f94652013-02-12 13:10:19 +0800633
Andy Greenfd963302012-04-03 17:02:20 +0200634 /*
635 * WSORIGIN is protocol equiv to ORIGIN,
636 * JWebSocket likes to send it, map to ORIGIN
637 */
638 if (n == WSI_TOKEN_SWORIGIN)
639 n = WSI_TOKEN_ORIGIN;
640
Andy Green16ab3182013-02-10 18:02:31 +0800641 wsi->u.hdr.parser_state = (enum lws_token_indexes)
642 (WSI_TOKEN_GET_URI + n);
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400643
Andy Greenf012f752014-08-22 19:38:17 +0800644 if (context->token_limits)
645 wsi->u.hdr.current_token_limit =
Andy Green6b5de702015-12-15 21:15:58 +0800646 context->token_limits->token_limit[
647 wsi->u.hdr.parser_state];
Andy Greenf012f752014-08-22 19:38:17 +0800648 else
Andy Green3df58002015-12-25 12:44:12 +0800649 wsi->u.hdr.current_token_limit =
650 wsi->context->max_http_header_data;
Andrew Canaday18fd4f62014-06-29 01:34:24 -0400651
Andy Green16ab3182013-02-10 18:02:31 +0800652 if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
653 goto set_parsing_complete;
Andy Green6964bb52011-01-23 16:50:33 +0000654
Andy Green16ab3182013-02-10 18:02:31 +0800655 goto start_fragment;
656 }
657 break;
Nick Dowell30592632012-04-05 10:31:48 +0800658
Andy Green16ab3182013-02-10 18:02:31 +0800659start_fragment:
Andy Green6b5de702015-12-15 21:15:58 +0800660 ah->nfrag++;
Andy Green4eb36372015-12-15 22:57:19 +0800661excessive:
Andy Green6b5de702015-12-15 21:15:58 +0800662 if (ah->nfrag == ARRAY_SIZE(ah->frags)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800663 lwsl_warn("More hdr frags than we can deal with\n");
Andy Green16ab3182013-02-10 18:02:31 +0800664 return -1;
Andy Green7c212cc2010-11-08 20:20:42 +0000665 }
666
Andy Green6b5de702015-12-15 21:15:58 +0800667 ah->frags[ah->nfrag].offset = ah->pos;
668 ah->frags[ah->nfrag].len = 0;
669 ah->frags[ ah->nfrag].nfrag = 0;
Andy Green16ab3182013-02-10 18:02:31 +0800670
Andy Green6b5de702015-12-15 21:15:58 +0800671 n = ah->frag_index[wsi->u.hdr.parser_state];
Andy Green16ab3182013-02-10 18:02:31 +0800672 if (!n) { /* first fragment */
Andy Green6b5de702015-12-15 21:15:58 +0800673 ah->frag_index[wsi->u.hdr.parser_state] = ah->nfrag;
Andy Greencc13c6f2013-11-09 10:09:09 +0800674 break;
675 }
676 /* continuation */
Andy Green6b5de702015-12-15 21:15:58 +0800677 while (ah->frags[n].nfrag)
678 n = ah->frags[n].nfrag;
679 ah->frags[n].nfrag = ah->nfrag;
Andy Green16ab3182013-02-10 18:02:31 +0800680
Andy Greenbc401292016-01-20 07:40:13 +0800681 if (issue_char(wsi, ' ') < 0)
Andy Greencc13c6f2013-11-09 10:09:09 +0800682 return -1;
Andy Greene4dffc92013-02-04 09:24:18 +0800683 break;
Andy Greene77ddd82010-11-13 10:03:47 +0000684
Andy Green7c212cc2010-11-08 20:20:42 +0000685 /* skipping arg part of a name we didn't recognize */
686 case WSI_TOKEN_SKIPPING:
Andy Green43db0452013-01-10 19:50:35 +0800687 lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
kapejodce64fb02013-11-19 13:38:16 +0100688
Andy Green7c212cc2010-11-08 20:20:42 +0000689 if (c == '\x0d')
Andy Green623a98d2013-01-21 11:04:23 +0800690 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
Andy Green7c212cc2010-11-08 20:20:42 +0000691 break;
Andy Green177ca782013-02-04 09:09:19 +0800692
Andy Green7c212cc2010-11-08 20:20:42 +0000693 case WSI_TOKEN_SKIPPING_SAW_CR:
Andy Green43db0452013-01-10 19:50:35 +0800694 lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
Andy Green6d1fcb72013-01-18 01:55:48 +0800695 if (c == '\x0a') {
Andy Green623a98d2013-01-21 11:04:23 +0800696 wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
697 wsi->u.hdr.lextable_pos = 0;
Andy Green6d1fcb72013-01-18 01:55:48 +0800698 } else
Andy Green623a98d2013-01-21 11:04:23 +0800699 wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
Andy Green7c212cc2010-11-08 20:20:42 +0000700 break;
701 /* we're done, ignore anything else */
kapejodce64fb02013-11-19 13:38:16 +0100702
Andy Green7c212cc2010-11-08 20:20:42 +0000703 case WSI_PARSING_COMPLETE:
Andy Green43db0452013-01-10 19:50:35 +0800704 lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
Andy Green7c212cc2010-11-08 20:20:42 +0000705 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000706 }
Andy Greene77ddd82010-11-13 10:03:47 +0000707
Andy Green7c212cc2010-11-08 20:20:42 +0000708 return 0;
Andy Green177ca782013-02-04 09:09:19 +0800709
710set_parsing_complete:
711
Andy Green16ab3182013-02-10 18:02:31 +0800712 if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
Andy Greenb5b23192013-02-11 17:13:32 +0800713 if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
Andy Green2b57a342013-02-06 15:15:25 +0900714 wsi->ietf_spec_revision =
Andy Green16ab3182013-02-10 18:02:31 +0800715 atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
Andy Green177ca782013-02-04 09:09:19 +0800716
Andy Greenb5b23192013-02-11 17:13:32 +0800717 lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision);
Andy Green2b57a342013-02-06 15:15:25 +0900718 }
Andy Green177ca782013-02-04 09:09:19 +0800719 wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE;
Andy Green224149a2013-02-11 21:43:41 +0800720 wsi->hdr_parsing_completed = 1;
Andy Green177ca782013-02-04 09:09:19 +0800721
722 return 0;
Andy Green7c212cc2010-11-08 20:20:42 +0000723}
724
Andy Greenbfb051f2011-02-09 08:49:14 +0000725
Andy Green2fd3f2f2013-01-18 09:49:20 +0800726/**
727 * lws_frame_is_binary: true if the current frame was sent in binary mode
728 *
729 * @wsi: the connection we are inquiring about
730 *
731 * This is intended to be called from the LWS_CALLBACK_RECEIVE callback if
732 * it's interested to see if the frame it's dealing with was sent in binary
733 * mode.
734 */
735
Andy Green4b85c1d2015-12-04 11:08:32 +0800736LWS_VISIBLE int lws_frame_is_binary(struct lws *wsi)
Andy Green2fd3f2f2013-01-18 09:49:20 +0800737{
Andy Green623a98d2013-01-21 11:04:23 +0800738 return wsi->u.ws.frame_is_binary;
Andy Green2fd3f2f2013-01-18 09:49:20 +0800739}
Andy Greenbfb051f2011-02-09 08:49:14 +0000740
Andy Greena41314f2011-05-23 10:00:03 +0100741int
Andy Green4b85c1d2015-12-04 11:08:32 +0800742lws_rx_sm(struct lws *wsi, unsigned char c)
Andy Green7c212cc2010-11-08 20:20:42 +0000743{
Andy Greend3a55052016-01-19 03:34:24 +0800744 struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
Andy Greena41314f2011-05-23 10:00:03 +0100745 struct lws_tokens eff_buf;
Andy Green67112662016-01-11 11:34:01 +0800746 int ret = 0, n, rx_draining_ext = 0;
John Tarlton05fc6ba2015-10-05 11:35:52 +0100747 int callback_action = LWS_CALLBACK_RECEIVE;
Andy Green67112662016-01-11 11:34:01 +0800748 if (wsi->socket_is_permanently_unusable)
749 return -1;
Andy Green7c212cc2010-11-08 20:20:42 +0000750
751 switch (wsi->lws_rx_parse_state) {
752 case LWS_RXPS_NEW:
Andy Green67112662016-01-11 11:34:01 +0800753 if (wsi->u.ws.rx_draining_ext) {
Andy Greend3a55052016-01-19 03:34:24 +0800754 struct lws **w = &pt->rx_draining_ext_list;
Andy Greene77ddd82010-11-13 10:03:47 +0000755
Andy Green67112662016-01-11 11:34:01 +0800756 eff_buf.token = NULL;
757 eff_buf.token_len = 0;
758 wsi->u.ws.rx_draining_ext = 0;
759 /* remove us from context draining ext list */
760 while (*w) {
761 if (*w == wsi) {
762 *w = wsi->u.ws.rx_draining_ext_list;
763 break;
764 }
765 w = &((*w)->u.ws.rx_draining_ext_list);
766 }
767 wsi->u.ws.rx_draining_ext_list = NULL;
768 rx_draining_ext = 1;
769 lwsl_err("%s: doing draining flow\n", __func__);
770
771 goto drain_extension;
772 }
Andy Green7c212cc2010-11-08 20:20:42 +0000773 switch (wsi->ietf_spec_revision) {
Andy Greend85cb202011-09-25 09:32:54 +0100774 case 13:
Andy Green283d0a22011-04-24 05:46:23 +0100775 /*
776 * no prepended frame key any more
777 */
Andy Green623a98d2013-01-21 11:04:23 +0800778 wsi->u.ws.all_zero_nonce = 1;
Andy Green283d0a22011-04-24 05:46:23 +0100779 goto handle_first;
780
Andy Greenbfb051f2011-02-09 08:49:14 +0000781 default:
Andy Greenb5b23192013-02-11 17:13:32 +0800782 lwsl_warn("lws_rx_sm: unknown spec version %d\n",
783 wsi->ietf_spec_revision);
Andy Greenbfb051f2011-02-09 08:49:14 +0000784 break;
Andy Green7c212cc2010-11-08 20:20:42 +0000785 }
Andy Green6452f1e2010-11-11 09:22:22 +0000786 break;
Andy Green67112662016-01-11 11:34:01 +0800787 case LWS_RXPS_04_mask_1:
788 wsi->u.ws.mask[1] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000789 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800790 wsi->u.ws.all_zero_nonce = 0;
Andy Green67112662016-01-11 11:34:01 +0800791 wsi->lws_rx_parse_state = LWS_RXPS_04_mask_2;
Andy Green3e5eb782011-01-18 18:14:26 +0000792 break;
Andy Green67112662016-01-11 11:34:01 +0800793 case LWS_RXPS_04_mask_2:
794 wsi->u.ws.mask[2] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000795 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800796 wsi->u.ws.all_zero_nonce = 0;
Andy Green67112662016-01-11 11:34:01 +0800797 wsi->lws_rx_parse_state = LWS_RXPS_04_mask_3;
Andy Green3e5eb782011-01-18 18:14:26 +0000798 break;
Andy Green67112662016-01-11 11:34:01 +0800799 case LWS_RXPS_04_mask_3:
800 wsi->u.ws.mask[3] = c;
Andy Green92970ba2011-02-10 09:22:35 +0000801 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800802 wsi->u.ws.all_zero_nonce = 0;
Andy Green3e5eb782011-01-18 18:14:26 +0000803
Andy Green3e5eb782011-01-18 18:14:26 +0000804 /*
805 * start from the zero'th byte in the XOR key buffer since
806 * this is the start of a frame with a new key
807 */
808
Andy Green67112662016-01-11 11:34:01 +0800809 wsi->u.ws.mask_idx = 0;
Andy Green6964bb52011-01-23 16:50:33 +0000810
Andy Green3e5eb782011-01-18 18:14:26 +0000811 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
812 break;
Andy Green38e57bb2011-01-19 12:20:27 +0000813
814 /*
815 * 04 logical framing from the spec (all this is masked when incoming
816 * and has to be unmasked)
817 *
818 * We ignore the possibility of extension data because we don't
819 * negotiate any extensions at the moment.
Andy Green6964bb52011-01-23 16:50:33 +0000820 *
Andy Green38e57bb2011-01-19 12:20:27 +0000821 * 0 1 2 3
822 * 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
823 * +-+-+-+-+-------+-+-------------+-------------------------------+
824 * |F|R|R|R| opcode|R| Payload len | Extended payload length |
825 * |I|S|S|S| (4) |S| (7) | (16/63) |
826 * |N|V|V|V| |V| | (if payload len==126/127) |
827 * | |1|2|3| |4| | |
828 * +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
829 * | Extended payload length continued, if payload len == 127 |
830 * + - - - - - - - - - - - - - - - +-------------------------------+
831 * | | Extension data |
832 * +-------------------------------+ - - - - - - - - - - - - - - - +
833 * : :
834 * +---------------------------------------------------------------+
835 * : Application data :
836 * +---------------------------------------------------------------+
837 *
838 * We pass payload through to userland as soon as we get it, ignoring
839 * FIN. It's up to userland to buffer it up if it wants to see a
840 * whole unfragmented block of the original size (which may be up to
841 * 2^63 long!)
842 */
843
844 case LWS_RXPS_04_FRAME_HDR_1:
Andy Green283d0a22011-04-24 05:46:23 +0100845handle_first:
846
Andy Green623a98d2013-01-21 11:04:23 +0800847 wsi->u.ws.opcode = c & 0xf;
848 wsi->u.ws.rsv = c & 0x70;
849 wsi->u.ws.final = !!((c >> 7) & 1);
Andy Green1bc12f92013-02-28 17:11:29 +0800850
Andy Green623a98d2013-01-21 11:04:23 +0800851 switch (wsi->u.ws.opcode) {
Andy Green54806b12015-12-17 17:03:59 +0800852 case LWSWSOPC_TEXT_FRAME:
853 case LWSWSOPC_BINARY_FRAME:
Andy Green67112662016-01-11 11:34:01 +0800854 wsi->u.ws.rsv_first_msg = (c & 0x70);
Andy Greenb5b23192013-02-11 17:13:32 +0800855 wsi->u.ws.frame_is_binary =
Andy Green54806b12015-12-17 17:03:59 +0800856 wsi->u.ws.opcode == LWSWSOPC_BINARY_FRAME;
Andy Green10601c12013-01-19 10:39:35 +0800857 break;
Andy Green67112662016-01-11 11:34:01 +0800858 case 3:
859 case 4:
860 case 5:
861 case 6:
862 case 7:
863 case 0xb:
864 case 0xc:
865 case 0xd:
866 case 0xe:
867 case 0xf:
868 lwsl_info("illegal opcode\n");
869 return -1;
Andy Green10601c12013-01-19 10:39:35 +0800870 }
Andy Green38e57bb2011-01-19 12:20:27 +0000871 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
872 break;
873
874 case LWS_RXPS_04_FRAME_HDR_LEN:
Andy Green38e57bb2011-01-19 12:20:27 +0000875
Andy Green623a98d2013-01-21 11:04:23 +0800876 wsi->u.ws.this_frame_masked = !!(c & 0x80);
Andy Green283d0a22011-04-24 05:46:23 +0100877
Andy Green5bf65782011-09-25 10:46:31 +0100878 switch (c & 0x7f) {
Andy Green38e57bb2011-01-19 12:20:27 +0000879 case 126:
880 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800881 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100882 goto illegal_ctl_length;
883
Andy Green38e57bb2011-01-19 12:20:27 +0000884 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
885 break;
886 case 127:
887 /* control frames are not allowed to have big lengths */
Andy Green623a98d2013-01-21 11:04:23 +0800888 if (wsi->u.ws.opcode & 8)
Andy Green23545db2011-04-24 06:19:22 +0100889 goto illegal_ctl_length;
890
Andy Green38e57bb2011-01-19 12:20:27 +0000891 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
892 break;
893 default:
Andy Green623a98d2013-01-21 11:04:23 +0800894 wsi->u.ws.rx_packet_length = c & 0x7f;
895 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100896 wsi->lws_rx_parse_state =
897 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
898 else
Andy Green8ea19552014-02-15 16:00:37 +0800899 if (wsi->u.ws.rx_packet_length)
900 wsi->lws_rx_parse_state =
Andy Green38e57bb2011-01-19 12:20:27 +0000901 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green8ea19552014-02-15 16:00:37 +0800902 else {
903 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
904 goto spill;
905 }
Andy Green38e57bb2011-01-19 12:20:27 +0000906 break;
907 }
908 break;
909
910 case LWS_RXPS_04_FRAME_HDR_LEN16_2:
Andy Green623a98d2013-01-21 11:04:23 +0800911 wsi->u.ws.rx_packet_length = c << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000912 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
913 break;
914
915 case LWS_RXPS_04_FRAME_HDR_LEN16_1:
Andy Green623a98d2013-01-21 11:04:23 +0800916 wsi->u.ws.rx_packet_length |= c;
917 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100918 wsi->lws_rx_parse_state =
919 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
920 else
921 wsi->lws_rx_parse_state =
922 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000923 break;
924
925 case LWS_RXPS_04_FRAME_HDR_LEN64_8:
Andy Green38e57bb2011-01-19 12:20:27 +0000926 if (c & 0x80) {
Andy Green43db0452013-01-10 19:50:35 +0800927 lwsl_warn("b63 of length must be zero\n");
Andy Green38e57bb2011-01-19 12:20:27 +0000928 /* kill the connection */
929 return -1;
930 }
Andy Greenf55830d2011-01-27 06:45:53 +0000931#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800932 wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
Andy Greenf55830d2011-01-27 06:45:53 +0000933#else
Andy Green623a98d2013-01-21 11:04:23 +0800934 wsi->u.ws.rx_packet_length = 0;
Andy Greenf55830d2011-01-27 06:45:53 +0000935#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000936 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
937 break;
938
939 case LWS_RXPS_04_FRAME_HDR_LEN64_7:
Andy Greenf55830d2011-01-27 06:45:53 +0000940#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800941 wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
Andy Greenf55830d2011-01-27 06:45:53 +0000942#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000943 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
944 break;
945
946 case LWS_RXPS_04_FRAME_HDR_LEN64_6:
Andy Greenf55830d2011-01-27 06:45:53 +0000947#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800948 wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
Andy Greenf55830d2011-01-27 06:45:53 +0000949#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000950 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
951 break;
952
953 case LWS_RXPS_04_FRAME_HDR_LEN64_5:
Andy Greenf55830d2011-01-27 06:45:53 +0000954#if defined __LP64__
Andy Green623a98d2013-01-21 11:04:23 +0800955 wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
Andy Greenf55830d2011-01-27 06:45:53 +0000956#endif
Andy Green38e57bb2011-01-19 12:20:27 +0000957 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
958 break;
959
960 case LWS_RXPS_04_FRAME_HDR_LEN64_4:
Andy Green623a98d2013-01-21 11:04:23 +0800961 wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
Andy Green38e57bb2011-01-19 12:20:27 +0000962 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
963 break;
964
965 case LWS_RXPS_04_FRAME_HDR_LEN64_3:
Andy Green623a98d2013-01-21 11:04:23 +0800966 wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
Andy Green38e57bb2011-01-19 12:20:27 +0000967 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
968 break;
969
970 case LWS_RXPS_04_FRAME_HDR_LEN64_2:
Andy Green623a98d2013-01-21 11:04:23 +0800971 wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
Andy Green38e57bb2011-01-19 12:20:27 +0000972 wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
973 break;
974
975 case LWS_RXPS_04_FRAME_HDR_LEN64_1:
Andy Green623a98d2013-01-21 11:04:23 +0800976 wsi->u.ws.rx_packet_length |= ((size_t)c);
977 if (wsi->u.ws.this_frame_masked)
Andy Green283d0a22011-04-24 05:46:23 +0100978 wsi->lws_rx_parse_state =
979 LWS_RXPS_07_COLLECT_FRAME_KEY_1;
980 else
981 wsi->lws_rx_parse_state =
982 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green38e57bb2011-01-19 12:20:27 +0000983 break;
984
Andy Green283d0a22011-04-24 05:46:23 +0100985 case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
Andy Green67112662016-01-11 11:34:01 +0800986 wsi->u.ws.mask[0] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100987 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800988 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100989 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
990 break;
991
992 case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
Andy Green67112662016-01-11 11:34:01 +0800993 wsi->u.ws.mask[1] = c;
Andy Green283d0a22011-04-24 05:46:23 +0100994 if (c)
Andy Green623a98d2013-01-21 11:04:23 +0800995 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +0100996 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
997 break;
998
999 case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
Andy Green67112662016-01-11 11:34:01 +08001000 wsi->u.ws.mask[2] = c;
Andy Green283d0a22011-04-24 05:46:23 +01001001 if (c)
Andy Green623a98d2013-01-21 11:04:23 +08001002 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +01001003 wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
1004 break;
1005
1006 case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
Andy Green67112662016-01-11 11:34:01 +08001007 wsi->u.ws.mask[3] = c;
Andy Green283d0a22011-04-24 05:46:23 +01001008 if (c)
Andy Green623a98d2013-01-21 11:04:23 +08001009 wsi->u.ws.all_zero_nonce = 0;
Andy Green283d0a22011-04-24 05:46:23 +01001010 wsi->lws_rx_parse_state =
1011 LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
Andy Green67112662016-01-11 11:34:01 +08001012 wsi->u.ws.mask_idx = 0;
Andy Green8ea19552014-02-15 16:00:37 +08001013 if (wsi->u.ws.rx_packet_length == 0) {
1014 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
Andy Green1bc12f92013-02-28 17:11:29 +08001015 goto spill;
Andy Green8ea19552014-02-15 16:00:37 +08001016 }
Andy Green283d0a22011-04-24 05:46:23 +01001017 break;
1018
1019
Andy Green7c212cc2010-11-08 20:20:42 +00001020 case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
Andy Green3182ece2013-01-20 17:08:31 +08001021
Andy Green67112662016-01-11 11:34:01 +08001022 assert(wsi->u.ws.rx_ubuf);
Andy Green54495112013-02-06 21:10:16 +09001023
Andy Greend3a55052016-01-19 03:34:24 +08001024 if (wsi->u.ws.rx_ubuf_head + LWS_PRE >=
1025 wsi->u.ws.rx_ubuf_alloc) {
1026 lwsl_err("Attempted overflow \n");
1027 return -1;
1028 }
Andy Green623a98d2013-01-21 11:04:23 +08001029 if (wsi->u.ws.all_zero_nonce)
Andy Green67112662016-01-11 11:34:01 +08001030 wsi->u.ws.rx_ubuf[LWS_PRE +
Andy Greend3a55052016-01-19 03:34:24 +08001031 (wsi->u.ws.rx_ubuf_head++)] = c;
Andy Green92970ba2011-02-10 09:22:35 +00001032 else
Andy Green67112662016-01-11 11:34:01 +08001033 wsi->u.ws.rx_ubuf[LWS_PRE +
1034 (wsi->u.ws.rx_ubuf_head++)] =
1035 c ^ wsi->u.ws.mask[
1036 (wsi->u.ws.mask_idx++) & 3];
Andy Green4739e5c2011-01-22 12:51:57 +00001037
Andy Green623a98d2013-01-21 11:04:23 +08001038 if (--wsi->u.ws.rx_packet_length == 0) {
Andy Greenc2bb3dc2013-02-14 11:25:44 +08001039 /* spill because we have the whole frame */
Andy Green4739e5c2011-01-22 12:51:57 +00001040 wsi->lws_rx_parse_state = LWS_RXPS_NEW;
1041 goto spill;
1042 }
Andy Greenc2bb3dc2013-02-14 11:25:44 +08001043
1044 /*
1045 * if there's no protocol max frame size given, we are
1046 * supposed to default to LWS_MAX_SOCKET_IO_BUF
1047 */
1048
1049 if (!wsi->protocol->rx_buffer_size &&
Andy Green67112662016-01-11 11:34:01 +08001050 wsi->u.ws.rx_ubuf_head !=
Andy Greenc2bb3dc2013-02-14 11:25:44 +08001051 LWS_MAX_SOCKET_IO_BUF)
Andy Green4739e5c2011-01-22 12:51:57 +00001052 break;
Andy Greenc2bb3dc2013-02-14 11:25:44 +08001053 else
1054 if (wsi->protocol->rx_buffer_size &&
Andy Green67112662016-01-11 11:34:01 +08001055 wsi->u.ws.rx_ubuf_head !=
Andy Greenc2bb3dc2013-02-14 11:25:44 +08001056 wsi->protocol->rx_buffer_size)
1057 break;
1058
1059 /* spill because we filled our rx buffer */
Andy Green4739e5c2011-01-22 12:51:57 +00001060spill:
1061 /*
1062 * is this frame a control packet we should take care of at this
1063 * layer? If so service it and hide it from the user callback
1064 */
1065
Andy Green43db0452013-01-10 19:50:35 +08001066 lwsl_parser("spill on %s\n", wsi->protocol->name);
Andy Greena41314f2011-05-23 10:00:03 +01001067
Andy Green623a98d2013-01-21 11:04:23 +08001068 switch (wsi->u.ws.opcode) {
Andy Green54806b12015-12-17 17:03:59 +08001069 case LWSWSOPC_CLOSE:
Andy Green066a7a12015-12-26 15:47:06 +08001070
Andy Greenda527df2011-03-07 07:08:12 +00001071 /* is this an acknowledgement of our close? */
Andy Green54806b12015-12-17 17:03:59 +08001072 if (wsi->state == LWSS_AWAITING_CLOSE_ACK) {
Andy Greenda527df2011-03-07 07:08:12 +00001073 /*
1074 * fine he has told us he is closing too, let's
1075 * finish our close
1076 */
Andy Green43db0452013-01-10 19:50:35 +08001077 lwsl_parser("seen client close ack\n");
Andy Greenda527df2011-03-07 07:08:12 +00001078 return -1;
1079 }
Andy Green54806b12015-12-17 17:03:59 +08001080 if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY)
Andy Green40d5abc2015-04-17 20:29:58 +08001081 /* if he sends us 2 CLOSE, kill him */
1082 return -1;
1083
Andy Green066a7a12015-12-26 15:47:06 +08001084 if (user_callback_handle_rxflow(
1085 wsi->protocol->callback, wsi,
1086 LWS_CALLBACK_WS_PEER_INITIATED_CLOSE,
1087 wsi->user_space,
Andy Greend3a55052016-01-19 03:34:24 +08001088 &wsi->u.ws.rx_ubuf[LWS_PRE],
Andy Green67112662016-01-11 11:34:01 +08001089 wsi->u.ws.rx_ubuf_head))
Andy Green066a7a12015-12-26 15:47:06 +08001090 return -1;
1091
Andy Green43db0452013-01-10 19:50:35 +08001092 lwsl_parser("server sees client close packet\n");
Andy Green54806b12015-12-17 17:03:59 +08001093 wsi->state = LWSS_RETURNED_CLOSE_ALREADY;
Andy Green40d5abc2015-04-17 20:29:58 +08001094 /* deal with the close packet contents as a PONG */
1095 wsi->u.ws.payload_is_close = 1;
1096 goto process_as_ping;
Andy Green4739e5c2011-01-22 12:51:57 +00001097
Andy Green54806b12015-12-17 17:03:59 +08001098 case LWSWSOPC_PING:
Andy Greenb5b23192013-02-11 17:13:32 +08001099 lwsl_info("received %d byte ping, sending pong\n",
Andy Green67112662016-01-11 11:34:01 +08001100 wsi->u.ws.rx_ubuf_head);
Andy Green82bac6b2014-08-24 14:39:19 +08001101
Andy Green2fd6e6f2015-03-24 21:07:01 +08001102 if (wsi->u.ws.ping_pending_flag) {
Andy Green40110e82015-12-14 08:52:03 +08001103 /*
Andy Green82bac6b2014-08-24 14:39:19 +08001104 * there is already a pending ping payload
1105 * we should just log and drop
1106 */
1107 lwsl_parser("DROP PING since one pending\n");
1108 goto ping_drop;
1109 }
Andy Green40d5abc2015-04-17 20:29:58 +08001110process_as_ping:
Andy Green82bac6b2014-08-24 14:39:19 +08001111 /* control packets can only be < 128 bytes long */
Andy Green67112662016-01-11 11:34:01 +08001112 if (wsi->u.ws.rx_ubuf_head > 128 - 3) {
Andy Green82bac6b2014-08-24 14:39:19 +08001113 lwsl_parser("DROP PING payload too large\n");
1114 goto ping_drop;
1115 }
Andy Green40110e82015-12-14 08:52:03 +08001116
Andy Green82bac6b2014-08-24 14:39:19 +08001117 /* stash the pong payload */
Andy Green67112662016-01-11 11:34:01 +08001118 memcpy(wsi->u.ws.ping_payload_buf + LWS_PRE,
1119 &wsi->u.ws.rx_ubuf[LWS_PRE],
1120 wsi->u.ws.rx_ubuf_head);
Andy Green40110e82015-12-14 08:52:03 +08001121
Andy Green67112662016-01-11 11:34:01 +08001122 wsi->u.ws.ping_payload_len = wsi->u.ws.rx_ubuf_head;
Andy Green2fd6e6f2015-03-24 21:07:01 +08001123 wsi->u.ws.ping_pending_flag = 1;
Andy Green40110e82015-12-14 08:52:03 +08001124
Andy Green82bac6b2014-08-24 14:39:19 +08001125 /* get it sent as soon as possible */
Andy Green11c05bf2015-12-16 18:19:08 +08001126 lws_callback_on_writable(wsi);
Andy Green82bac6b2014-08-24 14:39:19 +08001127ping_drop:
Andy Green67112662016-01-11 11:34:01 +08001128 wsi->u.ws.rx_ubuf_head = 0;
Andy Greena6cbece2011-01-27 20:06:03 +00001129 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +00001130
Andy Green54806b12015-12-17 17:03:59 +08001131 case LWSWSOPC_PONG:
John Tarlton05fc6ba2015-10-05 11:35:52 +01001132 lwsl_info("received pong\n");
Andy Green67112662016-01-11 11:34:01 +08001133 lwsl_hexdump(&wsi->u.ws.rx_ubuf[LWS_PRE],
1134 wsi->u.ws.rx_ubuf_head);
John Tarlton05fc6ba2015-10-05 11:35:52 +01001135
1136 /* issue it */
1137 callback_action = LWS_CALLBACK_RECEIVE_PONG;
1138 break;
Andy Green4739e5c2011-01-22 12:51:57 +00001139
Andy Green54806b12015-12-17 17:03:59 +08001140 case LWSWSOPC_TEXT_FRAME:
1141 case LWSWSOPC_BINARY_FRAME:
1142 case LWSWSOPC_CONTINUATION:
Andy Green4739e5c2011-01-22 12:51:57 +00001143 break;
Andy Greena41314f2011-05-23 10:00:03 +01001144
1145 default:
Andy Greenb5b23192013-02-11 17:13:32 +08001146 lwsl_parser("passing opc %x up to exts\n",
Andy Greend3a55052016-01-19 03:34:24 +08001147 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +01001148 /*
1149 * It's something special we can't understand here.
1150 * Pass the payload up to the extension's parsing
1151 * state machine.
1152 */
1153
Andy Green67112662016-01-11 11:34:01 +08001154 eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE];
1155 eff_buf.token_len = wsi->u.ws.rx_ubuf_head;
Andy Greena41314f2011-05-23 10:00:03 +01001156
Andy Green67112662016-01-11 11:34:01 +08001157 if (lws_ext_cb_active(wsi, LWS_EXT_CB_EXTENDED_PAYLOAD_RX,
Andy Green2c24ec02014-04-02 19:45:42 +08001158 &eff_buf, 0) <= 0) /* not handle or fail */
Andy Greenb5b23192013-02-11 17:13:32 +08001159 lwsl_ext("ext opc opcode 0x%x unknown\n",
1160 wsi->u.ws.opcode);
Andy Greena41314f2011-05-23 10:00:03 +01001161
Andy Green67112662016-01-11 11:34:01 +08001162 wsi->u.ws.rx_ubuf_head = 0;
Andy Greena41314f2011-05-23 10:00:03 +01001163 return 0;
Andy Green4739e5c2011-01-22 12:51:57 +00001164 }
1165
1166 /*
1167 * No it's real payload, pass it up to the user callback.
1168 * It's nicely buffered with the pre-padding taken care of
Andy Green62304762015-12-04 08:43:54 +08001169 * so it can be sent straight out again using lws_write
Andy Green4739e5c2011-01-22 12:51:57 +00001170 */
1171
Andy Green67112662016-01-11 11:34:01 +08001172 eff_buf.token = &wsi->u.ws.rx_ubuf[LWS_PRE];
1173 eff_buf.token_len = wsi->u.ws.rx_ubuf_head;
Andy Green40110e82015-12-14 08:52:03 +08001174
Andy Green67112662016-01-11 11:34:01 +08001175drain_extension:
1176 lwsl_ext("%s: passing %d to ext\n", __func__, eff_buf.token_len);
1177
1178 if (wsi->state == LWSS_RETURNED_CLOSE_ALREADY ||
1179 wsi->state == LWSS_AWAITING_CLOSE_ACK)
1180 goto already_done;
1181
1182 n = lws_ext_cb_active(wsi, LWS_EXT_CB_PAYLOAD_RX, &eff_buf, 0);
1183 if (n < 0) {
1184 /*
1185 * we may rely on this to get RX, just drop connection
1186 */
1187 wsi->socket_is_permanently_unusable = 1;
Andy Green2c24ec02014-04-02 19:45:42 +08001188 return -1;
Andy Green67112662016-01-11 11:34:01 +08001189 }
1190
1191 if (rx_draining_ext && eff_buf.token_len == 0)
1192 goto already_done;
1193
1194 if (n && eff_buf.token_len) {
1195 /* extension had more... main loop will come back */
1196 wsi->u.ws.rx_draining_ext = 1;
Andy Greend3a55052016-01-19 03:34:24 +08001197 wsi->u.ws.rx_draining_ext_list = pt->rx_draining_ext_list;
1198 pt->rx_draining_ext_list = wsi;
Andy Green67112662016-01-11 11:34:01 +08001199 }
Andy Green2c24ec02014-04-02 19:45:42 +08001200
Andrejs Hanins765914c2015-12-01 14:44:33 +02001201 if (eff_buf.token_len > 0 ||
1202 callback_action == LWS_CALLBACK_RECEIVE_PONG) {
Andy Greenaedc9532013-02-10 21:21:24 +08001203 eff_buf.token[eff_buf.token_len] = '\0';
David Galeanoe2cf9922013-01-09 18:06:55 +08001204
John Tarlton05fc6ba2015-10-05 11:35:52 +01001205 if (wsi->protocol->callback) {
1206
1207 if (callback_action == LWS_CALLBACK_RECEIVE_PONG)
Andy Green67112662016-01-11 11:34:01 +08001208 lwsl_info("Doing pong callback\n");
John Tarlton05fc6ba2015-10-05 11:35:52 +01001209
Andy Greenb5b23192013-02-11 17:13:32 +08001210 ret = user_callback_handle_rxflow(
1211 wsi->protocol->callback,
John Tarlton05fc6ba2015-10-05 11:35:52 +01001212 wsi,
Andy Green4b85c1d2015-12-04 11:08:32 +08001213 (enum lws_callback_reasons)callback_action,
Andy Greenb5b23192013-02-11 17:13:32 +08001214 wsi->user_space,
1215 eff_buf.token,
1216 eff_buf.token_len);
John Tarlton05fc6ba2015-10-05 11:35:52 +01001217 }
1218 else
1219 lwsl_err("No callback on payload spill!\n");
David Galeanoe2cf9922013-01-09 18:06:55 +08001220 }
Andy Greena41314f2011-05-23 10:00:03 +01001221
Andy Green67112662016-01-11 11:34:01 +08001222already_done:
1223 wsi->u.ws.rx_ubuf_head = 0;
Andy Green4739e5c2011-01-22 12:51:57 +00001224 break;
1225 }
1226
Andy Greenaedc9532013-02-10 21:21:24 +08001227 return ret;
Andy Green23545db2011-04-24 06:19:22 +01001228
1229illegal_ctl_length:
1230
Andy Greenb5b23192013-02-11 17:13:32 +08001231 lwsl_warn("Control frame with xtended length is illegal\n");
Andy Green23545db2011-04-24 06:19:22 +01001232 /* kill the connection */
1233 return -1;
Andy Green4739e5c2011-01-22 12:51:57 +00001234}
1235
1236
Andy Green38e57bb2011-01-19 12:20:27 +00001237/**
Andy Green62304762015-12-04 08:43:54 +08001238 * lws_remaining_packet_payload() - Bytes to come before "overall"
Andy Green6964bb52011-01-23 16:50:33 +00001239 * rx packet is complete
Andy Green38e57bb2011-01-19 12:20:27 +00001240 * @wsi: Websocket instance (available from user callback)
1241 *
1242 * This function is intended to be called from the callback if the
1243 * user code is interested in "complete packets" from the client.
1244 * libwebsockets just passes through payload as it comes and issues a buffer
1245 * additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE
1246 * callback handler can use this API to find out if the buffer it has just
1247 * been given is the last piece of a "complete packet" from the client --
Andy Green62304762015-12-04 08:43:54 +08001248 * when that is the case lws_remaining_packet_payload() will return
Andy Green38e57bb2011-01-19 12:20:27 +00001249 * 0.
1250 *
1251 * Many protocols won't care becuse their packets are always small.
1252 */
1253
Peter Pentchev9a4fef72013-03-30 09:52:21 +08001254LWS_VISIBLE size_t
Andy Green4b85c1d2015-12-04 11:08:32 +08001255lws_remaining_packet_payload(struct lws *wsi)
Andy Green38e57bb2011-01-19 12:20:27 +00001256{
Andy Green623a98d2013-01-21 11:04:23 +08001257 return wsi->u.ws.rx_packet_length;
Andy Green38e57bb2011-01-19 12:20:27 +00001258}