uri-util.c revision af53c056cf1e3d133a78c201e72a678b5431d0fb
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "lib.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "array.h"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#include "str.h"
472369cba85d9f7c995dda60e7cd01d78b4a960aTimo Sirainen#include "net.h"
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen#include "uri-util.h"
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen#include <ctype.h>
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen/* [URI-GEN] RFC3986 Appendix A:
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen absolute-URI = scheme ":" hier-part [ "?" query ]
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen URI-reference = URI / relative-ref
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen relative-ref = relative-part [ "?" query ] [ "#" fragment ]
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen relative-part = "//" authority path-abempty
ef50336eefcb9ba99f73c6af37420eaf8857a39bTimo Sirainen / path-absolute
91b203fd2132510a47a4b34252c0ae0efd688a19Timo Sirainen / path-noscheme
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen / path-empty
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen hier-part = "//" authority path-abempty
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen / path-absolute
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen / path-rootless
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen / path-empty
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
5694eeb99b69dea8033ca77ad69743c6b4871370Timo Sirainen authority = [ userinfo "@" ] host [ ":" port ]
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen host = IP-literal / IPv4address / reg-name
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen port = *DIGIT
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen IP-literal = "[" ( IPv6address / IPvFuture ) "]"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen IPv6address = 6( h16 ":" ) ls32
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen / "::" 5( h16 ":" ) ls32
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen / [ h16 ] "::" 4( h16 ":" ) ls32
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen / [ *4( h16 ":" ) h16 ] "::" ls32
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen / [ *5( h16 ":" ) h16 ] "::" h16
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen / [ *6( h16 ":" ) h16 ] "::"
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen h16 = 1*4HEXDIG
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen ls32 = ( h16 ":" h16 ) / IPv4address
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen dec-octet = DIGIT ; 0-9
220e21750948941dc6e33b8f11b552fa21d7f81eTimo Sirainen / %x31-39 DIGIT ; 10-99
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen / "1" 2DIGIT ; 100-199
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen / "2" %x30-34 DIGIT ; 200-249
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen / "25" %x30-35 ; 250-255
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen reg-name = *( unreserved / pct-encoded / sub-delims )
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen path = path-abempty ; begins with "/" or is empty
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen / path-absolute ; begins with "/" but not "//"
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen / path-noscheme ; begins with a non-colon segment
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen / path-rootless ; begins with a segment
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen / path-empty ; zero characters
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen path-abempty = *( "/" segment )
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen path-absolute = "/" [ segment-nz *( "/" segment ) ]
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen path-noscheme = segment-nz-nc *( "/" segment )
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen path-rootless = segment-nz *( "/" segment )
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen path-empty = 0<pchar>
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen segment = *pchar
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen segment-nz = 1*pchar
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen ; non-zero-length segment without any colon ":"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen query = *( pchar / "/" / "?" )
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen fragment = *( pchar / "/" / "?" )
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen pct-encoded = "%" HEXDIG HEXDIG
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen reserved = gen-delims / sub-delims
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen / "*" / "+" / "," / ";" / "="
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen */
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen
8a0ad174adb1eb5108511b90e97f4e5f9089b0eeTimo Sirainen#define URI_MAX_SCHEME_NAME_LEN 64
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen/* Character lookup table
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" [bit0]
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen * / "*" / "+" / "," / ";" / "=" [bit1]
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" [bit2]
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen * pchar = unreserved / sub-delims / ":" / "@" [bit0|bit1|bit3]
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen * 'pfchar' = unreserved / sub-delims / ":" / "@" / "/"
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen * [bit0|bit1|bit3|bit5]
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen * 'uchar' = unreserved / sub-delims / ":" [bit0|bit1|bit4]
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen * 'qchar' = pchar / "/" / "?" [bit0|bit1|bit3|bit5|bit6]
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen#define CHAR_MASK_UNRESERVED (1<<0)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen#define CHAR_MASK_SUB_DELIMS (1<<1)
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen#define CHAR_MASK_PCHAR ((1<<0)|(1<<1)|(1<<3))
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen#define CHAR_MASK_PFCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5))
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen#define CHAR_MASK_UCHAR ((1<<0)|(1<<1)|(1<<4))
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen#define CHAR_MASK_QCHAR ((1<<0)|(1<<1)|(1<<3)|(1<<5)|(1<<6))
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainenstatic unsigned const char _uri_char_lookup[256] = {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen 0, 2, 0, 4, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 1, 36, // 20
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 28, 2, 0, 2, 0, 68, // 30
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 0, 4, 0, 1, // 50
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 70
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen};
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenstatic inline int _decode_hex_digit(const unsigned char digit)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen switch (digit) {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen case '0': case '1': case '2': case '3': case '4':
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen case '5': case '6': case '7': case '8': case '9':
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen return digit - '0';
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return digit - 'a' + 0x0a;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return digit - 'A' + 0x0A;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return -1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainenstatic int
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainenuri_parse_pct_encoded_data(struct uri_parser *parser,
6600c05e2ab38e9f662582b63c56b0c980a03748Timo Sirainen const unsigned char **p, const unsigned char *pend,
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen unsigned char *ch_r) ATTR_NULL(3)
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen{
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen int value;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (**p != '%' || (pend != NULL && *p >= pend))
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen return 0;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen *p += 1;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen if (**p == 0 || *(*p+1) == 0 || (pend != NULL && *p+1 >= pend)) {
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen parser->error = "Unexpected URI boundary after '%'";
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen return -1;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen if ((value = _decode_hex_digit(**p)) < 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen parser->error = p_strdup_printf(parser->pool,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "Expecting hex digit after '%%', but found '%c'", **p);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return -1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *ch_r = (value & 0x0f) << 4;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *p += 1;
3fe67ec75ccae1230bb9eb9f16affc48377f6441Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((value = _decode_hex_digit(**p)) < 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen parser->error = p_strdup_printf(parser->pool,
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen "Expecting hex digit after '%%%c', but found '%c'", *((*p)-1), **p);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen return -1;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen }
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen *ch_r |= (value & 0x0f);
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen *p += 1;
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen if (*ch_r == '\0') {
2a6dcd984104fed84bed8795ccdfabb20e41ce52Timo Sirainen parser->error =
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "Percent encoding is not allowed to encode NUL character";
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return -1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return 1;
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint uri_parse_pct_encoded(struct uri_parser *parser,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned char *ch_r)
27586e4785d56aeb76e1fd96af8db799688dc64aTimo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return uri_parse_pct_encoded_data
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen (parser, &parser->cur, parser->end, ch_r);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic int
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenuri_parse_unreserved_char(struct uri_parser *parser, unsigned char *ch_r)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((*parser->cur & 0x80) != 0)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return 0;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((_uri_char_lookup[*parser->cur] & CHAR_MASK_UNRESERVED) != 0) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen *ch_r = *parser->cur;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk parser->cur++;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk return 1;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk }
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk return 0;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk}
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volkint uri_parse_unreserved(struct uri_parser *parser, string_t *part)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen int len = 0;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen while (parser->cur < parser->end) {
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen int ret;
db8b0a3f74a20528d66a3c4be7df920e5c4554c2Timo Sirainen unsigned char ch = 0;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen if ((ret = uri_parse_unreserved_char(parser, &ch)) < 0)
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen return -1;
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen if (ret == 0)
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen break;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (part != NULL)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen str_append_c(part, ch);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen len++;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return len > 0 ? 1 : 0;
9abf5be0962538e1f6f5c73c838ff677341da0c9Timo Sirainen}
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenint uri_parse_unreserved_pct(struct uri_parser *parser, string_t *part)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen{
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen int len = 0;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen while (parser->cur < parser->end) {
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen int ret;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen unsigned char ch = 0;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return -1;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen else if (ret == 0 &&
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen (ret=uri_parse_unreserved_char(parser, &ch)) < 0)
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen return -1;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen if (ret == 0)
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen break;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (part != NULL)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen str_append_c(part, ch);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen len++;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen return len > 0 ? 1 : 0;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen}
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainenbool uri_data_decode(struct uri_parser *parser, const char *data,
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen const char *until, const char **decoded_r)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen{
5c597df6aa8d81de4053c6986fab7739f3b44b20Timo Sirainen const unsigned char *p = (const unsigned char *)data;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen const unsigned char *pend = (const unsigned char *)until;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen string_t *decoded;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen int ret;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen if (pend == NULL) {
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* NULL means unlimited; solely rely on '\0' */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen pend = (const unsigned char *)(size_t)-1;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen }
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (p >= pend || *p == '\0') {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (decoded_r != NULL)
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen *decoded_r = "";
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return TRUE;
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen decoded = uri_parser_get_tmpbuf(parser, 256);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen while (p < pend && *p != '\0') {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen unsigned char ch;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if ((ret=uri_parse_pct_encoded_data
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen (parser, &p, NULL, &ch)) != 0) {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (ret < 0)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return FALSE;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen str_append_c(decoded, ch);
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen } else {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen str_append_c(decoded, *p);
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainen p++;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen }
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen }
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen if (decoded_r != NULL)
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen *decoded_r = p_strdup(parser->pool, str_c(decoded));
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen return TRUE;
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen}
c58c12049c883b281c088d47a2a7278c21c390e1Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainenint uri_parse_scheme(struct uri_parser *parser, const char **scheme_r)
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen{
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen const unsigned char *first = parser->cur;
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen size_t len = 1;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen /* RFC 3968:
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen * scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen */
c1d19144dd7b1de6822df6ed1d10af0c9cb38840Timo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen if (parser->cur >= parser->end || !i_isalpha(*parser->cur))
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen parser->cur++;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen while (len < URI_MAX_SCHEME_NAME_LEN &&
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen parser->cur < parser->end) {
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (!i_isalnum(*parser->cur) &&
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen *parser->cur != '+' && *parser->cur != '-' &&
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen *parser->cur != '.')
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen break;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen parser->cur++;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen len++;
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen }
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (parser->cur >= parser->end || *parser->cur != ':') {
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen parser->error = "Invalid URI scheme";
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen return -1;
5494a6bc149da8f02fd25c0434a9d612ac33f659Timo Sirainen }
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (scheme_r != NULL)
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen *scheme_r = t_strndup(first, parser->cur - first);
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen parser->cur++;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 1;
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen}
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen
94b0ff77495c3ed14bdd4b5d7ae1eb37e8c9efb5Timo Sirainenint uri_cut_scheme(const char **uri_p, const char **scheme_r)
02e61e13a8360a9d3ec92c5fa5ae60c0f0181b71Timo Sirainen{
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen struct uri_parser parser;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen uri_parser_init(&parser, NULL, *uri_p);
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen if (uri_parse_scheme(&parser, scheme_r) <= 0)
b365bd121cdc87f63e1dd47c5085a27091118e00Timo Sirainen return -1;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen *uri_p = (const char *)parser.cur;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen return 0;
adb6413686e52e00dded4932babcc08ff041876bTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic int
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenuri_parse_dec_octet(struct uri_parser *parser, string_t *literal,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen uint8_t *octet_r) ATTR_NULL(2)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen unsigned int octet = 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen int count = 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* RFC 3986:
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen *
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen * dec-octet = DIGIT ; 0-9
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen * / %x31-39 DIGIT ; 10-99
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen * / "1" 2DIGIT ; 100-199
1433bf361ddb0bba8878c8ada5726d0284edad57Timo Sirainen * / "2" %x30-34 DIGIT ; 200-249
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen * / "25" %x30-35 ; 250-255
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen while (parser->cur < parser->end && i_isdigit(*parser->cur)) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen octet = octet * 10 + (parser->cur[0] - '0');
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (octet > 255)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return -1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen if (literal != NULL)
4a514fb20e04df397842cde11cc9ea92abfe9728Timo Sirainen str_append_c(literal, *parser->cur);
94d8e51119003d2bc5a100c663f90141f297385dTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->cur++;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen count++;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (count > 0) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen *octet_r = octet;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return 1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenstatic int
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenuri_parse_ipv4address(struct uri_parser *parser, string_t *literal,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen struct in_addr *ip4_r) ATTR_NULL(2,3)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen{
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen uint8_t octet;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen uint32_t ip = 0;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen int ret;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen int i;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* RFC 3986:
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen *
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if ((ret = uri_parse_dec_octet(parser, literal, &octet)) <= 0)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return ret;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ip = octet;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen for (i = 0; i < 3 && parser->cur < parser->end; i++) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (*parser->cur != '.')
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return -1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (literal != NULL)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_append_c(literal, '.');
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen parser->cur++;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if ((ret = uri_parse_dec_octet(parser, literal, &octet)) <= 0)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return -1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ip = (ip << 8) + octet;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (ip4_r != NULL)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ip4_r->s_addr = htonl(ip);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return 1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen}
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenuri_parse_reg_name(struct uri_parser *parser,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen string_t *reg_name) ATTR_NULL(2)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* RFC 3986:
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen *
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen * reg-name = *( unreserved / pct-encoded / sub-delims )
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen while (parser->cur < parser->end) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen int ret;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned char c;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
494a5de15db3b2806ab31d5ecc3e1c306ae14d06Timo Sirainen /* unreserved / pct-encoded */
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen if ((ret=uri_parse_pct_encoded(parser, &c)) < 0)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen else if (ret == 0 &&
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen (ret=uri_parse_unreserved_char(parser, &c)) < 0)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen return -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (ret > 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (reg_name != NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen str_append_c(reg_name, c);
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen continue;
08ed4ab71fd2a4e800d9025a736f0f46b771ea90Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* sub-delims */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen c = *parser->cur;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if ((c & 0x80) == 0 && (_uri_char_lookup[c] & CHAR_MASK_SUB_DELIMS) != 0) {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (reg_name != NULL)
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen str_append_c(reg_name, *parser->cur);
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen parser->cur++;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen continue;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen break;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainenstatic int uri_do_parse_host_name_dns(struct uri_parser *parser,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen string_t *host_name) ATTR_NULL(2, 3)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen{
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const unsigned char *first, *part;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen int ret;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* RFC 3986, Section 3.2.2:
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen A registered name intended for lookup in the DNS uses the syntax
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen defined in Section 3.5 of [RFC1034] and Section 2.1 of [RFC1123].
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen Such a name consists of a sequence of domain labels separated by ".",
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen each domain label starting and ending with an alphanumeric character
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen and possibly also containing "-" characters. The rightmost domain
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen label of a fully qualified domain name in DNS may be followed by a
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen single "." and should be if it is necessary to distinguish between
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen the complete domain name and some local domain.
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen RFC 2396, Section 3.2.2 (old URI specification):
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen hostname = *( domainlabel "." ) toplabel [ "." ]
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen toplabel = alpha | alpha *( alphanum | "-" ) alphanum
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen The description in RFC 3986 is more liberal, so:
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen hostname = *( domainlabel "." ) domainlabel [ "." ]
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen We also support percent encoding in spirit of the generic reg-name,
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen even though this should explicitly not be used according to the RFC.
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen It is, however, not strictly forbidden (unlike older RFC), so we
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen support it.
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen first = part = parser->cur;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen for (;;) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen const unsigned char *offset;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen unsigned char ch, pch;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* alphanum */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen offset = parser->cur;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen ch = pch = *parser->cur;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (parser->cur >= parser->end)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen break;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return -1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen } else if (ret > 0) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (!i_isalnum(ch))
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return -1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (host_name != NULL)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_append_c(host_name, ch);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen part = parser->cur;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } else {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (!i_isalnum(*parser->cur))
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen break;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen parser->cur++;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (parser->cur < parser->end) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* *( alphanum | "-" ) alphanum */
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen do {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen offset = parser->cur;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if ((ret=uri_parse_pct_encoded(parser, &ch)) < 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen } else if (ret > 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (!i_isalnum(ch) && ch != '-')
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen break;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (host_name != NULL) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (offset > part)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen str_append_n(host_name, part, offset - part);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen str_append_c(host_name, ch);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen part = parser->cur;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen } else {
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen ch = *parser->cur;
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen if (!i_isalnum(ch) && ch != '-')
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen break;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen parser->cur++;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen pch = ch;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen } while (parser->cur < parser->end);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (!i_isalnum(pch)) {
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen parser->error = "Invalid domain label in hostname";
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen return -1;
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen }
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (host_name != NULL && parser->cur > part)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_append_n(host_name, part, parser->cur - part);
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen /* "." */
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (parser->cur >= parser->end || ch != '.')
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen break;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (host_name != NULL)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen str_append_c(host_name, '.');
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen if (parser->cur == offset)
dc5606fb66d30a659459446b6ca1a8b4f1146052Timo Sirainen parser->cur++;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen part = parser->cur;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (parser->cur == first)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return 0;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen /* remove trailing '.' */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (host_name != NULL) {
1701e3f91107051b1704721bf1dc1e32491faaf9Timo Sirainen const char *name = str_c(host_name);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen i_assert(str_len(host_name) > 0);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (name[str_len(host_name)-1] == '.')
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen str_truncate(host_name, str_len(host_name)-1);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen return 1;
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen}
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainenint uri_parse_host_name_dns(struct uri_parser *parser,
bd4e36a8cd7257cca7d1434c49a1e343ed7c5100Timo Sirainen const char **host_name_r)
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen{
cb933f0a570a9cef5c975eadb818aa6b1002a269Timo Sirainen string_t *host_name = NULL;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen int ret;
37847ec8eaec9ad55c9df10ae109efe7b37ac573Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (host_name_r != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen host_name = uri_parser_get_tmpbuf(parser, 256);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen if ((ret=uri_do_parse_host_name_dns(parser, host_name)) <= 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return ret;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *host_name_r = str_c(host_name);
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return 1;
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen}
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainenstatic int
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainenuri_parse_ip_literal(struct uri_parser *parser, string_t *literal,
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen struct in6_addr *ip6_r) ATTR_NULL(2,3)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen{
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen const unsigned char *p;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen const char *address;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen struct in6_addr ip6;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen int ret;
c58906589cafc32df4c04ffbef933baadd3f2276Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen /* IP-literal = "[" ( IPv6address / IPvFuture ) "]"
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen * IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen * IPv6address = ; Syntax not relevant: parsed using inet_pton()
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen */
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen /* "[" already verified */
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen /* Scan for end of address */
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainen for (p = parser->cur+1; p < parser->end; p++) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (*p == ']')
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen break;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (p >= parser->end || *p != ']') {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen parser->error = "Expecting ']' at end of IP-literal";
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (literal != NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen str_append_n(literal, parser->cur, p-parser->cur+1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen address = t_strdup_until(parser->cur+1, p);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen parser->cur = p + 1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (*address == '\0') {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen parser->error = "Empty IPv6 host address";
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return -1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (*address == 'v') {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen parser->error = p_strdup_printf(parser->pool,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "Future IP host address '%s' not supported", address);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return -1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if ((ret = inet_pton(AF_INET6, address, &ip6)) <= 0) {
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen parser->error = p_strdup_printf(parser->pool,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen "Invalid IPv6 host address '%s'", address);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return -1;
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen }
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen if (ip6_r != NULL)
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen *ip6_r = ip6;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return 1;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen}
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainenint uri_parse_host(struct uri_parser *parser,
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen struct uri_host *host, bool dns_name) ATTR_NULL(2)
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen{
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen const unsigned char *preserve;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct in_addr ip4;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen struct in6_addr ip6;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen string_t *literal = NULL;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen int ret;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen
b82d6d7f02734007c129fa25bc876049c8d9bddeTimo Sirainen /* RFC 3986:
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen *
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen * host = IP-literal / IPv4address / reg-name
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen */
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen if (host != NULL)
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen memset(host, 0, sizeof(*host));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk literal = uri_parser_get_tmpbuf(parser, 256);
c78e7a94528078728cc639b26a1c83e11b4d7e1bTimo Sirainen
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen /* IP-literal / */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (parser->cur < parser->end && *parser->cur == '[') {
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen if ((ret=uri_parse_ip_literal(parser, literal, &ip6)) <= 0)
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen return -1;
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen if (host != NULL) {
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen host->name = p_strdup(parser->pool, str_c(literal));;
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen host->ip.family = AF_INET6;
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen host->ip.u.ip6 = ip6;
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen }
d06c46087e9e6e66bbbbb9df1d5b33154349515cTimo Sirainen return 1;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen }
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* IPv4address /
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen *
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen * If it fails to parse, we try to parse it as a reg-name
0910ea0672c0295c442eb686cc41e98656831f37Timo Sirainen */
0910ea0672c0295c442eb686cc41e98656831f37Timo Sirainen preserve = parser->cur;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen if ((ret = uri_parse_ipv4address(parser, literal, &ip4)) > 0) {
e91543761d0b7b97a1dc28e036e44d76405545c2Timo Sirainen if (host != NULL) {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen host->name = p_strdup(parser->pool, str_c(literal));
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen host->ip.family = AF_INET;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen host->ip.u.ip4 = ip4;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen }
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return ret;
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen }
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen parser->cur = preserve;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen str_truncate(literal, 0);
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen /* reg-name */
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen if (dns_name) {
93688bfedcfb2b9c02750b8d4d409123a386de5cTimo Sirainen if (uri_do_parse_host_name_dns(parser, literal) < 0)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return -1;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen } else if (uri_parse_reg_name(parser, literal) < 0)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return -1;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (host != NULL)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen host->name = p_strdup(parser->pool, str_c(literal));
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen return 0;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen}
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainenstatic int
6dd77763f5451269ace733579cf58f2f3b18bca4Timo Sirainenuri_parse_port(struct uri_parser *parser,
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen struct uri_authority *auth) ATTR_NULL(2)
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen{
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen const unsigned char *first;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen in_port_t port;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen /* RFC 3986:
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen *
d02d34e138e32b4266f5a403d6c51d7803bf322fTimo Sirainen * port = *DIGIT
fe813f74aaccb12f38e1bd9cd338c6a37fa646e5Timo Sirainen */
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen first = parser->cur;
a24519c36d5f8fa22f58b2c693ba547e8d175a54Timo Sirainen while (parser->cur < parser->end && i_isdigit(*parser->cur))
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk parser->cur++;
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk if (parser->cur == first)
c78e7a94528078728cc639b26a1c83e11b4d7e1bTimo Sirainen return 0;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen if (net_str2port(t_strdup_until(first, parser->cur), &port) < 0) {
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen parser->error = "Invalid port number";
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen return -1;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen }
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen if (auth != NULL)
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen auth->port = port;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen return 1;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen}
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainenint uri_parse_authority(struct uri_parser *parser,
17cf149e5f47183bfcc1503649dfb92a14f9dcd9Timo Sirainen struct uri_authority *auth, bool dns_name)
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen{
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen const unsigned char *p;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen int ret;
490f66d6476d51cc02333d6eb398a5cd94b67f48Timo Sirainen
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen /*
fea7b8b3fc182e415b1875d79587c0aa1adb09d7Timo Sirainen * authority = [ userinfo "@" ] host [ ":" port ]
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (auth != NULL)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen memset(auth, 0, sizeof(*auth));
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* Scan ahead to check whether there is a [userinfo "@"] uri component */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen for (p = parser->cur; p < parser->end; p++){
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* refuse 8bit characters */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((*p & 0x80) != 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen break;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* break at first delimiter */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (*p != '%' && (_uri_char_lookup[*p] & CHAR_MASK_UCHAR) == 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen break;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* Extract userinfo */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (p < parser->end && *p == '@') {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (auth != NULL)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen auth->enc_userinfo = p_strdup_until(parser->pool, parser->cur, p);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->cur = p+1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* host */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (uri_parse_host(parser,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen (auth == NULL ? NULL : &auth->host), dns_name) < 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return -1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (parser->cur == parser->end)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return 1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen switch (*parser->cur) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen case ':': case '/': case '?': case '#':
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen break;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen default:
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->error = "Invalid host identifier";
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return -1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* [":" port] */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (*parser->cur == ':') {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->cur++;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((ret = uri_parse_port(parser, auth)) < 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return ret;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (parser->cur == parser->end)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return 1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen switch (*parser->cur) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen case '/': case '?': case '#':
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen break;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen default:
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->error = "Invalid host port";
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return -1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return 1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenint uri_parse_slashslash_authority(struct uri_parser *parser,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen struct uri_authority *auth, bool dns_name)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* "//" authority */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((parser->end - parser->cur) <= 2 || parser->cur[0] != '/' ||
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->cur[1] != '/')
be110f0a3888a24282f06820ec0b5068d2b8f906Timo Sirainen return 0;
be110f0a3888a24282f06820ec0b5068d2b8f906Timo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->cur += 2;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return uri_parse_authority(parser, auth, dns_name);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenint uri_parse_path_segment(struct uri_parser *parser, const char **segment_r)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen const unsigned char *p = parser->cur;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen while (p < parser->end) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (*p == '%') {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen p++;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen continue;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if ((*p & 0x80) != 0 || (_uri_char_lookup[*p] & CHAR_MASK_PCHAR) == 0)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen break;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen p++;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (p < parser->end &&
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen *p != '/' && *p != '?' && *p != '#' ) {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->error =
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen "Path component contains invalid character";
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return -1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen }
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (p == parser->cur)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (segment_r != NULL)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen *segment_r = p_strdup_until(parser->pool, parser->cur, p);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->cur = p;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen return 1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen}
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainenint uri_parse_path(struct uri_parser *parser,
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen int *relative_r, const char *const **path_r)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen{
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const unsigned char *pbegin = parser->cur;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen ARRAY_TYPE(const_string) segments;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen const char *segment = NULL;
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen unsigned int count;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen int relative = 1;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen int ret;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen count = 0;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (path_r != NULL)
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen p_array_init(&segments, parser->pool, 16);
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen else
e5aa8d4c9bdda79c2db03391ec45b37bf774df14Timo Sirainen memset(&segments, 0, sizeof(segments));
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen /* check for a leading '/' and indicate absolute path
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen when it is present
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen */
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen if (parser->cur < parser->end && *parser->cur == '/') {
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen parser->cur++;
0b4e1043e596bfb36d999dacbf1d4d63ee96d75fTimo Sirainen relative = 0;
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen }
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* parse first segment */
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen if ((ret = uri_parse_path_segment(parser, &segment)) < 0)
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen return -1;
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen for (;;) {
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen if (ret > 0) {
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen /* strip dot segments */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (segment[0] == '.') {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (segment[1] == '.') {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (segment[2] == '\0') {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* '..' -> skip and... */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen segment = NULL;
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen /* ... pop last segment (if any) */
9f1a154d6f436e67f22f737f66bb148b502d4d2aTimo Sirainen if (count > 0) {
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen if (path_r != NULL) {
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen i_assert(count == array_count(&segments));
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen array_delete(&segments, count-1, 1);
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen }
1c885b304f060e3ac4fe04195a2f53457d0ac99eTimo Sirainen count--;
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen } else if ( relative > 0 ) {
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen relative++;
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen }
6d931bbce16786df431e9ae8201a78a95084316dTimo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen } else if (segment[1] == '\0') {
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen /* '.' -> skip */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen segment = NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen } else {
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen segment = "";
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen }
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen if (segment != NULL) {
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen if (path_r != NULL)
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen array_append(&segments, &segment, 1);
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen count++;
6b067886457724ca13d81e869240500c5bd5d7e2Timo Sirainen }
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen if (parser->cur >= parser->end || *parser->cur != '/')
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen break;
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen parser->cur++;
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen
e28fa207d1a097fa6e4a867f74ee0761472ef1ceTimo Sirainen /* parse next path segment */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if ((ret = uri_parse_path_segment(parser, &segment)) < 0)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return -1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (relative_r != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *relative_r = relative;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (path_r != NULL)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen *path_r = NULL;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen if (parser->cur == pbegin) {
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen /* path part of URI is empty */
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen return 0;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen }
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen if (path_r != NULL) {
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen /* special treatment for a trailing '..' or '.' */
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen if (segment == NULL) {
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen segment = "";
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen array_append(&segments, &segment, 1);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen }
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen array_append_zero(&segments);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen *path_r = array_get(&segments, &count);
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen }
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen if (parser->cur < parser->end &&
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen *parser->cur != '?' && *parser->cur != '#') {
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen parser->error = "Path component contains invalid character";
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen return -1;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen }
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen return 1;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen}
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainenint uri_parse_query(struct uri_parser *parser, const char **query_r)
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen{
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen const unsigned char *p = parser->cur;
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen /* RFC 3986:
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen *
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen * URI = { ... } [ "?" query ] { ... }
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen * query = *( pchar / "/" / "?" )
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
e0ca8f2484847b57e20798a9f9c7040708696a90Timo Sirainen */
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen if (p >= parser->end || *p != '?')
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen return 0;
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen p++;
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen while (p < parser->end) {
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen if (*p == '%') {
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen p++;
c040ee67d0ac0fb7375bb543965bf67dcae6affaTimo Sirainen continue;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen }
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen if ((*p & 0x80) != 0 || (_uri_char_lookup[*p] & CHAR_MASK_QCHAR) == 0)
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen break;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen p++;
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen }
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen if (p < parser->end && *p != '#') {
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen parser->error = "Query component contains invalid character";
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen return -1;
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen }
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen
5160580b0ec3f3288a320987abdf12a990f09df5Timo Sirainen if (query_r != NULL)
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen *query_r = p_strdup_until(parser->pool, parser->cur+1, p);
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen parser->cur = p;
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen return 1;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen}
533bfba437e4120aa29dd45bca2aa87e30ee28a2Timo Sirainen
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainenint uri_parse_fragment(struct uri_parser *parser, const char **fragment_r)
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen{
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen const unsigned char *p = parser->cur;
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen /* RFC 3986:
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen *
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen * URI = { ... } [ "#" fragment ]
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen * fragment = *( pchar / "/" / "?" )
f97cacf16251b42f530c6a28686cc8c9aa7df3a2Timo Sirainen * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen */
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen if (p >= parser->end || *p != '#')
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen return 0;
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen p++;
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen while (p < parser->end) {
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen if (*p == '%') {
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen p++;
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen continue;
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen }
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen if ((*p & 0x80) != 0 || (_uri_char_lookup[*p] & CHAR_MASK_QCHAR) == 0)
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen break;
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen p++;
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainen }
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen if (p < parser->end) {
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen parser->error = "Fragment component contains invalid character";
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen return -1;
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen }
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen if (fragment_r != NULL)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen *fragment_r = p_strdup_until(parser->pool, parser->cur+1, p);
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen parser->cur = p;
d92f33f13830ba23d814342bf3ea8db721a15bb1Timo Sirainen return 1;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen}
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen
4ba962c3e78f140facdcfb1e093c4c46de75ae24Timo Sirainenvoid uri_parser_init_data(struct uri_parser *parser,
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen pool_t pool, const unsigned char *data, size_t size)
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen{
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen parser->pool = pool;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen parser->begin = parser->cur = data;
b13f738e8eb3f24dc2abf2c804f954b4d864ac6fTimo Sirainen parser->end = data + size;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen parser->error = NULL;
a27e065f1a1f91c7fbdf7c2ea1c387441af0cbb3Timo Sirainen parser->tmpbuf = NULL;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenvoid uri_parser_init(struct uri_parser *parser,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen pool_t pool, const char *uri)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen uri_parser_init_data
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen (parser, pool, (const unsigned char *)uri, strlen(uri));
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenstring_t *uri_parser_get_tmpbuf(struct uri_parser *parser, size_t size)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (parser->tmpbuf == NULL)
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen parser->tmpbuf = str_new(parser->pool, size);
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen else
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen str_truncate(parser->tmpbuf, 0);
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen return parser->tmpbuf;
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen}
eb64c3586d854cddd693f0b811d897399076a441Timo Sirainen
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen/*
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen * Generic URI manipulation
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainenvoid uri_host_copy(pool_t pool, struct uri_host *dest,
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen const struct uri_host *src)
6b8bcce7a001076605cb2cfdca8507204c88f376Timo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *host_name = src->name;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen /* create host name literal if caller is lazy */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (host_name == NULL && src->ip.family != 0) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen host_name = net_ip2addr(&src->ip);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen i_assert(*host_name != '\0');
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen *dest = *src;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen dest->name = p_strdup(pool, host_name);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen/*
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen * Generic URI construction
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen */
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenstatic void
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenuri_data_encode(string_t *out, const unsigned char esc_table[256],
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen unsigned char esc_mask, const char *esc_extra, const char *data)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const unsigned char *pbegin, *p;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen pbegin = p = (const unsigned char *)data;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen while (*p != '\0') {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if ((*p & 0x80) != 0 || (esc_table[*p] & esc_mask) == 0 ||
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen strchr(esc_extra, (char)*p) != NULL) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if ((p - pbegin) > 0)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append_n(out, pbegin, p - pbegin);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_printfa(out, "%%%02x", *p);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen p++;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen pbegin = p;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen } else {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen p++;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if ((p - pbegin) > 0)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append_n(out, pbegin, p - pbegin);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenvoid uri_append_scheme(string_t *out, const char *scheme)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append(out, scheme);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append_c(out, ':');
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenvoid uri_append_user_data(string_t *out, const char *esc,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *data)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen uri_data_encode(out, _uri_char_lookup, CHAR_MASK_UCHAR, esc, data);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenvoid uri_append_userinfo(string_t *out, const char *userinfo)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen uri_append_user_data(out, "", userinfo);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append_c(out, '@');
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenvoid uri_append_host_name(string_t *out, const char *name)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen uri_data_encode(out, _uri_char_lookup,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen CHAR_MASK_UNRESERVED | CHAR_MASK_SUB_DELIMS, "", name);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenvoid uri_append_host_ip(string_t *out, const struct ip_addr *host_ip)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *addr = net_ip2addr(host_ip);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen i_assert(host_ip->family != 0);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (host_ip->family == AF_INET) {
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append(out, addr);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen return;
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen }
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen i_assert(host_ip->family == AF_INET6);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append_c(out, '[');
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append(out, addr);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append_c(out, ']');
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainenvoid uri_append_host(string_t *out, const struct uri_host *host)
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen{
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen if (host->name != NULL) {
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen /* assume IPv6 literal if starts with '['; avoid encoding */
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen if (*host->name == '[')
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen str_append(out, host->name);
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen else
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen uri_append_host_name(out, host->name);
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen } else
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen uri_append_host_ip(out, &host->ip);
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
c07e35cfc9587fc7589cbc1db0daeeb828456b2bTimo Sirainenvoid uri_append_port(string_t *out, in_port_t port)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (port != 0)
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen str_printfa(out, ":%u", port);
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen}
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenvoid uri_append_path_segment_data(string_t *out, const char *esc,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *data)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen uri_data_encode(out, _uri_char_lookup, CHAR_MASK_PCHAR, esc, data);
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen}
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainenvoid uri_append_path_segment(string_t *out, const char *segment)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen str_append_c(out, '/');
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (*segment != '\0')
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen uri_append_path_data(out, "", segment);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen}
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenvoid uri_append_path_data(string_t *out, const char *esc,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *data)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen uri_data_encode(out, _uri_char_lookup, CHAR_MASK_PFCHAR, esc, data);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen}
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenvoid uri_append_path(string_t *out, const char *path)
407453d06e5622ac3bf099cc76bfcbfb5860b444Timo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen str_append_c(out, '/');
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (*path != '\0')
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen uri_append_path_data(out, "", path);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen}
547847191d4a95cd267fc846a1ca3c2111214719Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenvoid uri_append_query_data(string_t *out, const char *esc,
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen const char *data)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen uri_data_encode(out, _uri_char_lookup, CHAR_MASK_QCHAR, esc, data);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen}
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenvoid uri_append_query(string_t *out, const char *query)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen str_append_c(out, '?');
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen if (*query != '\0')
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen uri_append_query_data(out, "", query);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainenvoid uri_append_fragment_data(string_t *out, const char *esc,
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen const char *data)
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen{
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen uri_data_encode(out, _uri_char_lookup, CHAR_MASK_QCHAR, esc, data);
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen}
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen
de486b59018016977015ef42e6071155b60e82e1Timo Sirainenvoid uri_append_fragment(string_t *out, const char *fragment)
de486b59018016977015ef42e6071155b60e82e1Timo Sirainen{
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen str_append_c(out, '#');
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen if (*fragment != '\0')
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen uri_append_fragment_data(out, "", fragment);
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen}
de4d9f77d6378a416c9963963eac5ac18b75ec0bTimo Sirainen