const char *useurl = relurl;
CURLcode result = CURLE_OK;
CURLUcode uc;
+ bool skip_slash = FALSE;
*newurl = NULL;
/* protsep points to the start of the host name */
*pathsep = 0;
/* we have a relative path to append to the last slash if there's one
- available, or if the new URL is just a query string (starts with a
- '?') we append the new one at the end of the entire currently worked
- out URL */
- if(useurl[0] != '?') {
+ available, or the new URL is just a query string (starts with a '?') or
+ a fragment (starts with '#') we append the new one at the end of the
+ current URL */
+ if((useurl[0] != '?') && (useurl[0] != '#')) {
pathsep = strrchr(protsep, '/');
if(pathsep)
*pathsep = 0;
- }
- /* Check if there's any slash after the host name, and if so, remember
- that position instead */
- pathsep = strchr(protsep, '/');
- if(pathsep)
- protsep = pathsep + 1;
- else
- protsep = NULL;
+ /* Check if there's any slash after the host name, and if so, remember
+ that position instead */
+ pathsep = strchr(protsep, '/');
+ if(pathsep)
+ protsep = pathsep + 1;
+ else
+ protsep = NULL;
- /* now deal with one "./" or any amount of "../" in the newurl
- and act accordingly */
+ /* now deal with one "./" or any amount of "../" in the newurl
+ and act accordingly */
- if((useurl[0] == '.') && (useurl[1] == '/'))
- useurl += 2; /* just skip the "./" */
+ if((useurl[0] == '.') && (useurl[1] == '/'))
+ useurl += 2; /* just skip the "./" */
- while((useurl[0] == '.') &&
- (useurl[1] == '.') &&
- (useurl[2] == '/')) {
- level++;
- useurl += 3; /* pass the "../" */
- }
+ while((useurl[0] == '.') &&
+ (useurl[1] == '.') &&
+ (useurl[2] == '/')) {
+ level++;
+ useurl += 3; /* pass the "../" */
+ }
- if(protsep) {
- while(level--) {
- /* cut off one more level from the right of the original URL */
- pathsep = strrchr(protsep, '/');
- if(pathsep)
- *pathsep = 0;
- else {
- *protsep = 0;
- break;
+ if(protsep) {
+ while(level--) {
+ /* cut off one more level from the right of the original URL */
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *pathsep = 0;
+ else {
+ *protsep = 0;
+ break;
+ }
}
}
}
+ else
+ skip_slash = TRUE;
}
else {
/* We got a new absolute path for this server */
return result;
/* check if we need to append a slash */
- if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
+ if(('/' == useurl[0]) || (protsep && !*protsep) || skip_slash)
;
else {
result = Curl_dyn_addn(&newest, "/", 1);
}
static const struct redircase set_url_list[] = {
+ {"http://example.org/",
+ "../path/././../../moo",
+ "http://example.org/moo",
+ 0, 0, CURLUE_OK},
+ {"http://example.org/",
+ "//example.org/../path/../../",
+ "http://example.org/",
+ 0, 0, CURLUE_OK},
+ {"http://example.org/",
+ "///example.org/../path/../../",
+ "http://example.org/",
+ 0, 0, CURLUE_OK},
+ {"http://example.org/foo/bar",
+ ":23",
+ "http://example.org/foo/:23",
+ 0, 0, CURLUE_OK},
+ {"http://example.org/foo/bar",
+ "\\x",
+ "http://example.org/foo/\\x",
+ /* WHATWG disagrees */
+ 0, 0, CURLUE_OK},
+ {"http://example.org/foo/bar",
+ "#/",
+ "http://example.org/foo/bar#/",
+ 0, 0, CURLUE_OK},
+ {"http://example.org/foo/bar",
+ "?/",
+ "http://example.org/foo/bar?/",
+ 0, 0, CURLUE_OK},
+ {"http://example.org/foo/bar",
+ "#;?",
+ "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 fragments */
+ 0, 0, CURLUE_OK},
+ {"http://example.org/foo/bar",
+ "?",
+ "http://example.org/foo/bar",
+ /* This happens because the parser removes empty queries */
+ 0, 0, CURLUE_OK},
+ {"http://example.org/foo/bar",
+ "?#",
+ "http://example.org/foo/bar",
+ /* This happens because the parser removes empty queries and fragments */
+ 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",