uri-util.c revision e4e9ba5f43f9bf7e072d7d9fcc3259a42ecb15c8
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch/* [URI-GEN] RFC3986 Appendix A:
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch absolute-URI = scheme ":" hier-part [ "?" query ]
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch URI-reference = URI / relative-ref
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch relative-ref = relative-part [ "?" query ] [ "#" fragment ]
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch relative-part = "//" authority path-abempty
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / path-absolute
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / path-noscheme
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch hier-part = "//" authority path-abempty
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / path-absolute
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / path-rootless
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch authority = [ userinfo "@" ] host [ ":" port ]
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch host = IP-literal / IPv4address / reg-name
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch port = *DIGIT
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch IP-literal = "[" ( IPv6address / IPvFuture ) "]"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch IPv6address = 6( h16 ":" ) ls32
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / "::" 5( h16 ":" ) ls32
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / [ h16 ] "::" 4( h16 ":" ) ls32
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / [ *4( h16 ":" ) h16 ] "::" ls32
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / [ *5( h16 ":" ) h16 ] "::" h16
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / [ *6( h16 ":" ) h16 ] "::"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch h16 = 1*4HEXDIG
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch ls32 = ( h16 ":" h16 ) / IPv4address
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch dec-octet = DIGIT ; 0-9
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / %x31-39 DIGIT ; 10-99
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / "1" 2DIGIT ; 100-199
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / "2" %x30-34 DIGIT ; 200-249
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / "25" %x30-35 ; 250-255
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch reg-name = *( unreserved / pct-encoded / sub-delims )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch path = path-abempty ; begins with "/" or is empty
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / path-absolute ; begins with "/" but not "//"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / path-noscheme ; begins with a non-colon segment
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / path-rootless ; begins with a segment
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch / path-empty ; zero characters
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch path-abempty = *( "/" segment )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch path-absolute = "/" [ segment-nz *( "/" segment ) ]
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch path-noscheme = segment-nz-nc *( "/" segment )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch path-rootless = segment-nz *( "/" segment )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch path-empty = 0<pchar>
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch segment = *pchar
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch segment-nz = 1*pchar
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch ; non-zero-length segment without any colon ":"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch query = *( pchar / "/" / "?" )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch fragment = *( pchar / "/" / "?" )
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch pct-encoded = "%" HEXDIG HEXDIG
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch reserved = gen-delims / sub-delims
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen / "*" / "+" / "," / ";" / "="
9d0aee99a8c80d71137aa9b8c216cc203bec7a9aTimo Sirainen/* Character lookup table
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" [bit0]
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen * / "*" / "+" / "," / ";" / "=" [bit1]
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" [bit2]
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch * pchar = unreserved / sub-delims / ":" / "@" [bit0|bit1|bit3]
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch * 'pfchar' = unreserved / sub-delims / ":" / "@" / "/"
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch * [bit0|bit1|bit3|bit5]
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch * 'uchar' = unreserved / sub-delims / ":" [bit0|bit1|bit4]
4219de12b28f1936219e27501b9c4b27a4f8d53cStephan Bosch * 'qchar' = pchar / "/" / "?" [bit0|bit1|bit3|bit5|bit6]
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#define CHAR_MASK_PFCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5))
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch#define CHAR_MASK_QCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<6))
e47c2f17d8136c4d972d1074a3f84ba2ecef4fdcStephan Boschstatic unsigned const char _uri_char_lookup[256] = {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00
feba5e502b2131c9a1c766b7ef9ff041dbf71d1dStephan Bosch 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen 0, 2, 0, 4, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 1, 36, // 20
a8c4e79ff50fac21b05a7368b052583d410ca15cTimo Sirainen 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 2, 0, 2, 0, 68, // 30
70505f4839520ac67895992621c97d2480c22e7fTimo Sirainen 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 0, 4, 0, 1, // 50
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 70
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic inline int _decode_hex_digit(const unsigned char digit)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch case '0': case '1': case '2': case '3': case '4':
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch case '5': case '6': case '7': case '8': case '9':
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
7384b4e78eaab44693c985192276e31322155e32Stephan Boschuri_parse_pct_encoded_data(struct uri_parser *parser,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const unsigned char **p, const unsigned char *pend,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (**p != '%' || (pend != NULL && *p >= pend))
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen if (**p == 0 || *(*p+1) == 0 || (pend != NULL && *p+1 >= pend)) {
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen parser->error = "Unexpected URI boundary after '%'";
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch "Expecting hex digit after '%%', but found '%c'", **p);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch "Expecting hex digit after '%%%c', but found '%c'", *((*p)-1), **p);
fc94140acba51adafedafbc8491a3223a51db7a8Stephan Bosch "Percent encoding is not allowed to encode NUL character";
7384b4e78eaab44693c985192276e31322155e32Stephan Boschint uri_parse_pct_encoded(struct uri_parser *parser,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned char *ch_r)
fb1be3de0159d6a10e916ad992e2bc53be64c6d5Timo Sirainenuri_parse_unreserved_char(struct uri_parser *parser, unsigned char *ch_r)
1a9a35a6b307f8d5b25345af55e40a99162b4072Timo Sirainen if ((_uri_char_lookup[*parser->cur] & CHAR_MASK_UNRESERVED) != 0) {
7384b4e78eaab44693c985192276e31322155e32Stephan Boschint uri_parse_unreserved(struct uri_parser *parser, string_t *part)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch unsigned char ch = 0;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if ((ret = uri_parse_unreserved_char(parser, &ch)) < 0)
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainenint uri_parse_unreserved_pct(struct uri_parser *parser, string_t *part)
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen unsigned char ch = 0;
415e16c3dc185578695b7d88e561a52de6c8b1b1Timo Sirainen if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen else if (ret == 0 &&
35e962a9186b4e9b2001628c1d7b55c24b33ce84Timo Sirainen (ret=uri_parse_unreserved_char(parser, &ch)) < 0)
const unsigned char *p = (const unsigned char *)data;
int ret;
return TRUE;
unsigned char ch;
if (ret < 0)
return FALSE;
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)