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
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 URI *ret;
1069
1070 ret = g_new0(URI, 1);
1071 return ret;
1072}
1073
1074
1075
1076
1077
1078
1079
1080static char *realloc2n(char *ret, int *max)
1081{
1082 char *temp;
1083 int tmp;
1084
1085 tmp = *max * 2;
1086 temp = g_realloc(ret, (tmp + 1));
1087 *max = tmp;
1088 return temp;
1089}
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099char *uri_to_string(URI *uri)
1100{
1101 char *ret = NULL;
1102 char *temp;
1103 const char *p;
1104 int len;
1105 int max;
1106
1107 if (uri == NULL) {
1108 return NULL;
1109 }
1110
1111 max = 80;
1112 ret = g_malloc(max + 1);
1113 len = 0;
1114
1115 if (uri->scheme != NULL) {
1116 p = uri->scheme;
1117 while (*p != 0) {
1118 if (len >= max) {
1119 temp = realloc2n(ret, &max);
1120 ret = temp;
1121 }
1122 ret[len++] = *p++;
1123 }
1124 if (len >= max) {
1125 temp = realloc2n(ret, &max);
1126 ret = temp;
1127 }
1128 ret[len++] = ':';
1129 }
1130 if (uri->opaque != NULL) {
1131 p = uri->opaque;
1132 while (*p != 0) {
1133 if (len + 3 >= max) {
1134 temp = realloc2n(ret, &max);
1135 ret = temp;
1136 }
1137 if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p))) {
1138 ret[len++] = *p++;
1139 } else {
1140 int val = *(unsigned char *)p++;
1141 int hi = val / 0x10, lo = val % 0x10;
1142 ret[len++] = '%';
1143 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1144 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1145 }
1146 }
1147 } else {
1148 if (uri->server != NULL) {
1149 if (len + 3 >= max) {
1150 temp = realloc2n(ret, &max);
1151 ret = temp;
1152 }
1153 ret[len++] = '/';
1154 ret[len++] = '/';
1155 if (uri->user != NULL) {
1156 p = uri->user;
1157 while (*p != 0) {
1158 if (len + 3 >= max) {
1159 temp = realloc2n(ret, &max);
1160 ret = temp;
1161 }
1162 if ((IS_UNRESERVED(*(p))) || ((*(p) == ';')) ||
1163 ((*(p) == ':')) || ((*(p) == '&')) || ((*(p) == '=')) ||
1164 ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ','))) {
1165 ret[len++] = *p++;
1166 } else {
1167 int val = *(unsigned char *)p++;
1168 int hi = val / 0x10, lo = val % 0x10;
1169 ret[len++] = '%';
1170 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1171 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1172 }
1173 }
1174 if (len + 3 >= max) {
1175 temp = realloc2n(ret, &max);
1176 ret = temp;
1177 }
1178 ret[len++] = '@';
1179 }
1180 p = uri->server;
1181 while (*p != 0) {
1182 if (len >= max) {
1183 temp = realloc2n(ret, &max);
1184 ret = temp;
1185 }
1186 ret[len++] = *p++;
1187 }
1188 if (uri->port > 0) {
1189 if (len + 10 >= max) {
1190 temp = realloc2n(ret, &max);
1191 ret = temp;
1192 }
1193 len += snprintf(&ret[len], max - len, ":%d", uri->port);
1194 }
1195 } else if (uri->authority != NULL) {
1196 if (len + 3 >= max) {
1197 temp = realloc2n(ret, &max);
1198 ret = temp;
1199 }
1200 ret[len++] = '/';
1201 ret[len++] = '/';
1202 p = uri->authority;
1203 while (*p != 0) {
1204 if (len + 3 >= max) {
1205 temp = realloc2n(ret, &max);
1206 ret = temp;
1207 }
1208 if ((IS_UNRESERVED(*(p))) || ((*(p) == '$')) ||
1209 ((*(p) == ',')) || ((*(p) == ';')) || ((*(p) == ':')) ||
1210 ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||
1211 ((*(p) == '+'))) {
1212 ret[len++] = *p++;
1213 } else {
1214 int val = *(unsigned char *)p++;
1215 int hi = val / 0x10, lo = val % 0x10;
1216 ret[len++] = '%';
1217 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1218 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1219 }
1220 }
1221 } else if (uri->scheme != NULL) {
1222 if (len + 3 >= max) {
1223 temp = realloc2n(ret, &max);
1224 ret = temp;
1225 }
1226 ret[len++] = '/';
1227 ret[len++] = '/';
1228 }
1229 if (uri->path != NULL) {
1230 p = uri->path;
1231
1232
1233
1234
1235 if ((uri->scheme != NULL) && (p[0] == '/') &&
1236 (((p[1] >= 'a') && (p[1] <= 'z')) ||
1237 ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
1238 (p[2] == ':') && (!strcmp(uri->scheme, "file"))) {
1239 if (len + 3 >= max) {
1240 temp = realloc2n(ret, &max);
1241 ret = temp;
1242 }
1243 ret[len++] = *p++;
1244 ret[len++] = *p++;
1245 ret[len++] = *p++;
1246 }
1247 while (*p != 0) {
1248 if (len + 3 >= max) {
1249 temp = realloc2n(ret, &max);
1250 ret = temp;
1251 }
1252 if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
1253 ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1254 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
1255 ((*(p) == ','))) {
1256 ret[len++] = *p++;
1257 } else {
1258 int val = *(unsigned char *)p++;
1259 int hi = val / 0x10, lo = val % 0x10;
1260 ret[len++] = '%';
1261 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1262 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1263 }
1264 }
1265 }
1266 if (uri->query != NULL) {
1267 if (len + 1 >= max) {
1268 temp = realloc2n(ret, &max);
1269 ret = temp;
1270 }
1271 ret[len++] = '?';
1272 p = uri->query;
1273 while (*p != 0) {
1274 if (len + 1 >= max) {
1275 temp = realloc2n(ret, &max);
1276 ret = temp;
1277 }
1278 ret[len++] = *p++;
1279 }
1280 }
1281 }
1282 if (uri->fragment != NULL) {
1283 if (len + 3 >= max) {
1284 temp = realloc2n(ret, &max);
1285 ret = temp;
1286 }
1287 ret[len++] = '#';
1288 p = uri->fragment;
1289 while (*p != 0) {
1290 if (len + 3 >= max) {
1291 temp = realloc2n(ret, &max);
1292 ret = temp;
1293 }
1294 if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) {
1295 ret[len++] = *p++;
1296 } else {
1297 int val = *(unsigned char *)p++;
1298 int hi = val / 0x10, lo = val % 0x10;
1299 ret[len++] = '%';
1300 ret[len++] = hi + (hi > 9 ? 'A' - 10 : '0');
1301 ret[len++] = lo + (lo > 9 ? 'A' - 10 : '0');
1302 }
1303 }
1304 }
1305 if (len >= max) {
1306 temp = realloc2n(ret, &max);
1307 ret = temp;
1308 }
1309 ret[len] = 0;
1310 return ret;
1311}
1312
1313
1314
1315
1316
1317
1318
1319static void uri_clean(URI *uri)
1320{
1321 if (uri == NULL) {
1322 return;
1323 }
1324
1325 g_free(uri->scheme);
1326 uri->scheme = NULL;
1327 g_free(uri->server);
1328 uri->server = NULL;
1329 g_free(uri->user);
1330 uri->user = NULL;
1331 g_free(uri->path);
1332 uri->path = NULL;
1333 g_free(uri->fragment);
1334 uri->fragment = NULL;
1335 g_free(uri->opaque);
1336 uri->opaque = NULL;
1337 g_free(uri->authority);
1338 uri->authority = NULL;
1339 g_free(uri->query);
1340 uri->query = NULL;
1341}
1342
1343
1344
1345
1346
1347
1348
1349void uri_free(URI *uri)
1350{
1351 uri_clean(uri);
1352 g_free(uri);
1353}
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372static int normalize_uri_path(char *path)
1373{
1374 char *cur, *out;
1375
1376 if (path == NULL) {
1377 return -1;
1378 }
1379
1380
1381
1382
1383 cur = path;
1384 while (cur[0] == '/') {
1385 ++cur;
1386 }
1387 if (cur[0] == '\0') {
1388 return 0;
1389 }
1390
1391
1392 out = cur;
1393
1394
1395
1396
1397 while (cur[0] != '\0') {
1398
1399
1400
1401
1402 if ((cur[0] == '.') && (cur[1] == '/')) {
1403 cur += 2;
1404
1405 while (cur[0] == '/') {
1406 cur++;
1407 }
1408 continue;
1409 }
1410
1411
1412
1413
1414
1415 if ((cur[0] == '.') && (cur[1] == '\0')) {
1416 break;
1417 }
1418
1419
1420 while (cur[0] != '/') {
1421 if (cur[0] == '\0') {
1422 goto done_cd;
1423 }
1424 (out++)[0] = (cur++)[0];
1425 }
1426
1427 while ((cur[0] == '/') && (cur[1] == '/')) {
1428 cur++;
1429 }
1430
1431 (out++)[0] = (cur++)[0];
1432 }
1433done_cd:
1434 out[0] = '\0';
1435
1436
1437 cur = path;
1438 while (cur[0] == '/') {
1439 ++cur;
1440 }
1441 if (cur[0] == '\0') {
1442 return 0;
1443 }
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463 while (1) {
1464 char *segp, *tmp;
1465
1466
1467
1468
1469
1470
1471 segp = cur;
1472 while ((segp[0] != '/') && (segp[0] != '\0')) {
1473 ++segp;
1474 }
1475
1476
1477
1478
1479 if (segp[0] == '\0') {
1480 break;
1481 }
1482
1483
1484
1485
1486 ++segp;
1487 if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur + 3)) ||
1488 ((segp[0] != '.') || (segp[1] != '.') ||
1489 ((segp[2] != '/') && (segp[2] != '\0')))) {
1490 cur = segp;
1491 continue;
1492 }
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502 if (segp[2] == '\0') {
1503 cur[0] = '\0';
1504 break;
1505 }
1506
1507
1508 tmp = cur;
1509 segp += 3;
1510 while ((*tmp++ = *segp++) != 0) {
1511
1512 }
1513
1514
1515 segp = cur;
1516 while ((segp > path) && ((--segp)[0] == '/')) {
1517
1518 }
1519 if (segp == path) {
1520 continue;
1521 }
1522
1523
1524
1525
1526
1527
1528
1529
1530 cur = segp;
1531 while ((cur > path) && (cur[-1] != '/')) {
1532 --cur;
1533 }
1534 }
1535 out[0] = '\0';
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548 if (path[0] == '/') {
1549 cur = path;
1550 while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.') &&
1551 ((cur[3] == '/') || (cur[3] == '\0'))) {
1552 cur += 3;
1553 }
1554
1555 if (cur != path) {
1556 out = path;
1557 while (cur[0] != '\0') {
1558 (out++)[0] = (cur++)[0];
1559 }
1560 out[0] = 0;
1561 }
1562 }
1563
1564 return 0;
1565}
1566
1567static int is_hex(char c)
1568{
1569 if (((c >= '0') && (c <= '9')) || ((c >= 'a') && (c <= 'f')) ||
1570 ((c >= 'A') && (c <= 'F'))) {
1571 return 1;
1572 }
1573 return 0;
1574}
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590char *uri_string_unescape(const char *str, int len, char *target)
1591{
1592 char *ret, *out;
1593 const char *in;
1594
1595 if (str == NULL) {
1596 return NULL;
1597 }
1598 if (len <= 0) {
1599 len = strlen(str);
1600 }
1601 if (len < 0) {
1602 return NULL;
1603 }
1604
1605 if (target == NULL) {
1606 ret = g_malloc(len + 1);
1607 } else {
1608 ret = target;
1609 }
1610 in = str;
1611 out = ret;
1612 while (len > 0) {
1613 if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
1614 in++;
1615 if ((*in >= '0') && (*in <= '9')) {
1616 *out = (*in - '0');
1617 } else if ((*in >= 'a') && (*in <= 'f')) {
1618 *out = (*in - 'a') + 10;
1619 } else if ((*in >= 'A') && (*in <= 'F')) {
1620 *out = (*in - 'A') + 10;
1621 }
1622 in++;
1623 if ((*in >= '0') && (*in <= '9')) {
1624 *out = *out * 16 + (*in - '0');
1625 } else if ((*in >= 'a') && (*in <= 'f')) {
1626 *out = *out * 16 + (*in - 'a') + 10;
1627 } else if ((*in >= 'A') && (*in <= 'F')) {
1628 *out = *out * 16 + (*in - 'A') + 10;
1629 }
1630 in++;
1631 len -= 3;
1632 out++;
1633 } else {
1634 *out++ = *in++;
1635 len--;
1636 }
1637 }
1638 *out = 0;
1639 return ret;
1640}
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652char *uri_string_escape(const char *str, const char *list)
1653{
1654 char *ret, ch;
1655 char *temp;
1656 const char *in;
1657 int len, out;
1658
1659 if (str == NULL) {
1660 return NULL;
1661 }
1662 if (str[0] == 0) {
1663 return g_strdup(str);
1664 }
1665 len = strlen(str);
1666 if (!(len > 0)) {
1667 return NULL;
1668 }
1669
1670 len += 20;
1671 ret = g_malloc(len);
1672 in = str;
1673 out = 0;
1674 while (*in != 0) {
1675 if (len - out <= 3) {
1676 temp = realloc2n(ret, &len);
1677 ret = temp;
1678 }
1679
1680 ch = *in;
1681
1682 if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!strchr(list, ch))) {
1683 unsigned char val;
1684 ret[out++] = '%';
1685 val = ch >> 4;
1686 if (val <= 9) {
1687 ret[out++] = '0' + val;
1688 } else {
1689 ret[out++] = 'A' + val - 0xA;
1690 }
1691 val = ch & 0xF;
1692 if (val <= 9) {
1693 ret[out++] = '0' + val;
1694 } else {
1695 ret[out++] = 'A' + val - 0xA;
1696 }
1697 in++;
1698 } else {
1699 ret[out++] = *in++;
1700 }
1701 }
1702 ret[out] = 0;
1703 return ret;
1704}
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727char *uri_resolve(const char *uri, const char *base)
1728{
1729 char *val = NULL;
1730 int ret, len, indx, cur, out;
1731 URI *ref = NULL;
1732 URI *bas = NULL;
1733 URI *res = NULL;
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743 if (uri == NULL) {
1744 ret = -1;
1745 } else {
1746 if (*uri) {
1747 ref = uri_new();
1748 ret = uri_parse_into(ref, uri);
1749 } else {
1750 ret = 0;
1751 }
1752 }
1753 if (ret != 0) {
1754 goto done;
1755 }
1756 if ((ref != NULL) && (ref->scheme != NULL)) {
1757
1758
1759
1760 val = g_strdup(uri);
1761 goto done;
1762 }
1763 if (base == NULL) {
1764 ret = -1;
1765 } else {
1766 bas = uri_new();
1767 ret = uri_parse_into(bas, base);
1768 }
1769 if (ret != 0) {
1770 if (ref) {
1771 val = uri_to_string(ref);
1772 }
1773 goto done;
1774 }
1775 if (ref == NULL) {
1776
1777
1778
1779 g_free(bas->fragment);
1780 bas->fragment = NULL;
1781 val = uri_to_string(bas);
1782 goto done;
1783 }
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797 res = uri_new();
1798 if ((ref->scheme == NULL) && (ref->path == NULL) &&
1799 ((ref->authority == NULL) && (ref->server == NULL))) {
1800 res->scheme = g_strdup(bas->scheme);
1801 if (bas->authority != NULL) {
1802 res->authority = g_strdup(bas->authority);
1803 } else if (bas->server != NULL) {
1804 res->server = g_strdup(bas->server);
1805 res->user = g_strdup(bas->user);
1806 res->port = bas->port;
1807 }
1808 res->path = g_strdup(bas->path);
1809 if (ref->query != NULL) {
1810 res->query = g_strdup(ref->query);
1811 } else {
1812 res->query = g_strdup(bas->query);
1813 }
1814 res->fragment = g_strdup(ref->fragment);
1815 goto step_7;
1816 }
1817
1818
1819
1820
1821
1822
1823
1824 if (ref->scheme != NULL) {
1825 val = uri_to_string(ref);
1826 goto done;
1827 }
1828 res->scheme = g_strdup(bas->scheme);
1829
1830 res->query = g_strdup(ref->query);
1831 res->fragment = g_strdup(ref->fragment);
1832
1833
1834
1835
1836
1837
1838
1839
1840 if ((ref->authority != NULL) || (ref->server != NULL)) {
1841 if (ref->authority != NULL) {
1842 res->authority = g_strdup(ref->authority);
1843 } else {
1844 res->server = g_strdup(ref->server);
1845 res->user = g_strdup(ref->user);
1846 res->port = ref->port;
1847 }
1848 res->path = g_strdup(ref->path);
1849 goto step_7;
1850 }
1851 if (bas->authority != NULL) {
1852 res->authority = g_strdup(bas->authority);
1853 } else if (bas->server != NULL) {
1854 res->server = g_strdup(bas->server);
1855 res->user = g_strdup(bas->user);
1856 res->port = bas->port;
1857 }
1858
1859
1860
1861
1862
1863 if ((ref->path != NULL) && (ref->path[0] == '/')) {
1864 res->path = g_strdup(ref->path);
1865 goto step_7;
1866 }
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876 len = 2;
1877 if (ref->path != NULL) {
1878 len += strlen(ref->path);
1879 }
1880 if (bas->path != NULL) {
1881 len += strlen(bas->path);
1882 }
1883 res->path = g_malloc(len);
1884 res->path[0] = 0;
1885
1886
1887
1888
1889
1890
1891 cur = 0;
1892 out = 0;
1893 if (bas->path != NULL) {
1894 while (bas->path[cur] != 0) {
1895 while ((bas->path[cur] != 0) && (bas->path[cur] != '/')) {
1896 cur++;
1897 }
1898 if (bas->path[cur] == 0) {
1899 break;
1900 }
1901
1902 cur++;
1903 while (out < cur) {
1904 res->path[out] = bas->path[out];
1905 out++;
1906 }
1907 }
1908 }
1909 res->path[out] = 0;
1910
1911
1912
1913
1914
1915 if (ref->path != NULL && ref->path[0] != 0) {
1916 indx = 0;
1917
1918
1919
1920 if ((out == 0) && (bas->server != NULL)) {
1921 res->path[out++] = '/';
1922 }
1923 while (ref->path[indx] != 0) {
1924 res->path[out++] = ref->path[indx++];
1925 }
1926 }
1927 res->path[out] = 0;
1928
1929
1930
1931
1932 normalize_uri_path(res->path);
1933
1934step_7:
1935
1936
1937
1938
1939
1940
1941 val = uri_to_string(res);
1942
1943done:
1944 if (ref != NULL) {
1945 uri_free(ref);
1946 }
1947 if (bas != NULL) {
1948 uri_free(bas);
1949 }
1950 if (res != NULL) {
1951 uri_free(res);
1952 }
1953 return val;
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
1986
1987
1988char *uri_resolve_relative(const char *uri, const char *base)
1989{
1990 char *val = NULL;
1991 int ret;
1992 int ix;
1993 int pos = 0;
1994 int nbslash = 0;
1995 int len;
1996 URI *ref = NULL;
1997 URI *bas = NULL;
1998 char *bptr, *uptr, *vptr;
1999 int remove_path = 0;
2000
2001 if ((uri == NULL) || (*uri == 0)) {
2002 return NULL;
2003 }
2004
2005
2006
2007
2008 ref = uri_new();
2009
2010 if (uri[0] != '.') {
2011 ret = uri_parse_into(ref, uri);
2012 if (ret != 0) {
2013 goto done;
2014 }
2015 } else {
2016 ref->path = g_strdup(uri);
2017 }
2018
2019
2020
2021
2022 if ((base == NULL) || (*base == 0)) {
2023 val = g_strdup(uri);
2024 goto done;
2025 }
2026 bas = uri_new();
2027 if (base[0] != '.') {
2028 ret = uri_parse_into(bas, base);
2029 if (ret != 0) {
2030 goto done;
2031 }
2032 } else {
2033 bas->path = g_strdup(base);
2034 }
2035
2036
2037
2038
2039
2040 if ((ref->scheme != NULL) &&
2041 ((bas->scheme == NULL) || (strcmp(bas->scheme, ref->scheme)) ||
2042 (strcmp(bas->server, ref->server)))) {
2043 val = g_strdup(uri);
2044 goto done;
2045 }
2046 if (bas->path == ref->path ||
2047 (bas->path && ref->path && !strcmp(bas->path, ref->path))) {
2048 val = g_strdup("");
2049 goto done;
2050 }
2051 if (bas->path == NULL) {
2052 val = g_strdup(ref->path);
2053 goto done;
2054 }
2055 if (ref->path == NULL) {
2056 ref->path = (char *)"/";
2057 remove_path = 1;
2058 }
2059
2060
2061
2062
2063
2064
2065
2066 if (bas->path == NULL) {
2067 if (ref->path != NULL) {
2068 uptr = ref->path;
2069 if (*uptr == '/') {
2070 uptr++;
2071 }
2072
2073 val = uri_string_escape(uptr, "/;&=+$,");
2074 }
2075 goto done;
2076 }
2077 bptr = bas->path;
2078 if (ref->path == NULL) {
2079 for (ix = 0; bptr[ix] != 0; ix++) {
2080 if (bptr[ix] == '/') {
2081 nbslash++;
2082 }
2083 }
2084 uptr = NULL;
2085 len = 1;
2086 } else {
2087
2088
2089
2090 if ((ref->path[pos] == '.') && (ref->path[pos + 1] == '/')) {
2091 pos += 2;
2092 }
2093 if ((*bptr == '.') && (bptr[1] == '/')) {
2094 bptr += 2;
2095 } else if ((*bptr == '/') && (ref->path[pos] != '/')) {
2096 bptr++;
2097 }
2098 while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0)) {
2099 pos++;
2100 }
2101
2102 if (bptr[pos] == ref->path[pos]) {
2103 val = g_strdup("");
2104 goto done;
2105 }
2106
2107
2108
2109
2110
2111 ix = pos;
2112 if ((ref->path[ix] == '/') && (ix > 0)) {
2113 ix--;
2114 } else if ((ref->path[ix] == 0) && (ix > 1)
2115 && (ref->path[ix - 1] == '/')) {
2116 ix -= 2;
2117 }
2118 for (; ix > 0; ix--) {
2119 if (ref->path[ix] == '/') {
2120 break;
2121 }
2122 }
2123 if (ix == 0) {
2124 uptr = ref->path;
2125 } else {
2126 ix++;
2127 uptr = &ref->path[ix];
2128 }
2129
2130
2131
2132
2133 if (bptr[pos] != ref->path[pos]) {
2134 for (; bptr[ix] != 0; ix++) {
2135 if (bptr[ix] == '/') {
2136 nbslash++;
2137 }
2138 }
2139 }
2140 len = strlen(uptr) + 1;
2141 }
2142
2143 if (nbslash == 0) {
2144 if (uptr != NULL) {
2145
2146 val = uri_string_escape(uptr, "/;&=+$,");
2147 }
2148 goto done;
2149 }
2150
2151
2152
2153
2154
2155
2156 val = g_malloc(len + 3 * nbslash);
2157 vptr = val;
2158
2159
2160
2161 for (; nbslash > 0; nbslash--) {
2162 *vptr++ = '.';
2163 *vptr++ = '.';
2164 *vptr++ = '/';
2165 }
2166
2167
2168
2169 if (uptr != NULL) {
2170 if ((vptr > val) && (len > 0) && (uptr[0] == '/') &&
2171 (vptr[-1] == '/')) {
2172 memcpy(vptr, uptr + 1, len - 1);
2173 vptr[len - 2] = 0;
2174 } else {
2175 memcpy(vptr, uptr, len);
2176 vptr[len - 1] = 0;
2177 }
2178 } else {
2179 vptr[len - 1] = 0;
2180 }
2181
2182
2183 vptr = val;
2184
2185 val = uri_string_escape(vptr, "/;&=+$,");
2186 g_free(vptr);
2187
2188done:
2189
2190
2191
2192 if (remove_path != 0) {
2193 ref->path = NULL;
2194 }
2195 if (ref != NULL) {
2196 uri_free(ref);
2197 }
2198 if (bas != NULL) {
2199 uri_free(bas);
2200 }
2201
2202 return val;
2203}
2204
2205
2206
2207
2208
2209struct QueryParams *query_params_new(int init_alloc)
2210{
2211 struct QueryParams *ps;
2212
2213 if (init_alloc <= 0) {
2214 init_alloc = 1;
2215 }
2216
2217 ps = g_new(QueryParams, 1);
2218 ps->n = 0;
2219 ps->alloc = init_alloc;
2220 ps->p = g_new(QueryParam, ps->alloc);
2221
2222 return ps;
2223}
2224
2225
2226
2227
2228static int query_params_append(struct QueryParams *ps, const char *name,
2229 const char *value)
2230{
2231 if (ps->n >= ps->alloc) {
2232 ps->p = g_renew(QueryParam, ps->p, ps->alloc * 2);
2233 ps->alloc *= 2;
2234 }
2235
2236 ps->p[ps->n].name = g_strdup(name);
2237 ps->p[ps->n].value = g_strdup(value);
2238 ps->p[ps->n].ignore = 0;
2239 ps->n++;
2240
2241 return 0;
2242}
2243
2244void query_params_free(struct QueryParams *ps)
2245{
2246 int i;
2247
2248 for (i = 0; i < ps->n; ++i) {
2249 g_free(ps->p[i].name);
2250 g_free(ps->p[i].value);
2251 }
2252 g_free(ps->p);
2253 g_free(ps);
2254}
2255
2256struct QueryParams *query_params_parse(const char *query)
2257{
2258 struct QueryParams *ps;
2259 const char *end, *eq;
2260
2261 ps = query_params_new(0);
2262 if (!query || query[0] == '\0') {
2263 return ps;
2264 }
2265
2266 while (*query) {
2267 char *name = NULL, *value = NULL;
2268
2269
2270 end = strchr(query, '&');
2271 if (!end) {
2272 end = strchr(query, ';');
2273 }
2274 if (!end) {
2275 end = query + strlen(query);
2276 }
2277
2278
2279 eq = strchr(query, '=');
2280 if (eq && eq >= end) {
2281 eq = NULL;
2282 }
2283
2284
2285 if (end == query) {
2286 goto next;
2287 }
2288
2289
2290
2291
2292 else if (!eq) {
2293 name = uri_string_unescape(query, end - query, NULL);
2294 value = NULL;
2295 }
2296
2297
2298
2299 else if (eq + 1 == end) {
2300 name = uri_string_unescape(query, eq - query, NULL);
2301 value = g_new0(char, 1);
2302 }
2303
2304
2305
2306 else if (query == eq) {
2307 goto next;
2308 }
2309
2310
2311 else {
2312 name = uri_string_unescape(query, eq - query, NULL);
2313 value = uri_string_unescape(eq + 1, end - (eq + 1), NULL);
2314 }
2315
2316
2317 query_params_append(ps, name, value);
2318 g_free(name);
2319 g_free(value);
2320
2321 next:
2322 query = end;
2323 if (*query) {
2324 query++;
2325 }
2326 }
2327
2328 return ps;
2329}
2330