1 /**
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0.
4  */
5 
6 #include <aws/event-stream/event_stream.h>
7 #include <aws/testing/aws_test_harness.h>
8 
9 struct test_decoder_data {
10     struct aws_event_stream_message_prelude latest_prelude;
11     char latest_header_name[100];
12     char latest_header_value[100];
13     uint8_t *latest_payload;
14     size_t written;
15     struct aws_allocator *alloc;
16     int latest_error;
17 };
18 
s_decoder_test_on_payload_segment(struct aws_event_stream_streaming_decoder * decoder,struct aws_byte_buf * data,int8_t final_segment,void * user_data)19 static void s_decoder_test_on_payload_segment(
20     struct aws_event_stream_streaming_decoder *decoder,
21     struct aws_byte_buf *data,
22     int8_t final_segment,
23     void *user_data) {
24     (void)final_segment;
25     (void)decoder;
26     struct test_decoder_data *decoder_data = (struct test_decoder_data *)user_data;
27     memcpy(decoder_data->latest_payload + decoder_data->written, data->buffer, data->len);
28     decoder_data->written += data->len;
29 }
30 
s_decoder_test_on_prelude_received(struct aws_event_stream_streaming_decoder * decoder,struct aws_event_stream_message_prelude * prelude,void * user_data)31 static void s_decoder_test_on_prelude_received(
32     struct aws_event_stream_streaming_decoder *decoder,
33     struct aws_event_stream_message_prelude *prelude,
34     void *user_data) {
35 
36     (void)decoder;
37     struct test_decoder_data *decoder_data = (struct test_decoder_data *)user_data;
38     decoder_data->latest_prelude = *prelude;
39 
40     if (decoder_data->latest_payload) {
41         aws_mem_release(decoder_data->alloc, decoder_data->latest_payload);
42     }
43 
44     const size_t payload_size = decoder_data->latest_prelude.total_len - AWS_EVENT_STREAM_PRELUDE_LENGTH -
45                                 AWS_EVENT_STREAM_TRAILER_LENGTH - decoder_data->latest_prelude.headers_len;
46 
47     if (payload_size) {
48         decoder_data->latest_payload = aws_mem_acquire(decoder_data->alloc, payload_size);
49     } else {
50         decoder_data->latest_payload = NULL;
51     }
52     decoder_data->written = 0;
53 }
54 
s_decoder_test_header_received(struct aws_event_stream_streaming_decoder * decoder,struct aws_event_stream_message_prelude * prelude,struct aws_event_stream_header_value_pair * header,void * user_data)55 static void s_decoder_test_header_received(
56     struct aws_event_stream_streaming_decoder *decoder,
57     struct aws_event_stream_message_prelude *prelude,
58     struct aws_event_stream_header_value_pair *header,
59     void *user_data) {
60     (void)decoder;
61     (void)prelude;
62     struct test_decoder_data *decoder_data = (struct test_decoder_data *)user_data;
63     memset(decoder_data->latest_header_name, 0, sizeof(decoder_data->latest_header_name));
64     memcpy(decoder_data->latest_header_name, header->header_name, (size_t)header->header_name_len);
65     memset(decoder_data->latest_header_value, 0, sizeof(decoder_data->latest_header_value));
66     memcpy(decoder_data->latest_header_value, header->header_value.variable_len_val, header->header_value_len);
67 }
68 
s_decoder_test_on_error(struct aws_event_stream_streaming_decoder * decoder,struct aws_event_stream_message_prelude * prelude,int error_code,const char * message,void * user_data)69 static void s_decoder_test_on_error(
70     struct aws_event_stream_streaming_decoder *decoder,
71     struct aws_event_stream_message_prelude *prelude,
72     int error_code,
73     const char *message,
74     void *user_data) {
75 
76     (void)decoder;
77     (void)prelude;
78     (void)message;
79     struct test_decoder_data *decoder_data = (struct test_decoder_data *)user_data;
80     decoder_data->latest_error = error_code;
81 }
82 
s_test_streaming_decoder_incoming_no_op_valid_single_message_fn(struct aws_allocator * allocator,void * ctx)83 static int s_test_streaming_decoder_incoming_no_op_valid_single_message_fn(struct aws_allocator *allocator, void *ctx) {
84     uint8_t test_data[] = {
85         0x00,
86         0x00,
87         0x00,
88         0x10,
89         0x00,
90         0x00,
91         0x00,
92         0x00,
93         0x05,
94         0xc2,
95         0x48,
96         0xeb,
97         0x7d,
98         0x98,
99         0xc8,
100         0xff,
101     };
102 
103     (void)ctx;
104     struct test_decoder_data decoder_data = {.latest_payload = 0, .written = 0, .alloc = allocator, .latest_error = 0};
105 
106     struct aws_event_stream_streaming_decoder decoder;
107     aws_event_stream_streaming_decoder_init(
108         &decoder,
109         allocator,
110         s_decoder_test_on_payload_segment,
111         s_decoder_test_on_prelude_received,
112         s_decoder_test_header_received,
113         s_decoder_test_on_error,
114         &decoder_data);
115 
116     struct aws_byte_buf test_buf = aws_byte_buf_from_array(test_data, sizeof(test_data));
117     ASSERT_SUCCESS(
118         aws_event_stream_streaming_decoder_pump(&decoder, &test_buf), "Message validation should have succeeded");
119     ASSERT_SUCCESS(decoder_data.latest_error, "No Error callback shouldn't have been called");
120 
121     ASSERT_INT_EQUALS(0x00000010, decoder_data.latest_prelude.total_len, "Message length should have been 0x10");
122     ASSERT_INT_EQUALS(0x00000000, decoder_data.latest_prelude.headers_len, "Headers Length should have been 0x00");
123     ASSERT_INT_EQUALS(0x05c248eb, decoder_data.latest_prelude.prelude_crc, "Prelude CRC should have been 0x8c335472");
124     ASSERT_INT_EQUALS(0, decoder_data.written, "No payload data should have been written");
125 
126     if (decoder_data.latest_payload) {
127         aws_mem_release(allocator, decoder_data.latest_payload);
128     }
129 
130     aws_event_stream_streaming_decoder_clean_up(&decoder);
131 
132     return 0;
133 }
134 
AWS_TEST_CASE(test_streaming_decoder_incoming_no_op_valid_single_message,s_test_streaming_decoder_incoming_no_op_valid_single_message_fn)135 AWS_TEST_CASE(
136     test_streaming_decoder_incoming_no_op_valid_single_message,
137     s_test_streaming_decoder_incoming_no_op_valid_single_message_fn)
138 
139 static int s_test_streaming_decoder_incoming_application_no_headers_fn(struct aws_allocator *allocator, void *ctx) {
140     uint8_t test_data[] = {
141         0x00, 0x00, 0x00, 0x1D, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x52, 0x8c, 0x5a, 0x7b, 0x27, 0x66,
142         0x6f, 0x6f, 0x27, 0x3a, 0x27, 0x62, 0x61, 0x72, 0x27, 0x7d, 0xc3, 0x65, 0x39, 0x36,
143     };
144 
145     (void)ctx;
146     struct test_decoder_data decoder_data = {.latest_payload = 0, .written = 0, .alloc = allocator, .latest_error = 0};
147 
148     struct aws_event_stream_streaming_decoder decoder;
149     aws_event_stream_streaming_decoder_init(
150         &decoder,
151         allocator,
152         s_decoder_test_on_payload_segment,
153         s_decoder_test_on_prelude_received,
154         s_decoder_test_header_received,
155         s_decoder_test_on_error,
156         &decoder_data);
157 
158     struct aws_byte_buf test_buf = aws_byte_buf_from_array(test_data, sizeof(test_data));
159 
160     ASSERT_SUCCESS(
161         aws_event_stream_streaming_decoder_pump(&decoder, &test_buf), "Message validation should have succeeded");
162     ASSERT_SUCCESS(decoder_data.latest_error, "No Error callback shouldn't have been called");
163 
164     ASSERT_INT_EQUALS(0x0000001D, decoder_data.latest_prelude.total_len, "Message length should have been 0x1D");
165     ASSERT_INT_EQUALS(0x00000000, decoder_data.latest_prelude.headers_len, "Headers Length should have been 0x00");
166     ASSERT_INT_EQUALS(0xfd528c5a, decoder_data.latest_prelude.prelude_crc, "Prelude CRC should have been 0xfd528c5a");
167 
168     const char *expected_str = "{'foo':'bar'}";
169     size_t payload_len = decoder_data.latest_prelude.total_len - AWS_EVENT_STREAM_PRELUDE_LENGTH -
170                          AWS_EVENT_STREAM_TRAILER_LENGTH - decoder_data.latest_prelude.headers_len;
171     ASSERT_INT_EQUALS(
172         strlen(expected_str), payload_len, "payload length should have been %d", (int)(strlen(expected_str)));
173 
174     ASSERT_BIN_ARRAYS_EQUALS(
175         expected_str,
176         strlen(expected_str),
177         decoder_data.latest_payload,
178         payload_len,
179         "payload should have been %s",
180         expected_str);
181 
182     if (decoder_data.latest_payload) {
183         aws_mem_release(allocator, decoder_data.latest_payload);
184     }
185 
186     aws_event_stream_streaming_decoder_clean_up(&decoder);
187 
188     return 0;
189 }
190 
AWS_TEST_CASE(test_streaming_decoder_incoming_application_no_headers,s_test_streaming_decoder_incoming_application_no_headers_fn)191 AWS_TEST_CASE(
192     test_streaming_decoder_incoming_application_no_headers,
193     s_test_streaming_decoder_incoming_application_no_headers_fn)
194 
195 static int s_test_streaming_decoder_incoming_application_one_compressed_header_pair_valid_fn(
196     struct aws_allocator *allocator,
197     void *ctx) {
198     (void)ctx;
199     uint8_t test_data[] = {
200         0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x20, 0x07, 0xFD, 0x83, 0x96, 0x0C, 'c',  'o',  'n',
201         't',  'e',  'n',  't',  '-',  't',  'y',  'p',  'e',  0x07, 0x00, 0x10, 'a',  'p',  'p',  'l',
202         'i',  'c',  'a',  't',  'i',  'o',  'n',  '/',  'j',  's',  'o',  'n',  0x7b, 0x27, 0x66, 0x6f,
203         0x6f, 0x27, 0x3a, 0x27, 0x62, 0x61, 0x72, 0x27, 0x7d, 0x8D, 0x9C, 0x08, 0xB1,
204     };
205 
206     struct test_decoder_data decoder_data = {
207         .latest_payload = 0,
208         .written = 0,
209         .alloc = allocator,
210         .latest_error = 0,
211     };
212 
213     struct aws_event_stream_streaming_decoder decoder;
214     aws_event_stream_streaming_decoder_init(
215         &decoder,
216         allocator,
217         s_decoder_test_on_payload_segment,
218         s_decoder_test_on_prelude_received,
219         s_decoder_test_header_received,
220         s_decoder_test_on_error,
221         &decoder_data);
222 
223     struct aws_byte_buf test_buf = aws_byte_buf_from_array(test_data, sizeof(test_data));
224 
225     ASSERT_SUCCESS(
226         aws_event_stream_streaming_decoder_pump(&decoder, &test_buf), "Message validation should have succeeded");
227     ASSERT_SUCCESS(decoder_data.latest_error, "No Error callback shouldn't have been called");
228 
229     ASSERT_INT_EQUALS(0x0000003D, decoder_data.latest_prelude.total_len, "Message length should have been 0x3D");
230     ASSERT_INT_EQUALS(0x00000020, decoder_data.latest_prelude.headers_len, "Headers Length should have been 0x20");
231     ASSERT_INT_EQUALS(0x07FD8396, decoder_data.latest_prelude.prelude_crc, "Prelude CRC should have been 0x07FD8396");
232 
233     const char *content_type = "content-type";
234     const char *content_type_value = "application/json";
235 
236     ASSERT_BIN_ARRAYS_EQUALS(
237         content_type,
238         strlen(content_type),
239         decoder_data.latest_header_name,
240         strlen(decoder_data.latest_header_name),
241         "header name should have been %s",
242         content_type);
243     ASSERT_BIN_ARRAYS_EQUALS(
244         content_type_value,
245         strlen(content_type_value),
246         decoder_data.latest_header_value,
247         strlen(decoder_data.latest_header_value),
248         "header value should have been %s",
249         content_type_value);
250 
251     const char *expected_str = "{'foo':'bar'}";
252     size_t payload_len = decoder_data.latest_prelude.total_len - AWS_EVENT_STREAM_PRELUDE_LENGTH -
253                          AWS_EVENT_STREAM_TRAILER_LENGTH - decoder_data.latest_prelude.headers_len;
254     ASSERT_INT_EQUALS(
255         strlen(expected_str), payload_len, "payload length should have been %d", (int)(strlen(expected_str)));
256 
257     ASSERT_BIN_ARRAYS_EQUALS(
258         expected_str,
259         strlen(expected_str),
260         decoder_data.latest_payload,
261         payload_len,
262         "payload should have been %s",
263         expected_str);
264 
265     if (decoder_data.latest_payload) {
266         aws_mem_release(allocator, decoder_data.latest_payload);
267     }
268 
269     return 0;
270 }
271 
AWS_TEST_CASE(test_streaming_decoder_incoming_application_one_compressed_header_pair_valid,s_test_streaming_decoder_incoming_application_one_compressed_header_pair_valid_fn)272 AWS_TEST_CASE(
273     test_streaming_decoder_incoming_application_one_compressed_header_pair_valid,
274     s_test_streaming_decoder_incoming_application_one_compressed_header_pair_valid_fn)
275 
276 static int s_test_streaming_decoder_incoming_multiple_messages_fn(struct aws_allocator *allocator, void *ctx) {
277     (void)ctx;
278     uint8_t test_data[] = {
279         /* message 1 */
280         0x00,
281         0x00,
282         0x00,
283         0x10,
284         0x00,
285         0x00,
286         0x00,
287         0x00,
288         0x05,
289         0xc2,
290         0x48,
291         0xeb,
292         0x7d,
293         0x98,
294         0xc8,
295         0xff,
296         /* message 2 */
297         0x00,
298         0x00,
299         0x00,
300         0x3D,
301         0x00,
302         0x00,
303         0x00,
304         0x20,
305         0x07,
306         0xFD,
307         0x83,
308         0x96,
309         0x0C,
310         'c',
311         'o',
312         'n',
313         't',
314         'e',
315         'n',
316         't',
317         '-',
318         't',
319         'y',
320         'p',
321         'e',
322         0x07,
323         0x00,
324         0x10,
325         'a',
326         'p',
327         'p',
328         'l',
329         'i',
330         'c',
331         'a',
332         't',
333         'i',
334         'o',
335         'n',
336         '/',
337         'j',
338         's',
339         'o',
340         'n',
341         0x7b,
342         0x27,
343         0x66,
344         0x6f,
345         0x6f,
346         0x27,
347         0x3a,
348         0x27,
349         0x62,
350         0x61,
351         0x72,
352         0x27,
353         0x7d,
354         0x8D,
355         0x9C,
356         0x08,
357         0xB1,
358     };
359 
360     size_t first_message_size = 0x10;
361     size_t read_size = 7; /* make this a weird number to force edge case coverage in the parser.
362                                 This will fall into the middle of message boundaries and preludes. */
363 
364     struct test_decoder_data decoder_data = {.latest_payload = 0, .written = 0, .alloc = allocator, .latest_error = 0};
365 
366     struct aws_event_stream_streaming_decoder decoder;
367     aws_event_stream_streaming_decoder_init(
368         &decoder,
369         allocator,
370         s_decoder_test_on_payload_segment,
371         s_decoder_test_on_prelude_received,
372         s_decoder_test_header_received,
373         s_decoder_test_on_error,
374         &decoder_data);
375 
376     size_t current_written = 0;
377     int err_code = 0;
378     while (current_written < first_message_size && !err_code) {
379         struct aws_byte_buf test_buf = aws_byte_buf_from_array(test_data + current_written, read_size);
380         err_code = aws_event_stream_streaming_decoder_pump(&decoder, &test_buf);
381         current_written += read_size;
382     }
383 
384     /* we should have written into the second message, but prior to the new prelude being found.
385        check first message was parsed correctly */
386     ASSERT_SUCCESS(err_code, "Message validation should have succeeded");
387     ASSERT_SUCCESS(decoder_data.latest_error, "No Error callback shouldn't have been called");
388 
389     ASSERT_INT_EQUALS(0x00000010, decoder_data.latest_prelude.total_len, "Message length should have been 0x10");
390     ASSERT_INT_EQUALS(0x00000000, decoder_data.latest_prelude.headers_len, "Headers Length should have been 0x00");
391     ASSERT_INT_EQUALS(0x05c248eb, decoder_data.latest_prelude.prelude_crc, "Prelude CRC should have been 0x8c335472");
392     ASSERT_INT_EQUALS(0, decoder_data.written, "No payload data should have been written");
393 
394     while (current_written < sizeof(test_data) && !err_code) {
395         size_t to_write =
396             current_written + read_size < sizeof(test_data) ? read_size : sizeof(test_data) - current_written;
397         struct aws_byte_buf test_buf = aws_byte_buf_from_array(test_data + current_written, to_write);
398         err_code = aws_event_stream_streaming_decoder_pump(&decoder, &test_buf);
399         current_written += to_write;
400     }
401 
402     /* Second message should have been found and fully parsed at this point. */
403     ASSERT_SUCCESS(err_code, "Message validation should have succeeded");
404     ASSERT_SUCCESS(decoder_data.latest_error, "No Error callback shouldn't have been called");
405 
406     ASSERT_INT_EQUALS(0x0000003D, decoder_data.latest_prelude.total_len, "Message length should have been 0x3D");
407     ASSERT_INT_EQUALS(0x00000020, decoder_data.latest_prelude.headers_len, "Headers Length should have been 0x20");
408     ASSERT_INT_EQUALS(0x07FD8396, decoder_data.latest_prelude.prelude_crc, "Prelude CRC should have been 0x07FD8396");
409 
410     const char *content_type = "content-type";
411     const char *content_type_value = "application/json";
412 
413     ASSERT_BIN_ARRAYS_EQUALS(
414         content_type,
415         strlen(content_type),
416         decoder_data.latest_header_name,
417         strlen(decoder_data.latest_header_name),
418         "header name should have been %s",
419         content_type);
420     ASSERT_BIN_ARRAYS_EQUALS(
421         content_type_value,
422         strlen(content_type_value),
423         decoder_data.latest_header_value,
424         strlen(decoder_data.latest_header_value),
425         "header value should have been %s",
426         content_type_value);
427 
428     const char *expected_str = "{'foo':'bar'}";
429     size_t payload_len = decoder_data.latest_prelude.total_len - AWS_EVENT_STREAM_PRELUDE_LENGTH -
430                          AWS_EVENT_STREAM_TRAILER_LENGTH - decoder_data.latest_prelude.headers_len;
431     ASSERT_INT_EQUALS(
432         strlen(expected_str), payload_len, "payload length should have been %d", (int)(strlen(expected_str)));
433 
434     ASSERT_BIN_ARRAYS_EQUALS(
435         expected_str,
436         strlen(expected_str),
437         decoder_data.latest_payload,
438         payload_len,
439         "payload should have been %s",
440         expected_str);
441 
442     if (decoder_data.latest_payload) {
443         aws_mem_release(allocator, decoder_data.latest_payload);
444     }
445 
446     aws_event_stream_streaming_decoder_clean_up(&decoder);
447 
448     return 0;
449 }
450 
451 AWS_TEST_CASE(test_streaming_decoder_incoming_multiple_messages, s_test_streaming_decoder_incoming_multiple_messages_fn)
452