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 - - -