diff --git a/test/nsurl.c b/test/nsurl.c index c82bc888c..20109f8fb 100644 --- a/test/nsurl.c +++ b/test/nsurl.c @@ -17,6 +17,18 @@ struct test_pairs { const char* res; }; +struct test_triplets { + const char* test1; + const char* test2; + const char* res; +}; + +static void netsurf_lwc_iterator(lwc_string *str, void *pw) +{ + LOG(("[%3u] %.*s", str->refcnt, (int) lwc_string_length(str), + lwc_string_data(str))); +} + static const struct test_pairs create_tests[] = { { "http:", "http:" }, { "http:/", "http:" }, @@ -130,6 +142,26 @@ static const struct test_pairs join_tests[] = { { NULL, NULL } }; +static const struct test_triplets replace_query_tests[] = { + { "http://netsurf-browser.org/?magical=true", + "?magical=true&result=win", + "http://netsurf-browser.org/?magical=true&result=win"}, + + { "http://netsurf-browser.org/?magical=true#fragment", + "?magical=true&result=win", + "http://netsurf-browser.org/?magical=true&result=win#fragment"}, + + { "http://netsurf-browser.org/#fragment", + "?magical=true&result=win", + "http://netsurf-browser.org/?magical=true&result=win#fragment"}, + + { "http://netsurf-browser.org/path", + "?magical=true", + "http://netsurf-browser.org/path?magical=true"}, + + { NULL, NULL, NULL } +}; + /** * Test nsurl */ @@ -141,6 +173,7 @@ int main(void) size_t len; const char *url; const struct test_pairs *test; + const struct test_triplets *ttest; int passed = 0; int count = 0; @@ -207,6 +240,39 @@ int main(void) count++; } + /* Replace query tests */ + LOG(("Testing nsurl_replace_query")); + for (ttest = replace_query_tests; ttest->test1 != NULL; ttest++) { + if (nsurl_create(ttest->test1, &base) != NSERROR_OK) { + LOG(("Failed to create URL:\n\t\t%s.", ttest->test1)); + } else { + if (nsurl_replace_query(base, ttest->test2, &joined) != + NSERROR_OK) { + LOG(("Failed to make test URL")); + } else { + if (strcmp(nsurl_access(joined), + ttest->res) == 0) { + LOG(("\tPASS: \"%s\" + %s", + ttest->test1, + ttest->test2)); + passed++; + } else { + LOG(("\tFAIL: \"%s\" + %s", + ttest->test1, + ttest->test2)); + LOG(("\t\tExpecting %s", ttest->res)); + LOG(("\t\tGot %s", + nsurl_access(joined))); + } + + nsurl_unref(joined); + } + + nsurl_unref(base); + } + count++; + } + if (passed == count) { LOG(("Testing complete: SUCCESS")); } else { @@ -214,6 +280,9 @@ int main(void) LOG(("Failed %d out of %d", count - passed, count)); } + LOG(("Remaining lwc strings:")); + lwc_iterate_strings(netsurf_lwc_iterator, NULL); + return 0; } diff --git a/utils/nsurl.c b/utils/nsurl.c index af6581d0d..47b7f5451 100644 --- a/utils/nsurl.c +++ b/utils/nsurl.c @@ -1901,6 +1901,89 @@ nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url) } +/* exported interface, documented in nsurl.h */ +nserror nsurl_replace_query(const nsurl *url, const char *query, + nsurl **new_url) +{ + int query_len; + int base_len; + char *pos; + size_t len; + lwc_string *lwc_query; + + assert(url != NULL); + assert(query != NULL); + assert(query[0] == '?'); + + /* Get the length of the new query */ + query_len = strlen(query); + + /* 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); + } + if (url->components.fragment != NULL) { + base_len -= 1 + lwc_string_length(url->components.fragment); + } + + /* Set new_url's length */ + len = base_len + query_len; + + /* Create NetSurf URL object */ + *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */ + if (*new_url == NULL) { + 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; + + /* Set string */ + pos = (*new_url)->string; + memcpy(pos, url->string, base_len); + pos += base_len; + memcpy(pos, query, query_len); + pos += query_len; + if (url->components.fragment != NULL) { + const char *frag = lwc_string_data(url->components.fragment); + size_t frag_len = lwc_string_length(url->components.fragment); + *pos = '#'; + memcpy(++pos, frag, frag_len); + pos += frag_len; + } + *pos = '\0'; + + /* Copy components */ + (*new_url)->components.scheme = + nsurl__component_copy(url->components.scheme); + (*new_url)->components.username = + nsurl__component_copy(url->components.username); + (*new_url)->components.password = + nsurl__component_copy(url->components.password); + (*new_url)->components.host = + nsurl__component_copy(url->components.host); + (*new_url)->components.port = + nsurl__component_copy(url->components.port); + (*new_url)->components.path = + nsurl__component_copy(url->components.path); + (*new_url)->components.query = lwc_query; + (*new_url)->components.fragment = + nsurl__component_copy(url->components.fragment); + + (*new_url)->components.scheme_type = url->components.scheme_type; + + /* Give the URL a reference */ + (*new_url)->count = 1; + + return NSERROR_OK; +} + + /* exported interface, documented in nsurl.h */ nserror nsurl_parent(const nsurl *url, nsurl **new_url) { diff --git a/utils/nsurl.h b/utils/nsurl.h index 3b140e7ac..068d08b8d 100644 --- a/utils/nsurl.h +++ b/utils/nsurl.h @@ -242,6 +242,25 @@ nserror nsurl_defragment(const nsurl *url, nsurl **no_frag); nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url); +/** + * Create a NetSurf URL object, with query string replaced + * + * \param url NetSurf URL to create new NetSurf URL from + * \param query Query string to use + * \param new_url Returns new NetSurf URL with query string provided + * \return NSERROR_OK on success, appropriate error otherwise + * + * If return value != NSERROR_OK, nothing will be returned in new_url. + * + * It is up to the client to call nsurl_destroy when they are finished with + * the created object. + * + * Any query component in url is replaced with query in new_url. + */ +nserror nsurl_replace_query(const nsurl *url, const char *query, + nsurl **new_url); + + /** * Create a NetSurf URL object for URL with parent location of an existing URL. *