/src/dovecot/src/lib-url/uri-util.h
Line | Count | Source |
1 | | #ifndef URI_UTIL_H |
2 | | #define URI_UTIL_H |
3 | | |
4 | | #include "net.h" |
5 | | |
6 | | /* |
7 | | * Generic URI parsing. |
8 | | */ |
9 | | |
10 | | enum uri_parse_flags { |
11 | | /* Scheme part 'scheme:' is already parsed externally. */ |
12 | | URI_PARSE_SCHEME_EXTERNAL = BIT(0), |
13 | | /* Allow '#fragment' part in URI */ |
14 | | URI_PARSE_ALLOW_FRAGMENT_PART = BIT(1), |
15 | | /* Allow ';param' after host - violates RFC3986 */ |
16 | | URI_PARSE_SEMICOLON_PARAMS = BIT(2), |
17 | | /* Allow scheme:host - violates RFC3986 */ |
18 | | URI_PARSE_ALLOW_MISSING_SLASHSLASH = BIT(3), |
19 | | }; |
20 | | |
21 | | struct uri_host { |
22 | | const char *name; |
23 | | struct ip_addr ip; |
24 | | }; |
25 | | |
26 | | struct uri_authority { |
27 | | /* encoded userinfo part; e.g. "user:pass" */ |
28 | | const char *enc_userinfo; |
29 | | |
30 | | struct uri_host host; |
31 | | in_port_t port; /* 0 means no port specified */ |
32 | | }; |
33 | | |
34 | | struct uri_parser { |
35 | | pool_t pool; |
36 | | const char *error; |
37 | | |
38 | | const unsigned char *begin, *cur, *end; |
39 | | |
40 | | string_t *tmpbuf; |
41 | | |
42 | | bool allow_pct_nul:1; |
43 | | bool parse_prefix:1; |
44 | | bool semicolon_params:1; |
45 | | }; |
46 | | |
47 | | static inline const char *uri_char_sanitize(unsigned char c) |
48 | 54.6k | { |
49 | 54.6k | if (c >= 0x20 && c < 0x7F) |
50 | 43.3k | return t_strdup_printf("'%c'", c); |
51 | 11.3k | return t_strdup_printf("<0x%02x>", c); |
52 | 54.6k | } Unexecuted instantiation: ext-extlists-settings.c:uri_char_sanitize Unexecuted instantiation: urn.c:uri_char_sanitize Unexecuted instantiation: mail-storage-settings.c:uri_char_sanitize Unexecuted instantiation: settings-parser.c:uri_char_sanitize Unexecuted instantiation: http-url.c:uri_char_sanitize uri-util.c:uri_char_sanitize Line | Count | Source | 48 | 54.6k | { | 49 | 54.6k | if (c >= 0x20 && c < 0x7F) | 50 | 43.3k | return t_strdup_printf("'%c'", c); | 51 | 11.3k | return t_strdup_printf("<0x%02x>", c); | 52 | 54.6k | } |
Unexecuted instantiation: fuzz-http-url.c:uri_char_sanitize Unexecuted instantiation: sasl-server-mech-oauth2.c:uri_char_sanitize Unexecuted instantiation: oauth2.c:uri_char_sanitize Unexecuted instantiation: http-parser.c:uri_char_sanitize Unexecuted instantiation: json-pointer.c:uri_char_sanitize Unexecuted instantiation: fuzz-uri-util.c:uri_char_sanitize Unexecuted instantiation: fuzz-http-request-parser.c:uri_char_sanitize Unexecuted instantiation: http-request-parser.c:uri_char_sanitize http-request.c:uri_char_sanitize Line | Count | Source | 48 | 9 | { | 49 | 9 | if (c >= 0x20 && c < 0x7F) | 50 | 9 | return t_strdup_printf("'%c'", c); | 51 | 0 | return t_strdup_printf("<0x%02x>", c); | 52 | 9 | } |
|
53 | | |
54 | | /* Parse one instance of percent encoding. Returns 1 for success, 0 if none is |
55 | | present at the current parser position, and -1 in case of error. The decoded |
56 | | character is returned in ch_r upon success. */ |
57 | | int uri_parse_pct_encoded(struct uri_parser *parser, unsigned char *ch_r); |
58 | | |
59 | | /* Parse characters as long as these comply with the 'unreserved' syntax. |
60 | | Returns 1 if characters were found, 0 if none were found, and -1 if there was |
61 | | an error. */ |
62 | | int uri_parse_unreserved(struct uri_parser *parser, string_t *part); |
63 | | /* The same as uri_parse_unreserved(), but the allowed characters are extended |
64 | | to 'unreserved / pct-encoded', meaning that percent encoding is allowed. */ |
65 | | int uri_parse_unreserved_pct(struct uri_parser *parser, string_t *part); |
66 | | |
67 | | /* Decode percent-encoded data from the 'data' parameter, up until the 'until' |
68 | | parameter. If the latter is NULL, data is decoded up until the '\0' |
69 | | character. The decoded data is allocated on the parser pool and returned in |
70 | | decoded_r. Any errors are written to the parser object. */ |
71 | | bool uri_data_decode(struct uri_parser *parser, const char *data, |
72 | | const char *until, const char **decoded_r) ATTR_NULL(3); |
73 | | |
74 | | /* Cut the 'scheme ":"' part from the URI. The uri_p pointer is updated to point |
75 | | just past the ":". Returns 0 on success and -1 on error. The result is |
76 | | returned in the scheme_r parameter. This can be NULL to use this function for |
77 | | merely checking the presence of a valid scheme. */ |
78 | | int uri_cut_scheme(const char **uri_p, const char **scheme_r) ATTR_NULL(2); |
79 | | |
80 | | /* Parse the URI 'scheme ":"' part. Returns 1 if successful, 0 if the first |
81 | | character is not valid for a scheme, and -1 in case of error. The result |
82 | | parameter scheme_r can be NULL to use this function for merely checking the |
83 | | presence of a valid scheme. */ |
84 | | int uri_parse_scheme(struct uri_parser *parser, const char **scheme_r) |
85 | | ATTR_NULL(2); |
86 | | |
87 | | /* Parse the URI 'reg-name' syntax. Returns 1 if successful, 0 if the first |
88 | | character is not valid for a host name, and -1 in case of error. The result |
89 | | parameter reg_name_r can be NULL to use this function for merely checking the |
90 | | presence of a valid host name. The result is allocated from the data stack. |
91 | | */ |
92 | | int uri_parse_reg_name(struct uri_parser *parser, const char **reg_name_r) |
93 | | ATTR_NULL(2); |
94 | | /* Parse the URI 'reg-name' part as an Internet host name, which is a sequence |
95 | | of domain name labels separated by '.', as defined in Section 3.5 of RFC 1034 |
96 | | and Section 2.1 of RFC 1123. Returns 1 if successful, 0 if the first |
97 | | character is not valid for a host name, and -1 in case of error. The result |
98 | | parameter host_name_r can be NULL to use this function for merely checking |
99 | | the presence of a valid host name. The result is allocated from the data |
100 | | stack. |
101 | | */ |
102 | | int uri_parse_host_name(struct uri_parser *parser, const char **host_name_r) |
103 | | ATTR_NULL(2); |
104 | | /* Parse the URI 'host' syntax, which is either an IP address literal or a an |
105 | | Internet host name, as defined in Section 3.5 of RFC 1034 and Section 2.1 of |
106 | | RFC 1123. An IP address literal is always allowed. Returns 1 if successful, 0 |
107 | | if the first character is not valid for a host name, and -1 in case of error. |
108 | | The provided host struct is filled in with the parsed data, all allocated |
109 | | from the parser pool. The host parameter can be NULL to use this function for |
110 | | merely checking for valid 'host' syntax. |
111 | | */ |
112 | | int uri_parse_host(struct uri_parser *parser, struct uri_host *host) |
113 | | ATTR_NULL(2); |
114 | | |
115 | | /* Parse the URI 'authority' syntax. Returns 1 if successful, 0 if the first |
116 | | character is not valid for the 'authority' syntax and -1 in case of error. |
117 | | The provided uri_authority struct is filled in with the parsed data, all |
118 | | allocated from the parser pool. The auth parameter can be NULL to use this |
119 | | function for merely checking for valid 'authority' syntax. |
120 | | */ |
121 | | int uri_parse_authority(struct uri_parser *parser, struct uri_authority *auth) |
122 | | ATTR_NULL(2); |
123 | | /* Identical to uri_parse_authority(), except that this function parses |
124 | | '"//" authority', rather than 'authority'. |
125 | | */ |
126 | | int uri_parse_slashslash_authority(struct uri_parser *parser, |
127 | | struct uri_authority *auth) ATTR_NULL(2); |
128 | | /* Identical to uri_parse_authority(), except that this function parses the |
129 | | registered name ('reg-name' syntax) as an Internet host name, as defined in |
130 | | Section 3.5 of RFC 1034 and Section 2.1 of RFC 1123. |
131 | | */ |
132 | | int uri_parse_host_authority(struct uri_parser *parser, |
133 | | struct uri_authority *auth) ATTR_NULL(2); |
134 | | /* Identical to uri_parse_slashslash_authority(), except that this function |
135 | | parses the registered name ('reg-name' syntax) as an Internet host name, as |
136 | | defined in Section 3.5 of RFC 1034 and Section 2.1 of RFC 1123. |
137 | | */ |
138 | | int uri_parse_slashslash_host_authority(struct uri_parser *parser, |
139 | | struct uri_authority *auth) |
140 | | ATTR_NULL(2); |
141 | | |
142 | | /* Parse the URI 'segment' syntax. Returns 1 if successful, 0 if the first |
143 | | character is not valid for the 'segment' syntax and -1 in case of error. The |
144 | | result is allocated from the parser pool. Percent encoding is not decoded in |
145 | | the result. The result parameter can be NULL to use this function for merely |
146 | | checking for valid 'segment' syntax. |
147 | | */ |
148 | | int uri_parse_path_segment(struct uri_parser *parser, const char **segment_r) |
149 | | ATTR_NULL(2); |
150 | | /* Parse the URI 'path' syntax. This also resolves '..' and '.' segments in the |
151 | | path. If the path is relative, the relative_r parameter indicates how many |
152 | | segments the base path must be moved towards root (as caused by leading '..' |
153 | | segments). Returns 1 if successful, 0 if the first character is not valid for |
154 | | the 'segment' syntax and -1 in case of error. The result is a NULL-terminated |
155 | | string list allocated from the parser pool. Percent encoding is not decoded |
156 | | in the result. The result parameter can be NULL to use this function for |
157 | | merely checking for valid 'path' syntax. |
158 | | */ |
159 | | int uri_parse_path(struct uri_parser *parser, int *relative_r, |
160 | | const char *const **path_r) ATTR_NULL(2,3); |
161 | | |
162 | | /* Parse the URI 'query' syntax. Returns 1 if successful, 0 if the first |
163 | | character is not valid for the 'query' syntax and -1 in case of error. The |
164 | | result is allocated from the parser pool. Percent encoding is not decoded in |
165 | | the result. The result parameter can be NULL to use this function for merely |
166 | | checking for valid 'query' syntax. |
167 | | */ |
168 | | int uri_parse_query(struct uri_parser *parser, const char **query_r) |
169 | | ATTR_NULL(2); |
170 | | /* Parse the URI 'fragment' syntax. Returns 1 if successful, 0 if the first |
171 | | character is not valid for the 'fragment' syntax and -1 in case of error. The |
172 | | result is allocated from the parser pool. Percent encoding is not decoded in |
173 | | the result. The result parameter can be NULL to use this function for merely |
174 | | checking for valid 'fragment' syntax. |
175 | | */ |
176 | | int uri_parse_fragment(struct uri_parser *parser, const char **fragment_r) |
177 | | ATTR_NULL(2); |
178 | | |
179 | | /* Initialize the URI parser with the provided data */ |
180 | | void uri_parser_init_data(struct uri_parser *parser, pool_t pool, |
181 | | const unsigned char *data, size_t size); |
182 | | /* Initialize the URI parser with the provided '\0'-terminated string */ |
183 | | void uri_parser_init(struct uri_parser *parser, pool_t pool, const char *uri); |
184 | | |
185 | | /* Returns the temporary buffer associated with this parser. Can be used |
186 | | for higher-level parsing activities. */ |
187 | | string_t *uri_parser_get_tmpbuf(struct uri_parser *parser, size_t size); |
188 | | |
189 | | /* Parse a generic (RFC3986) absolute URI for validity. |
190 | | Returns 0 if valid and -1 otherwise. Note that some URI formats like |
191 | | "sip", "aix" and "aaa" violate RFC3986 and will currently fail with |
192 | | this function. |
193 | | */ |
194 | | int uri_parse_absolute_generic(struct uri_parser *parser, |
195 | | enum uri_parse_flags flags); |
196 | | |
197 | | /* |
198 | | * Generic URI manipulation |
199 | | */ |
200 | | |
201 | | /* Copy uri_host struct from src to dest and allocate it on pool */ |
202 | | void uri_host_copy(pool_t pool, struct uri_host *dest, |
203 | | const struct uri_host *src); |
204 | | |
205 | | /* |
206 | | * Generic URI validation |
207 | | */ |
208 | | |
209 | | /* Check whether the provided data is a valid absolute RFC3986 URI. Returns 0 if |
210 | | valid and -1 otherwise. */ |
211 | | int uri_check_data(const unsigned char *data, size_t size, |
212 | | enum uri_parse_flags flags, const char **error_r); |
213 | | /* Check whether the provided string is a valid absolute RFC3986 URI. Returns 0 |
214 | | if valid and -1 otherwise. */ |
215 | | int uri_check(const char *uri, enum uri_parse_flags, const char **error_r); |
216 | | |
217 | | /* |
218 | | * Generic URI construction |
219 | | */ |
220 | | |
221 | | /* Encodes the '\0'-terminated data using the percent encoding. The esc_table is |
222 | | a 256 byte lookup table. If none of the esc_mask bits are set at the |
223 | | character's position in the esc_table, a character needs to be encoded. Also, |
224 | | when esc_extra contains a character, it needs to be encoded. All other |
225 | | characters are copied verbatim to the out buffer. |
226 | | */ |
227 | | void uri_data_encode(string_t *out, const unsigned char esc_table[256], |
228 | | unsigned char esc_mask, const char *esc_extra, |
229 | | const char *data) ATTR_NULL(4); |
230 | | |
231 | | /* Append the provided scheme to the out buffer */ |
232 | | void uri_append_scheme(string_t *out, const char *scheme); |
233 | | |
234 | | /* Append partial user data (i.e. some part of what comes before '@') to the out |
235 | | buffer. No '@' is produced. Characters are percent-encoded when necessary. |
236 | | Characters in esc are always percent-encoded, even when these are valid |
237 | | 'userinfo' characters. */ |
238 | | void uri_append_user_data(string_t *out, const char *esc, const char *data) |
239 | | ATTR_NULL(2); |
240 | | /* Append userinfo and '@' to the out buffer. Characters in userinfo are |
241 | | percent-encoded when necessary. */ |
242 | | void uri_append_userinfo(string_t *out, const char *userinfo); |
243 | | |
244 | | /* Append the host name to the out buffer. Characters are percent-encoded when |
245 | | necessary.*/ |
246 | | void uri_append_host_name(string_t *out, const char *name); |
247 | | /* Append the host IP address to the out buffer. */ |
248 | | void uri_append_host_ip(string_t *out, const struct ip_addr *host_ip); |
249 | | /* Encode the URI host struct to the out buffer. */ |
250 | | void uri_append_host(string_t *out, const struct uri_host *host); |
251 | | /* Append the port to the out buffer. */ |
252 | | void uri_append_port(string_t *out, in_port_t port); |
253 | | |
254 | | /* Append partial path segment data to the out buffer. No '/' is produced. |
255 | | Characters are percent-encoded when necessary. Characters in esc are always |
256 | | percent-encoded, even when these are valid 'segment' characters. |
257 | | */ |
258 | | void uri_append_path_segment_data(string_t *out, const char *esc, |
259 | | const char *data) ATTR_NULL(2); |
260 | | /* Append a full path segment to the out buffer. A leading '/' is produced. |
261 | | Characters are percent-encoded when necessary. */ |
262 | | void uri_append_path_segment(string_t *out, const char *segment); |
263 | | /* Append partial path data to the out buffer. The data may include '/', which |
264 | | is not encoded. Characters are percent-encoded when necessary. Characters in |
265 | | esc are always percent-encoded, even when these are valid 'path' characters. |
266 | | */ |
267 | | void uri_append_path_data(string_t *out, const char *esc, const char *data) |
268 | | ATTR_NULL(2); |
269 | | /* Append a full path to the out buffer. A leading '/' is produced. The data may |
270 | | include more '/', which is not encoded. Characters are percent-encoded when |
271 | | necessary. |
272 | | */ |
273 | | void uri_append_path(string_t *out, const char *path); |
274 | | |
275 | | /* Append partial query data to the out buffer. No leading '?' is produced. |
276 | | Characters are percent-encoded when necessary. Characters in esc are always |
277 | | percent-encoded, even when these are valid 'query' characters.*/ |
278 | | void uri_append_query_data(string_t *out, const char *esc, const char *data) |
279 | | ATTR_NULL(2); |
280 | | /* Append a full URI query part to the out buffer. A leading '?' is produced. |
281 | | Characters are percent-encoded when necessary. */ |
282 | | void uri_append_query(string_t *out, const char *query); |
283 | | |
284 | | /* Append partial fragment data to the out buffer. No leading '#' is produced. |
285 | | Characters are percent-encoded when necessary. Characters in esc are always |
286 | | percent-encoded, even when these are valid 'fragment' characters.*/ |
287 | | void uri_append_fragment_data(string_t *out, const char *esc, const char *data) |
288 | | ATTR_NULL(2); |
289 | | /* Append a full URI fragment part to the out buffer. A leading '#' is produced. |
290 | | Characters are percent-encoded when necessary. */ |
291 | | void uri_append_fragment(string_t *out, const char *fragment); |
292 | | |
293 | | /* Append data to the out buffer and escape any reserved character. */ |
294 | | void uri_append_unreserved(string_t *out, const char *data); |
295 | | /* append data to the out buffer and escape any reserved character except '/'. |
296 | | */ |
297 | | void uri_append_unreserved_path(string_t *out, const char *data); |
298 | | |
299 | | #endif |