summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2018-09-26 09:39:09 +0100
committerVincent Sanders <vince@kyllikki.org>2018-09-26 17:21:33 +0100
commit9100fcb4095cf8858d4cd2c613bff69ceb4f71ec (patch)
treeaad9e4c8246f10ba5d12d8175bcec5fdc3b3f0dc
parent83512a6ff529c7c5cb6315167cba1cf132e6a67a (diff)
downloadnetsurf-9100fcb4095cf8858d4cd2c613bff69ceb4f71ec.tar.gz
netsurf-9100fcb4095cf8858d4cd2c613bff69ceb4f71ec.tar.bz2
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
-rw-r--r--test/nsurl.c26
-rw-r--r--utils/nsurl.h3
-rw-r--r--utils/nsurl/nsurl.c65
-rw-r--r--utils/nsurl/parse.c20
-rw-r--r--utils/nsurl/private.h7
5 files changed, 77 insertions, 44 deletions
diff --git a/test/nsurl.c b/test/nsurl.c
index ba024291b..631e7ae2c 100644
--- a/test/nsurl.c
+++ b/test/nsurl.c
@@ -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);
diff --git a/utils/nsurl.h b/utils/nsurl.h
index bc6e910a6..c6590bdbb 100644
--- a/utils/nsurl.h
+++ b/utils/nsurl.h
@@ -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);
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
index 4dbbe96e3..38c0e53e8 100644
--- a/utils/nsurl/nsurl.c
+++ b/utils/nsurl/nsurl.c
@@ -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;
}
-
diff --git a/utils/nsurl/parse.c b/utils/nsurl/parse.c
index 3e3c52165..3b8816dd8 100644
--- a/utils/nsurl/parse.c
+++ b/utils/nsurl/parse.c
@@ -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;
}
-
diff --git a/utils/nsurl/private.h b/utils/nsurl/private.h
index 4366ff68c..06f143f4d 100644
--- a/utils/nsurl/private.h
+++ b/utils/nsurl/private.h
@@ -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)
};
/**