1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 #include "s2n_test.h"
17 #include <string.h>
18 
19 #include "stuffer/s2n_stuffer.h"
20 #include "utils/s2n_blob.h"
21 #include "utils/s2n_random.h"
22 
main(int argc,char ** argv)23 int main(int argc, char **argv)
24 {
25     char c;
26     uint32_t skipped = 0;
27     struct s2n_stuffer stuffer, token;
28     struct s2n_blob pad_blob, token_blob;
29     char text[] = "    This is some text\r\n\tmore text";
30     char fields[] = "one,two,three";
31     uint8_t pad[1024];
32     char out[1024];
33     char tokenpad[6];
34 
35     BEGIN_TEST();
36     EXPECT_SUCCESS(s2n_disable_tls13());
37 
38     /* Check whitespace reading */
39     {
40         /* Create a stuffer */
41         EXPECT_SUCCESS(s2n_blob_init(&token_blob, (uint8_t *)tokenpad, sizeof(tokenpad)));
42         EXPECT_SUCCESS(s2n_stuffer_init(&token, &token_blob));
43         EXPECT_SUCCESS(s2n_blob_init(&pad_blob, (uint8_t *)pad, sizeof(pad)));
44         EXPECT_SUCCESS(s2n_stuffer_init(&stuffer, &pad_blob));
45         EXPECT_SUCCESS(s2n_stuffer_write_text(&stuffer, text, sizeof(text)));
46 
47         /* Skip 4 bytes of whitespace */
48         EXPECT_SUCCESS(s2n_stuffer_skip_whitespace(&stuffer, &skipped));
49         EXPECT_EQUAL(skipped, 4);
50         EXPECT_SUCCESS(s2n_stuffer_peek_char(&stuffer, &c));
51         EXPECT_EQUAL(c, 'T');
52 
53         /* Read the next 17 chars */
54         EXPECT_SUCCESS(s2n_stuffer_read_text(&stuffer, out, 17));
55         EXPECT_EQUAL(memcmp(out, "This is some text", 17), 0);
56 
57         /* Skip 3 bytes of whitespace */
58         EXPECT_SUCCESS(s2n_stuffer_skip_whitespace(&stuffer, &skipped));
59         EXPECT_EQUAL(skipped, 3);
60 
61         /* Read the next 10 chars (including the terminating zero) */
62         EXPECT_SUCCESS(s2n_stuffer_read_text(&stuffer, out, 10));
63         EXPECT_EQUAL(memcmp(out, "more text", 10), 0);
64 
65         /* Test end of stream behaviour */
66         EXPECT_SUCCESS(s2n_stuffer_skip_whitespace(&stuffer, NULL));
67         EXPECT_FAILURE(s2n_stuffer_peek_char(&stuffer, &c));
68         EXPECT_FAILURE(s2n_stuffer_read_char(&stuffer, &c));
69     }
70 
71     /* Check read_until, rewinding, and expecting */
72     {
73         /* Create a stuffer */
74         EXPECT_SUCCESS(s2n_blob_init(&token_blob, (uint8_t *)tokenpad, sizeof(tokenpad)));
75         EXPECT_SUCCESS(s2n_stuffer_init(&token, &token_blob));
76         EXPECT_SUCCESS(s2n_blob_init(&pad_blob, (uint8_t *)pad, sizeof(pad)));
77         EXPECT_SUCCESS(s2n_stuffer_init(&stuffer, &pad_blob));
78         EXPECT_SUCCESS(s2n_stuffer_write_text(&stuffer, text, sizeof(text)));
79 
80         char target[] = "text";
81         char non_target[] = "someStringNotInStuffer";
82         EXPECT_SUCCESS(s2n_stuffer_skip_read_until(&stuffer, target));
83         EXPECT_EQUAL(stuffer.read_cursor, 21);
84         EXPECT_SUCCESS(s2n_stuffer_rewind_read(&stuffer, strlen(target)));
85         EXPECT_EQUAL(stuffer.read_cursor, 17);
86         EXPECT_SUCCESS(s2n_stuffer_read_expected_str(&stuffer, target));
87         EXPECT_EQUAL(stuffer.read_cursor, 21);
88         EXPECT_SUCCESS(s2n_stuffer_skip_read_until(&stuffer, target));
89         EXPECT_EQUAL(stuffer.read_cursor, 33);
90         EXPECT_FAILURE(s2n_stuffer_rewind_read(&stuffer, 99));
91         EXPECT_SUCCESS(s2n_stuffer_reread(&stuffer));
92         EXPECT_SUCCESS(s2n_stuffer_skip_read_until(&stuffer, non_target));
93         EXPECT_EQUAL(stuffer.read_cursor, stuffer.write_cursor - strlen(non_target) + 1);
94     }
95 
96     /* Check token reading */
97     {
98         /* Start a new buffer */
99         EXPECT_SUCCESS(s2n_stuffer_init(&stuffer, &pad_blob));
100         EXPECT_SUCCESS(s2n_stuffer_write_text(&stuffer, fields, strlen(fields)));
101 
102         EXPECT_SUCCESS(s2n_stuffer_read_token(&stuffer, &token, ','));
103         EXPECT_EQUAL(memcmp("one", token.blob.data, 3), 0);
104 
105         EXPECT_SUCCESS(s2n_stuffer_init(&token, &token_blob));
106         EXPECT_SUCCESS(s2n_stuffer_read_token(&stuffer, &token, ','));
107         EXPECT_EQUAL(memcmp("two", token.blob.data, 3), 0);
108 
109         /* Check for end-of-stream termination */
110         EXPECT_SUCCESS(s2n_stuffer_init(&token, &token_blob));
111         EXPECT_SUCCESS(s2n_stuffer_read_token(&stuffer, &token, ','));
112         EXPECT_EQUAL(memcmp("three", token.blob.data, 5), 0);
113     }
114 
115     /* Check line reading */
116     {
117         struct s2n_blob line_blob = { 0 };
118         struct s2n_stuffer lstuffer;
119         char lf_line[] = "a LF terminated line\n";
120         char crlf_line[] = "a CRLF terminated line\r\n";
121         char lf_line_trailing_cr[] = "a LF terminated line with trailing CR\n\r\r\r\r\r\r";
122         char not_a_line[] = "not a line";
123 
124         EXPECT_SUCCESS(s2n_blob_init(&line_blob, (uint8_t *) lf_line, sizeof(lf_line)));
125         EXPECT_SUCCESS(s2n_stuffer_init(&lstuffer, &line_blob));
126         EXPECT_SUCCESS(s2n_stuffer_write(&lstuffer, &line_blob));
127         memset(pad, 0, sizeof(pad));
128         EXPECT_SUCCESS(s2n_blob_init(&pad_blob, pad, sizeof(pad)));
129         EXPECT_SUCCESS(s2n_stuffer_init(&token, &pad_blob));
130         EXPECT_SUCCESS(s2n_stuffer_read_line(&lstuffer, &token));
131         EXPECT_EQUAL(strlen("a LF terminated line"), s2n_stuffer_data_available(&token));
132         EXPECT_SUCCESS(memcmp("a LF terminated line", token.blob.data, s2n_stuffer_data_available(&token)));
133 
134         EXPECT_SUCCESS(s2n_blob_init(&line_blob, (uint8_t *) crlf_line, sizeof(crlf_line)));
135         EXPECT_SUCCESS(s2n_stuffer_init(&lstuffer, &line_blob));
136         EXPECT_SUCCESS(s2n_stuffer_write(&lstuffer, &line_blob));
137         memset(pad, 0, sizeof(pad));
138         EXPECT_SUCCESS(s2n_blob_init(&pad_blob, pad, sizeof(pad)));
139         EXPECT_SUCCESS(s2n_stuffer_init(&token, &pad_blob));
140         EXPECT_SUCCESS(s2n_stuffer_read_line(&lstuffer, &token));
141         EXPECT_EQUAL(strlen("a CRLF terminated line"), s2n_stuffer_data_available(&token));
142         EXPECT_SUCCESS(memcmp("a CRLF terminated line", token.blob.data, s2n_stuffer_data_available(&token)));
143 
144         EXPECT_SUCCESS(s2n_blob_init(&line_blob, (uint8_t *) lf_line_trailing_cr, sizeof(lf_line_trailing_cr)));
145         EXPECT_SUCCESS(s2n_stuffer_init(&lstuffer, &line_blob));
146         EXPECT_SUCCESS(s2n_stuffer_write(&lstuffer, &line_blob));
147         memset(pad, 0, sizeof(pad));
148         EXPECT_SUCCESS(s2n_blob_init(&pad_blob, pad, sizeof(pad)));
149         EXPECT_SUCCESS(s2n_stuffer_init(&token, &pad_blob));
150         EXPECT_SUCCESS(s2n_stuffer_read_line(&lstuffer, &token));
151         EXPECT_EQUAL(strlen("a LF terminated line with trailing CR"), s2n_stuffer_data_available(&token));
152         EXPECT_SUCCESS(memcmp("a LF terminated line with trailing CR", token.blob.data, s2n_stuffer_data_available(&token)));
153 
154         EXPECT_SUCCESS(s2n_blob_init(&line_blob, (uint8_t *) not_a_line, sizeof(not_a_line)));
155         EXPECT_SUCCESS(s2n_stuffer_init(&lstuffer, &line_blob));
156         EXPECT_SUCCESS(s2n_stuffer_write(&lstuffer, &line_blob));
157         memset(pad, 0, sizeof(pad));
158         EXPECT_SUCCESS(s2n_blob_init(&pad_blob, pad, sizeof(pad)));
159         EXPECT_SUCCESS(s2n_stuffer_init(&token, &pad_blob));
160         EXPECT_SUCCESS(s2n_stuffer_read_line(&lstuffer, &token));
161         EXPECT_EQUAL(sizeof(not_a_line), s2n_stuffer_data_available(&token));
162         EXPECT_SUCCESS(memcmp("not a line", token.blob.data, s2n_stuffer_data_available(&token)));
163     }
164 
165     END_TEST();
166     return 0;
167 }
168