Coverage Report

Created: 2026-10-17 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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