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
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
151#define ISA_DIGIT(p) ((*(p) >= '0') && (*(p) <= '9'))
152#define ISA_ALPHA(p) (((*(p) >= 'a') && (*(p) <= 'z')) || \
153 ((*(p) >= 'A') && (*(p) <= 'Z')))
154#define ISA_HEXDIG(p) \
155 (ISA_DIGIT(p) || ((*(p) >= 'a') && (*(p) <= 'f')) || \
156 ((*(p) >= 'A') && (*(p) <= 'F')))
157
158
159
160
161
162#define ISA_SUB_DELIM(p) \
163 (((*(p) == '!')) || ((*(p) == '$')) || ((*(p) == '&')) || \
164 ((*(p) == '(')) || ((*(p) == ')')) || ((*(p) == '*')) || \
165 ((*(p) == '+')) || ((*(p) == ',')) || ((*(p) == ';')) || \
166 ((*(p) == '=')) || ((*(p) == '\'')))
167
168
169
170
171#define ISA_GEN_DELIM(p) \
172 (((*(p) == ':')) || ((*(p) == '/')) || ((*(p) == '?')) || \
173 ((*(p) == '#')) || ((*(p) == '[')) || ((*(p) == ']')) || \
174 ((*(p) == '@')))
175
176
177
178
179#define ISA_RESERVED(p) (ISA_GEN_DELIM(p) || (ISA_SUB_DELIM(p)))
180
181
182
183
184#define ISA_UNRESERVED(p) \
185 ((ISA_ALPHA(p)) || (ISA_DIGIT(p)) || ((*(p) == '-')) || \
186 ((*(p) == '.')) || ((*(p) == '_')) || ((*(p) == '~')))
187
188
189
190
191#define ISA_PCT_ENCODED(p) \
192 ((*(p) == '%') && (ISA_HEXDIG(p + 1)) && (ISA_HEXDIG(p + 2)))
193
194
195
196
197#define ISA_PCHAR(p) \
198 (ISA_UNRESERVED(p) || ISA_PCT_ENCODED(p) || ISA_SUB_DELIM(p) || \
199 ((*(p) == ':')) || ((*(p) == '@')))
200
201
202
203
204
205
206
207
208
209
210
211
212static int
213rfc3986_parse_scheme(URI *uri, const char **str) {
214 const char *cur;
215
216 if (str == NULL)
217 return(-1);
218
219 cur = *str;
220 if (!ISA_ALPHA(cur))
221 return(2);
222 cur++;
223 while (ISA_ALPHA(cur) || ISA_DIGIT(cur) ||
224 (*cur == '+') || (*cur == '-') || (*cur == '.')) cur++;
225 if (uri != NULL) {
226 g_free(uri->scheme);
227 uri->scheme = g_strndup(*str, cur - *str);
228 }
229 *str = cur;
230 return(0);
231}
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248static int
249rfc3986_parse_fragment(URI *uri, const char **str)
250{
251 const char *cur;
252
253 if (str == NULL)
254 return (-1);
255
256 cur = *str;
257
258 while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
259 (*cur == '[') || (*cur == ']') ||
260 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
261 NEXT(cur);
262 if (uri != NULL) {
263 g_free(uri->fragment);
264 if (uri->cleanup & 2)
265 uri->fragment = g_strndup(*str, cur - *str);
266 else
267 uri->fragment = uri_string_unescape(*str, cur - *str, NULL);
268 }
269 *str = cur;
270 return (0);
271}
272
273
274
275
276
277
278
279
280
281
282
283
284static int
285rfc3986_parse_query(URI *uri, const char **str)
286{
287 const char *cur;
288
289 if (str == NULL)
290 return (-1);
291
292 cur = *str;
293
294 while ((ISA_PCHAR(cur)) || (*cur == '/') || (*cur == '?') ||
295 ((uri != NULL) && (uri->cleanup & 1) && (IS_UNWISE(cur))))
296 NEXT(cur);
297 if (uri != NULL) {
298 g_free(uri->query);
299 uri->query = g_strndup (*str, cur - *str);
300 }
301 *str = cur;
302 return (0);
303}
304
305
306
307
308
309
310
311
312
313
314
315
316
317static int
318rfc3986_parse_port(URI *uri, const char **str)
319{
320 const char *cur = *str;
321 int port = 0;
322
323 if (ISA_DIGIT(cur)) {
324 while (ISA_DIGIT(cur)) {
325 port = port * 10 + (*cur - '0');
326 if (port > 65535) {
327 return 1;
328 }
329 cur++;
330 }
331 if (uri) {
332 uri->port = port;
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 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 g_free(uri->authority);
477 uri->authority = NULL;
478 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 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 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 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 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 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 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 ret = rfc3986_parse_uri_reference(uri, str);
934 if (ret) {
935 uri_free(uri);
936 return(NULL);
937 }
938 return(uri);
939}
940
941
942
943
944
945
946
947
948
949
950
951
952
953int
954uri_parse_into(URI *uri, const char *str) {
955 return(rfc3986_parse_uri_reference(uri, str));
956}
957
958
959
960
961
962
963
964
965
966
967
968
969URI *
970uri_parse_raw(const char *str, int raw) {
971 URI *uri;
972 int ret;
973
974 if (str == NULL)
975 return(NULL);
976 uri = uri_new();
977 if (raw) {
978 uri->cleanup |= 2;
979 }
980 ret = uri_parse_into(uri, str);
981 if (ret) {
982 uri_free(uri);
983 return(NULL);
984 }
985 return(uri);
986}
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001URI *
1002uri_new(void) {
1003 URI *ret;
1004
1005 ret = g_new0(URI, 1);
1006 return(ret);
1007}
1008
1009
1010
1011
1012
1013
1014
1015static char *
1016realloc2n(char *ret, int *max) {
1017 char *temp;
1018 int tmp;
1019
1020 tmp = *max * 2;
1021 temp = g_realloc(ret, (tmp + 1));
1022 *max = tmp;
1023 return(temp);
1024}
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034char *
1035uri_to_string(URI *uri) {
1036 char *ret = NULL;
1037 char *temp;
1038 const char *p;
1039 int len;
1040 int max;
1041
1042 if (uri == NULL) return(NULL);
1043
1044
1045 max = 80;
1046 ret = g_malloc(max + 1);
1047 len = 0;
1048
1049 if (uri->scheme != NULL) {
1050 p = uri->scheme;
1051 while (*p != 0) {
1052 if (len >= max) {
1053 temp = realloc2n(ret, &max);
1054 ret = temp;
1055 }
1056 ret[len++] = *p++;
1057 }
1058 if (len >= max) {
1059 temp = realloc2n(ret, &max);
1060 ret = temp;
1061 }
1062 ret[len++] = ':';
1063 }
1064 if (uri->opaque != NULL) {
1065 p = uri->opaque;
1066 while (*p != 0) {
1067 if (len + 3 >= max) {
1068 temp = realloc2n(ret, &max);
1069 ret = temp;
1070 }
1071 if (IS_RESERVED(*(p)) || IS_UNRESERVED(*(p)))
1072 ret[len++] = *p++;
1073 else {
1074 int val = *(unsigned char *)p++;
1075 int hi = val / 0x10, lo = val % 0x10;
1076 ret[len++] = '%';
1077 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1078 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1079 }
1080 }
1081 } else {
1082 if (uri->server != NULL) {
1083 if (len + 3 >= max) {
1084 temp = realloc2n(ret, &max);
1085 ret = temp;
1086 }
1087 ret[len++] = '/';
1088 ret[len++] = '/';
1089 if (uri->user != NULL) {
1090 p = uri->user;
1091 while (*p != 0) {
1092 if (len + 3 >= max) {
1093 temp = realloc2n(ret, &max);
1094 ret = temp;
1095 }
1096 if ((IS_UNRESERVED(*(p))) ||
1097 ((*(p) == ';')) || ((*(p) == ':')) ||
1098 ((*(p) == '&')) || ((*(p) == '=')) ||
1099 ((*(p) == '+')) || ((*(p) == '$')) ||
1100 ((*(p) == ',')))
1101 ret[len++] = *p++;
1102 else {
1103 int val = *(unsigned char *)p++;
1104 int hi = val / 0x10, lo = val % 0x10;
1105 ret[len++] = '%';
1106 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1107 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1108 }
1109 }
1110 if (len + 3 >= max) {
1111 temp = realloc2n(ret, &max);
1112 ret = temp;
1113 }
1114 ret[len++] = '@';
1115 }
1116 p = uri->server;
1117 while (*p != 0) {
1118 if (len >= max) {
1119 temp = realloc2n(ret, &max);
1120 ret = temp;
1121 }
1122 ret[len++] = *p++;
1123 }
1124 if (uri->port > 0) {
1125 if (len + 10 >= max) {
1126 temp = realloc2n(ret, &max);
1127 ret = temp;
1128 }
1129 len += snprintf(&ret[len], max - len, ":%d", uri->port);
1130 }
1131 } else if (uri->authority != NULL) {
1132 if (len + 3 >= max) {
1133 temp = realloc2n(ret, &max);
1134 ret = temp;
1135 }
1136 ret[len++] = '/';
1137 ret[len++] = '/';
1138 p = uri->authority;
1139 while (*p != 0) {
1140 if (len + 3 >= max) {
1141 temp = realloc2n(ret, &max);
1142 ret = temp;
1143 }
1144 if ((IS_UNRESERVED(*(p))) ||
1145 ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
1146 ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1147 ((*(p) == '=')) || ((*(p) == '+')))
1148 ret[len++] = *p++;
1149 else {
1150 int val = *(unsigned char *)p++;
1151 int hi = val / 0x10, lo = val % 0x10;
1152 ret[len++] = '%';
1153 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1154 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1155 }
1156 }
1157 } else if (uri->scheme != NULL) {
1158 if (len + 3 >= max) {
1159 temp = realloc2n(ret, &max);
1160 ret = temp;
1161 }
1162 ret[len++] = '/';
1163 ret[len++] = '/';
1164 }
1165 if (uri->path != NULL) {
1166 p = uri->path;
1167
1168
1169
1170
1171 if ((uri->scheme != NULL) &&
1172 (p[0] == '/') &&
1173 (((p[1] >= 'a') && (p[1] <= 'z')) ||
1174 ((p[1] >= 'A') && (p[1] <= 'Z'))) &&
1175 (p[2] == ':') &&
1176 (!strcmp(uri->scheme, "file"))) {
1177 if (len + 3 >= max) {
1178 temp = realloc2n(ret, &max);
1179 ret = temp;
1180 }
1181 ret[len++] = *p++;
1182 ret[len++] = *p++;
1183 ret[len++] = *p++;
1184 }
1185 while (*p != 0) {
1186 if (len + 3 >= max) {
1187 temp = realloc2n(ret, &max);
1188 ret = temp;
1189 }
1190 if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
1191 ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
1192 ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
1193 ((*(p) == ',')))
1194 ret[len++] = *p++;
1195 else {
1196 int val = *(unsigned char *)p++;
1197 int hi = val / 0x10, lo = val % 0x10;
1198 ret[len++] = '%';
1199 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1200 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1201 }
1202 }
1203 }
1204 if (uri->query != NULL) {
1205 if (len + 1 >= max) {
1206 temp = realloc2n(ret, &max);
1207 ret = temp;
1208 }
1209 ret[len++] = '?';
1210 p = uri->query;
1211 while (*p != 0) {
1212 if (len + 1 >= max) {
1213 temp = realloc2n(ret, &max);
1214 ret = temp;
1215 }
1216 ret[len++] = *p++;
1217 }
1218 }
1219 }
1220 if (uri->fragment != NULL) {
1221 if (len + 3 >= max) {
1222 temp = realloc2n(ret, &max);
1223 ret = temp;
1224 }
1225 ret[len++] = '#';
1226 p = uri->fragment;
1227 while (*p != 0) {
1228 if (len + 3 >= max) {
1229 temp = realloc2n(ret, &max);
1230 ret = temp;
1231 }
1232 if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p))))
1233 ret[len++] = *p++;
1234 else {
1235 int val = *(unsigned char *)p++;
1236 int hi = val / 0x10, lo = val % 0x10;
1237 ret[len++] = '%';
1238 ret[len++] = hi + (hi > 9? 'A'-10 : '0');
1239 ret[len++] = lo + (lo > 9? 'A'-10 : '0');
1240 }
1241 }
1242 }
1243 if (len >= max) {
1244 temp = realloc2n(ret, &max);
1245 ret = temp;
1246 }
1247 ret[len] = 0;
1248 return(ret);
1249}
1250
1251
1252
1253
1254
1255
1256
1257static void
1258uri_clean(URI *uri) {
1259 if (uri == NULL) return;
1260
1261 g_free(uri->scheme);
1262 uri->scheme = NULL;
1263 g_free(uri->server);
1264 uri->server = NULL;
1265 g_free(uri->user);
1266 uri->user = NULL;
1267 g_free(uri->path);
1268 uri->path = NULL;
1269 g_free(uri->fragment);
1270 uri->fragment = NULL;
1271 g_free(uri->opaque);
1272 uri->opaque = NULL;
1273 g_free(uri->authority);
1274 uri->authority = NULL;
1275 g_free(uri->query);
1276 uri->query = NULL;
1277}
1278
1279
1280
1281
1282
1283
1284
1285void
1286uri_free(URI *uri) {
1287 uri_clean(uri);
1288 g_free(uri);
1289}
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308static int
1309normalize_uri_path(char *path) {
1310 char *cur, *out;
1311
1312 if (path == NULL)
1313 return(-1);
1314
1315
1316
1317
1318 cur = path;
1319 while (cur[0] == '/')
1320 ++cur;
1321 if (cur[0] == '\0')
1322 return(0);
1323
1324
1325 out = cur;
1326
1327
1328
1329
1330 while (cur[0] != '\0') {
1331
1332
1333
1334
1335 if ((cur[0] == '.') && (cur[1] == '/')) {
1336 cur += 2;
1337
1338 while (cur[0] == '/')
1339 cur++;
1340 continue;
1341 }
1342
1343
1344
1345
1346
1347 if ((cur[0] == '.') && (cur[1] == '\0'))
1348 break;
1349
1350
1351 while (cur[0] != '/') {
1352 if (cur[0] == '\0')
1353 goto done_cd;
1354 (out++)[0] = (cur++)[0];
1355 }
1356
1357 while ((cur[0] == '/') && (cur[1] == '/'))
1358 cur++;
1359
1360 (out++)[0] = (cur++)[0];
1361 }
1362 done_cd:
1363 out[0] = '\0';
1364
1365
1366 cur = path;
1367 while (cur[0] == '/')
1368 ++cur;
1369 if (cur[0] == '\0')
1370 return(0);
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390 while (1) {
1391 char *segp, *tmp;
1392
1393
1394
1395
1396
1397
1398 segp = cur;
1399 while ((segp[0] != '/') && (segp[0] != '\0'))
1400 ++segp;
1401
1402
1403
1404
1405 if (segp[0] == '\0')
1406 break;
1407
1408
1409
1410
1411 ++segp;
1412 if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
1413 || ((segp[0] != '.') || (segp[1] != '.')
1414 || ((segp[2] != '/') && (segp[2] != '\0')))) {
1415 cur = segp;
1416 continue;
1417 }
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427 if (segp[2] == '\0') {
1428 cur[0] = '\0';
1429 break;
1430 }
1431
1432
1433 tmp = cur;
1434 segp += 3;
1435 while ((*tmp++ = *segp++) != 0)
1436 ;
1437
1438
1439 segp = cur;
1440 while ((segp > path) && ((--segp)[0] == '/'))
1441 ;
1442 if (segp == path)
1443 continue;
1444
1445
1446
1447
1448
1449
1450
1451
1452 cur = segp;
1453 while ((cur > path) && (cur[-1] != '/'))
1454 --cur;
1455 }
1456 out[0] = '\0';
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469 if (path[0] == '/') {
1470 cur = path;
1471 while ((cur[0] == '/') && (cur[1] == '.') && (cur[2] == '.')
1472 && ((cur[3] == '/') || (cur[3] == '\0')))
1473 cur += 3;
1474
1475 if (cur != path) {
1476 out = path;
1477 while (cur[0] != '\0')
1478 (out++)[0] = (cur++)[0];
1479 out[0] = 0;
1480 }
1481 }
1482
1483 return(0);
1484}
1485
1486static int is_hex(char c) {
1487 if (((c >= '0') && (c <= '9')) ||
1488 ((c >= 'a') && (c <= 'f')) ||
1489 ((c >= 'A') && (c <= 'F')))
1490 return(1);
1491 return(0);
1492}
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509char *
1510uri_string_unescape(const char *str, int len, char *target) {
1511 char *ret, *out;
1512 const char *in;
1513
1514 if (str == NULL)
1515 return(NULL);
1516 if (len <= 0) len = strlen(str);
1517 if (len < 0) return(NULL);
1518
1519 if (target == NULL) {
1520 ret = g_malloc(len + 1);
1521 } else
1522 ret = target;
1523 in = str;
1524 out = ret;
1525 while(len > 0) {
1526 if ((len > 2) && (*in == '%') && (is_hex(in[1])) && (is_hex(in[2]))) {
1527 in++;
1528 if ((*in >= '0') && (*in <= '9'))
1529 *out = (*in - '0');
1530 else if ((*in >= 'a') && (*in <= 'f'))
1531 *out = (*in - 'a') + 10;
1532 else if ((*in >= 'A') && (*in <= 'F'))
1533 *out = (*in - 'A') + 10;
1534 in++;
1535 if ((*in >= '0') && (*in <= '9'))
1536 *out = *out * 16 + (*in - '0');
1537 else if ((*in >= 'a') && (*in <= 'f'))
1538 *out = *out * 16 + (*in - 'a') + 10;
1539 else if ((*in >= 'A') && (*in <= 'F'))
1540 *out = *out * 16 + (*in - 'A') + 10;
1541 in++;
1542 len -= 3;
1543 out++;
1544 } else {
1545 *out++ = *in++;
1546 len--;
1547 }
1548 }
1549 *out = 0;
1550 return(ret);
1551}
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563char *
1564uri_string_escape(const char *str, const char *list) {
1565 char *ret, ch;
1566 char *temp;
1567 const char *in;
1568 int len, out;
1569
1570 if (str == NULL)
1571 return(NULL);
1572 if (str[0] == 0)
1573 return(g_strdup(str));
1574 len = strlen(str);
1575 if (!(len > 0)) return(NULL);
1576
1577 len += 20;
1578 ret = g_malloc(len);
1579 in = str;
1580 out = 0;
1581 while(*in != 0) {
1582 if (len - out <= 3) {
1583 temp = realloc2n(ret, &len);
1584 ret = temp;
1585 }
1586
1587 ch = *in;
1588
1589 if ((ch != '@') && (!IS_UNRESERVED(ch)) && (!strchr(list, ch))) {
1590 unsigned char val;
1591 ret[out++] = '%';
1592 val = ch >> 4;
1593 if (val <= 9)
1594 ret[out++] = '0' + val;
1595 else
1596 ret[out++] = 'A' + val - 0xA;
1597 val = ch & 0xF;
1598 if (val <= 9)
1599 ret[out++] = '0' + val;
1600 else
1601 ret[out++] = 'A' + val - 0xA;
1602 in++;
1603 } else {
1604 ret[out++] = *in++;
1605 }
1606
1607 }
1608 ret[out] = 0;
1609 return(ret);
1610}
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633char *
1634uri_resolve(const char *uri, const char *base) {
1635 char *val = NULL;
1636 int ret, len, indx, cur, out;
1637 URI *ref = NULL;
1638 URI *bas = NULL;
1639 URI *res = NULL;
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649 if (uri == NULL)
1650 ret = -1;
1651 else {
1652 if (*uri) {
1653 ref = uri_new();
1654 ret = uri_parse_into(ref, uri);
1655 }
1656 else
1657 ret = 0;
1658 }
1659 if (ret != 0)
1660 goto done;
1661 if ((ref != NULL) && (ref->scheme != NULL)) {
1662
1663
1664
1665 val = g_strdup(uri);
1666 goto done;
1667 }
1668 if (base == NULL)
1669 ret = -1;
1670 else {
1671 bas = uri_new();
1672 ret = uri_parse_into(bas, base);
1673 }
1674 if (ret != 0) {
1675 if (ref)
1676 val = uri_to_string(ref);
1677 goto done;
1678 }
1679 if (ref == NULL) {
1680
1681
1682
1683 g_free(bas->fragment);
1684 bas->fragment = NULL;
1685 val = uri_to_string(bas);
1686 goto done;
1687 }
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701 res = uri_new();
1702 if ((ref->scheme == NULL) && (ref->path == NULL) &&
1703 ((ref->authority == NULL) && (ref->server == NULL))) {
1704 res->scheme = g_strdup(bas->scheme);
1705 if (bas->authority != NULL)
1706 res->authority = g_strdup(bas->authority);
1707 else if (bas->server != NULL) {
1708 res->server = g_strdup(bas->server);
1709 res->user = g_strdup(bas->user);
1710 res->port = bas->port;
1711 }
1712 res->path = g_strdup(bas->path);
1713 if (ref->query != NULL) {
1714 res->query = g_strdup (ref->query);
1715 } else {
1716 res->query = g_strdup(bas->query);
1717 }
1718 res->fragment = g_strdup(ref->fragment);
1719 goto step_7;
1720 }
1721
1722
1723
1724
1725
1726
1727
1728 if (ref->scheme != NULL) {
1729 val = uri_to_string(ref);
1730 goto done;
1731 }
1732 res->scheme = g_strdup(bas->scheme);
1733
1734 res->query = g_strdup(ref->query);
1735 res->fragment = g_strdup(ref->fragment);
1736
1737
1738
1739
1740
1741
1742
1743
1744 if ((ref->authority != NULL) || (ref->server != NULL)) {
1745 if (ref->authority != NULL)
1746 res->authority = g_strdup(ref->authority);
1747 else {
1748 res->server = g_strdup(ref->server);
1749 res->user = g_strdup(ref->user);
1750 res->port = ref->port;
1751 }
1752 res->path = g_strdup(ref->path);
1753 goto step_7;
1754 }
1755 if (bas->authority != NULL)
1756 res->authority = g_strdup(bas->authority);
1757 else if (bas->server != NULL) {
1758 res->server = g_strdup(bas->server);
1759 res->user = g_strdup(bas->user);
1760 res->port = bas->port;
1761 }
1762
1763
1764
1765
1766
1767 if ((ref->path != NULL) && (ref->path[0] == '/')) {
1768 res->path = g_strdup(ref->path);
1769 goto step_7;
1770 }
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781 len = 2;
1782 if (ref->path != NULL)
1783 len += strlen(ref->path);
1784 if (bas->path != NULL)
1785 len += strlen(bas->path);
1786 res->path = g_malloc(len);
1787 res->path[0] = 0;
1788
1789
1790
1791
1792
1793
1794 cur = 0;
1795 out = 0;
1796 if (bas->path != NULL) {
1797 while (bas->path[cur] != 0) {
1798 while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
1799 cur++;
1800 if (bas->path[cur] == 0)
1801 break;
1802
1803 cur++;
1804 while (out < cur) {
1805 res->path[out] = bas->path[out];
1806 out++;
1807 }
1808 }
1809 }
1810 res->path[out] = 0;
1811
1812
1813
1814
1815
1816 if (ref->path != NULL && ref->path[0] != 0) {
1817 indx = 0;
1818
1819
1820
1821 if ((out == 0) && (bas->server != NULL))
1822 res->path[out++] = '/';
1823 while (ref->path[indx] != 0) {
1824 res->path[out++] = ref->path[indx++];
1825 }
1826 }
1827 res->path[out] = 0;
1828
1829
1830
1831
1832 normalize_uri_path(res->path);
1833
1834step_7:
1835
1836
1837
1838
1839
1840
1841 val = uri_to_string(res);
1842
1843done:
1844 if (ref != NULL)
1845 uri_free(ref);
1846 if (bas != NULL)
1847 uri_free(bas);
1848 if (res != NULL)
1849 uri_free(res);
1850 return(val);
1851}
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885char *
1886uri_resolve_relative (const char *uri, const char * base)
1887{
1888 char *val = NULL;
1889 int ret;
1890 int ix;
1891 int pos = 0;
1892 int nbslash = 0;
1893 int len;
1894 URI *ref = NULL;
1895 URI *bas = NULL;
1896 char *bptr, *uptr, *vptr;
1897 int remove_path = 0;
1898
1899 if ((uri == NULL) || (*uri == 0))
1900 return NULL;
1901
1902
1903
1904
1905 ref = uri_new ();
1906
1907 if (uri[0] != '.') {
1908 ret = uri_parse_into (ref, uri);
1909 if (ret != 0)
1910 goto done;
1911 } else
1912 ref->path = g_strdup(uri);
1913
1914
1915
1916
1917 if ((base == NULL) || (*base == 0)) {
1918 val = g_strdup (uri);
1919 goto done;
1920 }
1921 bas = uri_new ();
1922 if (base[0] != '.') {
1923 ret = uri_parse_into (bas, base);
1924 if (ret != 0)
1925 goto done;
1926 } else
1927 bas->path = g_strdup(base);
1928
1929
1930
1931
1932
1933 if ((ref->scheme != NULL) &&
1934 ((bas->scheme == NULL) ||
1935 (strcmp (bas->scheme, ref->scheme)) ||
1936 (strcmp (bas->server, ref->server)))) {
1937 val = g_strdup (uri);
1938 goto done;
1939 }
1940 if (bas->path == ref->path ||
1941 (bas->path && ref->path && !strcmp(bas->path, ref->path))) {
1942 val = g_strdup("");
1943 goto done;
1944 }
1945 if (bas->path == NULL) {
1946 val = g_strdup(ref->path);
1947 goto done;
1948 }
1949 if (ref->path == NULL) {
1950 ref->path = (char *) "/";
1951 remove_path = 1;
1952 }
1953
1954
1955
1956
1957
1958
1959
1960 if (bas->path == NULL) {
1961 if (ref->path != NULL) {
1962 uptr = ref->path;
1963 if (*uptr == '/')
1964 uptr++;
1965
1966 val = uri_string_escape(uptr, "/;&=+$,");
1967 }
1968 goto done;
1969 }
1970 bptr = bas->path;
1971 if (ref->path == NULL) {
1972 for (ix = 0; bptr[ix] != 0; ix++) {
1973 if (bptr[ix] == '/')
1974 nbslash++;
1975 }
1976 uptr = NULL;
1977 len = 1;
1978 } else {
1979
1980
1981
1982 if ((ref->path[pos] == '.') && (ref->path[pos+1] == '/'))
1983 pos += 2;
1984 if ((*bptr == '.') && (bptr[1] == '/'))
1985 bptr += 2;
1986 else if ((*bptr == '/') && (ref->path[pos] != '/'))
1987 bptr++;
1988 while ((bptr[pos] == ref->path[pos]) && (bptr[pos] != 0))
1989 pos++;
1990
1991 if (bptr[pos] == ref->path[pos]) {
1992 val = g_strdup("");
1993 goto done;
1994 }
1995
1996
1997
1998
1999
2000 ix = pos;
2001 if ((ref->path[ix] == '/') && (ix > 0))
2002 ix--;
2003 else if ((ref->path[ix] == 0) && (ix > 1) && (ref->path[ix - 1] == '/'))
2004 ix -= 2;
2005 for (; ix > 0; ix--) {
2006 if (ref->path[ix] == '/')
2007 break;
2008 }
2009 if (ix == 0) {
2010 uptr = ref->path;
2011 } else {
2012 ix++;
2013 uptr = &ref->path[ix];
2014 }
2015
2016
2017
2018
2019 if (bptr[pos] != ref->path[pos]) {
2020 for (; bptr[ix] != 0; ix++) {
2021 if (bptr[ix] == '/')
2022 nbslash++;
2023 }
2024 }
2025 len = strlen (uptr) + 1;
2026 }
2027
2028 if (nbslash == 0) {
2029 if (uptr != NULL)
2030
2031 val = uri_string_escape(uptr, "/;&=+$,");
2032 goto done;
2033 }
2034
2035
2036
2037
2038
2039
2040 val = g_malloc (len + 3 * nbslash);
2041 vptr = val;
2042
2043
2044
2045 for (; nbslash>0; nbslash--) {
2046 *vptr++ = '.';
2047 *vptr++ = '.';
2048 *vptr++ = '/';
2049 }
2050
2051
2052
2053 if (uptr != NULL) {
2054 if ((vptr > val) && (len > 0) &&
2055 (uptr[0] == '/') && (vptr[-1] == '/')) {
2056 memcpy (vptr, uptr + 1, len - 1);
2057 vptr[len - 2] = 0;
2058 } else {
2059 memcpy (vptr, uptr, len);
2060 vptr[len - 1] = 0;
2061 }
2062 } else {
2063 vptr[len - 1] = 0;
2064 }
2065
2066
2067 vptr = val;
2068
2069 val = uri_string_escape(vptr, "/;&=+$,");
2070 g_free(vptr);
2071
2072done:
2073
2074
2075
2076 if (remove_path != 0)
2077 ref->path = NULL;
2078 if (ref != NULL)
2079 uri_free (ref);
2080 if (bas != NULL)
2081 uri_free (bas);
2082
2083 return val;
2084}
2085
2086
2087
2088
2089
2090struct QueryParams *
2091query_params_new (int init_alloc)
2092{
2093 struct QueryParams *ps;
2094
2095 if (init_alloc <= 0) init_alloc = 1;
2096
2097 ps = g_new(QueryParams, 1);
2098 ps->n = 0;
2099 ps->alloc = init_alloc;
2100 ps->p = g_new(QueryParam, ps->alloc);
2101
2102 return ps;
2103}
2104
2105
2106
2107
2108static int
2109query_params_append (struct QueryParams *ps,
2110 const char *name, const char *value)
2111{
2112 if (ps->n >= ps->alloc) {
2113 ps->p = g_renew(QueryParam, ps->p, ps->alloc * 2);
2114 ps->alloc *= 2;
2115 }
2116
2117 ps->p[ps->n].name = g_strdup(name);
2118 ps->p[ps->n].value = g_strdup(value);
2119 ps->p[ps->n].ignore = 0;
2120 ps->n++;
2121
2122 return 0;
2123}
2124
2125void
2126query_params_free (struct QueryParams *ps)
2127{
2128 int i;
2129
2130 for (i = 0; i < ps->n; ++i) {
2131 g_free (ps->p[i].name);
2132 g_free (ps->p[i].value);
2133 }
2134 g_free (ps->p);
2135 g_free (ps);
2136}
2137
2138struct QueryParams *
2139query_params_parse (const char *query)
2140{
2141 struct QueryParams *ps;
2142 const char *end, *eq;
2143
2144 ps = query_params_new (0);
2145 if (!query || query[0] == '\0') return ps;
2146
2147 while (*query) {
2148 char *name = NULL, *value = NULL;
2149
2150
2151 end = strchr (query, '&');
2152 if (!end)
2153 end = strchr (query, ';');
2154 if (!end)
2155 end = query + strlen (query);
2156
2157
2158 eq = strchr (query, '=');
2159 if (eq && eq >= end) eq = NULL;
2160
2161
2162 if (end == query)
2163 goto next;
2164
2165
2166
2167
2168 else if (!eq) {
2169 name = uri_string_unescape (query, end - query, NULL);
2170 value = NULL;
2171 }
2172
2173
2174
2175 else if (eq+1 == end) {
2176 name = uri_string_unescape (query, eq - query, NULL);
2177 value = g_new0(char, 1);
2178 }
2179
2180
2181
2182 else if (query == eq)
2183 goto next;
2184
2185
2186 else {
2187 name = uri_string_unescape (query, eq - query, NULL);
2188 value = uri_string_unescape (eq+1, end - (eq+1), NULL);
2189 }
2190
2191
2192 query_params_append (ps, name, value);
2193 g_free(name);
2194 g_free(value);
2195
2196 next:
2197 query = end;
2198 if (*query) query ++;
2199 }
2200
2201 return ps;
2202}
2203