diff --git a/docs/cmdline-opts/remote-name.md b/docs/cmdline-opts/remote-name.md
index 041800fa92..e39dd51aea 100644
--- a/docs/cmdline-opts/remote-name.md
+++ b/docs/cmdline-opts/remote-name.md
@@ -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.
diff --git a/src/tool_operate.c b/src/tool_operate.c
index c56b950a41..017119eab7 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -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) {
diff --git a/src/tool_operhlp.c b/src/tool_operhlp.c
index e2e2d4c3c4..8d356d9e4a 100644
--- a/src/tool_operhlp.c
+++ b/src/tool_operhlp.c
@@ -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);
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index c5a11f5564..d5ed7af56e 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -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 \
diff --git a/tests/data/test2036 b/tests/data/test2036
deleted file mode 100644
index 9fd89a2ac5..0000000000
--- a/tests/data/test2036
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-FAILURE
-
-
-#
-# Server-side
-
-
-
-#
-# Client-side
-
-
-none
-
-
-http
-
-
-HTTP, -O with no slash at all in the URL
-
-
-%HOSTIP:%NOLISTENPORT -O
-
-
-
-#
-# Verify data after the test has been "shot"
-
-
-23
-
-
-
diff --git a/tests/data/test690 b/tests/data/test690
new file mode 100644
index 0000000000..6f333381c0
--- /dev/null
+++ b/tests/data/test690
@@ -0,0 +1,67 @@
+
+
+
+HTTP
+HTTP GET
+
+
+
+#
+# Server-side
+
+
+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-
+
+
+
+#
+# Client-side
+
+
+http
+
+
+-O with URL without path using trailing slash
+
+
+http://%HOSTIP:%HTTPPORT/ -O --output-dir %LOGDIR
+
+
+
+#
+# Verify data after the test has been "shot"
+
+
+GET / HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+User-Agent: curl/%VERSION
+Accept: */*
+
+
+
+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-
+
+
+
diff --git a/tests/data/test691 b/tests/data/test691
new file mode 100644
index 0000000000..b8a9a08af3
--- /dev/null
+++ b/tests/data/test691
@@ -0,0 +1,67 @@
+
+
+
+HTTP
+HTTP GET
+
+
+
+#
+# Server-side
+
+
+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-
+
+
+
+#
+# Client-side
+
+
+http
+
+
+-O with URL with path using trailing slash
+
+
+http://%HOSTIP:%HTTPPORT/path/to/here/ -O --output-dir %LOGDIR
+
+
+
+#
+# Verify data after the test has been "shot"
+
+
+GET /path/to/here/ HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+User-Agent: curl/%VERSION
+Accept: */*
+
+
+
+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-
+
+
+
diff --git a/tests/data/test76 b/tests/data/test76
deleted file mode 100644
index 4c83566dd2..0000000000
--- a/tests/data/test76
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-FAILURE
-
-
-#
-# Server-side
-
-
-
-#
-# Client-side
-
-
-none
-
-
-http
-
-
-HTTP, -O with no file name part in the URL
-
-
-http://%HOSTIP:%NOLISTENPORT/%TESTNUMBER/ -O
-
-
-
-#
-# Verify data after the test has been "shot"
-
-
-23
-
-
-