bool uri_data_decode(struct uri_parser *parser, const char *data, const char *until, const char **decoded_r) { const unsigned char *p = (const unsigned char *)data; const unsigned char *pend = (const unsigned char *)until; string_t *decoded; if (pend == NULL) { /* NULL means unlimited; solely rely on '\0' */ pend = (const unsigned char *)(size_t)-1; } if (p >= pend || *p == '\0') { if (decoded_r != NULL) *decoded_r = ""; return TRUE; } decoded = uri_parser_get_tmpbuf(parser, 256); while (p < pend && *p != '\0') { unsigned char ch; if (*p == '%') { p++; if (uri_parse_pct_encoded(parser, &p, NULL, &ch) <= 0) return FALSE; str_append_c(decoded, ch); } else { str_append_c(decoded, *p); p++; } } if (decoded_r != NULL) *decoded_r = t_strdup(str_c(decoded)); return TRUE; }
static int uri_parse_host(struct uri_parser *parser, struct uri_authority *auth) { const unsigned char *preserve; struct in_addr ip4; struct in6_addr ip6; string_t *literal = NULL; int ret; /* RFC 3986: * * host = IP-literal / IPv4address / reg-name */ literal = uri_parser_get_tmpbuf(parser, 256); /* IP-literal / */ if (parser->cur < parser->end && *parser->cur == '[') { #ifdef HAVE_IPV6 if ((ret=uri_parse_ip_literal(parser, literal, &ip6)) <= 0) return -1; if (auth != NULL) { auth->host_literal = t_strdup(str_c(literal)); auth->host_ip.family = AF_INET6; auth->host_ip.u.ip6 = ip6; auth->have_host_ip = TRUE; } return 1; #else parser->error = "IPv6 host address is not supported"; return -1; #endif } /* IPv4address / * * If it fails to parse, we try to parse it as a reg-name */ preserve = parser->cur; if ((ret = uri_parse_ipv4address(parser, literal, &ip4)) > 0) { if (auth != NULL) { auth->host_literal = t_strdup(str_c(literal)); auth->host_ip.family = AF_INET; auth->host_ip.u.ip4 = ip4; auth->have_host_ip = TRUE; } return ret; } parser->cur = preserve; str_truncate(literal, 0); /* reg-name */ if ((ret = uri_parse_reg_name(parser, literal)) != 0) { if (ret > 0 && auth != NULL) { auth->host_literal = t_strdup(str_c(literal)); auth->have_host_ip = FALSE; } return ret; } return 0; }