Adds support for parsing host separately and manipulating host struct.
if ((ret = uri_parse_authority(parser, &auth, TRUE)) < 0)
return FALSE;
- if (auth.host_literal == NULL || *auth.host_literal == '\0') {
+ if (auth.host.name == NULL || *auth.host.name == '\0') {
/* RFC 7230, Section 2.7.1: http URI Scheme
A sender MUST NOT generate an "http" URI with an empty host
}
}
if (url != NULL) {
- url->host_name = p_strdup(parser->pool, auth.host_literal);
- url->host_ip = auth.host_ip;
+ url->host_name = p_strdup(parser->pool, auth.host.name);
+ url->host_ip = auth.host.ip;
url->port = auth.port;
url->user = p_strdup(parser->pool, user);
url->password = p_strdup(parser->pool, password);
{
struct http_url_parser url_parser;
struct uri_parser *parser;
- struct uri_authority host;
+ struct uri_authority auth;
struct http_url base;
memset(&url_parser, '\0', sizeof(url_parser));
parser = &url_parser.parser;
uri_parser_init(parser, pool, host_header);
- if (uri_parse_authority(parser, &host, TRUE) <= 0) {
+ if (uri_parse_authority(parser, &auth, TRUE) <= 0) {
*error_r = t_strdup_printf("Invalid Host header: %s", parser->error);
return -1;
}
- if (parser->cur != parser->end || host.enc_userinfo != NULL) {
+ if (parser->cur != parser->end || auth.enc_userinfo != NULL) {
*error_r = "Invalid Host header: Contains invalid character";
return -1;
}
if (request_target[0] == '*' && request_target[1] == '\0') {
struct http_url *url = p_new(pool, struct http_url, 1);
- url->host_name = p_strdup(pool, host.host_literal);
- url->host_ip = host.host_ip;
- url->port = host.port;
+ url->host_name = p_strdup(pool, auth.host.name);
+ url->host_ip = auth.host.ip;
+ url->port = auth.port;
target->url = url;
target->format = HTTP_REQUEST_TARGET_FORMAT_ASTERISK;
return 0;
}
memset(&base, 0, sizeof(base));
- base.host_name = host.host_literal;
- base.host_ip = host.host_ip;
- base.port = host.port;
+ base.host_name = auth.host.name;
+ base.host_ip = auth.host.ip;
+ base.port = auth.port;
memset(parser, '\0', sizeof(*parser));
uri_parser_init(parser, pool, request_target);
if ((ret = uri_parse_slashslash_authority
(parser, &auth, TRUE)) <= 0)
return ret;
- if (auth.host_literal == NULL || *auth.host_literal == '\0') {
+ if (auth.host.name == NULL || *auth.host.name == '\0') {
/* This situation is not documented anywhere, but it is not
currently useful either and potentially problematic if not
handled explicitly everywhere. So, it is denied hier for now.
}
if (url != NULL) {
- url->host_name = auth.host_literal;
- url->host_ip = auth.host_ip;
+ url->host_name = auth.host.name;
+ url->host_ip = auth.host.ip;
url->port = auth.port;
}
return 1;
return 0;
}
-static int uri_parse_host_name_dns(struct uri_parser *parser,
+static int uri_do_parse_host_name_dns(struct uri_parser *parser,
string_t *host_name) ATTR_NULL(2, 3)
{
const unsigned char *first, *part;
return 1;
}
+int uri_parse_host_name_dns(struct uri_parser *parser,
+ const char **host_name_r)
+{
+ string_t *host_name = NULL;
+ int ret;
+
+ if (host_name_r != NULL)
+ host_name = uri_parser_get_tmpbuf(parser, 256);
+
+ if ((ret=uri_do_parse_host_name_dns(parser, host_name)) <= 0)
+ return ret;
+
+ *host_name_r = str_c(host_name);
+ return 1;
+}
+
static int
uri_parse_ip_literal(struct uri_parser *parser, string_t *literal,
struct in6_addr *ip6_r) ATTR_NULL(2,3)
return 1;
}
-static int
-uri_parse_host(struct uri_parser *parser,
- struct uri_authority *auth, bool dns_name) ATTR_NULL(2)
+int uri_parse_host(struct uri_parser *parser,
+ struct uri_host *host, bool dns_name) ATTR_NULL(2)
{
const unsigned char *preserve;
struct in_addr ip4;
* host = IP-literal / IPv4address / reg-name
*/
+ if (host != NULL)
+ memset(host, 0, sizeof(*host));
+
literal = uri_parser_get_tmpbuf(parser, 256);
/* IP-literal / */
if ((ret=uri_parse_ip_literal(parser, literal, &ip6)) <= 0)
return -1;
- if (auth != NULL) {
- auth->host_literal = p_strdup(parser->pool, str_c(literal));
- auth->host_ip.family = AF_INET6;
- auth->host_ip.u.ip6 = ip6;
+ if (host != NULL) {
+ host->name = p_strdup(parser->pool, str_c(literal));;
+ host->ip.family = AF_INET6;
+ host->ip.u.ip6 = ip6;
}
return 1;
}
*/
preserve = parser->cur;
if ((ret = uri_parse_ipv4address(parser, literal, &ip4)) > 0) {
- if (auth != NULL) {
- auth->host_literal = p_strdup(parser->pool, str_c(literal));
- auth->host_ip.family = AF_INET;
- auth->host_ip.u.ip4 = ip4;
+ if (host != NULL) {
+ host->name = p_strdup(parser->pool, str_c(literal));
+ host->ip.family = AF_INET;
+ host->ip.u.ip4 = ip4;
}
return ret;
}
/* reg-name */
if (dns_name) {
- if (uri_parse_host_name_dns(parser, literal) < 0)
+ if (uri_do_parse_host_name_dns(parser, literal) < 0)
return -1;
} else if (uri_parse_reg_name(parser, literal) < 0)
return -1;
- if (auth != NULL)
- auth->host_literal = p_strdup(parser->pool, str_c(literal));
+ if (host != NULL)
+ host->name = p_strdup(parser->pool, str_c(literal));
return 0;
}
}
/* host */
- if (uri_parse_host(parser, auth, dns_name) < 0)
+ if (uri_parse_host(parser,
+ (auth == NULL ? NULL : &auth->host), dns_name) < 0)
return -1;
if (parser->cur == parser->end)
return 1;
return parser->tmpbuf;
}
+/*
+ * Generic URI manipulation
+ */
+
+void uri_host_copy(pool_t pool, struct uri_host *dest,
+ const struct uri_host *src)
+{
+ const char *host_name = src->name;
+
+ /* create host name literal if caller is lazy */
+ if (host_name == NULL && src->ip.family != 0) {
+ host_name = net_ip2addr(&src->ip);
+ i_assert(*host_name != '\0');
+ }
+
+ *dest = *src;
+ dest->name = p_strdup(pool, host_name);
+}
+
/*
* Generic URI construction
*/
str_append_c(out, ']');
}
+void uri_append_host(string_t *out, const struct uri_host *host)
+{
+ if (host->name != NULL) {
+ /* assume IPv6 literal if starts with '['; avoid encoding */
+ if (*host->name == '[')
+ str_append(out, host->name);
+ else
+ uri_append_host_name(out, host->name);
+ } else
+ uri_append_host_ip(out, &host->ip);
+}
+
void uri_append_port(string_t *out, in_port_t port)
{
if (port != 0)
* Generic URI parsing.
*/
+struct uri_host {
+ const char *name;
+ struct ip_addr ip;
+};
+
struct uri_authority {
const char *enc_userinfo;
- const char *host_literal;
- struct ip_addr host_ip;
-
+ struct uri_host host;
in_port_t port;
};
ATTR_NULL(2);
int uri_parse_scheme(struct uri_parser *parser, const char **scheme_r)
ATTR_NULL(2);
+
+int uri_parse_host_name_dns(struct uri_parser *parser,
+ const char **host_name_r) ATTR_NULL(2);
+int uri_parse_host(struct uri_parser *parser,
+ struct uri_host *host, bool dns_name) ATTR_NULL(2);
+
int uri_parse_authority(struct uri_parser *parser,
struct uri_authority *auth, bool dns_name) ATTR_NULL(2);
int uri_parse_slashslash_authority(struct uri_parser *parser,
string_t *uri_parser_get_tmpbuf(struct uri_parser *parser,
size_t size);
+/*
+ * Generic URI manipulation
+ */
+
+void uri_host_copy(pool_t pool, struct uri_host *dest,
+ const struct uri_host *src);
/*
* Generic URI construction
void uri_append_user_data(string_t *out, const char *esc, const char *data);
void uri_append_userinfo(string_t *out, const char *userinfo);
+
void uri_append_host_name(string_t *out, const char *name);
void uri_append_host_ip(string_t *out, const struct ip_addr *host_ip);
+void uri_append_host(string_t *out, const struct uri_host *host);
void uri_append_port(string_t *out, in_port_t port);
void uri_append_path_segment_data(string_t *out, const char *esc, const char *data);