tool_operate: for -O, use "default" as filename when the URL has none

... or pick the last directory part from the path if available.

Instead of returning error.

Add test 690 and 691 to verify. Test 76 and 2036 no longer apply.

Closes #13988
This commit is contained in:
Daniel Stenberg 2024-08-03 20:08:27 +02:00
parent cb829f994d
commit e26eefd9ce
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
8 changed files with 165 additions and 85 deletions

View File

@ -35,3 +35,8 @@ There is no URL decoding done on the filename. If it has %20 or other URL
encoded parts of the name, they end up as-is as filename.
You may use this option as many times as the number of URLs you have.
Before curl 8.10.0, curl returned an error if the URL ended with a slash,
which means that there is no filename part in the URL. Starting in 8.10.0,
curl sets the filename to the last directory part of the URL or if that also
is missing to `curl_response` (without extension) for this situation.

View File

@ -1147,9 +1147,13 @@ static CURLcode single_transfer(struct GlobalConfig *global,
break;
}
if(!*per->outfile && !config->content_disposition) {
errorf(global, "Remote filename has no length");
result = CURLE_WRITE_ERROR;
break;
free(per->outfile);
per->outfile = strdup("curl_response");
if(!per->outfile) {
result = CURLE_OUT_OF_MEMORY;
break;
}
warnf(global, "No remote file name, uses \"%s\"", per->outfile);
}
}
else if(state->urls) {

View File

@ -182,7 +182,7 @@ fail:
*/
CURLcode get_url_file_name(char **filename, const char *url)
{
const char *pc, *pc2;
char *pc, *pc2;
CURLU *uh = curl_url();
char *path = NULL;
CURLUcode uerr;
@ -195,20 +195,29 @@ CURLcode get_url_file_name(char **filename, const char *url)
uerr = curl_url_set(uh, CURLUPART_URL, url, CURLU_GUESS_SCHEME);
if(!uerr) {
uerr = curl_url_get(uh, CURLUPART_PATH, &path, 0);
curl_url_cleanup(uh);
uh = NULL;
if(!uerr) {
curl_url_cleanup(uh);
int i;
pc = strrchr(path, '/');
pc2 = strrchr(pc ? pc + 1 : path, '\\');
if(pc2)
pc = pc2;
for(i = 0; i < 2; i++) {
pc = strrchr(path, '/');
pc2 = strrchr(pc ? pc + 1 : path, '\\');
if(pc2)
pc = pc2;
if(pc && !pc[1] && !i) {
/* if the path ends with slash, try removing the trailing one
and get the last directory part */
*pc = 0;
}
}
if(pc)
/* duplicate the string beyond the slash */
pc++;
else
/* no slash => empty string */
pc = "";
pc = (char *)"";
*filename = strdup(pc);
curl_free(path);

View File

@ -33,7 +33,7 @@ test30 test31 test32 test33 test34 test35 test36 test37 test38 test39 \
test40 test41 test42 test43 test44 test45 test46 test47 test48 test49 \
test50 test51 test52 test53 test54 test55 test56 test57 test58 test59 \
test60 test61 test62 test63 test64 test65 test66 test67 test68 test69 \
test70 test71 test72 test73 test74 test75 test76 test77 test78 test79 \
test70 test71 test72 test73 test74 test75 test77 test78 test79 \
test80 test81 test82 test83 test84 test85 test86 test87 test88 test89 \
test90 test91 test92 test93 test94 test95 test96 test97 test98 test99 \
test100 test101 test102 test103 test104 test105 test106 test107 test108 \
@ -100,7 +100,7 @@ test652 test653 test654 test655 test656 test658 test659 test660 test661 \
test662 test663 test664 test665 test666 test667 test668 test669 test670 \
test671 test672 test673 test674 test675 test676 test677 test678 test679 \
test680 test681 test682 test683 test684 test685 test686 test687 test688 \
test689 \
test689 test690 test691 \
\
test700 test701 test702 test703 test704 test705 test706 test707 test708 \
test709 test710 test711 test712 test713 test714 test715 test716 test717 \
@ -238,7 +238,7 @@ test2000 test2001 test2002 test2003 test2004 \
\
test2023 \
test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \
test2032 test2033 test2034 test2035 test2036 test2037 test2038 test2039 \
test2032 test2033 test2034 test2035 test2037 test2038 test2039 \
test2040 test2041 test2042 test2043 test2044 test2045 test2046 test2047 \
test2048 test2049 test2050 test2051 test2052 test2053 test2054 test2055 \
test2056 test2057 test2058 test2059 test2060 test2061 test2062 test2063 \

View File

@ -1,36 +0,0 @@
<testcase>
<info>
<keywords>
FAILURE
</keywords>
</info>
#
# Server-side
<reply>
</reply>
#
# Client-side
<client>
<server>
none
</server>
<features>
http
</features>
<name>
HTTP, -O with no slash at all in the URL
</name>
<command option="no-output">
%HOSTIP:%NOLISTENPORT -O
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<errorcode>
23
</errorcode>
</verify>
</testcase>

67
tests/data/test690 Normal file
View File

@ -0,0 +1,67 @@
<testcase>
<info>
<keywords>
HTTP
HTTP GET
</keywords>
</info>
#
# Server-side
<reply>
<data crlf="yes" nocheck="yes">
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
ETag: "21025-dc7-39462498"
Accept-Ranges: bytes
Content-Length: 6
Connection: close
Content-Type: text/html
Funny-head: yesyes
-foo-
</data>
</reply>
#
# Client-side
<client>
<server>
http
</server>
<name>
-O with URL without path using trailing slash
</name>
<command option="no-output">
http://%HOSTIP:%HTTPPORT/ -O --output-dir %LOGDIR
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<protocol crlf="yes">
GET / HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
</protocol>
<file crlf="yes" name="%LOGDIR/curl_response">
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
ETag: "21025-dc7-39462498"
Accept-Ranges: bytes
Content-Length: 6
Connection: close
Content-Type: text/html
Funny-head: yesyes
-foo-
</file>
</verify>
</testcase>

67
tests/data/test691 Normal file
View File

@ -0,0 +1,67 @@
<testcase>
<info>
<keywords>
HTTP
HTTP GET
</keywords>
</info>
#
# Server-side
<reply>
<data crlf="yes" nocheck="yes">
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
ETag: "21025-dc7-39462498"
Accept-Ranges: bytes
Content-Length: 6
Connection: close
Content-Type: text/html
Funny-head: yesyes
-foo-
</data>
</reply>
#
# Client-side
<client>
<server>
http
</server>
<name>
-O with URL with path using trailing slash
</name>
<command option="no-output">
http://%HOSTIP:%HTTPPORT/path/to/here/ -O --output-dir %LOGDIR
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<protocol crlf="yes">
GET /path/to/here/ HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
</protocol>
<file crlf="yes" name="%LOGDIR/here">
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
ETag: "21025-dc7-39462498"
Accept-Ranges: bytes
Content-Length: 6
Connection: close
Content-Type: text/html
Funny-head: yesyes
-foo-
</file>
</verify>
</testcase>

View File

@ -1,36 +0,0 @@
<testcase>
<info>
<keywords>
FAILURE
</keywords>
</info>
#
# Server-side
<reply>
</reply>
#
# Client-side
<client>
<server>
none
</server>
<features>
http
</features>
<name>
HTTP, -O with no file name part in the URL
</name>
<command option="no-output">
http://%HOSTIP:%NOLISTENPORT/%TESTNUMBER/ -O
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<errorcode>
23
</errorcode>
</verify>
</testcase>