Monday, July 27, 2015

CFFTP listdir fails when SYST command is disabled on remote FTP server

In this blog article we are going to discuss an issue which prevents CFFTP to display list of folders and files retrieved from FTP server when SYST command is disabled on the remote FTP server.

Let's look at why this issue is happening when SYST command is disabled. CFFTP for listing the directories and files (action="listdir") from the remote FTP server invokes ftp list command. Remote ftp server executes issued list command and sends the directory listing as part of the response. Once CFFTP receives the response it needs to perform the parsing and represent it as a listing. But the parsing of the response depends on the file list layout style of the remote FTP server. FTP provides this information through SYST command using which CFFTP knows how to parse the the listing response.

Many ftp servers disable this SYST command as it reveals the target ftp server information and its OS type.  Then in this case the request for listing will fail. But there is a way to override this behaviour of not calling SYST command with a JVM flag named org.apache.commons.net.ftp.systemType. If this jvm flag is specified with a value which specifies how to parse list command response, SYST command will not be invoked and parsing happens as specified in the JVM flag. But if the CF instance is connecting to multiple remote FTP servers hosted on different operating systems which does not allow SYST command setting this flag will result in errors which lead us to add a new attribute to the CFFTP tag.

A new attribute has been added to CFFTP tag called systemType which specifies how to parse the file list response without invoking SYST command. This attribute is available from CF11 update 3.

Possible values for the attribute are (The same values are also applicable for the JVM flag)
     WINDOWS: if specified CFFTP treats the response as Windows-Style directory listing
      UNIX:  if specified CFFTP treats the response as Unix-Style directory listing
     Also, can specify any class name which implements org.apache.commons.net.ftp.FTPFileEntryParser

The attribute can be set at multiple levels one during the connection open operation or when doing any of the FTP operation like listdir.  If this attribute is set during named ftp connection then the systemtype will be used across all ftp operations  where systemType is left unspecified.

Lets take a look at an example. For this example purpose i am using IIS ftp server and disabled the SYST command as shown in the screenshot.


then ran the below script to retrieve the files from this ftp server.
<cfscript>
ftpService = new ftp(server = "localhost", username = "pavan", password="P#$a12$3", connection="myconn");
files = ftpService.listdir(directory="/", connection="myconn", name="files");
writeDump(files);
files = ftpService.listdir(directory="/sample", connection="myconn", name="files");
writeDump(files);
</cfscript> 
Running the above script thrown the below error saying that the remote ftp server does not allow SYST command



To fix this add the systemtype attribute to the listdir operation and run the example
<cfscript>
ftpService = new ftp(server = "localhost", username = "pavan", password="P#$a12$3", connection="myconn");
files = ftpService.listdir(directory="/", connection="myconn", name="files", systemtype = "WINDOWS");
writeDump(files);
files = ftpService.listdir(directory="/sample", connection="myconn", name="files", systemtype = "WINDOWS");
writeDump(files);
</cfscript>
Now the script executes successfully and returns the listing

This code further can be optimized by specifying the systemtype at the named connection level (then no need to specify at listdir operation)

<cfscript>
ftpService = new ftp(server = "localhost", username = "pavan", password="P#$a12$3", connection="myconn", systemtype = "WINDOWS");
files = ftpService.listdir(directory="/", connection="myconn", name="files");
writeDump(files);
files = ftpService.listdir(directory="/sample", connection="myconn", name="files");
writeDump(files);
</cfscript>
 Here is the order how CFFTP looks for System Type
1) Checks if there is any systemtype specified at the tag/script. If found uses it for parsing
2) Otherwise looks at the JVM flag org.apache.commons.net.ftp.systemType if any value specified uses it.
3) As a last resort invokes SYST command if SYST command is unsuccessful listing fails otherwise listing is successful.

Thanks,
Pavan Kumar.


1 comment :

  1. Really Good blog post.provided a helpful information.I hope that you will post more updates like this.
    Digital marketing company in Chennai

    ReplyDelete