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