1 /* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "net.h"
5 #include "http-url.h"
6 #include "test-common.h"
7
8 struct valid_http_url_test {
9 const char *url;
10 enum http_url_parse_flags flags;
11 struct http_url url_base;
12
13 struct http_url url_parsed;
14 };
15
16 /* Valid HTTP URL tests */
17 static struct valid_http_url_test valid_url_tests[] = {
18 /* Generic tests */
19 {
20 .url = "http://localhost",
21 .url_parsed = {
22 .host = { .name = "localhost" },
23 },
24 },
25 {
26 .url = "http://www.%65%78%61%6d%70%6c%65.com",
27 .url_parsed = {
28 .host = { .name = "www.example.com" },
29 },
30 },
31 {
32 .url = "http://www.dovecot.org:8080",
33 .url_parsed = {
34 .host = { .name = "www.dovecot.org" },
35 .port = 8080,
36 },
37 },
38 {
39 .url = "http://127.0.0.1",
40 .url_parsed = {
41 .host = {
42 .name = "127.0.0.1",
43 .ip = { .family = AF_INET },
44 },
45 },
46 },
47 {
48 .url = "http://[::1]",
49 .url_parsed = {
50 .host = {
51 .name = "[::1]",
52 .ip = { .family = AF_INET6 },
53 },
54 },
55 },
56 {
57 .url = "http://[::1]:8080",
58 .url_parsed = {
59 .host = {
60 .name = "[::1]",
61 .ip = { .family = AF_INET6 },
62 },
63 .port = 8080,
64 },
65 },
66 {
67 .url = "http://user@api.dovecot.org",
68 .flags = HTTP_URL_ALLOW_USERINFO_PART,
69 .url_parsed = {
70 .host = { .name = "api.dovecot.org" },
71 .user = "user",
72 },
73 },
74 {
75 .url = "http://userid:secret@api.dovecot.org",
76 .flags = HTTP_URL_ALLOW_USERINFO_PART,
77 .url_parsed = {
78 .host = { .name = "api.dovecot.org" },
79 .user = "userid",
80 .password = "secret",
81 },
82 },
83 {
84 .url = "http://su%3auserid:secret@api.dovecot.org",
85 .flags = HTTP_URL_ALLOW_USERINFO_PART,
86 .url_parsed = {
87 .host = { .name = "api.dovecot.org" },
88 .user = "su:userid",
89 .password = "secret",
90 },
91 },
92 {
93 .url = "http://www.example.com/"
94 "?question=What%20are%20you%20doing%3f&answer=Nothing.",
95 .url_parsed = {
96 .path = "/",
97 .host = { .name = "www.example.com" },
98 .enc_query = "question=What%20are%20you%20doing%3f&answer=Nothing.",
99 },
100 },
101 /* Empty path segments */
102 {
103 .url = "http://target//index.php",
104 .url_parsed = {
105 .path = "//index.php",
106 .host = { .name = "target" },
107 },
108 },
109 {
110 .url = "http://target//path//index.php",
111 .url_parsed = {
112 .path = "//path//index.php",
113 .host = { .name = "target" },
114 },
115 },
116 {
117 .url = "http://target//path/",
118 .url_parsed = {
119 .path = "//path/",
120 .host = { .name = "target" },
121 },
122 },
123 {
124 .url = "http://target//path//",
125 .url_parsed = {
126 .path = "//path//",
127 .host = { .name = "target" },
128 },
129 },
130 {
131 .url = "http://target//path//to//./index.php",
132 .url_parsed = {
133 .path = "//path//to//index.php",
134 .host = { .name = "target" },
135 },
136 },
137 {
138 .url = "http://target//path//to//../index.php",
139 .url_parsed = {
140 .path = "//path//to/index.php",
141 .host = { .name = "target" },
142 },
143 },
144 {
145 .url = "/index.php",
146 .url_base = {
147 .host = { .name = "target" },
148 },
149 .url_parsed = {
150 .host = { .name = "target" },
151 .path = "/index.php",
152 },
153 },
154 {
155 .url = "//index.php",
156 .url_base = {
157 .host = { .name = "target" },
158 },
159 .url_parsed = {
160 .host = { .name = "index.php" },
161 },
162 },
163 {
164 .url = "/path/to/index.php",
165 .url_base = {
166 .host = { .name = "target" },
167 },
168 .url_parsed = {
169 .host = { .name = "target" },
170 .path = "/path/to/index.php",
171 },
172 },
173 {
174 .url = "//path//to//index.php",
175 .url_base = {
176 .host = { .name = "target" },
177 },
178 .url_parsed = {
179 .host = { .name = "path" },
180 .path = "//to//index.php",
181 },
182 },
183 /* These next 2 URLs don't follow the recommendations in
184 http://tools.ietf.org/html/rfc1034#section-3.5 and
185 http://tools.ietf.org/html/rfc3696
186 However they satisfy the grammar in
187 http://tools.ietf.org/html/rfc1123#section-2 and
188 http://tools.ietf.org/html/rfc952
189 so we should parse them.
190 */
191 {
192 .url = "http://256.0.0.1/that/reverts/to/DNS",
193 .url_parsed = {
194 .path = "/that/reverts/to/DNS",
195 .host = { .name = "256.0.0.1" },
196 },
197 },
198 {
199 .url = "http://127.0.0.284/this/also/reverts/to/DNS",
200 .url_parsed = {
201 .path = "/this/also/reverts/to/DNS",
202 .host = { .name = "127.0.0.284" },
203 },
204 },
205 {
206 .url = "http://www.example.com/#Status%20of%20development",
207 .flags = HTTP_URL_ALLOW_FRAGMENT_PART,
208 .url_parsed = {
209 .path = "/",
210 .host = { .name = "www.example.com" },
211 .enc_fragment = "Status%20of%20development",
212 },
213 },
214 /* RFC 3986, Section 5.4. Reference Resolution Examples
215 *
216 * Within a representation with a well defined base URI of
217 *
218 * http://a/b/c/d;p?q
219 *
220 * a relative reference is transformed to its target URI as follows.
221 *
222 * 5.4.1. Normal Examples
223 */
224 { // "g" = "http://a/b/c/g"
225 .url = "g",
226 .url_base = {
227 .host = { .name = "a" },
228 .path = "/b/c/d;p",
229 .enc_query = "q",
230 },
231 .url_parsed = {
232 .host = { .name = "a" },
233 .path = "/b/c/g",
234 },
235 },
236 { // "./g" = "http://a/b/c/g"
237 .url = "./g",
238 .url_base = {
239 .host = { .name = "a" },
240 .path = "/b/c/d;p",
241 .enc_query = "q",
242 },
243 .url_parsed = {
244 .host = { .name = "a" },
245 .path = "/b/c/g",
246 },
247 },
248 { // "g/" = "http://a/b/c/g/"
249 .url = "g/",
250 .url_base = {
251 .host = { .name = "a" },
252 .path = "/b/c/d;p",
253 .enc_query = "q",
254 },
255 .url_parsed = {
256 .host = { .name = "a" },
257 .path = "/b/c/g/",
258 },
259 },
260 { // "/g" = "http://a/g"
261 .url = "/g",
262 .url_base = {
263 .host = { .name = "a" },
264 .path = "/b/c/d;p",
265 .enc_query = "q",
266 },
267 .url_parsed = {
268 .host = { .name = "a" },
269 .path = "/g",
270 },
271 },
272 { // "//g" = "http://g"
273 .url = "//g",
274 .url_base = {
275 .host = { .name = "a" },
276 .path = "/b/c/d;p",
277 .enc_query = "q",
278 },
279 .url_parsed = {
280 .host = { .name = "g" },
281 },
282 },
283 { // "?y" = "http://a/b/c/d;p?y"
284 .url = "?y",
285 .url_base = {
286 .host = { .name = "a" },
287 .path = "/b/c/d;p",
288 .enc_query = "q",
289 },
290 .url_parsed = {
291 .host = { .name = "a" },
292 .path = "/b/c/d;p",
293 .enc_query = "y",
294 },
295 },
296 { // "g?y" = "http://a/b/c/g?y"
297 .url = "g?y",
298 .url_base = {
299 .host = { .name = "a" },
300 .path = "/b/c/d;p",
301 .enc_query = "q",
302 },
303 .url_parsed = {
304 .host = { .name = "a" },
305 .path = "/b/c/g",
306 .enc_query = "y",
307 },
308 },
309 { // "#s" = "http://a/b/c/d;p?q#s"
310 .url = "#s",
311 .flags = HTTP_URL_ALLOW_FRAGMENT_PART,
312 .url_base = {
313 .host = { .name = "a" },
314 .path = "/b/c/d;p",
315 .enc_query = "q",
316 },
317 .url_parsed = {
318 .host = { .name = "a" },
319 .path = "/b/c/d;p",
320 .enc_query = "q",
321 .enc_fragment = "s",
322 },
323 },
324 { // "g#s" = "http://a/b/c/g#s"
325 .url = "g#s",
326 .flags = HTTP_URL_ALLOW_FRAGMENT_PART,
327 .url_base = {
328 .host = { .name = "a" },
329 .path = "/b/c/d;p",
330 .enc_query = "q",
331 },
332 .url_parsed = {
333 .host = { .name = "a" },
334 .path = "/b/c/g",
335 .enc_fragment = "s",
336 },
337 },
338 { // "g?y#s" = "http://a/b/c/g?y#s"
339 .url = "g?y#s",
340 .flags = HTTP_URL_ALLOW_FRAGMENT_PART,
341 .url_base = {
342 .host = { .name = "a" },
343 .path = "/b/c/d;p",
344 .enc_query = "q",
345 },
346 .url_parsed = {
347 .host = { .name = "a" },
348 .path = "/b/c/g",
349 .enc_query = "y",
350 .enc_fragment = "s",
351 },
352 },
353 { // ";x" = "http://a/b/c/;x"
354 .url = ";x",
355 .url_base = {
356 .host = { .name = "a" },
357 .path = "/b/c/d;p",
358 .enc_query = "q",
359 },
360 .url_parsed = {
361 .host = { .name = "a" },
362 .path = "/b/c/;x",
363 },
364 },
365 { // "g;x" = "http://a/b/c/g;x"
366 .url = "g;x",
367 .url_base = {
368 .host = { .name = "a" },
369 .path = "/b/c/d;p",
370 .enc_query = "q",
371 },
372 .url_parsed = {
373 .host = { .name = "a" },
374 .path = "/b/c/g;x",
375 },
376
377 },
378 { // "g;x?y#s" = "http://a/b/c/g;x?y#s"
379 .url = "g;x?y#s",
380 .flags = HTTP_URL_ALLOW_FRAGMENT_PART,
381 .url_base = {
382 .host = { .name = "a" },
383 .path = "/b/c/d;p",
384 .enc_query = "q",
385 },
386 .url_parsed = {
387 .host = { .name = "a" },
388 .path = "/b/c/g;x",
389 .enc_query = "y",
390 .enc_fragment = "s",
391 },
392 },
393 { // "" = "http://a/b/c/d;p?q"
394 .url = "",
395 .url_base = {
396 .host = { .name = "a" },
397 .path = "/b/c/d;p",
398 .enc_query = "q",
399 },
400 .url_parsed = {
401 .host = { .name = "a" },
402 .path = "/b/c/d;p",
403 .enc_query = "q",
404 },
405 },
406 { // "." = "http://a/b/c/"
407 .url = ".",
408 .url_base = {
409 .host = { .name = "a" },
410 .path = "/b/c/d;p",
411 .enc_query = "q",
412 },
413 .url_parsed = {
414 .host = { .name = "a" },
415 .path = "/b/c/",
416 },
417 },
418 { // "./" = "http://a/b/c/"
419 .url = "./",
420 .url_base = {
421 .host = { .name = "a" },
422 .path = "/b/c/d;p",
423 .enc_query = "q",
424 },
425 .url_parsed = {
426 .host = { .name = "a" },
427 .path = "/b/c/",
428 },
429 },
430 { // ".." = "http://a/b/"
431 .url = "..",
432 .url_base = {
433 .host = { .name = "a" },
434 .path = "/b/c/d;p",
435 .enc_query = "q",
436 },
437 .url_parsed = {
438 .host = { .name = "a" },
439 .path = "/b/",
440 },
441 },
442 { // "../" = "http://a/b/"
443 .url = "../",
444 .url_base = {
445 .host = { .name = "a" },
446 .path = "/b/c/d;p",
447 .enc_query = "q",
448 },
449 .url_parsed = {
450 .host = { .name = "a" },
451 .path = "/b/",
452 },
453 },
454 { // "../g" = "http://a/b/g"
455 .url = "../g",
456 .url_base = {
457 .host = { .name = "a" },
458 .path = "/b/c/d;p",
459 .enc_query = "q",
460 },
461 .url_parsed = {
462 .host = { .name = "a" },
463 .path = "/b/g",
464 },
465 },
466 { // "../.." = "http://a/"
467 .url = "../..",
468 .url_base = {
469 .host = { .name = "a" },
470 .path = "/b/c/d;p",
471 .enc_query = "q",
472 },
473 .url_parsed = {
474 .host = { .name = "a" },
475 .path = "/",
476 },
477 },
478 { // "../../" = "http://a/"
479 .url = "../../",
480 .url_base = {
481 .host = { .name = "a" },
482 .path = "/b/c/d;p",
483 .enc_query = "q",
484 },
485 .url_parsed = {
486 .host = { .name = "a" },
487 .path = "/",
488 },
489 },
490 { // "../../g" = "http://a/g"
491 .url = "../../g",
492 .url_base = {
493 .host = { .name = "a" },
494 .path = "/b/c/d;p",
495 .enc_query = "q",
496 },
497 .url_parsed = {
498 .host = { .name = "a" },
499 .path = "/g",
500 },
501 },
502 /* 5.4.2. Abnormal Examples
503 */
504 { // "../../../g" = "http://a/g"
505 .url = "../../../g",
506 .url_base = {
507 .host = { .name = "a" },
508 .path = "/b/c/d;p",
509 .enc_query = "q",
510 },
511 .url_parsed = {
512 .host = { .name = "a" },
513 .path = "/g",
514 },
515 },
516 { // "../../../../g" = "http://a/g"
517 .url = "../../../../g",
518 .url_base = {
519 .host = { .name = "a" },
520 .path = "/b/c/d;p",
521 .enc_query = "q",
522 },
523 .url_parsed = {
524 .host = { .name = "a" },
525 .path = "/g",
526 },
527 },
528 { // "/./g" = "http://a/g"
529 .url = "/./g",
530 .url_base = {
531 .host = {.name = "a"},
532 .path = "/b/c/d;p",
533 .enc_query = "q",
534 },
535 .url_parsed = {
536 .host = {.name = "a"},
537 .path = "/g",
538 },
539 },
540 { // "/../g" = "http://a/g"
541 .url = "/../g",
542 .url_base = {
543 .host = { .name = "a" },
544 .path = "/b/c/d;p",
545 .enc_query = "q",
546 },
547 .url_parsed = {
548 .host = { .name = "a" },
549 .path = "/g",
550 },
551 },
552 { // "g." = "http://a/b/c/g."
553 .url = "g.",
554 .url_base = {
555 .host = { .name = "a" },
556 .path = "/b/c/d;p",
557 .enc_query = "q",
558 },
559 .url_parsed = {
560 .host = { .name = "a" },
561 .path = "/b/c/g.",
562 },
563 },
564 { // ".g" = "http://a/b/c/.g"
565 .url = ".g",
566 .url_base = {
567 .host = { .name = "a" },
568 .path = "/b/c/d;p",
569 .enc_query = "q",
570 },
571 .url_parsed = {
572 .host = { .name = "a" },
573 .path = "/b/c/.g",
574 },
575 },
576 { // "g.." = "http://a/b/c/g.."
577 .url = "g..",
578 .url_base = {
579 .host = { .name = "a" },
580 .path = "/b/c/d;p",
581 .enc_query = "q",
582 },
583 .url_parsed = {
584 .host = { .name = "a" },
585 .path = "/b/c/g..",
586 },
587 },
588 { // "..g" = "http://a/b/c/..g"
589 .url = "..g",
590 .url_base = {
591 .host = { .name = "a" },
592 .path = "/b/c/d;p",
593 .enc_query = "q",
594 },
595 .url_parsed = {
596 .host = { .name = "a" },
597 .path = "/b/c/..g",
598 },
599 },
600 { // "./../g" = "http://a/b/g"
601 .url = "./../g",
602 .url_base = {
603 .host = {.name = "a"},
604 .path = "/b/c/d;p",
605 .enc_query = "q",
606 },
607 .url_parsed = {
608 .host = {.name = "a"},
609 .path = "/b/g",
610 },
611 },
612 { // "./g/." = "http://a/b/c/g/"
613 .url = "./g/.",
614 .url_base = {
615 .host = { .name = "a" },
616 .path = "/b/c/d;p",
617 .enc_query = "q",
618 },
619 .url_parsed = {
620 .host = { .name = "a" },
621 .path = "/b/c/g/",
622 },
623 },
624 { // "g/./h" = "http://a/b/c/g/h"
625 .url = "g/./h",
626 .url_base = {
627 .host = { .name = "a" },
628 .path = "/b/c/d;p",
629 .enc_query = "q",
630 },
631 .url_parsed = {
632 .host = { .name = "a" },
633 .path = "/b/c/g/h",
634 },
635 },
636 { // "g/../h" = "http://a/b/c/h"
637 .url = "g/../h",
638 .url_base = {
639 .host = { .name = "a" },
640 .path = "/b/c/d;p",
641 .enc_query = "q",
642 },
643 .url_parsed = {
644 .host = { .name = "a" },
645 .path = "/b/c/h",
646 },
647 },
648 { // "g;x=1/./y" = "http://a/b/c/g;x=1/y"
649 .url = "g;x=1/./y",
650 .url_base = {
651 .host = { .name = "a" },
652 .path = "/b/c/d;p",
653 .enc_query = "q",
654 },
655 .url_parsed = {
656 .host = { .name = "a" },
657 .path = "/b/c/g;x=1/y",
658 },
659 },
660 { // "g;x=1/../y" = "http://a/b/c/y"
661 .url = "g;x=1/../y",
662 .url_base = {
663 .host = { .name = "a" },
664 .path = "/b/c/d;p",
665 .enc_query = "q",
666 },
667 .url_parsed = {
668 .host = { .name = "a" },
669 .path = "/b/c/y",
670 },
671 },
672 { // "g?y/./x" = "http://a/b/c/g?y/./x"
673 .url = "g?y/./x",
674 .url_base = {
675 .host = { .name = "a" },
676 .path = "/b/c/d;p",
677 .enc_query = "q",
678 },
679 .url_parsed = {
680 .host = { .name = "a" },
681 .path = "/b/c/g",
682 .enc_query = "y/./x",
683 },
684 },
685 { // "g?y/../x" = "http://a/b/c/g?y/../x"
686 .url = "g?y/../x",
687 .url_base = {
688 .host = { .name = "a" },
689 .path = "/b/c/d;p",
690 .enc_query = "q",
691 },
692 .url_parsed = {
693 .host = { .name = "a" },
694 .path = "/b/c/g",
695 .enc_query = "y/../x",
696 },
697 },
698 { // "g#s/./x" = "http://a/b/c/g#s/./x"
699 .url = "g#s/./x",
700 .flags = HTTP_URL_ALLOW_FRAGMENT_PART,
701 .url_base = {
702 .host = { .name = "a" },
703 .path = "/b/c/d;p",
704 .enc_query = "q",
705 },
706 .url_parsed =
707 {
708 .host = { .name = "a" },
709 .path = "/b/c/g",
710 .enc_fragment = "s/./x",
711 },
712 },
713 { // "g#s/../x" = "http://a/b/c/g#s/../x"
714 .url = "g#s/../x",
715 .flags = HTTP_URL_ALLOW_FRAGMENT_PART,
716 .url_base = {
717 .host = { .name = "a" },
718 .path = "/b/c/d;p",
719 .enc_query = "q",
720 },
721 .url_parsed =
722 {
723 .host = { .name = "a" },
724 .path = "/b/c/g",
725 .enc_fragment = "s/../x",
726 },
727 }
728 };
729
730 static unsigned int valid_url_test_count = N_ELEMENTS(valid_url_tests);
731
732 static void
test_http_url_equal(struct http_url * urlt,struct http_url * urlp)733 test_http_url_equal(struct http_url *urlt, struct http_url *urlp)
734 {
735 if (urlp->host.name == NULL || urlt->host.name == NULL) {
736 test_assert(urlp->host.name == urlt->host.name);
737 } else {
738 test_assert(strcmp(urlp->host.name, urlt->host.name) == 0);
739 }
740 test_assert(urlp->port == urlt->port);
741 test_assert(urlp->host.ip.family == urlt->host.ip.family);
742 if (urlp->user == NULL || urlt->user == NULL) {
743 test_assert(urlp->user == urlt->user);
744 } else {
745 test_assert(strcmp(urlp->user, urlt->user) == 0);
746 }
747 if (urlp->password == NULL || urlt->password == NULL) {
748 test_assert(urlp->password == urlt->password);
749 } else {
750 test_assert(strcmp(urlp->password, urlt->password) == 0);
751 }
752 if (urlp->path == NULL || urlt->path == NULL) {
753 test_assert(urlp->path == urlt->path);
754 } else {
755 test_assert(strcmp(urlp->path, urlt->path) == 0);
756 }
757 if (urlp->enc_query == NULL || urlt->enc_query == NULL) {
758 test_assert(urlp->enc_query == urlt->enc_query);
759 } else {
760 test_assert(strcmp(urlp->enc_query, urlt->enc_query) == 0);
761 }
762 if (urlp->enc_fragment == NULL || urlt->enc_fragment == NULL) {
763 test_assert(urlp->enc_fragment == urlt->enc_fragment);
764 } else {
765 test_assert(strcmp(urlp->enc_fragment,
766 urlt->enc_fragment) == 0);
767 }
768 }
769
test_http_url_valid(void)770 static void test_http_url_valid(void)
771 {
772 unsigned int i;
773
774 for (i = 0; i < valid_url_test_count; i++) T_BEGIN {
775 const char *url = valid_url_tests[i].url;
776 enum http_url_parse_flags flags = valid_url_tests[i].flags;
777 struct http_url *urlt = &valid_url_tests[i].url_parsed;
778 struct http_url *urlb = &valid_url_tests[i].url_base;
779 struct http_url *urlp;
780 const char *error = NULL;
781
782 test_begin(t_strdup_printf("http url valid [%d]", i));
783
784 if (urlb->host.name == NULL) urlb = NULL;
785 if (http_url_parse(url, urlb, flags, pool_datastack_create(),
786 &urlp, &error) < 0)
787 urlp = NULL;
788
789 test_out_reason(t_strdup_printf("http_url_parse(%s)",
790 valid_url_tests[i].url), urlp != NULL, error);
791 if (urlp != NULL)
792 test_http_url_equal(urlt, urlp);
793
794 test_end();
795 } T_END;
796 }
797
798 struct invalid_http_url_test {
799 const char *url;
800 enum http_url_parse_flags flags;
801 struct http_url url_base;
802 };
803
804 static struct invalid_http_url_test invalid_url_tests[] = {
805 {
806 .url = "imap://example.com/INBOX"
807 },
808 {
809 .url = "http:/www.example.com"
810 },
811 {
812 .url = ""
813 },
814 {
815 .url = "/index.html"
816 },
817 {
818 .url = "http://www.example.com/index.html\""
819 },
820 {
821 .url = "http:///dovecot.org"
822 },
823 {
824 .url = "http://[]/index.html"
825 },
826 {
827 .url = "http://[v08.234:232:234:234:2221]/index.html"
828 },
829 {
830 .url = "http://[1::34a:34:234::6]/index.html"
831 },
832 {
833 .url = "http://example%a.com/index.html"
834 },
835 {
836 .url = "http://example.com%/index.html"
837 },
838 {
839 .url = "http://example%00.com/index.html"
840 },
841 {
842 .url = "http://example.com:65536/index.html"
843 },
844 {
845 .url = "http://example.com:72817/index.html"
846 },
847 {
848 .url = "http://example.com/settings/%00/"
849 },
850 {
851 .url = "http://example.com/settings/%0r/"
852 },
853 {
854 .url = "http://example.com/settings/misc/%/"
855 },
856 {
857 .url = "http://example.com/?%00"
858 },
859 {
860 .url = "http://www.example.com/network.html#IMAP_Server"
861 },
862 {
863 .url = "http://example.com/#%00",
864 .flags = HTTP_URL_ALLOW_FRAGMENT_PART
865 }
866 };
867
868 static unsigned int invalid_url_test_count = N_ELEMENTS(invalid_url_tests);
869
test_http_url_invalid(void)870 static void test_http_url_invalid(void)
871 {
872 unsigned int i;
873
874 for (i = 0; i < invalid_url_test_count; i++) T_BEGIN {
875 const char *url = invalid_url_tests[i].url;
876 enum http_url_parse_flags flags = invalid_url_tests[i].flags;
877 struct http_url *urlb = &invalid_url_tests[i].url_base;
878 struct http_url *urlp;
879 const char *error = NULL;
880
881 if (urlb->host.name == NULL)
882 urlb = NULL;
883
884 test_begin(t_strdup_printf("http url invalid [%d]", i));
885
886 if (http_url_parse(url, urlb, flags,
887 pool_datastack_create(), &urlp, &error) < 0)
888 urlp = NULL;
889 test_out_reason(t_strdup_printf("parse %s", url),
890 urlp == NULL, error);
891
892 test_end();
893 } T_END;
894
895 }
896
897 static const char *parse_create_url_tests[] = {
898 "http://www.example.com/",
899 "http://10.0.0.1/",
900 "http://[::1]/",
901 "http://www.example.com:993/",
902 "http://www.example.com/index.html",
903 "http://www.example.com/settings/index.html",
904 "http://www.example.com/%23shared/news",
905 "http://www.example.com/query.php?name=Hendrik%20Visser",
906 "http://www.example.com/network.html#IMAP%20Server",
907 };
908
909 static unsigned int
910 parse_create_url_test_count = N_ELEMENTS(parse_create_url_tests);
911
test_http_url_parse_create(void)912 static void test_http_url_parse_create(void)
913 {
914 unsigned int i;
915
916 for (i = 0; i < parse_create_url_test_count; i++) T_BEGIN {
917 const char *url = parse_create_url_tests[i];
918 struct http_url *urlp;
919 const char *error = NULL;
920
921 test_begin(t_strdup_printf("http url parse/create [%d]", i));
922
923 if (http_url_parse
924 (url, NULL, HTTP_URL_ALLOW_FRAGMENT_PART,
925 pool_datastack_create(), &urlp, &error) < 0)
926 urlp = NULL;
927 test_out_reason(t_strdup_printf("parse %s", url),
928 urlp != NULL, error);
929 if (urlp != NULL) {
930 const char *urlnew = http_url_create(urlp);
931 test_out(t_strdup_printf("create %s", urlnew),
932 strcmp(url, urlnew) == 0);
933 }
934
935 test_end();
936 } T_END;
937
938 }
939
main(void)940 int main(void)
941 {
942 static void (*const test_functions[])(void) = {
943 test_http_url_valid,
944 test_http_url_invalid,
945 test_http_url_parse_create,
946 NULL
947 };
948 return test_run(test_functions);
949 }
950
951