diff --git a/lib/urlapi.c b/lib/urlapi.c index 1aab7f9418..d546b18397 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -1279,16 +1279,16 @@ static CURLUcode redirect_url(const char *base, const char *relurl, case '#': /* fragment-only change */ - if(u->fragment) + if(u->fragment_present) cutoff = strchr(protsep, '#'); break; default: /* path or query-only change */ - if(u->query && u->query[0]) + if(u->query_present) /* remove existing query */ cutoff = strchr(protsep, '?'); - else if(u->fragment && u->fragment[0]) + else if(u->fragment_present) /* Remove existing fragment */ cutoff = strchr(protsep, '#'); @@ -1772,7 +1772,10 @@ static CURLUcode set_url(CURLU *u, const char *url, size_t part_size, /* if the old URL is incomplete (we cannot get an absolute URL in 'oldurl'), replace the existing with the new. Always include "scheme://" to make the URL "complete" */ - uc = curl_url_get(u, CURLUPART_URL, &oldurl, flags & ~CURLU_NO_GUESS_SCHEME); + /* Preserve empty query/fragment separators: they affect where relative + references splice into the base URL. */ + uc = curl_url_get(u, CURLUPART_URL, &oldurl, + (flags & ~CURLU_NO_GUESS_SCHEME) | CURLU_GET_EMPTY); if(uc == CURLUE_OUT_OF_MEMORY) return uc; else if(uc) diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c index 9c8f0e2b35..fd8073c876 100644 --- a/tests/libtest/lib1560.c +++ b/tests/libtest/lib1560.c @@ -1629,19 +1629,26 @@ static const struct redircase set_url_list[] = { 0, 0, CURLUE_OK}, {"http://example.org/foo/bar", "#", - "http://example.org/foo/bar", - /* This happens because the parser removes empty fragments */ + "http://example.org/foo/bar#", 0, 0, CURLUE_OK}, {"http://example.org/foo/bar", "?", - "http://example.org/foo/bar", - /* This happens because the parser removes empty queries */ + "http://example.org/foo/bar?", 0, 0, CURLUE_OK}, {"http://example.org/foo/bar", "?#", - "http://example.org/foo/bar", - /* This happens because the parser removes empty queries and fragments */ + "http://example.org/foo/bar?#", 0, 0, CURLUE_OK}, + {"http://host/path?", "#new", + "http://host/path?#new", 0, 0, CURLUE_OK}, + {"http://host/path?#", "#new", + "http://host/path?#new", 0, 0, CURLUE_OK}, + {"http://host/path#", "?new", + "http://host/path?new", 0, 0, CURLUE_OK}, + {"http://host/path?#", "?new", + "http://host/path?new", 0, 0, CURLUE_OK}, + {"http://host/path?#", "sub", + "http://host/sub", 0, 0, CURLUE_OK}, {"http://example.com/please/../gimme/%TESTNUMBER?foobar#hello", "http://example.net/there/it/is/../../tes t case=/%TESTNUMBER0002? yes no", "http://example.net/there/tes%20t%20case=/%TESTNUMBER0002?+yes+no", @@ -1716,7 +1723,7 @@ static int set_url(void) } else { char *url = NULL; - rc = curl_url_get(urlp, CURLUPART_URL, &url, 0); + rc = curl_url_get(urlp, CURLUPART_URL, &url, CURLU_GET_EMPTY); if(rc) { curl_mfprintf(stderr, "%s:%d Get URL returned %d (%s)\n", __FILE__, __LINE__, (int)rc, curl_url_strerror(rc));