1
votes

I have an annoying problem preventing me to get a file I need in an FTP. This file may have differents names so I need to access the folder first and list files inside to do a request directly to the file then.

My problem is that I can access this file in Filezilla for example, and perfectly discovers the folder as well, but when using an FtpWebResponse instance to get the folder, I have an error 550

550 File unavailable (e.g. file not found, no access)

here is the code :

FtpWebRequest wr = (FtpWebRequest)WebRequest.Create("ftp://ftp.dachser.com/data/edi/kunden/da46168958/out");

wr.Method = WebRequestMethods.Ftp.ListDirectoryDetails;

wr.Credentials = new NetworkCredential("login", "password");

FtpWebResponse response = (FtpWebResponse)wr.GetResponse();

Stream reponseStream = response.GetResponseStream();

StreamReader reader = new StreamReader(reponseStream);

string names = reader.ReadToEnd();

FtpWebResponse response = (FtpWebResponse)wr.GetResponse();

is the line throwing the error

PS: Production, tests and FileZilla are on the same domain, using the same internet connection (if it helps)

Thanks for your attention and feedback

The FileZilla logs:

Logs from my program, error circled in red isn't related to FTP error

2

2 Answers

3
votes

When FtpWebRequest interprets the URL, it does not consider the slash that separates the hostname and the path as a part of the path. The extracted path is then used with FTP CWD command as is. That means that the FTP server will resolve the path relatively to your home directory. If your account is not chrooted (the home is not seen as the root by the client), the lack of the leading slash leads to unexpected behaviour.

In your case, you start in /remote/path and with URL like ftp://example.com/remote/path/, it will try to change to remote/path, so ultimately to /remote/path/remote/path. That's not what you want.

  • Either you must use a relative path to the home folder. What in your case means using an URL without any path.
  • Or use an absolute path, for which you need to use two slashes after the hostname: ftp://example.com//remote/path/.

Also note that an URL to a folder should end with a slash: Why does FtpWebRequest return an empty stream for this existing directory?

For other 550 problems, see FtpWebRequest returns error 550 File unavailable

0
votes

In 2021 this works on both our Linux and Windows live boxes reading from ftp server (both on Windows and Linux)

Note

  • the main folder on the Windows ftp is web
  • the main folder on the Linux ftp is public_html

TL;DR;

  • bottom line: the URL needs to be ended with /

It works:

ftp://ftp.yourdomain.com.br/public_html/
ftp://ftp.yourdomain.com.br//public_html/
ftp://ftp.yourdomain.com.br/web/
ftp://ftp.yourdomain.com.br//web/

It doesn't work:

ftp://ftp.yourdomain.com.br/public_html
ftp://ftp.yourdomain.com.br//public_html
ftp://ftp.yourdomain.com.br/web
ftp://ftp.yourdomain.com.br//web

Usage: //verifiy if the directory public_html does exists

var url = "/public_html/";
var result = FtpUtil.DoesDirectoryExists(url,  "ftp://ftp.yourdomain.com.br", "ftp user here", "ftp password here");

static bool DoesDirectoryExists(string directory, string ftpHost, string ftpUser, string ftpPassword) {
                    FtpWebRequest ftpRequest = null;
                    try {
                            ftpRequest = (FtpWebRequest)WebRequest.Create(new Uri("ftp://" + ftpHost + directory));
                            ftpRequest.Credentials = new NetworkCredential(ftpUser, string ftpPassword);
                            ftpRequest.UseBinary = true;// optional
                            ftpRequest.KeepAlive = false;// optional
                            ftpRequest.UsePassive = true;// optional
                            ftpRequest.Method = WebRequestMethods.Ftp.ListDirectory;
        
                            using (FtpWebResponse response = (FtpWebResponse)ftpRequest.GetResponse()) {
                                return true;//directory found
                            }
                    }
                    catch (WebException ex) {
                            if (ex.Response != null) {
                                FtpWebResponse response = (FtpWebResponse)ex.Response;
                                if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
                                    return false;// directory not found.  
                            }
                            return false; // directory not found.
                    }
                    finally {
                        ftpRequest = null;
                    }
        }