improve nsurl query handling.

Alter the handling of query values within nsurl to be like fragments.

This ensures callers never have to care about the query punctuation,
e.g. the question mark

This also means the strings generated will no longer have trailing
question marks which now conforms to behaviour in whatwg url spec
on url serializing in section 4.5
This commit is contained in:
Vincent Sanders 2018-09-26 09:39:09 +01:00
parent 83512a6ff5
commit 9100fcb409
5 changed files with 77 additions and 44 deletions

View File

@ -428,9 +428,9 @@ static const struct test_pairs join_tests[] = {
{ " ", "http://a/b/c/d;p?q" },
{ "/", "http://a/" },
{ " / ", "http://a/" },
{ " ? ", "http://a/b/c/d;p?" },
{ " ? ", "http://a/b/c/d;p" },
{ " h ", "http://a/b/c/h" },
{ "//foo?", "http://foo/?" },
{ "//foo?", "http://foo/" },
{ "//foo#bar", "http://foo/#bar" },
{ "//foo/", "http://foo/" },
{ "http://<!--#echo var=", "http://<!--/#echo%20var="},
@ -531,21 +531,25 @@ END_TEST
*/
static const struct test_triplets replace_query_tests[] = {
{ "http://netsurf-browser.org/?magical=true",
"?magical=true&result=win",
"magical=true&result=win",
"http://netsurf-browser.org/?magical=true&result=win"},
{ "http://netsurf-browser.org/?magical=true#fragment",
"?magical=true&result=win",
"magical=true&result=win",
"http://netsurf-browser.org/?magical=true&result=win#fragment"},
{ "http://netsurf-browser.org/#fragment",
"?magical=true&result=win",
"magical=true&result=win",
"http://netsurf-browser.org/?magical=true&result=win#fragment"},
{ "http://netsurf-browser.org/path",
"?magical=true",
"magical=true",
"http://netsurf-browser.org/path?magical=true"},
{ "http://netsurf-browser.org/path?magical=true",
"",
"http://netsurf-browser.org/path"},
};
/**
@ -655,7 +659,7 @@ static const struct test_compare component_tests[] = {
{ "http://u:p@a:66/b/c/d;p?q#f", "a", NSURL_HOST, true },
{ "http://u:p@a:66/b/c/d;p?q#f", "66", NSURL_PORT, true },
{ "http://u:p@a:66/b/c/d;p?q#f", "/b/c/d;p", NSURL_PATH, true },
{ "http://u:p@a:66/b/c/d;p?q#f", "?q", NSURL_QUERY, true },
{ "http://u:p@a:66/b/c/d;p?q#f", "q", NSURL_QUERY, true },
{ "http://u:p@a:66/b/c/d;p?q#f", "f", NSURL_FRAGMENT, true },
{ "file:", "file", NSURL_SCHEME, true },
@ -667,6 +671,11 @@ static const struct test_compare component_tests[] = {
{ "file:", NULL, NSURL_QUERY, false },
{ "file:", NULL, NSURL_FRAGMENT, false },
{ "http://u:p@a:66/b/c/d;p?q=v#f", "q=v", NSURL_QUERY, true },
{ "http://u:p@a:66/b/c/d;p?q=v", "q=v", NSURL_QUERY, true },
{ "http://u:p@a:66/b/c/d;p?q=v&q1=v1#f", "q=v&q1=v1", NSURL_QUERY, true },
{ "http://u:p@a:66/b/c/d;p?q=v&q1=v1", "q=v&q1=v1", NSURL_QUERY, true },
};
@ -1167,12 +1176,11 @@ START_TEST(nsurl_api_assert_replace_query3_test)
nsurl *url;
nsurl *res;
nserror err;
const char *rel = "moo";
err = nsurl_create(base_str, &url);
ck_assert(err == NSERROR_OK);
err = nsurl_replace_query(url, rel, &res);
err = nsurl_replace_query(url, NULL, &res);
ck_assert(err != NSERROR_OK);
nsurl_unref(url);

View File

@ -313,6 +313,9 @@ nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url);
* the created object.
*
* Any query component in url is replaced with query in new_url.
*
* Passing the empty string as a replacement will result in the query
* component being removed.
*/
nserror nsurl_replace_query(const nsurl *url, const char *query,
nsurl **new_url);

View File

@ -54,7 +54,7 @@
* Does nothing if the components are the same, so ensure match is
* preset to true.
*/
#define nsurl__component_compare(c1, c2, match) \
#define nsurl__component_compare(c1, c2, match) \
if (c1 && c2 && lwc_error_ok == \
lwc_string_isequal(c1, c2, match)) { \
/* do nothing */ \
@ -364,7 +364,7 @@ nserror nsurl_get_utf8(const nsurl *url, char **url_s, size_t *url_l)
}
*url_l = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */
*url_s = malloc(*url_l);
*url_s = malloc(*url_l);
if (*url_s == NULL) {
err = NSERROR_NOMEM;
@ -574,57 +574,67 @@ nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url)
nserror nsurl_replace_query(const nsurl *url, const char *query,
nsurl **new_url)
{
int query_len; /* Length of new query string, including '?' */
int frag_len = 0; /* Length of fragment, including '#' */
int base_len; /* Length of URL up to start of query */
char *pos;
size_t len;
lwc_string *lwc_query;
int query_len; /* Length of new query string excluding '?' */
int frag_len = 0; /* Length of fragment, excluding '#' */
int base_len; /* Length of URL up to start of query */
char *pos; /* current position in output string */
size_t length; /* new url string length */
lwc_string *lwc_query = NULL;
assert(url != NULL);
assert(query != NULL);
assert(query[0] == '?');
/* Get the length of the new query */
query_len = strlen(query);
length = query_len = strlen(query);
if (query_len > 0) {
length++; /* allow for '?' */
/* intern string */
if (lwc_intern_string(query,
query_len,
&lwc_query) != lwc_error_ok) {
return NSERROR_NOMEM;
}
}
/* Find the change in length from url to new_url */
base_len = url->length;
if (url->components.query != NULL) {
base_len -= lwc_string_length(url->components.query);
base_len -= (1 + lwc_string_length(url->components.query));
}
if (url->components.fragment != NULL) {
frag_len = 1 + lwc_string_length(url->components.fragment);
base_len -= frag_len;
frag_len = lwc_string_length(url->components.fragment);
base_len -= (1 + frag_len);
length += frag_len + 1; /* allow for '#' */
}
/* Set new_url's length */
len = base_len + query_len + frag_len;
/* compute new url string length */
length += base_len;
/* Create NetSurf URL object */
*new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
*new_url = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
if (*new_url == NULL) {
if (query_len > 0) {
lwc_string_unref(lwc_query);
}
return NSERROR_NOMEM;
}
if (lwc_intern_string(query, query_len, &lwc_query) != lwc_error_ok) {
free(*new_url);
return NSERROR_NOMEM;
}
(*new_url)->length = len;
(*new_url)->length = length;
/* Set string */
pos = (*new_url)->string;
memcpy(pos, url->string, base_len);
pos += base_len;
memcpy(pos, query, query_len);
pos += query_len;
if (query_len > 0) {
*pos = '?';
memcpy(++pos, query, query_len);
pos += query_len;
}
if (url->components.fragment != NULL) {
const char *frag = lwc_string_data(url->components.fragment);
*pos = '#';
memcpy(++pos, frag, frag_len - 1);
pos += frag_len - 1;
memcpy(++pos, frag, frag_len);
pos += frag_len;
}
*pos = '\0';
@ -945,4 +955,3 @@ nserror nsurl_parent(const nsurl *url, nsurl **new_url)
return NSERROR_OK;
}

View File

@ -344,7 +344,7 @@ static void nsurl__get_string_markers(const char * const url_s,
* and in the case of mailto: when we assume there is an authority.
*/
if ((*pos == '/' && *(pos + 1) == '/') ||
(is_http && ((joining && *pos == '/') ||
(is_http && ((joining && *pos == '/') ||
(joining == false &&
marker.scheme_end != marker.start))) ||
marker.scheme_type == NSURL_SCHEME_MAILTO) {
@ -577,7 +577,7 @@ static size_t nsurl__remove_dot_segments(char *path, char *output)
/* Copy up to but not including next '/' */
while ((*path_pos != '/') && (*path_pos != '\0'))
*output_pos++ = *path_pos++;
*output_pos++ = *path_pos++;
}
return output_pos - output;
@ -671,7 +671,9 @@ static nserror nsurl__create_from_section(const char * const url_s,
break;
case URL_QUERY:
start = pegs->query;
start = (*(url_s + pegs->query) != '?') ?
pegs->query :
pegs->query + 1;
end = pegs->fragment;
break;
@ -1085,6 +1087,15 @@ static void nsurl__get_string_data(const struct nsurl_components *url,
*url_l += SLEN("@");
}
/* spanned query question mark */
if ((flags & ~(NSURL_F_QUERY | NSURL_F_FRAGMENT)) &&
(flags & NSURL_F_QUERY)) {
flags |= NSURL_F_QUERY_PUNCTUATION;
*url_l += SLEN("?");
}
/* spanned fragment hash mark */
if ((flags & ~NSURL_F_FRAGMENT) && (flags & NSURL_F_FRAGMENT)) {
flags |= NSURL_F_FRAGMENT_PUNCTUATION;
@ -1158,6 +1169,8 @@ static void nsurl__get_string(const struct nsurl_components *url, char *url_s,
}
if (flags & NSURL_F_QUERY) {
if (flags & NSURL_F_QUERY_PUNCTUATION)
*(pos++) = '?';
memcpy(pos, lwc_string_data(url->query), l->query);
pos += l->query;
}
@ -1557,4 +1570,3 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
return NSERROR_OK;
}

View File

@ -105,9 +105,10 @@ enum nsurl_string_flags {
NSURL_F_HOST |
NSURL_F_PORT),
NSURL_F_PATH = (1 << 8),
NSURL_F_QUERY = (1 << 9),
NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10),
NSURL_F_FRAGMENT = (1 << 11)
NSURL_F_QUERY_PUNCTUATION = (1 << 9),
NSURL_F_QUERY = (1 << 10),
NSURL_F_FRAGMENT_PUNCTUATION = (1 << 11),
NSURL_F_FRAGMENT = (1 << 12)
};
/**