You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2014/12/12 01:57:16 UTC

svn commit: r1644802 - in /commons/proper/net/trunk/src: changes/ main/java/examples/ftp/ main/java/examples/telnet/ main/java/org/apache/commons/net/ftp/ test/java/org/apache/commons/net/ftp/

Author: sebb
Date: Fri Dec 12 00:57:15 2014
New Revision: 1644802

URL: http://svn.apache.org/r1644802
Log:
NET-528 FTPListParseEngine does not provide access to raw responses

Added:
    commons/proper/net/trunk/src/main/java/examples/telnet/TelnetClientScript.java
Modified:
    commons/proper/net/trunk/src/changes/changes.xml
    commons/proper/net/trunk/src/main/java/examples/ftp/FTPClientExample.java
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClient.java
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClientConfig.java
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPFile.java
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java
    commons/proper/net/trunk/src/test/java/org/apache/commons/net/ftp/FTPClientTest.java

Modified: commons/proper/net/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/changes/changes.xml?rev=1644802&r1=1644801&r2=1644802&view=diff
==============================================================================
--- commons/proper/net/trunk/src/changes/changes.xml [utf-8] (original)
+++ commons/proper/net/trunk/src/changes/changes.xml [utf-8] Fri Dec 12 00:57:15 2014
@@ -68,7 +68,10 @@ This is mainly a bug-fix release. See fu
   IMAPExportMbox (example app) allows IMAP folders to be exported into an mbox file.
   This is the inverse of the IMAPImportMbox example added previously
         ">
-            <action issue="NET-565" type="update" dev="sebb">
+            <action issue="NET-528" type="add" dev="sebb">
+            FTPListParseEngine does not provide access to raw responses
+            </action>
+            <action issue="NET-565" type="add" dev="sebb">
             Add FTPClient method to return an FTPFile from an MDTM command
             </action>
             <action issue="NET-564" type="update" dev="sebb">

Modified: commons/proper/net/trunk/src/main/java/examples/ftp/FTPClientExample.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/examples/ftp/FTPClientExample.java?rev=1644802&r1=1644801&r2=1644802&view=diff
==============================================================================
--- commons/proper/net/trunk/src/main/java/examples/ftp/FTPClientExample.java (original)
+++ commons/proper/net/trunk/src/main/java/examples/ftp/FTPClientExample.java Fri Dec 12 00:57:15 2014
@@ -70,7 +70,9 @@ public final class FTPClientExample
         "\t-n - list file names using NLST (remote is used as the pathname if provided)\n" +
         "\t-p true|false|protocol[,true|false] - use FTPSClient with the specified protocol and/or isImplicit setting\n" +
         "\t-s - store file on server (upload)\n" +
+        "\t-S - systemType set server system type (e.g. UNIX VMS WINDOWS)\n" +
         "\t-t - list file details using MLST (remote is used as the pathname if provided)\n" +
+        "\t-U - save unparseable responses\n" +
         "\t-w msec - wait time for keep-alive reply (setControlKeepAliveReplyTimeout)\n" +
         "\t-T  all|valid|none - use one of the built-in TrustManager implementations (none = JVM default)\n" +
         "\t-Z timezone - set the server timezone for parsing LIST responses\n" +
@@ -84,7 +86,7 @@ public final class FTPClientExample
     {
         boolean storeFile = false, binaryTransfer = false, error = false, listFiles = false, listNames = false, hidden = false;
         boolean localActive = false, useEpsvWithIPv4 = false, feat = false, printHash = false;
-        boolean mlst = false, mlsd = false, mdtm = false;
+        boolean mlst = false, mlsd = false, mdtm = false, saveUnparseable = false;
         boolean lenient = false;
         long keepAliveTimeout = -1;
         int controlKeepAliveReplyTimeout = -1;
@@ -101,6 +103,7 @@ public final class FTPClientExample
         String encoding = null;
         String serverTimeZoneId = null;
         String displayTimeZoneId = null;
+        String serverType = null;
 
 
         int base = 0;
@@ -161,10 +164,16 @@ public final class FTPClientExample
             else if (args[base].equals("-p")) {
                 protocol = args[++base];
             }
+            else if (args[base].equals("-S")) {
+                serverType = args[++base];
+            }
             else if (args[base].equals("-t")) {
                 mlst = true;
                 minParams = 3;
             }
+            else if (args[base].equals("-U")) {
+                saveUnparseable = true;
+            }
             else if (args[base].equals("-w")) {
                 controlKeepAliveReplyTimeout = Integer.parseInt(args[++base]);
             }
@@ -281,6 +290,15 @@ public final class FTPClientExample
         // suppress login details
         ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
 
+        final FTPClientConfig config;
+        if (serverType != null) {
+            config = new FTPClientConfig(serverType);
+        } else {
+            config = new FTPClientConfig();            
+        }
+        config.setUnparseableEntries(saveUnparseable);
+        ftp.configure(config);
+
         try
         {
             int reply;
@@ -388,17 +406,20 @@ __main:
                 // Do this last because it changes the client
                 if (listFiles) {
                     if (lenient || serverTimeZoneId != null) {
-                        FTPClientConfig config = new FTPClientConfig();
                         config.setLenientFutureDates(lenient);
                         if (serverTimeZoneId != null) {
                             config.setServerTimeZoneId(serverTimeZoneId);
                         }
                         ftp.configure(config );
                     }
-    
+
                     for (FTPFile f : ftp.listFiles(remote)) {
                         System.out.println(f.getRawListing());
-                        System.out.println(f.toFormattedString(displayTimeZoneId));
+                        if (f.isValid()) {
+                            System.out.println(f.toFormattedString(displayTimeZoneId));
+                        } else {
+                            System.out.println("[Unparseable]");                            
+                        }
                     }
                 }
             }

Added: commons/proper/net/trunk/src/main/java/examples/telnet/TelnetClientScript.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/examples/telnet/TelnetClientScript.java?rev=1644802&view=auto
==============================================================================
--- commons/proper/net/trunk/src/main/java/examples/telnet/TelnetClientScript.java (added)
+++ commons/proper/net/trunk/src/main/java/examples/telnet/TelnetClientScript.java Fri Dec 12 00:57:15 2014
@@ -0,0 +1,75 @@
+package examples.telnet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketTimeoutException;
+
+import org.apache.commons.net.telnet.TelnetClient;
+
+public class TelnetClientScript {
+
+    private final InputStream in;
+    private final OutputStream out;
+    private final TelnetClient telnet = new TelnetClient();
+    TelnetClientScript(String host, int port) throws IOException {
+        telnet.connect(host, port);
+        telnet.setSoTimeout(1000);
+        this.in=telnet.getInputStream();
+        this.out=telnet.getOutputStream();
+    }
+    
+    void login() {
+        
+    }
+    void write(String command) throws IOException {
+        out.write(command.getBytes());
+        out.write('\r');
+        out.write('\n');
+    }
+    
+    void readResponse() {
+        int i;
+        try {
+            while((i=in.read()) != -1){
+                System.out.print((char) i);
+            }
+        } catch (SocketTimeoutException e) {
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+    public static void main(String [] args) throws IOException{
+        if(args.length < 1)
+        {
+            System.err.println("Usage: TelnetClientScriptExample <remote-ip> [<remote-port>]");
+            System.exit(1);
+        }
+
+        String remoteip = args[0];
+
+        int remoteport;
+
+        if (args.length > 1)
+        {
+            remoteport = (new Integer(args[1])).intValue();
+        }
+        else
+        {
+            remoteport = 23;
+        }
+
+        TelnetClientScript script = new TelnetClientScript(remoteip, remoteport);
+        
+        script.login();
+        script.write("INFORMATION");
+        script.readResponse();
+        System.out.println("--------------------");
+        
+        script.write("INFORMATION");
+        script.readResponse();
+        System.out.println("--------------------");
+    }
+
+}

Modified: commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClient.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClient.java?rev=1644802&r1=1644801&r2=1644802&view=diff
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClient.java (original)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClient.java Fri Dec 12 00:57:15 2014
@@ -3361,7 +3361,7 @@ implements Configurable
     {
         Socket socket = _openDataConnection_(FTPCmd.LIST, getListArguments(pathname));
 
-        FTPListParseEngine engine = new FTPListParseEngine(parser);
+        FTPListParseEngine engine = new FTPListParseEngine(parser, __configuration);
         if (socket == null)
         {
             return engine;
@@ -3388,7 +3388,7 @@ implements Configurable
     private FTPListParseEngine initiateMListParsing(String pathname) throws IOException
     {
         Socket socket = _openDataConnection_(FTPCmd.MLSD, pathname);
-        FTPListParseEngine engine = new FTPListParseEngine(MLSxEntryParser.getInstance());
+        FTPListParseEngine engine = new FTPListParseEngine(MLSxEntryParser.getInstance(), __configuration);
         if (socket == null)
         {
             return engine;

Modified: commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClientConfig.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClientConfig.java?rev=1644802&r1=1644801&r2=1644802&view=diff
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClientConfig.java (original)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPClientConfig.java Fri Dec 12 00:57:15 2014
@@ -217,6 +217,7 @@ public class FTPClientConfig
     private String serverLanguageCode = null;
     private String shortMonthNames = null;
     private String serverTimeZoneId = null;
+    private boolean saveUnparseableEntries = false;
 
 
     /**
@@ -583,5 +584,21 @@ public class FTPClientConfig
         return LANGUAGE_CODE_MAP.keySet();
     }
 
+    /**
+     * Allow list parsing methods to create basic FTPFile entries if parsing fails
+     * @param saveUnparseable if true, then create FTPFile entries if parsing fails
+     * @since 3.4
+     */
+    public void setUnparseableEntries(boolean saveUnparseable) {
+        this.saveUnparseableEntries = saveUnparseable;
+    }
+
+    /**
+     * @return true if list parsing should return FTPFile entries even for unparseable response lines
+     * @since 3.4
+     */
+    public boolean getUnparseableEntries() {
+        return this.saveUnparseableEntries;
+    }
 
 }

Modified: commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPFile.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPFile.java?rev=1644802&r1=1644801&r2=1644802&view=diff
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPFile.java (original)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPFile.java Fri Dec 12 00:57:15 2014
@@ -65,13 +65,34 @@ public class FTPFile implements Serializ
     private long _size;
     private String _rawListing, _user, _group, _name, _link;
     private Calendar _date;
+    // If this is null, then list entry parsing failed
     private final boolean[] _permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION]
 
     /*** Creates an empty FTPFile. ***/
     public FTPFile()
     {
         _permissions = new boolean[3][3];
-        _rawListing = null;
+        _type = UNKNOWN_TYPE;
+        // init these to values that do not occur in listings
+        // so can distinguish which fields are unset
+        _hardLinkCount = 0; // 0 is invalid as a link count
+        _size = -1; // 0 is valid, so use -1
+        _user = "";
+        _group = "";
+        _date = null;
+        _name = null;
+    }
+
+    /**
+     * Constructor for use by {@link FTPListParseEngine} only.
+     * Used to create FTPFile entries for failed parses 
+     * @param rawListing line that could not be parsed.
+     * @since 3.4
+     */
+    FTPFile(String rawListing)
+    {
+        _permissions = null; // flag that entry is invalid
+        _rawListing = rawListing;
         _type = UNKNOWN_TYPE;
         // init these to values that do not occur in listings
         // so can distinguish which fields are unset
@@ -151,6 +172,18 @@ public class FTPFile implements Serializ
         return (_type == UNKNOWN_TYPE);
     }
 
+    /**
+     * Used to indicate whether an entry is valid or not.
+     * If the entry is invalid, only the {@link #getRawListing()} method will be useful.
+     * Other methods may fail.
+     * 
+     * Used in conjunction with list parsing that preseverves entries that failed to parse.
+     * @return true if the entry is valid
+     * @since 3.4
+     */
+    public boolean isValid() {
+        return (_permissions != null);        
+    }
 
     /***
      * Set the type of the file (<code>DIRECTORY_TYPE</code>,
@@ -410,6 +443,10 @@ public class FTPFile implements Serializ
      */
     public String toFormattedString(final String timezone)
     {
+        
+        if (!isValid()) {
+            return getRawListing();
+        }
         StringBuilder sb = new StringBuilder();
         Formatter fmt = new Formatter(sb);
         sb.append(formatType());

Modified: commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java?rev=1644802&r1=1644801&r2=1644802&view=diff
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java (original)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java Fri Dec 12 00:57:15 2014
@@ -80,9 +80,24 @@ public class FTPListParseEngine {
     private ListIterator<String> _internalIterator = entries.listIterator();
 
     private final FTPFileEntryParser parser;
+    // Should invalid files (parse failures) be allowed?
+    private final boolean saveUnparseableEntries;
 
     public FTPListParseEngine(FTPFileEntryParser parser) {
+        this(parser, null);
+    }
+
+    /**
+     * Intended for use by FTPClient only
+     * @since 3.4
+     */
+    FTPListParseEngine(FTPFileEntryParser parser, FTPClientConfig configuration) {
         this.parser = parser;
+        if (configuration != null) {
+            this.saveUnparseableEntries = configuration.getUnparseableEntries();
+        } else {
+            this.saveUnparseableEntries = false;
+        }
     }
 
     /**
@@ -164,6 +179,9 @@ public class FTPListParseEngine {
         while (count > 0 && this._internalIterator.hasNext()) {
             String entry = this._internalIterator.next();
             FTPFile temp = this.parser.parseFTPEntry(entry);
+            if (temp == null && saveUnparseableEntries) {
+                temp = new FTPFile(entry);
+            }
             tmpResults.add(temp);
             count--;
         }
@@ -203,6 +221,9 @@ public class FTPListParseEngine {
         while (count > 0 && this._internalIterator.hasPrevious()) {
             String entry = this._internalIterator.previous();
             FTPFile temp = this.parser.parseFTPEntry(entry);
+            if (temp == null && saveUnparseableEntries) {
+                temp = new FTPFile(entry);
+            }
             tmpResults.add(0,temp);
             count--;
         }
@@ -250,6 +271,9 @@ public class FTPListParseEngine {
         while (iter.hasNext()) {
             String entry = iter.next();
             FTPFile temp = this.parser.parseFTPEntry(entry);
+            if (temp == null && saveUnparseableEntries) {
+                temp = new FTPFile(entry);
+            }
             if (filter.accept(temp)){
                 tmpResults.add(temp);
             }

Modified: commons/proper/net/trunk/src/test/java/org/apache/commons/net/ftp/FTPClientTest.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/test/java/org/apache/commons/net/ftp/FTPClientTest.java?rev=1644802&r1=1644801&r2=1644802&view=diff
==============================================================================
--- commons/proper/net/trunk/src/test/java/org/apache/commons/net/ftp/FTPClientTest.java (original)
+++ commons/proper/net/trunk/src/test/java/org/apache/commons/net/ftp/FTPClientTest.java Fri Dec 12 00:57:15 2014
@@ -18,8 +18,12 @@
 
 package org.apache.commons.net.ftp;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
+import org.apache.commons.net.ftp.parser.UnixFTPEntryParser;
+
 import junit.framework.TestCase;
 
 public class FTPClientTest extends TestCase {
@@ -100,4 +104,25 @@ public class FTPClientTest extends TestC
         client.__createParser(null);
         assertSame(entryParser, client.getEntryParser()); // parser was cached
     }
+    public void testUnparseableFiles() throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        baos.write("-rwxr-xr-x   2 root     root         4096 Mar  2 15:13 zxbox".getBytes());
+        baos.write(new byte[]{'\r','\n'});
+        baos.write("zrwxr-xr-x   2 root     root         4096 Mar  2 15:13 zxbox".getBytes());
+        baos.write(new byte[]{'\r','\n'});
+        FTPFileEntryParser parser = new UnixFTPEntryParser();
+        FTPClientConfig config = new FTPClientConfig();
+        FTPListParseEngine engine = new FTPListParseEngine(parser, config);
+        config.setUnparseableEntries(false);
+        engine.readServerList(new ByteArrayInputStream(baos.toByteArray()), null); // use default encoding
+        FTPFile[] files = engine.getFiles();
+        assertEquals(1, files.length);
+        config.setUnparseableEntries(true);
+        engine = new FTPListParseEngine(parser, config );
+        engine.readServerList(new ByteArrayInputStream(baos.toByteArray()), null); // use default encoding
+        files = engine.getFiles();
+        assertEquals(2, files.length);
+    }
+
+
 }