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 uri_free(ref);
1943 uri_free(bas);
1944 uri_free(res);
1945 return val;
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
1979
1980char *uri_resolve_relative(const char *uri, const char *base)
1981{
1982 char *val = NULL;
1983 int ret;
1984 int ix;
1985 int pos = 0;
1986 int nbslash = 0;
1987 int len;
1988 URI *ref = NULL;
1989 URI *bas = NULL;
1990 char *bptr, *uptr, *vptr;
1991 int remove_path = 0;
1992
1993 if ((uri == NULL) || (*uri == 0)) {
1994 return NULL;
1995 }
1996
1997
1998
1999
2000 ref = uri_new();
2001
2002 if (uri[0] != '.') {
2003 ret = uri_parse_into(ref, uri);
2004 if (ret != 0) {
2005 goto done;
2006 }
2007 } else {
2008 ref->path = g_strdup(uri);
2009 }
2010
2011
2012
2013
2014 if ((base == NULL) || (*base == 0)) {
2015 val = g_strdup(uri);
2016 goto done;
2017 }
2018 bas = uri_new();
2019 if (base[0] != '.') {
2020 ret = uri_parse_into(bas, base);
2021 if (ret != 0) {
2022 goto done;
2023 }
2024 } else {
2025 bas->path = g_strdup(base);
2026 }
2027
2028
2029
2030
2031
2032 if ((ref->scheme != NULL) &&
2033 ((bas->scheme == NULL) || (strcmp(bas->scheme, ref->scheme)) ||
2034 (strcmp(bas->server, ref->server)))) {
2035 val = g_strdup(uri);
2036 goto done;
2037 }
2038 if (bas->path == ref->path ||
2039 (bas->path && ref->path && !strcmp(bas->path, ref->path))) {
2040 val = g_strdup("");
2041 goto done;
2042 }
2043 if (bas->path == NULL) {
2044 val = g_strdup(ref->path);
2045 goto done;
2046 }
2047 if (ref->path == NULL) {
2048 ref->path = (char *)"/";
2049 remove_path = 1;
2050 }
2051
2052
2053
2054
2055
2056
2057
2058 if (bas->path == NULL) {
2059 if (ref->path != NULL) {
2060 uptr = ref->path;
2061 if (*uptr == '/') {
2062 uptr++;
2063 }
2064
2065 val = uri_string_escape(uptr, "/;&=+$,");
2066 }
2067 goto done;
2068 }
2069 bptr = bas->path;
2070 if (ref->path == NULL) {
2071 for (ix = 0; bptr[ix] != 0; ix++) {
2072 if (bptr[ix] == '/') {
2073 nbslash++;
2074 }
2075 }
2076 uptr = NULL;
2077 len = 1;
2078 } else {
2079
2080
2081
2082 if ((ref->path[pos] == '.') && (ref->path[pos + 1] == '/')) {
2083 pos += 2;
2084 }
2085 if ((*bptr == '.') && (bptr[1] == '/')) {
2086 bptr += 2;
2087 } else if ((*bptr == '/') && (ref->path[pos] != '/')) {
2088 bptr++;
2089 }
2090 while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0)) {
2091 pos++;
2092 }
2093
2094 if (bptr[pos] == ref->path[pos]) {
2095 val = g_strdup("");
2096 goto done;
2097 }
2098
2099
2100
2101
2102
2103 ix = pos;
2104 if ((ref->path[ix] == '/') && (ix > 0)) {
2105 ix--;
2106 } else if ((ref->path[ix] == 0) && (ix > 1)
2107 && (ref->path[ix - 1] == '/')) {
2108 ix -= 2;
2109 }
2110 for (; ix > 0; ix--) {
2111 if (ref->path[ix] == '/') {
2112 break;
2113 }
2114 }
2115 if (ix == 0) {
2116 uptr = ref->path;
2117 } else {
2118 ix++;
2119 uptr = &ref->path[ix];
2120 }
2121
2122
2123
2124
2125 if (bptr[pos] != ref->path[pos]) {
2126 for (; bptr[ix] != 0; ix++) {
2127 if (bptr[ix] == '/') {
2128 nbslash++;
2129 }
2130 }
2131 }
2132 len = strlen(uptr) + 1;
2133 }
2134
2135 if (nbslash == 0) {
2136 if (uptr != NULL) {
2137
2138 val = uri_string_escape(uptr, "/;&=+$,");
2139 }
2140 goto done;
2141 }
2142
2143
2144
2145
2146
2147
2148 val = g_malloc(len + 3 * nbslash);
2149 vptr = val;
2150
2151
2152
2153 for (; nbslash > 0; nbslash--) {
2154 *vptr++ = '.';
2155 *vptr++ = '.';
2156 *vptr++ = '/';
2157 }
2158
2159
2160
2161 if (uptr != NULL) {
2162 if ((vptr > val) && (len > 0) && (uptr[0] == '/') &&
2163 (vptr[-1] == '/')) {
2164 memcpy(vptr, uptr + 1, len - 1);
2165 vptr[len - 2] = 0;
2166 } else {
2167 memcpy(vptr, uptr, len);
2168 vptr[len - 1] = 0;
2169 }
2170 } else {
2171 vptr[len - 1] = 0;
2172 }
2173
2174
2175 vptr = val;
2176
2177 val = uri_string_escape(vptr, "/;&=+$,");
2178 g_free(vptr);
2179
2180done:
2181
2182
2183
2184 if (remove_path != 0) {
2185 ref->path = NULL;
2186 }
2187 uri_free(ref);
2188 uri_free(bas);
2189
2190 return val;
2191}
2192
2193
2194
2195
2196
2197struct QueryParams *query_params_new(int init_alloc)
2198{
2199 struct QueryParams *ps;
2200
2201 if (init_alloc <= 0) {
2202 init_alloc = 1;
2203 }
2204
2205 ps = g_new(QueryParams, 1);
2206 ps->n = 0;
2207 ps->alloc = init_alloc;
2208 ps->p = g_new(QueryParam, ps->alloc);
2209
2210 return ps;
2211}
2212
2213
2214
2215
2216static int query_params_append(struct QueryParams *ps, const char *name,
2217 const char *value)
2218{
2219 if (ps->n >= ps->alloc) {
2220 ps->p = g_renew(QueryParam, ps->p, ps->alloc * 2);
2221 ps->alloc *= 2;
2222 }
2223
2224 ps->p[ps->n].name = g_strdup(name);
2225 ps->p[ps->n].value = g_strdup(value);
2226 ps->p[ps->n].ignore = 0;
2227 ps->n++;
2228
2229 return 0;
2230}
2231
2232void query_params_free(struct QueryParams *ps)
2233{
2234 int i;
2235
2236 for (i = 0; i < ps->n; ++i) {
2237 g_free(ps->p[i].name);
2238 g_free(ps->p[i].value);
2239 }
2240 g_free(ps->p);
2241 g_free(ps);
2242}
2243
2244struct QueryParams *query_params_parse(const char *query)
2245{
2246 struct QueryParams *ps;
2247 const char *end, *eq;
2248
2249 ps = query_params_new(0);
2250 if (!query || query[0] == '\0') {
2251 return ps;
2252 }
2253
2254 while (*query) {
2255 char *name = NULL, *value = NULL;
2256
2257
2258 end = strchr(query, '&');
2259 if (!end) {
2260 end = qemu_strchrnul(query, ';');
2261 }
2262
2263
2264 eq = strchr(query, '=');
2265 if (eq && eq >= end) {
2266 eq = NULL;
2267 }
2268
2269
2270 if (end == query) {
2271 goto next;
2272 }
2273
2274
2275
2276
2277 else if (!eq) {
2278 name = uri_string_unescape(query, end - query, NULL);
2279 value = NULL;
2280 }
2281
2282
2283
2284 else if (eq + 1 == end) {
2285 name = uri_string_unescape(query, eq - query, NULL);
2286 value = g_new0(char, 1);
2287 }
2288
2289
2290
2291 else if (query == eq) {
2292 goto next;
2293 }
2294
2295
2296 else {
2297 name = uri_string_unescape(query, eq - query, NULL);
2298 value = uri_string_unescape(eq + 1, end - (eq + 1), NULL);
2299 }
2300
2301
2302 query_params_append(ps, name, value);
2303 g_free(name);
2304 g_free(value);
2305
2306 next:
2307 query = end;
2308 if (*query) {
2309 query++;
2310 }
2311 }
2312
2313 return ps;
2314}
2315