1 #define _POSIX_C_SOURCE 200809L
10 /*!stags:re2c format = "const char *@@;\n"; */
13 static void init_input(struct input *in) {
14 /*!stags:re2c format = "in->@@ = 0;\n"; */
31 #define YYSKIP() if (++cur > lim) return 3;
32 #define YYBACKUP() mar = cur
33 #define YYRESTORE() cur = mar
34 #define YYSTAGP(p) p = cur
35 #define YYSTAGN(p) p = 0
37 static int parse_uri(const char *cur, struct tls_uri *uri) {
39 *s1, *u1, *h1, *h3, *h5, *r1, *p1, *p3, *q1, *f1,
40 *s2, *u2, *h2, *h4, *h6, *r2, *p2, *p4, *q2, *f2;
42 const char *mar, *lim;
44 struct input *in = &inp;
47 lim = cur + strlen(cur);
52 re2c:yyfill:enable = 0;
53 re2c:tags:expression = "in->@@";
60 hexdigit = [0-9a-fA-F];
61 unreserved = alpha | digit | [-._~];
62 pct_encoded = "%" hexdigit{2};
63 sub_delims = [!$&'()*+,;=];
64 pchar = unreserved | pct_encoded | sub_delims | [:@];
66 scheme = @s1 alpha (alpha | digit | [-+.])* @s2;
67 userinfo = @u1 (unreserved | pct_encoded | sub_delims | ":")* @u2;
72 | "2" [\x30-\x34] digit
74 ipv4address = dec_octet "." dec_octet "." dec_octet "." dec_octet;
76 ls32 = h16 ":" h16 | ipv4address;
79 | "::" (h16 ":"){5} ls32
80 | ( h16)? "::" (h16 ":"){4} ls32
81 | ((h16 ":"){0,1} h16)? "::" (h16 ":"){3} ls32
82 | ((h16 ":"){0,2} h16)? "::" (h16 ":"){2} ls32
83 | ((h16 ":"){0,3} h16)? "::" h16 ":" ls32
84 | ((h16 ":"){0,4} h16)? "::" ls32
85 | ((h16 ":"){0,5} h16)? "::" h16
86 | ((h16 ":"){0,6} h16)? "::";
87 ipvfuture = "v" hexdigit+ "." (unreserved | sub_delims | ":" )+;
88 ip_literal = "[" ( ipv6address | ipvfuture ) "]";
89 reg_name = (unreserved | pct_encoded | sub_delims)*;
94 port = @r1 digit* @r2;
95 authority = (userinfo "@")? host (":" port)?;
96 path_abempty = ("/" pchar*)*;
97 path_absolute = "/" (pchar+ ("/" pchar*)*)?;
98 path_rootless = pchar+ ("/" pchar*)*;
101 = "//" authority @p1 path_abempty @p2
102 | @p3 (path_absolute | path_rootless | path_empty) @p4;
103 query = @q1 (pchar | [/?])* @q2;
104 fragment = @f1 (pchar | [/?])* @f2;
105 uri = scheme ":" hier_part ("?" query)? ("#" fragment)?;
111 uri->scheme = strndup(s1, (size_t)(s2 - s1));
112 if (u1) uri->userinfo = strndup(u1, (size_t)(u2 - u1));
113 if (h1) uri->host = strndup(h1, (size_t)(h2 - h1));
114 if (h3) uri->host = strndup(h3, (size_t)(h4 - h3));
115 if (h5) uri->host = strndup(h5, (size_t)(h6 - h5));
116 if (r1) uri->port = strndup(r1, (size_t)(r2 - r1));
117 if (p1) uri->path = strndup(p1, (size_t)(p2 - p1));
118 if (p3) uri->path = strndup(p3, (size_t)(p4 - p3));
119 if (q1) uri->query = strndup(q1, (size_t)(q2 - q1));
120 if (f1) uri->fragment = strndup(f1, (size_t)(f2 - f1));
127 static int hex(char *s) {
130 for (i = 0; i < 2; i++) {
134 case '1': r += 1; break;
135 case '2': r += 2; break;
136 case '3': r += 3; break;
137 case '4': r += 4; break;
138 case '5': r += 5; break;
139 case '6': r += 6; break;
140 case '7': r += 7; break;
141 case '8': r += 8; break;
142 case '9': r += 9; break;
144 case 'a': r += 11; break;
146 case 'b': r += 11; break;
148 case 'c': r += 12; break;
150 case 'd': r += 13; break;
152 case 'e': r += 14; break;
154 case 'f': r += 15; break;
156 /* This is an error, but should have
157 been caught at the lexing stage */
164 static void percent_decode(char *s) {
174 if (*(s+1) && *(s+2)) {
187 int tls_parse_uri(char *s, struct tls_uri *uri) {
190 rv = parse_uri(s, uri);
195 if (uri->port == NULL) {
196 if (!strcmp(uri->scheme, "http")) {
197 uri->port = strdup("80");
198 } else if (!strcmp(uri->scheme, "https")) {
199 uri->port = strdup("443");
200 } else if (!strcmp(uri->scheme, "ftp")) {
201 uri->port = strdup("21");
203 uri->port = strdup("0");
208 uri->encoded_path = strdup(uri->path);
211 uri->encoded_query = strdup(uri->query);
214 percent_decode(uri->host);
215 percent_decode(uri->path);
216 percent_decode(uri->query);
218 if (uri->path == NULL || uri->path[0] == 0) {
220 uri->path = strdup("/");
226 #define MARK fprintf(stderr, "%s %s:%d\n", __FILE__, __func__, __LINE__)
227 void tls_free_uri(struct tls_uri *uri) {
242 free(uri->encoded_path);
243 uri->encoded_path = 0;
244 free(uri->encoded_query);
245 uri->encoded_query = 0;