aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmar Polo <op@omarpolo.com>2024-05-29 08:52:25 +0000
committerOmar Polo <op@omarpolo.com>2024-05-29 08:52:25 +0000
commitb00f71ba97cf4448446fc5ccf715ca0dfda3a93b (patch)
tree9e9fdb9892c4079ebcbad7305c11df61e912003a
parent6ff8de1f8a389dd6b0de7e442ba95ccfe2734484 (diff)
iri: add support for raw IPv6 addresses
-rw-r--r--iri.c48
-rw-r--r--regress/iri_test.c8
2 files changed, 43 insertions, 13 deletions
diff --git a/iri.c b/iri.c
index 1436314..ec5e128 100644
--- a/iri.c
+++ b/iri.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, 2022 Omar Polo <op@omarpolo.com>
+ * Copyright (c) 2020, 2022, 2024 Omar Polo <op@omarpolo.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -177,25 +177,47 @@ parse_port(struct parser *p)
return 1;
}
-/* TODO: add support for ip-literal and ipv4addr ? */
/* *( unreserved / sub-delims / pct-encoded ) */
static int
parse_authority(struct parser *p)
{
- p->parsed->host = p->iri;
+ struct addrinfo hints, *ai;
+ char *end;
+ int err;
- while (unreserved(*p->iri)
- || sub_delimiters(*p->iri)
- || parse_pct_encoded(p)
- || valid_multibyte_utf8(p)) {
- /* normalize the host name. */
- if (*p->iri < 0x7F)
- *p->iri = tolower(*p->iri);
+ if (*p->iri == '[') {
p->iri++;
- }
+ p->parsed->host = p->iri;
+ if ((end = strchr(p->iri, ']')) == NULL) {
+ p->err = "invalid IPv6 address";
+ return 0;
+ }
+ *end++ = '\0';
+ p->iri = end;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ err = getaddrinfo(p->parsed->host, NULL, &hints, &ai);
+ if (err != 0) {
+ p->err = "invalid IPv6 address";
+ return 0;
+ }
+ freeaddrinfo(ai);
+ } else {
+ p->parsed->host = p->iri;
+ while (unreserved(*p->iri)
+ || sub_delimiters(*p->iri)
+ || parse_pct_encoded(p)
+ || valid_multibyte_utf8(p)) {
+ /* normalize the host name. */
+ if (*p->iri < 0x7F)
+ *p->iri = tolower(*p->iri);
+ p->iri++;
+ }
- if (p->err != NULL)
- return 0;
+ if (p->err != NULL)
+ return 0;
+ }
if (*p->iri == ':') {
*p->iri = '\0';
diff --git a/regress/iri_test.c b/regress/iri_test.c
index 32d40a8..fa6d578 100644
--- a/regress/iri_test.c
+++ b/regress/iri_test.c
@@ -162,6 +162,14 @@ main(void)
PASS,
IRI("gemini", "naïve.omarpolo.com", "", "", "", ""),
"Can percent decode hostnames");
+ TEST("gemini://100.64.3.27/",
+ PASS,
+ IRI("gemini", "100.64.3.27", "", "", "", ""),
+ "Accepts IPv4 addresses");
+ TEST("gemini://[::1]/",
+ PASS,
+ IRI("gemini", "::1", "", "", "", ""),
+ "Accepts IPv6 addresses");
/* path */
TEST("gemini://omarpolo.com/foo/bar/baz",