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