Skip to content

Commit

Permalink
uri-util: Split struct uri_host from uri_authority.
Browse files Browse the repository at this point in the history
Adds support for parsing host separately and manipulating host struct.
  • Loading branch information
stephanbosch authored and GitLab committed May 16, 2016
1 parent 62ed330 commit 8d2d278
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 34 deletions.
24 changes: 12 additions & 12 deletions src/lib-http/http-url.c
Expand Up @@ -37,7 +37,7 @@ static bool http_url_parse_authority(struct http_url_parser *url_parser)

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
Expand Down Expand Up @@ -79,8 +79,8 @@ static bool http_url_parse_authority(struct http_url_parser *url_parser)
}
}
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);
Expand Down Expand Up @@ -362,37 +362,37 @@ int http_url_request_target_parse(const char *request_target,
{
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);
Expand Down
6 changes: 3 additions & 3 deletions src/lib-imap/imap-url.c
Expand Up @@ -194,7 +194,7 @@ static int imap_url_parse_iserver(struct imap_url_parser *url_parser)
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.
Expand Down Expand Up @@ -260,8 +260,8 @@ static int imap_url_parse_iserver(struct imap_url_parser *url_parser)
}

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;
Expand Down
82 changes: 66 additions & 16 deletions src/lib/uri-util.c
Expand Up @@ -433,7 +433,7 @@ uri_parse_reg_name(struct uri_parser *parser,
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;
Expand Down Expand Up @@ -549,6 +549,22 @@ static int uri_parse_host_name_dns(struct uri_parser *parser,
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)
Expand Down Expand Up @@ -600,9 +616,8 @@ uri_parse_ip_literal(struct uri_parser *parser, string_t *literal,
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;
Expand All @@ -615,17 +630,20 @@ uri_parse_host(struct uri_parser *parser,
* host = IP-literal / IPv4address / reg-name
*/

if (host != NULL)
memset(host, 0, sizeof(*host));

literal = uri_parser_get_tmpbuf(parser, 256);

/* IP-literal / */
if (parser->cur < parser->end && *parser->cur == '[') {
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;
}
Expand All @@ -636,10 +654,10 @@ uri_parse_host(struct uri_parser *parser,
*/
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;
}
Expand All @@ -648,12 +666,12 @@ uri_parse_host(struct uri_parser *parser,

/* 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;
}

Expand Down Expand Up @@ -717,7 +735,8 @@ int uri_parse_authority(struct uri_parser *parser,
}

/* 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;
Expand Down Expand Up @@ -993,6 +1012,25 @@ string_t *uri_parser_get_tmpbuf(struct uri_parser *parser, size_t size)
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
*/
Expand Down Expand Up @@ -1055,6 +1093,18 @@ void uri_append_host_ip(string_t *out, const struct ip_addr *host_ip)
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)
Expand Down
23 changes: 20 additions & 3 deletions src/lib/uri-util.h
Expand Up @@ -7,12 +7,15 @@
* 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;
};

Expand All @@ -38,6 +41,12 @@ int uri_cut_scheme(const char **uri_p, const char **scheme_r)
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,
Expand All @@ -61,6 +70,12 @@ void uri_parser_init(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
Expand All @@ -70,8 +85,10 @@ void uri_append_scheme(string_t *out, const char *scheme);

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);
Expand Down

0 comments on commit 8d2d278

Please sign in to comment.