Commit Diff


commit - 92e07b23c3cad37a92a7888b062064996891b1a3
commit + a165601e7e2641edcf7b36be8ce9c03ab281fd99
blob - f2687041ed034ffc3566a0168819e0ec26fc5c1c
blob + a95449659fd9a1b6d311f3ae106dd7544d79d1df
--- iri.c
+++ iri.c
@@ -362,6 +362,26 @@ parse_query(const char *s, struct iri *iri)
 	if (cpstr(s, t, iri->iri_query, sizeof(iri->iri_query)) == -1)
 		return (NULL);
 	iri->iri_flags |= IH_QUERY;
+	return (t);
+}
+
+static const char *
+parse_fragment(const char *s, struct iri *iri)
+{
+	const char	*n, *t = s;
+
+	for (;;) {
+		if ((n = advance_pchar(t)) != NULL)
+			t = n;
+		else if (*t == '/' || *t == '?')
+			t++;
+		else
+			break;
+	}
+
+	if (cpstr(s, t, iri->iri_fragment, sizeof(iri->iri_fragment)) == -1)
+		return (NULL);
+	iri->iri_flags |= IH_FRAGMENT;
 	return (t);
 }
 
@@ -380,8 +400,10 @@ parse_uri(const char *s, struct iri *iri)
 	if (*s == '?' && (s = parse_query(s + 1, iri)) == NULL)
 		return (-1);
 
-	/* skip fragments */
-	if (*s == '#' || *s == '\0')
+	if (*s == '#' && (s = parse_fragment(s + 1, iri)) == NULL)
+		return (-1);
+
+	if (*s == '\0')
 		return (0);
 
 	return (-1);
@@ -396,8 +418,10 @@ parse_relative_ref(const char *s, struct iri *iri)
 	if (*s == '?' && (s = parse_query(s + 1, iri)) == NULL)
 		return (-1);
 
-	/* skip fragments */
-	if (*s == '#' || *s == '\0')
+	if (*s == '#' && (s = parse_fragment(s + 1, iri)) == NULL)
+		return (-1);
+
+	if (*s == '\0')
 		return (0);
 
 	return (-1);
@@ -468,6 +492,13 @@ cpfields(struct iri *dest, const struct iri *src, int 
 			dest->iri_flags |= IH_QUERY;
 			memcpy(dest->iri_query, src->iri_query,
 			    sizeof(dest->iri_query));
+		}
+	}
+	if (flags & IH_FRAGMENT) {
+		if (src->iri_flags & IH_FRAGMENT) {
+			dest->iri_flags |= IH_FRAGMENT;
+			memcpy(dest->iri_fragment, src->iri_fragment,
+			    sizeof(dest->iri_fragment));
 		}
 	}
 }
@@ -560,14 +591,14 @@ iri_parse(const char *base, const char *str, struct ir
 		}
 	}
 
+	cpfields(iri, &iparsed, IH_FRAGMENT);
+
 	if (iparsed.iri_flags & IH_SCHEME) {
 		cpfields(iri, &iparsed, iparsed.iri_flags);
 		remove_dot_segments(iri);
 		return (0);
 	}
 
-	/* if fragments are supported, copy iparsed fragment to iri */
-
 	cpfields(iri, &ibase, IH_SCHEME);
 
 	if (iparsed.iri_flags & IH_HOST) {
@@ -654,6 +685,12 @@ iri_unparse(const struct iri *i, char *buf, size_t buf
 			goto err;
 	}
 
+	if (i->iri_flags & IH_FRAGMENT) {
+		if (strlcat(buf, "#", buflen) >= buflen ||
+		    strlcat(buf, i->iri_fragment, buflen) >= buflen)
+			goto err;
+	}
+
 	return (0);
 
  err:
blob - 385c9423629d58a2d8807928a7bda8e6446c0418
blob + dcb6c2151e2bbfe69ffb5925c192635f8033696b
--- iri.h
+++ iri.h
@@ -25,6 +25,7 @@ struct iri {
 	uint16_t	iri_port;
 	char		iri_path[1024];
 	char		iri_query[1024];
+	char		iri_fragment[1024];
 
 #define IH_SCHEME	0x01
 #define IH_UINFO	0x02
@@ -33,6 +34,7 @@ struct iri {
 #define IH_AUTHORITY	(IH_UINFO|IH_HOST|IH_PORT)
 #define IH_PATH		0x10
 #define IH_QUERY	0x20
+#define IH_FRAGMENT	0x40
 	int		iri_flags;
 };
 
blob - 9904d91b3d90115ac086109bb8a049244509e0c5
blob + 85308278a62e6b91bb85a43a889150d3034ffc35
--- test/iritest.c
+++ test/iritest.c
@@ -70,12 +70,12 @@ main(void)
 
 	ret |= check(base, "?y", "http://a/b/c/d;p?y");
 	ret |= check(base, "g?y", "http://a/b/c/g?y");
-//	ret |= check(base, "#s", "http://a/b/c/d;p?q#s");
-//	ret |= check(base, "g#s", "http://a/b/c/g#s");
-//	ret |= check(base, "g?y#s", "http://a/b/c/g?y#s");
+	ret |= check(base, "#s", "http://a/b/c/d;p?q#s");
+	ret |= check(base, "g#s", "http://a/b/c/g#s");
+	ret |= check(base, "g?y#s", "http://a/b/c/g?y#s");
 	ret |= check(base, ";x", "http://a/b/c/;x");
 	ret |= check(base, "g;x", "http://a/b/c/g;x");
-//	ret |= check(base, "g;x?y#s", "http://a/b/c/g;x?y#s");
+	ret |= check(base, "g;x?y#s", "http://a/b/c/g;x?y#s");
 	ret |= check(base, "", "http://a/b/c/d;p?q");
 	ret |= check(base, ".", "http://a/b/c/");
 	ret |= check(base, "./", "http://a/b/c/");
@@ -104,8 +104,8 @@ main(void)
 
 	ret |= check(base, "g?y/./x", "http://a/b/c/g?y/./x");
 	ret |= check(base, "g?y/../x", "http://a/b/c/g?y/../x");
-//	ret |= check(base, "g#s/./x", "http://a/b/c/g#s/./x");
-//	ret |= check(base, "g#s/../x", "http://a/b/c/g#s/../x");
+	ret |= check(base, "g#s/./x", "http://a/b/c/g#s/./x");
+	ret |= check(base, "g#s/../x", "http://a/b/c/g#s/../x");
 
 	ret |= check(base, "http:g", "http:g");