]> pd.if.org Git - zpackage/blob - crypto/rfc3986.re
add option to determine name from url
[zpackage] / crypto / rfc3986.re
1 #define _POSIX_C_SOURCE 200809L
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6
7 /*!max:re2c*/
8
9 struct input {
10         /*!stags:re2c format = "const char *@@;\n"; */
11 };
12
13 static void init_input(struct input *in) {
14         /*!stags:re2c format = "in->@@ = 0;\n"; */
15 }
16
17 struct tls_uri {
18         char *scheme;
19         char *userinfo;
20         char *host;
21         char *port;
22         char *path;
23         char *query;
24         char *fragment;
25 };
26
27 #define YYCTYPE     char
28 #define YYPEEK()    *cur
29 #define YYSKIP()    if (++cur > lim) return 3;
30 #define YYBACKUP()  mar = cur
31 #define YYRESTORE() cur = mar
32 #define YYSTAGP(p) p = cur
33 #define YYSTAGN(p) p = 0
34
35 static int parse_uri(const char *cur, struct tls_uri *uri) {
36     const char
37         *s1, *u1, *h1, *h3, *h5, *r1, *p1, *p3, *q1, *f1,
38         *s2, *u2, *h2, *h4, *h6, *r2, *p2, *p4, *q2, *f2;
39     long c;
40     const char *mar, *lim;
41         struct input inp;
42         struct input *in = &inp;
43         init_input(in);
44
45         lim = cur + strlen(cur);
46
47     c = 0;
48 loop:
49 /*!re2c
50         re2c:yyfill:enable = 0;
51     re2c:tags:expression     = "in->@@";
52
53     end = "\x00";
54     eol = "\n";
55
56     alpha       = [a-zA-Z];
57     digit       = [0-9];
58     hexdigit    = [0-9a-fA-F];
59     unreserved  = alpha | digit | [-._~];
60     pct_encoded = "%" hexdigit{2};
61     sub_delims  = [!$&'()*+,;=];
62     pchar       = unreserved | pct_encoded | sub_delims | [:@];
63
64     scheme = @s1 alpha (alpha | digit | [-+.])* @s2;
65     userinfo = @u1 (unreserved | pct_encoded | sub_delims | ":")* @u2;
66     dec_octet
67         = digit
68         | [\x31-\x39] digit
69         | "1" digit{2}
70         | "2" [\x30-\x34] digit
71         | "25" [\x30-\x35];
72     ipv4address = dec_octet "." dec_octet "." dec_octet "." dec_octet;
73     h16         = hexdigit{1,4};
74     ls32        = h16 ":" h16 | ipv4address;
75     ipv6address
76         =                            (h16 ":"){6} ls32
77         |                       "::" (h16 ":"){5} ls32
78         | (               h16)? "::" (h16 ":"){4} ls32
79         | ((h16 ":"){0,1} h16)? "::" (h16 ":"){3} ls32
80         | ((h16 ":"){0,2} h16)? "::" (h16 ":"){2} ls32
81         | ((h16 ":"){0,3} h16)? "::"  h16 ":"     ls32
82         | ((h16 ":"){0,4} h16)? "::"              ls32
83         | ((h16 ":"){0,5} h16)? "::"              h16
84         | ((h16 ":"){0,6} h16)? "::";
85     ipvfuture   = "v" hexdigit+ "." (unreserved | sub_delims | ":" )+;
86     ip_literal  = "[" ( ipv6address | ipvfuture ) "]";
87     reg_name    = (unreserved | pct_encoded | sub_delims)*;
88     host
89         = @h1 ip_literal  @h2
90         | @h3 ipv4address @h4
91         | @h5 reg_name    @h6;
92     port      = @r1 digit* @r2;
93     authority = (userinfo "@")? host (":" port)?;
94     path_abempty  = ("/" pchar*)*;
95     path_absolute = "/" (pchar+ ("/" pchar*)*)?;
96     path_rootless = pchar+ ("/" pchar*)*;
97     path_empty    = "";
98     hier_part
99         = "//" authority @p1 path_abempty @p2
100         | @p3 (path_absolute | path_rootless | path_empty) @p4;
101     query    = @q1 (pchar | [/?])* @q2;
102     fragment = @f1 (pchar | [/?])* @f2;
103     uri = scheme ":" hier_part ("?" query)? ("#" fragment)?;
104
105     *   { return 1; }
106     end { return 0; }
107     eol { goto loop; }
108     uri {
109         uri->scheme = strndup(s1, (size_t)(s2 - s1));
110         if (u1) uri->userinfo = strndup(u1, (size_t)(u2 - u1));
111         if (h1) uri->host = strndup(h1, (size_t)(h2 - h1));
112         if (h3) uri->host = strndup(h3, (size_t)(h4 - h3));
113         if (h5) uri->host = strndup(h5, (size_t)(h6 - h5));
114         if (r1) uri->port = strndup(r1, (size_t)(r2 - r1));
115         if (p1) uri->path = strndup(p1, (size_t)(p2 - p1));
116         if (p3) uri->path = strndup(p3, (size_t)(p4 - p3));
117         if (q1) uri->query = strndup(q1, (size_t)(q2 - q1));
118         if (f1) uri->fragment = strndup(f1, (size_t)(f2 - f1));
119
120         return 0;
121     }
122 */
123 }
124
125 static int hex(char *s) {
126         int r = 0;
127         int i;
128         for (i = 0; i < 2; i++) {
129                 r *= 16;
130                 switch (s[i]) {
131                         case '0': break;
132                         case '1': r += 1; break;
133                         case '2': r += 2; break;
134                         case '3': r += 3; break;
135                         case '4': r += 4; break;
136                         case '5': r += 5; break;
137                         case '6': r += 6; break;
138                         case '7': r += 7; break;
139                         case '8': r += 8; break;
140                         case '9': r += 9; break;
141                         case 'A':
142                         case 'a': r += 11; break;
143                         case 'B':
144                         case 'b': r += 11; break;
145                         case 'C':
146                         case 'c': r += 12; break;
147                         case 'D':
148                         case 'd': r += 13; break;
149                         case 'E':
150                         case 'e': r += 14; break;
151                         case 'F':
152                         case 'f': r += 15; break;
153                         default:
154                                 /* This is an error, but should have
155                                 been caught at the lexing stage */
156                                 break;
157                 }
158         }
159         return r;
160 }
161
162 static void percent_decode(char *s) {
163         char *d = s;
164
165         if (!s) {
166                 return;
167         }
168
169         while (*s) {
170                 switch (*s) {
171                         case '%':
172                                 if (*(s+1) && *(s+2)) {
173                                         *d++ = hex(s+1);
174                                         s += 3;
175                                 }
176                                 break;
177                         default:
178                                 *d++ = *s++;
179                                 break;
180                 }
181         }
182         *d = 0;
183 }
184
185 int tls_parse_uri(char *s, struct tls_uri *uri) {
186         int rv;
187
188         rv = parse_uri(s, uri);
189         if (rv != 0) {
190                 return rv;
191         }
192
193         if (uri->port == NULL) {
194                 if (!strcmp(uri->scheme, "http")) {
195                         uri->port = strdup("80");
196                 } else if (!strcmp(uri->scheme, "https")) {
197                         uri->port = strdup("443");
198                 } else if (!strcmp(uri->scheme, "ftp")) {
199                         uri->port = strdup("21");
200                 } else {
201                         uri->port = strdup("0");
202                 }
203         }
204
205         percent_decode(uri->host);
206         percent_decode(uri->path);
207         percent_decode(uri->query);
208
209         
210         if (uri->path == NULL || uri->path[0] == 0) {
211                 free(uri->path);
212                 uri->path = strdup("/");
213         }
214
215         return rv;
216 }
217
218 void tls_free_uri(struct tls_uri *uri) {
219         free(uri->host);
220         free(uri->path);
221         free(uri->query);
222         free(uri->port);
223         free(uri->scheme);
224 }