1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5
6 #include <aws/http/private/websocket_decoder.h>
7
8 #include <aws/io/logging.h>
9 #include <aws/testing/aws_test_harness.h>
10
11 #if _MSC_VER
12 # pragma warning(disable : 4204) /* non-constant aggregate initializer */
13 #endif
14
15 #define DECODER_TEST_CASE(NAME) \
16 AWS_TEST_CASE(NAME, s_test_##NAME); \
17 static int s_test_##NAME(struct aws_allocator *allocator, void *ctx)
18
19 struct decoder_tester {
20 struct aws_allocator *alloc;
21 struct aws_logger logger;
22
23 struct aws_websocket_decoder decoder;
24 void *specific_test_data;
25
26 struct aws_websocket_frame frame;
27 size_t on_frame_count;
28 size_t fail_on_nth_frame;
29
30 struct aws_byte_buf payload;
31 size_t on_payload_count;
32 size_t fail_on_nth_payload;
33 };
34
s_on_frame(const struct aws_websocket_frame * frame,void * user_data)35 static int s_on_frame(const struct aws_websocket_frame *frame, void *user_data) {
36 struct decoder_tester *tester = user_data;
37
38 tester->frame = *frame;
39
40 tester->on_frame_count++;
41 if (tester->on_frame_count == tester->fail_on_nth_frame) {
42 return aws_raise_error(AWS_ERROR_HTTP_UNKNOWN);
43 }
44
45 return AWS_OP_SUCCESS;
46 }
47
s_on_payload(struct aws_byte_cursor data,void * user_data)48 static int s_on_payload(struct aws_byte_cursor data, void *user_data) {
49 struct decoder_tester *tester = user_data;
50
51 ASSERT_SUCCESS(aws_byte_buf_append_dynamic(&tester->payload, &data));
52
53 tester->on_payload_count++;
54 if (tester->on_payload_count == tester->fail_on_nth_payload) {
55 return aws_raise_error(AWS_ERROR_HTTP_UNKNOWN);
56 }
57
58 return AWS_OP_SUCCESS;
59 }
60
61 /* For resetting the decoder and its results mid-test */
s_decoder_tester_reset(struct decoder_tester * tester)62 static void s_decoder_tester_reset(struct decoder_tester *tester) {
63 aws_websocket_decoder_init(&tester->decoder, s_on_frame, s_on_payload, tester);
64 AWS_ZERO_STRUCT(tester->frame);
65 tester->on_frame_count = 0;
66 tester->payload.len = 0;
67 tester->on_payload_count = 0;
68 }
69
s_decoder_tester_init(struct decoder_tester * tester,struct aws_allocator * alloc)70 static int s_decoder_tester_init(struct decoder_tester *tester, struct aws_allocator *alloc) {
71 aws_http_library_init(alloc);
72
73 AWS_ZERO_STRUCT(*tester);
74 tester->alloc = alloc;
75
76 struct aws_logger_standard_options logger_options = {
77 .level = AWS_LOG_LEVEL_TRACE,
78 .file = stderr,
79 };
80 ASSERT_SUCCESS(aws_logger_init_standard(&tester->logger, tester->alloc, &logger_options));
81 aws_logger_set(&tester->logger);
82
83 ASSERT_SUCCESS(aws_byte_buf_init(&tester->payload, alloc, 1024));
84
85 s_decoder_tester_reset(tester);
86
87 return AWS_OP_SUCCESS;
88 }
89
s_decoder_tester_clean_up(struct decoder_tester * tester)90 static int s_decoder_tester_clean_up(struct decoder_tester *tester) {
91 aws_byte_buf_clean_up(&tester->payload);
92 aws_http_library_clean_up();
93 aws_logger_clean_up(&tester->logger);
94 return AWS_OP_SUCCESS;
95 }
96
s_compare_frame(const struct aws_websocket_frame * expected,const struct aws_websocket_frame * decoded)97 static int s_compare_frame(const struct aws_websocket_frame *expected, const struct aws_websocket_frame *decoded) {
98 uint8_t a[24];
99 memcpy(a, expected, 24);
100 uint8_t b[24];
101 memcpy(b, decoded, 24);
102
103 /* compare each field so it's clear where test failed */
104 ASSERT_UINT_EQUALS(expected->fin, decoded->fin);
105 ASSERT_UINT_EQUALS(expected->rsv[0], decoded->rsv[0]);
106 ASSERT_UINT_EQUALS(expected->rsv[1], decoded->rsv[1]);
107 ASSERT_UINT_EQUALS(expected->rsv[2], decoded->rsv[2]);
108 ASSERT_UINT_EQUALS(expected->masked, decoded->masked);
109 ASSERT_UINT_EQUALS(expected->opcode, decoded->opcode);
110 ASSERT_UINT_EQUALS(expected->payload_length, decoded->payload_length);
111 ASSERT_UINT_EQUALS(expected->masking_key[0], decoded->masking_key[0]);
112 ASSERT_UINT_EQUALS(expected->masking_key[1], decoded->masking_key[1]);
113 ASSERT_UINT_EQUALS(expected->masking_key[2], decoded->masking_key[2]);
114 ASSERT_UINT_EQUALS(expected->masking_key[3], decoded->masking_key[3]);
115
116 return AWS_OP_SUCCESS;
117 };
118
DECODER_TEST_CASE(websocket_decoder_sanity_check)119 DECODER_TEST_CASE(websocket_decoder_sanity_check) {
120 (void)ctx;
121 struct decoder_tester tester;
122 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
123 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
124 return AWS_OP_SUCCESS;
125 }
126
127 /* Test decoding simplest possible frame, no payload */
DECODER_TEST_CASE(websocket_decoder_simplest_frame)128 DECODER_TEST_CASE(websocket_decoder_simplest_frame) {
129 (void)ctx;
130 struct decoder_tester tester;
131 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
132
133 uint8_t input[] = {
134 0x89, // fin | rsv1 | rsv2 | rsv3 | 4bit opcode
135 0x00, // mask | 7bit payload len
136 };
137
138 struct aws_websocket_frame expected_frame = {
139 .fin = true,
140 .opcode = 9,
141 };
142
143 bool frame_complete;
144 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
145 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
146
147 /* check result */
148 ASSERT_TRUE(frame_complete);
149 ASSERT_UINT_EQUALS(1, tester.on_frame_count);
150 ASSERT_UINT_EQUALS(0, tester.on_payload_count);
151 ASSERT_UINT_EQUALS(0, tester.payload.len);
152 ASSERT_UINT_EQUALS(0, input_cursor.len);
153
154 ASSERT_SUCCESS(s_compare_frame(&expected_frame, &tester.frame));
155
156 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
157 return AWS_OP_SUCCESS;
158 }
159
160 /* Test the 3 RSV bools */
DECODER_TEST_CASE(websocket_decoder_rsv)161 DECODER_TEST_CASE(websocket_decoder_rsv) {
162 (void)ctx;
163 struct decoder_tester tester;
164 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
165
166 /* Test 3 times, each time with one RSV bool set */
167 for (int rsv = 0; rsv < 3; ++rsv) {
168
169 uint8_t input[] = {
170 0x89, // fin | rsv1 | rsv2 | rsv3 | 4bit opcode
171 0x00, // mask | 7bit payload len
172 };
173
174 /* Set the appropriate RSV */
175 /* the bit arithmetic is setup this way to avoid Conversion warnings from the compiler. */
176 input[0] |= (1 << (6 - rsv));
177
178 struct aws_websocket_frame expected_frame = {
179 .fin = true,
180 .opcode = 9,
181 };
182 expected_frame.rsv[rsv] = true;
183
184 bool frame_complete;
185 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
186 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
187
188 /* check result */
189 ASSERT_TRUE(frame_complete);
190 ASSERT_SUCCESS(s_compare_frame(&expected_frame, &tester.frame));
191 }
192
193 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
194 return AWS_OP_SUCCESS;
195 }
196
197 /* Test decoding a simple data frame, with a payload */
DECODER_TEST_CASE(websocket_decoder_data_frame)198 DECODER_TEST_CASE(websocket_decoder_data_frame) {
199 (void)ctx;
200 struct decoder_tester tester;
201 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
202
203 uint8_t input[] = {
204 0x82, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
205 0x04, /* mask | 7bit payload len */
206 /* payload */
207 0x00,
208 0x0F,
209 0xF0,
210 0xFF,
211 };
212
213 const uint8_t expected_payload[] = {0x00, 0x0F, 0xF0, 0xFF};
214
215 struct aws_websocket_frame expected_frame = {
216 .fin = true,
217 .opcode = 2,
218 .payload_length = sizeof(expected_payload),
219 };
220
221 bool frame_complete;
222 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
223 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
224
225 /* check result */
226 ASSERT_TRUE(frame_complete);
227 ASSERT_UINT_EQUALS(1, tester.on_frame_count);
228 ASSERT_UINT_EQUALS(1, tester.on_payload_count);
229 ASSERT_UINT_EQUALS(0, input_cursor.len);
230
231 ASSERT_SUCCESS(s_compare_frame(&expected_frame, &tester.frame));
232
233 struct aws_byte_cursor expected_cursor = aws_byte_cursor_from_array(expected_payload, sizeof(expected_payload));
234 ASSERT_TRUE(aws_byte_cursor_eq_byte_buf(&expected_cursor, &tester.payload));
235
236 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
237 return AWS_OP_SUCCESS;
238 }
239
240 /* Test aws_websocket_decoder_process() returns at the end of each frame */
DECODER_TEST_CASE(websocket_decoder_stops_at_frame_end)241 DECODER_TEST_CASE(websocket_decoder_stops_at_frame_end) {
242 (void)ctx;
243 struct decoder_tester tester;
244 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
245
246 uint8_t input[] = {
247 0x82, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
248 0x04, /* mask | 7bit payload len */
249 /* payload */
250 0x00,
251 0x0F,
252 0xF0,
253 0xFF,
254 /* extra data that should not be processed */
255 0x11,
256 0x22,
257 };
258
259 bool frame_complete;
260 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
261 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
262
263 /* check result */
264 ASSERT_TRUE(frame_complete);
265 ASSERT_UINT_EQUALS(1, tester.on_frame_count);
266 ASSERT_UINT_EQUALS(1, tester.on_payload_count);
267 ASSERT_UINT_EQUALS(2, input_cursor.len); /* Check that there's data left over */
268
269 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
270 return AWS_OP_SUCCESS;
271 }
272
273 /* Test a single frame masked text message */
DECODER_TEST_CASE(websocket_decoder_masking)274 DECODER_TEST_CASE(websocket_decoder_masking) {
275 (void)ctx;
276 struct decoder_tester tester;
277 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
278
279 /* Test from RFC-6545 Section 5.7 - Examples - A single-frame masked text message */
280 uint8_t input[] = {
281 0x81, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
282 0x85, /* mask | 7bit payload len */
283 /* masking key */
284 0x37,
285 0xfa,
286 0x21,
287 0x3d,
288 /* payload */
289 0x7f,
290 0x9f,
291 0x4d,
292 0x51,
293 0x58,
294 };
295
296 const char *expected_payload = "Hello";
297
298 struct aws_websocket_frame expected_frame = {
299 .fin = true,
300 .opcode = 1,
301 .masked = true,
302 .masking_key = {0x37, 0xfa, 0x21, 0x3d},
303 .payload_length = strlen(expected_payload),
304 };
305
306 bool frame_complete;
307 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
308 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
309
310 /* check result */
311 ASSERT_TRUE(frame_complete);
312 ASSERT_SUCCESS(s_compare_frame(&expected_frame, &tester.frame));
313 ASSERT_TRUE(aws_byte_buf_eq_c_str(&tester.payload, expected_payload));
314
315 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
316 return AWS_OP_SUCCESS;
317 }
318
319 /* Test a data frame which uses the 2 byte extended-length encoding */
DECODER_TEST_CASE(websocket_decoder_extended_length_2byte)320 DECODER_TEST_CASE(websocket_decoder_extended_length_2byte) {
321 (void)ctx;
322 struct decoder_tester tester;
323 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
324
325 struct length_validity_pair {
326 uint16_t len;
327 bool valid;
328 };
329
330 uint8_t input[4] = {
331 0x82, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
332 0x7E, /* mask | 7bit payload len */
333 /* 2byte extended length... */
334 };
335
336 struct aws_websocket_frame expected_frame = {
337 .fin = true,
338 .opcode = 2,
339 };
340
341 /* lengths greater than 125 should be encoded in 2 bytes */
342 struct length_validity_pair length_validity_pairs[] = {
343 {0, false}, /* should use 7bit length encoding */
344 {1, false}, /* should use 7bit length encoding */
345 {125, false}, /* highest number for 7bit length encoding */
346 {126, true}, /* lowest number for 2byte extended length */
347 {127, true}, /* should be encoded in 2byte extended length */
348 {0x0100, true}, /* just another value for 2byte extended length */
349 {0xFFFF, true}, /* highest number for 2byte extended length */
350 };
351
352 for (size_t i = 0; i < AWS_ARRAY_SIZE(length_validity_pairs); ++i) {
353 struct length_validity_pair pair_i = length_validity_pairs[i];
354 s_decoder_tester_reset(&tester);
355
356 /* write extended-length to input buffer */
357 uint16_t network_num = aws_hton16(pair_i.len);
358 memcpy(input + 2, &network_num, sizeof(network_num));
359
360 /* adapt expected_frame */
361 expected_frame.payload_length = pair_i.len;
362
363 /* Process input (only sending non-payload portion of frame) */
364 bool frame_complete;
365 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
366
367 if (pair_i.valid) {
368 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
369
370 /* check result */
371 ASSERT_FALSE(frame_complete);
372 ASSERT_UINT_EQUALS(0, input_cursor.len);
373 ASSERT_UINT_EQUALS(1, tester.on_frame_count);
374 ASSERT_UINT_EQUALS(0, tester.on_payload_count);
375 ASSERT_SUCCESS(s_compare_frame(&expected_frame, &tester.frame));
376 } else {
377 aws_raise_error(-1); /* overwrite last-error */
378
379 ASSERT_FAILS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
380 ASSERT_INT_EQUALS(AWS_ERROR_HTTP_PROTOCOL_ERROR, aws_last_error());
381 }
382 }
383
384 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
385 return AWS_OP_SUCCESS;
386 }
387
DECODER_TEST_CASE(websocket_decoder_extended_length_8byte)388 DECODER_TEST_CASE(websocket_decoder_extended_length_8byte) {
389 (void)ctx;
390 struct decoder_tester tester;
391 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
392
393 struct length_validity_pair {
394 uint64_t len;
395 bool valid;
396 };
397
398 uint8_t input[10] = {
399 0x82, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
400 0x7F, /* mask | 7bit payload len */
401 /* 8byte extended length... */
402 };
403
404 struct aws_websocket_frame expected_frame = {
405 .fin = true,
406 .opcode = 2,
407 };
408
409 /* 8byte lengths should require at least 2 bytes to encode, and the high-order bit should be 0 */
410 struct length_validity_pair length_validity_pairs[] = {
411 {125, false}, /* highest number for 7bit length encoding */
412 {126, false}, /* lowest number for 2byte extended length */
413 {127, false}, /* should be encoded in 2byte extended length */
414 {0x0100, false}, /* just another value for 2byte extended length */
415 {0xFFFF, false}, /* highest number for 2byte extended length */
416 {0x0000000000010000, true}, /* lowest number for 8byte extended length */
417 {0x7FFFFFFFFFFFFFFF, true}, /* highest number for 8byte extended length */
418 {0x123456789ABCDEF0, true}, /* just another value for 8byte extended length */
419 {0x8000000000000000, false}, /* illegal use high bit in 8byte extended length */
420 {0xFFFFFFFFFFFFFFFF, false}, /* illegal use high bit in 8byte extended length */
421 };
422
423 for (size_t i = 0; i < AWS_ARRAY_SIZE(length_validity_pairs); ++i) {
424 struct length_validity_pair pair_i = length_validity_pairs[i];
425 s_decoder_tester_reset(&tester);
426
427 /* write extended-length to input buffer */
428 uint64_t network_num = aws_hton64(pair_i.len);
429 memcpy(input + 2, &network_num, sizeof(network_num));
430
431 /* adapt expected_frame */
432 expected_frame.payload_length = pair_i.len;
433
434 /* Process input (only sending non-payload portion of frame) */
435 bool frame_complete;
436 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
437
438 if (pair_i.valid) {
439 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
440
441 /* check result */
442 ASSERT_FALSE(frame_complete);
443 ASSERT_UINT_EQUALS(0, input_cursor.len);
444 ASSERT_UINT_EQUALS(1, tester.on_frame_count);
445 ASSERT_UINT_EQUALS(0, tester.on_payload_count);
446 ASSERT_SUCCESS(s_compare_frame(&expected_frame, &tester.frame));
447 } else {
448 aws_raise_error(-1); /* overwrite last-error */
449
450 ASSERT_FAILS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
451 ASSERT_INT_EQUALS(AWS_ERROR_HTTP_PROTOCOL_ERROR, aws_last_error());
452 }
453 }
454
455 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
456 return AWS_OP_SUCCESS;
457 }
458
459 /* Test that decoder can handle data that's split at any possible point */
DECODER_TEST_CASE(websocket_decoder_1byte_at_a_time)460 DECODER_TEST_CASE(websocket_decoder_1byte_at_a_time) {
461 (void)ctx;
462 struct decoder_tester tester;
463 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
464
465 /* Use all optional frame features in this test (8byte extended payload length and masking-key).
466 * Even though we say the payload is long, we're only going to send a portion of it in this test */
467 uint8_t input[] = {
468 0x81, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
469 0xFF, /* mask | 7bit payload len */
470 /* 8byte extended payload len */
471 0x00,
472 0x00,
473 0x00,
474 0x00,
475 0x00,
476 0x01,
477 0x00,
478 0x00,
479 /* masking key */
480 0x37,
481 0xfa,
482 0x21,
483 0x3d,
484 /* payload */
485 0x7f,
486 0x9f,
487 0x4d,
488 0x51,
489 0x58,
490 };
491
492 const char *expected_payload = "Hello";
493
494 struct aws_websocket_frame expected_frame = {
495 .fin = true,
496 .opcode = 1,
497 .masked = true,
498 .masking_key = {0x37, 0xfa, 0x21, 0x3d},
499 .payload_length = 0x10000,
500 };
501
502 for (size_t i = 0; i < sizeof(input); ++i) {
503 bool frame_complete;
504 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input + i, 1);
505 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
506 ASSERT_FALSE(frame_complete);
507 ASSERT_UINT_EQUALS(0, input_cursor.len);
508 }
509
510 /* check result */
511 ASSERT_UINT_EQUALS(1, tester.on_frame_count);
512 ASSERT_UINT_EQUALS(5, tester.on_payload_count);
513 ASSERT_SUCCESS(s_compare_frame(&expected_frame, &tester.frame));
514 ASSERT_TRUE(aws_byte_buf_eq_c_str(&tester.payload, expected_payload));
515
516 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
517 return AWS_OP_SUCCESS;
518 }
519
DECODER_TEST_CASE(websocket_decoder_fail_on_unknown_opcode)520 DECODER_TEST_CASE(websocket_decoder_fail_on_unknown_opcode) {
521 (void)ctx;
522 struct decoder_tester tester;
523 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
524
525 uint8_t input[] = {
526 0x07, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
527 0x00, /* mask | 7bit payload len */
528 };
529
530 bool frame_complete;
531 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
532 ASSERT_FAILS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
533 ASSERT_INT_EQUALS(AWS_ERROR_HTTP_PROTOCOL_ERROR, aws_last_error());
534
535 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
536 return AWS_OP_SUCCESS;
537 }
538
539 /* Test fragmented messages, which arrive across multiple frames whose FIN bit is cleared */
DECODER_TEST_CASE(websocket_decoder_fragmented_message)540 DECODER_TEST_CASE(websocket_decoder_fragmented_message) {
541 (void)ctx;
542 struct decoder_tester tester;
543 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
544
545 uint8_t input[] = {
546 /* TEXT FRAME */
547 0x01, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
548 0x03, /* mask | 7bit payload len */
549 'h',
550 'o',
551 't',
552
553 /* CONTINUATION FRAME */
554 0x00, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
555 0x02, /* mask | 7bit payload len */
556 'd',
557 'o',
558
559 /* PING FRAME - Control frames may be injected in the middle of a fragmented message. */
560 0x89, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
561 0x00, /* mask | 7bit payload len */
562
563 /* CONTINUATION FRAME */
564 0x80, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
565 0x01, /* mask | 7bit payload len */
566 'g',
567 };
568
569 struct aws_websocket_frame expected_frames[] = {
570 {
571 .fin = false,
572 .opcode = 1,
573 .payload_length = 3,
574 },
575 {
576 .fin = false,
577 .opcode = 0,
578 .payload_length = 2,
579 },
580 {
581 .fin = true,
582 .opcode = 9,
583 },
584 {
585 .fin = true,
586 .opcode = 0,
587 .payload_length = 1,
588 },
589 };
590
591 const char *expected_payload = "hotdog";
592
593 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
594 for (size_t i = 0; i < AWS_ARRAY_SIZE(expected_frames); ++i) {
595 bool frame_complete;
596 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
597 ASSERT_TRUE(frame_complete);
598 ASSERT_UINT_EQUALS(i + 1, tester.on_frame_count);
599 ASSERT_SUCCESS(s_compare_frame(&expected_frames[i], &tester.frame));
600 }
601
602 ASSERT_TRUE(aws_byte_buf_eq_c_str(&tester.payload, expected_payload));
603
604 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
605 return AWS_OP_SUCCESS;
606 }
607
DECODER_TEST_CASE(websocket_decoder_fail_on_bad_fragmentation)608 DECODER_TEST_CASE(websocket_decoder_fail_on_bad_fragmentation) {
609 (void)ctx;
610 struct decoder_tester tester;
611 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
612
613 uint8_t input[] = {
614 /* TEXT FRAME with FIN=0 */
615 0x01, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
616 0x01, /* mask | 7bit payload len */
617 'a',
618
619 /* TEXT FRAME - but ought to be a CONTINUATION frame */
620 0x01, /* fin | rsv1 | rsv2 | rsv3 | 4bit opcode */
621 0x01, /* mask | 7bit payload len */
622 'b',
623 };
624
625 bool frame_complete;
626 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
627 ASSERT_SUCCESS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
628 ASSERT_FAILS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
629 ASSERT_INT_EQUALS(AWS_ERROR_HTTP_PROTOCOL_ERROR, aws_last_error());
630
631 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
632 return AWS_OP_SUCCESS;
633 }
634
635 /* Control frames must have FIN bit set */
DECODER_TEST_CASE(websocket_decoder_control_frame_cannot_be_fragmented)636 DECODER_TEST_CASE(websocket_decoder_control_frame_cannot_be_fragmented) {
637 (void)ctx;
638 struct decoder_tester tester;
639 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
640
641 uint8_t input[] = {
642 0x0A, // fin | rsv1 | rsv2 | rsv3 | 4bit opcode
643 0x00, // mask | 7bit payload len
644 };
645
646 bool frame_complete;
647 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
648 ASSERT_FAILS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
649 ASSERT_INT_EQUALS(AWS_ERROR_HTTP_PROTOCOL_ERROR, aws_last_error());
650
651 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
652 return AWS_OP_SUCCESS;
653 }
654
655 /* Test that an error from the on_frame callback fails the decoder */
DECODER_TEST_CASE(websocket_decoder_on_frame_callback_can_fail_decoder)656 DECODER_TEST_CASE(websocket_decoder_on_frame_callback_can_fail_decoder) {
657 (void)ctx;
658 struct decoder_tester tester;
659 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
660
661 uint8_t input[] = {
662 0x81, // fin | rsv1 | rsv2 | rsv3 | 4bit opcode
663 0x01, // mask | 7bit payload len
664 'a',
665 };
666
667 tester.fail_on_nth_frame = 1;
668
669 bool frame_complete;
670 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
671 ASSERT_FAILS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
672
673 /* Check that error returned by callback bubbles up.
674 * UNKNOWN error just happens to be what our test callback throws */
675 ASSERT_INT_EQUALS(AWS_ERROR_HTTP_UNKNOWN, aws_last_error());
676
677 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
678 return AWS_OP_SUCCESS;
679 }
680
DECODER_TEST_CASE(websocket_decoder_on_payload_callback_can_fail_decoder)681 DECODER_TEST_CASE(websocket_decoder_on_payload_callback_can_fail_decoder) {
682 (void)ctx;
683 struct decoder_tester tester;
684 ASSERT_SUCCESS(s_decoder_tester_init(&tester, allocator));
685
686 uint8_t input[] = {
687 0x81, // fin | rsv1 | rsv2 | rsv3 | 4bit opcode
688 0x01, // mask | 7bit payload len
689 'a',
690 };
691
692 tester.fail_on_nth_payload = 1;
693
694 bool frame_complete;
695 struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input, sizeof(input));
696 ASSERT_FAILS(aws_websocket_decoder_process(&tester.decoder, &input_cursor, &frame_complete));
697
698 /* Check that error returned by callback bubbles up.
699 * UNKNOWN error just happens to be what our test callback throws */
700 ASSERT_INT_EQUALS(AWS_ERROR_HTTP_UNKNOWN, aws_last_error());
701
702 ASSERT_SUCCESS(s_decoder_tester_clean_up(&tester));
703 return AWS_OP_SUCCESS;
704 }
705