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