commit a165601e7e2641edcf7b36be8ce9c03ab281fd99 from: Omar Polo date: Sun Dec 25 18:49:56 2022 UTC iri: support framents and enable fragments tests 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");