Changelog
+Daniel Stenberg (1 Jan 2010)
+- Ingmar Runge enhanced libcurl's FTP engine to support the PRET command. This
+ command is a special "hack" used by the drftpd server, but even though it is
+ a custom extension I've deemed it fine to add to libcurl since this server
+ seems to survive and people keep using it and want libcurl to support
+ it. The new libcurl option is named CURLOPT_FTP_USE_PRET, and it is also
+ usable from the curl tool with --ftp-pret. Using this option on a server
+ that doesn't support this command will make libcurl fail.
+
+ I added test cases 1107 and 1108 to verify the functionality.
+
+ The PRET command is documented at
+ http://www.drftpd.org/index.php/Distributed_PASV
+
Yang Tse (30 Dec 2009)
- Steven M. Schweda improved VMS build system, and Craig A. Berry helped
with the patch and testing.
Curl and libcurl 7.20.0
Public curl releases: 114
- Command line options: 134
- curl_easy_setopt() options: 165
+ Command line options: 135
+ curl_easy_setopt() options: 166
Public functions in libcurl: 58
Known libcurl bindings: 39
Contributors: 761
o added support for IMAP, POP3 and SMTP transfers
o added --mail-from and --mail-rcpt for SMTP
o VMS build system enhancements
+ o added support for the PRET ftp command
This release includes the following bugfixes:
Marco Maggi, Camille Moncelier, Claes Jakobsson, Kevin Baughman,
Marc Kleine-Budde, Jad Chamcham, Bjorn Augustsson, David Byron,
Markus Koetter, Chad Monroe, Martin Storsjo, Siegfried Gyuricsko,
- Jon Nelson, Julien Chaffraix, Renato Botelho, Peter Pentchev
+ Jon Nelson, Julien Chaffraix, Renato Botelho, Peter Pentchev, Ingmar Runge
Thanks! (and sorry if I forgot to mention someone)
connection. (Added in 7.14.2)
This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
+.IP "--ftp-pret"
+(FTP) Tell curl to send a PRET command before PASV (and EPSV). Certain
+FTP servers, mainly drftpd, require this non-standard command for
+directory listings as well as up and downloads in PASV mode.
+(Added in 7.20.x)
.IP "--ftp-ssl"
(FTP) Try to use SSL/TLS for the FTP connection. Reverts to a non-secure
connection if the server doesn't support SSL/TLS. See also
pass zero to this option, it will not try using EPSV, only plain PASV.
If the server is an IPv6 host, this option will have no effect as of 7.12.3.
+.IP CURLOPT_FTP_USE_PRET
+Pass a long. If the value is 1, it tells curl to send a PRET command
+before PASV (and EPSV). Certain FTP servers, mainly drftpd, require this
+non-standard command for directory listings as well as up and downloads in
+PASV mode. Has no effect when using the active FTP transfers mode.
+(Added in 7.20.x)
.IP CURLOPT_FTP_CREATE_MISSING_DIRS
Pass a long. If the value is 1, curl will attempt to create any remote
directory that it fails to CWD into. CWD is the command that changes working
.IP "CURLE_FTP_WEIRD_227_FORMAT (14)"
FTP servers return a 227-line as a response to a PASV command. If libcurl
fails to parse that line, this return code is passed back.
+.IP "CURLE_FTP_PRET_FAILED (84)"
+The FTP server does not understand the PRET command at all or does not
+support the given argument. Be careful when using \fICURLOPT_CUSTOMREQUEST\fP,
+a custom LIST command will be sent with PRET CMD before PASV as well.
.IP "CURLE_FTP_CANT_GET_HOST (15)"
An internal failure to lookup the host used for the new connection.
.IP "CURLE_FTP_COULDNT_SET_TYPE (17)"
wrong format (Added in 7.19.0) */
CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in
7.19.0) */
+ CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */
CURL_LAST /* never use! */
} CURLcode;
/* set the SMTP mail receiver(s) */
CINIT(MAIL_RCPT, OBJECTPOINT, 187),
+ /* FTP: send PRET before PASV */
+ CINIT(FTP_USE_PRET, LONG, 188),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
"REST",
"RETR_REST",
"PORT",
+ "PRET",
"PASV",
"LIST",
"RETR",
}
else {
/* We have chosen (this is default) to use the PASV (or similar) command */
- result = ftp_state_use_pasv(conn);
+ if(data->set.ftp_use_pret) {
+ /* The user has requested that we send a PRET command
+ to prepare the server for the upcoming PASV */
+ if(!conn->proto.ftpc.file) {
+ PPSENDF(&conn->proto.ftpc.pp, "PRET %s", data->set.str[STRING_CUSTOMREQUEST]?
+ data->set.str[STRING_CUSTOMREQUEST]:
+ (data->set.ftp_list_only?"NLST":"LIST"));
+ }
+ else if(data->set.upload) {
+ PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
+ }
+ else {
+ PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
+ }
+ state(conn, FTP_PRET);
+ }
+ else {
+ result = ftp_state_use_pasv(conn);
+ }
}
return result;
}
result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
break;
+ case FTP_PRET:
+ if(ftpcode != 200) {
+ /* there only is this one standard OK return code. */
+ failf(data, "PRET command not accepted: %03d", ftpcode);
+ return CURLE_FTP_PRET_FAILED;
+ }
+ result = ftp_state_use_pasv(conn);
+ break;
+
case FTP_PASV:
result = ftp_state_pasv_resp(conn, ftpcode);
break;
FTP_REST, /* when used to check if the server supports it in head-like */
FTP_RETR_REST, /* when asking for "resume" in for RETR */
FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */
+ FTP_PRET, /* generic state for PRET RETR, PRET STOR and PRET LIST/NLST */
FTP_PASV, /* generic state for PASV and EPSV, check count1 */
FTP_LIST, /* generic state for LIST, NLST or a custom list command */
FTP_RETR,
case CURLE_REMOTE_ACCESS_DENIED:
return "Access denied to remote resource";
+ case CURLE_FTP_PRET_FAILED:
+ return "FTP: The server did not accept the PRET command.";
+
case CURLE_FTP_WEIRD_PASS_REPLY:
return "FTP: unknown PASS reply";
set->httpreq = HTTPREQ_GET; /* Default HTTP request */
set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
+ set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
set->ftp_filemethod = FTPFILE_MULTICWD;
set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long));
break;
+ case CURLOPT_FTP_USE_PRET:
+ data->set.ftp_use_pret = (bool)(0 != va_arg(param, long));
+ break;
+
case CURLOPT_FTP_SSL_CCC:
data->set.ftp_ccc = (curl_ftpccc)va_arg(param, long);
break;
bool reuse_fresh; /* do not re-use an existing connection */
bool ftp_use_epsv; /* if EPSV is to be attempted or not */
bool ftp_use_eprt; /* if EPRT is to be attempted or not */
+ bool ftp_use_pret; /* if PRET is to be used before PASV or not */
curl_usessl ftp_ssl; /* if AUTH TLS is to be attempted etc, for FTP or
IMAP or POP3 or others! */
bool resume_from_current;
bool disable_epsv;
bool disable_eprt;
+ bool ftp_pret;
curl_off_t resume_from;
char *postfields;
curl_off_t postfieldsize;
" --ftp-pasv Use PASV/EPSV instead of PORT (F)",
" -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
" --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
+ " --ftp-pret Send PRET before PASV (for drftpd) (F)",
" --ftp-ssl Try SSL/TLS for ftp transfer (F)",
" --ftp-ssl-ccc Send CCC after authenticating (F)",
" --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)",
{"$9", "tftp-blksize", TRUE},
{"$A", "mail-from", TRUE},
{"$B", "mail-rcpt", TRUE},
+ {"$C", "ftp-pret", FALSE},
{"0", "http1.0", FALSE},
{"1", "tlsv1", FALSE},
{"2", "sslv2", FALSE},
if(err)
return err;
break;
+ case 'C': /* --ftp-pret */
+ config->ftp_pret = toggle;
+ break;
}
break;
case '#': /* --progress-bar */
if(config->mail_rcpt)
my_setopt_str(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
+ /* curl 7.20.x */
+ if(config->ftp_pret)
+ my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
+
retry_numretries = config->req_retry;
retrystart = cutil_tvnow();
test1089 test1090 test1091 test1092 test1093 test1094 test1095 test1096 \
test1097 test560 test561 test1098 test1099 test562 test563 test1100 \
test564 test1101 test1102 test1103 test1104 test299 test310 test311 \
- test312 test1105 test565 test800 test1106 test801 test566 test802 test803
+ test312 test1105 test565 test800 test1106 test801 test566 test802 test803 \
+ test1107 test1108
filecheck:
@mkdir test-place; \
--- /dev/null
+<testcase>
+<info>
+<keywords>
+FTP
+PASV
+RETR
+PRET
+</keywords>
+</info>
+# Server-side
+<reply>
+<data>
+data
+ to
+ see
+that FTP
+works
+ so does it?
+</data>
+<servercmd>
+REPLY PRET 200 fine
+</servercmd>
+</reply>
+
+# Client-side
+<client>
+<server>
+ftp
+</server>
+ <name>
+FTP RETR PASV with PRET
+ </name>
+ <command>
+ftp://%HOSTIP:%FTPPORT/1107 --ftp-pret
+</command>
+
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+USER anonymous\r
+PASS ftp@example.com\r
+PWD\r
+PRET RETR 1107\r
+EPSV\r
+TYPE I\r
+SIZE 1107\r
+RETR 1107\r
+QUIT\r
+</protocol>
+</verify>
+</testcase>
--- /dev/null
+<testcase>
+<info>
+<keywords>
+FTP
+PASV
+RETR
+PRET
+</keywords>
+</info>
+# Server-side
+<reply>
+
+<servercmd>
+REPLY PRET 550 unkown command
+</servercmd>
+</reply>
+
+# Client-side
+<client>
+<server>
+ftp
+</server>
+ <name>
+FTP RETR PASV with PRET not supported
+ </name>
+ <command>
+ftp://%HOSTIP:%FTPPORT/1108 --ftp-pret
+</command>
+
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+USER anonymous\r
+PASS ftp@example.com\r
+PWD\r
+PRET RETR 1108\r
+</protocol>
+# we expect that the server doesn't understand PRET
+<errorcode>
+84
+</errorcode>
+</verify>
+</testcase>