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