1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54#include "qemu/osdep.h"
55#include "qemu/cutils.h"
56
57#include "qemu/uri.h"
58
59static void uri_clean(URI *uri);
60
61
62
63
64
65#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
66
67
68
69
70
71
72
73#define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
74
75
76
77
78
79
80#define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
81
82#ifdef IS_DIGIT
83#undef IS_DIGIT
84#endif
85
86
87
88#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
89
90
91
92
93
94#define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
95
96
97
98
99
100#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') || \
101 ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') || \
102 ((x) == '(') || ((x) == ')'))
103
104
105
106
107
108#define IS_UNWISE(p) \
109 (((*(p) == '{')) || ((*(p) == '}')) || ((*(p) == '|')) || \
110 ((*(p) == '\\')) || ((*(p) == '^')) || ((*(p) == '[')) || \
111 ((*(p) == ']')) || ((*(p) == '`')))
112
113
114
115
116
117#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') || \
118 ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') || \
119 ((x) == '+') || ((x) == '$') || ((x) == ',') || ((x) == '[') || \
120 ((x) == ']'))
121
122
123
124
125
126#define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
127
128
129
130
131
132#define NEXT(p) ((*p == '%') ? p += 3 : p++)
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150#define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
151#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) || \
152 ((*(p) >= 'A') && (*(p) <= 'Z')))
153#define ISA_HEXDIG(p) \
154 (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) || \
155 ((*(p) >= 'A') && (*(p) <= 'F')))
156
157
158
159
160
161#define ISA_SUB_DELIM(p) \
162 (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) || \
163 ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) || \
164 ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) || \
165 ((*(p) == '=')) || ((*(p) == '\'')))
166
167
168
169
170#define ISA_GEN_DELIM(p) \
171 (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) || \
172 ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) || \
173 ((*(p) == '@')))
174
175
176
177
178#define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p)))
179
180
181
182
183#define ISA_UNRESERVED(p) \
184 ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) || \
185 ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
186
187
188
189
190#define ISA_PCT_ENCODED(p) \
191 ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
192
193
194
195
196#define ISA_PCHAR(p) \
197 (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \
198 ((*(p) == ':')) || ((*(p) == '@')))
199
200
201
202
203
204
205
206
207
208
209
210
211static int rfc3986_parse_scheme(URI *uri, const char **str)
212{
213 const char *cur;
214
215 if (str == NULL) {
216 return -1;
217 }
218
219 cur = *str;
220 if (!ISA_ALPHA(cur)) {
221 return 2;
222 }
223 cur++;
224 while (ISA_ALPHA(cur) || ISA_DIGIT(cur) || (*cur == '+') || (*cur == '-') ||
225 (*cur == '.')) {
226 cur++;
227 }
228 if (uri != NULL) {
229 g_free(uri->scheme);
230 uri->scheme = g_strndup(*str, cur - *str);
231 }
232 *str = cur;
233 return 0;
234}
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251static int rfc3986_parse_fragment(URI *uri, const char **str)
252{
253 const char *cur;
254
255 if (str == NULL) {
256 return -1;
257 }
258
259 cur = *str;
260
261 while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
262 (*cur == '[') || (*cur == ']') ||
263 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) {
264 NEXT(cur);
265 }
266 if (uri != NULL) {
267 g_free(uri->fragment);
268 if (uri->cleanup & 2) {
269 uri->fragment = g_strndup(*str, cur - *str);
270 } else {
271 uri->fragment = uri_string_unescape(*str, cur - *str, NULL);
272 }
273 }
274 *str = cur;
275 return 0;
276}
277
278
279
280
281
282
283
284
285
286
287
288
289static int rfc3986_parse_query(URI *uri, const char **str)
290{
291 const char *cur;
292
293 if (str == NULL) {
294 return -1;
295 }
296
297 cur = *str;
298
299 while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
300 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur)))) {
301 NEXT(cur);
302 }
303 if (uri != NULL) {
304 g_free(uri->query);
305 uri->query = g_strndup(*str, cur - *str);
306 }
307 *str = cur;
308 return 0;
309}
310
311
312
313
314
315
316
317
318
319
320
321
322
323static int rfc3986_parse_port(URI *uri, const char **str)
324{
325 const char *cur = *str;
326 int port = 0;
327
328 if (ISA_DIGIT(cur)) {
329 while (ISA_DIGIT(cur)) {
330 port = port * 10 + (*cur - '0');
331 if (port > 65535) {
332 return 1;
333 }
334 cur++;
335 }
336 if (uri) {
337 uri->port = port;
338 }
339 *str = cur;
340 return 0;
341 }
342 return 1;
343}
344
345
346
347
348
349
350
351
352
353
354
355
356
357static int rfc3986_parse_user_info(URI *uri, const char **str)
358{
359 const char *cur;
360
361 cur = *str;
362 while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur) ||
363 (*cur == ':')) {
364 NEXT(cur);
365 }
366 if (*cur == '@') {
367 if (uri != NULL) {
368 g_free(uri->user);
369 if (uri->cleanup & 2) {
370 uri->user = g_strndup(*str, cur - *str);
371 } else {
372 uri->user = uri_string_unescape(*str, cur - *str, NULL);
373 }
374 }
375 *str = cur;
376 return 0;
377 }
378 return 1;
379}
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395static int rfc3986_parse_dec_octet(const char **str)
396{
397 const char *cur = *str;
398
399 if (!(ISA_DIGIT(cur))) {
400 return 1;
401 }
402 if (!ISA_DIGIT(cur + 1)) {
403 cur++;
404 } else if ((*cur != '0') && (ISA_DIGIT(cur + 1)) && (!ISA_DIGIT(cur + 2))) {
405 cur += 2;
406 } else if ((*cur == '1') && (ISA_DIGIT(cur + 1)) && (ISA_DIGIT(cur + 2))) {
407 cur += 3;
408 } else if ((*cur == '2') && (*(cur + 1) >= '0') && (*(cur + 1) <= '4') &&
409 (ISA_DIGIT(cur + 2))) {
410 cur += 3;
411 } else if ((*cur == '2') && (*(cur + 1) == '5') && (*(cur + 2) >= '0') &&
412 (*(cur + 1) <= '5')) {
413 cur += 3;
414 } else {
415 return 1;
416 }
417 *str = cur;
418 return 0;
419}
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435static int rfc3986_parse_host(URI *uri, const char **str)
436{
437 const char *cur = *str;
438 const char *host;
439
440 host = cur;
441
442
443
444 if (*cur == '[') {
445 cur++;
446 while ((*cur != ']') && (*cur != 0)) {
447 cur++;
448 }
449 if (*cur != ']') {
450 return 1;
451 }
452 cur++;
453 goto found;
454 }
455
456
457
458 if (ISA_DIGIT(cur)) {
459 if (rfc3986_parse_dec_octet(&cur) != 0) {
460 goto not_ipv4;
461 }
462 if (*cur != '.') {
463 goto not_ipv4;
464 }
465 cur++;
466 if (rfc3986_parse_dec_octet(&cur) != 0) {
467 goto not_ipv4;
468 }
469 if (*cur != '.') {
470 goto not_ipv4;
471 }
472 if (rfc3986_parse_dec_octet(&cur) != 0) {
473 goto not_ipv4;
474 }
475 if (*cur != '.') {
476 goto not_ipv4;
477 }
478 if (rfc3986_parse_dec_octet(&cur) != 0) {
479 goto not_ipv4;
480 }
481 goto found;
482 not_ipv4:
483 cur = *str;
484 }
485
486
487
488 while (ISA_UNRESERVED(cur) || ISA_PCT_ENCODED(cur) || ISA_SUB_DELIM(cur)) {
489 NEXT(cur);
490 }
491found:
492 if (uri != NULL) {
493 g_free(uri->authority);
494 uri->authority = NULL;
495 g_free(uri->server);
496 if (cur != host) {
497 if (uri->cleanup & 2) {
498 uri->server = g_strndup(host, cur - host);
499 } else {
500 uri->server = uri_string_unescape(host, cur - host, NULL);
501 }
502 } else {
503 uri->server = NULL;
504 }
505 }
506 *str = cur;
507 return 0;
508}
509
510
511
512
513
514
515
516
517
518
519
520
521
522static int rfc3986_parse_authority(URI *uri, const char **str)
523{
524 const char *cur;
525 int ret;
526
527 cur = *str;
528
529
530
531 ret = rfc3986_parse_user_info(uri, &cur);
532 if ((ret != 0) || (*cur != '@')) {
533 cur = *str;
534 } else {
535 cur++;
536 }
537 ret = rfc3986_parse_host(uri, &cur);
538 if (ret != 0) {
539 return ret;
540 }
541 if (*cur == ':') {
542 cur++;
543 ret = rfc3986_parse_port(uri, &cur);
544 if (ret != 0) {
545 return ret;
546 }
547 }
548 *str = cur;
549 return 0;
550}
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568static int rfc3986_parse_segment(const char **str, char forbid, int empty)
569{
570 const char *cur;
571
572 cur = *str;
573 if (!ISA_PCHAR(cur)) {
574 if (empty) {
575 return 0;
576 }
577 return 1;
578 }
579 while (ISA_PCHAR(cur) && (*cur != forbid)) {
580 NEXT(cur);
581 }
582 *str = cur;
583 return 0;
584}
585
586
587
588
589
590
591
592
593
594
595
596
597
598static int rfc3986_parse_path_ab_empty(URI *uri, const char **str)
599{
600 const char *cur;
601 int ret;
602
603 cur = *str;
604
605 while (*cur == '/') {
606 cur++;
607 ret = rfc3986_parse_segment(&cur, 0, 1);
608 if (ret != 0) {
609 return ret;
610 }
611 }
612 if (uri != NULL) {
613 g_free(uri->path);
614 if (*str != cur) {
615 if (uri->cleanup & 2) {
616 uri->path = g_strndup(*str, cur - *str);
617 } else {
618 uri->path = uri_string_unescape(*str, cur - *str, NULL);
619 }
620 } else {
621 uri->path = NULL;
622 }
623 }
624 *str = cur;
625 return 0;
626}
627
628
629
630
631
632
633
634
635
636
637
638
639
640static int rfc3986_parse_path_absolute(URI *uri, const char **str)
641{
642 const char *cur;
643 int ret;
644
645 cur = *str;
646
647 if (*cur != '/') {
648 return 1;
649 }
650 cur++;
651 ret = rfc3986_parse_segment(&cur, 0, 0);
652 if (ret == 0) {
653 while (*cur == '/') {
654 cur++;
655 ret = rfc3986_parse_segment(&cur, 0, 1);
656 if (ret != 0) {
657 return ret;
658 }
659 }
660 }
661 if (uri != NULL) {
662 g_free(uri->path);
663 if (cur != *str) {
664 if (uri->cleanup & 2) {
665 uri->path = g_strndup(*str, cur - *str);
666 } else {
667 uri->path = uri_string_unescape(*str, cur - *str, NULL);
668 }
669 } else {
670 uri->path = NULL;
671 }
672 }
673 *str = cur;
674 return 0;
675}
676
677
678
679
680
681
682
683
684
685
686
687
688
689static int rfc3986_parse_path_rootless(URI *uri, const char **str)
690{
691 const char *cur;
692 int ret;
693
694 cur = *str;
695
696 ret = rfc3986_parse_segment(&cur, 0, 0);
697 if (ret != 0) {
698 return ret;
699 }
700 while (*cur == '/') {
701 cur++;
702 ret = rfc3986_parse_segment(&cur, 0, 1);
703 if (ret != 0) {
704 return ret;
705 }
706 }
707 if (uri != NULL) {
708 g_free(uri->path);
709 if (cur != *str) {
710 if (uri->cleanup & 2) {
711 uri->path = g_strndup(*str, cur - *str);
712 } else {
713 uri->path = uri_string_unescape(*str, cur - *str, NULL);
714 }
715 } else {
716 uri->path = NULL;
717 }
718 }
719 *str = cur;
720 return 0;
721}
722
723
724
725
726
727
728
729
730
731
732
733
734
735static int rfc3986_parse_path_no_scheme(URI *uri, const char **str)
736{
737 const char *cur;
738 int ret;
739
740 cur = *str;
741
742 ret = rfc3986_parse_segment(&cur, ':', 0);
743 if (ret != 0) {
744 return ret;
745 }
746 while (*cur == '/') {
747 cur++;
748 ret = rfc3986_parse_segment(&cur, 0, 1);
749 if (ret != 0) {
750 return ret;
751 }
752 }
753 if (uri != NULL) {
754 g_free(uri->path);
755 if (cur != *str) {
756 if (uri->cleanup & 2) {
757 uri->path = g_strndup(*str, cur - *str);
758 } else {
759 uri->path = uri_string_unescape(*str, cur - *str, NULL);
760 }
761 } else {
762 uri->path = NULL;
763 }
764 }
765 *str = cur;
766 return 0;
767}
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784static int rfc3986_parse_hier_part(URI *uri, const char **str)
785{
786 const char *cur;
787 int ret;
788
789 cur = *str;
790
791 if ((*cur == '/') && (*(cur + 1) == '/')) {
792 cur += 2;
793 ret = rfc3986_parse_authority(uri, &cur);
794 if (ret != 0) {
795 return ret;
796 }
797 ret = rfc3986_parse_path_ab_empty(uri, &cur);
798 if (ret != 0) {
799 return ret;
800 }
801 *str = cur;
802 return 0;
803 } else if (*cur == '/') {
804 ret = rfc3986_parse_path_absolute(uri, &cur);
805 if (ret != 0) {
806 return ret;
807 }
808 } else if (ISA_PCHAR(cur)) {
809 ret = rfc3986_parse_path_rootless(uri, &cur);
810 if (ret != 0) {
811 return ret;
812 }
813 } else {
814
815 if (uri != NULL) {
816 g_free(uri->path);
817 uri->path = NULL;
818 }
819 }
820 *str = cur;
821 return 0;
822}
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840static int rfc3986_parse_relative_ref(URI *uri, const char *str)
841{
842 int ret;
843
844 if ((*str == '/') && (*(str + 1) == '/')) {
845 str += 2;
846 ret = rfc3986_parse_authority(uri, &str);
847 if (ret != 0) {
848 return ret;
849 }
850 ret = rfc3986_parse_path_ab_empty(uri, &str);
851 if (ret != 0) {
852 return ret;
853 }
854 } else if (*str == '/') {
855 ret = rfc3986_parse_path_absolute(uri, &str);
856 if (ret != 0) {
857 return ret;
858 }
859 } else if (ISA_PCHAR(str)) {
860 ret = rfc3986_parse_path_no_scheme(uri, &str);
861 if (ret != 0) {
862 return ret;
863 }
864 } else {
865
866 if (uri != NULL) {
867 g_free(uri->path);
868 uri->path = NULL;
869 }
870 }
871
872 if (*str == '?') {
873 str++;
874 ret = rfc3986_parse_query(uri, &str);
875 if (ret != 0) {
876 return ret;
877 }
878 }
879 if (*str == '#') {
880 str++;
881 ret = rfc3986_parse_fragment(uri, &str);
882 if (ret != 0) {
883 return ret;
884 }
885 }
886 if (*str != 0) {
887 uri_clean(uri);
888 return 1;
889 }
890 return 0;
891}
892
893
894
895
896
897
898
899
900
901
902
903
904
905static int rfc3986_parse(URI *uri, const char *str)
906{
907 int ret;
908
909 ret = rfc3986_parse_scheme(uri, &str);
910 if (ret != 0) {
911 return ret;
912 }
913 if (*str != ':') {
914 return 1;
915 }
916 str++;
917 ret = rfc3986_parse_hier_part(uri, &str);
918 if (ret != 0) {
919 return ret;
920 }
921 if (*str == '?') {
922 str++;
923 ret = rfc3986_parse_query(uri, &str);
924 if (ret != 0) {
925 return ret;
926 }
927 }
928 if (*str == '#') {
929 str++;
930 ret = rfc3986_parse_fragment(uri, &str);
931 if (ret != 0) {
932 return ret;
933 }
934 }
935 if (*str != 0) {
936 uri_clean(uri);
937 return 1;
938 }
939 return 0;
940}
941
942
943
944
945
946
947
948
949
950
951
952
953
954static int rfc3986_parse_uri_reference(URI *uri, const char *str)
955{
956 int ret;
957
958 if (str == NULL) {
959 return -1;
960 }
961 uri_clean(uri);
962
963
964
965
966
967 ret = rfc3986_parse(uri, str);
968 if (ret != 0) {
969 uri_clean(uri);
970 ret = rfc3986_parse_relative_ref(uri, str);
971 if (ret != 0) {
972 uri_clean(uri);
973 return ret;
974 }
975 }
976 return 0;
977}
978
979
980
981
982
983
984
985
986
987
988
989URI *uri_parse(const char *str)
990{
991 URI *uri;
992 int ret;
993
994 if (str == NULL) {
995 return NULL;
996 }
997 uri = uri_new();
998 ret = rfc3986_parse_uri_reference(uri, str);
999 if (ret) {
1000 uri_free(uri);
1001 return NULL;
1002 }
1003 return uri;
1004}
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018int uri_parse_into(URI *uri, const char *str)
1019{
1020 return rfc3986_parse_uri_reference(uri, str);
1021}
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034URI *uri_parse_raw(const char *str, int raw)
1035{
1036 URI *uri;
1037 int ret;
1038
1039 if (str == NULL) {
1040 return NULL;
1041 }
1042 uri = uri_new();
1043 if (raw) {
1044 uri->cleanup |= 2;
1045 }
1046 ret = uri_parse_into(uri, str);
1047 if (ret) {
1048 uri_free(uri);
1049 return NULL;
1050 }
1051 return uri;
1052}
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067URI *uri_new(void)
1068{
1069 return g_new0(URI, 1);
1070}
1071
1072
1073
1074
1075
1076
1077
1078static char *realloc2n(char *ret, int *max)
1079{
1080 char *temp;
1081 int tmp;
1082
1083 tmp = *max * 2;
1084 temp = g_realloc(ret, (tmp + 1));
1085 *max = tmp;
1086 return temp;
1087}
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097char *uri_to_string(URI *uri)
1098{
1099 char *ret = NULL;
1100 char *temp;
1101 const char *p;
1102 int len;
1103 int max;
1104
1105 if (uri == NULL) {
1106 return NULL;
1107 }
1108
1109 max = 80;
1110 ret = g_malloc(max + 1);
1111 len = 0;
1112
1113 if (uri->scheme != NULL) {
1114 p = uri->scheme;
1115 while (*p != 0) {
1116 if (len >= max) {
1117 temp = realloc2n(ret, &max);
1118 ret = temp;
1119 }
1120 ret[len++] = *p++;
1121 }
1122 if (len >= max) {
1123 temp = realloc2n(ret, &max);
1124 ret = temp;
1125 }
1126 ret[len++] = ':';
1127 }
1128 if (uri->opaque != NULL) {
1129 p = uri->opaque;
1130 while (*p != 0) {
1131 if (len + 3 >= max) {
1132 temp = realloc2n(ret, &max);
1133 ret = temp;
1134 }
1135 if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p))) {
1136 ret[len++] = *p++;
1137 } else {
1138 int val = *(unsigned char *)p++;
1139 int hi = val / 0x10, lo = val % 0x10;
1140 ret[len++] = '%';
1141 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1142 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1143 }
1144 }
1145 } else {
1146 if (uri->server != NULL) {
1147 if (len + 3 >= max) {
1148 temp = realloc2n(ret, &max);
1149 ret = temp;
1150 }
1151 ret[len++] = '/';
1152 ret[len++] = '/';
1153 if (uri->user != NULL) {
1154 p = uri->user;
1155 while (*p != 0) {
1156 if (len + 3 >= max) {
1157 temp = realloc2n(ret, &max);
1158 ret = temp;
1159 }
1160 if ((IS_UNRESERVED(*(p))) || ((*(p) == ';')) ||
1161 ((*(p) == ':')) || ((*(p) == '&')) || ((*(p) == '=')) ||
1162 ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ','))) {
1163 ret[len++] = *p++;
1164 } else {
1165 int val = *(unsigned char *)p++;
1166 int hi = val / 0x10, lo = val % 0x10;
1167 ret[len++] = '%';
1168 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1169 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1170 }
1171 }
1172 if (len + 3 >= max) {
1173 temp = realloc2n(ret, &max);
1174 ret = temp;
1175 }
1176 ret[len++] = '@';
1177 }
1178 p = uri->server;
1179 while (*p != 0) {
1180 if (len >= max) {
1181 temp = realloc2n(ret, &max);
1182 ret = temp;
1183 }
1184 ret[len++] = *p++;
1185 }
1186 if (uri->port > 0) {
1187 if (len + 10 >= max) {
1188 temp = realloc2n(ret, &max);
1189 ret = temp;
1190 }
1191 len += snprintf(&ret[len], max - len, ":%d", uri->port);
1192 }
1193 } else if (uri->authority != NULL) {
1194 if (len + 3 >= max) {
1195 temp = realloc2n(ret, &max);
1196 ret = temp;
1197 }
1198 ret[len++] = '/';
1199 ret[len++] = '/';
1200 p = uri->authority;
1201 while (*p != 0) {
1202 if (len + 3 >= max) {
1203 temp = realloc2n(ret, &max);
1204 ret = temp;
1205 }
1206 if ((IS_UNRESERVED(*(p))) || ((*(p) == '$')) ||
1207 ((*(p) == ',')) || ((*(p) == ';')) || ((*(p) == ':')) ||
1208 ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||
1209 ((*(p) == '+'))) {
1210 ret[len++] = *p++;
1211 } else {
1212 int val = *(unsigned char *)p++;
1213 int hi = val / 0x10, lo = val % 0x10;
1214 ret[len++] = '%';
1215 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1216 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1217 }
1218 }
1219 } else if (uri->scheme != NULL) {
1220 if (len + 3 >= max) {
1221 temp = realloc2n(ret, &max);
1222 ret = temp;
1223 }
1224 ret[len++] = '/';
1225 ret[len++] = '/';
1226 }
1227 if (uri->path != NULL) {
1228 p = uri->path;
1229
1230
1231
1232
1233 if ((uri->scheme != NULL) && (p[0] == '/') &&
1234 (((p[1] >= 'a') && (p[1] <= 'z')) ||
1235 ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
1236 (p[2] == ':') && (!strcmp(uri->scheme, "file"))) {
1237 if (len + 3 >= max) {
1238 temp = realloc2n(ret, &max);
1239 ret = temp;
1240 }
1241 ret[len++] = *p++;
1242 ret[len++] = *p++;
1243 ret[len++] = *p++;
1244 }
1245 while (*p != 0) {
1246 if (len + 3 >= max) {
1247 temp = realloc2n(ret, &max);
1248 ret = temp;
1249 }
1250 if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
1251 ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1252 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
1253 ((*(p) == ','))) {
1254 ret[len++] = *p++;
1255 } else {
1256 int val = *(unsigned char *)p++;
1257 int hi = val / 0x10, lo = val % 0x10;
1258 ret[len++] = '%';
1259 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1260 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1261 }
1262 }
1263 }
1264 if (uri->query != NULL) {
1265 if (len + 1 >= max) {
1266 temp = realloc2n(ret, &max);
1267 ret = temp;
1268 }
1269 ret[len++] = '?';
1270 p = uri->query;
1271 while (*p != 0) {
1272 if (len + 1 >= max) {
1273 temp = realloc2n(ret, &max);
1274 ret = temp;
1275 }
1276 ret[len++] = *p++;
1277 }
1278 }
1279 }
1280 if (uri->fragment != NULL) {
1281 if (len + 3 >= max) {
1282 temp = realloc2n(ret, &max);
1283 ret = temp;
1284 }
1285 ret[len++] = '#';
1286 p = uri->fragment;
1287 while (*p != 0) {
1288 if (len + 3 >= max) {
1289 temp = realloc2n(ret, &max);
1290 ret = temp;
1291 }
1292 if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) {
1293 ret[len++] = *p++;
1294 } else {
1295 int val = *(unsigned char *)p++;
1296 int hi = val / 0x10, lo = val % 0x10;
1297 ret[len++] = '%';
1298 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1299 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1300 }
1301 }
1302 }
1303 if (len >= max) {
1304 temp = realloc2n(ret, &max);
1305 ret = temp;
1306 }
1307 ret[len] = 0;
1308 return ret;
1309}
1310
1311
1312
1313
1314
1315
1316
1317static void uri_clean(URI *uri)
1318{
1319 if (uri == NULL) {
1320 return;
1321 }
1322
1323 g_free(uri->scheme);
1324 uri->scheme = NULL;
1325 g_free(uri->server);
1326 uri->server = NULL;
1327 g_free(uri->user);
1328 uri->user = NULL;
1329 g_free(uri->path);
1330 uri->path = NULL;
1331 g_free(uri->fragment);
1332 uri->fragment = NULL;
1333 g_free(uri->opaque);
1334 uri->opaque = NULL;
1335 g_free(uri->authority);
1336 uri->authority = NULL;
1337 g_free(uri->query);
1338 uri->query = NULL;
1339}
1340
1341
1342
1343
1344
1345
1346
1347void uri_free(URI *uri)
1348{
1349 uri_clean(uri);
1350 g_free(uri);
1351}
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370static int normalize_uri_path(char *path)
1371{
1372 char *cur, *out;
1373
1374 if (path == NULL) {
1375 return -1;
1376 }
1377
1378
1379
1380
1381 cur = path;
1382 while (cur[0] == '/') {
1383 ++cur;
1384 }
1385 if (cur[0] == '\0') {
1386 return 0;
1387 }
1388
1389
1390 out = cur;
1391
1392
1393
1394
1395 while (cur[0] != '\0') {
1396
1397
1398
1399
1400 if ((cur[0] == '.') && (cur[1] == '/')) {
1401 cur += 2;
1402
1403 while (cur[0] == '/') {
1404 cur++;
1405 }
1406 continue;
1407 }
1408
1409
1410
1411
1412
1413 if ((cur[0] == '.') && (cur[1] == '\0')) {
1414 break;
1415 }
1416
1417
1418 while (cur[0] != '/') {
1419 if (cur[0] == '\0') {
1420 goto done_cd;
1421 }
1422 (out++)[0] = (cur++)[0];
1423 }
1424
1425 while ((cur[0] == '/') && (cur[1] == '/')) {
1426 cur++;
1427 }
1428
1429 (out++)[0] = (cur++)[0];
1430 }
1431done_cd:
1432 out[0] = '\0';
1433
1434
1435 cur = path;
1436 while (cur[0] == '/') {
1437 ++cur;
1438 }
1439 if (cur[0] == '\0') {
1440 return 0;
1441 }
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461 while (1) {
1462 char *segp, *tmp;
1463
1464
1465
1466
1467
1468
1469 segp = cur;
1470 while ((segp[0] != '/') && (segp[0] != '\0')) {
1471 ++segp;
1472 }
1473
1474
1475
1476
1477 if (segp[0] == '\0') {
1478 break;
1479 }
1480
1481
1482
1483
1484 ++segp;
1485 if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur + 3)) ||
1486 ((segp[0] != '.') || (segp[1] != '.') ||
1487 ((segp[2] != '/') && (segp[2] != '\0')))) {
1488 cur = segp;
1489 continue;
1490 }
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500 if (segp[2] == '\0') {
1501 cur[0] = '\0';
1502 break;
1503 }
1504
1505
1506 tmp = cur;
1507 segp += 3;
1508 while ((*tmp++ = *segp++) != 0) {
1509
1510 }
1511
1512
1513 segp = cur;
1514 while ((segp > path) && ((--segp)[0] == '/')) {
1515
1516 }
1517 if (segp == path) {
1518 continue;
1519 }
1520
1521
1522
1523
1524
1525
1526
1527
1528 cur = segp;
1529 while ((cur > path) && (cur[-1] != '/')) {
1530 --cur;
1531 }
1532 }
1533 out[0] = '\0';
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546 if (path[0] == '/') {
1547 cur = path;
1548 while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.') &&
1549 ((cur[3] == '/') || (cur[3] == '\0'))) {
1550 cur += 3;
1551 }
1552
1553 if (cur != path) {
1554 out = path;
1555 while (cur[0] != '\0') {
1556 (out++)[0] = (cur++)[0];
1557 }
1558 out[0] = 0;
1559 }
1560 }
1561
1562 return 0;
1563}
1564
1565static int is_hex(char c)
1566{
1567 if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) ||
1568 ((c >= 'A') && (c <= 'F'))) {
1569 return 1;
1570 }
1571 return 0;
1572}
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588char *uri_string_unescape(const char *str, int len, char *target)
1589{
1590 char *ret, *out;
1591 const char *in;
1592
1593 if (str == NULL) {
1594 return NULL;
1595 }
1596 if (len <= 0) {
1597 len = strlen(str);
1598 }
1599 if (len < 0) {
1600 return NULL;
1601 }
1602
1603 if (target == NULL) {
1604 ret = g_malloc(len + 1);
1605 } else {
1606 ret = target;
1607 }
1608 in = str;
1609 out = ret;
1610 while (len > 0) {
1611 if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
1612 in++;
1613 if ((*in >= '0') && (*in <= '9')) {
1614 *out = (*in - '0');
1615 } else if ((*in >= 'a') && (*in <= 'f')) {
1616 *out = (*in - 'a') + 10;
1617 } else if ((*in >= 'A') && (*in <= 'F')) {
1618 *out = (*in - 'A') + 10;
1619 }
1620 in++;
1621 if ((*in >= '0') && (*in <= '9')) {
1622 *out = *out * 16 + (*in - '0');
1623 } else if ((*in >= 'a') && (*in <= 'f')) {
1624 *out = *out * 16 + (*in - 'a') + 10;
1625 } else if ((*in >= 'A') && (*in <= 'F')) {
1626 *out = *out * 16 + (*in - 'A') + 10;
1627 }
1628 in++;
1629 len -= 3;
1630 out++;
1631 } else {
1632 *out++ = *in++;
1633 len--;
1634 }
1635 }
1636 *out = 0;
1637 return ret;
1638}
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650char *uri_string_escape(const char *str, const char *list)
1651{
1652 char *ret, ch;
1653 char *temp;
1654 const char *in;
1655 int len, out;
1656
1657 if (str == NULL) {
1658 return NULL;
1659 }
1660 if (str[0] == 0) {
1661 return g_strdup(str);
1662 }
1663 len = strlen(str);
1664 if (!(len > 0)) {
1665 return NULL;
1666 }
1667
1668 len += 20;
1669 ret = g_malloc(len);
1670 in = str;
1671 out = 0;
1672 while (*in != 0) {
1673 if (len - out <= 3) {
1674 temp = realloc2n(ret, &len);
1675 ret = temp;
1676 }
1677
1678 ch = *in;
1679
1680 if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!strchr(list, ch))) {
1681 unsigned char val;
1682 ret[out++] = '%';
1683 val = ch >> 4;
1684 if (val <= 9) {
1685 ret[out++] = '0' + val;
1686 } else {
1687 ret[out++] = 'A' + val - 0xA;
1688 }
1689 val = ch & 0xF;
1690 if (val <= 9) {
1691 ret[out++] = '0' + val;
1692 } else {
1693 ret[out++] = 'A' + val - 0xA;
1694 }
1695 in++;
1696 } else {
1697 ret[out++] = *in++;
1698 }
1699 }
1700 ret[out] = 0;
1701 return ret;
1702}
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725char *uri_resolve(const char *uri, const char *base)
1726{
1727 char *val = NULL;
1728 int ret, len, indx, cur, out;
1729 URI *ref = NULL;
1730 URI *bas = NULL;
1731 URI *res = NULL;
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741 if (uri == NULL) {
1742 ret = -1;
1743 } else {
1744 if (*uri) {
1745 ref = uri_new();
1746 ret = uri_parse_into(ref, uri);
1747 } else {
1748 ret = 0;
1749 }
1750 }
1751 if (ret != 0) {
1752 goto done;
1753 }
1754 if ((ref != NULL) && (ref->scheme != NULL)) {
1755
1756
1757
1758 val = g_strdup(uri);
1759 goto done;
1760 }
1761 if (base == NULL) {
1762 ret = -1;
1763 } else {
1764 bas = uri_new();
1765 ret = uri_parse_into(bas, base);
1766 }
1767 if (ret != 0) {
1768 if (ref) {
1769 val = uri_to_string(ref);
1770 }
1771 goto done;
1772 }
1773 if (ref == NULL) {
1774
1775
1776
1777 g_free(bas->fragment);
1778 bas->fragment = NULL;
1779 val = uri_to_string(bas);
1780 goto done;
1781 }
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795 res = uri_new();
1796 if ((ref->scheme == NULL) && (ref->path == NULL) &&
1797 ((ref->authority == NULL) && (ref->server == NULL))) {
1798 res->scheme = g_strdup(bas->scheme);
1799 if (bas->authority != NULL) {
1800 res->authority = g_strdup(bas->authority);
1801 } else if (bas->server != NULL) {
1802 res->server = g_strdup(bas->server);
1803 res->user = g_strdup(bas->user);
1804 res->port = bas->port;
1805 }
1806 res->path = g_strdup(bas->path);
1807 if (ref->query != NULL) {
1808 res->query = g_strdup(ref->query);
1809 } else {
1810 res->query = g_strdup(bas->query);
1811 }
1812 res->fragment = g_strdup(ref->fragment);
1813 goto step_7;
1814 }
1815
1816
1817
1818
1819
1820
1821
1822 if (ref->scheme != NULL) {
1823 val = uri_to_string(ref);
1824 goto done;
1825 }
1826 res->scheme = g_strdup(bas->scheme);
1827
1828 res->query = g_strdup(ref->query);
1829 res->fragment = g_strdup(ref->fragment);
1830
1831
1832
1833
1834
1835
1836
1837
1838 if ((ref->authority != NULL) || (ref->server != NULL)) {
1839 if (ref->authority != NULL) {
1840 res->authority = g_strdup(ref->authority);
1841 } else {
1842 res->server = g_strdup(ref->server);
1843 res->user = g_strdup(ref->user);
1844 res->port = ref->port;
1845 }
1846 res->path = g_strdup(ref->path);
1847 goto step_7;
1848 }
1849 if (bas->authority != NULL) {
1850 res->authority = g_strdup(bas->authority);
1851 } else if (bas->server != NULL) {
1852 res->server = g_strdup(bas->server);
1853 res->user = g_strdup(bas->user);
1854 res->port = bas->port;
1855 }
1856
1857
1858
1859
1860
1861 if ((ref->path != NULL) && (ref->path[0] == '/')) {
1862 res->path = g_strdup(ref->path);
1863 goto step_7;
1864 }
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874 len = 2;
1875 if (ref->path != NULL) {
1876 len += strlen(ref->path);
1877 }
1878 if (bas->path != NULL) {
1879 len += strlen(bas->path);
1880 }
1881 res->path = g_malloc(len);
1882 res->path[0] = 0;
1883
1884
1885
1886
1887
1888
1889 cur = 0;
1890 out = 0;
1891 if (bas->path != NULL) {
1892 while (bas->path[cur] != 0) {
1893 while ((bas->path[cur] != 0) && (bas->path[cur] != '/')) {
1894 cur++;
1895 }
1896 if (bas->path[cur] == 0) {
1897 break;
1898 }
1899
1900 cur++;
1901 while (out < cur) {
1902 res->path[out] = bas->path[out];
1903 out++;
1904 }
1905 }
1906 }
1907 res->path[out] = 0;
1908
1909
1910
1911
1912
1913 if (ref->path != NULL && ref->path[0] != 0) {
1914 indx = 0;
1915
1916
1917
1918 if ((out == 0) && (bas->server != NULL)) {
1919 res->path[out++] = '/';
1920 }
1921 while (ref->path[indx] != 0) {
1922 res->path[out++] = ref->path[indx++];
1923 }
1924 }
1925 res->path[out] = 0;
1926
1927
1928
1929
1930 normalize_uri_path(res->path);
1931
1932step_7:
1933
1934
1935
1936
1937
1938
1939 val = uri_to_string(res);
1940
1941done:
1942 if (ref != NULL) {
1943 uri_free(ref);
1944 }
1945 if (bas != NULL) {
1946 uri_free(bas);
1947 }
1948 if (res != NULL) {
1949 uri_free(res);
1950 }
1951 return val;
1952}
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986char *uri_resolve_relative(const char *uri, const char *base)
1987{
1988 char *val = NULL;
1989 int ret;
1990 int ix;
1991 int pos = 0;
1992 int nbslash = 0;
1993 int len;
1994 URI *ref = NULL;
1995 URI *bas = NULL;
1996 char *bptr, *uptr, *vptr;
1997 int remove_path = 0;
1998
1999 if ((uri == NULL) || (*uri == 0)) {
2000 return NULL;
2001 }
2002
2003
2004
2005
2006 ref = uri_new();
2007
2008 if (uri[0] != '.') {
2009 ret = uri_parse_into(ref, uri);
2010 if (ret != 0) {
2011 goto done;
2012 }
2013 } else {
2014 ref->path = g_strdup(uri);
2015 }
2016
2017
2018
2019
2020 if ((base == NULL) || (*base == 0)) {
2021 val = g_strdup(uri);
2022 goto done;
2023 }
2024 bas = uri_new();
2025 if (base[0] != '.') {
2026 ret = uri_parse_into(bas, base);
2027 if (ret != 0) {
2028 goto done;
2029 }
2030 } else {
2031 bas->path = g_strdup(base);
2032 }
2033
2034
2035
2036
2037
2038 if ((ref->scheme != NULL) &&
2039 ((bas->scheme == NULL) || (strcmp(bas->scheme, ref->scheme)) ||
2040 (strcmp(bas->server, ref->server)))) {
2041 val = g_strdup(uri);
2042 goto done;
2043 }
2044 if (bas->path == ref->path ||
2045 (bas->path && ref->path && !strcmp(bas->path, ref->path))) {
2046 val = g_strdup("");
2047 goto done;
2048 }
2049 if (bas->path == NULL) {
2050 val = g_strdup(ref->path);
2051 goto done;
2052 }
2053 if (ref->path == NULL) {
2054 ref->path = (char *)"/";
2055 remove_path = 1;
2056 }
2057
2058
2059
2060
2061
2062
2063
2064 if (bas->path == NULL) {
2065 if (ref->path != NULL) {
2066 uptr = ref->path;
2067 if (*uptr == '/') {
2068 uptr++;
2069 }
2070
2071 val = uri_string_escape(uptr, "/;&=+$,");
2072 }
2073 goto done;
2074 }
2075 bptr = bas->path;
2076 if (ref->path == NULL) {
2077 for (ix = 0; bptr[ix] != 0; ix++) {
2078 if (bptr[ix] == '/') {
2079 nbslash++;
2080 }
2081 }
2082 uptr = NULL;
2083 len = 1;
2084 } else {
2085
2086
2087
2088 if ((ref->path[pos] == '.') && (ref->path[pos + 1] == '/')) {
2089 pos += 2;
2090 }
2091 if ((*bptr == '.') && (bptr[1] == '/')) {
2092 bptr += 2;
2093 } else if ((*bptr == '/') && (ref->path[pos] != '/')) {
2094 bptr++;
2095 }
2096 while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0)) {
2097 pos++;
2098 }
2099
2100 if (bptr[pos] == ref->path[pos]) {
2101 val = g_strdup("");
2102 goto done;
2103 }
2104
2105
2106
2107
2108
2109 ix = pos;
2110 if ((ref->path[ix] == '/') && (ix > 0)) {
2111 ix--;
2112 } else if ((ref->path[ix] == 0) && (ix > 1)
2113 && (ref->path[ix - 1] == '/')) {
2114 ix -= 2;
2115 }
2116 for (; ix > 0; ix--) {
2117 if (ref->path[ix] == '/') {
2118 break;
2119 }
2120 }
2121 if (ix == 0) {
2122 uptr = ref->path;
2123 } else {
2124 ix++;
2125 uptr = &ref->path[ix];
2126 }
2127
2128
2129
2130
2131 if (bptr[pos] != ref->path[pos]) {
2132 for (; bptr[ix] != 0; ix++) {
2133 if (bptr[ix] == '/') {
2134 nbslash++;
2135 }
2136 }
2137 }
2138 len = strlen(uptr) + 1;
2139 }
2140
2141 if (nbslash == 0) {
2142 if (uptr != NULL) {
2143
2144 val = uri_string_escape(uptr, "/;&=+$,");
2145 }
2146 goto done;
2147 }
2148
2149
2150
2151
2152
2153
2154 val = g_malloc(len + 3 * nbslash);
2155 vptr = val;
2156
2157
2158
2159 for (; nbslash > 0; nbslash--) {
2160 *vptr++ = '.';
2161 *vptr++ = '.';
2162 *vptr++ = '/';
2163 }
2164
2165
2166
2167 if (uptr != NULL) {
2168 if ((vptr > val) && (len > 0) && (uptr[0] == '/') &&
2169 (vptr[-1] == '/')) {
2170 memcpy(vptr, uptr + 1, len - 1);
2171 vptr[len - 2] = 0;
2172 } else {
2173 memcpy(vptr, uptr, len);
2174 vptr[len - 1] = 0;
2175 }
2176 } else {
2177 vptr[len - 1] = 0;
2178 }
2179
2180
2181 vptr = val;
2182
2183 val = uri_string_escape(vptr, "/;&=+$,");
2184 g_free(vptr);
2185
2186done:
2187
2188
2189
2190 if (remove_path != 0) {
2191 ref->path = NULL;
2192 }
2193 if (ref != NULL) {
2194 uri_free(ref);
2195 }
2196 if (bas != NULL) {
2197 uri_free(bas);
2198 }
2199
2200 return val;
2201}
2202
2203
2204
2205
2206
2207struct QueryParams *query_params_new(int init_alloc)
2208{
2209 struct QueryParams *ps;
2210
2211 if (init_alloc <= 0) {
2212 init_alloc = 1;
2213 }
2214
2215 ps = g_new(QueryParams, 1);
2216 ps->n = 0;
2217 ps->alloc = init_alloc;
2218 ps->p = g_new(QueryParam, ps->alloc);
2219
2220 return ps;
2221}
2222
2223
2224
2225
2226static int query_params_append(struct QueryParams *ps, const char *name,
2227 const char *value)
2228{
2229 if (ps->n >= ps->alloc) {
2230 ps->p = g_renew(QueryParam, ps->p, ps->alloc * 2);
2231 ps->alloc *= 2;
2232 }
2233
2234 ps->p[ps->n].name = g_strdup(name);
2235 ps->p[ps->n].value = g_strdup(value);
2236 ps->p[ps->n].ignore = 0;
2237 ps->n++;
2238
2239 return 0;
2240}
2241
2242void query_params_free(struct QueryParams *ps)
2243{
2244 int i;
2245
2246 for (i = 0; i < ps->n; ++i) {
2247 g_free(ps->p[i].name);
2248 g_free(ps->p[i].value);
2249 }
2250 g_free(ps->p);
2251 g_free(ps);
2252}
2253
2254struct QueryParams *query_params_parse(const char *query)
2255{
2256 struct QueryParams *ps;
2257 const char *end, *eq;
2258
2259 ps = query_params_new(0);
2260 if (!query || query[0] == '\0') {
2261 return ps;
2262 }
2263
2264 while (*query) {
2265 char *name = NULL, *value = NULL;
2266
2267
2268 end = strchr(query, '&');
2269 if (!end) {
2270 end = qemu_strchrnul(query, ';');
2271 }
2272
2273
2274 eq = strchr(query, '=');
2275 if (eq && eq >= end) {
2276 eq = NULL;
2277 }
2278
2279
2280 if (end == query) {
2281 goto next;
2282 }
2283
2284
2285
2286
2287 else if (!eq) {
2288 name = uri_string_unescape(query, end - query, NULL);
2289 value = NULL;
2290 }
2291
2292
2293
2294 else if (eq + 1 == end) {
2295 name = uri_string_unescape(query, eq - query, NULL);
2296 value = g_new0(char, 1);
2297 }
2298
2299
2300
2301 else if (query == eq) {
2302 goto next;
2303 }
2304
2305
2306 else {
2307 name = uri_string_unescape(query, eq - query, NULL);
2308 value = uri_string_unescape(eq + 1, end - (eq + 1), NULL);
2309 }
2310
2311
2312 query_params_append(ps, name, value);
2313 g_free(name);
2314 g_free(value);
2315
2316 next:
2317 query = end;
2318 if (*query) {
2319 query++;
2320 }
2321 }
2322
2323 return ps;
2324}
2325