diff --git a/core/pom.xml b/core/pom.xml index ed29fa69..de541e95 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -108,6 +108,19 @@ + + + org.apache.maven.plugins + maven-javadoc-plugin + + + -Xmaxerrs + 65536 + -Xmaxwarns + 65536 + + + diff --git a/core/src/main/java/org/apache/ftpserver/ConnectionConfigFactory.java b/core/src/main/java/org/apache/ftpserver/ConnectionConfigFactory.java index d2f38aee..a42f06d2 100644 --- a/core/src/main/java/org/apache/ftpserver/ConnectionConfigFactory.java +++ b/core/src/main/java/org/apache/ftpserver/ConnectionConfigFactory.java @@ -28,7 +28,6 @@ * */ public class ConnectionConfigFactory { - private int maxLogins = 10; private boolean anonymousLoginEnabled = true; @@ -41,6 +40,13 @@ public class ConnectionConfigFactory { private int maxThreads = 0; + /** + * Create a ConnectionConfigFactory instance + */ + public ConnectionConfigFactory() { + // Nothing to do + } + /** * Create a connection configuration instances based on the configuration on this factory * @return The {@link ConnectionConfig} instance diff --git a/core/src/main/java/org/apache/ftpserver/DataConnectionConfiguration.java b/core/src/main/java/org/apache/ftpserver/DataConnectionConfiguration.java index b7e8c8a5..5a8ec1f1 100644 --- a/core/src/main/java/org/apache/ftpserver/DataConnectionConfiguration.java +++ b/core/src/main/java/org/apache/ftpserver/DataConnectionConfiguration.java @@ -123,6 +123,8 @@ public interface DataConnectionConfiguration { SslConfiguration getSslConfiguration(); /** + * Tells if the connection is implicitely secured + * * @return True if SSL is mandatory for the data channel */ boolean isImplicitSsl(); diff --git a/core/src/main/java/org/apache/ftpserver/DataConnectionConfigurationFactory.java b/core/src/main/java/org/apache/ftpserver/DataConnectionConfigurationFactory.java index 0a092efb..9ada0c90 100644 --- a/core/src/main/java/org/apache/ftpserver/DataConnectionConfigurationFactory.java +++ b/core/src/main/java/org/apache/ftpserver/DataConnectionConfigurationFactory.java @@ -35,7 +35,7 @@ * @author Apache MINA Project */ public class DataConnectionConfigurationFactory { - + /** The class logger */ private Logger log = LoggerFactory.getLogger(DataConnectionConfigurationFactory.class); // maximum idle time in seconds @@ -53,6 +53,12 @@ public class DataConnectionConfigurationFactory { private boolean passiveIpCheck = false; private boolean implicitSsl; + /** + * Public constructor for DataConnectionConfigurationFactory + */ + public DataConnectionConfigurationFactory() { + // Nothing to do + } /** * Create a {@link DataConnectionConfiguration} instance based on the * configuration on this factory @@ -308,6 +314,8 @@ public void setSslConfiguration(SslConfiguration ssl) { } /** + * Tells if the connection is implicitely scured or not + * * @return True if ssl is mandatory for the data connection */ public boolean isImplicitSsl() { diff --git a/core/src/main/java/org/apache/ftpserver/FtpServer.java b/core/src/main/java/org/apache/ftpserver/FtpServer.java index 49da5b5e..6e28f8a3 100644 --- a/core/src/main/java/org/apache/ftpserver/FtpServer.java +++ b/core/src/main/java/org/apache/ftpserver/FtpServer.java @@ -30,10 +30,10 @@ * @author Apache MINA Project */ public interface FtpServer { - /** * Start the server. Open a new listener thread. - * @throws FtpException + * + * @throws FtpException If the server failed to start */ void start() throws FtpException; @@ -44,6 +44,7 @@ public interface FtpServer { /** * Get the server status. + * * @return true if the server is stopped */ boolean isStopped(); @@ -60,8 +61,8 @@ public interface FtpServer { /** * Is the server suspended + * * @return true if the server is suspended */ boolean isSuspended(); - } diff --git a/core/src/main/java/org/apache/ftpserver/Version.java b/core/src/main/java/org/apache/ftpserver/Version.java index db7c4512..eefac9ba 100644 --- a/core/src/main/java/org/apache/ftpserver/Version.java +++ b/core/src/main/java/org/apache/ftpserver/Version.java @@ -24,31 +24,33 @@ import java.io.UncheckedIOException; import java.util.Properties; -import org.apache.ftpserver.util.IoUtils; - /** * Provides the version of this release of FtpServer * * @author Apache MINA Project */ public class Version { + /** + * A private constructor: this class should not be instanciated + */ + private Version() { + // Nothing to do + } /** * Get the version of this FtpServer + * * @return The current version */ public static String getVersion() { - Properties props = new Properties(); - InputStream in = null; - - try { - in = Version.class.getClassLoader().getResourceAsStream("org/apache/ftpserver/ftpserver.properties"); + try (InputStream in = Version.class.getClassLoader(). + getResourceAsStream("org/apache/ftpserver/ftpserver.properties")) { + Properties props = new Properties(); props.load(in); + return props.getProperty("ftpserver.version"); } catch (IOException e) { throw new UncheckedIOException("Failed to read version", e); - } finally { - IoUtils.close(in); } } } diff --git a/core/src/main/java/org/apache/ftpserver/command/AbstractCommand.java b/core/src/main/java/org/apache/ftpserver/command/AbstractCommand.java index bdfd0da8..840abcb4 100644 --- a/core/src/main/java/org/apache/ftpserver/command/AbstractCommand.java +++ b/core/src/main/java/org/apache/ftpserver/command/AbstractCommand.java @@ -26,5 +26,8 @@ * @author Apache MINA Project */ public abstract class AbstractCommand implements Command { - + /** potected constructor */ + protected AbstractCommand() { + // Nothing to do + } } diff --git a/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java b/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java index 5e7af9d8..ec54868b 100644 --- a/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java +++ b/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java @@ -164,13 +164,19 @@ public class CommandFactoryFactory { /** A flag indicating of we have non-default commands */ private boolean useDefaultCommands = true; + /** + * Create a CommandFactoryFactory instance + */ + public CommandFactoryFactory() { + // Nothing to do + } + /** * Create an {@link CommandFactory} based on the configuration on the factory. * * @return The {@link CommandFactory} */ public CommandFactory createCommandFactory() { - Map mergedCommands = new HashMap<>(); if (useDefaultCommands) { diff --git a/core/src/main/java/org/apache/ftpserver/command/NotSupportedCommand.java b/core/src/main/java/org/apache/ftpserver/command/NotSupportedCommand.java index e0eb6409..a1fccf86 100644 --- a/core/src/main/java/org/apache/ftpserver/command/NotSupportedCommand.java +++ b/core/src/main/java/org/apache/ftpserver/command/NotSupportedCommand.java @@ -34,6 +34,12 @@ * @author Apache MINA Project */ public class NotSupportedCommand extends AbstractCommand { + /** + * Create a NotSupportedCommand instance + */ + public NotSupportedCommand() { + super(); + } /** * Execute command @@ -43,7 +49,6 @@ public class NotSupportedCommand extends AbstractCommand { public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/ABOR.java b/core/src/main/java/org/apache/ftpserver/command/impl/ABOR.java index 39bafaaa..9a1ae637 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/ABOR.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/ABOR.java @@ -45,9 +45,12 @@ * @author Apache MINA Project */ public class ABOR extends AbstractCommand { + /** Public constructor */ + public ABOR() { + super(); + } + /** - * Execute command - * * {@inheritDoc} */ public void execute(final FtpIoSession session, diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/ACCT.java b/core/src/main/java/org/apache/ftpserver/command/impl/ACCT.java index 56f430ee..33ec3037 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/ACCT.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/ACCT.java @@ -41,15 +41,17 @@ * @author Apache MINA Project */ public class ACCT extends AbstractCommand { + /** Public constructor */ + public ACCT() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/APPE.java b/core/src/main/java/org/apache/ftpserver/command/impl/APPE.java index 3da784de..20fa549a 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/APPE.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/APPE.java @@ -38,7 +38,6 @@ import org.apache.ftpserver.impl.LocalizedDataTransferFtpReply; import org.apache.ftpserver.impl.LocalizedFtpReply; import org.apache.ftpserver.impl.ServerFtpStatistics; -import org.apache.ftpserver.util.IoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,12 +57,15 @@ * @author Apache MINA Project */ public class APPE extends AbstractCommand { - + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(APPE.class); + /** Public constructor */ + public APPE() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, @@ -71,51 +73,57 @@ public void execute(final FtpIoSession session, throws IOException, FtpException { try { - // reset state variables session.resetState(); // argument check String fileName = request.getArgument(); + if (fileName == null) { - session - .write(LocalizedDataTransferFtpReply + session.write(LocalizedDataTransferFtpReply .translate( session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "APPE", null, null)); + return; } // 24-10-2007 - added check if PORT or PASV is issued, see // https://issues.apache.org/jira/browse/FTPSERVER-110 DataConnectionFactory connFactory = session.getDataConnection(); + if (connFactory instanceof IODataConnectionFactory) { - InetAddress address = ((IODataConnectionFactory) connFactory) - .getInetAddress(); + InetAddress address = ((IODataConnectionFactory) connFactory).getInetAddress(); + if (address == null) { session.write(new DefaultFtpReply( FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "PORT or PASV must be issued first")); + return; } } // get filenames FtpFile file = null; + try { file = session.getFileSystemView().getFile(fileName); } catch (Exception e) { LOG.debug("File system threw exception", e); } + if (file == null) { session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "APPE.invalid", fileName, null)); + return; } + fileName = file.getAbsolutePath(); // check file existance @@ -123,6 +131,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "APPE.invalid", fileName, file)); + return; } @@ -131,6 +140,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "APPE.permission", fileName, file)); + return; } @@ -139,6 +149,7 @@ public void execute(final FtpIoSession session, FtpReply.REPLY_150_FILE_STATUS_OKAY, "APPE", fileName)); DataConnection dataConnection; + try { dataConnection = session.getDataConnection().openConnection(); } catch (Exception e) { @@ -146,24 +157,22 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "APPE", fileName, file)); + return; } // get data from client boolean failure = false; - OutputStream os = null; long transSz = 0L; - try { - // find offset - long offset = 0L; - if (file.doesExist()) { - offset = file.getSize(); - } + // find offset + long offset = 0L; - // open streams - os = file.createOutputStream(offset); + if (file.doesExist()) { + offset = file.getSize(); + } + try (OutputStream os = file.createOutputStream(offset)) { // transfer data transSz = dataConnection.transferFromClient(session.getFtpletSession(), os); @@ -176,8 +185,7 @@ public void execute(final FtpIoSession session, LOG.info("File uploaded {}", fileName); // notify the statistics component - ServerFtpStatistics ftpStat = (ServerFtpStatistics) context - .getFtpStatistics(); + ServerFtpStatistics ftpStat = (ServerFtpStatistics) context.getFtpStatistics(); ftpStat.setUpload(session, file, transSz); } catch (SocketException e) { @@ -189,17 +197,13 @@ public void execute(final FtpIoSession session, } catch (IOException e) { LOG.debug("IOException during file upload", e); failure = true; - session - .write(LocalizedDataTransferFtpReply + session.write(LocalizedDataTransferFtpReply .translate( session, request, context, FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, "APPE", fileName, file)); - } finally { - // make sure we really close the output stream - IoUtils.close(os); } // if data transfer ok - send transfer complete message diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/AUTH.java b/core/src/main/java/org/apache/ftpserver/command/impl/AUTH.java index 8a592f97..bd9f377e 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/AUTH.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/AUTH.java @@ -47,34 +47,55 @@ * @author Apache MINA Project */ public class AUTH extends AbstractCommand { + /** The command name */ + private static final String AUTH_COMMAND = "AUTH"; + /** The MINA filter name */ private static final String SSL_SESSION_FILTER_NAME = "sslSessionFilter"; + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(AUTH.class); - private static final List VALID_AUTH_TYPES = Arrays.asList("SSL", "TLS", "TLS-C", "TLS-P"); + /** SSL authentication type */ + private static final String SSL_TYPE = "SSL"; + + /** TLS authentication type */ + private static final String TLS_TYPE = "TLS"; + + /** TLS authentication type */ + private static final String TLS_C_TYPE = "TLS_C"; + + /** TLS authentication type */ + private static final String TLS_P_TYPE = "TLS_P"; + + /** The valid authentication types */ + private static final List VALID_AUTH_TYPES = Arrays.asList(SSL_TYPE, TLS_TYPE, TLS_C_TYPE, TLS_P_TYPE); + + /** Public constructor */ + public AUTH() { + super(); + } /** - * Execute command - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); // argument check if (!request.hasArgument()) { session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "AUTH", null)); + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, AUTH_COMMAND, null)); + return; } // check SSL configuration if (session.getListener().getSslConfiguration() == null) { - session.write(LocalizedFtpReply.translate(session, request, context, 431, "AUTH", null)); + session.write(LocalizedFtpReply.translate(session, request, context, 431, AUTH_COMMAND, null)); + return; } @@ -93,17 +114,19 @@ public void execute(final FtpIoSession session, final FtpServerContext context, // Here we choose not to support reissued AUTH if (session.getFilterChain().contains(SslFilter.class)) { - session.write(LocalizedFtpReply.translate(session, request, context, 534, "AUTH", null)); + session.write(LocalizedFtpReply.translate(session, request, context, 534, AUTH_COMMAND, null)); + return; } // check parameter String authType = request.getArgument().toUpperCase(); + if (VALID_AUTH_TYPES.contains(authType)) { - if (authType.equals("TLS-C")) { - authType = "TLS"; - } else if (authType.equals("TLS-P")) { - authType = "SSL"; + if (authType.equals(TLS_C_TYPE)) { + authType = TLS_TYPE; + } else if (authType.equals(TLS_P_TYPE)) { + authType = SSL_TYPE; } try { @@ -120,7 +143,7 @@ public void execute(final FtpIoSession session, final FtpServerContext context, } } else { session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_502_COMMAND_NOT_IMPLEMENTED, "AUTH", null)); + FtpReply.REPLY_502_COMMAND_NOT_IMPLEMENTED, AUTH_COMMAND, null)); } } @@ -139,6 +162,7 @@ public void filterWrite(NextFilter next, IoSession session, WriteRequest request } } }; + if (ssl.getClientAuth() == ClientAuth.NEED) { sslFilter.setNeedClientAuth(true); } else if (ssl.getClientAuth() == ClientAuth.WANT) { @@ -148,7 +172,6 @@ public void filterWrite(NextFilter next, IoSession session, WriteRequest request // note that we do not care about the protocol, we allow both types // and leave it to the SSL handshake to determine the protocol to // use. Thus the type argument is ignored. - if (ssl.getEnabledCipherSuites() != null) { sslFilter.setEnabledCipherSuites(ssl.getEnabledCipherSuites()); } @@ -159,7 +182,7 @@ public void filterWrite(NextFilter next, IoSession session, WriteRequest request session.getFilterChain().addFirst(SSL_SESSION_FILTER_NAME, sslFilter); - if ("SSL".equals(type)) { + if (SSL_TYPE.equals(type)) { session.getDataConnection().setSecure(true); } } else { diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/CDUP.java b/core/src/main/java/org/apache/ftpserver/command/impl/CDUP.java index 4397deac..1ddd62a7 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/CDUP.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/CDUP.java @@ -48,30 +48,36 @@ * @author Apache MINA Project */ public class CDUP extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(CDUP.class); + /** Public constructor */ + public CDUP() { + super(); + } + /** - * Execute command. * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); // change directory FileSystemView fsview = session.getFileSystemView(); boolean success = false; + try { success = fsview.changeWorkingDirectory(".."); } catch (Exception ex) { LOG.debug("Failed to change directory in file system", ex); } + FtpFile cwd = fsview.getWorkingDirectory(); + if (success) { String dirName = cwd.getAbsolutePath(); session.write(LocalizedFileActionFtpReply.translate(session, request, context, diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/CWD.java b/core/src/main/java/org/apache/ftpserver/command/impl/CWD.java index a73edaf9..a7135058 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/CWD.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/CWD.java @@ -48,23 +48,26 @@ * @author Apache MINA Project */ public class CWD extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(CWD.class); + /** Public constructor */ + public CWD() { + super(); + } + /** - * Execute command - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); // get new directory name String dirName = "/"; + if (request.hasArgument()) { dirName = request.getArgument(); } @@ -72,12 +75,15 @@ public void execute(final FtpIoSession session, // change directory FileSystemView fsview = session.getFileSystemView(); boolean success = false; + try { success = fsview.changeWorkingDirectory(dirName); } catch (Exception ex) { LOG.debug("Failed to change directory in file system", ex); } + FtpFile cwd = fsview.getWorkingDirectory(); + if (success) { dirName = cwd.getAbsolutePath(); session.write(LocalizedFileActionFtpReply.translate(session, request, context, diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/DELE.java b/core/src/main/java/org/apache/ftpserver/command/impl/DELE.java index 221de0a8..dedf3eb6 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/DELE.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/DELE.java @@ -46,9 +46,14 @@ * @author Apache MINA Project */ public class DELE extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(DELE.class); + /** Public constructor */ + public DELE() { + super(); + } + /** * Execute command. * @@ -67,6 +72,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "DELE", null, null)); + return; } @@ -78,10 +84,12 @@ public void execute(final FtpIoSession session, } catch (Exception ex) { LOG.debug("Could not get file {}", fileName, ex); } + if (file == null) { session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "DELE.invalid", fileName, null)); + return; } @@ -92,6 +100,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "DELE.invalid", fileName, file)); + return; } @@ -99,6 +108,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN, "DELE.permission", fileName, file)); + return; } @@ -114,8 +124,7 @@ public void execute(final FtpIoSession session, LOG.info("File delete : " + userName + " - " + fileName); // notify statistics object - ServerFtpStatistics ftpStat = (ServerFtpStatistics) context - .getFtpStatistics(); + ServerFtpStatistics ftpStat = (ServerFtpStatistics) context.getFtpStatistics(); ftpStat.setDelete(session, file); } else { session.write(LocalizedFileActionFtpReply.translate(session, request, context, @@ -123,5 +132,4 @@ public void execute(final FtpIoSession session, fileName, file)); } } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/EPRT.java b/core/src/main/java/org/apache/ftpserver/command/impl/EPRT.java index 75ce62bf..6b221624 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/EPRT.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/EPRT.java @@ -49,42 +49,48 @@ * @author Apache MINA Project */ public class EPRT extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(EPRT.class); + /** Public constructor */ + public EPRT() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); // argument check String arg = request.getArgument(); + if (arg == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT", null)); + return; } // is port enabled - DataConnectionConfiguration dataCfg = session.getListener() - .getDataConnectionConfiguration(); + DataConnectionConfiguration dataCfg = session.getListener().getDataConnectionConfiguration(); + if (!dataCfg.isActiveEnabled()) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT.disabled", null)); + return; } // parse argument String host = null; String port = null; + try { char delim = arg.charAt(0); int lastDelimIdx = arg.indexOf(delim, 3); @@ -94,34 +100,34 @@ public void execute(final FtpIoSession session, LOG.debug("Exception parsing host and port: {}", arg, ex); session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT", null)); + return; } // get data server InetAddress dataAddr = null; + try { dataAddr = InetAddress.getByName(host); } catch (UnknownHostException ex) { LOG.debug("Unknown host: {}", host, ex); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT.host", null)); + return; } // check IP if (dataCfg.isActiveIpCheck()) { if (session.getRemoteAddress() instanceof InetSocketAddress) { - InetAddress clientAddr = ((InetSocketAddress) session - .getRemoteAddress()).getAddress(); + InetAddress clientAddr = ((InetSocketAddress) session.getRemoteAddress()).getAddress(); + if (!dataAddr.equals(clientAddr)) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT.mismatch", null)); + return; } } @@ -129,23 +135,20 @@ public void execute(final FtpIoSession session, // get data server port int dataPort = 0; + try { dataPort = Integer.parseInt(port); } catch (NumberFormatException ex) { LOG.debug("Invalid port: {}", port, ex); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT.invalid", null)); + return; } - session.getDataConnection().initActiveDataConnection( - new InetSocketAddress(dataAddr, dataPort)); + session.getDataConnection().initActiveDataConnection(new InetSocketAddress(dataAddr, dataPort)); session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_200_COMMAND_OKAY, "EPRT", null)); } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/EPSV.java b/core/src/main/java/org/apache/ftpserver/command/impl/EPSV.java index 9a8fa16f..5337054b 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/EPSV.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/EPSV.java @@ -47,16 +47,19 @@ * @author Apache MINA Project */ public class EPSV extends AbstractCommand { + /** + * A EPSV constructor + */ + public EPSV() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); @@ -64,21 +67,20 @@ public void execute(final FtpIoSession session, ServerDataConnectionFactory dataCon = session.getDataConnection(); try { - InetSocketAddress dataConAddress = dataCon - .initPassiveDataConnection(); + InetSocketAddress dataConAddress = dataCon.initPassiveDataConnection(); + // get connection info int servPort = dataConAddress.getPort(); // send connection info to client String portStr = "|||" + servPort + '|'; - session.write(LocalizedFtpReply.translate(session, request, context, - 229, "EPSV", portStr)); + session.write(LocalizedFtpReply.translate(session, request, context, 229, "EPSV", portStr)); } catch (DataConnectionException e) { - session - .write(LocalizedFtpReply.translate(session, request, context, + session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "EPSV", null)); + return; } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/FEAT.java b/core/src/main/java/org/apache/ftpserver/command/impl/FEAT.java index 25683cae..def035c8 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/FEAT.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/FEAT.java @@ -40,16 +40,17 @@ * @author Apache MINA Project */ public class FEAT extends AbstractCommand { + /** Public constructor */ + public FEAT() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/HELP.java b/core/src/main/java/org/apache/ftpserver/command/impl/HELP.java index b2dbbcf3..4d2a138c 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/HELP.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/HELP.java @@ -46,15 +46,17 @@ * @author Apache MINA Project */ public class HELP extends AbstractCommand { + /** Public constructor */ + public HELP() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); @@ -62,6 +64,7 @@ public void execute(final FtpIoSession session, if (!request.hasArgument()) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_214_HELP_MESSAGE, null, null)); + return; } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/LANG.java b/core/src/main/java/org/apache/ftpserver/command/impl/LANG.java index 08e1105f..0678b557 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/LANG.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/LANG.java @@ -41,6 +41,10 @@ * @author Apache MINA Project */ public class LANG extends AbstractCommand { + /** Public constructor */ + public LANG() { + super(); + } /** * Execute command. @@ -55,10 +59,12 @@ public void execute(final FtpIoSession session, // default language String language = request.getArgument(); + if (language == null) { session.setLanguage(null); session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_200_COMMAND_OKAY, "LANG", null)); + return; } @@ -66,13 +72,14 @@ public void execute(final FtpIoSession session, language = language.toLowerCase(); MessageResource msgResource = context.getMessageResource(); List availableLanguages = msgResource.getAvailableLanguages(); + if (availableLanguages != null) { - for (int i = 0; i < availableLanguages.size(); ++i) { - if (availableLanguages.get(i).equals(language)) { + for (String availableLanguage:availableLanguages) { + if (availableLanguage.equals(language)) { session.setLanguage(language); session.write(LocalizedFtpReply.translate(session, request, - context, FtpReply.REPLY_200_COMMAND_OKAY, "LANG", - null)); + context, FtpReply.REPLY_200_COMMAND_OKAY, "LANG", null)); + return; } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/LIST.java b/core/src/main/java/org/apache/ftpserver/command/impl/LIST.java index 52432002..df8df52e 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/LIST.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/LIST.java @@ -60,16 +60,21 @@ * @author Apache MINA Project */ public class LIST extends AbstractCommand { - + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(LIST.class); + /** The list formatter instance */ private static final LISTFileFormater LIST_FILE_FORMATER = new LISTFileFormater(); + /** The directory lister instance */ private final DirectoryLister directoryLister = new DirectoryLister(); + /** Public constructor */ + public LIST() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, @@ -77,13 +82,11 @@ public void execute(final FtpIoSession session, throws IOException, FtpException { try { - // reset state variables session.resetState(); // parse argument - ListArgument parsedArg = ListArgumentParser.parse(request - .getArgument()); + ListArgument parsedArg = ListArgumentParser.parse(request.getArgument()); // checl that the directory or file exists FtpFile file = session.getFileSystemView().getFile(parsedArg.getFile()); @@ -99,13 +102,15 @@ public void execute(final FtpIoSession session, // 24-10-2007 - added check if PORT or PASV is issued, see // https://issues.apache.org/jira/browse/FTPSERVER-110 DataConnectionFactory connFactory = session.getDataConnection(); + if (connFactory instanceof IODataConnectionFactory) { - InetAddress address = ((IODataConnectionFactory) connFactory) - .getInetAddress(); + InetAddress address = ((IODataConnectionFactory) connFactory).getInetAddress(); + if (address == null) { session.write(new DefaultFtpReply( FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "PORT or PASV must be issued first")); + return; } } @@ -115,6 +120,7 @@ public void execute(final FtpIoSession session, FtpReply.REPLY_150_FILE_STATUS_OKAY, "LIST", null)); DataConnection dataConnection; + try { dataConnection = session.getDataConnection().openConnection(); } catch (Exception e) { @@ -122,11 +128,13 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "LIST", null, file)); + return; } // transfer listing data boolean failure = false; + String dirList = directoryLister.listFiles(parsedArg, session.getFileSystemView(), LIST_FILE_FORMATER); try { @@ -140,23 +148,15 @@ public void execute(final FtpIoSession session, } catch (IOException ex) { LOG.debug("IOException during list transfer", ex); failure = true; - session - .write(LocalizedDataTransferFtpReply - .translate( - session, - request, - context, + session.write(LocalizedDataTransferFtpReply + .translate(session, request, context, FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, "LIST", null, file)); } catch (IllegalArgumentException e) { LOG.debug("Illegal list syntax: " + request.getArgument(), e); // if listing syntax error - send message - session - .write(LocalizedDataTransferFtpReply - .translate( - session, - request, - context, + session.write(LocalizedDataTransferFtpReply + .translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "LIST", null, file)); } @@ -171,5 +171,4 @@ public void execute(final FtpIoSession session, session.getDataConnection().closeDataConnection(); } } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/MD5.java b/core/src/main/java/org/apache/ftpserver/command/impl/MD5.java index c71871ae..03770197 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/MD5.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/MD5.java @@ -32,7 +32,6 @@ import org.apache.ftpserver.impl.FtpIoSession; import org.apache.ftpserver.impl.FtpServerContext; import org.apache.ftpserver.impl.LocalizedFtpReply; -import org.apache.ftpserver.util.IoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,11 +55,15 @@ public class MD5 extends AbstractCommand { /** The MMD5 String constant */ public static final String MMD5 = "MMD5"; + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(MD5.class); + /** Public constructor */ + public MD5() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, @@ -88,6 +91,7 @@ public void execute(final FtpIoSession session, } String[] fileNames = null; + if (isMMD5) { fileNames = argument.split(","); } else { @@ -95,6 +99,7 @@ public void execute(final FtpIoSession session, } StringBuilder sb = new StringBuilder(); + for (int i = 0; i < fileNames.length; i++) { String fileName = fileNames[i].trim(); @@ -108,46 +113,45 @@ public void execute(final FtpIoSession session, } if (file == null) { - session - .write(LocalizedFtpReply + session.write(LocalizedFtpReply .translate( session, request, context, FtpReply.REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER, "MD5.invalid", fileName)); + return; } // check file if (!file.isFile()) { - session - .write(LocalizedFtpReply + session.write(LocalizedFtpReply .translate( session, request, context, FtpReply.REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER, "MD5.invalid", fileName)); + return; } - InputStream is = null; - try { - is = file.createInputStream(0); + try (InputStream is = file.createInputStream(0)) { String md5Hash = md5(is); if (i > 0) { sb.append(", "); } - boolean nameHasSpaces = fileName.indexOf(' ') >= 0; - if (nameHasSpaces) { + + if (fileName.indexOf(' ') >= 0) { sb.append('"'); - } - sb.append(fileName); - if (nameHasSpaces) { + sb.append(fileName); sb.append('"'); + } else { + sb.append(fileName); } + sb.append(' '); sb.append(md5Hash); @@ -156,10 +160,9 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_502_COMMAND_NOT_IMPLEMENTED, "MD5.notimplemened", null)); - } finally { - IoUtils.close(is); } } + if (isMMD5) { session.write(LocalizedFtpReply.translate(session, request, context, 252, MMD5, sb.toString())); @@ -170,8 +173,9 @@ public void execute(final FtpIoSession session, } /** - * @param is - * InputStream for which the MD5 hash is calculated + * Encode a Stream using the MD5 algorithm + * + * @param is InputStream for which the MD5 hash is calculated * @return The hash of the content in the input stream * @throws IOException * @throws NoSuchAlgorithmException @@ -184,6 +188,7 @@ private String md5(InputStream is) throws IOException, byte[] buffer = new byte[1024]; int read = dis.read(buffer); + while (read > -1) { read = dis.read(buffer); } @@ -197,18 +202,16 @@ private String md5(InputStream is) throws IOException, * double the length of the passed array, as it takes two characters to * represent any given byte. * - * @param data - * a byte[] to convert to Hex characters + * @param data a byte[] to convert to Hex characters * @return A char[] containing hexidecimal characters */ public static char[] encodeHex(byte[] data) { + int len = data.length; - int l = data.length; - - char[] out = new char[l << 1]; + char[] out = new char[len << 1]; // two characters form the hex value. - for (int i = 0, j = 0; i < l; i++) { + for (int i = 0, j = 0; i < len; i++) { out[j++] = DIGITS[(0xF0 & data[i]) >>> 4]; out[j++] = DIGITS[0x0F & data[i]]; } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/MDTM.java b/core/src/main/java/org/apache/ftpserver/command/impl/MDTM.java index d37f2e2c..dd8d31e9 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/MDTM.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/MDTM.java @@ -45,46 +45,54 @@ * @author Apache MINA Project */ public class MDTM extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(MDTM.class); + /** MDTM constructor */ + public MDTM() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state session.resetState(); // argument check String fileName = request.getArgument(); + if (fileName == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MDTM", null)); + return; } // get file object FtpFile file = null; + try { file = session.getFileSystemView().getFile(fileName); } catch (Exception ex) { LOG.debug("Exception getting file object", ex); } + if (file == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "MDTM", fileName)); + return; } // now print date fileName = file.getAbsolutePath(); + if (file.doesExist()) { String dateStr = DateUtils.getFtpDate(file.getLastModified()); session.write(LocalizedFtpReply.translate(session, request, context, diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/MFMT.java b/core/src/main/java/org/apache/ftpserver/command/impl/MFMT.java index d90c7a9e..f8e63793 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/MFMT.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/MFMT.java @@ -43,56 +43,49 @@ * @author Apache MINA Project */ public class MFMT extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(MFMT.class); + /** Public constructor */ + public MFMT() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - - // reset state variables session.resetState(); String argument = request.getArgument(); if (argument == null || argument.trim().length() == 0) { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MFMT.invalid", null)); + return; } String[] arguments = argument.split(" ", 2); if (arguments.length != 2) { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MFMT.invalid", null)); + return; } String timestamp = arguments[0].trim(); try { - Date time = DateUtils.parseFTPDate(timestamp); - String fileName = arguments[1].trim(); // get file object @@ -105,27 +98,21 @@ public void execute(final FtpIoSession session, } if (file == null || !file.doesExist()) { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "MFMT.filemissing", fileName)); + return; } // check file if (!file.isFile()) { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MFMT.invalid", null)); + return; } @@ -136,31 +123,24 @@ public void execute(final FtpIoSession session, FtpReply.REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN, "MFMT", fileName)); return; + } // all checks okay, lets go - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_213_FILE_STATUS, "MFMT", "ModifyTime=" + timestamp + "; " + fileName)); + return; } catch (ParseException e) { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MFMT.invalid", null)); + return; } - - } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/MKD.java b/core/src/main/java/org/apache/ftpserver/command/impl/MKD.java index 2bf5eaa4..074f1068 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/MKD.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/MKD.java @@ -47,50 +47,59 @@ * @author Apache MINA Project */ public class MKD extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(MKD.class); + /** Public constructor */ + public MKD() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state session.resetState(); // argument check String fileName = request.getArgument(); + if (fileName == null) { session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MKD", null, null)); + return; } // get file object FtpFile file = null; + try { file = session.getFileSystemView().getFile(fileName); } catch (Exception ex) { LOG.debug("Exception getting file object", ex); } + if (file == null) { session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "MKD.invalid", fileName, file)); + return; } // check permission fileName = file.getAbsolutePath(); + if (!file.isWritable()) { session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "MKD.permission", fileName, file)); + return; } @@ -99,6 +108,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "MKD.exists", fileName, file)); + return; } @@ -112,8 +122,7 @@ public void execute(final FtpIoSession session, LOG.info("Directory create : " + userName + " - " + fileName); // notify statistics object - ServerFtpStatistics ftpStat = (ServerFtpStatistics) context - .getFtpStatistics(); + ServerFtpStatistics ftpStat = (ServerFtpStatistics) context.getFtpStatistics(); ftpStat.setMkdir(session, file); } else { diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/MLSD.java b/core/src/main/java/org/apache/ftpserver/command/impl/MLSD.java index 97513ff7..2a9f9e38 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/MLSD.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/MLSD.java @@ -57,35 +57,39 @@ * @author Apache MINA Project */ public class MLSD extends AbstractCommand { - + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(MLSD.class); + /** The directory lister instance */ private final DirectoryLister directoryLister = new DirectoryLister(); + /** Public constructor */ + public MLSD() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - try { - // reset state session.resetState(); // 24-10-2007 - added check if PORT or PASV is issued, see // https://issues.apache.org/jira/browse/FTPSERVER-110 DataConnectionFactory connFactory = session.getDataConnection(); + if (connFactory instanceof IODataConnectionFactory) { - InetAddress address = ((IODataConnectionFactory) connFactory) - .getInetAddress(); + InetAddress address = ((IODataConnectionFactory) connFactory).getInetAddress(); + if (address == null) { session.write(new DefaultFtpReply( FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "PORT or PASV must be issued first")); + return; } } @@ -96,6 +100,7 @@ public void execute(final FtpIoSession session, // print listing data DataConnection dataConnection; + try { dataConnection = session.getDataConnection().openConnection(); } catch (Exception e) { @@ -103,17 +108,17 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "MLSD", null)); + return; } boolean failure = false; + try { // parse argument - ListArgument parsedArg = ListArgumentParser.parse(request - .getArgument()); + ListArgument parsedArg = ListArgumentParser.parse(request.getArgument()); - FileFormater formater = new MLSTFileFormater((String[]) session - .getAttribute("MLST.types")); + FileFormater formater = new MLSTFileFormater((String[]) session.getAttribute("MLST.types")); dataConnection.transferToClient(session.getFtpletSession(), directoryLister.listFiles( parsedArg, session.getFileSystemView(), formater)); @@ -126,25 +131,16 @@ public void execute(final FtpIoSession session, } catch (IOException ex) { LOG.debug("IOException during data transfer", ex); failure = true; - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, "MLSD", null)); } catch (IllegalArgumentException e) { - LOG - .debug("Illegal listing syntax: " - + request.getArgument(), e); + LOG.debug("Illegal listing syntax: {}", request.getArgument(), e); + // if listing syntax error - send message - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MLSD", null)); } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/MLST.java b/core/src/main/java/org/apache/ftpserver/command/impl/MLST.java index 4b95f47b..6362dc18 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/MLST.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/MLST.java @@ -48,18 +48,19 @@ * @author Apache MINA Project */ public class MLST extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(MLST.class); - /** - * Execute command. - * - * {@inheritDoc} + /** Public constructor */ + public MLST() { + super(); + } + + /** * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); @@ -68,22 +69,18 @@ public void execute(final FtpIoSession session, .parse(request.getArgument()); FtpFile file = null; + try { - file = session.getFileSystemView().getFile( - parsedArg.getFile()); + file = session.getFileSystemView().getFile(parsedArg.getFile()); + if (file != null && file.doesExist()) { - FileFormater formater = new MLSTFileFormater((String[]) session - .getAttribute("MLST.types")); + FileFormater formater = new MLSTFileFormater((String[]) session.getAttribute("MLST.types")); session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_250_REQUESTED_FILE_ACTION_OKAY, "MLST", formater.format(file))); } else { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MLST", null)); } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/MODE.java b/core/src/main/java/org/apache/ftpserver/command/impl/MODE.java index 2a3e21df..4d77cf3f 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/MODE.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/MODE.java @@ -41,16 +41,17 @@ * @author Apache MINA Project */ public class MODE extends AbstractCommand { + /** Public constructor */ + public MODE() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state session.resetState(); @@ -59,27 +60,31 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MODE", null)); + return; } // set mode - char md = request.getArgument().charAt(0); - md = Character.toUpperCase(md); - if (md == 'S') { - session.getDataConnection().setZipMode(false); - session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_200_COMMAND_OKAY, "MODE", "S")); - } else if (md == 'Z') { - session.getDataConnection().setZipMode(true); - session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_200_COMMAND_OKAY, "MODE", "Z")); - } else { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, + switch (request.getArgument().charAt(0)) { + case 's': + case 'S': + session.getDataConnection().setZipMode(false); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_200_COMMAND_OKAY, "MODE", "S")); + + return; + + case 'z': + case 'Z': + session.getDataConnection().setZipMode(true); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_200_COMMAND_OKAY, "MODE", "Z")); + + return; + + default: + session.write(LocalizedFtpReply + .translate(session, request, context, FtpReply.REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER, "MODE", null)); } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/NLST.java b/core/src/main/java/org/apache/ftpserver/command/impl/NLST.java index 6d41e7a3..ced24259 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/NLST.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/NLST.java @@ -58,15 +58,23 @@ * @author Apache MINA Project */ public class NLST extends AbstractCommand { - + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(NLST.class); + /** The NLST formatter */ private static final NLSTFileFormater NLST_FILE_FORMATER = new NLSTFileFormater(); + /** The LIST formatter */ private static final LISTFileFormater LIST_FILE_FORMATER = new LISTFileFormater(); + /** The directory lister */ private final DirectoryLister directoryLister = new DirectoryLister(); + /** Public constructor */ + public NLST() { + super(); + } + /** * Execute command * @@ -75,22 +83,21 @@ public class NLST extends AbstractCommand { public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - try { - // reset state session.resetState(); // 24-10-2007 - added check if PORT or PASV is issued, see // https://issues.apache.org/jira/browse/FTPSERVER-110 DataConnectionFactory connFactory = session.getDataConnection(); + if (connFactory instanceof IODataConnectionFactory) { - InetAddress address = ((IODataConnectionFactory) connFactory) - .getInetAddress(); + InetAddress address = ((IODataConnectionFactory) connFactory).getInetAddress(); + if (address == null) { session.write(new DefaultFtpReply( - FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, - "PORT or PASV must be issued first")); + FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "PORT or PASV must be issued first")); + return; } } @@ -101,23 +108,25 @@ public void execute(final FtpIoSession session, // print listing data DataConnection dataConnection; + try { dataConnection = session.getDataConnection().openConnection(); } catch (Exception e) { LOG.debug("Exception getting the output data stream", e); session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "NLST", - null)); + FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "NLST", null)); + return; } boolean failure = false; + try { // parse argument - ListArgument parsedArg = ListArgumentParser.parse(request - .getArgument()); + ListArgument parsedArg = ListArgumentParser.parse(request.getArgument()); FileFormater formater; + if (parsedArg.hasOption('l')) { formater = LIST_FILE_FORMATER; } else { @@ -130,39 +139,24 @@ public void execute(final FtpIoSession session, LOG.debug("Socket exception during data transfer", ex); failure = true; session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_426_CONNECTION_CLOSED_TRANSFER_ABORTED, - "NLST", null)); + FtpReply.REPLY_426_CONNECTION_CLOSED_TRANSFER_ABORTED, "NLST", null)); } catch (IOException ex) { LOG.debug("IOException during data transfer", ex); failure = true; - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, - "NLST", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, "NLST", null)); } catch (IllegalArgumentException e) { - LOG - .debug("Illegal listing syntax: " + LOG.debug("Illegal listing syntax: " + request.getArgument(), e); // if listing syntax error - send message - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "LIST", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "LIST", null)); } // if data transfer ok - send transfer complete message if (!failure) { session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_226_CLOSING_DATA_CONNECTION, "NLST", - null)); + FtpReply.REPLY_226_CLOSING_DATA_CONNECTION, "NLST", null)); } } finally { session.getDataConnection().closeDataConnection(); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/NOOP.java b/core/src/main/java/org/apache/ftpserver/command/impl/NOOP.java index 8b8251cb..0420f755 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/NOOP.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/NOOP.java @@ -42,16 +42,17 @@ * @author Apache MINA Project */ public class NOOP extends AbstractCommand { + /** Public constructor */ + public NOOP() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - session.resetState(); session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_200_COMMAND_OKAY, "NOOP", null)); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/OPTS.java b/core/src/main/java/org/apache/ftpserver/command/impl/OPTS.java index a778aab9..f17d8072 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/OPTS.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/OPTS.java @@ -46,43 +46,56 @@ * @author Apache MINA Project */ public class OPTS extends AbstractCommand { - + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(OPTS.class); - private static final HashMap COMMAND_MAP = new HashMap<>( - 16); + /** The command map */ + private static final HashMap COMMAND_MAP = new HashMap<>(16); + + // initialize all the OPTS command handlers + static { + COMMAND_MAP.put("OPTS_MLST", new org.apache.ftpserver.command.impl.OPTS_MLST()); + COMMAND_MAP.put("OPTS_UTF8", new org.apache.ftpserver.command.impl.OPTS_UTF8()); + } + + /** Public constructor */ + public OPTS() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state session.resetState(); // no params String argument = request.getArgument(); + if (argument == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "OPTS", null)); + return; } // get request name int spaceIndex = argument.indexOf(' '); + if (spaceIndex != -1) { argument = argument.substring(0, spaceIndex); } + argument = argument.toUpperCase(); // call appropriate command method String optsRequest = "OPTS_" + argument; Command command = COMMAND_MAP.get(optsRequest); + try { if (command != null) { command.execute(session, context, request); @@ -100,12 +113,4 @@ public void execute(final FtpIoSession session, "OPTS", null)); } } - - // initialize all the OPTS command handlers - static { - COMMAND_MAP.put("OPTS_MLST", - new org.apache.ftpserver.command.impl.OPTS_MLST()); - COMMAND_MAP.put("OPTS_UTF8", - new org.apache.ftpserver.command.impl.OPTS_UTF8()); - } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/OPTS_MLST.java b/core/src/main/java/org/apache/ftpserver/command/impl/OPTS_MLST.java index bc6147be..af638d8b 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/OPTS_MLST.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/OPTS_MLST.java @@ -42,18 +42,20 @@ * @author Apache MINA Project */ public class OPTS_MLST extends AbstractCommand { - + /** The existing types */ private static final String[] AVAILABLE_TYPES = { "Size", "Modify", "Type", "Perm" }; + /** Public constructor */ + public OPTS_MLST() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state session.resetState(); @@ -82,19 +84,18 @@ public void execute(final FtpIoSession session, // set the list types String[] validatedTypes = validateSelectedTypes(types); - //if (validatedTypes.length != 0) { - session.setAttribute("MLST.types", validatedTypes); - session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_200_COMMAND_OKAY, "OPTS.MLST", listTypes)); - /*} else { - session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "OPTS.MLST", listTypes)); - }*/ + session.setAttribute("MLST.types", validatedTypes); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_200_COMMAND_OKAY, "OPTS.MLST", listTypes)); } + /** + * Get the valid selected types + * + * @param types The types + * @return The selected types + */ private String[] validateSelectedTypes(String... types) { - // ignore null types if (types == null) { return new String[0]; diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/OPTS_UTF8.java b/core/src/main/java/org/apache/ftpserver/command/impl/OPTS_UTF8.java index a800cc6a..5352811e 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/OPTS_UTF8.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/OPTS_UTF8.java @@ -40,16 +40,17 @@ * @author Apache MINA Project */ public class OPTS_UTF8 extends AbstractCommand { + /** Public constructor */ + public OPTS_UTF8() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state session.resetState(); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/PASS.java b/core/src/main/java/org/apache/ftpserver/command/impl/PASS.java index 48dd1e8a..e97d16e3 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/PASS.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/PASS.java @@ -55,11 +55,15 @@ * @author Apache MINA Project */ public class PASS extends AbstractCommand { + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(PASS.class); + /** Public constructor */ + public PASS() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/PASV.java b/core/src/main/java/org/apache/ftpserver/command/impl/PASV.java index 5bf8c7cc..f70ed752 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/PASV.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/PASV.java @@ -72,18 +72,20 @@ * @author Apache MINA Project */ public class PASV extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(PASV.class); + /** Public constructor */ + public PASV() { + super(); + } + /** - * Execute command - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); @@ -92,11 +94,11 @@ public void execute(final FtpIoSession session, String externalPassiveAddress = getPassiveExternalAddress(session); try { - InetSocketAddress dataConAddress = dataCon.initPassiveDataConnection(); // get connection info InetAddress servAddr; + if (externalPassiveAddress != null) { servAddr = resolveAddress(externalPassiveAddress); } else { @@ -115,15 +117,15 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "PASV", null)); + return; } - } + /* * (non-Javadoc) * Returns an InetAddress object from a hostname or IP address. */ - private InetAddress resolveAddress(String host) throws DataConnectionException { try { return InetAddress.getByName(host); @@ -131,13 +133,14 @@ private InetAddress resolveAddress(String host) throws DataConnectionException { throw new DataConnectionException(ex.getLocalizedMessage(), ex); } } - /* - * (non-Javadoc) + + /** * Returns the server's IP address which will be reported by the PASV response. * + * @param session The FTP session + * @return The passive external address */ protected String getPassiveExternalAddress(final FtpIoSession session) { return session.getListener().getDataConnectionConfiguration().getPassiveExernalAddress(); - } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/PBSZ.java b/core/src/main/java/org/apache/ftpserver/command/impl/PBSZ.java index aaef2a42..32787268 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/PBSZ.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/PBSZ.java @@ -37,16 +37,17 @@ * @author Apache MINA Project */ public class PBSZ extends AbstractCommand { + /** Public constructor */ + public PBSZ() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - session.resetState(); session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_200_COMMAND_OKAY, "PBSZ", null)); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/PORT.java b/core/src/main/java/org/apache/ftpserver/command/impl/PORT.java index fd216f9c..490c8876 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/PORT.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/PORT.java @@ -62,18 +62,20 @@ * @author Apache MINA Project */ public class PORT extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(PORT.class); + /** Public constructor */ + public PORT() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); @@ -82,19 +84,22 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT", null)); + return; } // is port enabled - DataConnectionConfiguration dataCfg = session.getListener() - .getDataConnectionConfiguration(); + DataConnectionConfiguration dataCfg = session.getListener().getDataConnectionConfiguration(); + if (!dataCfg.isActiveEnabled()) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT.disabled", null)); + return; } InetSocketAddress address; + try { address = SocketAddressEncoder.decode(request.getArgument()); @@ -105,40 +110,31 @@ public void execute(final FtpIoSession session, } catch (IllegalInetAddressException e) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT", null)); + return; } catch (IllegalPortException e) { LOG.debug("Invalid data port: {}", request.getArgument(), e); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "PORT.invalid", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT.invalid", null)); + return; } catch (UnknownHostException e) { LOG.debug("Unknown host", e); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "PORT.host", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT.host", null)); + return; } // check IP if (dataCfg.isActiveIpCheck()) { if (session.getRemoteAddress() instanceof InetSocketAddress) { - InetAddress clientAddr = ((InetSocketAddress) session - .getRemoteAddress()).getAddress(); + InetAddress clientAddr = ((InetSocketAddress) session .getRemoteAddress()).getAddress(); + if (!address.getAddress().equals(clientAddr)) { - session.write(LocalizedFtpReply.translate(session, request, - context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "PORT.mismatch", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT.mismatch", null)); + return; } } @@ -148,5 +144,4 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_200_COMMAND_OKAY, "PORT", null)); } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/PROT.java b/core/src/main/java/org/apache/ftpserver/command/impl/PROT.java index b340b726..ae1ea84c 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/PROT.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/PROT.java @@ -40,10 +40,13 @@ * @author Apache MINA Project */ public class PROT extends AbstractCommand { + /** Public constructor */ + public PROT() { + super(); + } private SslConfiguration getSslConfiguration(final FtpIoSession session) { DataConnectionConfiguration dataCfg = session.getListener().getDataConnectionConfiguration(); - SslConfiguration configuration = dataCfg.getSslConfiguration(); // fall back if no configuration has been provided on the data connection config @@ -55,14 +58,11 @@ private SslConfiguration getSslConfiguration(final FtpIoSession session) { } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); @@ -72,12 +72,14 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PROT", null)); + return; } // check argument arg = arg.toUpperCase(); ServerDataConnectionFactory dcon = session.getDataConnection(); + if (arg.equals("C")) { dcon.setSecure(false); session.write(LocalizedFtpReply.translate(session, request, context, @@ -92,15 +94,8 @@ public void execute(final FtpIoSession session, FtpReply.REPLY_200_COMMAND_OKAY, "PROT", null)); } } else { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER, - "PROT", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER, "PROT", null)); } } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/PWD.java b/core/src/main/java/org/apache/ftpserver/command/impl/PWD.java index 612d7819..fe911b6a 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/PWD.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/PWD.java @@ -43,10 +43,12 @@ * @author Apache MINA Project */ public class PWD extends AbstractCommand { + /** Public constructor */ + public PWD() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, @@ -58,5 +60,4 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_257_PATHNAME_CREATED, "PWD", currDir)); } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/QUIT.java b/core/src/main/java/org/apache/ftpserver/command/impl/QUIT.java index 10e52d8e..653da93e 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/QUIT.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/QUIT.java @@ -43,17 +43,19 @@ * @author Apache MINA Project */ public class QUIT extends AbstractCommand { - + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(QUIT.class); + /** Public constructor */ + public QUIT() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, - final FtpServerContext context, final FtpRequest request) - throws IOException { + final FtpServerContext context, final FtpRequest request) throws IOException { session.resetState(); session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_221_CLOSING_CONTROL_CONNECTION, "QUIT", null)); @@ -62,5 +64,4 @@ public void execute(final FtpIoSession session, session.close(false).awaitUninterruptibly(10000); session.getDataConnection().closeDataConnection(); } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/REIN.java b/core/src/main/java/org/apache/ftpserver/command/impl/REIN.java index 9d8548a8..f0b5bdf1 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/REIN.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/REIN.java @@ -41,16 +41,17 @@ * @author Apache MINA Project */ public class REIN extends AbstractCommand { + /** Public constructor */ + public REIN() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - session.reinitialize(); session.setLanguage(null); session.write(LocalizedFtpReply.translate(session, request, context, diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/REST.java b/core/src/main/java/org/apache/ftpserver/command/impl/REST.java index 6dfeb583..5efa29f0 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/REST.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/REST.java @@ -46,62 +46,53 @@ * @author Apache MINA Project */ public class REST extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(REST.class); + /** Public constructor */ + public REST() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // argument check String argument = request.getArgument(); + if (argument == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "REST", null)); + return; } // get offset number session.resetState(); long skipLen = 0L; + try { skipLen = Long.parseLong(argument); // check offset number if (skipLen < 0L) { skipLen = 0L; - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "REST.negetive", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "REST.negetive", null)); } else { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_350_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFORMATION, - "REST", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_350_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFORMATION, "REST", null)); } } catch (NumberFormatException ex) { LOG.debug("Invalid restart position: {}", argument, ex); session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "REST.invalid", null)); + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "REST.invalid", null)); } session.setFileOffset(skipLen); } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/RETR.java b/core/src/main/java/org/apache/ftpserver/command/impl/RETR.java index 21067d01..1ce18cf6 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/RETR.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/RETR.java @@ -40,7 +40,6 @@ import org.apache.ftpserver.impl.LocalizedDataTransferFtpReply; import org.apache.ftpserver.impl.LocalizedFtpReply; import org.apache.ftpserver.impl.ServerFtpStatistics; -import org.apache.ftpserver.util.IoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,9 +58,14 @@ * @author Apache MINA Project */ public class RETR extends AbstractCommand { - + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(RETR.class); + /** Public constructor */ + public RETR() { + super(); + } + /** * Execute command. * @@ -70,37 +74,36 @@ public class RETR extends AbstractCommand { public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - try { - // get state variable long skipLen = session.getFileOffset(); // argument check String fileName = request.getArgument(); if (fileName == null) { - session.write(LocalizedDataTransferFtpReply.translate( - session, - request, - context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "RETR", null, null)); + session.write(LocalizedDataTransferFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "RETR", null, null)); + return; } // get file object FtpFile file = null; + try { file = session.getFileSystemView().getFile(fileName); } catch (Exception ex) { LOG.debug("Exception getting file object", ex); } + if (file == null) { session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "RETR.missing", fileName, file)); + return; } + fileName = file.getAbsolutePath(); // check file existance @@ -108,6 +111,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "RETR.missing", fileName, file)); + return; } @@ -116,6 +120,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "RETR.invalid", fileName, file)); + return; } @@ -124,6 +129,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "RETR.permission", fileName, file)); + return; } @@ -133,13 +139,15 @@ public void execute(final FtpIoSession session, //sense to have this as the first check before checking everything //else such as the file and its permissions. DataConnectionFactory connFactory = session.getDataConnection(); + if (connFactory instanceof IODataConnectionFactory) { - InetAddress address = ((IODataConnectionFactory) connFactory) - .getInetAddress(); + InetAddress address = ((IODataConnectionFactory) connFactory).getInetAddress(); + if (address == null) { session.write(new DefaultFtpReply( FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "PORT or PASV must be issued first")); + return; } } @@ -150,27 +158,26 @@ public void execute(final FtpIoSession session, // send file data to client boolean failure = false; - InputStream is = null; DataConnection dataConnection; + try { dataConnection = session.getDataConnection().openConnection(); } catch (Exception e) { LOG.debug("Exception getting the output data stream", e); session.write(LocalizedDataTransferFtpReply.translate(session, request, context, - FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "RETR", - null, file)); + FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "RETR", null, file)); + return; } long transSz = 0L; - try { - // open streams - is = openInputStream(session, file, skipLen); + try (InputStream is = openInputStream(session, file, skipLen)) { // transfer data transSz = dataConnection.transferToClient(session.getFtpletSession(), is); + // attempt to close the input stream so that errors in // closing it will return an error to the client (FTPSERVER-119) if (is != null) { @@ -180,8 +187,8 @@ public void execute(final FtpIoSession session, LOG.info("File downloaded {}", fileName); // notify the statistics component - ServerFtpStatistics ftpStat = (ServerFtpStatistics) context - .getFtpStatistics(); + ServerFtpStatistics ftpStat = (ServerFtpStatistics) context.getFtpStatistics(); + if (ftpStat != null) { ftpStat.setDownload(session, file, transSz); } @@ -195,17 +202,9 @@ public void execute(final FtpIoSession session, } catch (IOException ex) { LOG.debug("IOException during data transfer", ex); failure = true; - session - .write(LocalizedDataTransferFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, - "RETR", fileName, file, transSz)); - } finally { - // make sure we really close the input stream - IoUtils.close(is); + session.write(LocalizedDataTransferFtpReply .translate(session, request, context, + FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, + "RETR", fileName, file, transSz)); } // if data transfer ok - send transfer complete message @@ -213,7 +212,6 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_226_CLOSING_DATA_CONNECTION, "RETR", fileName, file, transSz)); - } } finally { session.resetState(); @@ -228,18 +226,21 @@ public void execute(final FtpIoSession session, * @param file The file to open * @param skipLen The number of bytes to skip * @return The opened stream + * @throws IOException the stream cannot be opened */ - public InputStream openInputStream(FtpIoSession session, FtpFile file, - long skipLen) throws IOException { + public InputStream openInputStream(FtpIoSession session, FtpFile file, long skipLen) throws IOException { InputStream in; + if (session.getDataType() == DataType.ASCII) { int c; long offset = 0L; in = new BufferedInputStream(file.createInputStream(0L)); + while (offset++ < skipLen) { if ((c = in.read()) == -1) { throw new IOException("Cannot skip"); } + if (c == '\n') { offset++; } @@ -247,7 +248,7 @@ public InputStream openInputStream(FtpIoSession session, FtpFile file, } else { in = file.createInputStream(skipLen); } + return in; } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/RMD.java b/core/src/main/java/org/apache/ftpserver/command/impl/RMD.java index df156f6e..f7857efb 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/RMD.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/RMD.java @@ -47,41 +47,48 @@ * @author Apache MINA Project */ public class RMD extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(RMD.class); + /** Public constructor */ + public RMD() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); // argument check String fileName = request.getArgument(); + if (fileName == null) { session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "RMD", null, null)); + return; } // get file object FtpFile file = null; + try { file = session.getFileSystemView().getFile(fileName); } catch (Exception ex) { LOG.debug("Exception getting file object", ex); } + if (file == null) { session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "RMD.permission", fileName, file)); + return; } @@ -92,16 +99,19 @@ public void execute(final FtpIoSession session, session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "RMD.invalid", fileName, file)); + return; } // then make sure that the client did not request the deletion of // current working directory. FtpFile cwd = session.getFileSystemView().getWorkingDirectory(); + if (file.equals(cwd)) { session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN, "RMD.busy", fileName, file)); + return; } @@ -110,6 +120,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "RMD.permission", fileName, file)); + return; } @@ -124,12 +135,10 @@ public void execute(final FtpIoSession session, LOG.info("Directory remove : " + userName + " - " + fileName); // notify statistics object - ServerFtpStatistics ftpStat = (ServerFtpStatistics) context - .getFtpStatistics(); + ServerFtpStatistics ftpStat = (ServerFtpStatistics) context.getFtpStatistics(); ftpStat.setRmdir(session, file); } else { - session.write(LocalizedFileActionFtpReply.translate(session, request, context, FtpReply.REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN, "RMD", fileName, file)); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/RNFR.java b/core/src/main/java/org/apache/ftpserver/command/impl/RNFR.java index 9790f9a6..2fbeb9b4 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/RNFR.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/RNFR.java @@ -46,32 +46,37 @@ * @author Apache MINA Project */ public class RNFR extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(RNFR.class); + /** Public constructor */ + public RNFR() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variable session.resetState(); // argument check String fileName = request.getArgument(); + if (fileName == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "RNFR", null)); + return; } // get filename FtpFile renFr = null; + try { renFr = session.getFileSystemView().getFile(fileName); } catch (Exception ex) { @@ -86,15 +91,8 @@ public void execute(final FtpIoSession session, } else { session.setRenameFrom(renFr); fileName = renFr.getAbsolutePath(); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_350_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFORMATION, - "RNFR", fileName)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_350_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFORMATION, "RNFR", fileName)); } } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/RNTO.java b/core/src/main/java/org/apache/ftpserver/command/impl/RNTO.java index 491a30aa..5021b3aa 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/RNTO.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/RNTO.java @@ -46,85 +46,75 @@ * @author Apache MINA Project */ public class RNTO extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(RNTO.class); + /** RNTO constructor */ + public RNTO() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { try { - // argument check String toFileStr = request.getArgument(); if (toFileStr == null) { - session - .write(LocalizedRenameFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "RNTO", null, null, null)); + session.write(LocalizedRenameFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "RNTO", null, null, null)); + return; } // get the "rename from" file object FtpFile frFile = session.getRenameFrom(); + if (frFile == null) { session.write(LocalizedRenameFtpReply.translate(session, request, context, FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "RNTO", null, null, null)); + return; } // get target file FtpFile toFile = null; + try { toFile = session.getFileSystemView().getFile(toFileStr); } catch (Exception ex) { LOG.debug("Exception getting file object", ex); } + if (toFile == null) { - session - .write(LocalizedRenameFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, - "RNTO.invalid", null, frFile, toFile)); + session.write(LocalizedRenameFtpReply.translate(session, request, context, + FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, + "RNTO.invalid", null, frFile, toFile)); + return; } + toFileStr = toFile.getAbsolutePath(); // check permission if (!toFile.isWritable()) { - session - .write(LocalizedRenameFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, - "RNTO.permission", null, frFile, toFile)); + session.write(LocalizedRenameFtpReply.translate(session, request, context, + FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, + "RNTO.permission", null, frFile, toFile)); + return; } // check file existence if (!frFile.doesExist()) { - session - .write(LocalizedRenameFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, - "RNTO.missing", null, frFile, toFile)); + session.write(LocalizedRenameFtpReply.translate(session, request, context, + FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, + "RNTO.missing", null, frFile, toFile)); + return; } @@ -140,19 +130,12 @@ public void execute(final FtpIoSession session, LOG.info("File rename from \"{}\" to \"{}\"", logFrFileAbsolutePath, toFile.getAbsolutePath()); } else { - session - .write(LocalizedRenameFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, - "RNTO", toFileStr, frFile, toFile)); + session.write(LocalizedRenameFtpReply.translate(session, request, context, + FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, + "RNTO", toFileStr, frFile, toFile)); } - } finally { session.resetState(); } } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/SITE.java b/core/src/main/java/org/apache/ftpserver/command/impl/SITE.java index 195c5e8e..4c3972ea 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/SITE.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/SITE.java @@ -40,25 +40,30 @@ * @author Apache MINA Project */ public class SITE extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(SITE.class); + /** Public constructor */ + public SITE() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // get request name String argument = request.getArgument(); + if (argument != null) { int spaceIndex = argument.indexOf(' '); + if (spaceIndex != -1) { argument = argument.substring(0, spaceIndex); } + argument = argument.toUpperCase(); } @@ -67,12 +72,14 @@ public void execute(final FtpIoSession session, session.resetState(); session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_200_COMMAND_OKAY, "SITE", null)); + return; } // call appropriate command method String siteRequest = "SITE_" + argument; Command command = context.getCommandFactory().getCommand(siteRequest); + try { if (command != null) { command.execute(session, context, request); @@ -89,6 +96,5 @@ public void execute(final FtpIoSession session, FtpReply.REPLY_500_SYNTAX_ERROR_COMMAND_UNRECOGNIZED, "SITE", null)); } - } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_DESCUSER.java b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_DESCUSER.java index 13e4448a..0166d9c8 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_DESCUSER.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_DESCUSER.java @@ -44,44 +44,52 @@ * @author Apache MINA Project */ public class SITE_DESCUSER extends AbstractCommand { - + /** Class loader */ private final Logger LOG = LoggerFactory.getLogger(SITE_DESCUSER.class); + /** SITE_DESCUSER constructor */ + public SITE_DESCUSER() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); // only administrator can execute this UserManager userManager = context.getUserManager(); boolean isAdmin = userManager.isAdmin(session.getUser().getName()); + if (!isAdmin) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_530_NOT_LOGGED_IN, "SITE", null)); + return; } // get the user name String argument = request.getArgument(); int spIndex = argument.indexOf(' '); + if (spIndex == -1) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "SITE.DESCUSER", null)); + return; } + String userName = argument.substring(spIndex + 1); // check the user existance UserManager usrManager = context.getUserManager(); User user = null; + try { if (usrManager.doesExist(userName)) { user = usrManager.getUserByName(userName); @@ -89,10 +97,12 @@ public void execute(final FtpIoSession session, } catch (FtpException ex) { LOG.debug("Exception trying to get user from user manager", ex); } + if (user == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "SITE.DESCUSER", userName)); + return; } @@ -101,30 +111,23 @@ public void execute(final FtpIoSession session, sb.append("\n"); sb.append("userid : ").append(user.getName()).append("\n"); sb.append("userpassword : ********\n"); - sb.append("homedirectory : ").append(user.getHomeDirectory()).append( - "\n"); - sb.append("writepermission : ").append( - user.authorize(new WriteRequest()) != null).append("\n"); + sb.append("homedirectory : ").append(user.getHomeDirectory()).append("\n"); + sb.append("writepermission : ").append(user.authorize(new WriteRequest()) != null).append("\n"); sb.append("enableflag : ").append(user.getEnabled()).append("\n"); - sb.append("idletime : ").append(user.getMaxIdleTime()).append( - "\n"); + sb.append("idletime : ").append(user.getMaxIdleTime()).append("\n"); TransferRateRequest transferRateRequest = new TransferRateRequest(); - transferRateRequest = (TransferRateRequest) session.getUser() - .authorize(transferRateRequest); + transferRateRequest = (TransferRateRequest) session.getUser().authorize(transferRateRequest); if (transferRateRequest != null) { - sb.append("uploadrate : ").append( - transferRateRequest.getMaxUploadRate()).append("\n"); - sb.append("downloadrate : ").append( - transferRateRequest.getMaxDownloadRate()).append("\n"); + sb.append("uploadrate : ").append(transferRateRequest.getMaxUploadRate()).append("\n"); + sb.append("downloadrate : ").append(transferRateRequest.getMaxDownloadRate()).append("\n"); } else { sb.append("uploadrate : 0\n"); sb.append("downloadrate : 0\n"); } + sb.append('\n'); - session.write(new DefaultFtpReply(FtpReply.REPLY_200_COMMAND_OKAY, sb - .toString())); + session.write(new DefaultFtpReply(FtpReply.REPLY_200_COMMAND_OKAY, sb.toString())); } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_HELP.java b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_HELP.java index 1f761eba..0bd2d1af 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_HELP.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_HELP.java @@ -37,16 +37,17 @@ * @author Apache MINA Project */ public class SITE_HELP extends AbstractCommand { + /** SITE_HELP constructor */ + public SITE_HELP() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); @@ -54,5 +55,4 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_200_COMMAND_OKAY, "SITE.HELP", null)); } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_STAT.java b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_STAT.java index c438dd52..792faade 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_STAT.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_STAT.java @@ -41,25 +41,28 @@ * @author Apache MINA Project */ public class SITE_STAT extends AbstractCommand { + /** SITE_STAT constructor */ + public SITE_STAT() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); // only administrator can execute this UserManager userManager = context.getUserManager(); boolean isAdmin = userManager.isAdmin(session.getUser().getName()); + if (!isAdmin) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_530_NOT_LOGGED_IN, "SITE", null)); + return; } @@ -97,8 +100,6 @@ public void execute(final FtpIoSession session, sb.append("Total Connections : ").append( stat.getTotalConnectionNumber()).append('\n'); sb.append('\n'); - session.write(new DefaultFtpReply(FtpReply.REPLY_200_COMMAND_OKAY, sb - .toString())); + session.write(new DefaultFtpReply(FtpReply.REPLY_200_COMMAND_OKAY, sb.toString())); } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_WHO.java b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_WHO.java index a1e9da7e..af1377d2 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_WHO.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_WHO.java @@ -46,40 +46,41 @@ * @author Apache MINA Project */ public class SITE_WHO extends AbstractCommand { + /** SITE_WHO constructor */ + public SITE_WHO() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); // only administrator can execute this UserManager userManager = context.getUserManager(); boolean isAdmin = userManager.isAdmin(session.getUser().getName()); + if (!isAdmin) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_530_NOT_LOGGED_IN, "SITE", null)); + return; } // print all the connected user information StringBuilder sb = new StringBuilder(); - Map sessions = session.getService() - .getManagedSessions(); + Map sessions = session.getService().getManagedSessions(); sb.append('\n'); Iterator sessionIterator = sessions.values().iterator(); while (sessionIterator.hasNext()) { - FtpIoSession managedSession = new FtpIoSession(sessionIterator - .next(), context); + FtpIoSession managedSession = new FtpIoSession(sessionIterator.next(), context); if (!managedSession.isLoggedIn()) { continue; @@ -93,15 +94,15 @@ public void execute(final FtpIoSession session, .getRemoteAddress()).getAddress().getHostAddress(), ' ', true, 16)); } + sb.append(StringUtils.pad(DateUtils.getISO8601Date(managedSession .getLoginTime().getTime()), ' ', true, 20)); sb.append(StringUtils.pad(DateUtils.getISO8601Date(managedSession .getLastAccessTime().getTime()), ' ', true, 20)); sb.append('\n'); } + sb.append('\n'); - session.write(new DefaultFtpReply(FtpReply.REPLY_200_COMMAND_OKAY, sb - .toString())); + session.write(new DefaultFtpReply(FtpReply.REPLY_200_COMMAND_OKAY, sb.toString())); } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_ZONE.java b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_ZONE.java index 83fd91b7..ea88342e 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/SITE_ZONE.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/SITE_ZONE.java @@ -39,8 +39,14 @@ * @author Apache MINA Project */ public class SITE_ZONE extends AbstractCommand { + /** The date formatter for the time zone. We confine it in a thread local to avoid concurrency troubles */ + private final ThreadLocal formatter = ThreadLocal.withInitial(() -> + new SimpleDateFormat("Z")); - private static final SimpleDateFormat TIMEZONE_FMT = new SimpleDateFormat("Z"); + /** SITE_ZONE constructor */ + public SITE_ZONE() { + super(); + } /** * Execute command. @@ -50,13 +56,12 @@ public class SITE_ZONE extends AbstractCommand { public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); // send timezone data - String timezone = TIMEZONE_FMT.format(new Date()); - session.write(new DefaultFtpReply(FtpReply.REPLY_200_COMMAND_OKAY, - timezone)); + String timezone = formatter.get().format(new Date()); + + session.write(new DefaultFtpReply(FtpReply.REPLY_200_COMMAND_OKAY, timezone)); } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/SIZE.java b/core/src/main/java/org/apache/ftpserver/command/impl/SIZE.java index afb70e71..000875d6 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/SIZE.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/SIZE.java @@ -43,46 +43,55 @@ * @author Apache MINA Project */ public class SIZE extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(SIZE.class); + /** SIZE constructor */ + public SIZE() { + super(); + } + /** - * Execute command. * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - // reset state variables session.resetState(); // argument check String fileName = request.getArgument(); + if (fileName == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "SIZE", null)); + return; } // get file object FtpFile file = null; + try { file = session.getFileSystemView().getFile(fileName); } catch (Exception ex) { LOG.debug("Exception getting file object", ex); } + if (file == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "SIZE.missing", fileName)); + return; } // print file size fileName = file.getAbsolutePath(); + if (!file.doesExist()) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, @@ -97,5 +106,4 @@ public void execute(final FtpIoSession session, FtpReply.REPLY_213_FILE_STATUS, "SIZE", fileLen)); } } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/STAT.java b/core/src/main/java/org/apache/ftpserver/command/impl/STAT.java index 27015fe7..79448587 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/STAT.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/STAT.java @@ -49,20 +49,23 @@ * @author Apache MINA Project */ public class STAT extends AbstractCommand { - + /** The list file formatter */ private static final LISTFileFormater LIST_FILE_FORMATER = new LISTFileFormater(); + /** The directory listener */ private final DirectoryLister directoryLister = new DirectoryLister(); + /** STAT constructor */ + public STAT() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); @@ -71,12 +74,15 @@ public void execute(final FtpIoSession session, // check that the directory or file exists FtpFile file = null; + try { file = session.getFileSystemView().getFile(parsedArg.getFile()); + if (!file.doesExist()) { session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN, "LIST", null, file)); + return; } @@ -84,6 +90,7 @@ public void execute(final FtpIoSession session, session.getFileSystemView(), LIST_FILE_FORMATER); int replyCode; + if (file.isDirectory()) { replyCode = FtpReply.REPLY_212_DIRECTORY_STATUS; } else { @@ -94,14 +101,8 @@ public void execute(final FtpIoSession session, replyCode, "STAT", dirList, file)); } catch (FtpException e) { - session - .write(LocalizedFileActionFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN, - "STAT", null, file)); + session.write(LocalizedFileActionFtpReply.translate(session, request, context, + FtpReply.REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN, "STAT", null, file)); } } else { @@ -110,5 +111,4 @@ public void execute(final FtpIoSession session, FtpReply.REPLY_211_SYSTEM_STATUS_REPLY, "STAT", null)); } } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/STOR.java b/core/src/main/java/org/apache/ftpserver/command/impl/STOR.java index abf3cc6a..bcf1df07 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/STOR.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/STOR.java @@ -38,7 +38,6 @@ import org.apache.ftpserver.impl.LocalizedDataTransferFtpReply; import org.apache.ftpserver.impl.LocalizedFtpReply; import org.apache.ftpserver.impl.ServerFtpStatistics; -import org.apache.ftpserver.util.IoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,9 +57,14 @@ * @author Apache MINA Project */ public class STOR extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(STOR.class); + /** rNSTORTO constructor */ + public STOR() { + super(); + } + /** * Execute command. * @@ -69,53 +73,53 @@ public class STOR extends AbstractCommand { public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - try { - // get state variable long skipLen = session.getFileOffset(); // argument check String fileName = request.getArgument(); + if (fileName == null) { - session - .write(LocalizedDataTransferFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "STOR", null, null)); + session.write(LocalizedDataTransferFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "STOR", null, null)); + return; } // 24-10-2007 - added check if PORT or PASV is issued, see // https://issues.apache.org/jira/browse/FTPSERVER-110 DataConnectionFactory connFactory = session.getDataConnection(); + if (connFactory instanceof IODataConnectionFactory) { - InetAddress address = ((IODataConnectionFactory) connFactory) - .getInetAddress(); + InetAddress address = ((IODataConnectionFactory) connFactory).getInetAddress(); + if (address == null) { session.write(new DefaultFtpReply( FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "PORT or PASV must be issued first")); + return; } } // get filename FtpFile file = null; + try { file = session.getFileSystemView().getFile(fileName); } catch (Exception ex) { LOG.debug("Exception getting file object", ex); } + if (file == null) { session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "STOR.invalid", fileName, file)); + return; } + fileName = file.getAbsolutePath(); // get permission @@ -123,16 +127,17 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "STOR.permission", fileName, file)); + return; } // get data connection - session.write( - LocalizedFtpReply.translate(session, request, context, + session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_150_FILE_STATUS_OKAY, "STOR", fileName)).awaitUninterruptibly(10000); DataConnection dataConnection; + try { dataConnection = session.getDataConnection().openConnection(); } catch (Exception e) { @@ -140,15 +145,15 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "STOR", fileName, file)); + return; } // transfer data boolean failure = false; - OutputStream outStream = null; long transSz = 0L; - try { - outStream = file.createOutputStream(skipLen); + + try (OutputStream outStream = file.createOutputStream(skipLen)) { transSz = dataConnection.transferFromClient(session.getFtpletSession(), outStream); // attempt to close the output stream so that errors in @@ -160,10 +165,8 @@ public void execute(final FtpIoSession session, LOG.info("File uploaded {}", fileName); // notify the statistics component - ServerFtpStatistics ftpStat = (ServerFtpStatistics) context - .getFtpStatistics(); + ServerFtpStatistics ftpStat = (ServerFtpStatistics) context.getFtpStatistics(); ftpStat.setUpload(session, file, transSz); - } catch (SocketException ex) { LOG.debug("Socket exception during data transfer", ex); failure = true; @@ -173,17 +176,8 @@ public void execute(final FtpIoSession session, } catch (IOException ex) { LOG.debug("IOException during data transfer", ex); failure = true; - session - .write(LocalizedDataTransferFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, - "STOR", fileName, file)); - } finally { - // make sure we really close the output stream - IoUtils.close(outStream); + session.write(LocalizedDataTransferFtpReply.translate(session, request, context, + FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, "STOR", fileName, file)); } // if data transfer ok - send transfer complete message @@ -191,7 +185,6 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_226_CLOSING_DATA_CONNECTION, "STOR", fileName, file, transSz)); - } } finally { session.resetState(); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/STOU.java b/core/src/main/java/org/apache/ftpserver/command/impl/STOU.java index 6ae9ecc9..19b73629 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/STOU.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/STOU.java @@ -38,7 +38,6 @@ import org.apache.ftpserver.impl.IODataConnectionFactory; import org.apache.ftpserver.impl.LocalizedDataTransferFtpReply; import org.apache.ftpserver.impl.ServerFtpStatistics; -import org.apache.ftpserver.util.IoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,47 +56,52 @@ * @author Apache MINA Project */ public class STOU extends AbstractCommand { - + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(STOU.class); + /** Public constructor */ + public STOU() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - try { // 24-10-2007 - added check if PORT or PASV is issued, see // https://issues.apache.org/jira/browse/FTPSERVER-110 DataConnectionFactory connFactory = session.getDataConnection(); + if (connFactory instanceof IODataConnectionFactory) { - InetAddress address = ((IODataConnectionFactory) connFactory) - .getInetAddress(); + InetAddress address = ((IODataConnectionFactory) connFactory).getInetAddress(); + if (address == null) { session.write(new DefaultFtpReply( FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "PORT or PASV must be issued first")); + return; } } // reset state variables session.resetState(); - String pathName = request.getArgument(); // get filenames FtpFile file = null; + try { String filePrefix; + if (pathName == null) { filePrefix = "ftp.dat"; } else { - FtpFile dir = session.getFileSystemView().getFile( - pathName); + FtpFile dir = session.getFileSystemView().getFile(pathName); + if (dir.isDirectory()) { filePrefix = pathName + "/ftp.dat"; } else { @@ -106,6 +110,7 @@ public void execute(final FtpIoSession session, } file = session.getFileSystemView().getFile(filePrefix); + if (file != null) { file = getUniqueFile(session, file); } @@ -117,8 +122,10 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "STOU", null, null)); + return; } + String fileName = file.getAbsolutePath(); // check permission @@ -126,18 +133,18 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_550_REQUESTED_ACTION_NOT_TAKEN, "STOU.permission", fileName, file)); + return; } // get data connection - session.write(new DefaultFtpReply( - FtpReply.REPLY_150_FILE_STATUS_OKAY, "FILE: " + fileName)); + session.write(new DefaultFtpReply(FtpReply.REPLY_150_FILE_STATUS_OKAY, "FILE: " + fileName)); // get data from client boolean failure = false; - OutputStream os = null; DataConnection dataConnection; + try { dataConnection = session.getDataConnection().openConnection(); } catch (Exception e) { @@ -145,29 +152,25 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_425_CANT_OPEN_DATA_CONNECTION, "STOU", fileName, file)); + return; } long transSz = 0L; - try { - - // open streams - os = file.createOutputStream(0L); + try (OutputStream os = file.createOutputStream(0L)) { // transfer data transSz = dataConnection.transferFromClient(session.getFtpletSession(), os); // attempt to close the output stream so that errors in // closing it will return an error to the client (FTPSERVER-119) - if (os != null) { - os.close(); - } + os.close(); LOG.info("File uploaded {}", fileName); // notify the statistics component - ServerFtpStatistics ftpStat = (ServerFtpStatistics) context - .getFtpStatistics(); + ServerFtpStatistics ftpStat = (ServerFtpStatistics) context.getFtpStatistics(); + if (ftpStat != null) { ftpStat.setUpload(session, file, transSz); } @@ -181,17 +184,8 @@ public void execute(final FtpIoSession session, } catch (IOException ex) { LOG.debug("IOException during data transfer", ex); failure = true; - session - .write(LocalizedDataTransferFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, - "STOU", fileName, file)); - } finally { - // make sure we really close the output stream - IoUtils.close(os); + session.write(LocalizedDataTransferFtpReply.translate(session, request, context, + FtpReply.REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN, "STOU", fileName, file)); } // if data transfer ok - send transfer complete message @@ -199,7 +193,6 @@ public void execute(final FtpIoSession session, session.write(LocalizedDataTransferFtpReply.translate(session, request, context, FtpReply.REPLY_226_CLOSING_DATA_CONNECTION, "STOU", fileName, file, transSz)); - } } finally { session.getDataConnection().closeDataConnection(); @@ -208,22 +201,27 @@ public void execute(final FtpIoSession session, } /** - * Get unique file object. + * Get unique file object based on a given file. + * + * @param session The FTP Session + * @param oldFile The file which name is used to create the new file + * @return A new file that does not exist on the file system + * @throws FtpException If a new unique file can't be created */ //TODO may need synchronization - protected FtpFile getUniqueFile(FtpIoSession session, FtpFile oldFile) - throws FtpException { + protected FtpFile getUniqueFile(FtpIoSession session, FtpFile oldFile) throws FtpException { FtpFile newFile = oldFile; FileSystemView fsView = session.getFileSystemView(); String fileName = newFile.getAbsolutePath(); + while (newFile.doesExist()) { - newFile = fsView.getFile(fileName + '.' - + System.currentTimeMillis()); + newFile = fsView.getFile(fileName + '.' + System.currentTimeMillis()); + if (newFile == null) { break; } } + return newFile; } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/STRU.java b/core/src/main/java/org/apache/ftpserver/command/impl/STRU.java index 4d231b82..079727cc 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/STRU.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/STRU.java @@ -43,12 +43,15 @@ * @author Apache MINA Project */ public class STRU extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(STRU.class); + /** STRU constructor */ + public STRU() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, @@ -63,28 +66,21 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "STRU", null)); + return; } // set structure char stru = request.getArgument().charAt(0); + try { session.setStructure(Structure.parseArgument(stru)); session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_200_COMMAND_OKAY, "STRU", null)); } catch (IllegalArgumentException e) { - LOG - .debug("Illegal structure argument: " - + request.getArgument(), e); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER, - "STRU", null)); + LOG.debug("Illegal structure argument: {}", request.getArgument(), e); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER, "STRU", null)); } } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/SYST.java b/core/src/main/java/org/apache/ftpserver/command/impl/SYST.java index 3b80e770..14333976 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/SYST.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/SYST.java @@ -40,28 +40,31 @@ * @author Apache MINA Project */ public class SYST extends AbstractCommand { + /** SYST constructor */ + public SYST() { + super(); + } /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); // get server system info String systemName = System.getProperty("os.name"); + if (systemName == null) { systemName = "UNKNOWN"; } else { systemName = systemName.toUpperCase(); systemName = systemName.replace(' ', '-'); } - // print server system info + + // print server system info session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_215_NAME_SYSTEM_TYPE, "SYST", systemName)); } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/TYPE.java b/core/src/main/java/org/apache/ftpserver/command/impl/TYPE.java index 214a1551..50746804 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/TYPE.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/TYPE.java @@ -42,35 +42,32 @@ * @author Apache MINA Project */ public class TYPE extends AbstractCommand { - + /** Cass logger */ private final Logger LOG = LoggerFactory.getLogger(TYPE.class); + /** TYPE constructor */ + public TYPE() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ - public void execute(final FtpIoSession session, - final FtpServerContext context, final FtpRequest request) + public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException { - // reset state variables session.resetState(); // get type from argument char type; + if (request.hasArgument()) { type = request.getArgument().charAt(0); } else { // no type specified - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "TYPE", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "TYPE", null)); + return; } @@ -81,15 +78,8 @@ public void execute(final FtpIoSession session, FtpReply.REPLY_200_COMMAND_OKAY, "TYPE", null)); } catch (IllegalArgumentException e) { LOG.debug("Illegal type argument: {}", request.getArgument(), e); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER, - "TYPE", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER, "TYPE", null)); } } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/USER.java b/core/src/main/java/org/apache/ftpserver/command/impl/USER.java index 6fdaa491..ec12fc3f 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/USER.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/USER.java @@ -52,21 +52,22 @@ * @author Apache MINA Project */ public class USER extends AbstractCommand { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(USER.class); + /** USER constructor */ + public USER() { + super(); + } + /** - * Execute command. - * * {@inheritDoc} */ public void execute(final FtpIoSession session, final FtpServerContext context, final FtpRequest request) throws IOException, FtpException { - boolean success = false; - ServerFtpStatistics stat = (ServerFtpStatistics) context - .getFtpStatistics(); + ServerFtpStatistics stat = (ServerFtpStatistics) context.getFtpStatistics(); try { // reset state variables @@ -75,14 +76,9 @@ public void execute(final FtpIoSession session, // argument check String userName = request.getArgument(); if (userName == null) { - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, - "USER", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "USER", null)); + return; } @@ -91,6 +87,7 @@ public void execute(final FtpIoSession session, // already logged-in User user = session.getUser(); + if (session.isLoggedIn()) { if (userName.equals(user.getName())) { session.write(LocalizedFtpReply.translate(session, request, @@ -101,40 +98,37 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, 530, "USER.invalid", null)); } + return; } // anonymous login is not enabled boolean anonymous = userName.equals("anonymous"); - if (anonymous - && (!context.getConnectionConfig() - .isAnonymousLoginEnabled())) { + + if (anonymous && (!context.getConnectionConfig().isAnonymousLoginEnabled())) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_530_NOT_LOGGED_IN, "USER.anonymous", null)); + return; } // anonymous login limit check int currAnonLogin = stat.getCurrentAnonymousLoginNumber(); - int maxAnonLogin = context.getConnectionConfig() - .getMaxAnonymousLogins(); + int maxAnonLogin = context.getConnectionConfig().getMaxAnonymousLogins(); + if (maxAnonLogin == 0) { LOG.debug("Currently {} anonymous users logged in, unlimited allowed", currAnonLogin); } else { LOG.debug("Currently {} out of {} anonymous users logged in", currAnonLogin, maxAnonLogin); } + if (anonymous && (currAnonLogin >= maxAnonLogin)) { LOG.debug("Too many anonymous users logged in, user will be disconnected"); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_421_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION, - "USER.anonymous", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_421_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION, "USER.anonymous", null)); + return; } @@ -151,25 +145,19 @@ public void execute(final FtpIoSession session, if (maxLogin != 0 && currLogin >= maxLogin) { LOG.debug("Too many users logged in, user will be disconnected"); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_421_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION, - "USER.login", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_421_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION, "USER.login", null)); return; } User configUser = context.getUserManager().getUserByName(userName); + if (configUser != null) { // user login limit check - InetAddress address = null; + if (session.getRemoteAddress() instanceof InetSocketAddress) { - address = ((InetSocketAddress) session.getRemoteAddress()) - .getAddress(); + address = ((InetSocketAddress) session.getRemoteAddress()).getAddress(); } ConcurrentLoginRequest loginRequest = new ConcurrentLoginRequest( @@ -178,14 +166,9 @@ public void execute(final FtpIoSession session, if (configUser.authorize(loginRequest) == null) { LOG.debug("User logged in too many sessions, user will be disconnected"); - session - .write(LocalizedFtpReply - .translate( - session, - request, - context, - FtpReply.REPLY_421_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION, - "USER.login", null)); + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_421_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION, "USER.login", null)); + return; } } @@ -193,6 +176,7 @@ public void execute(final FtpIoSession session, // finally set the user name success = true; session.setUserArgument(userName); + if (anonymous) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_331_USER_NAME_OKAY_NEED_PASSWORD, @@ -203,7 +187,6 @@ public void execute(final FtpIoSession session, "USER", userName)); } } finally { - // if not ok - close connection if (!success) { LOG.debug("User failed to login, session will be closed"); diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/DirectoryLister.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/DirectoryLister.java index 3c7c6d7a..37020111 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/DirectoryLister.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/DirectoryLister.java @@ -35,6 +35,13 @@ * @author Apache MINA Project */ public class DirectoryLister { + /** + * Create a DirectoryLister instance + */ + public DirectoryLister() { + // Nothing to do + } + private String traverseFiles(final List files, final FileFilter filter, final FileFormater formater) { @@ -50,6 +57,7 @@ private String traverseFiles(final List files, final FileFilter filter, final FileFormater formater, boolean matchDirs) { StringBuilder sb = new StringBuilder(); + for (FtpFile file : files) { if (file == null) { continue; @@ -65,19 +73,30 @@ private String traverseFiles(final List files, return sb.toString(); } + /** + * Get the list of existing files in the directory + * + * @param argument The command arguments + * @param fileSystemView The underlaying file system + * @param formater The formatter to use to represent the found list + * @return A list of found files + * @throws IOException Not actually thrown... To be removed + */ public String listFiles(final ListArgument argument, final FileSystemView fileSystemView, final FileFormater formater) throws IOException { - StringBuilder sb = new StringBuilder(); // get all the file objects List files = listFiles(fileSystemView, argument.getFile()); + if (files != null) { FileFilter filter = null; + if (!argument.hasOption('a')) { filter = new VisibleFileFilter(); } + if (argument.getPattern() != null) { filter = new RegexFileFilter(argument.getPattern(), filter); } @@ -97,7 +116,9 @@ public String listFiles(final ListArgument argument, */ private List listFiles(FileSystemView fileSystemView, String file) { List files = null; + try { + FtpFile virtualFile = fileSystemView.getFile(file); if (virtualFile.isFile()) { List auxFiles = new ArrayList<>(); @@ -108,6 +129,7 @@ private List listFiles(FileSystemView fileSystemView, String } } catch (FtpException ex) { } + return files; } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/LISTFileFormater.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/LISTFileFormater.java index 396b7ae5..a9cf2d58 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/LISTFileFormater.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/LISTFileFormater.java @@ -22,23 +22,26 @@ import org.apache.ftpserver.ftplet.FtpFile; import org.apache.ftpserver.util.DateUtils; +import org.apache.ftpserver.util.StringUtils; /** * Internal class, do not use directly. - * + *

* Formats files according to the LIST specification * * @author Apache MINA Project */ public class LISTFileFormater implements FileFormater { - + /** The delimiter, default to space */ private static final char DELIM = ' '; - private static final char[] NEWLINE = { '\r', '\n' }; - /** - * @see FileFormater#format(FtpFile) - * + * Create a LISTFileFormater insance + */ + public LISTFileFormater() { + // Nothing to do + } + /** * {@inheritDoc} */ public String format(FtpFile file) { @@ -58,7 +61,7 @@ public String format(FtpFile file) { sb.append(getLastModified(file)); sb.append(DELIM); sb.append(file.getName()); - sb.append(NEWLINE); + sb.append(StringUtils.NEWLINE); return sb.toString(); } @@ -69,13 +72,17 @@ public String format(FtpFile file) { private String getLength(FtpFile file) { String initStr = " "; long sz = 0; + if (file.isFile()) { sz = file.getSize(); } + String szStr = String.valueOf(sz); + if (szStr.length() > initStr.length()) { return szStr; } + return initStr.substring(0, initStr.length() - szStr.length()) + szStr; } @@ -97,6 +104,7 @@ private char[] getPermission(FtpFile file) { permission[1] = file.isReadable() ? 'r' : '-'; permission[2] = file.isWritable() ? 'w' : '-'; permission[3] = file.isDirectory() ? 'x' : '-'; + return permission; } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/ListArgument.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/ListArgument.java index 6370b851..cd8574e1 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/ListArgument.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/ListArgument.java @@ -20,7 +20,7 @@ /** * Internal class, do not use directly. - * + *

* Contains the parsed argument for a list command (e.g. LIST or NLST) * * @author Apache MINA Project @@ -34,16 +34,16 @@ public class ListArgument { private final char[] options; /** - * @param file - * The file path including the directory - * @param pattern - * A regular expression pattern that files must match - * @param options - * List options, such as -la + * Create a ListArgument instance + * + * @param file The file path including the directory + * @param pattern A regular expression pattern that files must match + * @param options List options, such as -la */ public ListArgument(String file, String pattern, char[] options) { this.file = file; this.pattern = pattern; + if (options == null) { this.options = new char[0]; } else { @@ -94,5 +94,4 @@ public boolean hasOption(char option) { public String getFile() { return file; } - } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/ListArgumentParser.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/ListArgumentParser.java index 57ec0232..62bbe0de 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/ListArgumentParser.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/ListArgumentParser.java @@ -22,21 +22,25 @@ /** * Internal class, do not use directly. - * + *

* Parses a list argument (e.g. for LIST or NLST) into a {@link ListArgument} * * @author Apache MINA Project */ public class ListArgumentParser { + /** + * A private constructor + */ + private ListArgumentParser() { + // Nothing to do + } /** * Parse the argument * - * @param argument - * The argument string + * @param argument The argument string * @return The parsed argument - * @throws IllegalArgumentException - * If the argument string is incorrectly formated + * @throws IllegalArgumentException If the argument string is incorrectly formated */ public static ListArgument parse(String argument) { String file = "./"; @@ -49,6 +53,7 @@ public static ListArgument parse(String argument) { StringBuilder optionsSb = new StringBuilder(4); StringBuilder fileSb = new StringBuilder(16); StringTokenizer st = new StringTokenizer(argument, " ", true); + while (st.hasMoreTokens()) { String token = st.nextToken(); @@ -73,10 +78,12 @@ public static ListArgument parse(String argument) { if (fileSb.length() != 0) { file = fileSb.toString(); } + options = optionsSb.toString(); } int slashIndex = file.lastIndexOf('/'); + if (slashIndex == -1) { if (containsPattern(file)) { pattern = file; @@ -91,8 +98,7 @@ public static ListArgument parse(String argument) { } if (containsPattern(file)) { - throw new IllegalArgumentException( - "Directory path can not contain regular expression"); + throw new IllegalArgumentException("Directory path can not contain regular expression"); } } @@ -104,8 +110,6 @@ public static ListArgument parse(String argument) { } private static boolean containsPattern(String file) { - return file.indexOf('*') > -1 || file.indexOf('?') > -1 - || file.indexOf('[') > -1; - + return file.indexOf('*') > -1 || file.indexOf('?') > -1 || file.indexOf('[') > -1; } } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/MLSTFileFormater.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/MLSTFileFormater.java index f212eff7..711356f0 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/MLSTFileFormater.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/MLSTFileFormater.java @@ -20,26 +20,26 @@ import org.apache.ftpserver.ftplet.FtpFile; import org.apache.ftpserver.util.DateUtils; +import org.apache.ftpserver.util.StringUtils; /** * Internal class, do not use directly. - * + *

* Formats files according to the MLST specification * * @author Apache MINA Project */ public class MLSTFileFormater implements FileFormater { + /** The default types */ + private static final String[] DEFAULT_TYPES = new String[] { "Size", "Modify", "Type" }; - private static final String[] DEFAULT_TYPES = new String[] { "Size", - "Modify", "Type" }; - - private static final char[] NEWLINE = { '\r', '\n' }; - + /** The selected types default value */ private String[] selectedTypes = DEFAULT_TYPES; /** - * @param selectedTypes - * The types to show in the formated file + * Create an instance + * + * @param selectedTypes The types to show in the formated file */ public MLSTFileFormater(String[] selectedTypes) { if (selectedTypes != null) { @@ -48,60 +48,62 @@ public MLSTFileFormater(String[] selectedTypes) { } /** - * @see FileFormater#format(FtpFile) - * * {@inheritDoc} */ public String format(FtpFile file) { StringBuilder sb = new StringBuilder(); - for (int i = 0; i < selectedTypes.length; ++i) { - String type = selectedTypes[i]; - if (type.equalsIgnoreCase("size")) { - sb.append("Size="); - sb.append(String.valueOf(file.getSize())); - sb.append(';'); - } else if (type.equalsIgnoreCase("modify")) { - String timeStr = DateUtils.getFtpDate(file.getLastModified()); - sb.append("Modify="); - sb.append(timeStr); - sb.append(';'); - } else if (type.equalsIgnoreCase("type")) { - if (file.isFile()) { - sb.append("Type=file;"); - } else if (file.isDirectory()) { - sb.append("Type=dir;"); - } - } else if (type.equalsIgnoreCase("perm")) { - sb.append("Perm="); - if (file.isReadable()) { + for (String selectedType:selectedTypes) { + switch (selectedType.toUpperCase()) { + case "SIZE": + sb.append("Size="); + sb.append(String.valueOf(file.getSize())); + sb.append(';'); + break; + + case "MODIFY": + String timeStr = DateUtils.getFtpDate(file.getLastModified()); + sb.append("Modify="); + sb.append(timeStr); + sb.append(';'); + break; + + case "TYPE": if (file.isFile()) { - sb.append('r'); + sb.append("Type=file;"); } else if (file.isDirectory()) { - sb.append('e'); - sb.append('l'); + sb.append("Type=dir;"); } - } - if (file.isWritable()) { - if (file.isFile()) { - sb.append('a'); - sb.append('d'); - sb.append('f'); - sb.append('w'); - } else if (file.isDirectory()) { - sb.append('f'); - sb.append('p'); - sb.append('c'); - sb.append('m'); + + break; + + default: + sb.append("Perm="); + + if (file.isReadable()) { + if (file.isFile()) { + sb.append('r'); + } else if (file.isDirectory()) { + sb.append("el"); + } + } + + if (file.isWritable()) { + if (file.isFile()) { + sb.append("adfw"); + } else if (file.isDirectory()) { + sb.append("fpcm"); + } } - } - sb.append(';'); + + sb.append(';'); + break; } } + sb.append(' '); sb.append(file.getName()); - - sb.append(NEWLINE); + sb.append(StringUtils.NEWLINE); return sb.toString(); } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/NLSTFileFormater.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/NLSTFileFormater.java index 692bb63e..8320decd 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/NLSTFileFormater.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/NLSTFileFormater.java @@ -19,27 +19,28 @@ package org.apache.ftpserver.command.impl.listing; import org.apache.ftpserver.ftplet.FtpFile; +import org.apache.ftpserver.util.StringUtils; /** * Internal class, do not use directly. - * + *

* Formats files according to the NLST specification * * @author Apache MINA Project */ public class NLSTFileFormater implements FileFormater { - - private static final char[] NEWLINE = { '\r', '\n' }; + /** Public constructor */ + public NLSTFileFormater() { + // Nothing to do + } /** - * @see FileFormater#format(FtpFile) - * * {@inheritDoc} */ public String format(FtpFile file) { StringBuilder sb = new StringBuilder(); sb.append(file.getName()); - sb.append(NEWLINE); + sb.append(StringUtils.NEWLINE); return sb.toString(); } diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/RegexFileFilter.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/RegexFileFilter.java index eda113eb..0bcefae9 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/RegexFileFilter.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/RegexFileFilter.java @@ -58,8 +58,6 @@ public RegexFileFilter(String regex, FileFilter wrappedFilter) { } /** - * @see FileFilter#accept(FtpFile) - * * {@inheritDoc} */ public boolean accept(FtpFile file) { diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/VisibleFileFilter.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/VisibleFileFilter.java index 20f39bf4..58d66413 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/VisibleFileFilter.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/VisibleFileFilter.java @@ -28,7 +28,7 @@ * @author Apache MINA Project */ public class VisibleFileFilter implements FileFilter { - + /** The wrapped filter */ private final FileFilter wrappedFilter; /** @@ -41,16 +41,13 @@ public VisibleFileFilter() { /** * Constructor with a wrapped filter, allows for chaining filters * - * @param wrappedFilter - * The {@link FileFilter} to wrap + * @param wrappedFilter The {@link FileFilter} to wrap */ public VisibleFileFilter(FileFilter wrappedFilter) { this.wrappedFilter = wrappedFilter; } /** - * @see FileFilter#accept(FtpFile) - * * {@inheritDoc} */ public boolean accept(FtpFile file) { diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/CommandFactoryBeanDefinitionParser.java b/core/src/main/java/org/apache/ftpserver/config/spring/CommandFactoryBeanDefinitionParser.java index e1700428..5c8cff4a 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/CommandFactoryBeanDefinitionParser.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/CommandFactoryBeanDefinitionParser.java @@ -37,8 +37,13 @@ * * @author Apache MINA Project */ -public class CommandFactoryBeanDefinitionParser extends - AbstractSingleBeanDefinitionParser { +public class CommandFactoryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + /** + * A CommandFactoryBeanDefinitionParser constrcutor + */ + public CommandFactoryBeanDefinitionParser() { + super(); + } /** * {@inheritDoc} @@ -52,10 +57,8 @@ protected Class getBeanClass(final Element element) { * {@inheritDoc} */ @Override - protected void doParse(final Element element, - final ParserContext parserContext, - final BeanDefinitionBuilder builder) { - + protected void doParse(final Element element, final ParserContext parserContext, + final BeanDefinitionBuilder builder) { BeanDefinitionBuilder factoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(CommandFactoryFactory.class); ManagedMap commands = new ManagedMap(); @@ -64,16 +67,14 @@ protected void doParse(final Element element, for (Element commandElm : childs) { String name = commandElm.getAttribute("name"); - Object bean = SpringUtil.parseSpringChildElement(commandElm, - parserContext, builder); + Object bean = SpringUtil.parseSpringChildElement(commandElm, parserContext, builder); commands.put(name, bean); } factoryBuilder.addPropertyValue("commandMap", commands); if (StringUtils.hasText(element.getAttribute("use-default"))) { - factoryBuilder.addPropertyValue("useDefaultCommands", Boolean - .valueOf(element.getAttribute("use-default"))); + factoryBuilder.addPropertyValue("useDefaultCommands", Boolean.valueOf(element.getAttribute("use-default"))); } BeanDefinition factoryDefinition = factoryBuilder.getBeanDefinition(); @@ -85,6 +86,5 @@ protected void doParse(final Element element, // set the factory on the listener bean builder.getRawBeanDefinition().setFactoryBeanName(factoryId); builder.getRawBeanDefinition().setFactoryMethodName("createCommandFactory"); - } } diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/FileSystemBeanDefinitionParser.java b/core/src/main/java/org/apache/ftpserver/config/spring/FileSystemBeanDefinitionParser.java index a35db35d..b09a8dc8 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/FileSystemBeanDefinitionParser.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/FileSystemBeanDefinitionParser.java @@ -32,15 +32,19 @@ * * @author Apache MINA Project */ -public class FileSystemBeanDefinitionParser extends - AbstractSingleBeanDefinitionParser { +public class FileSystemBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + /** + * Create a FileSystemBeanDefinitionParser instance + */ + public FileSystemBeanDefinitionParser() { + super(); + } /** * {@inheritDoc} */ @Override - protected Class getBeanClass( - final Element element) { + protected Class getBeanClass(final Element element) { return NativeFileSystemFactory.class; } @@ -48,16 +52,14 @@ protected Class getBeanClass( * {@inheritDoc} */ @Override - protected void doParse(final Element element, - final ParserContext parserContext, + protected void doParse(final Element element, final ParserContext parserContext, final BeanDefinitionBuilder builder) { if (StringUtils.hasText(element.getAttribute("case-insensitive"))) { - builder.addPropertyValue("caseInsensitive", Boolean - .valueOf(element.getAttribute("case-insensitive"))); + builder.addPropertyValue("caseInsensitive", Boolean.valueOf(element.getAttribute("case-insensitive"))); } + if (StringUtils.hasText(element.getAttribute("create-home"))) { - builder.addPropertyValue("createHome", Boolean - .valueOf(element.getAttribute("create-home"))); + builder.addPropertyValue("createHome", Boolean.valueOf(element.getAttribute("create-home"))); } } } diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/ListenerBeanDefinitionParser.java b/core/src/main/java/org/apache/ftpserver/config/spring/ListenerBeanDefinitionParser.java index 02de6b30..b85de028 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/ListenerBeanDefinitionParser.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/ListenerBeanDefinitionParser.java @@ -44,11 +44,16 @@ * * @author Apache MINA Project */ -public class ListenerBeanDefinitionParser extends - AbstractSingleBeanDefinitionParser { +public class ListenerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + /** Class logger */ + private final Logger LOG = LoggerFactory.getLogger(ListenerBeanDefinitionParser.class); - private final Logger LOG = LoggerFactory - .getLogger(ListenerBeanDefinitionParser.class); + /** + * Create a ListenerBeanDefinitionParser instance + */ + public ListenerBeanDefinitionParser() { + super(); + } /** * {@inheritDoc} @@ -65,15 +70,14 @@ protected Class getBeanClass(final Element element) { protected void doParse(final Element element, final ParserContext parserContext, final BeanDefinitionBuilder builder) { - BeanDefinitionBuilder factoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(ListenerFactory.class); if (StringUtils.hasText(element.getAttribute("port"))) { - factoryBuilder.addPropertyValue("port", Integer.valueOf(element - .getAttribute("port"))); + factoryBuilder.addPropertyValue("port", Integer.valueOf(element.getAttribute("port"))); } SslConfiguration ssl = parseSsl(element); + if (ssl != null) { factoryBuilder.addPropertyValue("sslConfiguration", ssl); } @@ -84,23 +88,24 @@ protected void doParse(final Element element, factoryBuilder.addPropertyValue("dataConnectionConfiguration", dc); if (StringUtils.hasText(element.getAttribute("idle-timeout"))) { - factoryBuilder.addPropertyValue("idleTimeout", SpringUtil.parseInt( - element, "idle-timeout", 300)); + factoryBuilder.addPropertyValue("idleTimeout", SpringUtil.parseInt(element, "idle-timeout", 300)); } - String localAddress = SpringUtil.parseStringFromInetAddress(element, - "local-address"); + String localAddress = SpringUtil.parseStringFromInetAddress(element, "local-address"); + if (localAddress != null) { factoryBuilder.addPropertyValue("serverAddress", localAddress); } - factoryBuilder.addPropertyValue("implicitSsl", SpringUtil.parseBoolean( - element, "implicit-ssl", false)); + + factoryBuilder.addPropertyValue("implicitSsl", SpringUtil.parseBoolean( element, "implicit-ssl", false)); Element blacklistElm = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "blacklist"); + if (blacklistElm != null) { LOG.warn("Element 'blacklist' is deprecated, and may be removed in a future release. " + "Please use 'remote-ip-filter' instead. "); + try { RemoteIpFilter remoteIpFilter = new RemoteIpFilter(IpFilterType.DENY, blacklistElm.getTextContent()); @@ -114,18 +119,20 @@ protected void doParse(final Element element, Element remoteIpFilterElement = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "remote-ip-filter"); + if (remoteIpFilterElement != null) { if (blacklistElm != null) { throw new FtpServerConfigurationException( "Element 'remote-ip-filter' may not be used when 'blacklist' element is specified. "); } + String filterType = remoteIpFilterElement.getAttribute("type"); + try { RemoteIpFilter remoteIpFilter = new RemoteIpFilter(IpFilterType .parse(filterType), remoteIpFilterElement .getTextContent()); - factoryBuilder - .addPropertyValue("sessionFilter", remoteIpFilter); + factoryBuilder.addPropertyValue("sessionFilter", remoteIpFilter); } catch (UnknownHostException e) { throw new IllegalArgumentException( "Invalid IP address or subnet in the 'remote-ip-filter' element"); @@ -145,38 +152,38 @@ protected void doParse(final Element element, } private SslConfiguration parseSsl(final Element parent) { - Element sslElm = SpringUtil.getChildElement(parent, - FtpServerNamespaceHandler.FTPSERVER_NS, "ssl"); + Element sslElm = SpringUtil.getChildElement(parent, FtpServerNamespaceHandler.FTPSERVER_NS, "ssl"); if (sslElm != null) { SslConfigurationFactory ssl = new SslConfigurationFactory(); Element keyStoreElm = SpringUtil.getChildElement(sslElm, FtpServerNamespaceHandler.FTPSERVER_NS, "keystore"); + if (keyStoreElm != null) { ssl.setKeystoreFile(SpringUtil.parseFile(keyStoreElm, "file")); - ssl.setKeystorePassword(SpringUtil.parseString(keyStoreElm, - "password")); + ssl.setKeystorePassword(SpringUtil.parseString(keyStoreElm, "password")); String type = SpringUtil.parseString(keyStoreElm, "type"); + if (type != null) { ssl.setKeystoreType(type); } - String keyAlias = SpringUtil.parseString(keyStoreElm, - "key-alias"); + String keyAlias = SpringUtil.parseString(keyStoreElm, "key-alias"); + if (keyAlias != null) { ssl.setKeyAlias(keyAlias); } - String keyPassword = SpringUtil.parseString(keyStoreElm, - "key-password"); + String keyPassword = SpringUtil.parseString(keyStoreElm, "key-password"); + if (keyPassword != null) { ssl.setKeyPassword(keyPassword); } - String algorithm = SpringUtil.parseString(keyStoreElm, - "algorithm"); + String algorithm = SpringUtil.parseString(keyStoreElm, "algorithm"); + if (algorithm != null) { ssl.setKeystoreAlgorithm(algorithm); } @@ -184,32 +191,32 @@ private SslConfiguration parseSsl(final Element parent) { Element trustStoreElm = SpringUtil.getChildElement(sslElm, FtpServerNamespaceHandler.FTPSERVER_NS, "truststore"); + if (trustStoreElm != null) { - ssl.setTruststoreFile(SpringUtil.parseFile(trustStoreElm, - "file")); - ssl.setTruststorePassword(SpringUtil.parseString(trustStoreElm, - "password")); + ssl.setTruststoreFile(SpringUtil.parseFile(trustStoreElm, "file")); + ssl.setTruststorePassword(SpringUtil.parseString(trustStoreElm, "password")); String type = SpringUtil.parseString(trustStoreElm, "type"); + if (type != null) { ssl.setTruststoreType(type); } - String algorithm = SpringUtil.parseString(trustStoreElm, - "algorithm"); + String algorithm = SpringUtil.parseString(trustStoreElm, "algorithm"); + if (algorithm != null) { ssl.setTruststoreAlgorithm(algorithm); } } - String clientAuthStr = SpringUtil.parseString(sslElm, - "client-authentication"); + String clientAuthStr = SpringUtil.parseString(sslElm, "client-authentication"); + if (clientAuthStr != null) { ssl.setClientAuthentication(clientAuthStr); } - String enabledCiphersuites = SpringUtil.parseString(sslElm, - "enabled-ciphersuites"); + String enabledCiphersuites = SpringUtil.parseString(sslElm, "enabled-ciphersuites"); + if (enabledCiphersuites != null) { ssl.setEnabledCipherSuites(enabledCiphersuites.split(" ")); } @@ -224,7 +231,6 @@ private SslConfiguration parseSsl(final Element parent) { } else { return null; } - } private DataConnectionConfiguration parseDataConnection( @@ -233,7 +239,6 @@ private DataConnectionConfiguration parseDataConnection( DataConnectionConfigurationFactory dc = new DataConnectionConfigurationFactory(); if (element != null) { - dc.setImplicitSsl(SpringUtil.parseBoolean(element, "implicit-ssl", false)); // data con config element available @@ -248,16 +253,14 @@ private DataConnectionConfiguration parseDataConnection( Element activeElm = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "active"); + if (activeElm != null) { - dc.setActiveEnabled(SpringUtil.parseBoolean(activeElm, "enabled", - true)); - dc.setActiveIpCheck(SpringUtil.parseBoolean(activeElm, - "ip-check", false)); - dc.setActiveLocalPort(SpringUtil.parseInt(activeElm, - "local-port", 0)); - - String localAddress = SpringUtil.parseStringFromInetAddress( - activeElm, "local-address"); + dc.setActiveEnabled(SpringUtil.parseBoolean(activeElm, "enabled", true)); + dc.setActiveIpCheck(SpringUtil.parseBoolean(activeElm, "ip-check", false)); + dc.setActiveLocalPort(SpringUtil.parseInt(activeElm, "local-port", 0)); + + String localAddress = SpringUtil.parseStringFromInetAddress( activeElm, "local-address"); + if (localAddress != null) { dc.setActiveLocalAddress(localAddress); } @@ -265,25 +268,27 @@ private DataConnectionConfiguration parseDataConnection( Element passiveElm = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "passive"); + if (passiveElm != null) { - String address = SpringUtil.parseStringFromInetAddress(passiveElm, - "address"); + String address = SpringUtil.parseStringFromInetAddress(passiveElm, "address"); + if (address != null) { dc.setPassiveAddress(address); } - String externalAddress = SpringUtil.parseStringFromInetAddress( - passiveElm, "external-address"); + String externalAddress = SpringUtil.parseStringFromInetAddress( passiveElm, "external-address"); + if (externalAddress != null) { dc.setPassiveExternalAddress(externalAddress); } String ports = SpringUtil.parseString(passiveElm, "ports"); + if (ports != null) { dc.setPassivePorts(ports); } - dc.setPassiveIpCheck(SpringUtil.parseBoolean(passiveElm, - "ip-check", false)); + + dc.setPassiveIpCheck(SpringUtil.parseBoolean(passiveElm, "ip-check", false)); } } else { // no data conn config element, do we still have SSL config from the @@ -296,5 +301,4 @@ private DataConnectionConfiguration parseDataConnection( return dc.createDataConnectionConfiguration(); } - } diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/ServerBeanDefinitionParser.java b/core/src/main/java/org/apache/ftpserver/config/spring/ServerBeanDefinitionParser.java index 033268ea..07731821 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/ServerBeanDefinitionParser.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/ServerBeanDefinitionParser.java @@ -44,8 +44,13 @@ * * @author Apache MINA Project */ -public class ServerBeanDefinitionParser extends - AbstractSingleBeanDefinitionParser { +public class ServerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + /** + * Create a ServerBeanDefinitionParser instance + */ + public ServerBeanDefinitionParser() { + super(); + } /** * {@inheritDoc} @@ -66,50 +71,61 @@ protected void doParse(final Element element, BeanDefinitionBuilder factoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(FtpServerFactory.class); List childs = SpringUtil.getChildElements(element); + for (Element childElm : childs) { String childName = childElm.getLocalName(); - if ("listeners".equals(childName)) { - Map listeners = parseListeners(childElm, parserContext, builder); - - if (listeners.size() > 0) { - factoryBuilder.addPropertyValue("listeners", listeners); - } - } else if ("ftplets".equals(childName)) { - Map ftplets = parseFtplets(childElm, parserContext, builder); - factoryBuilder.addPropertyValue("ftplets", ftplets); - } else if ("file-user-manager".equals(childName) - || "db-user-manager".equals(childName)) { - Object userManager = parserContext.getDelegate() - .parseCustomElement(childElm, - builder.getBeanDefinition()); - factoryBuilder.addPropertyValue("userManager", userManager); - } else if ("user-manager".equals(childName)) { - factoryBuilder.addPropertyValue("userManager", SpringUtil - .parseSpringChildElement(childElm, parserContext, - builder)); - } else if ("native-filesystem".equals(childName)) { - Object fileSystem = parserContext.getDelegate() - .parseCustomElement(childElm, - builder.getBeanDefinition()); - factoryBuilder.addPropertyValue("fileSystem", fileSystem); - } else if ("filesystem".equals(childName)) { - factoryBuilder.addPropertyValue("fileSystem", SpringUtil - .parseSpringChildElement(childElm, parserContext, - builder)); - } else if ("commands".equals(childName)) { - Object commandFactory = parserContext.getDelegate() - .parseCustomElement(childElm, - builder.getBeanDefinition()); - factoryBuilder.addPropertyValue("commandFactory", commandFactory); - } else if ("messages".equals(childName)) { - MessageResource mr = parseMessageResource(childElm, - parserContext, builder); - factoryBuilder.addPropertyValue("messageResource", mr); - - } else { - throw new FtpServerConfigurationException( - "Unknown configuration name: " + childName); + switch (childName) { + case "listeners": + Map listeners = parseListeners(childElm, parserContext, builder); + + if (listeners.size() > 0) { + factoryBuilder.addPropertyValue("listeners", listeners); + } + + break; + + case "ftplets": + Map ftplets = parseFtplets(childElm, parserContext, builder); + factoryBuilder.addPropertyValue("ftplets", ftplets); + break; + + case "file-user-manager": + case "db-user-manager": + Object userManager = parserContext.getDelegate().parseCustomElement(childElm, + builder.getBeanDefinition()); + factoryBuilder.addPropertyValue("userManager", userManager); + break; + + case "user-manager": + factoryBuilder.addPropertyValue("userManager", SpringUtil + .parseSpringChildElement(childElm, parserContext, builder)); + break; + + case "native-filesystem": + Object fileSystem = parserContext.getDelegate().parseCustomElement(childElm, + builder.getBeanDefinition()); + factoryBuilder.addPropertyValue("fileSystem", fileSystem); + break; + + case "filesystem": + factoryBuilder.addPropertyValue("fileSystem", SpringUtil + .parseSpringChildElement(childElm, parserContext, builder)); + break; + + case "commands": + Object commandFactory = parserContext.getDelegate().parseCustomElement(childElm, + builder.getBeanDefinition()); + factoryBuilder.addPropertyValue("commandFactory", commandFactory); + break; + + case "messages": + MessageResource mr = parseMessageResource(childElm, parserContext, builder); + factoryBuilder.addPropertyValue("messageResource", mr); + break; + + default: + throw new FtpServerConfigurationException( "Unknown configuration name: " + childName); } } @@ -119,22 +135,27 @@ protected void doParse(final Element element, connectionConfig.setMaxLogins(SpringUtil.parseInt(element, "max-logins")); } + if (StringUtils.hasText(element.getAttribute("max-threads"))) { connectionConfig.setMaxThreads(SpringUtil.parseInt(element, "max-threads")); } + if (StringUtils.hasText(element.getAttribute("max-anon-logins"))) { connectionConfig.setMaxAnonymousLogins(SpringUtil.parseInt(element, "max-anon-logins")); } + if (StringUtils.hasText(element.getAttribute("anon-enabled"))) { connectionConfig.setAnonymousLoginEnabled(SpringUtil.parseBoolean( element, "anon-enabled", true)); } + if (StringUtils.hasText(element.getAttribute("max-login-failures"))) { connectionConfig.setMaxLoginFailures(SpringUtil.parseInt(element, "max-login-failures")); } + if (StringUtils.hasText(element.getAttribute("login-failure-delay"))) { connectionConfig.setLoginFailureDelay(SpringUtil.parseInt(element, "login-failure-delay")); @@ -142,12 +163,10 @@ protected void doParse(final Element element, factoryBuilder.addPropertyValue("connectionConfig", connectionConfig.createConnectionConfig()); - BeanDefinition factoryDefinition = factoryBuilder.getBeanDefinition(); - String factoryName = parserContext.getReaderContext().generateBeanName(factoryDefinition); - BeanDefinitionHolder factoryHolder = new BeanDefinitionHolder(factoryDefinition, factoryName); + registerBeanDefinition(factoryHolder, parserContext.getRegistry()); // set the factory on the listener bean @@ -162,20 +181,17 @@ protected void doParse(final Element element, private MessageResource parseMessageResource(final Element childElm, final ParserContext parserContext, final BeanDefinitionBuilder builder) { - MessageResourceFactory mr = new MessageResourceFactory(); if (StringUtils.hasText(childElm.getAttribute("languages"))) { String langString = childElm.getAttribute("languages"); - String[] languages = langString.split("[\\s,]+"); mr.setLanguages(Arrays.asList(languages)); } if (StringUtils.hasText(childElm.getAttribute("directory"))) { - mr.setCustomMessageDirectory(new File(childElm - .getAttribute("directory"))); + mr.setCustomMessageDirectory(new File(childElm.getAttribute("directory"))); } @@ -198,6 +214,7 @@ private MessageResource parseMessageResource(final Element childElm, builder.getBeanDefinition()); } else { ManagedMap ftplets = new ManagedMap(); + for (Element ftpletElm : childs) { ftplets.put(ftpletElm.getAttribute("name"), SpringUtil .parseSpringChildElement(ftpletElm, parserContext, @@ -222,19 +239,22 @@ private MessageResource parseMessageResource(final Element childElm, for (Element listenerElm : childs) { Object listener = null; String ln = listenerElm.getLocalName(); - if ("nio-listener".equals(ln)) { - listener = parserContext.getDelegate().parseCustomElement( - listenerElm, builder.getBeanDefinition()); - } else if ("listener".equals(ln)) { - listener = SpringUtil.parseSpringChildElement(listenerElm, - parserContext, builder); - } else { - throw new FtpServerConfigurationException( - "Unknown listener element " + ln); + + switch (ln) { + case "nio-listener": + listener = parserContext.getDelegate().parseCustomElement( + listenerElm, builder.getBeanDefinition()); + break; + + case "listener": + listener = SpringUtil.parseSpringChildElement(listenerElm, parserContext, builder); + break; + + default: + throw new FtpServerConfigurationException("Unknown listener element " + ln); } String name = listenerElm.getAttribute("name"); - listeners.put(name, listener); } diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/SpringUtil.java b/core/src/main/java/org/apache/ftpserver/config/spring/SpringUtil.java index a99541f3..74ec08a4 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/SpringUtil.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/SpringUtil.java @@ -40,17 +40,23 @@ * @author Apache MINA Project */ public class SpringUtil { + /** + * A private constructor + */ + private SpringUtil() { + // Nothing to do + } /** * Get all child elements for the element * - * @param elm - * The element for which to locate children + * @param elm The element for which to locate children * @return All children */ public static List getChildElements(final Element elm) { List elements = new ArrayList<>(); NodeList childs = elm.getChildNodes(); + for (int i = 0; i < childs.getLength(); i++) { Node child = childs.item(i); @@ -65,16 +71,12 @@ public static List getChildElements(final Element elm) { /** * Get the first child element matching the local name and namespace * - * @param parent - * The element for which to locate the child - * @param ns - * The namespace to match, or null for any namespace - * @param localName - * The local name to match, or null for any local name + * @param parent The element for which to locate the child + * @param ns The namespace to match, or null for any namespace + * @param localName The local name to match, or null for any local name * @return The first child matching the criteria */ - public static Element getChildElement(final Element parent, - final String ns, final String localName) { + public static Element getChildElement(final Element parent, final String ns, final String localName) { List elements = getChildElements(parent); for (Element element : elements) { @@ -92,17 +94,12 @@ public static Element getChildElement(final Element parent, * Get the text context of first child element matching the local name and * namespace * - * @param parent - * The element for which to locate the child - * @param ns - * The namespace to match, or null for any namespace - * @param localName - * The local name to match, or null for any local name - * @return The text content of the first child matching the criteria or null - * if element not found + * @param parent The element for which to locate the child + * @param ns The namespace to match, or null for any namespace + * @param localName The local name to match, or null for any local name + * @return The text content of the first child matching the criteria or null if element not found */ - public static String getChildElementText(final Element parent, - final String ns, final String localName) { + public static String getChildElementText(final Element parent, final String ns, final String localName) { List elements = getChildElements(parent); for (Element element : elements) { @@ -119,29 +116,23 @@ public static String getChildElementText(final Element parent, /** * Parse specific Spring elements, bean and ref * - * @param parent - * The element in which we will look for Spring elements - * @param parserContext - * The Spring parser context - * @param builder - * The Spring bean definition builder + * @param parent The element in which we will look for Spring elements + * @param parserContext The Spring parser context + * @param builder The Spring bean definition builder * @return The Spring bean definition */ - public static Object parseSpringChildElement(final Element parent, - final ParserContext parserContext, + public static Object parseSpringChildElement(final Element parent, final ParserContext parserContext, final BeanDefinitionBuilder builder) { Element springElm = getChildElement(parent, null, null); String ln = springElm.getLocalName(); + if ("bean".equals(ln)) { - return parserContext.getDelegate().parseBeanDefinitionElement( - springElm, builder.getBeanDefinition()); + return parserContext.getDelegate().parseBeanDefinitionElement( springElm, builder.getBeanDefinition()); } else if ("ref".equals(ln)) { - return parserContext.getDelegate().parsePropertySubElement( - springElm, builder.getBeanDefinition()); + return parserContext.getDelegate().parsePropertySubElement( springElm, builder.getBeanDefinition()); } else { - throw new FtpServerConfigurationException("Unknown spring element " - + ln); + throw new FtpServerConfigurationException("Unknown spring element " + ln); } } @@ -149,32 +140,26 @@ public static Object parseSpringChildElement(final Element parent, * Parses a attribute value into a boolean. If the attribute is missing or * has no content, a default value is returned * - * @param parent - * The element - * @param attrName - * The attribute name - * @param defaultValue - * The default value + * @param parent The element + * @param attrName The attribute name + * @param defaultValue The default value * @return The value, or the default value */ - public static boolean parseBoolean(final Element parent, - final String attrName, final boolean defaultValue) { + public static boolean parseBoolean(final Element parent, final String attrName, final boolean defaultValue) { if (StringUtils.hasText(parent.getAttribute(attrName))) { return Boolean.parseBoolean(parent.getAttribute(attrName)); } + return defaultValue; } /** * Parses a attribute value into an integer. * - * @param parent - * The element - * @param attrName - * The attribute name + * @param parent The element + * @param attrName The attribute name * @return The value - * @throws NumberFormatException - * If the attribute does not contain a number + * @throws NumberFormatException If the attribute does not contain a number */ public static int parseInt(final Element parent, final String attrName) { return Integer.parseInt(parent.getAttribute(attrName)); @@ -184,19 +169,16 @@ public static int parseInt(final Element parent, final String attrName) { * Parses a attribute value into an integer. If the attribute is missing or * has no content, a default value is returned * - * @param parent - * The element - * @param attrName - * The attribute name - * @param defaultValue - * The default value + * @param parent The element + * @param attrName The attribute name + * @param defaultValue The default value * @return The value, or the default value */ - public static int parseInt(final Element parent, final String attrName, - final int defaultValue) { + public static int parseInt(final Element parent, final String attrName, final int defaultValue) { if (StringUtils.hasText(parent.getAttribute(attrName))) { return Integer.parseInt(parent.getAttribute(attrName)); } + return defaultValue; } @@ -204,10 +186,8 @@ public static int parseInt(final Element parent, final String attrName, * Return the string value of an attribute, or null if the attribute is * missing * - * @param parent - * The element - * @param attrName - * The attribute name + * @param parent The element + * @param attrName The attribute name * @return The attribute string value */ public static String parseString(final Element parent, final String attrName) { @@ -221,30 +201,26 @@ public static String parseString(final Element parent, final String attrName) { /** * Return an attribute value as a {@link File} * - * @param parent - * The element - * @param attrName - * The attribute name + * @param parent The element + * @param attrName The attribute name * @return The file representing the path used in the attribute */ public static File parseFile(final Element parent, final String attrName) { if (StringUtils.hasText(parent.getAttribute(attrName))) { return new File(parent.getAttribute(attrName)); } + return null; } /** * Return an attribute value as an {@link InetAddress} * - * @param parent - * The element - * @param attrName - * The attribute name + * @param parent The element + * @param attrName The attribute name * @return The attribute value parsed into a {@link InetAddress} */ - public static InetAddress parseInetAddress(final Element parent, - final String attrName) { + public static InetAddress parseInetAddress(final Element parent, final String attrName) { if (StringUtils.hasText(parent.getAttribute(attrName))) { try { return InetAddress.getByName(parent.getAttribute(attrName)); @@ -252,22 +228,22 @@ public static InetAddress parseInetAddress(final Element parent, throw new FtpServerConfigurationException("Unknown host", e); } } + return null; } + /** * Return an attribute value after checking it is a valid {@link InetAddress} * - * @param parent - * The element - * @param attrName - * The attribute name + * @param parent The element + * @param attrName The attribute name * @return The attribute string value. */ - public static String parseStringFromInetAddress(final Element parent, - final String attrName){ + public static String parseStringFromInetAddress(final Element parent, final String attrName){ if ( parseInetAddress(parent, attrName)!=null){ return parent.getAttribute(attrName); } + return null; } } diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/UserManagerBeanDefinitionParser.java b/core/src/main/java/org/apache/ftpserver/config/spring/UserManagerBeanDefinitionParser.java index 03bfd0b3..68928c39 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/UserManagerBeanDefinitionParser.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/UserManagerBeanDefinitionParser.java @@ -38,26 +38,37 @@ * * @author Apache MINA Project */ -public class UserManagerBeanDefinitionParser extends - AbstractSingleBeanDefinitionParser { +public class UserManagerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { + /** + * Public constructor + */ + public UserManagerBeanDefinitionParser() { + super(); + } + /** + * {@inheritDoc} + */ @Override protected Class getBeanClass(final Element element) { return null; } + /** + * {@inheritDoc} + */ @Override protected void doParse(final Element element, final ParserContext parserContext, final BeanDefinitionBuilder builder) { - - Class factoryClass; + if (element.getLocalName().equals("file-user-manager")) { factoryClass = PropertiesUserManagerFactory.class; } else { factoryClass = DbUserManagerFactory.class; } + BeanDefinitionBuilder factoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(factoryClass); @@ -88,6 +99,7 @@ protected void doParse(final Element element, // schema ensure we get the right type of element Element springElm = SpringUtil.getChildElement(dsElm, null, null); Object o; + if ("bean".equals(springElm.getLocalName())) { o = parserContext.getDelegate().parseBeanDefinitionElement( springElm, builder.getBeanDefinition()); @@ -97,22 +109,15 @@ protected void doParse(final Element element, springElm, builder.getBeanDefinition()); } - factoryBuilder.addPropertyValue("dataSource", o); - factoryBuilder.addPropertyValue("sqlUserInsert", getSql(element, - "insert-user")); - factoryBuilder.addPropertyValue("sqlUserUpdate", getSql(element, - "update-user")); - factoryBuilder.addPropertyValue("sqlUserDelete", getSql(element, - "delete-user")); - factoryBuilder.addPropertyValue("sqlUserSelect", getSql(element, - "select-user")); - factoryBuilder.addPropertyValue("sqlUserSelectAll", getSql(element, - "select-all-users")); - factoryBuilder.addPropertyValue("sqlUserAdmin", - getSql(element, "is-admin")); - factoryBuilder.addPropertyValue("sqlUserAuthenticate", getSql(element, - "authenticate")); + factoryBuilder.addPropertyValue("dataSource", o); + factoryBuilder.addPropertyValue("sqlUserInsert", getSql(element, "insert-user")); + factoryBuilder.addPropertyValue("sqlUserUpdate", getSql(element, "update-user")); + factoryBuilder.addPropertyValue("sqlUserDelete", getSql(element, "delete-user")); + factoryBuilder.addPropertyValue("sqlUserSelect", getSql(element, "select-user")); + factoryBuilder.addPropertyValue("sqlUserSelectAll", getSql(element, "select-all-users")); + factoryBuilder.addPropertyValue("sqlUserAdmin", getSql(element, "is-admin")); + factoryBuilder.addPropertyValue("sqlUserAuthenticate", getSql(element, "authenticate")); } BeanDefinition factoryDefinition = factoryBuilder.getBeanDefinition(); diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/ConnectionConfigFactoryBean.java b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/ConnectionConfigFactoryBean.java index b6f28d24..516bdc23 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/ConnectionConfigFactoryBean.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/ConnectionConfigFactoryBean.java @@ -32,17 +32,38 @@ * @see ConnectionConfigFactory */ public class ConnectionConfigFactoryBean extends ConnectionConfigFactory implements FactoryBean { + /** + * Create a ConnectionConfigFactoryBean instance + */ + public ConnectionConfigFactoryBean() { + // Nothing to do + } + /** + * Create a ConnectionConfig instance + * + * @return An instance of ConnectionConfig + * @throws Exception Never thrown, but the interface requires this declaration + */ public Object getObject() throws Exception { return createConnectionConfig(); } + /** + * Get the ConnectionConfig instance type + * + * @return The ConnectionConfig instance type + */ public Class getObjectType() { return ConnectionConfig.class; } + /** + * This instance is not a singleton + * + * @return Always false + */ public boolean isSingleton() { return false; } - } diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/DataConnectionConfigurationFactoryBean.java b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/DataConnectionConfigurationFactoryBean.java index aab77936..d8db2ae9 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/DataConnectionConfigurationFactoryBean.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/DataConnectionConfigurationFactoryBean.java @@ -32,17 +32,31 @@ * @see DataConnectionConfigurationFactory */ public class DataConnectionConfigurationFactoryBean extends DataConnectionConfigurationFactory implements FactoryBean { + /** + * Create a DataConnectionConfigurationFactoryBean + */ + public DataConnectionConfigurationFactoryBean() { + // Nothing to do + } + /** + * {@inheritDoc} + */ public Object getObject() throws Exception { return createDataConnectionConfiguration(); } + /** + * {@inheritDoc} + */ public Class getObjectType() { return DataConnectionConfiguration.class; } + /** + * {@inheritDoc} + */ public boolean isSingleton() { return false; } - } diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/FtpServerFactoryBean.java b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/FtpServerFactoryBean.java index 0a9661ca..72e6ecd5 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/FtpServerFactoryBean.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/FtpServerFactoryBean.java @@ -32,17 +32,32 @@ * @see FtpServerFactory */ public class FtpServerFactoryBean extends FtpServerFactory implements FactoryBean { + /** + * Create a FtpServerFactoryBean instance + */ + public FtpServerFactoryBean() { + super(); + } + + /** + * {@inheritDoc} + */ public Object getObject() throws Exception { return createServer(); } + /** + * {@inheritDoc} + */ public Class getObjectType() { return FtpServer.class; } + /** + * {@inheritDoc} + */ public boolean isSingleton() { return false; } - } diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/ListenerFactoryBean.java b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/ListenerFactoryBean.java index 64687dfe..3ed39521 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/ListenerFactoryBean.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/ListenerFactoryBean.java @@ -32,17 +32,31 @@ * @see ListenerFactory */ public class ListenerFactoryBean extends ListenerFactory implements FactoryBean { + /** + * Create a ListenerFactoryBean instance + */ + public ListenerFactoryBean() { + super(); + } + /** + * {@inheritDoc} + */ public Object getObject() throws Exception { return createListener(); } + /** + * {@inheritDoc} + */ public Class getObjectType() { return Listener.class; } + /** + * {@inheritDoc} + */ public boolean isSingleton() { return false; } - } diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/SslConfigurationFactoryBean.java b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/SslConfigurationFactoryBean.java index f3a5ae0c..249975a2 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/SslConfigurationFactoryBean.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/factorybeans/SslConfigurationFactoryBean.java @@ -32,6 +32,12 @@ * @see SslConfigurationFactory */ public class SslConfigurationFactoryBean extends SslConfigurationFactory implements FactoryBean { + /** + * Create a SslConfigurationFactoryBean instance + */ + public SslConfigurationFactoryBean() { + // Nothing tp do + } public Object getObject() throws Exception { return createSslConfiguration(); diff --git a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/NativeFileSystemFactory.java b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/NativeFileSystemFactory.java index 49d4c347..960e57a1 100644 --- a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/NativeFileSystemFactory.java +++ b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/NativeFileSystemFactory.java @@ -35,12 +35,20 @@ * @author Apache MINA Project */ public class NativeFileSystemFactory implements FileSystemFactory { + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(NativeFileSystemFactory.class); private boolean createHome; private boolean caseInsensitive; + /** + * Create a NativeFileSystemFactory instance + */ + public NativeFileSystemFactory() { + // Nothing to do + } + /** * Should the home directories be created automatically * diff --git a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileSystemView.java b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileSystemView.java index d14b96a6..f08f5141 100644 --- a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileSystemView.java +++ b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileSystemView.java @@ -32,7 +32,7 @@ /** * Internal class, do not use directly. - * + *

* File system view based on native file system. Here the root directory will be * user virtual root (/). * @@ -41,7 +41,6 @@ public class NativeFileSystemView implements FileSystemView { private final Logger LOG = LoggerFactory.getLogger(NativeFileSystemView.class); - // the root directory will always end with '/'. private String rootDir; @@ -57,6 +56,9 @@ public class NativeFileSystemView implements FileSystemView { /** * Constructor - internal do not use directly, use {@link NativeFileSystemFactory} instead + * + * @param user The current user + * @throws FtpException Actually, never thrown... To be removed! */ protected NativeFileSystemView(User user) throws FtpException { this(user, false); @@ -139,20 +141,22 @@ public FtpFile getFile(String file) { public boolean changeWorkingDirectory(String dir) { // not a directory - return false - dir = getPhysicalName(rootDir, currDir, dir, - caseInsensitive); + dir = getPhysicalName(rootDir, currDir, dir, caseInsensitive); File dirObj = new File(dir); + if (!dirObj.isDirectory()) { return false; } // strip user root and add last '/' if necessary dir = dir.substring(rootDir.length() - 1); + if (dir.charAt(dir.length() - 1) != '/') { dir = dir + '/'; } currDir = dir; + return true; } @@ -173,20 +177,15 @@ public void dispose() { * Get the physical canonical file name. It works like * File.getCanonicalPath(). * - * @param rootDir - * The root directory. - * @param currDir - * The current directory. It will always be with respect to the - * root directory. - * @param fileName - * The input file name. - * @return The return string will always begin with the root directory. It - * will never be null. + * @param rootDir The root directory. + * @param currDir The current directory. It will always be with respect to the root directory. + * @param fileName The input file name. + * @param caseInsensitive Tells if the file name case sensitivity should be considered or not + * @return The return string will always begin with the root directory. It will never be null. */ protected String getPhysicalName(final String rootDir, final String currDir, final String fileName, final boolean caseInsensitive) { - // normalize root dir String normalizedRootDir = normalizeSeparateChar(rootDir); normalizedRootDir = appendSlash(normalizedRootDir); @@ -212,6 +211,7 @@ protected String getPhysicalName(final String rootDir, // replace ., ~ and .. // in this loop resArg will never end with '/' StringTokenizer st = new StringTokenizer(normalizedFileName, "/"); + while (st.hasMoreTokens()) { String tok = st.nextToken(); @@ -222,6 +222,7 @@ protected String getPhysicalName(final String rootDir, // .. => parent directory (if not root) if (result.startsWith(normalizedRootDir)) { int slashIndex = result.lastIndexOf('/'); + if (slashIndex != -1) { result = result.substring(0, slashIndex); } @@ -235,8 +236,7 @@ protected String getPhysicalName(final String rootDir, if (caseInsensitive) { // we're case insensitive, find a directory with the name, ignoring casing - File[] matches = new File(result) - .listFiles(new NameEqualsFileFilter(tok, true)); + File[] matches = new File(result).listFiles(new NameEqualsFileFilter(tok, true)); if (matches != null && matches.length > 0) { // found a file matching tok, replace tok for get the right casing @@ -316,6 +316,7 @@ private String normalize(String path, String defaultPath) { path = normalizeSeparateChar(path); path = prependSlash(appendSlash(path)); + return path; } } diff --git a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFtpFile.java b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFtpFile.java index 2237ab52..3ec1ec96 100644 --- a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFtpFile.java +++ b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFtpFile.java @@ -60,12 +60,17 @@ public class NativeFtpFile implements FtpFile { /** * Constructor, internal do not use directly. + * + * @param fileName The file name + * @param file The file itself + * @param user The user */ protected NativeFtpFile(final String fileName, final File file, final User user) { if (fileName == null) { throw new IllegalArgumentException("fileName can not be null"); } + if (file == null) { throw new IllegalArgumentException("file can not be null"); } diff --git a/core/src/main/java/org/apache/ftpserver/ftpletcontainer/impl/DefaultFtpletContainer.java b/core/src/main/java/org/apache/ftpserver/ftpletcontainer/impl/DefaultFtpletContainer.java index 8fa98d97..00de5bef 100644 --- a/core/src/main/java/org/apache/ftpserver/ftpletcontainer/impl/DefaultFtpletContainer.java +++ b/core/src/main/java/org/apache/ftpserver/ftpletcontainer/impl/DefaultFtpletContainer.java @@ -37,24 +37,32 @@ /** * Internal class, do not use directly. - * + *

* This ftplet calls other ftplet methods and returns appropriate return value. - * + *

* Internal class, do not use directly. * * @author Apache MINA Project */ public class DefaultFtpletContainer implements FtpletContainer { + /** The class logger */ + private final Logger LOG = LoggerFactory.getLogger(DefaultFtpletContainer.class); - private final Logger LOG = LoggerFactory - .getLogger(DefaultFtpletContainer.class); - + /** The contained FtpLets */ private final Map ftplets; + /** + * Create a DefaultFtpletContainer instance + */ public DefaultFtpletContainer() { this(new ConcurrentHashMap<>()); } + /** + * Create a DefaultFtpletContainer instance + * + * @param ftplets The set of FtpLets to store + */ public DefaultFtpletContainer(Map ftplets) { this.ftplets = ftplets; } @@ -70,6 +78,12 @@ public synchronized Ftplet getFtplet(String name) { return ftplets.get(name); } + /** + * Initialize teh container + * + * @param ftpletContext The context to use + * @throws FtpException If the initialization failed + */ public synchronized void init(FtpletContext ftpletContext) throws FtpException { for (Entry entry : ftplets.entrySet()) { entry.getValue().init(ftpletContext); @@ -77,8 +91,6 @@ public synchronized void init(FtpletContext ftpletContext) throws FtpException { } /** - * @see FtpletContainer#getFtplets() - * * {@inheritDoc} */ public synchronized Map getFtplets() { @@ -101,11 +113,12 @@ public void destroy() { /** * {@inheritDoc} */ - public FtpletResult onConnect(FtpSession session) throws FtpException, - IOException { + public FtpletResult onConnect(FtpSession session) throws FtpException, IOException { FtpletResult retVal = FtpletResult.DEFAULT; + for (Entry entry : ftplets.entrySet()) { retVal = entry.getValue().onConnect(session); + if (retVal == null) { retVal = FtpletResult.DEFAULT; } @@ -115,18 +128,19 @@ public FtpletResult onConnect(FtpSession session) throws FtpException, break; } } + return retVal; } /** * {@inheritDoc} */ - public FtpletResult onDisconnect(FtpSession session) throws FtpException, - IOException { + public FtpletResult onDisconnect(FtpSession session) throws FtpException, IOException { FtpletResult retVal = FtpletResult.DEFAULT; - for (Entry entry : ftplets.entrySet()) { + for (Entry entry : ftplets.entrySet()) { retVal = entry.getValue().onDisconnect(session); + if (retVal == null) { retVal = FtpletResult.DEFAULT; } @@ -136,6 +150,7 @@ public FtpletResult onDisconnect(FtpSession session) throws FtpException, break; } } + return retVal; } @@ -145,9 +160,10 @@ public FtpletResult onDisconnect(FtpSession session) throws FtpException, public FtpletResult afterCommand(FtpSession session, FtpRequest request, FtpReply reply) throws FtpException, IOException { FtpletResult retVal = FtpletResult.DEFAULT; - for (Entry entry : ftplets.entrySet()) { + for (Entry entry : ftplets.entrySet()) { retVal = entry.getValue().afterCommand(session, request, reply); + if (retVal == null) { retVal = FtpletResult.DEFAULT; } @@ -157,18 +173,19 @@ public FtpletResult afterCommand(FtpSession session, FtpRequest request, FtpRepl break; } } + return retVal; } /** * {@inheritDoc} */ - public FtpletResult beforeCommand(FtpSession session, FtpRequest request) - throws FtpException, IOException { + public FtpletResult beforeCommand(FtpSession session, FtpRequest request) throws FtpException, IOException { FtpletResult retVal = FtpletResult.DEFAULT; - for (Entry entry : ftplets.entrySet()) { + for (Entry entry : ftplets.entrySet()) { retVal = entry.getValue().beforeCommand(session, request); + if (retVal == null) { retVal = FtpletResult.DEFAULT; } @@ -178,7 +195,7 @@ public FtpletResult beforeCommand(FtpSession session, FtpRequest request) break; } } + return retVal; } - } diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultConnectionConfig.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultConnectionConfig.java index 56c24ad9..4c3e6cf4 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultConnectionConfig.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultConnectionConfig.java @@ -42,6 +42,18 @@ public class DefaultConnectionConfig implements ConnectionConfig { private final int maxThreads; + /** + * Create a DefaultConnectionConfig istance, with default values: + * + *

    + *
  • anonymousLoginEnabled: true
  • + *
  • loginFailureDelay: 500ms
  • + *
  • maxLogins: 10
  • + *
  • maxAnonymousLogins: 10
  • + *
  • maxLoginFailures: 3
  • + *
  • maxThreads: 0
  • + *
+ */ public DefaultConnectionConfig() { this(true, 500, 10, 10, 3, 0); } @@ -90,5 +102,4 @@ public boolean isAnonymousLoginEnabled() { public int getMaxThreads() { return maxThreads; } - } diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultDataConnectionConfiguration.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultDataConnectionConfiguration.java index c5406039..03620718 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultDataConnectionConfiguration.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultDataConnectionConfiguration.java @@ -189,8 +189,6 @@ public SslConfiguration getSslConfiguration() { } /** - * @see org.apache.ftpserver.DataConnectionConfiguration#isImplicitSsl() - * * {@inheritDoc} */ public boolean isImplicitSsl() { diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpHandler.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpHandler.java index 3afe06bd..f8829c78 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpHandler.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpHandler.java @@ -53,6 +53,15 @@ public class DefaultFtpHandler implements FtpHandler { private Listener listener; + /** + * Create a DefaultFtpHandler instance + */ + public DefaultFtpHandler() { + // Nothing to do + } + + /** + * {@inheritDoc} */ public void init(final FtpServerContext context, final Listener listener) { this.context = context; this.listener = listener; diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java index 0bbb6b55..8443f27f 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java @@ -66,7 +66,7 @@ public DefaultFtpServer(final FtpServerContext serverContext) { /** * Start the server. Open a new listener thread. - * @throws FtpException + * @throws FtpException If the server failed to start */ public void start() throws FtpException { if (serverContext == null) { @@ -185,8 +185,6 @@ public void resume() { } /** - * Is the server suspended - * * {@inheritDoc} */ public boolean isSuspended() { @@ -196,7 +194,7 @@ public boolean isSuspended() { /** * Get the root server context. * - * {@inheritDoc} + * @return The FTP Server context */ public FtpServerContext getServerContext() { return serverContext; diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java index 9708d262..1c0a02a1 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java @@ -65,14 +65,19 @@ public class DefaultFtpServerContext implements FtpServerContext { /** The FTP messages per language */ private MessageResource messageResource = new MessageResourceFactory().createMessageResource(); + /** The user manager */ private UserManager userManager = new PropertiesUserManagerFactory().createUserManager(); + /** The file system factory */ private FileSystemFactory fileSystemManager = new NativeFileSystemFactory(); + /** The FtpLet container */ private FtpletContainer ftpletContainer = new DefaultFtpletContainer(); + /** The FTP statistics */ private FtpStatistics statistics = new DefaultFtpStatistics(); + /** The comand factory */ private CommandFactory commandFactory = new CommandFactoryFactory().createCommandFactory(); /** The connection configuration */ @@ -81,7 +86,10 @@ public class DefaultFtpServerContext implements FtpServerContext { /** The declared listeners for this context */ private Map listeners = new HashMap<>(); + /** Thelist of admin authorities */ private static final List ADMIN_AUTHORITIES = new ArrayList<>(); + + /** The list of anonymous authorities */ private static final List ANON_AUTHORITIES = new ArrayList<>(); /** @@ -95,7 +103,9 @@ public class DefaultFtpServerContext implements FtpServerContext { ANON_AUTHORITIES.add(new TransferRatePermission(4800, 4800)); } - + /** + * Create an instance + */ public DefaultFtpServerContext() { // create the default listener listeners.put("default", new ListenerFactory().createListener()); @@ -107,6 +117,8 @@ public DefaultFtpServerContext() { *
  • Admin
  • *
  • Anonymous
  • * + * + * @throws Exception If the users creation failed */ public void createDefaultUsers() throws Exception { UserManager userManager = getUserManager(); @@ -175,12 +187,16 @@ public FtpStatistics getFtpStatistics() { return statistics; } + /** + * Set the FTP server statistics + * + * @param statistics The FTP server statistics + */ public void setFtpStatistics(FtpStatistics statistics) { this.statistics = statistics; } /** - * Get ftplet handler. * {@inheritDoc} */ public FtpletContainer getFtpletContainer() { @@ -188,7 +204,6 @@ public FtpletContainer getFtpletContainer() { } /** - * Get the command factory. * {@inheritDoc} */ public CommandFactory getCommandFactory() { @@ -196,15 +211,14 @@ public CommandFactory getCommandFactory() { } /** - * Get Ftplet. * {@inheritDoc} */ + @Override public Ftplet getFtplet(String name) { return ftpletContainer.getFtplet(name); } /** - * Close all the components. * {@inheritDoc} */ public void dispose() { @@ -231,6 +245,12 @@ public Listener getListener(String name) { return listeners.get(name); } + /** + * Set a listener. It does pretty much what addListener does. + * + * @param name The listener's name + * @param listener The listener + */ public void setListener(String name, Listener listener) { listeners.put(name, listener); } @@ -242,34 +262,76 @@ public Map getListeners() { return listeners; } + /** + * Set the listeners + * + * @param listeners The listeners + */ public void setListeners(Map listeners) { this.listeners = listeners; } + /** + * Add a listener + * + * @param name The added listener's name + * @param listener The added listener + */ public void addListener(String name, Listener listener) { listeners.put(name, listener); } + /** + * Remove a listener + * + * @param name The listener name + * @return The removed listener + */ public Listener removeListener(String name) { return listeners.remove(name); } + /** + * Set the command factory + * + * @param commandFactory The command factory + */ public void setCommandFactory(CommandFactory commandFactory) { this.commandFactory = commandFactory; } + /** + * Set the file system manager + * + * @param fileSystemManager The file system manager + */ public void setFileSystemManager(FileSystemFactory fileSystemManager) { this.fileSystemManager = fileSystemManager; } + /** + * Set the FtpLet container + * + * @param ftpletContainer The FtpLet container + */ public void setFtpletContainer(FtpletContainer ftpletContainer) { this.ftpletContainer = ftpletContainer; } + /** + * Set the message resource + * + * @param messageResource The message resource + */ public void setMessageResource(MessageResource messageResource) { this.messageResource = messageResource; } + /** + * Set the user manager + * + * @param userManager The user manager + */ public void setUserManager(UserManager userManager) { this.userManager = userManager; } @@ -281,10 +343,21 @@ public ConnectionConfig getConnectionConfig() { return connectionConfig; } + /** + * Set the connection configuration + * + * @param connectionConfig The connection configuration + */ public void setConnectionConfig(ConnectionConfig connectionConfig) { this.connectionConfig = connectionConfig; } + /** + * Get the ThreadPool executor configured with the maxThreads parameter, + * or the maxLogins parameter if maxThreads isn't defined, or 16 threads. + * + * @return An Ordered Thread Pool executor + */ public synchronized ThreadPoolExecutor getThreadPoolExecutor() { if (threadPoolExecutor == null) { int maxThreads = connectionConfig.getMaxThreads(); diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpStatistics.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpStatistics.java index 98a73739..9f0dcf39 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpStatistics.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpStatistics.java @@ -76,6 +76,14 @@ public class DefaultFtpStatistics implements ServerFtpStatistics { private AtomicLong bytesDownload = new AtomicLong(0L); + /** + * Create a DefaultFtpStatistics instance + */ + public DefaultFtpStatistics() { + // Nothing to do + } + + private static class UserLogins { private Map perAddress = new ConcurrentHashMap<>(); @@ -104,6 +112,7 @@ public AtomicInteger loginsFromInetAddress(InetAddress address) { */ private Map userLoginTable = new ConcurrentHashMap<>(); + /** The loging number parameter */ public static final String LOGIN_NUMBER = "login_number"; /** diff --git a/core/src/main/java/org/apache/ftpserver/impl/FtpHandler.java b/core/src/main/java/org/apache/ftpserver/impl/FtpHandler.java index a410390b..d0a58545 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/FtpHandler.java +++ b/core/src/main/java/org/apache/ftpserver/impl/FtpHandler.java @@ -35,7 +35,12 @@ * */ public interface FtpHandler { - + /** + * Initialize the FTP handler + * + * @param context The FTP server context + * @param listener The listener + */ void init(FtpServerContext context, Listener listener); /** diff --git a/core/src/main/java/org/apache/ftpserver/impl/FtpIoSession.java b/core/src/main/java/org/apache/ftpserver/impl/FtpIoSession.java index aaba9b07..9e1cc9be 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/FtpIoSession.java +++ b/core/src/main/java/org/apache/ftpserver/impl/FtpIoSession.java @@ -579,12 +579,16 @@ public void resetState() { removeAttribute(ATTRIBUTE_FILE_OFFSET); } + /** + * Get the DataConnection + * + * @return The DataConnection instance + */ public synchronized ServerDataConnectionFactory getDataConnection() { if (containsAttribute(ATTRIBUTE_DATA_CONNECTION)) { return (ServerDataConnectionFactory) getAttribute(ATTRIBUTE_DATA_CONNECTION); } else { - IODataConnectionFactory dataCon = new IODataConnectionFactory( - context, this); + IODataConnectionFactory dataCon = new IODataConnectionFactory(context, this); dataCon.setServerControlAddress(((InetSocketAddress) getLocalAddress()).getAddress()); setAttribute(ATTRIBUTE_DATA_CONNECTION, dataCon); diff --git a/core/src/main/java/org/apache/ftpserver/impl/FtpReplyTranslator.java b/core/src/main/java/org/apache/ftpserver/impl/FtpReplyTranslator.java index 391356d1..5a6a381b 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/FtpReplyTranslator.java +++ b/core/src/main/java/org/apache/ftpserver/impl/FtpReplyTranslator.java @@ -123,6 +123,14 @@ public class FtpReplyTranslator { /** Server starting time */ public static final String STAT_START_TIME = "stat.start.time"; + /** + * A private constructor + */ + private FtpReplyTranslator() { + // Nothing to do + } + + /** * Returns the translated message. * @@ -163,11 +171,13 @@ private static String replaceVariables(FtpIoSession session, int startIndex = 0; int openIndex = str.indexOf('{', startIndex); + if (openIndex == -1) { return str; } int closeIndex = str.indexOf('}', startIndex); + if ((closeIndex == -1) || (openIndex > closeIndex)) { return str; } @@ -177,8 +187,7 @@ private static String replaceVariables(FtpIoSession session, while (true) { String varName = str.substring(openIndex + 1, closeIndex); - sb.append(getVariableValue(session, request, context, code, - basicMsg, varName)); + sb.append(getVariableValue(session, request, context, code, basicMsg, varName)); startIndex = closeIndex + 1; openIndex = str.indexOf('{', startIndex); diff --git a/core/src/main/java/org/apache/ftpserver/impl/IODataConnection.java b/core/src/main/java/org/apache/ftpserver/impl/IODataConnection.java index 633c4b19..1a76edbe 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/IODataConnection.java +++ b/core/src/main/java/org/apache/ftpserver/impl/IODataConnection.java @@ -61,6 +61,13 @@ public class IODataConnection implements DataConnection { private final ServerDataConnectionFactory factory; + /** + * Create a IODataConnection instance + * + * @param socket The connection socket + * @param session The FTP session + * @param factory The DataConnection factory to use + */ public IODataConnection(final Socket socket, final FtpIoSession session, final ServerDataConnectionFactory factory) { this.session = session; @@ -132,11 +139,8 @@ public final long transferFromClient(FtpSession session, maxRate = transferRateRequest.getMaxUploadRate(); } - InputStream is = getDataInputStream(); - try { + try(InputStream is = getDataInputStream()) { return transfer(session, false, is, out, maxRate); - } finally { - IoUtils.close(is); } } @@ -157,11 +161,8 @@ public final long transferToClient(FtpSession session, final InputStream in) maxRate = transferRateRequest.getMaxDownloadRate(); } - OutputStream out = getDataOutputStream(); - try { + try (OutputStream out = getDataOutputStream()) { return transfer(session, true, in, out, maxRate); - } finally { - IoUtils.close(out); } } @@ -172,26 +173,20 @@ public final long transferToClient(FtpSession session, final InputStream in) * org.apache.ftpserver.FtpDataConnection2#transferToClient(java.lang.String * ) */ - public final void transferToClient(FtpSession session, final String str) - throws IOException { + public final void transferToClient(FtpSession session, final String str) throws IOException { OutputStream out = getDataOutputStream(); - Writer writer = null; - try { - writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); + //Writer writer = null; + + try (Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)){ writer.write(str); // update session if (session instanceof DefaultFtpSession) { - ((DefaultFtpSession) session).increaseWrittenDataBytes(str - .getBytes(StandardCharsets.UTF_8).length); + ((DefaultFtpSession) session).increaseWrittenDataBytes(str.getBytes(StandardCharsets.UTF_8).length); } - } finally { - if (writer != null) { - writer.flush(); - } - IoUtils.close(writer); - } + writer.flush(); + } } private long transfer(FtpSession session, boolean isWrite, diff --git a/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java b/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java index 1d49276d..ec9f9553 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java +++ b/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java @@ -40,7 +40,7 @@ /** * Internal class, do not use directly. - * + *

    * We can get the FTP data connection using this class. It uses either PORT or PASV command. * * @author Apache MINA Project @@ -71,6 +71,12 @@ public class IODataConnectionFactory implements ServerDataConnectionFactory { FtpIoSession session; + /** + * Create a IODataConnectionFactory instance + * + * @param serverContext The FTP server context + * @param session The FTP session + */ public IODataConnectionFactory(final FtpServerContext serverContext, final FtpIoSession session) { this.session = session; this.serverContext = serverContext; diff --git a/core/src/main/java/org/apache/ftpserver/impl/LocalizedFtpReply.java b/core/src/main/java/org/apache/ftpserver/impl/LocalizedFtpReply.java index 6a5bf7bb..dc17e19c 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/LocalizedFtpReply.java +++ b/core/src/main/java/org/apache/ftpserver/impl/LocalizedFtpReply.java @@ -30,7 +30,17 @@ * @author Apache MINA Project */ public class LocalizedFtpReply extends DefaultFtpReply { - + /** + * Provide a localized message + * + * @param session the FTP session for which a reply is to be sent + * @param request the FTP request object + * @param context the FTP server context + * @param code the reply code + * @param subId the ID of the sub message + * @param basicMsg the basic message + * @return the translated message + */ public static LocalizedFtpReply translate(FtpIoSession session, FtpRequest request, FtpServerContext context, int code, String subId, String basicMsg) { String msg = FtpReplyTranslator.translateMessage(session, request, context, code, subId, @@ -42,10 +52,8 @@ public static LocalizedFtpReply translate(FtpIoSession session, FtpRequest reque /** * Creates a new instance of LocalizedFtpReply. * - * @param code - * the reply code - * @param message - * the reply text + * @param code the reply code + * @param message the reply text */ public LocalizedFtpReply(int code, String message) { super(code, message); diff --git a/core/src/main/java/org/apache/ftpserver/impl/PassivePorts.java b/core/src/main/java/org/apache/ftpserver/impl/PassivePorts.java index a27bbc74..f61c097c 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/PassivePorts.java +++ b/core/src/main/java/org/apache/ftpserver/impl/PassivePorts.java @@ -77,6 +77,7 @@ private static Set parse(final String portsString) { boolean inRange = false; Integer lastPort = Integer.valueOf(1); StringTokenizer st = new StringTokenizer(portsString, ",;-", true); + while (st.hasMoreTokens()) { String token = st.nextToken().trim(); @@ -144,12 +145,26 @@ private static void verifyPort(final int port) { } } + /** + * Create an instance with a port and the flag that tells + * if the port should be checked before being used + * + * @param passivePorts The port + * @param checkIfBound The check for port bound flag + */ public PassivePorts(final String passivePorts, boolean checkIfBound) { this(parse(passivePorts), checkIfBound); this.passivePortsString = passivePorts; } + /** + * Create an instance with a set of ports and the flag that tells + * if the ports should be checked before being used + * + * @param passivePorts The set of ports + * @param checkIfBound The check for ports bound flag + */ public PassivePorts(Set passivePorts, boolean checkIfBound) { if (passivePorts == null) { throw new NullPointerException("passivePorts can not be null"); @@ -198,6 +213,11 @@ private boolean checkPortUnbound(int port) { } } + /** + * Reserve the next port + * + * @return The reserved port + */ public synchronized int reserveNextPort() { // create a copy of the free ports, so that we can keep track of the tested ports List freeCopy = new ArrayList<>(freeList); @@ -229,6 +249,11 @@ public synchronized int reserveNextPort() { return -1; } + /** + * Release a port + * + * @param port The port to release + */ public synchronized void releasePort(final int port) { if (port == 0) { // Ignore port 0 being released, diff --git a/core/src/main/java/org/apache/ftpserver/impl/ServerDataConnectionFactory.java b/core/src/main/java/org/apache/ftpserver/impl/ServerDataConnectionFactory.java index 136317c4..c315c297 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/ServerDataConnectionFactory.java +++ b/core/src/main/java/org/apache/ftpserver/impl/ServerDataConnectionFactory.java @@ -64,6 +64,11 @@ InetSocketAddress initPassiveDataConnection() */ void setServerControlAddress(InetAddress serverControlAddress); + /** + * Switch to ZIP mode + * + * @param zip The flag value + */ void setZipMode(boolean zip); /** diff --git a/core/src/main/java/org/apache/ftpserver/listener/nio/FtpHandlerAdapter.java b/core/src/main/java/org/apache/ftpserver/listener/nio/FtpHandlerAdapter.java index 833b041f..4d7e41d3 100644 --- a/core/src/main/java/org/apache/ftpserver/listener/nio/FtpHandlerAdapter.java +++ b/core/src/main/java/org/apache/ftpserver/listener/nio/FtpHandlerAdapter.java @@ -43,6 +43,12 @@ public class FtpHandlerAdapter extends IoHandlerAdapter { private FtpHandler ftpHandler; + /** + * Create a FtpHandlerAdapter instance + * + * @param context The FTP server context + * @param ftpHandler The FtpHandler instance + */ public FtpHandlerAdapter(FtpServerContext context, FtpHandler ftpHandler) { this.context = context; this.ftpHandler = ftpHandler; @@ -51,8 +57,7 @@ public FtpHandlerAdapter(FtpServerContext context, FtpHandler ftpHandler) { /** * {@inheritDoc} */ - public void exceptionCaught(IoSession session, Throwable cause) - throws Exception { + public void exceptionCaught(IoSession session, Throwable cause) throws Exception { FtpIoSession ftpSession = new FtpIoSession(session, context); ftpHandler.exceptionCaught(ftpSession, cause); } @@ -60,8 +65,7 @@ public void exceptionCaught(IoSession session, Throwable cause) /** * {@inheritDoc} */ - public void messageReceived(IoSession session, Object message) - throws Exception { + public void messageReceived(IoSession session, Object message) throws Exception { FtpIoSession ftpSession = new FtpIoSession(session, context); FtpRequest request = new DefaultFtpRequest(message.toString()); @@ -92,14 +96,12 @@ public void sessionCreated(IoSession session) throws Exception { MdcInjectionFilter.setProperty(session, "session", ftpSession.getSessionId().toString()); ftpHandler.sessionCreated(ftpSession); - } /** * {@inheritDoc} */ - public void sessionIdle(IoSession session, IdleStatus status) - throws Exception { + public void sessionIdle(IoSession session, IdleStatus status) throws Exception { FtpIoSession ftpSession = new FtpIoSession(session, context); ftpHandler.sessionIdle(ftpSession, status); } @@ -112,13 +114,22 @@ public void sessionOpened(IoSession session) throws Exception { ftpHandler.sessionOpened(ftpSession); } + /** + * Get the FTPHandler instance + * + * @return The FTPHandler instance + */ public FtpHandler getFtpHandler() { return ftpHandler; } + /** + * Set the FTPHandler instance + * + * @param handler The FTPHandler instance + */ public void setFtpHandler(FtpHandler handler) { this.ftpHandler = handler; } - } diff --git a/core/src/main/java/org/apache/ftpserver/listener/nio/FtpLoggingFilter.java b/core/src/main/java/org/apache/ftpserver/listener/nio/FtpLoggingFilter.java index b8e0f262..31a5d5b6 100644 --- a/core/src/main/java/org/apache/ftpserver/listener/nio/FtpLoggingFilter.java +++ b/core/src/main/java/org/apache/ftpserver/listener/nio/FtpLoggingFilter.java @@ -39,25 +39,25 @@ public class FtpLoggingFilter extends LoggingFilter { private final Logger logger; /** - * @see LoggingFilter#LoggingFilter() + * Create an instance using the FtpLoggingFilter class name as a logger name */ public FtpLoggingFilter() { this(FtpLoggingFilter.class.getName()); } /** - * @see LoggingFilter#LoggingFilter(Class) + * Create an instance of this class * - * {@inheritDoc} + * @param clazz The class for which we want this logger to be named from */ public FtpLoggingFilter(Class clazz) { this(clazz.getName()); } /** - * @see LoggingFilter#LoggingFilter(String) + * Create an instance of this class * - * {@inheritDoc} + * @param name The logger name to use */ public FtpLoggingFilter(String name) { super(name); @@ -66,9 +66,6 @@ public FtpLoggingFilter(String name) { } /** - * @see LoggingFilter#messageReceived(org.apache.mina.core.filterchain.IoFilter.NextFilter, - * IoSession, Object) - * * {@inheritDoc} */ @Override diff --git a/core/src/main/java/org/apache/ftpserver/listener/nio/FtpResponseEncoder.java b/core/src/main/java/org/apache/ftpserver/listener/nio/FtpResponseEncoder.java index 4276f8f2..6a141183 100644 --- a/core/src/main/java/org/apache/ftpserver/listener/nio/FtpResponseEncoder.java +++ b/core/src/main/java/org/apache/ftpserver/listener/nio/FtpResponseEncoder.java @@ -44,13 +44,19 @@ protected CharsetEncoder initialValue() { } }; + /** + * Create a FtpResponseEncoder instance + */ + public FtpResponseEncoder() { + // Nothing to do + } + + public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception { String value = message.toString(); - IoBuffer buf = IoBuffer.allocate(value.length()).setAutoExpand(true); buf.putString(value, ENCODER.get()); - buf.flip(); out.write(buf); } diff --git a/core/src/main/java/org/apache/ftpserver/listener/nio/FtpServerProtocolCodecFactory.java b/core/src/main/java/org/apache/ftpserver/listener/nio/FtpServerProtocolCodecFactory.java index 796ad0c4..54060582 100644 --- a/core/src/main/java/org/apache/ftpserver/listener/nio/FtpServerProtocolCodecFactory.java +++ b/core/src/main/java/org/apache/ftpserver/listener/nio/FtpServerProtocolCodecFactory.java @@ -38,11 +38,23 @@ public class FtpServerProtocolCodecFactory implements ProtocolCodecFactory { private final ProtocolDecoder decoder = new TextLineDecoder(StandardCharsets.UTF_8); private final ProtocolEncoder encoder = new FtpResponseEncoder(); + /** + * Create a FtpServerProtocolCodecFactory instance + */ + public FtpServerProtocolCodecFactory() { + // Nothing to do + } + /** + * {@inheritDoc} + */ public ProtocolDecoder getDecoder(IoSession session) throws Exception { return decoder; } + /** + * {@inheritDoc} + */ public ProtocolEncoder getEncoder(IoSession session) throws Exception { return encoder; } diff --git a/core/src/main/java/org/apache/ftpserver/listener/nio/NioListener.java b/core/src/main/java/org/apache/ftpserver/listener/nio/NioListener.java index 63f5fd8e..e8cca033 100644 --- a/core/src/main/java/org/apache/ftpserver/listener/nio/NioListener.java +++ b/core/src/main/java/org/apache/ftpserver/listener/nio/NioListener.java @@ -111,8 +111,6 @@ public NioListener(String serverAddress, int port, boolean implicitSsl, SslConfi } /** - * @see Listener#start(FtpServerContext) - * * {@inheritDoc} */ public synchronized void start(FtpServerContext context) { @@ -209,8 +207,6 @@ private void updatePort() { } /** - * @see Listener#stop() - * * {@inheritDoc} */ public synchronized void stop() { @@ -225,8 +221,6 @@ public synchronized void stop() { } /** - * @see Listener#isStopped() - * * {@inheritDoc} */ public boolean isStopped() { @@ -234,8 +228,6 @@ public boolean isStopped() { } /** - * @see Listener#isSuspended() - * * {@inheritDoc} */ public boolean isSuspended() { @@ -243,8 +235,6 @@ public boolean isSuspended() { } /** - * @see Listener#resume() - * * {@inheritDoc} */ public synchronized void resume() { @@ -264,8 +254,6 @@ public synchronized void resume() { } /** - * @see Listener#suspend() - * * {@inheritDoc} */ public synchronized void suspend() { @@ -279,8 +267,6 @@ public synchronized void suspend() { } /** - * @see Listener#getActiveSessions() - * * {@inheritDoc} */ public synchronized Set getActiveSessions() { diff --git a/core/src/main/java/org/apache/ftpserver/main/Daemon.java b/core/src/main/java/org/apache/ftpserver/main/Daemon.java index dfc12ae2..19f95330 100644 --- a/core/src/main/java/org/apache/ftpserver/main/Daemon.java +++ b/core/src/main/java/org/apache/ftpserver/main/Daemon.java @@ -41,15 +41,24 @@ public class Daemon { private static Object lock = new Object(); /** - * Main entry point for the daemon + * Create a Daemon instance. + */ + private Daemon() { + // Nothing to do + } + + /** + * Main entry point for the daemon. It can only be started once. + * * @param args The arguments - * @throws Exception + * @throws Exception If any error was met during the launch */ public static void main(String[] args) throws Exception { try { if (server == null) { // get configuration server = getConfiguration(args); + if (server == null) { LOG.error("No configuration provided"); throw new FtpException("No configuration provided"); @@ -66,6 +75,7 @@ public static void main(String[] args) throws Exception { LOG.info("Starting FTP server daemon"); server.start(); + // TODO: Should encapsulate the server.start()... synchronized (lock) { lock.wait(); } @@ -73,6 +83,7 @@ public static void main(String[] args) throws Exception { synchronized (lock) { lock.notify(); } + LOG.info("Stopping FTP server daemon"); server.stop(); } @@ -85,15 +96,14 @@ public static void main(String[] args) throws Exception { * Get the configuration object. */ private static FtpServer getConfiguration(String[] args) throws Exception { - FtpServer server = null; + if (args == null || args.length < 2) { LOG.info("Using default configuration...."); server = new FtpServerFactory().createServer(); } else if ((args.length == 2) && args[1].equals("-default")) { // supported for backwards compatibility, but not documented - System.out - .println("The -default switch is deprecated, please use --default instead"); + System.out.println("The -default switch is deprecated, please use --default instead"); LOG.info("Using default configuration...."); server = new FtpServerFactory().createServer(); } else if ((args.length == 2) && args[1].equals("--default")) { @@ -108,16 +118,14 @@ private static FtpServer getConfiguration(String[] args) throws Exception { server = (FtpServer) ctx.getBean("server"); } else { String[] beanNames = ctx.getBeanNamesForType(FtpServer.class); + if (beanNames.length == 1) { server = (FtpServer) ctx.getBean(beanNames[0]); } else if (beanNames.length > 1) { - System.out - .println("Using the first server defined in the configuration, named " - + beanNames[0]); + System.out.println("Using the first server defined in the configuration, named " + beanNames[0]); server = (FtpServer) ctx.getBean(beanNames[0]); } else { - System.err - .println("XML configuration does not contain a server configuration"); + System.err.println("XML configuration does not contain a server configuration"); } } } else { diff --git a/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java b/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java index 9c998bc7..e73632a8 100644 --- a/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java +++ b/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java @@ -36,6 +36,13 @@ public class MessageResourceFactory { /** The directory where the message are stored */ private File customMessageDirectory; + /** + * Create a MessageResourceFactory instance + */ + public MessageResourceFactory() { + // Nothing to do + } + /** * Create an {@link MessageResource} based on the configuration on this factory * diff --git a/core/src/main/java/org/apache/ftpserver/ssl/SslConfiguration.java b/core/src/main/java/org/apache/ftpserver/ssl/SslConfiguration.java index aeeebdcc..79004e24 100644 --- a/core/src/main/java/org/apache/ftpserver/ssl/SslConfiguration.java +++ b/core/src/main/java/org/apache/ftpserver/ssl/SslConfiguration.java @@ -30,14 +30,14 @@ * @author Apache MINA Project */ public interface SslConfiguration { + /** The default TLS enabled protocol */ String DEFAULT_ENABLED_PROTOCOL = "TLSv1.2"; /** * Returns the socket factory that can be used to create sockets using this SslConfiguration. * * @return the socket factory that can be used to create sockets using this SslConfiguration. - * @throws GeneralSecurityException - * if any error occurs while creating the socket factory. + * @throws GeneralSecurityException if any error occurs while creating the socket factory. * */ SSLSocketFactory getSocketFactory() throws GeneralSecurityException; @@ -46,7 +46,7 @@ public interface SslConfiguration { * Return the SSL context for this configuration * * @return The {@link SSLContext} - * @throws GeneralSecurityException + * @throws GeneralSecurityException If we got an error trying to get the SSL context */ SSLContext getSSLContext() throws GeneralSecurityException; @@ -56,7 +56,7 @@ public interface SslConfiguration { * @param protocol * The protocol, SSL or TLS must be supported * @return The {@link SSLContext} - * @throws GeneralSecurityException + * @throws GeneralSecurityException If we got an error trying to get the SSL context */ SSLContext getSSLContext(String protocol) throws GeneralSecurityException; diff --git a/core/src/main/java/org/apache/ftpserver/ssl/SslConfigurationFactory.java b/core/src/main/java/org/apache/ftpserver/ssl/SslConfigurationFactory.java index 4fb4a832..d50c59b1 100644 --- a/core/src/main/java/org/apache/ftpserver/ssl/SslConfigurationFactory.java +++ b/core/src/main/java/org/apache/ftpserver/ssl/SslConfigurationFactory.java @@ -31,7 +31,6 @@ import org.apache.ftpserver.FtpServerConfigurationException; import org.apache.ftpserver.ssl.impl.DefaultSslConfiguration; -import org.apache.ftpserver.util.IoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,7 +40,7 @@ * @author Apache MINA Project */ public class SslConfigurationFactory { - + /** Class logger */ private final Logger LOG = LoggerFactory.getLogger(SslConfigurationFactory.class); private File keystoreFile = new File("./res/.keystore"); @@ -70,6 +69,13 @@ public class SslConfigurationFactory { private String[] enabledCipherSuites; + /** + * A SslConfigurationFactory constructor + */ + public SslConfigurationFactory() { + // Nothing to do + } + /** * The key store file used by this configuration * @@ -322,27 +328,26 @@ public void setTruststoreAlgorithm(String trustStoreAlgorithm) { private KeyStore loadStore(File storeFile, String storeType, String storePass) throws IOException, GeneralSecurityException { - InputStream fin = null; - try { + if (storeFile.exists()) { - LOG.debug("Trying to load store from file"); - fin = new FileInputStream(storeFile); - } else { - LOG.debug("Trying to load store from classpath"); - fin = getClass().getClassLoader().getResourceAsStream(storeFile.getPath()); + LOG.debug("Trying to load store from file"); - if (fin == null) { - throw new FtpServerConfigurationException("Key store could not be loaded from " + storeFile.getPath()); - } - } + try (InputStream fin = new FileInputStream(storeFile)) { + KeyStore store = KeyStore.getInstance(storeType); + store.load(fin, storePass.toCharArray()); - KeyStore store = KeyStore.getInstance(storeType); - store.load(fin, storePass.toCharArray()); + return store; + } + } else { + LOG.debug("Trying to load store from classpath"); - return store; - } finally { - IoUtils.close(fin); - } + try (InputStream fin = getClass().getClassLoader().getResourceAsStream(storeFile.getPath())) { + KeyStore store = KeyStore.getInstance(storeType); + store.load(fin, storePass.toCharArray()); + + return store; + } + } } /** @@ -420,7 +425,7 @@ public String[] getEnabledCipherSuites() { * Set the allowed cipher suites, note that the exact list of supported cipher suites differs between JRE * implementations. * - * @param enabledCipherSuites + * @param enabledCipherSuites The set of enabled ciphers */ public void setEnabledCipherSuites(String[] enabledCipherSuites) { if (enabledCipherSuites != null) { diff --git a/core/src/main/java/org/apache/ftpserver/ssl/impl/DefaultSslConfiguration.java b/core/src/main/java/org/apache/ftpserver/ssl/impl/DefaultSslConfiguration.java index bae0fbf6..0caa5b43 100644 --- a/core/src/main/java/org/apache/ftpserver/ssl/impl/DefaultSslConfiguration.java +++ b/core/src/main/java/org/apache/ftpserver/ssl/impl/DefaultSslConfiguration.java @@ -123,8 +123,9 @@ public SSLContext getSSLContext(String enabledProtocol) throws GeneralSecurityEx /** * @deprecated Use {@link #getEnabledProtocol()} + * Get the enabled protocol * - * {@inheritDoc} + * @return The enabled protocol */ public String getEnabledProtoco() { return getEnabledProtocol(); diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/ClearTextPasswordEncryptor.java b/core/src/main/java/org/apache/ftpserver/usermanager/ClearTextPasswordEncryptor.java index c8d7824b..2f61f3e9 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/ClearTextPasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/ClearTextPasswordEncryptor.java @@ -28,8 +28,14 @@ * @author Apache MINA Project */ public class ClearTextPasswordEncryptor implements PasswordEncryptor { + /** A ClearTextPasswordEncryptor constructor */ + public ClearTextPasswordEncryptor() { + // Nothing to do + } + /** * Returns the clear text password + * * @param password The password to encrypt * @return The encrypted password */ diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java b/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java index e50bdf15..83149b57 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java @@ -31,7 +31,6 @@ * @author Apache MINA Project */ public class DbUserManagerFactory implements UserManagerFactory { - private String adminName = "admin"; private String insertUserStmt; @@ -52,6 +51,13 @@ public class DbUserManagerFactory implements UserManagerFactory { private PasswordEncryptor passwordEncryptor = new Md5PasswordEncryptor(); + /** + * Create a DbUserManagerFactory instance + */ + public DbUserManagerFactory() { + // Nothing to do + } + public UserManager createUserManager() { if (dataSource == null) { throw new FtpServerConfigurationException( diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/Md5PasswordEncryptor.java b/core/src/main/java/org/apache/ftpserver/usermanager/Md5PasswordEncryptor.java index 01739495..f59a201f 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/Md5PasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/Md5PasswordEncryptor.java @@ -29,6 +29,12 @@ * @author Apache MINA Project */ public class Md5PasswordEncryptor implements PasswordEncryptor { + /** + * Create a Md5PasswordEncryptor instance + */ + public Md5PasswordEncryptor() { + // Nothing to do + } /** * Hashes the password using MD5 @@ -46,6 +52,7 @@ public boolean matches(String passwordToCheck, String storedPassword) { if (storedPassword == null) { throw new NullPointerException("storedPassword can not be null"); } + if (passwordToCheck == null) { throw new NullPointerException("passwordToCheck can not be null"); } diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java b/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java index fb4777f8..f0e63725 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java @@ -38,6 +38,13 @@ public class PropertiesUserManagerFactory implements UserManagerFactory { private URL userDataURL; + /** + * Create a PropertiesUserManagerFactory instance + */ + public PropertiesUserManagerFactory() { + // Nothing to do + } + /** * The default password encryption method. It's a one way mechanism, ie * a password is *never* unencrypted. @@ -78,6 +85,7 @@ public void setAdminName(String adminName) { /** * Retrieve the file used to load and store users + * * @return The file */ public File getFile() { @@ -87,8 +95,7 @@ public File getFile() { /** * Set the file used to store and read users. * - * @param propFile - * A file containing users + * @param propFile A file containing users */ public void setFile(File propFile) { this.userDataFile = propFile; @@ -96,6 +103,7 @@ public void setFile(File propFile) { /** * Retrieve the URL used to load and store users + * * @return The {@link URL} */ public URL getUrl() { @@ -105,8 +113,7 @@ public URL getUrl() { /** * Set the URL used to store and read users. * - * @param userDataURL - * A {@link URL} containing users + * @param userDataURL A {@link URL} containing users */ public void setUrl(URL userDataURL) { this.userDataURL = userDataURL; @@ -114,6 +121,7 @@ public void setUrl(URL userDataURL) { /** * Retrieve the password encryptor used by user managers created by this factory + * * @return The password encryptor. Default to {@link Md5PasswordEncryptor} * if no other has been provided */ @@ -123,6 +131,7 @@ public PasswordEncryptor getPasswordEncryptor() { /** * Set the password encryptor to use by user managers created by this factory + * * @param passwordEncryptor The password encryptor */ public void setPasswordEncryptor(PasswordEncryptor passwordEncryptor) { diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/SaltedPasswordEncryptor.java b/core/src/main/java/org/apache/ftpserver/usermanager/SaltedPasswordEncryptor.java index 8a52ba85..b449c463 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/SaltedPasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/SaltedPasswordEncryptor.java @@ -35,17 +35,25 @@ * @author Apache MINA Project */ public class SaltedPasswordEncryptor implements PasswordEncryptor { - private SecureRandom rnd = new SecureRandom(); private static final int MAX_SEED = 99999999; private static final int HASH_ITERATIONS = 1000; + /** + * Create a SaltedPasswordEncryptor instance + */ + public SaltedPasswordEncryptor() { + // Nothing to do + } + private String encrypt(String password, String salt) { String hash = salt + password; + for (int i = 0; i < HASH_ITERATIONS; i++) { hash = EncryptUtils.encryptMD5(hash); } + return salt + ":" + hash; } @@ -68,6 +76,7 @@ public boolean matches(String passwordToCheck, String storedPassword) { if (storedPassword == null) { throw new NullPointerException("storedPassword can not be null"); } + if (passwordToCheck == null) { throw new NullPointerException("passwordToCheck can not be null"); } @@ -84,5 +93,4 @@ public boolean matches(String passwordToCheck, String storedPassword) { return PasswordUtil.secureCompareFast(encrypt(passwordToCheck, storedSalt).toLowerCase(), storedPassword.toLowerCase()); } - } diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/Sha1PasswordEncryptor.java b/core/src/main/java/org/apache/ftpserver/usermanager/Sha1PasswordEncryptor.java index 9a292743..5eadf06d 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/Sha1PasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/Sha1PasswordEncryptor.java @@ -30,9 +30,16 @@ * @author Apache MINA Project */ public class Sha1PasswordEncryptor implements PasswordEncryptor { + /** + * Create a Sha1PasswordEncryptor instance + */ + public Sha1PasswordEncryptor() { + // Nothing to do + } /** * Hashes the password using SHA-1 + * * @param password The password to encrypt * @return The encrypted password */ @@ -47,6 +54,7 @@ public boolean matches(String passwordToCheck, String storedPassword) { if (storedPassword == null) { throw new NullPointerException("storedPassword can not be null"); } + if (passwordToCheck == null) { throw new NullPointerException("passwordToCheck can not be null"); } diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/Sha256PasswordEncryptor.java b/core/src/main/java/org/apache/ftpserver/usermanager/Sha256PasswordEncryptor.java index fda69cb7..059f68ba 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/Sha256PasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/Sha256PasswordEncryptor.java @@ -29,9 +29,16 @@ * @author Apache MINA Project */ public class Sha256PasswordEncryptor implements PasswordEncryptor { + /** + * Create a Sha256PasswordEncryptor instance + */ + public Sha256PasswordEncryptor() { + // Nothing to do + } /** * Hashes the password using SHA-256 + * * @param password The password to encrypt * @return The encrypted password */ @@ -46,6 +53,7 @@ public boolean matches(String passwordToCheck, String storedPassword) { if (storedPassword == null) { throw new NullPointerException("storedPassword can not be null"); } + if (passwordToCheck == null) { throw new NullPointerException("passwordToCheck can not be null"); } diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/Sha512PasswordEncryptor.java b/core/src/main/java/org/apache/ftpserver/usermanager/Sha512PasswordEncryptor.java index 503d2dd8..44fa2560 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/Sha512PasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/Sha512PasswordEncryptor.java @@ -29,9 +29,16 @@ * @author Apache MINA Project */ public class Sha512PasswordEncryptor implements PasswordEncryptor { + /** + * Create a Sha512PasswordEncryptor instance + */ + public Sha512PasswordEncryptor() { + // Nothing to do + } /** * Hashes the password using SHA-512 + * * @param password The password to encrypt * @return The encrypted password */ @@ -46,6 +53,7 @@ public boolean matches(String passwordToCheck, String storedPassword) { if (storedPassword == null) { throw new NullPointerException("storedPassword can not be null"); } + if (passwordToCheck == null) { throw new NullPointerException("passwordToCheck can not be null"); } diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/UserFactory.java b/core/src/main/java/org/apache/ftpserver/usermanager/UserFactory.java index eaa353ab..1144ebc1 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/UserFactory.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/UserFactory.java @@ -45,8 +45,17 @@ public class UserFactory { private List authorities = new ArrayList<>(); + /** + * Public constructor + */ + public UserFactory() { + // Nothing to do + } + + /** * Creates a user based on the configuration set on the factory + * * @return The created user */ public User createUser() { @@ -63,6 +72,7 @@ public User createUser() { /** * Get the user name for users created by this factory + * * @return The user name */ public String getName() { @@ -71,6 +81,7 @@ public String getName() { /** * Set the user name for users created by this factory + * * @param name The user name */ public void setName(String name) { @@ -79,6 +90,7 @@ public void setName(String name) { /** * Get the password for users created by this factory + * * @return The password */ public String getPassword() { @@ -87,6 +99,7 @@ public String getPassword() { /** * Set the user name for users created by this factory + * * @param password The password */ public void setPassword(String password) { @@ -95,6 +108,7 @@ public void setPassword(String password) { /** * Get the max idle time for users created by this factory + * * @return The max idle time in seconds */ public int getMaxIdleTime() { @@ -103,6 +117,7 @@ public int getMaxIdleTime() { /** * Set the user name for users created by this factory + * * @param maxIdleTimeSec The max idle time in seconds */ public void setMaxIdleTime(int maxIdleTimeSec) { @@ -111,6 +126,7 @@ public void setMaxIdleTime(int maxIdleTimeSec) { /** * Get the home directory for users created by this factory + * * @return The home directory path */ public String getHomeDirectory() { @@ -119,6 +135,7 @@ public String getHomeDirectory() { /** * Set the user name for users created by this factory + * * @param homeDir The home directory path */ public void setHomeDirectory(String homeDir) { @@ -127,6 +144,7 @@ public void setHomeDirectory(String homeDir) { /** * Get the enabled status for users created by this factory + * * @return true if the user is enabled (allowed to log in) */ public boolean isEnabled() { @@ -135,6 +153,7 @@ public boolean isEnabled() { /** * Get the enabled status for users created by this factory + * * @param isEnabled true if the user should be enabled (allowed to log in) */ public void setEnabled(boolean isEnabled) { @@ -143,6 +162,7 @@ public void setEnabled(boolean isEnabled) { /** * Get the authorities for users created by this factory + * * @return The authorities */ public List getAuthorities() { @@ -151,6 +171,7 @@ public List getAuthorities() { /** * Set the authorities for users created by this factory + * * @param authorities The authorities */ public void setAuthorities(List authorities) { diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/AbstractUserManager.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/AbstractUserManager.java index 5b073b4a..3b1b892e 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/AbstractUserManager.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/AbstractUserManager.java @@ -66,6 +66,9 @@ public abstract class AbstractUserManager implements UserManager { private final PasswordEncryptor passwordEncryptor; + /** + * An AbstractUserManager constructor. The default password encryptor is using MD5 + */ public AbstractUserManager() { this(null, new Md5PasswordEncryptor()); } diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginPermission.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginPermission.java index 5ed6aeb7..9267dbd2 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginPermission.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginPermission.java @@ -24,7 +24,7 @@ /** * Internal class, do not use directly. - * + *

    * The max upload rate permission * * @author Apache MINA Project @@ -35,34 +35,32 @@ public class ConcurrentLoginPermission implements Authority { private final int maxConcurrentLoginsPerIP; - public ConcurrentLoginPermission(int maxConcurrentLogins, - int maxConcurrentLoginsPerIP) { + /** + * Create an instance + * + * @param maxConcurrentLogins The maximum number of concurren logins + * @param maxConcurrentLoginsPerIP The maximum number of concurren logins per IP + */ + public ConcurrentLoginPermission(int maxConcurrentLogins, int maxConcurrentLoginsPerIP) { this.maxConcurrentLogins = maxConcurrentLogins; this.maxConcurrentLoginsPerIP = maxConcurrentLoginsPerIP; } /** - * @see Authority#authorize(AuthorizationRequest) - * * {@inheritDoc} */ public AuthorizationRequest authorize(AuthorizationRequest request) { if (request instanceof ConcurrentLoginRequest) { ConcurrentLoginRequest concurrentLoginRequest = (ConcurrentLoginRequest) request; - if (maxConcurrentLogins != 0 - && maxConcurrentLogins < concurrentLoginRequest - .getConcurrentLogins()) { + if (maxConcurrentLogins != 0 && maxConcurrentLogins < concurrentLoginRequest.getConcurrentLogins()) { return null; } else if (maxConcurrentLoginsPerIP != 0 - && maxConcurrentLoginsPerIP < concurrentLoginRequest - .getConcurrentLoginsFromThisIP()) { + && maxConcurrentLoginsPerIP < concurrentLoginRequest.getConcurrentLoginsFromThisIP()) { return null; } else { - concurrentLoginRequest - .setMaxConcurrentLogins(maxConcurrentLogins); - concurrentLoginRequest - .setMaxConcurrentLoginsPerIP(maxConcurrentLoginsPerIP); + concurrentLoginRequest.setMaxConcurrentLogins(maxConcurrentLogins); + concurrentLoginRequest.setMaxConcurrentLoginsPerIP(maxConcurrentLoginsPerIP); return concurrentLoginRequest; } @@ -72,8 +70,6 @@ public AuthorizationRequest authorize(AuthorizationRequest request) { } /** - * @see Authority#canAuthorize(AuthorizationRequest) - * * {@inheritDoc} */ public boolean canAuthorize(AuthorizationRequest request) { diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginRequest.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginRequest.java index f173f02c..34465271 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginRequest.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginRequest.java @@ -23,7 +23,7 @@ /** * Internal class, do not use directly. - * + *

    * Class representing a request to log in a number of concurrent times * * @author Apache MINA Project @@ -39,11 +39,12 @@ public class ConcurrentLoginRequest implements AuthorizationRequest { private int maxConcurrentLoginsPerIP = 0; /** - * @param concurrentLogins - * @param concurrentLoginsFromThisIP + * Create a ConcurrentLoginRequest instance + * + * @param concurrentLogins Number of concurrent logins + * @param concurrentLoginsFromThisIP Number of concurrent logins for this IP address */ - public ConcurrentLoginRequest(int concurrentLogins, - int concurrentLoginsFromThisIP) { + public ConcurrentLoginRequest(int concurrentLogins, int concurrentLoginsFromThisIP) { super(); this.concurrentLogins = concurrentLogins; this.concurrentLoginsFromThisIP = concurrentLoginsFromThisIP; @@ -81,8 +82,7 @@ public int getMaxConcurrentLogins() { /** * Set the maximum allowed concurrent logins for this user * - * @param maxConcurrentLogins - * Set max allowed concurrent connections + * @param maxConcurrentLogins Set max allowed concurrent connections */ void setMaxConcurrentLogins(int maxConcurrentLogins) { this.maxConcurrentLogins = maxConcurrentLogins; @@ -102,8 +102,7 @@ public int getMaxConcurrentLoginsPerIP() { /** * Set the maximum allowed concurrent logins per IP for this user * - * @param maxConcurrentLoginsPerIP - * Set max allowed concurrent connections per IP + * @param maxConcurrentLoginsPerIP Set max allowed concurrent connections per IP */ void setMaxConcurrentLoginsPerIP(int maxConcurrentLoginsPerIP) { this.maxConcurrentLoginsPerIP = maxConcurrentLoginsPerIP; diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/DbUserManager.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/DbUserManager.java index 908cec36..37b691b7 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/DbUserManager.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/DbUserManager.java @@ -55,7 +55,7 @@ * @author Apache MINA Project */ public class DbUserManager extends AbstractUserManager { - + /** The class logger */ private final Logger LOG = LoggerFactory.getLogger(DbUserManager.class); private String insertUserStmt; @@ -124,8 +124,7 @@ public DataSource getDataSource() { /** * Set the data source to be used by the user manager * - * @param dataSource - * The data source to use + * @param dataSource The data source to use */ public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; @@ -144,8 +143,7 @@ public String getSqlUserInsert() { * Set the SQL INSERT statement used to add a new user. All the dynamic * values will be replaced during runtime. * - * @param sql - * The SQL statement + * @param sql The SQL statement */ public void setSqlUserInsert(String sql) { insertUserStmt = sql; @@ -164,8 +162,7 @@ public String getSqlUserDelete() { * Set the SQL DELETE statement used to delete an existing user. All the * dynamic values will be replaced during runtime. * - * @param sql - * The SQL statement + * @param sql The SQL statement */ public void setSqlUserDelete(String sql) { deleteUserStmt = sql; @@ -184,8 +181,7 @@ public String getSqlUserUpdate() { * Set the SQL UPDATE statement used to update an existing user. All the * dynamic values will be replaced during runtime. * - * @param sql - * The SQL statement + * @param sql The SQL statement */ public void setSqlUserUpdate(String sql) { updateUserStmt = sql; @@ -224,8 +220,7 @@ public String getSqlUserSelectAll() { * Set the SQL SELECT statement used to select all user ids. All the dynamic * values will be replaced during runtime. * - * @param sql - * The SQL statement + * @param sql The SQL statement */ public void setSqlUserSelectAll(String sql) { selectAllStmt = sql; @@ -244,8 +239,7 @@ public String getSqlUserAuthenticate() { * Set the SQL SELECT statement used to authenticate user. All the dynamic * values will be replaced during runtime. * - * @param sql - * The SQL statement + * @param sql The SQL statement */ public void setSqlUserAuthenticate(String sql) { authenticateStmt = sql; @@ -265,8 +259,7 @@ public String getSqlUserAdmin() { * Set the SQL SELECT statement used to find whether an user is admin or * not. All the dynamic values will be replaced during runtime. * - * @param sql - * The SQL statement + * @param sql The SQL statement */ public void setSqlUserAdmin(String sql) { isAdminStmt = sql; @@ -290,7 +283,8 @@ public boolean isAdmin(String login) throws FtpException { // execute query try (Statement stmt = createConnection().createStatement(); - ResultSet rs = stmt.executeQuery(sql)) { + ResultSet rs = stmt.executeQuery(sql)) { + return rs.next(); } catch (SQLException ex) { LOG.error("DbUserManager.isAdmin()", ex); @@ -300,6 +294,9 @@ public boolean isAdmin(String login) throws FtpException { /** * Open connection to database. + * + * @return The oepned connection + * @throws SQLException If the connection can't be created */ protected Connection createConnection() throws SQLException { Connection connection = dataSource.getConnection(); @@ -310,8 +307,6 @@ protected Connection createConnection() throws SQLException { /** - * Delete user. Delete the row from the table. - * * {@inheritDoc} */ public void delete(String name) throws FtpException { @@ -331,8 +326,6 @@ public void delete(String name) throws FtpException { } /** - * Save user. If new insert a new row, else update the existing row. - * * {@inheritDoc} */ public void save(User user) throws FtpException { @@ -432,6 +425,7 @@ private BaseUser selectUserByName(String name) throws SQLException { // execute query try (Statement stmt = createConnection().createStatement(); ResultSet rs = stmt.executeQuery(sql)) { + // populate user object BaseUser thisUser = null; @@ -464,13 +458,10 @@ private BaseUser selectUserByName(String name) throws SQLException { } /** - * Get the user object. Fetch the row from the table. - * * {@inheritDoc} */ public User getUserByName(String name) throws FtpException { try { - BaseUser user = selectUserByName(name); if (user != null) { @@ -486,8 +477,6 @@ public User getUserByName(String name) throws FtpException { } /** - * User existance check. - * * {@inheritDoc} */ public boolean doesExist(String name) throws FtpException { @@ -500,6 +489,7 @@ public boolean doesExist(String name) throws FtpException { // execute query try (Statement stmt = createConnection().createStatement(); ResultSet rs = stmt.executeQuery(sql)) { + return rs.next(); } catch (SQLException ex) { LOG.error("DbUserManager.doesExist()", ex); @@ -508,8 +498,6 @@ public boolean doesExist(String name) throws FtpException { } /** - * Get all user names from the database. - * * {@inheritDoc} */ public String[] getAllUserNames() throws FtpException { @@ -535,8 +523,6 @@ public String[] getAllUserNames() throws FtpException { } /** - * User authentication. - * * {@inheritDoc} */ public User authenticate(Authentication authentication) throws AuthenticationFailedException { @@ -563,6 +549,7 @@ public User authenticate(Authentication authentication) throws AuthenticationFai // execute query try (Statement stmt = createConnection().createStatement(); ResultSet rs = stmt.executeQuery(sql)) { + if (rs.next()) { try { String storedPassword = rs.getString(ATTR_PASSWORD); diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/TransferRatePermission.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/TransferRatePermission.java index fea29c52..058d01a7 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/TransferRatePermission.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/TransferRatePermission.java @@ -24,7 +24,7 @@ /** * Internal class, do not use directly. - * + *

    * The max upload rate permission * * @author Apache MINA Project @@ -35,14 +35,18 @@ public class TransferRatePermission implements Authority { private int maxUploadRate; + /** + * Create a TransferRatePermission istance + * + * @param maxDownloadRate Maximum download rate + * @param maxUploadRate Maximum upload rate + */ public TransferRatePermission(int maxDownloadRate, int maxUploadRate) { this.maxDownloadRate = maxDownloadRate; this.maxUploadRate = maxUploadRate; } /** - * @see Authority#authorize(AuthorizationRequest) - * * {@inheritDoc} */ public AuthorizationRequest authorize(AuthorizationRequest request) { @@ -59,8 +63,6 @@ public AuthorizationRequest authorize(AuthorizationRequest request) { } /** - * @see Authority#canAuthorize(AuthorizationRequest) - * * {@inheritDoc} */ public boolean canAuthorize(AuthorizationRequest request) { diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/TransferRateRequest.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/TransferRateRequest.java index 857a22de..7c9bf269 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/TransferRateRequest.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/TransferRateRequest.java @@ -24,17 +24,28 @@ /** * Internal class, do not use directly. * + *

    * Request for getting the maximum allowed transfer rates for a user * * @author Apache MINA Project */ public class TransferRateRequest implements AuthorizationRequest { - + /** Max download rate for a user */ private int maxDownloadRate = 0; + /** Max upload rate for a user */ private int maxUploadRate = 0; /** + * Public constructor + */ + public TransferRateRequest() { + // Nothing to do + } + + /** + * Get the user maximum download rate + * * @return the maxDownloadRate */ public int getMaxDownloadRate() { @@ -42,14 +53,17 @@ public int getMaxDownloadRate() { } /** - * @param maxDownloadRate - * the maxDownloadRate to set + * Set the user maximum download rate + * + * @param maxDownloadRate the maxDownloadRate to set */ public void setMaxDownloadRate(int maxDownloadRate) { this.maxDownloadRate = maxDownloadRate; } /** + * Get the user maximum upload rate + * * @return the maxUploadRate */ public int getMaxUploadRate() { @@ -57,11 +71,11 @@ public int getMaxUploadRate() { } /** - * @param maxUploadRate - * the maxUploadRate to set + * Set the user maximum upload rate + * + * @param maxUploadRate the maxUploadRate to set */ public void setMaxUploadRate(int maxUploadRate) { this.maxUploadRate = maxUploadRate; } - } diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/UserMetadata.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/UserMetadata.java index eb9694ab..1255fe7a 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/UserMetadata.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/UserMetadata.java @@ -24,17 +24,25 @@ /** * Internal class, do not use directly. - * + *

    * User metadata used during authentication * * @author Apache MINA Project */ public class UserMetadata { - + /** The array of certificates up to the CA */ private Certificate[] certificateChain; + /** The user address */ private InetAddress inetAddress; + /** + * Public constructor + */ + public UserMetadata() { + // Nothing to do + } + /** * Retrive the certificate chain used for an SSL connection. * @@ -52,8 +60,7 @@ public Certificate[] getCertificateChain() { /** * Set the certificate chain * - * @param certificateChain - * The certificate chain to set + * @param certificateChain The certificate chain to set */ public void setCertificateChain(final Certificate[] certificateChain) { if (certificateChain != null) { @@ -75,11 +82,9 @@ public InetAddress getInetAddress() { /** * Set the remote IP adress of the client * - * @param inetAddress - * The client IP adress + * @param inetAddress The client IP adress */ public void setInetAddress(final InetAddress inetAddress) { this.inetAddress = inetAddress; } - } diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/WritePermission.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/WritePermission.java index e32f624a..87f547c1 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/WritePermission.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/WritePermission.java @@ -44,16 +44,13 @@ public WritePermission() { * Construct a write permission for a file or directory relative to the user * home directory * - * @param permissionRoot - * The file or directory + * @param permissionRoot The file or directory */ public WritePermission(final String permissionRoot) { this.permissionRoot = permissionRoot; } /** - * @see Authority#authorize(AuthorizationRequest) - * * {@inheritDoc} */ public AuthorizationRequest authorize(final AuthorizationRequest request) { @@ -73,8 +70,6 @@ public AuthorizationRequest authorize(final AuthorizationRequest request) { } /** - * @see Authority#canAuthorize(AuthorizationRequest) - * * {@inheritDoc} */ public boolean canAuthorize(final AuthorizationRequest request) { diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/WriteRequest.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/WriteRequest.java index 0ac8acd5..5540a638 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/WriteRequest.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/WriteRequest.java @@ -44,7 +44,7 @@ public WriteRequest() { * Request write access to a file or directory relative to the user home * directory * - * @param file + * @param file The file to which we want write access */ public WriteRequest(final String file) { this.file = file; diff --git a/core/src/main/java/org/apache/ftpserver/util/ClassUtils.java b/core/src/main/java/org/apache/ftpserver/util/ClassUtils.java index 42352566..5d8a3822 100644 --- a/core/src/main/java/org/apache/ftpserver/util/ClassUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/ClassUtils.java @@ -26,16 +26,20 @@ * */ public class ClassUtils { + /** + * Private constructor + */ + private ClassUtils() { + // Nothing to do + } /** * Checks if a class is a subclass of a class with the specified name. Used * as an instanceOf without having to load the class, useful when trying to * check for classes that might not be available in the runtime JRE. * - * @param clazz - * The class to check - * @param className - * The class name to look for in the super classes + * @param clazz The class to check + * @param className The class name to look for in the super classes * @return true if the class extends a class by the specified name. */ public static boolean extendsClass(final Class clazz, String className) { @@ -45,9 +49,11 @@ public static boolean extendsClass(final Class clazz, String className) { if (superClass.getName().equals(className)) { return true; } + superClass = superClass.getSuperclass(); } + return false; } } diff --git a/core/src/main/java/org/apache/ftpserver/util/DateUtils.java b/core/src/main/java/org/apache/ftpserver/util/DateUtils.java index c2aced1e..0a89ae13 100644 --- a/core/src/main/java/org/apache/ftpserver/util/DateUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/DateUtils.java @@ -35,26 +35,31 @@ * @author Apache MINA Project */ public class DateUtils { - private static final TimeZone TIME_ZONE_UTC = TimeZone.getTimeZone("UTC"); private static final String[] MONTHS = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + /** + * A private constructor + */ + private DateUtils() { + // Nothing to do + } + /* * Creates the DateFormat object used to parse/format * dates in FTP format. */ private static final ThreadLocal FTP_DATE_FORMAT = new ThreadLocal() { - @Override protected DateFormat initialValue() { - DateFormat df=new SimpleDateFormat("yyyyMMddHHmmss"); + DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); df.setLenient(false); df.setTimeZone(TimeZone.getTimeZone("GMT")); + return df; } - }; /** @@ -234,12 +239,15 @@ public static final String getFtpDate(long millis) { return sb.toString(); } - /* - * Parses a date in the format used by the FTP commands - * involving dates(MFMT, MDTM) + /** + * Parses a date in the format used by the FTP commands + * involving dates(MFMT, MDTM) + * + * @param dateStr The date to parse + * @return The parsed date + * @throws ParseException If teh date is invalid */ public static final Date parseFTPDate(String dateStr) throws ParseException { return FTP_DATE_FORMAT.get().parse(dateStr); - } } diff --git a/core/src/main/java/org/apache/ftpserver/util/EncryptUtils.java b/core/src/main/java/org/apache/ftpserver/util/EncryptUtils.java index d62edee3..1644cdc6 100644 --- a/core/src/main/java/org/apache/ftpserver/util/EncryptUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/EncryptUtils.java @@ -33,6 +33,12 @@ * @author Apache MINA Project */ public class EncryptUtils { + /** + * A private constructor + */ + public EncryptUtils() { + // Nothing to do + } /** * Encrypt byte array. diff --git a/core/src/main/java/org/apache/ftpserver/util/IllegalInetAddressException.java b/core/src/main/java/org/apache/ftpserver/util/IllegalInetAddressException.java index 9119b3db..2fd5e83e 100644 --- a/core/src/main/java/org/apache/ftpserver/util/IllegalInetAddressException.java +++ b/core/src/main/java/org/apache/ftpserver/util/IllegalInetAddressException.java @@ -28,13 +28,21 @@ * @author Apache MINA Project */ public class IllegalInetAddressException extends IllegalArgumentException { - + /** The serial version UID */ private static final long serialVersionUID = -7771719692741419933L; + /** + * Create a IllegalInetAddressException instance + */ public IllegalInetAddressException() { super(); } + /** + * Create a IllegalInetAddressException instance with an error message + + + * @param s The message to pass + */ public IllegalInetAddressException(String s) { super(s); } diff --git a/core/src/main/java/org/apache/ftpserver/util/IllegalPortException.java b/core/src/main/java/org/apache/ftpserver/util/IllegalPortException.java index 72306c7c..8f75b1b9 100644 --- a/core/src/main/java/org/apache/ftpserver/util/IllegalPortException.java +++ b/core/src/main/java/org/apache/ftpserver/util/IllegalPortException.java @@ -30,10 +30,18 @@ public class IllegalPortException extends IllegalArgumentException { private static final long serialVersionUID = -7771719692741419931L; + /** + * Public constructor + */ public IllegalPortException() { super(); } + /** + * Public constructor with a default message + * + * @param s The exception message + */ public IllegalPortException(String s) { super(s); } diff --git a/core/src/main/java/org/apache/ftpserver/util/IoUtils.java b/core/src/main/java/org/apache/ftpserver/util/IoUtils.java index bf31d2e3..9d568d5e 100644 --- a/core/src/main/java/org/apache/ftpserver/util/IoUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/IoUtils.java @@ -47,12 +47,17 @@ * @author Apache MINA Project */ public class IoUtils { + /** + * Private constructor + */ + private IoUtils () { + // Nothing to do + } /** * Random number generator to make unique file name */ - private static final Random RANDOM_GEN = new Random(System - .currentTimeMillis()); + private static final Random RANDOM_GEN = new Random(System.currentTimeMillis()); /** * Get a BufferedInputStream. @@ -60,14 +65,15 @@ public class IoUtils { * @param in The incoming InputStream * @return A BufferedInputStream */ - public static final BufferedInputStream getBufferedInputStream( - InputStream in) { + public static final BufferedInputStream getBufferedInputStream(InputStream in) { BufferedInputStream bin = null; + if (in instanceof java.io.BufferedInputStream) { bin = (BufferedInputStream) in; } else { bin = new BufferedInputStream(in); } + return bin; } @@ -77,14 +83,15 @@ public static final BufferedInputStream getBufferedInputStream( * @param out The incoming OutputStream * @return A BufferedOutputStream */ - public static final BufferedOutputStream getBufferedOutputStream( - OutputStream out) { + public static final BufferedOutputStream getBufferedOutputStream(OutputStream out) { BufferedOutputStream bout = null; + if (out instanceof java.io.BufferedOutputStream) { bout = (BufferedOutputStream) out; } else { bout = new BufferedOutputStream(out); } + return bout; } @@ -96,11 +103,13 @@ public static final BufferedOutputStream getBufferedOutputStream( */ public static final BufferedReader getBufferedReader(Reader reader) { BufferedReader buffered = null; + if (reader instanceof java.io.BufferedReader) { buffered = (BufferedReader) reader; } else { buffered = new BufferedReader(reader); } + return buffered; } @@ -112,11 +121,13 @@ public static final BufferedReader getBufferedReader(Reader reader) { */ public static final BufferedWriter getBufferedWriter(Writer wr) { BufferedWriter bw = null; + if (wr instanceof java.io.BufferedWriter) { bw = (BufferedWriter) wr; } else { bw = new BufferedWriter(wr); } + return bw; } @@ -128,13 +139,15 @@ public static final BufferedWriter getBufferedWriter(Writer wr) { */ public static final File getUniqueFile(File oldFile) { File newFile = oldFile; + while (true) { if (!newFile.exists()) { break; } - newFile = new File(oldFile.getAbsolutePath() + '.' - + Math.abs(RANDOM_GEN.nextLong())); + + newFile = new File(oldFile.getAbsolutePath() + '.' + Math.abs(RANDOM_GEN.nextLong())); } + return newFile; } @@ -142,6 +155,7 @@ public static final File getUniqueFile(File oldFile) { * No exception InputStream close method. * * @param is The InputStream to close + * @deprecated Use try-with-resources instead */ public static final void close(InputStream is) { if (is != null) { @@ -156,6 +170,7 @@ public static final void close(InputStream is) { * No exception OutputStream close method. * * @param os The OutputStream to close + * @deprecated Use try-with-resources instead */ public static final void close(OutputStream os) { if (os != null) { @@ -170,6 +185,7 @@ public static final void close(OutputStream os) { * No exception java.io.Reader close method. * * @param rd The Reader to close + * @deprecated Use try-with-resources instead */ public static final void close(Reader rd) { if (rd != null) { @@ -184,6 +200,7 @@ public static final void close(Reader rd) { * No exception java.io.Writer close method. * * @param wr The Writer to close + * @deprecated Use try-with-resources instead */ public static final void close(Writer wr) { if (wr != null) { @@ -202,6 +219,7 @@ public static final void close(Writer wr) { */ public static final String getStackTrace(Throwable ex) { String result = ""; + if (ex != null) { try { StringWriter sw = new StringWriter(); @@ -214,6 +232,7 @@ public static final String getStackTrace(Throwable ex) { e.printStackTrace(); } } + return result; } @@ -225,10 +244,10 @@ public static final String getStackTrace(Throwable ex) { * @param bufferSize Size of internal buffer to use. * @throws IOException If the copy failed */ - public static final void copy(Reader input, Writer output, int bufferSize) - throws IOException { + public static final void copy(Reader input, Writer output, int bufferSize) throws IOException { char[] buffer = new char[bufferSize]; int n = 0; + while ((n = input.read(buffer)) != -1) { output.write(buffer, 0, n); } @@ -242,10 +261,10 @@ public static final void copy(Reader input, Writer output, int bufferSize) * @param bufferSize Size of internal buffer to use. * @throws IOException If the copy failed */ - public static final void copy(InputStream input, OutputStream output, - int bufferSize) throws IOException { + public static final void copy(InputStream input, OutputStream output, int bufferSize) throws IOException { byte[] buffer = new byte[bufferSize]; int n = 0; + while ((n = input.read(buffer)) != -1) { output.write(buffer, 0, n); } @@ -261,6 +280,7 @@ public static final void copy(InputStream input, OutputStream output, public static final String readFully(Reader reader) throws IOException { StringWriter writer = new StringWriter(); copy(reader, writer, 1024); + return writer.toString(); } @@ -275,9 +295,16 @@ public static final String readFully(InputStream input) throws IOException { StringWriter writer = new StringWriter(); InputStreamReader reader = new InputStreamReader(input); copy(reader, writer, 1024); + return writer.toString(); } + /** + * Delete a file + * + * @param file The file to delete + * @throws IOException If the deletion failed + */ public static final void delete(File file) throws IOException { if (file.isDirectory()) { deleteDir(file); @@ -311,10 +338,12 @@ private static void deleteFile(File file) throws IOException { if (OS.isFamilyWindows()) { System.gc(); } + try { Thread.sleep(10); } catch (InterruptedException e) { } + if (!file.delete()) { throw new IOException("Failed to delete file: " + file); } diff --git a/core/src/main/java/org/apache/ftpserver/util/OS.java b/core/src/main/java/org/apache/ftpserver/util/OS.java index b8b1f717..c1bfd405 100644 --- a/core/src/main/java/org/apache/ftpserver/util/OS.java +++ b/core/src/main/java/org/apache/ftpserver/util/OS.java @@ -29,37 +29,49 @@ * @author Apache MINA Project */ public final class OS { + /** OS/400 */ private static final String FAMILY_OS_400 = "os/400"; + /** Z/OS */ private static final String FAMILY_Z_OS = "z/os"; + /** WIN9x */ private static final String FAMILY_WIN9X = "win9x"; + /** OpenVMS */ private static final String FAMILY_OPENVMS = "openvms"; + /** Unix */ private static final String FAMILY_UNIX = "unix"; + /** Tandem */ private static final String FAMILY_TANDEM = "tandem"; + /** MAC */ private static final String FAMILY_MAC = "mac"; + /** MS/DOS */ private static final String FAMILY_DOS = "dos"; + /** NetWare */ private static final String FAMILY_NETWARE = "netware"; + /** OS/2 */ private static final String FAMILY_OS_2 = "os/2"; + /** Windows */ private static final String FAMILY_WINDOWS = "windows"; - private static final String OS_NAME = System.getProperty("os.name") - .toLowerCase(Locale.US); + /** The OS name */ + private static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.US); - private static final String OS_ARCH = System.getProperty("os.arch") - .toLowerCase(Locale.US); + /** The OS architecture */ + private static final String OS_ARCH = System.getProperty("os.arch").toLowerCase(Locale.US); - private static final String OS_VERSION = System.getProperty("os.version") - .toLowerCase(Locale.US); + /** The OS version */ + private static final String OS_VERSION = System.getProperty("os.version").toLowerCase(Locale.US); + /** The OS path separator */ private static final String PATH_SEP = System.getProperty("path.separator"); /** @@ -84,54 +96,108 @@ private OS() { *

  • os/400
  • * * - * @param family - * the family to check for + * @param family the family to check for * @return true if the OS matches */ private static boolean isFamily(final String family) { return isOs(family, null, null, null); } + /** + * Tells if the underlaying OS is MS/DOS + * + * @return true if the underlaying OS is MS/DOS + */ public static boolean isFamilyDOS() { return isFamily(FAMILY_DOS); } + /** + * Tells if the underlaying OS is MAC + * + * @return true if the underlaying OS is MAC + */ public static boolean isFamilyMac() { return isFamily(FAMILY_MAC); } + /** + * Tells if the underlaying OS is NetWare + * + * @return true if the underlaying OS is NetWare + */ public static boolean isFamilyNetware() { return isFamily(FAMILY_NETWARE); } + /** + * Tells if the underlaying OS is OS/2 + * + * @return true if the underlaying OS is OS/2 + */ public static boolean isFamilyOS2() { return isFamily(FAMILY_OS_2); } + /** + * Tells if the underlaying OS is Tandem + * + * @return true if the underlaying OS is Tandem + */ public static boolean isFamilyTandem() { return isFamily(FAMILY_TANDEM); } + /** + * Tells if the underlaying OS is Unix + * + * @return true if the underlaying OS is Unix + */ public static boolean isFamilyUnix() { return isFamily(FAMILY_UNIX); } + /** + * Tells if the underlaying OS is Windows + * + * @return true if the underlaying OS is Windows + */ public static boolean isFamilyWindows() { return isFamily(FAMILY_WINDOWS); } + /** + * Tells if the underlaying OS is Win9x + * + * @return true if the underlaying OS is Win9x + */ public static boolean isFamilyWin9x() { return isFamily(FAMILY_WIN9X); } + /** + * Tells if the underlaying OS is Z/OS + * + * @return true if the underlaying OS is Z/OS + */ public static boolean isFamilyZOS() { return isFamily(FAMILY_Z_OS); } + /** + * Tells if the underlaying OS is OS/400 + * + * @return true if the underlaying OS is OS/400 + */ public static boolean isFamilyOS400() { return isFamily(FAMILY_OS_400); } + /** + * Tells if the underlaying OS is OpenVMS + * + * @return true if the underlaying OS is OpenVMS + */ public static boolean isFamilyOpenVms() { return isFamily(FAMILY_OPENVMS); } @@ -139,8 +205,7 @@ public static boolean isFamilyOpenVms() { /** * Determines if the OS on which Ant is executing matches the given OS name. * - * @param name - * the OS name to check for + * @param name the OS name to check for * @return true if the OS matches */ public static boolean isName(final String name) { @@ -151,8 +216,7 @@ public static boolean isName(final String name) { * Determines if the OS on which Ant is executing matches the given OS * architecture. * - * @param arch - * the OS architecture to check for + * @param arch the OS architecture to check for * @return true if the OS matches */ public static boolean isArch(final String arch) { @@ -163,8 +227,7 @@ public static boolean isArch(final String arch) { * Determines if the OS on which Ant is executing matches the given OS * version. * - * @param version - * the OS version to check for + * @param version the OS version to check for * @return true if the OS matches */ public static boolean isVersion(final String version) { @@ -175,18 +238,13 @@ public static boolean isVersion(final String version) { * Determines if the OS on which Ant is executing matches the given OS * family, name, architecture and version * - * @param family - * The OS family - * @param name - * The OS name - * @param arch - * The OS architecture - * @param version - * The OS version + * @param family The OS family + * @param name The OS name + * @param arch The OS architecture + * @param version The OS version * @return true if the OS matches */ - public static boolean isOs(final String family, final String name, - final String arch, final String version) { + public static boolean isOs(final String family, final String name, final String arch, final String version) { boolean retValue = false; if (family != null || name != null || arch != null || version != null) { @@ -197,53 +255,77 @@ public static boolean isOs(final String family, final String name, boolean isVersion = true; if (family != null) { - if (family.equals(FAMILY_WINDOWS)) { - isFamily = OS_NAME.indexOf(FAMILY_WINDOWS) > -1; - } else if (family.equals(FAMILY_OS_2)) { - isFamily = OS_NAME.indexOf(FAMILY_OS_2) > -1; - } else if (family.equals(FAMILY_NETWARE)) { - isFamily = OS_NAME.indexOf(FAMILY_NETWARE) > -1; - } else if (family.equals(FAMILY_DOS)) { - isFamily = PATH_SEP.equals(";") - && !isFamily(FAMILY_NETWARE); - } else if (family.equals(FAMILY_MAC)) { - isFamily = OS_NAME.indexOf(FAMILY_MAC) > -1; - } else if (family.equals(FAMILY_TANDEM)) { - isFamily = OS_NAME.indexOf("nonstop_kernel") > -1; - } else if (family.equals(FAMILY_UNIX)) { - isFamily = PATH_SEP.equals(":") + switch (family) { + case FAMILY_WINDOWS: + isFamily = OS_NAME.indexOf(FAMILY_WINDOWS) > -1; + break; + + case FAMILY_OS_2: + isFamily = OS_NAME.indexOf(FAMILY_OS_2) > -1; + break; + + case FAMILY_NETWARE: + isFamily = OS_NAME.indexOf(FAMILY_NETWARE) > -1; + break; + + case FAMILY_DOS: + isFamily = PATH_SEP.equals(";") && !isFamily(FAMILY_NETWARE); + break; + + case FAMILY_MAC: + isFamily = OS_NAME.indexOf(FAMILY_MAC) > -1; + break; + + case FAMILY_TANDEM: + isFamily = OS_NAME.indexOf("nonstop_kernel") > -1; + break; + + case FAMILY_UNIX: + isFamily = PATH_SEP.equals(":") && !isFamily(FAMILY_OPENVMS) && (!isFamily(FAMILY_MAC) || OS_NAME.endsWith("x")); - } else if (family.equals(FAMILY_WIN9X)) { - isFamily = isFamily(FAMILY_WINDOWS) + break; + + case FAMILY_WIN9X: + isFamily = isFamily(FAMILY_WINDOWS) && (OS_NAME.indexOf("95") >= 0 || OS_NAME.indexOf("98") >= 0 || OS_NAME.indexOf("me") >= 0 || OS_NAME .indexOf("ce") >= 0); - } else if (family.equals(FAMILY_Z_OS)) { - isFamily = OS_NAME.indexOf(FAMILY_Z_OS) > -1 - || OS_NAME.indexOf("os/390") > -1; - } else if (family.equals(FAMILY_OS_400)) { - isFamily = OS_NAME.indexOf(FAMILY_OS_400) > -1; - } else if (family.equals(FAMILY_OPENVMS)) { - isFamily = OS_NAME.indexOf(FAMILY_OPENVMS) > -1; - } else { - throw new IllegalArgumentException( - "Don\'t know how to detect os family \"" + family - + "\""); + break; + + case FAMILY_Z_OS: + isFamily = OS_NAME.indexOf(FAMILY_Z_OS) > -1 || OS_NAME.indexOf("os/390") > -1; + break; + + case FAMILY_OS_400: + isFamily = OS_NAME.indexOf(FAMILY_OS_400) > -1; + break; + + case FAMILY_OPENVMS: + isFamily = OS_NAME.indexOf(FAMILY_OPENVMS) > -1; + break; + + default: + throw new IllegalArgumentException("Don\'t know how to detect os family \"" + family + "\""); } } + if (name != null) { isName = name.equals(OS_NAME); } + if (arch != null) { isArch = arch.equals(OS_ARCH); } + if (version != null) { isVersion = version.equals(OS_VERSION); } + retValue = isFamily && isName && isArch && isVersion; } + return retValue; } } diff --git a/core/src/main/java/org/apache/ftpserver/util/PasswordUtil.java b/core/src/main/java/org/apache/ftpserver/util/PasswordUtil.java index 511cbf7c..dea1916f 100644 --- a/core/src/main/java/org/apache/ftpserver/util/PasswordUtil.java +++ b/core/src/main/java/org/apache/ftpserver/util/PasswordUtil.java @@ -19,7 +19,19 @@ package org.apache.ftpserver.util; +/** + * Utility class for password management + * + * @author Apache MINA Project + */ public class PasswordUtil { + /** + * A private constructor + */ + private PasswordUtil() { + // Nothing to do + } + /** * Securely compares two strings up to a maximum number of characters in a way * that obscures the password length from timing attacks diff --git a/core/src/main/java/org/apache/ftpserver/util/SocketAddressEncoder.java b/core/src/main/java/org/apache/ftpserver/util/SocketAddressEncoder.java index 771e6919..b4125466 100644 --- a/core/src/main/java/org/apache/ftpserver/util/SocketAddressEncoder.java +++ b/core/src/main/java/org/apache/ftpserver/util/SocketAddressEncoder.java @@ -26,34 +26,48 @@ /** * Internal class, do not use directly. - * + *

    * Encodes and decodes socket addresses (IP and port) from and to the format * used with for example the PORT and PASV command * * @author Apache MINA Project */ public class SocketAddressEncoder { + /** + * Public constructor + */ + public SocketAddressEncoder() { + // Nothinhg to do + } private static int convertAndValidateNumber(String s) { int i = Integer.parseInt(s); + if (i < 0) { throw new IllegalArgumentException("Token can not be less than 0"); } else if (i > 255) { - throw new IllegalArgumentException( - "Token can not be larger than 255"); + throw new IllegalArgumentException("Token can not be larger than 255"); } return i; } - public static InetSocketAddress decode(String str) - throws UnknownHostException { + /** + * Decode an address + * + * @param str The string containing the address to decode + * @return The decodd address + * @throws UnknownHostException If the host is unkown + */ + public static InetSocketAddress decode(String str) throws UnknownHostException { StringTokenizer st = new StringTokenizer(str, ","); + if (st.countTokens() != 6) { throw new IllegalInetAddressException("Illegal amount of tokens"); } StringBuilder sb = new StringBuilder(); + try { sb.append(convertAndValidateNumber(st.nextToken())); sb.append('.'); @@ -70,6 +84,7 @@ public static InetSocketAddress decode(String str) // get data server port int dataPort = 0; + try { int hi = convertAndValidateNumber(st.nextToken()); int lo = convertAndValidateNumber(st.nextToken()); @@ -81,11 +96,16 @@ public static InetSocketAddress decode(String str) return new InetSocketAddress(dataAddr, dataPort); } + /** + * Encode the address + * + * @param address The address to encode + * @return The encoded address + */ public static String encode(InetSocketAddress address) { InetAddress servAddr = address.getAddress(); int servPort = address.getPort(); - return servAddr.getHostAddress().replace('.', ',') + ',' - + (servPort >> 8) + ',' + (servPort & 0xFF); - } + return servAddr.getHostAddress().replace('.', ',') + ',' + (servPort >> 8) + ',' + (servPort & 0xFF); + } } diff --git a/core/src/main/java/org/apache/ftpserver/util/StringUtils.java b/core/src/main/java/org/apache/ftpserver/util/StringUtils.java index dc5083dc..3d530fa2 100644 --- a/core/src/main/java/org/apache/ftpserver/util/StringUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/StringUtils.java @@ -29,6 +29,9 @@ * @author Apache MINA Project */ public class StringUtils { + /** Newline characters */ + public static final char[] NEWLINE = { '\r', '\n' }; + /** * @deprecated Do not instantiate. */ diff --git a/core/src/test/java/org/apache/ftpserver/ssl/ExplicitSecurityTestTemplate.java b/core/src/test/java/org/apache/ftpserver/ssl/ExplicitSecurityTestTemplate.java index fa65f2d3..62d9b8f3 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/ExplicitSecurityTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/ExplicitSecurityTestTemplate.java @@ -180,12 +180,8 @@ public void testReceiveEmptyFile() throws Exception { File file = new File(ROOT_DIR, "foo"); file.createNewFile(); - InputStream is = null; - try { - is = client.retrieveFileStream(file.getName()); + try (InputStream is = client.retrieveFileStream(file.getName())) { assertEquals(-1, is.read(new byte[1024])); - } finally { - IoUtils.close(is); } } } diff --git a/core/src/test/java/org/apache/ftpserver/ssl/SSLTestTemplate.java b/core/src/test/java/org/apache/ftpserver/ssl/SSLTestTemplate.java index 49dea047..0d48de4e 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/SSLTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/SSLTestTemplate.java @@ -132,14 +132,8 @@ protected FTPSClient createFTPClient() throws Exception { protected abstract String getAuthValue(); protected void writeDataToFile(File file, byte[] data) throws IOException { - FileOutputStream fos = null; - - try { - fos = new FileOutputStream(file); - + try (FileOutputStream fos = new FileOutputStream(file)) { fos.write(data); - } finally { - IoUtils.close(fos); } } diff --git a/core/src/test/java/org/apache/ftpserver/test/TestUtil.java b/core/src/test/java/org/apache/ftpserver/test/TestUtil.java index 9723c085..b931b574 100644 --- a/core/src/test/java/org/apache/ftpserver/test/TestUtil.java +++ b/core/src/test/java/org/apache/ftpserver/test/TestUtil.java @@ -167,36 +167,20 @@ public static InetAddress findNonLocalhostIp() throws Exception { return null; } - public static void writeDataToFile(File file, byte[] data) - throws IOException { - FileOutputStream fos = null; - - try { - fos = new FileOutputStream(file); - + public static void writeDataToFile(File file, byte[] data) throws IOException { + try (FileOutputStream fos = new FileOutputStream(file)) { fos.write(data); - } finally { - IoUtils.close(fos); } } - public static void assertFileEqual(byte[] expected, File file) - throws Exception { - ByteArrayOutputStream baos = null; - FileInputStream fis = null; - - try { - baos = new ByteArrayOutputStream(); - fis = new FileInputStream(file); - + public static void assertFileEqual(byte[] expected, File file) throws Exception { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + FileInputStream fis = new FileInputStream(file)) { IoUtils.copy(fis, baos, 1024); byte[] actual = baos.toByteArray(); assertArraysEqual(expected, actual); - } finally { - IoUtils.close(fis); - IoUtils.close(baos); } }