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