1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21 
22 #include <zephyr/net/http/parser.h>
23 #include <string.h>
24 #include <errno.h>
25 
26 #include <zephyr/sys/printk.h>
27 #include <zephyr/tc_util.h>
28 #include <zephyr/ztest.h>
29 
30 static
31 struct http_parser_settings settings_null = {
32 	.on_message_begin = 0,
33 	.on_header_field = 0,
34 	.on_header_value = 0,
35 	.on_url = 0,
36 	.on_status = 0,
37 	.on_body = 0,
38 	.on_headers_complete = 0,
39 	.on_message_complete = 0,
40 	.on_chunk_header = 0,
41 	.on_chunk_complete = 0};
42 
43 struct url_test {
44 	const char *name;
45 	const char *url;
46 	int is_connect;
47 	struct http_parser_url u;
48 	int rv;
49 };
50 
51 const struct url_test url_tests[] = {
52 	{
53 	.name = "proxy request",
54 	.url = "http://hostname/",
55 	.is_connect = 0,
56 	.u = {	.field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH),
57 		.port = 0,
58 		.field_data = {
59 			{  0,  4 },	/* UF_SCHEMA */
60 			{  7,  8 },	/* UF_HOST */
61 			{  0,  0 },	/* UF_PORT */
62 			{ 15,  1 },	/* UF_PATH */
63 			{  0,  0 },	/* UF_QUERY */
64 			{  0,  0 },	/* UF_FRAGMENT */
65 			{  0,  0 } } },	/* UF_USERINFO */
66 	.rv = 0
67 	},
68 
69 	{
70 	.name = "proxy request with port",
71 	.url = "http://hostname:444/",
72 	.is_connect = 0,
73 	.u = {	.field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) |
74 			     (1 << UF_PORT) | (1 << UF_PATH),
75 		.port = 444,
76 		.field_data = {
77 			{  0,  4 },	/* UF_SCHEMA */
78 			{  7,  8 },	/* UF_HOST */
79 			{ 16,  3 },	/* UF_PORT */
80 			{ 19,  1 },	/* UF_PATH */
81 			{  0,  0 },	/* UF_QUERY */
82 			{  0,  0 },	/* UF_FRAGMENT */
83 			{  0,  0 } } },	/* UF_USERINFO */
84 	.rv = 0
85 	},
86 
87 	{
88 	.name = "CONNECT request",
89 	.url = "hostname:443",
90 	.is_connect = 1,
91 	.u = {	.field_set = (1 << UF_HOST) | (1 << UF_PORT),
92 		.port = 443,
93 		.field_data = {
94 			{  0,  0 },	/* UF_SCHEMA */
95 			{  0,  8 },	/* UF_HOST */
96 			{  9,  3 },	/* UF_PORT */
97 			{  0,  0 },	/* UF_PATH */
98 			{  0,  0 },	/* UF_QUERY */
99 			{  0,  0 },	/* UF_FRAGMENT */
100 			{  0,  0 } } },	/* UF_USERINFO */
101 	.rv = 0
102 	},
103 
104 	{
105 	.name = "CONNECT request but not connect",
106 	.url = "hostname:443",
107 	.is_connect = 0,
108 	.rv = 1
109 	},
110 
111 	{
112 	.name = "proxy ipv6 request",
113 	.url = "http://[1:2::3:4]/",
114 	.is_connect = 0,
115 	.u = {	.field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH),
116 		.port = 0,
117 		.field_data = {
118 			{  0,  4 },	/* UF_SCHEMA */
119 			{  8,  8 },	/* UF_HOST */
120 			{  0,  0 },	/* UF_PORT */
121 			{ 17,  1 },	/* UF_PATH */
122 			{  0,  0 },	/* UF_QUERY */
123 			{  0,  0 },	/* UF_FRAGMENT */
124 			{  0,  0 } } },	/* UF_USERINFO */
125 	.rv = 0
126 	},
127 
128 	{
129 	.name = "proxy ipv6 request with port",
130 	.url = "http://[1:2::3:4]:67/",
131 	.is_connect = 0,
132 	.u = {	.field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) |
133 			     (1 << UF_PORT) | (1 << UF_PATH),
134 		.port = 67,
135 		.field_data = {
136 			{  0,  4 },	/* UF_SCHEMA */
137 			{  8,  8 },	/* UF_HOST */
138 			{ 18,  2 },	/* UF_PORT */
139 			{ 20,  1 },	/* UF_PATH */
140 			{  0,  0 },	/* UF_QUERY */
141 			{  0,  0 },	/* UF_FRAGMENT */
142 			{  0,  0 } } },	/* UF_USERINFO */
143 	.rv = 0
144 	},
145 
146 	{
147 	.name = "CONNECT ipv6 address",
148 	.url = "[1:2::3:4]:443",
149 	.is_connect = 1,
150 	.u = {	.field_set = (1 << UF_HOST) | (1 << UF_PORT),
151 		.port = 443,
152 		.field_data = {
153 			{  0,  0 },	/* UF_SCHEMA */
154 			{  1,  8 },	/* UF_HOST */
155 			{ 11,  3 },	/* UF_PORT */
156 			{  0,  0 },	/* UF_PATH */
157 			{  0,  0 },	/* UF_QUERY */
158 			{  0,  0 },	/* UF_FRAGMENT */
159 			{  0,  0 } } },	/* UF_USERINFO */
160 	.rv = 0
161 	},
162 
163 	{
164 	.name = "ipv4 in ipv6 address",
165 	.url = "http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/",
166 	.is_connect = 0,
167 	.u = {	.field_set = (1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH),
168 		.port = 0,
169 		.field_data = {
170 			{  0,  4 },	/* UF_SCHEMA */
171 			{  8, 37 },	/* UF_HOST */
172 			{  0,  0 },	/* UF_PORT */
173 			{ 46,  1 },	/* UF_PATH */
174 			{  0,  0 },	/* UF_QUERY */
175 			{  0,  0 },	/* UF_FRAGMENT */
176 			{  0,  0 } } },	/* UF_USERINFO */
177 	.rv = 0
178 	},
179 
180 	{
181 	.name = "extra ? in query string",
182 	.url = "http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,"
183 	       "fp-base-min.css,fp-channel-min.css,fp-product-min.css,fp-mall-"
184 	       "min.css,fp-category-min.css,fp-sub-min.css,fp-gdp4p-min.css,"
185 	       "fp-css3-min.css,fp-misc-min.css?t=20101022.css",
186 	.is_connect = 0,
187 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
188 			     (1<<UF_QUERY),
189 		.port = 0,
190 		.field_data = {
191 			{  0,  4 },	/* UF_SCHEMA */
192 			{  7, 10 },	/* UF_HOST */
193 			{  0,  0 },	/* UF_PORT */
194 			{ 17, 12 },	/* UF_PATH */
195 			{ 30, 187},	/* UF_QUERY */
196 			{  0,  0 },	/* UF_FRAGMENT */
197 			{  0,  0 } } },	/* UF_USERINFO */
198 		.rv = 0
199 	},
200 
201 	{
202 	.name = "space URL encoded",
203 	.url = "/toto.html?toto=a%20b",
204 	.is_connect = 0,
205 	.u = {	.field_set = (1<<UF_PATH) | (1<<UF_QUERY),
206 		.port = 0,
207 		.field_data = {
208 			{  0,  0 },	/* UF_SCHEMA */
209 			{  0,  0 },	/* UF_HOST */
210 			{  0,  0 },	/* UF_PORT */
211 			{  0, 10 },	/* UF_PATH */
212 			{ 11, 10 },	/* UF_QUERY */
213 			{  0,  0 },	/* UF_FRAGMENT */
214 			{  0,  0 } } },	/* UF_USERINFO */
215 	.rv = 0
216 	},
217 
218 	{
219 	.name = "URL fragment",
220 	.url = "/toto.html#titi",
221 	.is_connect = 0,
222 	.u = {	.field_set = (1<<UF_PATH) | (1<<UF_FRAGMENT),
223 		.port = 0,
224 		.field_data = {
225 			{  0,  0 },	/* UF_SCHEMA */
226 			{  0,  0 },	/* UF_HOST */
227 			{  0,  0 },	/* UF_PORT */
228 			{  0, 10 },	/* UF_PATH */
229 			{  0,  0 },	/* UF_QUERY */
230 			{ 11,  4 },	/* UF_FRAGMENT */
231 			{  0,  0 } } },	/* UF_USERINFO */
232 	.rv = 0
233 	},
234 
235 	{
236 	.name = "complex URL fragment",
237 	.url = "http://www.webmasterworld.com/r.cgi?f=21&d=8405&url="
238 		"http://www.example.com/index.html?foo=bar&hello=world#midpage",
239 	.is_connect = 0,
240 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
241 			     (1<<UF_QUERY) | (1<<UF_FRAGMENT),
242 		.port = 0,
243 		.field_data = {
244 			{  0,  4 },	/* UF_SCHEMA */
245 			{  7, 22 },	/* UF_HOST */
246 			{  0,  0 },	/* UF_PORT */
247 			{ 29,  6 },	/* UF_PATH */
248 			{ 36, 69 },	/* UF_QUERY */
249 			{106,  7 },	/* UF_FRAGMENT */
250 			{  0,  0 } } },	/* UF_USERINFO */
251 	.rv = 0
252 	},
253 
254 	{
255 	.name = "complex URL from node js url parser doc",
256 	.url = "http://host.com:8080/p/a/t/h?query=string#hash",
257 	.is_connect = 0,
258 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) |
259 			     (1<<UF_PATH) | (1<<UF_QUERY) | (1<<UF_FRAGMENT),
260 		.port = 8080,
261 		.field_data =  {
262 			{  0,  4 },	/* UF_SCHEMA */
263 			{  7,  8 },	/* UF_HOST */
264 			{ 16,  4 },	/* UF_PORT */
265 			{ 20,  8 },	/* UF_PATH */
266 			{ 29, 12 },	/* UF_QUERY */
267 			{ 42,  4 },	/* UF_FRAGMENT */
268 			{  0,  0 } } },	/* UF_USERINFO */
269 	.rv = 0
270 	},
271 
272 	{
273 	.name = "complex URL with basic auth from node js url parser doc",
274 	.url = "http://a:b@host.com:8080/p/a/t/h?query=string#hash",
275 	.is_connect = 0,
276 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PORT) |
277 			     (1<<UF_PATH) | (1<<UF_QUERY) | (1<<UF_FRAGMENT) |
278 			     (1<<UF_USERINFO),
279 	.port = 8080,
280 	.field_data = {
281 			{  0,  4 },	/* UF_SCHEMA */
282 			{ 11,  8 },	/* UF_HOST */
283 			{ 20,  4 },	/* UF_PORT */
284 			{ 24,  8 },	/* UF_PATH */
285 			{ 33, 12 },	/* UF_QUERY */
286 			{ 46,  4 },	/* UF_FRAGMENT */
287 			{  7,  3 } } },	/* UF_USERINFO */
288 	.rv = 0
289 	},
290 
291 	{
292 	.name = "double @",
293 	.url = "http://a:b@@hostname:443/",
294 	.is_connect = 0,
295 	.rv = 1
296 	},
297 
298 	{
299 	.name = "proxy empty host",
300 	.url = "http://:443/",
301 	.is_connect = 0,
302 	.rv = 1
303 	},
304 
305 	{
306 	.name = "proxy empty port",
307 	.url = "http://hostname:/",
308 	.is_connect = 0,
309 	.rv = 1,
310 	},
311 
312 	{
313 	.name = "CONNECT with basic auth",
314 	.url = "a:b@hostname:443",
315 	.is_connect = 1,
316 	.rv = 1,
317 	},
318 
319 	{
320 	.name = "CONNECT empty host",
321 	.url = ":443",
322 	.is_connect = 1,
323 	.rv = 1,
324 	},
325 
326 	{
327 	.name = "CONNECT empty port",
328 	.url = "hostname:",
329 	.is_connect = 1,
330 	.rv = 1,
331 	},
332 
333 	{
334 	.name = "CONNECT with extra bits",
335 	.url = "hostname:443/",
336 	.is_connect = 1,
337 	.rv = 1,
338 	},
339 
340 	{
341 	.name = "space in URL",
342 	.url = "/foo bar/",
343 	.rv = 1, /* s_dead */
344 	},
345 
346 	{
347 	.name = "proxy basic auth with space url encoded",
348 	.url = "http://a%20:b@host.com/",
349 	.is_connect = 0,
350 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
351 			     (1<<UF_USERINFO),
352 		.port = 0,
353 		.field_data = {
354 			{  0,  4 },	/* UF_SCHEMA */
355 			{ 14,  8 },	/* UF_HOST */
356 			{  0,  0 },	/* UF_PORT */
357 			{ 22,  1 },	/* UF_PATH */
358 			{  0,  0 },	/* UF_QUERY */
359 			{  0,  0 },	/* UF_FRAGMENT */
360 			{  7,  6 } } },	/* UF_USERINFO */
361 	.rv = 0
362 	},
363 
364 	{
365 	.name = "carriage return in URL",
366 	.url = "/foo\rbar/",
367 	.rv = 1 /* s_dead */
368 	},
369 
370 	{
371 	.name = "proxy double : in URL",
372 	.url = "http://hostname::443/",
373 	.rv = 1 /* s_dead */
374 	},
375 
376 	{
377 	.name = "proxy basic auth with double :",
378 	.url = "http://a::b@host.com/",
379 	.is_connect = 0,
380 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
381 			     (1<<UF_USERINFO),
382 		.port = 0,
383 		.field_data = {
384 			{  0,  4 },	/* UF_SCHEMA */
385 			{ 12,  8 },	/* UF_HOST */
386 			{  0,  0 },	/* UF_PORT */
387 			{ 20,  1 },	/* UF_PATH */
388 			{  0,  0 },	/* UF_QUERY */
389 			{  0,  0 },	/* UF_FRAGMENT */
390 			{  7,  4 } } },	/* UF_USERINFO */
391 	.rv = 0
392 	},
393 
394 	{
395 	.name = "line feed in URL",
396 	.url = "/foo\nbar/",
397 	.rv = 1 /* s_dead */
398 	},
399 
400 	{
401 	.name = "proxy empty basic auth",
402 	.url = "http://@hostname/fo",
403 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH),
404 		.port = 0,
405 		.field_data = {
406 			{  0,  4 },	/* UF_SCHEMA */
407 			{  8,  8 },	/* UF_HOST */
408 			{  0,  0 },	/* UF_PORT */
409 			{ 16,  3 },	/* UF_PATH */
410 			{  0,  0 },	/* UF_QUERY */
411 			{  0,  0 },	/* UF_FRAGMENT */
412 			{  0,  0 } } },	/* UF_USERINFO */
413 	.rv = 0
414 	},
415 
416 	{
417 	.name = "proxy line feed in hostname",
418 	.url = "http://host\name/fo",
419 	.rv = 1 /* s_dead */
420 	},
421 
422 	{
423 	.name = "proxy % in hostname",
424 	.url = "http://host%name/fo",
425 	.rv = 1 /* s_dead */
426 	},
427 
428 	{
429 	.name = "proxy ; in hostname",
430 	.url = "http://host;ame/fo",
431 	.rv = 1 /* s_dead */
432 	},
433 
434 	{
435 	.name = "proxy basic auth with unreservedchars",
436 	.url = "http://a!;-_!=+$@host.com/",
437 	.is_connect = 0,
438 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH) |
439 			     (1<<UF_USERINFO),
440 		.port = 0,
441 		.field_data = {
442 			{  0,  4 },	/* UF_SCHEMA */
443 			{ 17,  8 },	/* UF_HOST */
444 			{  0,  0 },	/* UF_PORT */
445 			{ 25,  1 },	/* UF_PATH */
446 			{  0,  0 },	/* UF_QUERY */
447 			{  0,  0 },	/* UF_FRAGMENT */
448 			{  7,  9 } } },	/* UF_USERINFO */
449 	.rv = 0
450 	},
451 
452 	{
453 	.name = "proxy only empty basic auth",
454 	.url = "http://@/fo",
455 	.rv = 1 /* s_dead */
456 	},
457 
458 	{
459 	.name = "proxy only basic auth",
460 	.url = "http://toto@/fo",
461 	.rv = 1 /* s_dead */
462 	},
463 
464 	{
465 	.name = "proxy empty hostname",
466 	.url = "http:///fo",
467 	.rv = 1 /* s_dead */
468 	},
469 
470 	{
471 	.name = "proxy = in URL",
472 	.url = "http://host=ame/fo",
473 	.rv = 1 /* s_dead */
474 	},
475 
476 	{
477 	.name = "ipv6 address with Zone ID",
478 	.url = "http://[fe80::a%25eth0]/",
479 	.is_connect = 0,
480 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH),
481 		.port = 0,
482 		.field_data = {
483 			{  0,  4 },	/* UF_SCHEMA */
484 			{  8, 14 },	/* UF_HOST */
485 			{  0,  0 },	/* UF_PORT */
486 			{ 23,  1 },	/* UF_PATH */
487 			{  0,  0 },	/* UF_QUERY */
488 			{  0,  0 },	/* UF_FRAGMENT */
489 			{  0,  0 } } },	/* UF_USERINFO */
490 	.rv = 0
491 	},
492 
493 	{
494 	.name = "ipv6 address with Zone ID, but '%' is not percent-encoded",
495 	.url = "http://[fe80::a%eth0]/",
496 	.is_connect = 0,
497 	.u = {	.field_set = (1<<UF_SCHEMA) | (1<<UF_HOST) | (1<<UF_PATH),
498 		.port = 0,
499 		.field_data = {
500 			{  0,  4 },	/* UF_SCHEMA */
501 			{  8, 12 },	/* UF_HOST */
502 			{  0,  0 },	/* UF_PORT */
503 			{ 21,  1 },	/* UF_PATH */
504 			{  0,  0 },	/* UF_QUERY */
505 			{  0,  0 },	/* UF_FRAGMENT */
506 			{  0,  0 } } },	/* UF_USERINFO */
507 	.rv = 0
508 	},
509 
510 	{
511 	.name = "ipv6 address ending with '%'",
512 	.url = "http://[fe80::a%]/",
513 	.rv = 1 /* s_dead */
514 	},
515 
516 	{
517 	.name = "ipv6 address with Zone ID including bad character",
518 	.url = "http://[fe80::a%$HOME]/",
519 	.rv = 1 /* s_dead */
520 	},
521 
522 	{
523 	.name = "just ipv6 Zone ID",
524 	.url = "http://[%eth0]/",
525 	.rv = 1 /* s_dead */
526 	},
527 
528 #ifdef CONFIG_HTTP_PARSER_STRICT
529 	{
530 	.name = "tab in URL",
531 	.url = "/foo\tbar/",
532 	.rv = 1 /* s_dead */
533 	},
534 
535 	{
536 	.name = "form feed in URL",
537 	.url = "/foo\fbar/",
538 	.rv = 1 /* s_dead */
539 	},
540 
541 #else /* !HTTP_PARSER_STRICT */
542 
543 	{
544 	.name = "tab in URL",
545 	.url = "/foo\tbar/",
546 	.u = {	.field_set = (1 << UF_PATH),
547 		.field_data = {
548 			{  0,  0 },	/* UF_SCHEMA */
549 			{  0,  0 },	/* UF_HOST */
550 			{  0,  0 },	/* UF_PORT */
551 			{  0,  9 },	/* UF_PATH */
552 			{  0,  0 },	/* UF_QUERY */
553 			{  0,  0 },	/* UF_FRAGMENT */
554 			{  0,  0 } } },	/* UF_USERINFO */
555 	.rv = 0
556 	},
557 
558 	{
559 	.name = "form feed in URL",
560 	.url = "/foo\fbar/",
561 	.u = {	.field_set = (1 << UF_PATH),
562 		.field_data = {
563 			{  0,  0 },	/* UF_SCHEMA */
564 			{  0,  0 },	/* UF_HOST */
565 			{  0,  0 },	/* UF_PORT */
566 			{  0,  9 },	/* UF_PATH */
567 			{  0,  0 },	/* UF_QUERY */
568 			{  0,  0 },	/* UF_FRAGMENT */
569 			{  0,  0 } } },	/* UF_USERINFO */
570 	.rv = 0
571 	}
572 #endif
573 };
574 
ZTEST(http_header_fields_fn,test_preserve_data)575 ZTEST(http_header_fields_fn, test_preserve_data)
576 {
577 	struct http_parser parser = { 0 };
578 	char my_data[] = "application-specific data";
579 
580 	parser.data = my_data;
581 	http_parser_init(&parser, HTTP_REQUEST);
582 
583 	/**TESTPOINT: Check results*/
584 	zassert_equal(parser.data, my_data, "test_preserve_data error");
585 }
586 
ZTEST(http_header_fields_fn,test_parse_url)587 ZTEST(http_header_fields_fn, test_parse_url)
588 {
589 	struct http_parser_url u;
590 	const struct url_test *test;
591 	unsigned int elements;
592 	unsigned int i;
593 	int rv;
594 
595 	elements = ARRAY_SIZE(url_tests);
596 	for (i = 0U; i < elements; i++) {
597 		test = &url_tests[i];
598 		(void)memset(&u, 0, sizeof(u));
599 
600 		rv = http_parser_parse_url(test->url,
601 					   strlen(test->url),
602 					   test->is_connect,
603 					   &u);
604 
605 		if (test->rv == 0) {
606 
607 			/**TESTPOINT: Check test_parse_url functions*/
608 			zassert_false(rv, "http_parser_parse_url error");
609 
610 			zassert_false(memcmp(&u, &test->u, sizeof(u)),
611 					"test_parse_url failed");
612 		} else {
613 			/* test->rv != 0 */
614 			zassert_true(rv, "http_parser_parse_url error");
615 		}
616 	}
617 }
618 
ZTEST(http_header_fields_fn,test_method_str)619 ZTEST(http_header_fields_fn, test_method_str)
620 {
621 	/**TESTPOINT: Check test_method_str function*/
622 	zassert_false(strcmp("GET", http_method_str(HTTP_GET)),
623 			"http_method_str error");
624 	zassert_false(strcmp("<unknown>", http_method_str(127)),
625 			"http_method_str error");
626 }
627 
ZTEST(http_header_fields_fn,test_header_nread_value)628 ZTEST(http_header_fields_fn, test_header_nread_value)
629 {
630 	struct http_parser parser = { 0 };
631 	const char *buf;
632 	size_t parsed;
633 
634 	http_parser_init(&parser, HTTP_REQUEST);
635 	buf = "GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n";
636 	parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
637 
638 	zassert_equal(parsed, strlen(buf),
639 			"http_parser error");
640 	zassert_equal(parser.nread, strlen(buf),
641 			"http_parser error");
642 }
643 
test_invalid_header_content(int req,const char * str)644 int test_invalid_header_content(int req, const char *str)
645 {
646 	struct http_parser parser = { 0 };
647 	const char *buf;
648 	size_t parsed;
649 	size_t buflen;
650 
651 	http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
652 	buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
653 	parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
654 
655 	/**TESTPOINTS: Check test_invalid_header_content functions*/
656 	zassert_equal(parsed, strlen(buf),
657 			"http_parser_execute error");
658 
659 	buf = str;
660 	buflen = strlen(buf);
661 	parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
662 	if (parsed != buflen) {
663 		zassert_equal(HTTP_PARSER_ERRNO(&parser),
664 				HPE_INVALID_HEADER_TOKEN,
665 				"http_parser_execute error");
666 
667 		return TC_PASS;
668 	}
669 
670 	return TC_FAIL;
671 }
672 
test_invalid_header_field_content_error(int req)673 int test_invalid_header_field_content_error(int req)
674 {
675 	int rc;
676 
677 	rc = test_invalid_header_content(req, "Foo: F\01ailure");
678 
679 	/**TESTPOINTS: Check test_invalid_header_field_content_error*/
680 	zassert_false(rc, "test_invalid_header_content error");
681 
682 	rc = test_invalid_header_content(req, "Foo: B\02ar");
683 
684 	zassert_false(rc, "test_invalid_header_content error");
685 
686 	return TC_PASS;
687 }
688 
test_invalid_header_field(int req,const char * str)689 int test_invalid_header_field(int req, const char *str)
690 {
691 	struct http_parser parser = { 0 };
692 	const char *buf;
693 	size_t parsed;
694 	size_t buflen;
695 
696 	http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
697 	buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
698 	parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
699 
700 	/**TESTPOINTS: Check http_parser_execute*/
701 	zassert_equal(parsed, strlen(buf),
702 			"http_parser_execute error");
703 	buf = str;
704 	buflen = strlen(buf);
705 	parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
706 	if (parsed != buflen) {
707 		zassert_equal(HTTP_PARSER_ERRNO(&parser),
708 				HPE_INVALID_HEADER_TOKEN,
709 				"http_parser_execute error");
710 
711 		return TC_PASS;
712 	}
713 
714 	return TC_FAIL;
715 }
716 
test_invalid_header_field_token_error(int req)717 int test_invalid_header_field_token_error(int req)
718 {
719 	int rc;
720 
721 	rc = test_invalid_header_field(req, "Fo@: Failure");
722 
723 	/**TESTPOINTS: Check test_invalid_header_field_token_error*/
724 	zassert_false(rc, "test_invalid_header_field error");
725 
726 	rc = test_invalid_header_field(req, "Foo\01\test: Bar");
727 	zassert_false(rc, "test_invalid_header_field error");
728 
729 	return TC_PASS;
730 }
731 
test_double_content_length_error(int req)732 int test_double_content_length_error(int req)
733 {
734 	struct http_parser parser = { 0 };
735 	const char *buf;
736 	size_t parsed;
737 	size_t buflen;
738 
739 	http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
740 	buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
741 	parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
742 
743 	/**TESTPOINTS: Check http_parser_execute*/
744 	zassert_equal(parsed, strlen(buf),
745 			"http_parser_execute error");
746 
747 	buf = "Content-Length: 0\r\nContent-Length: 1\r\n\r\n";
748 	buflen = strlen(buf);
749 	parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
750 	if (parsed != buflen) {
751 		int error = HTTP_PARSER_ERRNO(&parser);
752 
753 		zassert_equal(error, HPE_UNEXPECTED_CONTENT_LENGTH,
754 			"http_parser_execute error");
755 
756 		return TC_PASS;
757 	}
758 
759 	return TC_FAIL;
760 }
761 
test_chunked_content_length_error(int req)762 int test_chunked_content_length_error(int req)
763 {
764 	struct http_parser parser = { 0 };
765 	const char *buf;
766 	size_t parsed;
767 	size_t buflen;
768 
769 	http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
770 
771 	buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
772 	parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
773 
774 	/**TESTPOINTS: Check http_parser_execute*/
775 	zassert_equal(parsed, strlen(buf),
776 			"http_parser_execute error");
777 
778 	buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n";
779 	buflen = strlen(buf);
780 	parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
781 	if (parsed != buflen) {
782 		int error = HTTP_PARSER_ERRNO(&parser);
783 
784 		zassert_equal(error, HPE_UNEXPECTED_CONTENT_LENGTH,
785 			"http_parser_execute error");
786 
787 		return TC_PASS;
788 	}
789 
790 	return TC_FAIL;
791 }
792 
test_header_cr_no_lf_error(int req)793 int test_header_cr_no_lf_error(int req)
794 {
795 	struct http_parser parser = { 0 };
796 	const char *buf;
797 	size_t parsed;
798 	size_t buflen;
799 
800 	http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE);
801 	buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n";
802 	parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf));
803 
804 	/**TESTPOINTS: Check http_parser_execute*/
805 	zassert_equal(parsed, strlen(buf),
806 			"http_parser_execute error");
807 
808 
809 	buf = "Foo: 1\rBar: 1\r\n\r\n";
810 	buflen = strlen(buf);
811 	parsed = http_parser_execute(&parser, &settings_null, buf, buflen);
812 	if (parsed != buflen) {
813 		int error = HTTP_PARSER_ERRNO(&parser);
814 
815 		zassert_equal(error, HPE_LF_EXPECTED,
816 			"http_parser_execute error");
817 
818 		return TC_PASS;
819 	}
820 
821 	return TC_FAIL;
822 }
823 
ZTEST(http_header_fields_fn,test_http_header_fields)824 ZTEST(http_header_fields_fn, test_http_header_fields)
825 {
826 	int rc;
827 
828 	/* header field tests */
829 	rc = test_double_content_length_error(HTTP_REQUEST);
830 
831 	/**TESTPOINT: Check test_double_content_length_error*/
832 	zassert_false(rc, "test_double_content_length_error failed");
833 
834 	rc = test_chunked_content_length_error(HTTP_REQUEST);
835 
836 	/**TESTPOINT: Check test_chunked_content_length_error*/
837 	zassert_false(rc, "test_chunked_content_length_error failed");
838 
839 	rc = test_header_cr_no_lf_error(HTTP_REQUEST);
840 
841 	/**TESTPOINT: Check test_header_cr_no_lf_error*/
842 	zassert_false(rc, "test_header_cr_no_lf_error failed");
843 
844 	rc = test_invalid_header_field_token_error(HTTP_REQUEST);
845 
846 	/**TESTPOINT: Check test_invalid_header_field_token_error*/
847 	zassert_false(rc, "test_invalid_header_field_token_error failed");
848 
849 	rc = test_invalid_header_field_content_error(HTTP_REQUEST);
850 
851 	/**TESTPOINT: Check test_invalid_header_field_content_error*/
852 	zassert_false(rc, "test_invalid_header_field_content_error failed");
853 
854 	rc = test_double_content_length_error(HTTP_RESPONSE);
855 
856 	/**TESTPOINT: Check test_double_content_length_error*/
857 	zassert_false(rc, "test_double_content_length_error failed");
858 
859 	rc = test_chunked_content_length_error(HTTP_RESPONSE);
860 
861 	/**TESTPOINT: Check test_chunked_content_length_error*/
862 	zassert_false(rc, "test_chunked_content_length_error failed");
863 
864 	rc = test_header_cr_no_lf_error(HTTP_RESPONSE);
865 
866 	/**TESTPOINT: Check test_header_cr_no_lf_error*/
867 	zassert_false(rc, "test_header_cr_no_lf_error failed");
868 
869 	rc = test_invalid_header_field_token_error(HTTP_RESPONSE);
870 
871 	/**TESTPOINT: Check test_invalid_header_field_token_error*/
872 	zassert_false(rc, "test_invalid_header_field_token_error failed");
873 
874 	rc = test_invalid_header_field_content_error(HTTP_RESPONSE);
875 
876 	/**TESTPOINT: Check test_invalid_header_field_content_error*/
877 	zassert_false(rc, "test_invalid_header_field_content_error failed");
878 }
879 
880 ZTEST_SUITE(http_header_fields_fn, NULL, NULL, NULL, NULL, NULL);
881