uri-util.c revision 4e52bade0f83746405ecc1d0396e9b2ac7b98cd8
fa9e4066f08beec538e775443c5be79dd423fcabahrens/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
fa9e4066f08beec538e775443c5be79dd423fcabahrens/* [URI-GEN] RFC3986 Appendix A:
fa9e4066f08beec538e775443c5be79dd423fcabahrens URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
fa9e4066f08beec538e775443c5be79dd423fcabahrens absolute-URI = scheme ":" hier-part [ "?" query ]
fa9e4066f08beec538e775443c5be79dd423fcabahrens scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
fa9e4066f08beec538e775443c5be79dd423fcabahrens URI-reference = URI / relative-ref
fa9e4066f08beec538e775443c5be79dd423fcabahrens relative-ref = relative-part [ "?" query ] [ "#" fragment ]
fa9e4066f08beec538e775443c5be79dd423fcabahrens relative-part = "//" authority path-abempty
fa9e4066f08beec538e775443c5be79dd423fcabahrens / path-absolute
98d1cbfec254295273b6a761bc1861c0374bdf02George Wilson / path-noscheme
fa9e4066f08beec538e775443c5be79dd423fcabahrens hier-part = "//" authority path-abempty
fa9e4066f08beec538e775443c5be79dd423fcabahrens / path-absolute
fa9e4066f08beec538e775443c5be79dd423fcabahrens / path-rootless
fa9e4066f08beec538e775443c5be79dd423fcabahrens / path-empty
fa9e4066f08beec538e775443c5be79dd423fcabahrens authority = [ userinfo "@" ] host [ ":" port ]
fa9e4066f08beec538e775443c5be79dd423fcabahrens userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
fa9e4066f08beec538e775443c5be79dd423fcabahrens host = IP-literal / IPv4address / reg-name
fa9e4066f08beec538e775443c5be79dd423fcabahrens port = *DIGIT
fa9e4066f08beec538e775443c5be79dd423fcabahrens IP-literal = "[" ( IPv6address / IPvFuture ) "]"
fa9e4066f08beec538e775443c5be79dd423fcabahrens IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
fa9e4066f08beec538e775443c5be79dd423fcabahrens IPv6address = 6( h16 ":" ) ls32
fa9e4066f08beec538e775443c5be79dd423fcabahrens / "::" 5( h16 ":" ) ls32
fa9e4066f08beec538e775443c5be79dd423fcabahrens / [ h16 ] "::" 4( h16 ":" ) ls32
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson / [ *4( h16 ":" ) h16 ] "::" ls32
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson / [ *5( h16 ":" ) h16 ] "::" h16
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson / [ *6( h16 ":" ) h16 ] "::"
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson h16 = 1*4HEXDIG
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson ls32 = ( h16 ":" h16 ) / IPv4address
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson dec-octet = DIGIT ; 0-9
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson / %x31-39 DIGIT ; 10-99
dcba9f3fbefe06ad19972b4de0351924601e5767George Wilson / "1" 2DIGIT ; 100-199
fa9e4066f08beec538e775443c5be79dd423fcabahrens / "2" %x30-34 DIGIT ; 200-249
4263d13f00c9691fa14620eff82abef795be0693George Wilson / "25" %x30-35 ; 250-255
4263d13f00c9691fa14620eff82abef795be0693George Wilson reg-name = *( unreserved / pct-encoded / sub-delims )
fa9e4066f08beec538e775443c5be79dd423fcabahrens path = path-abempty ; begins with "/" or is empty
fa9e4066f08beec538e775443c5be79dd423fcabahrens / path-absolute ; begins with "/" but not "//"
e14bb3258d05c1b1077e2db7cf77088924e56919Jeff Bonwick / path-noscheme ; begins with a non-colon segment
fa9e4066f08beec538e775443c5be79dd423fcabahrens / path-rootless ; begins with a segment
fa9e4066f08beec538e775443c5be79dd423fcabahrens / path-empty ; zero characters
fa9e4066f08beec538e775443c5be79dd423fcabahrens path-abempty = *( "/" segment )
fa9e4066f08beec538e775443c5be79dd423fcabahrens path-absolute = "/" [ segment-nz *( "/" segment ) ]
fa9e4066f08beec538e775443c5be79dd423fcabahrens path-noscheme = segment-nz-nc *( "/" segment )
fa9e4066f08beec538e775443c5be79dd423fcabahrens path-rootless = segment-nz *( "/" segment )
fa9e4066f08beec538e775443c5be79dd423fcabahrens path-empty = 0<pchar>
fa9e4066f08beec538e775443c5be79dd423fcabahrens segment = *pchar
fa9e4066f08beec538e775443c5be79dd423fcabahrens segment-nz = 1*pchar
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilson segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilson ; non-zero-length segment without any colon ":"
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilson pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilson query = *( pchar / "/" / "?" )
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilson fragment = *( pchar / "/" / "?" )
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilson pct-encoded = "%" HEXDIG HEXDIG
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilson unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilson reserved = gen-delims / sub-delims
fa9e4066f08beec538e775443c5be79dd423fcabahrens gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
fa9e4066f08beec538e775443c5be79dd423fcabahrens sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
fa9e4066f08beec538e775443c5be79dd423fcabahrens / "*" / "+" / "," / ";" / "="
fa9e4066f08beec538e775443c5be79dd423fcabahrens/* Character lookup table
0a4e9518a44f226be6d39383330b5b1792d2f184gw * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" [bit0]
8ad4d6dd86f5bc65fb3afa566c8133f3bac21648Jeff Bonwick * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
fa9e4066f08beec538e775443c5be79dd423fcabahrens * / "*" / "+" / "," / ";" / "=" [bit1]
fa9e4066f08beec538e775443c5be79dd423fcabahrens * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" [bit2]
fa9e4066f08beec538e775443c5be79dd423fcabahrens * pchar = unreserved / sub-delims / ":" / "@" [bit0|bit1|bit3]
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 'pfchar' = unreserved / sub-delims / ":" / "@" / "/"
fa9e4066f08beec538e775443c5be79dd423fcabahrens * [bit0|bit1|bit3|bit5]
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 'uchar' = unreserved / sub-delims / ":" [bit0|bit1|bit4]
fa9e4066f08beec538e775443c5be79dd423fcabahrens * 'qchar' = pchar / "/" / "?" [bit0|bit1|bit3|bit5|bit6]
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define CHAR_MASK_PFCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5))
be6fd75a69ae679453d9cda5bff3326111e6d1caMatthew Ahrens#define CHAR_MASK_UCHAR ((1<<0)|(1<<1)|(1<<4))
fa9e4066f08beec538e775443c5be79dd423fcabahrens#define CHAR_MASK_QCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<6))
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilsonstatic unsigned const char _uri_char_lookup[256] = {
095bcd6622e3b3520eb3b71039a3be5cfab25b74George Wilson 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00
fa9e4066f08beec538e775443c5be79dd423fcabahrens 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10
fa9e4066f08beec538e775443c5be79dd423fcabahrens 0, 2, 0, 4, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 1, 36, // 20
fa9e4066f08beec538e775443c5be79dd423fcabahrens 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 2, 0, 2, 0, 68, // 30
fa9e4066f08beec538e775443c5be79dd423fcabahrens 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40
fa9e4066f08beec538e775443c5be79dd423fcabahrens 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60
fa9e4066f08beec538e775443c5be79dd423fcabahrens 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 70
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic inline int _decode_hex_digit(const unsigned char digit)
fa9e4066f08beec538e775443c5be79dd423fcabahrens case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
fa9e4066f08beec538e775443c5be79dd423fcabahrens case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
8ad4d6dd86f5bc65fb3afa566c8133f3bac21648Jeff Bonwickuri_parse_pct_encoded_data(struct uri_parser *parser,
8ad4d6dd86f5bc65fb3afa566c8133f3bac21648Jeff Bonwick const unsigned char **p, const unsigned char *pend,
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson if (**p == 0 || *(*p+1) == 0 || (pend != NULL && *p+1 >= pend)) {
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson parser->error = "Unexpected URI boundary after '%'";
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson "Expecting hex digit after '%%', but found '%c'", **p);
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson "Expecting hex digit after '%%%c', but found '%c'", *((*p)-1), **p);
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson "Percent encoding is not allowed to encode NUL character";
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilsonint uri_parse_pct_encoded(struct uri_parser *parser,
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson unsigned char *ch_r)
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilsonuri_parse_unreserved_char(struct uri_parser *parser, unsigned char *ch_r)
fa9e4066f08beec538e775443c5be79dd423fcabahrens if ((_uri_char_lookup[*parser->cur] & CHAR_MASK_UNRESERVED) != 0) {
be6fd75a69ae679453d9cda5bff3326111e6d1caMatthew Ahrensint uri_parse_unreserved(struct uri_parser *parser, string_t *part)
fa9e4066f08beec538e775443c5be79dd423fcabahrens unsigned char ch = 0;
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilsonint uri_parse_unreserved_pct(struct uri_parser *parser, string_t *part)
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson unsigned char ch = 0;
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson else if (ret == 0 &&
31d7e8fa33fae995f558673adb22641b5aa8b6e1George Wilson (ret=uri_parse_unreserved_char(parser, &ch)) < 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrensbool uri_data_decode(struct uri_parser *parser, const char *data,
fa9e4066f08beec538e775443c5be79dd423fcabahrens const unsigned char *p = (const unsigned char *)data;
fa9e4066f08beec538e775443c5be79dd423fcabahrens const unsigned char *pend = (const unsigned char *)until;
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* NULL means unlimited; solely rely on '\0' */
fa9e4066f08beec538e775443c5be79dd423fcabahrens unsigned char ch;
return TRUE;
len++;
unsigned int octet = 0;
int count = 0;
count++;
if (count > 0) {
int ret;
return ret;
int ret;
else if (ret == 0 &&
if (ret > 0) {
int ret;
const unsigned char *offset;
} else if (ret > 0) {
} else if (ret > 0) {
const char **host_name_r)
int ret;
return ret;
const char *address;
int ret;
const unsigned char *preserve;
int ret;
return ret;
if (dns_name) {
const unsigned char *first;
int ret;
return ret;
unsigned int count;
int ret;
count = 0;
relative = 0;
if (ret > 0) {
if (count > 0) {
count--;
} else if ( relative > 0 ) {
relative++;
count++;
const char *data)
const unsigned char *pbegin, *p;
if ((p - pbegin) > 0)
pbegin = p;
if ((p - pbegin) > 0)
const char *data)
if (port != 0)
const char *data)
const char *data)
const char *data)
const char *data)