diff --git a/core/pom.xml b/core/pom.xml index 9fc4264f..ce064eee 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -17,13 +17,13 @@ ftpserver-parent org.apache.ftpserver - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT 4.0.0 org.apache.ftpserver ftpserver-core Apache FtpServer Core - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT bundle @@ -58,32 +58,25 @@ org.apache.felix maven-bundle-plugin - 1.4.1 + 2.3.4 true ${artifactId} The Apache Software Foundation - org.apache.ftpserver;version=${pom.version}, - org.apache.ftpserver.command;version=${pom.version}, - org.apache.ftpserver.config.spring;version=${pom.version}, - org.apache.ftpserver.filesystem.nativefs;version=${pom.version}, - org.apache.ftpserver.ftpletcontainer;version=${pom.version}, - org.apache.ftpserver.listener;version=${pom.version}, - org.apache.ftpserver.main;version=${pom.version}, - org.apache.ftpserver.message;version=${pom.version}, - org.apache.ftpserver.ssl;version=${pom.version}, - org.apache.ftpserver.usermanager;version=${pom.version} + org.apache.ftpserver;version=${project.version}, + org.apache.ftpserver.command;version=${project.version}, + org.apache.ftpserver.config.spring;version=${project.version}, + org.apache.ftpserver.filesystem.nativefs;version=${project.version}, + org.apache.ftpserver.ftpletcontainer;version=${project.version}, + org.apache.ftpserver.ipfilter;version=${project.version}, + org.apache.ftpserver.listener;version=${project.version}, + org.apache.ftpserver.main;version=${project.version}, + org.apache.ftpserver.message;version=${project.version}, + org.apache.ftpserver.ssl;version=${project.version}, + org.apache.ftpserver.usermanager;version=${project.version} - org.apache.ftpserver.command.impl, - org.apache.ftpserver.command.impl.listing, - org.apache.ftpserver.filesystem.nativefs.impl, - org.apache.ftpserver.ftpletcontainer.impl, - org.apache.ftpserver.impl, org.apache.ftpserver.listener.nio, - org.apache.ftpserver.message.impl, org.apache.ftpserver.ssl.impl, - org.apache.ftpserver.usermanager.impl, - org.apache.ftpserver.util - + org.springframework.beans.factory.config;resolution:=optional;version="2.5", org.springframework.beans.factory.support;resolution:=optional;version="2.5", org.springframework.beans.factory.xml;resolution:=optional;version="2.5", @@ -108,7 +101,7 @@ - ${groupId} + ${project.groupId} ftplet-api @@ -159,11 +152,6 @@ commons-codec test - - oro - oro - test - hsqldb hsqldb diff --git a/core/src/examples/java/org/apache/ftpserver/examples/EmbeddingFtpServer.java b/core/src/examples/java/org/apache/ftpserver/examples/EmbeddingFtpServer.java index 6b970b09..3e3d5576 100644 --- a/core/src/examples/java/org/apache/ftpserver/examples/EmbeddingFtpServer.java +++ b/core/src/examples/java/org/apache/ftpserver/examples/EmbeddingFtpServer.java @@ -1,5 +1,3 @@ -package org.apache.ftpserver.examples; - /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -19,6 +17,8 @@ * under the License. */ +package org.apache.ftpserver.examples; + import java.io.File; import org.apache.ftpserver.FtpServer; @@ -27,6 +27,9 @@ import org.apache.ftpserver.ssl.SslConfigurationFactory; import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory; +/** +* @author Apache MINA Project* +*/ public class EmbeddingFtpServer { public static void main(String[] args) throws Exception { diff --git a/core/src/examples/java/org/apache/ftpserver/examples/ManagingUsers.java b/core/src/examples/java/org/apache/ftpserver/examples/ManagingUsers.java index bec4802d..e19cd828 100644 --- a/core/src/examples/java/org/apache/ftpserver/examples/ManagingUsers.java +++ b/core/src/examples/java/org/apache/ftpserver/examples/ManagingUsers.java @@ -25,8 +25,12 @@ import org.apache.ftpserver.ftplet.UserManager; import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory; import org.apache.ftpserver.usermanager.SaltedPasswordEncryptor; +import org.apache.ftpserver.usermanager.UserFactory; import org.apache.ftpserver.usermanager.impl.BaseUser; +/** +* @author Apache MINA Project* +*/ public class ManagingUsers { public static void main(String[] args) throws Exception { @@ -35,11 +39,11 @@ public static void main(String[] args) throws Exception { userManagerFactory.setPasswordEncryptor(new SaltedPasswordEncryptor()); UserManager um = userManagerFactory.createUserManager(); - BaseUser user = new BaseUser(); - user.setName("myNewUser"); - user.setPassword("secret"); - user.setHomeDirectory("ftproot"); - + UserFactory userFact = new UserFactory(); + userFact.setName("myNewUser"); + userFact.setPassword("secret"); + userFact.setHomeDirectory("ftproot"); + User user = userFact.createUser(); um.save(user); } } diff --git a/core/src/main/java/org/apache/ftpserver/ConnectionConfig.java b/core/src/main/java/org/apache/ftpserver/ConnectionConfig.java index cd0d7bb5..cdacad47 100644 --- a/core/src/main/java/org/apache/ftpserver/ConnectionConfig.java +++ b/core/src/main/java/org/apache/ftpserver/ConnectionConfig.java @@ -23,9 +23,7 @@ * Interface for providing the configuration for the control socket connections. * * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project */ public interface ConnectionConfig { @@ -60,4 +58,13 @@ public interface ConnectionConfig { * @return true if anonymous logins are enabled */ boolean isAnonymousLoginEnabled(); + + /** + * Returns the maximum number of threads the server is allowed to create for + * processing client requests. + * + * @return the maximum number of threads the server is allowed to create for + * processing client requests. + */ + int getMaxThreads(); } diff --git a/core/src/main/java/org/apache/ftpserver/ConnectionConfigFactory.java b/core/src/main/java/org/apache/ftpserver/ConnectionConfigFactory.java index 84e71117..b59bd874 100644 --- a/core/src/main/java/org/apache/ftpserver/ConnectionConfigFactory.java +++ b/core/src/main/java/org/apache/ftpserver/ConnectionConfigFactory.java @@ -24,9 +24,7 @@ /** * Factory for creating connection configurations * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project */ public class ConnectionConfigFactory { @@ -40,6 +38,8 @@ public class ConnectionConfigFactory { private int loginFailureDelay = 500; + private int maxThreads = 0; + /** * Create a connection configuration instances based on the configuration on this factory * @return The {@link ConnectionConfig} instance @@ -47,9 +47,9 @@ public class ConnectionConfigFactory { public ConnectionConfig createConnectionConfig() { return new DefaultConnectionConfig(anonymousLoginEnabled, loginFailureDelay, maxLogins, maxAnonymousLogins, - maxLoginFailures); + maxLoginFailures, maxThreads); } - + /** * The delay in number of milliseconds between login failures. Important to * make brute force attacks harder. @@ -61,8 +61,8 @@ public int getLoginFailureDelay() { } /** - * The maximum number of time an anonymous user can fail to login before getting disconnected - * @return The maximum number of failer login attempts + * The maximum number of anonymous logins the server would allow at any given time + * @return The maximum number of anonymous logins */ public int getMaxAnonymousLogins() { return maxAnonymousLogins; @@ -101,6 +101,29 @@ public void setMaxLogins(final int maxLogins) { this.maxLogins = maxLogins; } + /** + * Returns the maximum number of threads the server is allowed to create for + * processing client requests. + * + * @return the maximum number of threads the server is allowed to create for + * processing client requests. + */ + public int getMaxThreads() { + return maxThreads; + } + + /** + * Sets the maximum number of threads the server is allowed to create for + * processing client requests. + * + * @param maxThreads + * the maximum number of threads the server is allowed to create + * for processing client requests. + */ + public void setMaxThreads(int maxThreads) { + this.maxThreads = maxThreads; + } + /** * Set if anonymous logins are allowed at the server * @param anonymousLoginEnabled true if anonymous logins should be enabled @@ -110,8 +133,8 @@ public void setAnonymousLoginEnabled(final boolean anonymousLoginEnabled) { } /** - * Sets the maximum number of time an anonymous user can fail to login before getting disconnected - * @param maxAnonymousLogins The maximum number of failer login attempts + * Sets the maximum number of anonymous logins the server would allow at any given time + * @param maxAnonymousLogins The maximum number of anonymous logins */ public void setMaxAnonymousLogins(final int maxAnonymousLogins) { this.maxAnonymousLogins = maxAnonymousLogins; diff --git a/core/src/main/java/org/apache/ftpserver/DataConnectionConfiguration.java b/core/src/main/java/org/apache/ftpserver/DataConnectionConfiguration.java index b67fcfc8..6cdd11e8 100644 --- a/core/src/main/java/org/apache/ftpserver/DataConnectionConfiguration.java +++ b/core/src/main/java/org/apache/ftpserver/DataConnectionConfiguration.java @@ -26,8 +26,7 @@ /** * Data connection configuration interface. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface DataConnectionConfiguration { diff --git a/core/src/main/java/org/apache/ftpserver/DataConnectionConfigurationFactory.java b/core/src/main/java/org/apache/ftpserver/DataConnectionConfigurationFactory.java index 20e2d080..0e2e3335 100644 --- a/core/src/main/java/org/apache/ftpserver/DataConnectionConfigurationFactory.java +++ b/core/src/main/java/org/apache/ftpserver/DataConnectionConfigurationFactory.java @@ -21,19 +21,23 @@ import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.Collections; import org.apache.ftpserver.impl.DefaultDataConnectionConfiguration; import org.apache.ftpserver.impl.PassivePorts; import org.apache.ftpserver.ssl.SslConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Data connection factory * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 701863 $, $Date: 2008-10-05 21:25:50 +0200 (Sun, 05 Oct 2008) $ + * @author Apache MINA Project */ public class DataConnectionConfigurationFactory { + private Logger log = LoggerFactory.getLogger(DataConnectionConfigurationFactory.class); + // maximum idle time in seconds private int idleTime = 300; private SslConfiguration ssl; @@ -45,7 +49,7 @@ public class DataConnectionConfigurationFactory { private String passiveAddress; private String passiveExternalAddress; - private PassivePorts passivePorts = new PassivePorts(new int[] { 0 }); + private PassivePorts passivePorts = new PassivePorts(Collections.emptySet(), true); private boolean implicitSsl; /** @@ -212,6 +216,7 @@ public synchronized int requestPassivePort() { // no available free port - wait for the release notification if (dataPort == -1) { try { + log.info("Out of passive ports, waiting for one to be released. Might be stuck"); wait(); } catch (InterruptedException ex) { } @@ -245,7 +250,7 @@ public String getPassivePorts() { * @param passivePorts The passive ports string */ public void setPassivePorts(String passivePorts) { - this.passivePorts = new PassivePorts(passivePorts); + this.passivePorts = new PassivePorts(passivePorts, true); } diff --git a/core/src/main/java/org/apache/ftpserver/DataConnectionException.java b/core/src/main/java/org/apache/ftpserver/DataConnectionException.java index 246375cc..626cf80e 100644 --- a/core/src/main/java/org/apache/ftpserver/DataConnectionException.java +++ b/core/src/main/java/org/apache/ftpserver/DataConnectionException.java @@ -24,8 +24,7 @@ /** * Thrown if a data connection can not be established * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DataConnectionException extends FtpException { private static final long serialVersionUID = -1328383839917648987L; @@ -67,6 +66,6 @@ public DataConnectionException(final Throwable th) { * the original cause */ public DataConnectionException(final String msg, final Throwable th) { - super(msg); + super(msg, th); } } diff --git a/core/src/main/java/org/apache/ftpserver/FtpServer.java b/core/src/main/java/org/apache/ftpserver/FtpServer.java index 08e6a2fb..6f84e496 100644 --- a/core/src/main/java/org/apache/ftpserver/FtpServer.java +++ b/core/src/main/java/org/apache/ftpserver/FtpServer.java @@ -27,8 +27,7 @@ * thread. Server implementation is used to create the server * socket and handle client connection. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 701885 $, $Date: 2008-10-05 22:51:37 +0200 (Sun, 05 Oct 2008) $ + * @author Apache MINA Project */ public interface FtpServer { diff --git a/core/src/main/java/org/apache/ftpserver/FtpServerConfigurationException.java b/core/src/main/java/org/apache/ftpserver/FtpServerConfigurationException.java index 232a6571..ae19a520 100644 --- a/core/src/main/java/org/apache/ftpserver/FtpServerConfigurationException.java +++ b/core/src/main/java/org/apache/ftpserver/FtpServerConfigurationException.java @@ -23,8 +23,7 @@ * Exception used during startup to indicate that the configuration is not * correct. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class FtpServerConfigurationException extends RuntimeException { diff --git a/core/src/main/java/org/apache/ftpserver/FtpServerFactory.java b/core/src/main/java/org/apache/ftpserver/FtpServerFactory.java index 30c1a444..cac1aa8b 100644 --- a/core/src/main/java/org/apache/ftpserver/FtpServerFactory.java +++ b/core/src/main/java/org/apache/ftpserver/FtpServerFactory.java @@ -27,8 +27,8 @@ import org.apache.ftpserver.ftplet.Ftplet; import org.apache.ftpserver.ftplet.UserManager; import org.apache.ftpserver.ftpletcontainer.impl.DefaultFtpletContainer; -import org.apache.ftpserver.impl.DefaultFtpServerContext; import org.apache.ftpserver.impl.DefaultFtpServer; +import org.apache.ftpserver.impl.DefaultFtpServerContext; import org.apache.ftpserver.listener.Listener; import org.apache.ftpserver.message.MessageResource; @@ -36,8 +36,7 @@ * This is the starting point of all the servers. Creates server instances based on * the provided configuration. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 701885 $, $Date: 2008-10-05 22:51:37 +0200 (Sun, 05 Oct 2008) $ + * @author Apache MINA Project */ public class FtpServerFactory { 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 ef5b9993..43a06061 100644 --- a/core/src/main/java/org/apache/ftpserver/command/AbstractCommand.java +++ b/core/src/main/java/org/apache/ftpserver/command/AbstractCommand.java @@ -23,8 +23,7 @@ /** * Common base class recommended for {@link Command} implementations * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public abstract class AbstractCommand implements Command { diff --git a/core/src/main/java/org/apache/ftpserver/command/Command.java b/core/src/main/java/org/apache/ftpserver/command/Command.java index ca520767..24c1dc1c 100644 --- a/core/src/main/java/org/apache/ftpserver/command/Command.java +++ b/core/src/main/java/org/apache/ftpserver/command/Command.java @@ -29,8 +29,7 @@ /** * This interface encapsulates all the FTP commands. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface Command { diff --git a/core/src/main/java/org/apache/ftpserver/command/CommandFactory.java b/core/src/main/java/org/apache/ftpserver/command/CommandFactory.java index 713475d6..ced5bdad 100644 --- a/core/src/main/java/org/apache/ftpserver/command/CommandFactory.java +++ b/core/src/main/java/org/apache/ftpserver/command/CommandFactory.java @@ -22,8 +22,7 @@ /** * Command factory interface. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface CommandFactory { 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 14e366a6..ad3a2316 100644 --- a/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java +++ b/core/src/main/java/org/apache/ftpserver/command/CommandFactoryFactory.java @@ -73,8 +73,7 @@ /** * Factory for {@link CommandFactory} instances * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class CommandFactoryFactory { 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 3e501b39..0a7f14f8 100644 --- a/core/src/main/java/org/apache/ftpserver/command/NotSupportedCommand.java +++ b/core/src/main/java/org/apache/ftpserver/command/NotSupportedCommand.java @@ -31,8 +31,7 @@ * A command used primarily for overriding already installed commands when one * wants to disable the command. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class NotSupportedCommand extends AbstractCommand { 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 36d4dbb1..e1583bec 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 @@ -40,8 +40,7 @@ * Current implementation does not do anything. As here data transfers are not * multi-threaded. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ABOR extends AbstractCommand { 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 fd230c09..e57c6c4f 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 @@ -36,8 +36,7 @@ * Acknowledges the ACCT (account) command with a 202 reply. The command however * is irrelevant to any workings. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ACCT extends AbstractCommand { 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 e769d2c7..c506d2e5 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 @@ -52,8 +52,7 @@ * be appended to that file; otherwise the file specified in the pathname shall * be created at the server site. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class APPE extends AbstractCommand { @@ -162,6 +161,12 @@ public void execute(final FtpIoSession session, // transfer data long 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(); + } + LOG.info("File uploaded {}", fileName); // notify the statistics component @@ -169,11 +174,6 @@ public void execute(final FtpIoSession session, .getFtpStatistics(); ftpStat.setUpload(session, file, transSz); - // 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(); - } } catch (SocketException e) { LOG.debug("SocketException during file upload", e); failure = true; 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 df1f8b4c..d3dfd17c 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 @@ -21,6 +21,8 @@ import java.io.IOException; import java.security.GeneralSecurityException; +import java.util.Arrays; +import java.util.List; import org.apache.ftpserver.command.AbstractCommand; import org.apache.ftpserver.ftplet.FtpException; @@ -40,8 +42,7 @@ * * This server supports explicit SSL support. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class AUTH extends AbstractCommand { @@ -49,6 +50,8 @@ public class AUTH extends AbstractCommand { private final Logger LOG = LoggerFactory.getLogger(AUTH.class); + private static final List VALID_AUTH_TYPES = Arrays.asList("SSL", "TLS", "TLS-C", "TLS-P"); + /** * Execute command */ @@ -96,22 +99,17 @@ public void execute(final FtpIoSession session, // check parameter String authType = request.getArgument().toUpperCase(); - if (authType.equals("SSL")) { - try { - secureSession(session, "SSL"); - session.write(LocalizedFtpReply.translate(session, request, context, - 234, "AUTH.SSL", null)); - } catch (FtpException ex) { - throw ex; - } catch (Exception ex) { - LOG.warn("AUTH.execute()", ex); - throw new FtpException("AUTH.execute()", ex); + if (VALID_AUTH_TYPES.contains(authType)) { + if(authType.equals("TLS-C")) { + authType = "TLS"; + } else if(authType.equals("TLS-P")) { + authType = "SSL"; } - } else if (authType.equals("TLS")) { + try { - secureSession(session, "TLS"); + secureSession(session, authType); session.write(LocalizedFtpReply.translate(session, request, context, - 234, "AUTH.TLS", null)); + 234, "AUTH." + authType, null)); } catch (FtpException ex) { throw ex; } catch (Exception ex) { @@ -149,6 +147,9 @@ private void secureSession(final FtpIoSession session, final String type) session.getFilterChain().addFirst(SSL_SESSION_FILTER_NAME, sslFilter); + if("SSL".equals(type)) { + session.getDataConnection().setSecure(true); + } } else { throw new FtpException("Socket factory SSL not configured"); } 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 541643e2..90fee6ef 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 @@ -42,8 +42,7 @@ * systems having different syntaxes for naming the parent directory. The reply * codes shall be identical to the reply codes of CWD. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class CDUP extends AbstractCommand { 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 237e3421..c92cc1d6 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 @@ -42,8 +42,7 @@ * Transfer parameters are similarly unchanged. The argument is a pathname * specifying a directory. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class CWD extends AbstractCommand { 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 550504d7..3035e269 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 @@ -41,8 +41,7 @@ * This command causes the file specified in the pathname to be deleted at the * server site. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DELE extends AbstractCommand { diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/DefaultCommandFactory.java b/core/src/main/java/org/apache/ftpserver/command/impl/DefaultCommandFactory.java index b6ec7288..dea5a2e4 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/DefaultCommandFactory.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/DefaultCommandFactory.java @@ -34,8 +34,7 @@ * * Internal class, do not use directly. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultCommandFactory implements CommandFactory { 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 5fb10e69..81506a15 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 @@ -43,8 +43,7 @@ * * EPRT * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class EPRT extends AbstractCommand { @@ -74,7 +73,7 @@ public void execute(final FtpIoSession session, .getDataConnectionConfiguration(); if (!dataCfg.isActiveEnabled()) { session.write(LocalizedFtpReply.translate(session, request, context, - 510, "EPRT.disabled", null)); + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT.disabled", null)); return; } @@ -89,7 +88,7 @@ public void execute(final FtpIoSession session, } catch (Exception ex) { LOG.debug("Exception parsing host and port: " + arg, ex); session.write(LocalizedFtpReply.translate(session, request, context, - 510, "EPRT", null)); + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT", null)); return; } @@ -105,7 +104,7 @@ public void execute(final FtpIoSession session, session, request, context, - FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT.host", null)); return; } @@ -117,7 +116,7 @@ public void execute(final FtpIoSession session, .getRemoteAddress()).getAddress(); if (!dataAddr.equals(clientAddr)) { session.write(LocalizedFtpReply.translate(session, request, - context, 510, "EPRT.mismatch", null)); + context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT.mismatch", null)); return; } } @@ -135,7 +134,7 @@ public void execute(final FtpIoSession session, session, request, context, - FtpReply.REPLY_552_REQUESTED_FILE_ACTION_ABORTED_EXCEEDED_STORAGE, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "EPRT.invalid", null)); return; } 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 4f9ec1af..09c95830 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 @@ -44,8 +44,7 @@ * response code for entering passive mode using an extended address MUST be * 229. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class EPSV extends AbstractCommand { 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 f2f5bb5f..e1558380 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 @@ -37,8 +37,7 @@ * a server supports the FEAT command then it MUST advertise supported AUTH, * PBSZ and PROT commands in the reply. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class FEAT extends AbstractCommand { 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 fcee7369..6a7ebcff 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 @@ -39,8 +39,7 @@ * may take an argument (e.g., any command name) and return more specific * information as a response. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class HELP extends AbstractCommand { 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 78214c1a..01422ccb 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 @@ -38,8 +38,7 @@ * process to determine in which language to present server greetings and the * textual part of command responses. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class LANG extends AbstractCommand { 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 f0a26c1b..86f142e2 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 @@ -54,8 +54,7 @@ * A null argument implies the user's current working or default directory. The * data transfer is over the data connection. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class LIST extends AbstractCommand { 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 10a46dbd..606b5be1 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 @@ -45,8 +45,7 @@ * Returns the MD5 value for a file or multiple files according to * draft-twine-ftpmd5-00.txt. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class MD5 extends AbstractCommand { @@ -90,7 +89,7 @@ public void execute(final FtpIoSession session, fileNames = new String[] { argument }; } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (int i = 0; i < fileNames.length; i++) { String fileName = fileNames[i].trim(); @@ -136,8 +135,14 @@ public void execute(final FtpIoSession session, if (i > 0) { sb.append(", "); } - + boolean nameHasSpaces = fileName.indexOf(' ') >= 0; + if(nameHasSpaces) { + sb.append('"'); + } sb.append(fileName); + if(nameHasSpaces) { + sb.append('"'); + } sb.append(' '); sb.append(md5Hash); 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 c9e7861c..d67cd8bc 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 @@ -40,8 +40,7 @@ * * Returns the date and time of when a file was modified. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class MDTM extends AbstractCommand { 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 9ff73be3..db515b85 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 @@ -40,8 +40,7 @@ * Specified in the following document: * http://www.omz13.com/downloads/draft-somers-ftp-mfxx-00.html#anchor8 *

- * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class MFMT extends AbstractCommand { 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 e80862eb..6ad39d74 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 @@ -43,8 +43,7 @@ * a directory (if the pathname is absolute) or as a subdirectory of the current * working directory (if the pathname is relative). * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class MKD extends AbstractCommand { @@ -62,7 +61,7 @@ public void execute(final FtpIoSession session, // argument check String fileName = request.getArgument(); - if (fileName == null || fileName.indexOf(File.pathSeparatorChar) > -1) { + if (fileName == null) { session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "MKD", null)); 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 a1cfba9f..f1f49aa9 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 @@ -52,8 +52,7 @@ * files in the specified directory. A null argument implies the user's current * working or default directory. The data transfer is over the data connection * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class MLSD extends AbstractCommand { 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 9ff5e57b..2c137c8f 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 @@ -43,8 +43,7 @@ * * Returns info on the file over the control connection. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class MLST extends AbstractCommand { 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 95637fae..4271b730 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 @@ -36,8 +36,7 @@ * The argument is a single Telnet character code specifying the data transfer * modes described in the Section on Transmission Modes. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class MODE extends AbstractCommand { 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 4cbfcb0b..61bdf59a 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 @@ -53,8 +53,7 @@ * descriptor; a null argument implies the current directory. The server will * return a stream of names of files and no other information. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class NLST extends AbstractCommand { 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 2de01048..2c95d11f 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 @@ -37,8 +37,7 @@ * This command does not affect any parameters or previously entered commands. * It specifies no action other than that the server send an OK reply. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class NOOP extends AbstractCommand { 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 90ff2e3d..cc0742c3 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 @@ -41,8 +41,7 @@ * This command shall cause the server use optional features for the command * specified. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class OPTS extends AbstractCommand { 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 ea17d84d..fe2b6a47 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 @@ -20,6 +20,8 @@ package org.apache.ftpserver.command.impl; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.StringTokenizer; import org.apache.ftpserver.command.AbstractCommand; @@ -36,8 +38,7 @@ * Client-Server listing negotation. Instruct the server what listing types to * include in machine directory/file listings. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class OPTS_MLST extends AbstractCommand { @@ -56,22 +57,23 @@ public void execute(final FtpIoSession session, // get the listing types String argument = request.getArgument(); + + String listTypes; + String types[]; int spIndex = argument.indexOf(' '); if (spIndex == -1) { - session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_503_BAD_SEQUENCE_OF_COMMANDS, "OPTS.MLST", - null)); - return; - } - String listTypes = argument.substring(spIndex + 1); - - // parse all the type tokens - StringTokenizer st = new StringTokenizer(listTypes, ";"); - String types[] = new String[st.countTokens()]; - for (int i = 0; i < types.length; ++i) { - types[i] = st.nextToken(); + types = new String[0]; + listTypes = ""; + } else { + listTypes = argument.substring(spIndex + 1); + + // parse all the type tokens + StringTokenizer st = new StringTokenizer(listTypes, ";"); + types = new String[st.countTokens()]; + for (int i = 0; i < types.length; ++i) { + types[i] = st.nextToken(); + } } - // set the list types String[] validatedTypes = validateSelectedTypes(types); if (validatedTypes != null) { @@ -89,26 +91,20 @@ private String[] validateSelectedTypes(final String types[]) { // ignore null types if (types == null) { - return null; + return new String[0]; } + List selectedTypes = new ArrayList(); // check all the types for (int i = 0; i < types.length; ++i) { - boolean bMatch = false; for (int j = 0; j < AVAILABLE_TYPES.length; ++j) { - if (AVAILABLE_TYPES[j].equals(types[i])) { - bMatch = true; + if (AVAILABLE_TYPES[j].equalsIgnoreCase(types[i])) { + selectedTypes.add(AVAILABLE_TYPES[j]); break; } } - if (!bMatch) { - return null; - } } - // set the user types - String[] selectedTypes = new String[types.length]; - System.arraycopy(types, 0, selectedTypes, 0, types.length); - return selectedTypes; + return selectedTypes.toArray(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 7dac1c8d..a38d1bc6 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 @@ -36,8 +36,7 @@ * UTF-8 and back. Note that the servers default encoding is UTF-8. So this * command has no effect. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class OPTS_UTF8 extends AbstractCommand { 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 93bc0920..e8f169f8 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 @@ -50,8 +50,7 @@ * The argument field is a Telnet string specifying the user's password. This * command must be immediately preceded by the user name command. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class PASS extends AbstractCommand { @@ -103,7 +102,14 @@ public void execute(final FtpIoSession session, int currAnonLogin = stat.getCurrentAnonymousLoginNumber(); 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 (currAnonLogin >= maxAnonLogin) { + LOG.debug("Too many anonymous users logged in, user will be disconnected"); session .write(LocalizedFtpReply .translate( @@ -119,7 +125,13 @@ public void execute(final FtpIoSession session, // login limit check int currLogin = stat.getCurrentLoginNumber(); int maxLogin = context.getConnectionConfig().getMaxLogins(); + if(maxLogin == 0) { + LOG.debug("Currently {} users logged in, unlimited allowed", currLogin); + } else { + LOG.debug("Currently {} out of {} users logged in", currLogin, maxLogin); + } if (maxLogin != 0 && currLogin >= maxLogin) { + LOG.debug("Too many users logged in, user will be disconnected"); session .write(LocalizedFtpReply .translate( @@ -168,6 +180,19 @@ public void execute(final FtpIoSession session, int oldMaxIdleTime = session.getMaxIdleTime(); if (authenticatedUser != null) { + if(!authenticatedUser.getEnabled()) { + session + .write(LocalizedFtpReply + .translate( + session, + request, + context, + FtpReply.REPLY_530_NOT_LOGGED_IN, + "PASS", null)); + return; + } + + session.setUser(authenticatedUser); session.setUserArgument(null); session.setMaxIdleTime(authenticatedUser.getMaxIdleTime()); @@ -197,6 +222,8 @@ public void execute(final FtpIoSession session, .getMaxLoginFailures(); if (maxAllowedLoginFailues != 0 && session.getFailedLogins() >= maxAllowedLoginFailues) { + LOG.warn("User exceeded the number of allowed failed logins, session will be closed"); + session.close(false).awaitUninterruptibly(10000); } 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 200bc652..6ef1bf51 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 @@ -47,8 +47,7 @@ * upon receipt of a transfer command. The response to this command includes the * host and port address this server is listening on. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class PASV extends AbstractCommand { 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 6cb348b1..9f7d0237 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 @@ -34,8 +34,7 @@ * * Protection buffer size. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class PBSZ extends AbstractCommand { 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 1448a9c6..761dd4f3 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 @@ -55,8 +55,7 @@ * * where h1 is the high order 8 bits of the internet host address. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class PORT extends AbstractCommand { @@ -85,16 +84,21 @@ public void execute(final FtpIoSession session, .getDataConnectionConfiguration(); if (!dataCfg.isActiveEnabled()) { session.write(LocalizedFtpReply.translate(session, request, context, - 510, "PORT.disabled", null)); + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT.disabled", null)); return; } InetSocketAddress address; try { address = SocketAddressEncoder.decode(request.getArgument()); + + // port must not be 0 + if(address.getPort() == 0) { + throw new IllegalPortException("PORT port must not be 0"); + } } catch (IllegalInetAddressException e) { session.write(LocalizedFtpReply.translate(session, request, context, - 510, "PORT", null)); + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT", null)); return; } catch (IllegalPortException e) { LOG.debug("Invalid data port: " + request.getArgument(), e); @@ -104,7 +108,7 @@ public void execute(final FtpIoSession session, session, request, context, - FtpReply.REPLY_552_REQUESTED_FILE_ACTION_ABORTED_EXCEEDED_STORAGE, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT.invalid", null)); return; } catch (UnknownHostException e) { @@ -115,7 +119,7 @@ public void execute(final FtpIoSession session, session, request, context, - FtpReply.REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED, + FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT.host", null)); return; } @@ -127,7 +131,7 @@ public void execute(final FtpIoSession session, .getRemoteAddress()).getAddress(); if (!address.getAddress().equals(clientAddr)) { session.write(LocalizedFtpReply.translate(session, request, - context, 510, "PORT.mismatch", null)); + context, FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "PORT.mismatch", null)); return; } } 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 7d50133c..119309c2 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 @@ -37,8 +37,7 @@ * * Data channel protection level. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class PROT extends AbstractCommand { 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 8c0148f8..bb6902c9 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 @@ -38,8 +38,7 @@ * This command causes the name of the current working directory to be returned * in the reply. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class PWD extends AbstractCommand { 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 fde131d9..128bb527 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 @@ -27,6 +27,8 @@ import org.apache.ftpserver.impl.FtpIoSession; import org.apache.ftpserver.impl.FtpServerContext; import org.apache.ftpserver.impl.LocalizedFtpReply; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Internal class, do not use directly. @@ -36,11 +38,12 @@ * This command terminates a USER and if file transfer is not in progress, the * server closes the control connection. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class QUIT extends AbstractCommand { + private final Logger LOG = LoggerFactory.getLogger(QUIT.class); + /** * Execute command */ @@ -51,6 +54,7 @@ public void execute(final FtpIoSession session, session.write(LocalizedFtpReply.translate(session, request, context, FtpReply.REPLY_221_CLOSING_CONTROL_CONNECTION, "QUIT", null)); + LOG.debug("QUIT received, closing 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 88182fc6..e6d4385b 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 @@ -36,8 +36,7 @@ * This command flushes a USER, without affecting transfers in progress. The * server state should otherwise be as when the user first connects. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class REIN extends AbstractCommand { 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 70e7848b..a671af05 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 @@ -41,8 +41,7 @@ * followed by the appropriate FTP service command which shall cause file * transfer to resume. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class REST extends AbstractCommand { 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 16d2073c..ac3b4c88 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 @@ -53,8 +53,7 @@ * connection. The status and contents of the file at the server site shall be * unaffected. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class RETR extends AbstractCommand { @@ -165,6 +164,11 @@ public void execute(final FtpIoSession session, // transfer data long 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) { + is.close(); + } LOG.info("File downloaded {}", fileName); @@ -175,11 +179,6 @@ public void execute(final FtpIoSession session, ftpStat.setDownload(session, file, transSz); } - // attempt to close the input stream so that errors in - // closing it will return an error to the client (FTPSERVER-119) - if(is != null) { - is.close(); - } } catch (SocketException ex) { LOG.debug("Socket exception during data transfer", ex); failure = true; 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 32668c66..b934db76 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 @@ -42,8 +42,7 @@ * a directory (if the pathname is absolute) or as a subdirectory of the current * working directory (if the pathname is relative). * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class RMD extends AbstractCommand { 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 a4b590ed..9548ab96 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 @@ -41,8 +41,7 @@ * This command must be immediately followed by a "rename to" command specifying * the new file pathname. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class RNFR extends AbstractCommand { 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 7b519673..54b7cbf1 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 @@ -41,8 +41,7 @@ * immediately preceding "rename from" command. Together the two commands cause * a file to be renamed. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class RNTO extends AbstractCommand { 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 4c79a8d0..52d3291e 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 @@ -38,8 +38,7 @@ * * Handle SITE command. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SITE extends AbstractCommand { 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 7bef7151..c60bb7e3 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 @@ -41,8 +41,7 @@ * * This SITE command returns the specified user information. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SITE_DESCUSER extends AbstractCommand { @@ -97,7 +96,7 @@ public void execute(final FtpIoSession session, } // send the user information - StringBuffer sb = new StringBuffer(128); + StringBuilder sb = new StringBuilder(128); sb.append("\n"); sb.append("userid : ").append(user.getName()).append("\n"); sb.append("userpassword : ********\n"); 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 5f572d59..bd4c9e47 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 @@ -34,8 +34,7 @@ * * Show SITE help message. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SITE_HELP extends AbstractCommand { 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 2db027db..c39f496c 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 @@ -38,8 +38,7 @@ * * Show all statistics information. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SITE_STAT extends AbstractCommand { @@ -64,7 +63,7 @@ public void execute(final FtpIoSession session, // get statistics information FtpStatistics stat = context.getFtpStatistics(); - StringBuffer sb = new StringBuffer(256); + StringBuilder sb = new StringBuilder(256); sb.append('\n'); sb.append("Start Time : ").append( DateUtils.getISO8601Date(stat.getStartTime().getTime())) 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 1f6769f1..c3d3a1d5 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 @@ -43,8 +43,7 @@ * * Sends the list of all the connected users. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SITE_WHO extends AbstractCommand { @@ -68,7 +67,7 @@ public void execute(final FtpIoSession session, } // print all the connected user information - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); Map sessions = session.getService() .getManagedSessions(); 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 62235ce6..64d41afe 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 @@ -36,8 +36,7 @@ * * Displays the FTP server timezone in RFC 822 format. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SITE_ZONE extends AbstractCommand { 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 9c18f784..99665fe5 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 @@ -39,8 +39,7 @@ * * Returns the size of the file in bytes. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SIZE extends AbstractCommand { 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 5f4896bf..2618f28d 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 @@ -22,6 +22,12 @@ import java.io.IOException; import org.apache.ftpserver.command.AbstractCommand; +import org.apache.ftpserver.command.impl.listing.DirectoryLister; +import org.apache.ftpserver.command.impl.listing.LISTFileFormater; +import org.apache.ftpserver.command.impl.listing.ListArgument; +import org.apache.ftpserver.command.impl.listing.ListArgumentParser; +import org.apache.ftpserver.ftplet.FtpException; +import org.apache.ftpserver.ftplet.FtpFile; import org.apache.ftpserver.ftplet.FtpReply; import org.apache.ftpserver.ftplet.FtpRequest; import org.apache.ftpserver.impl.FtpIoSession; @@ -36,11 +42,14 @@ * This command shall cause a status response to be sent over the control * connection in the form of a reply. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class STAT extends AbstractCommand { + private static final LISTFileFormater LIST_FILE_FORMATER = new LISTFileFormater(); + + private DirectoryLister directoryLister = new DirectoryLister(); + /** * Execute command */ @@ -51,9 +60,49 @@ public void execute(final FtpIoSession session, // reset state variables session.resetState(); - // write the status info - session.write(LocalizedFtpReply.translate(session, request, context, - FtpReply.REPLY_211_SYSTEM_STATUS_REPLY, "STAT", null)); + if(request.getArgument() != null) { + ListArgument parsedArg = ListArgumentParser.parse(request.getArgument()); + + // check that the directory or file exists + FtpFile file = null; + try { + file = session.getFileSystemView().getFile(parsedArg.getFile()); + if(!file.doesExist()) { + session.write(LocalizedFtpReply.translate(session, request, context, + FtpReply.REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN, "LIST", + null)); + return; + } + + String dirList = directoryLister.listFiles(parsedArg, + session.getFileSystemView(), LIST_FILE_FORMATER); + + int replyCode; + if(file.isDirectory()) { + replyCode = FtpReply.REPLY_212_DIRECTORY_STATUS; + } else { + replyCode = FtpReply.REPLY_213_FILE_STATUS; + } + + session.write(LocalizedFtpReply.translate(session, request, context, + replyCode, "STAT", + dirList)); + + } catch (FtpException e) { + session.write(LocalizedFtpReply + .translate( + session, + request, + context, + FtpReply.REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN, + "STAT", null)); + } + + } else { + // write the status info + session.write(LocalizedFtpReply.translate(session, request, context, + 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 f8a93f79..4a6a6051 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 @@ -52,8 +52,7 @@ * shall be replaced by the data being transferred. A new file is created at the * server site if the file specified in the pathname does not already exist. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class STOR extends AbstractCommand { @@ -146,6 +145,12 @@ public void execute(final FtpIoSession session, outStream = file.createOutputStream(skipLen); long transSz = dataConnection.transferFromClient(session.getFtpletSession(), outStream); + // attempt to close the output stream so that errors in + // closing it will return an error to the client (FTPSERVER-119) + if(outStream != null) { + outStream.close(); + } + LOG.info("File uploaded {}", fileName); // notify the statistics component @@ -153,11 +158,6 @@ public void execute(final FtpIoSession session, .getFtpStatistics(); ftpStat.setUpload(session, file, transSz); - // attempt to close the output stream so that errors in - // closing it will return an error to the client (FTPSERVER-119) - if(outStream != null) { - outStream.close(); - } } catch (SocketException ex) { LOG.debug("Socket exception during data transfer", ex); failure = true; 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 97cd00b0..6b506f2e 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 @@ -52,8 +52,7 @@ * 150 Transfer Started response must include the name generated, See RFC1123 * section 4.1.2.9 * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class STOU extends AbstractCommand { @@ -153,6 +152,12 @@ public void execute(final FtpIoSession session, // transfer data long 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(); + } + LOG.info("File uploaded {}", fileName); // notify the statistics component @@ -162,11 +167,6 @@ public void execute(final FtpIoSession session, ftpStat.setUpload(session, file, transSz); } - // 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(); - } } catch (SocketException ex) { LOG.debug("Socket exception during data transfer", ex); failure = true; 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 b363fbcd..d86d0d01 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 @@ -38,8 +38,7 @@ * * The argument is a single Telnet character code specifying file structure. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class STRU extends AbstractCommand { 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 b6209a94..e2612de4 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 @@ -35,8 +35,7 @@ * * This command is used to find out the type of operating system at the server. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SYST extends AbstractCommand { 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 bc394f85..48ee344e 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 @@ -38,8 +38,7 @@ * * The argument specifies the representation type. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class TYPE extends AbstractCommand { 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 93e0a96e..8e98e362 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 @@ -34,6 +34,8 @@ import org.apache.ftpserver.impl.ServerFtpStatistics; import org.apache.ftpserver.usermanager.impl.ConcurrentLoginRequest; import org.apache.mina.filter.logging.MdcInjectionFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Internal class, do not use directly. @@ -45,11 +47,12 @@ * system. This command will normally be the first command transmitted by the * user after the control connections are made. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class USER extends AbstractCommand { + private final Logger LOG = LoggerFactory.getLogger(USER.class); + /** * Execute command. */ @@ -112,7 +115,14 @@ public void execute(final FtpIoSession session, int currAnonLogin = stat.getCurrentAnonymousLoginNumber(); 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( @@ -127,7 +137,16 @@ public void execute(final FtpIoSession session, // login limit check int currLogin = stat.getCurrentLoginNumber(); int maxLogin = context.getConnectionConfig().getMaxLogins(); + + if(maxLogin == 0) { + LOG.debug("Currently {} users logged in, unlimited allowed", currLogin); + } else { + LOG.debug("Currently {} out of {} users logged in", currLogin, maxLogin); + } + if (maxLogin != 0 && currLogin >= maxLogin) { + LOG.debug("Too many users logged in, user will be disconnected"); + session .write(LocalizedFtpReply .translate( @@ -154,6 +173,7 @@ public void execute(final FtpIoSession session, stat.getCurrentUserLoginNumber(configUser, address) + 1); if (configUser.authorize(loginRequest) == null) { + LOG.debug("User logged in too many sessions, user will be disconnected"); session .write(LocalizedFtpReply .translate( @@ -182,6 +202,7 @@ public void execute(final FtpIoSession session, // if not ok - close connection if (!success) { + LOG.debug("User failed to login, session will be closed"); session.close(false).awaitUninterruptibly(10000); } } 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 5efbbc9b..49782829 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 @@ -32,14 +32,13 @@ * * This class prints file listing. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DirectoryLister { private String traverseFiles(final List files, final FileFilter filter, final FileFormater formater) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(traverseFiles(files, filter, formater, true)); sb.append(traverseFiles(files, filter, formater, false)); @@ -50,7 +49,7 @@ private String traverseFiles(final List files, private String traverseFiles(final List files, final FileFilter filter, final FileFormater formater, boolean matchDirs) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (FtpFile file : files) { if (file == null) { continue; @@ -70,13 +69,13 @@ public String listFiles(final ListArgument argument, final FileSystemView fileSystemView, final FileFormater formater) throws IOException { - StringBuffer sb = new StringBuffer(); + 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'))) { + if (!argument.hasOption('a')) { filter = new VisibleFileFilter(); } if (argument.getPattern() != null) { diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/FileFilter.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/FileFilter.java index 0054d9b6..0fed5fc4 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/FileFilter.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/FileFilter.java @@ -27,8 +27,7 @@ * * @see java.io.FileFilter * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FileFilter { diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/FileFormater.java b/core/src/main/java/org/apache/ftpserver/command/impl/listing/FileFormater.java index 3b21a9a9..96eb4826 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/FileFormater.java +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/FileFormater.java @@ -25,8 +25,7 @@ * * Interface for formating output based on a {@link FtpFile} * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FileFormater { 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 8d856edf..148d63e0 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 @@ -28,8 +28,7 @@ * * Formats files according to the LIST specification * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class LISTFileFormater implements FileFormater { @@ -41,7 +40,7 @@ public class LISTFileFormater implements FileFormater { * @see FileFormater#format(FtpFile) */ public String format(FtpFile file) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(getPermission(file)); sb.append(DELIM); sb.append(DELIM); @@ -100,8 +99,8 @@ private char[] getPermission(FtpFile file) { } /* - * public String format(FileObject[] files) { StringBuffer sb = new - * StringBuffer(); + * public String format(FileObject[] files) { StringBuilder sb = new + * StringBuilder(); * * for (int i = 0; i < files.length; i++) { sb.append(format(files[i])); * sb.append(NEWLINE); } return sb.toString(); } 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 d61adb8c..b1002ed5 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 @@ -23,8 +23,7 @@ * * Contains the parsed argument for a list command (e.g. LIST or NLST) * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ListArgument { 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 4128135a..82c54b92 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 @@ -25,8 +25,7 @@ * * Parses a list argument (e.g. for LIST or NLST) into a {@link ListArgument} * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ListArgumentParser { @@ -47,8 +46,8 @@ public static ListArgument parse(String argument) { // find options and file name (may have regular expression) if (argument != null) { argument = argument.trim(); - StringBuffer optionsSb = new StringBuffer(4); - StringBuffer fileSb = new StringBuffer(16); + StringBuilder optionsSb = new StringBuilder(4); + StringBuilder fileSb = new StringBuilder(16); StringTokenizer st = new StringTokenizer(argument, " ", true); while (st.hasMoreTokens()) { String token = st.nextToken(); 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 22561470..b3cd9267 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 @@ -26,8 +26,7 @@ * * Formats files according to the MLST specification * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class MLSTFileFormater implements FileFormater { @@ -52,7 +51,7 @@ public MLSTFileFormater(String[] selectedTypes) { * @see FileFormater#format(FtpFile) */ public String format(FtpFile file) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (int i = 0; i < selectedTypes.length; ++i) { String type = selectedTypes[i]; 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 a2147cbe..7ab683a3 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 @@ -25,8 +25,7 @@ * * Formats files according to the NLST specification * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class NLSTFileFormater implements FileFormater { @@ -36,7 +35,7 @@ public class NLSTFileFormater implements FileFormater { * @see FileFormater#format(FtpFile) */ public String format(FtpFile file) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(file.getName()); sb.append(NEWLINE); 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 c4791bca..490653ef 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 @@ -26,8 +26,7 @@ * * Selects files which short name matches a regular expression * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class RegexFileFilter implements FileFilter { 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 14e1a2e6..e424983d 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 @@ -25,8 +25,7 @@ * * Selects files that are visible * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class VisibleFileFilter implements FileFilter { diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/listing/package.html b/core/src/main/java/org/apache/ftpserver/command/impl/listing/package.html index 87346453..4a250c22 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/listing/package.html +++ b/core/src/main/java/org/apache/ftpserver/command/impl/listing/package.html @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + + + + + Internal classes, do not use directly! -

File listing implementations used by various FTP commands

- - +

File listing implementations used by various FTP commands

+ + diff --git a/core/src/main/java/org/apache/ftpserver/command/impl/package.html b/core/src/main/java/org/apache/ftpserver/command/impl/package.html index dc9e0e90..399ab0fd 100644 --- a/core/src/main/java/org/apache/ftpserver/command/impl/package.html +++ b/core/src/main/java/org/apache/ftpserver/command/impl/package.html @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + + + + + Internal classes, do not use directly! -

FTP command implementations

- - +

FTP command implementations

+ + 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 17680822..6239cf03 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 @@ -35,8 +35,7 @@ /** * Parses the FtpServer "commands" element into a Spring bean graph * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class CommandFactoryBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 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 1f7c7119..8aa1ff6b 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 @@ -30,8 +30,7 @@ /** * Parses the FtpServer "native-filesystem" element into a Spring bean graph * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class FileSystemBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/FtpServerNamespaceHandler.java b/core/src/main/java/org/apache/ftpserver/config/spring/FtpServerNamespaceHandler.java index 721cc24a..ae0ddcc0 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/FtpServerNamespaceHandler.java +++ b/core/src/main/java/org/apache/ftpserver/config/spring/FtpServerNamespaceHandler.java @@ -24,8 +24,7 @@ /** * Registration point for FtpServer bean defintion parsers * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class FtpServerNamespaceHandler extends NamespaceHandlerSupport { 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 a94e7a2c..5be20bd8 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 @@ -21,11 +21,12 @@ import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.List; import org.apache.ftpserver.DataConnectionConfiguration; import org.apache.ftpserver.DataConnectionConfigurationFactory; +import org.apache.ftpserver.FtpServerConfigurationException; +import org.apache.ftpserver.ipfilter.DefaultIpFilter; +import org.apache.ftpserver.ipfilter.IpFilterType; import org.apache.ftpserver.listener.ListenerFactory; import org.apache.ftpserver.ssl.SslConfiguration; import org.apache.ftpserver.ssl.SslConfigurationFactory; @@ -43,8 +44,7 @@ /** * Parses the FtpServer "nio-listener" element into a Spring bean graph * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ListenerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { @@ -60,45 +60,6 @@ protected Class getBeanClass(final Element element) { return null; } - /** - * Parse CIDR notations into MINA {@link Subnet}s. TODO: move to Mina - */ - private Subnet parseSubnet(final String subnet) { - if (subnet == null) { - throw new NullPointerException("subnet can not be null"); - } - - String[] tokens = subnet.split("/"); - - String ipString; - String maskString; - if (tokens.length == 2) { - ipString = tokens[0]; - maskString = tokens[1]; - } else if (tokens.length == 1) { - ipString = tokens[0]; - maskString = "32"; - } else { - throw new IllegalArgumentException("Illegal subnet format: " - + subnet); - } - - InetAddress address; - try { - address = InetAddress.getByName(ipString); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("Illegal IP address in subnet: " - + subnet); - } - - int mask = Integer.parseInt(maskString); - if (mask < 0 || mask > 32) { - throw new IllegalArgumentException("Mask must be in the range 0-32"); - } - - return new Subnet(address, mask); - } - /** * {@inheritDoc} */ @@ -139,16 +100,30 @@ protected void doParse(final Element element, Element blacklistElm = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "blacklist"); - if (blacklistElm != null - && StringUtils.hasText(blacklistElm.getTextContent())) { - String[] blocks = blacklistElm.getTextContent().split("[\\s,]+"); - List subnets = new ArrayList(); - - for (String block : blocks) { - subnets.add(parseSubnet(block)); - } - - factoryBuilder.addPropertyValue("blockedSubnets", subnets); + if (blacklistElm != null) { + LOG.warn("Element 'blacklist' is deprecated, and may be removed in a future release. Please use 'ip-filter' instead. "); + try { + DefaultIpFilter ipFilter = new DefaultIpFilter(IpFilterType.DENY, blacklistElm.getTextContent()); + factoryBuilder.addPropertyValue("ipFilter", ipFilter); + } + catch (UnknownHostException e) { + throw new IllegalArgumentException("Invalid IP address or subnet in the 'blacklist' element", e); + } + } + + Element ipFilterElement = SpringUtil.getChildElement(element, FtpServerNamespaceHandler.FTPSERVER_NS, "ip-filter"); + if(ipFilterElement != null) { + if(blacklistElm != null) { + throw new FtpServerConfigurationException("Element 'ipFilter' may not be used when 'blacklist' element is specified. "); + } + String filterType = ipFilterElement.getAttribute("type"); + try { + DefaultIpFilter ipFilter = new DefaultIpFilter(IpFilterType.parse(filterType), ipFilterElement.getTextContent()); + factoryBuilder.addPropertyValue("ipFilter", ipFilter); + } + catch (UnknownHostException e) { + throw new IllegalArgumentException("Invalid IP address or subnet in the 'ip-filter' element"); + } } BeanDefinition factoryDefinition = factoryBuilder.getBeanDefinition(); 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 c890dddf..ab6cab21 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 @@ -42,8 +42,7 @@ /** * Parses the FtpServer "server" element into a Spring bean graph * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ServerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { @@ -119,6 +118,10 @@ 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")); 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 404cd7dc..dbd96b8e 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 @@ -37,8 +37,7 @@ /** * Various util methods for the Spring config parsing and configuration * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SpringUtil { 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 99dab8cd..8e56d991 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 @@ -36,8 +36,7 @@ * Parses the FtpServer "file-user-manager" or "db-user-manager" elements into a * Spring bean graph * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class UserManagerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { diff --git a/core/src/main/java/org/apache/ftpserver/config/spring/package.html b/core/src/main/java/org/apache/ftpserver/config/spring/package.html index e31fac25..ca4f67dc 100644 --- a/core/src/main/java/org/apache/ftpserver/config/spring/package.html +++ b/core/src/main/java/org/apache/ftpserver/config/spring/package.html @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + + + + + Internal classes, do not use directly! -

Support classes for Spring based XML configuration

- - +

Support classes for Spring based XML configuration

+ + 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 ad7103c6..f15a19de 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 @@ -32,8 +32,7 @@ /** * Native file system factory. It uses the OS file system. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class NativeFileSystemFactory implements FileSystemFactory { diff --git a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NameEqualsFileFilter.java b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NameEqualsFileFilter.java index 7e4fdaa3..3bacdac2 100644 --- a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NameEqualsFileFilter.java +++ b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/NameEqualsFileFilter.java @@ -27,8 +27,7 @@ * * FileFilter used for simple file name matching * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class NameEqualsFileFilter implements FileFilter { 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 92665281..55da62da 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 @@ -26,7 +26,6 @@ import org.apache.ftpserver.ftplet.FtpException; import org.apache.ftpserver.ftplet.FtpFile; import org.apache.ftpserver.ftplet.User; -import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,8 +35,7 @@ * File system view based on native file system. Here the root directory will be * user virtual root (/). * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class NativeFileSystemView implements FileSystemView { 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 400188a4..1f8ddbe7 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 @@ -43,13 +43,12 @@ * * This class wraps native file object. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class NativeFtpFile implements FtpFile { private final Logger LOG = LoggerFactory.getLogger(NativeFtpFile.class); - + // the file name with respect to the user root. // The path separator character will be '/' and // it will always begin with '/'. @@ -192,7 +191,7 @@ public long getLastModified() { public boolean setLastModified(long time) { return file.setLastModified(time); } - + /** * Check read permission. */ @@ -215,7 +214,7 @@ public boolean isWritable() { LOG.debug("Checking can write: " + file.canWrite()); return file.canWrite(); } - + LOG.debug("Authorized"); return true; } @@ -225,7 +224,6 @@ public boolean isWritable() { */ public boolean isRemovable() { - // root cannot be deleted if ("/".equals(fileName)) { return false; @@ -235,25 +233,25 @@ public boolean isRemovable() { * we will check if the parent file has write permission as most systems consider that a file can * be deleted when their parent directory is writable. */ - String fullName=getAbsolutePath(); - + String fullName = getAbsolutePath(); + // we check FTPServer's write permission for this file. if (user.authorize(new WriteRequest(fullName)) == null) { return false; } // In order to maintain consistency, when possible we delete the last '/' character in the String - int indexOfSlash=fullName.lastIndexOf('/'); + int indexOfSlash = fullName.lastIndexOf('/'); String parentFullName; - if (indexOfSlash==0){ - parentFullName="/"; - } - else{ - parentFullName=fullName.substring(0,indexOfSlash); + if (indexOfSlash == 0) { + parentFullName = "/"; + } else { + parentFullName = fullName.substring(0, indexOfSlash); } - + // we check if the parent FileObject is writable. - NativeFtpFile parentObject=new NativeFtpFile(parentFullName,file.getAbsoluteFile().getParentFile(),user); - return parentObject.isWritable(); + NativeFtpFile parentObject = new NativeFtpFile(parentFullName, file + .getAbsoluteFile().getParentFile(), user); + return parentObject.isWritable(); } /** @@ -364,6 +362,7 @@ public OutputStream createOutputStream(final long offset) // The IBM jre needs to have both the stream and the random access file // objects closed to actually close the file return new FileOutputStream(raf.getFD()) { + @Override public void close() throws IOException { super.close(); raf.close(); @@ -388,6 +387,7 @@ public InputStream createInputStream(final long offset) throws IOException { // The IBM jre needs to have both the stream and the random access file // objects closed to actually close the file return new FileInputStream(raf.getFD()) { + @Override public void close() throws IOException { super.close(); raf.close(); @@ -496,7 +496,7 @@ public final static String getPhysicalName(final String rootDir, File[] matches = new File(resArg) .listFiles(new NameEqualsFileFilter(tok, true)); - if (matches.length > 0) { + if (matches != null && matches.length > 0) { tok = matches[0].getName(); } } @@ -517,12 +517,36 @@ public final static String getPhysicalName(final String rootDir, return resArg; } - + + /** + * Implements equals by comparing getCanonicalPath() for the underlying file instabnce. + * Ignores the fileName and User fields + */ @Override public boolean equals(Object obj) { - if(obj != null && obj instanceof NativeFtpFile) { - return this.file.equals(((NativeFtpFile) obj).file); - } - return false; + if (obj instanceof NativeFtpFile) { + String thisCanonicalPath; + String otherCanonicalPath; + try { + thisCanonicalPath = this.file.getCanonicalPath(); + otherCanonicalPath = ((NativeFtpFile) obj).file + .getCanonicalPath(); + } catch (IOException e) { + throw new RuntimeException("Failed to get the canonical path", e); + } + + return thisCanonicalPath.equals(otherCanonicalPath); + } + return false; } + + + @Override + public int hashCode() { + try { + return file.getCanonicalPath().hashCode(); + } catch (IOException e) { + return 0; + } + } } diff --git a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/package.html b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/package.html index a9cc7085..e1d20c09 100644 --- a/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/package.html +++ b/core/src/main/java/org/apache/ftpserver/filesystem/nativefs/impl/package.html @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + + + + + Internal classes, do not use directly! -

Native file system implementation

- - +

Native file system implementation

+ + diff --git a/core/src/main/java/org/apache/ftpserver/ftpletcontainer/FtpletContainer.java b/core/src/main/java/org/apache/ftpserver/ftpletcontainer/FtpletContainer.java index 14c3b049..fb84971f 100644 --- a/core/src/main/java/org/apache/ftpserver/ftpletcontainer/FtpletContainer.java +++ b/core/src/main/java/org/apache/ftpserver/ftpletcontainer/FtpletContainer.java @@ -28,8 +28,7 @@ * {@link Ftplet} interface and forward any events to the Ftplets hosted by the * container. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FtpletContainer extends Ftplet { 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 1dcc38dc..7d85fa3d 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 @@ -42,8 +42,7 @@ * * Internal class, do not use directly. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultFtpletContainer implements FtpletContainer { diff --git a/core/src/main/java/org/apache/ftpserver/ftpletcontainer/impl/package.html b/core/src/main/java/org/apache/ftpserver/ftpletcontainer/impl/package.html index af5f8f7a..baac85c3 100644 --- a/core/src/main/java/org/apache/ftpserver/ftpletcontainer/impl/package.html +++ b/core/src/main/java/org/apache/ftpserver/ftpletcontainer/impl/package.html @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + + + + + Internal classes, do not use directly! -

Ftplet container implementation

- - +

Ftplet container implementation

+ + 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 f29e92c2..a5650f6d 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultConnectionConfig.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultConnectionConfig.java @@ -25,9 +25,7 @@ /** * Internal class, do not use directly. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class DefaultConnectionConfig implements ConnectionConfig { @@ -40,18 +38,21 @@ public class DefaultConnectionConfig implements ConnectionConfig { private int maxLoginFailures = 3; private int loginFailureDelay = 500; + + private int maxThreads = 0; /** * Internal constructor, do not use directly. Use {@link ConnectionConfigFactory} instead */ public DefaultConnectionConfig(boolean anonymousLoginEnabled, int loginFailureDelay, int maxLogins, int maxAnonymousLogins, - int maxLoginFailures) { + int maxLoginFailures, int maxThreads) { this.anonymousLoginEnabled = anonymousLoginEnabled; this.loginFailureDelay = loginFailureDelay; this.maxLogins = maxLogins; this.maxAnonymousLogins = maxAnonymousLogins; this.maxLoginFailures = maxLoginFailures; + this.maxThreads = maxThreads; } public int getLoginFailureDelay() { @@ -73,5 +74,9 @@ public int getMaxLogins() { public boolean isAnonymousLoginEnabled() { return anonymousLoginEnabled; } - + + 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 628665dc..ae1a94ec 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultDataConnectionConfiguration.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultDataConnectionConfiguration.java @@ -28,8 +28,7 @@ * * Data connection configuration. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultDataConnectionConfiguration implements DataConnectionConfiguration { @@ -123,25 +122,7 @@ public String getPassiveExernalAddress() { * port will be used. */ public synchronized int requestPassivePort() { - int dataPort = -1; - int loopTimes = 2; - Thread currThread = Thread.currentThread(); - - while ((dataPort == -1) && (--loopTimes >= 0) - && (!currThread.isInterrupted())) { - - // search for a free port - dataPort = passivePorts.reserveNextPort(); - - // no available free port - wait for the release notification - if (dataPort == -1) { - try { - wait(); - } catch (InterruptedException ex) { - } - } - } - return dataPort; + return passivePorts.reserveNextPort(); } /** @@ -158,8 +139,6 @@ public String getPassivePorts() { */ public synchronized void releasePassivePort(final int port) { passivePorts.releasePort(port); - - notify(); } /** 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 f5918574..bd66ab2d 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpHandler.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpHandler.java @@ -20,9 +20,11 @@ package org.apache.ftpserver.impl; import java.io.IOException; +import java.nio.charset.MalformedInputException; import org.apache.ftpserver.command.Command; import org.apache.ftpserver.command.CommandFactory; +import org.apache.ftpserver.ftplet.DefaultFtpReply; import org.apache.ftpserver.ftplet.FileSystemView; import org.apache.ftpserver.ftplet.FtpReply; import org.apache.ftpserver.ftplet.FtpRequest; @@ -31,15 +33,14 @@ import org.apache.ftpserver.listener.Listener; import org.apache.mina.core.session.IdleStatus; import org.apache.mina.core.write.WriteToClosedSessionException; +import org.apache.mina.filter.codec.ProtocolDecoderException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Internal class, do not use directly. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class DefaultFtpHandler implements FtpHandler { @@ -69,15 +70,28 @@ public void sessionCreated(final FtpIoSession session) throws Exception { } public void sessionOpened(final FtpIoSession session) throws Exception { - context.getFtpletContainer().onConnect(session.getFtpletSession()); + FtpletContainer ftplets = context.getFtpletContainer(); - session.updateLastAccessTime(); - - session.write(LocalizedFtpReply.translate(session, null, context, - FtpReply.REPLY_220_SERVICE_READY, null, null)); + FtpletResult ftpletRet; + try { + ftpletRet = ftplets.onConnect(session.getFtpletSession()); + } catch (Exception e) { + LOG.debug("Ftplet threw exception", e); + ftpletRet = FtpletResult.DISCONNECT; + } + if (ftpletRet == FtpletResult.DISCONNECT) { + LOG.debug("Ftplet returned DISCONNECT, session will be closed"); + session.close(false).awaitUninterruptibly(10000); + } else { + session.updateLastAccessTime(); + + session.write(LocalizedFtpReply.translate(session, null, context, + FtpReply.REPLY_220_SERVICE_READY, null, null)); + } } public void sessionClosed(final FtpIoSession session) throws Exception { + LOG.debug("Closing session"); try { context.getFtpletContainer().onDisconnect( session.getFtpletSession()); @@ -85,6 +99,17 @@ public void sessionClosed(final FtpIoSession session) throws Exception { // swallow the exception, we're closing down the session anyways LOG.warn("Ftplet threw an exception on disconnect", e); } + + // make sure we close the data connection if it happens to be open + try { + ServerDataConnectionFactory dc = session.getDataConnection(); + if(dc != null) { + dc.closeDataConnection(); + } + } catch (Exception e) { + // swallow the exception, we're closing down the session anyways + LOG.warn("Data connection threw an exception on disconnect", e); + } FileSystemView fs = session.getFileSystemView(); if(fs != null) { @@ -101,23 +126,38 @@ public void sessionClosed(final FtpIoSession session) throws Exception { if (stats != null) { stats.setLogout(session); stats.setCloseConnection(session); + LOG.debug("Statistics login and connection count decreased due to session close"); + } else { + LOG.warn("Statistics not available in session, can not decrease login and connection count"); } + LOG.debug("Session closed"); } public void exceptionCaught(final FtpIoSession session, final Throwable cause) throws Exception { - if (cause instanceof WriteToClosedSessionException) { + + if(cause instanceof ProtocolDecoderException && + cause.getCause() instanceof MalformedInputException) { + // client probably sent something which is not UTF-8 and we failed to + // decode it + + LOG.warn( + "Client sent command that could not be decoded: {}", + ((ProtocolDecoderException)cause).getHexdump()); + session.write(new DefaultFtpReply(FtpReply.REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS, "Invalid character in command")); + } else if (cause instanceof WriteToClosedSessionException) { WriteToClosedSessionException writeToClosedSessionException = (WriteToClosedSessionException) cause; LOG.warn( "Client closed connection before all replies could be sent, last reply was {}", writeToClosedSessionException.getRequest()); - + session.close(false).awaitUninterruptibly(10000); } else { LOG.error("Exception caught, closing session", cause); + session.close(false).awaitUninterruptibly(10000); } - session.close(false).awaitUninterruptibly(10000); + } private boolean isCommandOkWithoutAuthentication(String command) { @@ -160,6 +200,7 @@ public void messageReceived(final FtpIoSession session, ftpletRet = FtpletResult.DISCONNECT; } if (ftpletRet == FtpletResult.DISCONNECT) { + LOG.debug("Ftplet returned DISCONNECT, session will be closed"); session.close(false).awaitUninterruptibly(10000); return; } else if (ftpletRet != FtpletResult.SKIP) { @@ -184,6 +225,8 @@ public void messageReceived(final FtpIoSession session, ftpletRet = FtpletResult.DISCONNECT; } if (ftpletRet == FtpletResult.DISCONNECT) { + LOG.debug("Ftplet returned DISCONNECT, session will be closed"); + session.close(false).awaitUninterruptibly(10000); return; } diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpRequest.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpRequest.java index 10fbafc9..548e3ad2 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpRequest.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpRequest.java @@ -26,8 +26,7 @@ * * FTP request object. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultFtpRequest implements FtpRequest { 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 bf509c07..680bd19a 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServer.java @@ -43,8 +43,7 @@ * thread. Server implementation is used to create the server * socket and handle client connection. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultFtpServer implements FtpServer { @@ -68,6 +67,10 @@ public DefaultFtpServer(final FtpServerContext serverContext) { * @throws FtpException */ public void start() throws FtpException { + if (serverContext == null) { + // we have already been stopped, can not be restarted + throw new IllegalStateException("FtpServer has been stopped. Restart is not supported"); + } List startedListeners = new ArrayList(); @@ -100,7 +103,8 @@ public void start() throws FtpException { } /** - * Stop the server. Stop the listener thread. + * Stop the server. Stopping the server will close completely and + * it not supported to restart using {@link #start()}. */ public void stop() { if (serverContext == null) { 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 8417ea03..731b0f58 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpServerContext.java @@ -21,9 +21,10 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import org.apache.ftpserver.ConnectionConfig; import org.apache.ftpserver.ConnectionConfigFactory; @@ -46,6 +47,7 @@ import org.apache.ftpserver.usermanager.impl.ConcurrentLoginPermission; import org.apache.ftpserver.usermanager.impl.TransferRatePermission; import org.apache.ftpserver.usermanager.impl.WritePermission; +import org.apache.mina.filter.executor.OrderedThreadPoolExecutor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,8 +56,7 @@ * * FTP server configuration implementation. It holds all the components used. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultFtpServerContext implements FtpServerContext { @@ -80,6 +81,12 @@ public class DefaultFtpServerContext implements FtpServerContext { private static final List ADMIN_AUTHORITIES = new ArrayList(); private static final List ANON_AUTHORITIES = new ArrayList(); + + /** + * The thread pool executor to be used by the server using this context + */ + private ThreadPoolExecutor threadPoolExecutor = null; + static { ADMIN_AUTHORITIES.add(new WritePermission()); @@ -191,6 +198,16 @@ public Ftplet getFtplet(String name) { public void dispose() { listeners.clear(); ftpletContainer.getFtplets().clear(); + if (threadPoolExecutor != null) { + LOG.debug("Shutting down the thread pool executor"); + threadPoolExecutor.shutdown(); + try { + threadPoolExecutor.awaitTermination(5000, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + } finally { + // TODO: how to handle? + } + } } public Listener getListener(String name) { @@ -244,4 +261,22 @@ public ConnectionConfig getConnectionConfig() { public void setConnectionConfig(ConnectionConfig connectionConfig) { this.connectionConfig = connectionConfig; } + + public synchronized ThreadPoolExecutor getThreadPoolExecutor() { + if(threadPoolExecutor == null) { + int maxThreads = connectionConfig.getMaxThreads(); + if(maxThreads < 1) { + int maxLogins = connectionConfig.getMaxLogins(); + if(maxLogins > 0) { + maxThreads = maxLogins; + } + else { + maxThreads = 16; + } + } + LOG.debug("Intializing shared thread pool executor with max threads of {}", maxThreads); + threadPoolExecutor = new OrderedThreadPoolExecutor(maxThreads); + } + return threadPoolExecutor; + } } diff --git a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpSession.java b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpSession.java index 822486ec..cefad774 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpSession.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpSession.java @@ -39,8 +39,7 @@ * * FTP session * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultFtpSession implements FtpSession { 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 4e41227c..e8228e5a 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpStatistics.java +++ b/core/src/main/java/org/apache/ftpserver/impl/DefaultFtpStatistics.java @@ -38,8 +38,7 @@ * TODO revisit concurrency, right now we're a bit over zealous with both Atomic* * counters and synchronization * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultFtpStatistics implements ServerFtpStatistics { diff --git a/core/src/main/java/org/apache/ftpserver/impl/FileObserver.java b/core/src/main/java/org/apache/ftpserver/impl/FileObserver.java index 178dcd44..9eba476b 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/FileObserver.java +++ b/core/src/main/java/org/apache/ftpserver/impl/FileObserver.java @@ -26,8 +26,7 @@ * * This is the file related activity observer. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FileObserver { 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 ac1a731f..69e1c2e7 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/FtpHandler.java +++ b/core/src/main/java/org/apache/ftpserver/impl/FtpHandler.java @@ -31,9 +31,7 @@ /** * Internal class, do not use directly. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public interface FtpHandler { 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 abe0d7bc..9f79c3ae 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/FtpIoSession.java +++ b/core/src/main/java/org/apache/ftpserver/impl/FtpIoSession.java @@ -51,801 +51,829 @@ import org.apache.mina.core.write.WriteRequest; import org.apache.mina.core.write.WriteRequestQueue; import org.apache.mina.filter.ssl.SslFilter; +import org.slf4j.LoggerFactory; /** * Internal class, do not use directly. - * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * + * @author Apache MINA Project * */ public class FtpIoSession implements IoSession { - /** - * Contains user name between USER and PASS commands - */ - public static final String ATTRIBUTE_PREFIX = "org.apache.ftpserver."; + /** + * Contains user name between USER and PASS commands + */ + public static final String ATTRIBUTE_PREFIX = "org.apache.ftpserver."; + + private static final String ATTRIBUTE_USER_ARGUMENT = ATTRIBUTE_PREFIX + + "user-argument"; + + private static final String ATTRIBUTE_SESSION_ID = ATTRIBUTE_PREFIX + + "session-id"; + + private static final String ATTRIBUTE_USER = ATTRIBUTE_PREFIX + "user"; - private static final String ATTRIBUTE_USER_ARGUMENT = ATTRIBUTE_PREFIX - + "user-argument"; + private static final String ATTRIBUTE_LANGUAGE = ATTRIBUTE_PREFIX + + "language"; - private static final String ATTRIBUTE_SESSION_ID = ATTRIBUTE_PREFIX - + "session-id"; - - private static final String ATTRIBUTE_USER = ATTRIBUTE_PREFIX + "user"; + private static final String ATTRIBUTE_LOGIN_TIME = ATTRIBUTE_PREFIX + + "login-time"; + + private static final String ATTRIBUTE_DATA_CONNECTION = ATTRIBUTE_PREFIX + + "data-connection"; - private static final String ATTRIBUTE_LANGUAGE = ATTRIBUTE_PREFIX - + "language"; - - private static final String ATTRIBUTE_LOGIN_TIME = ATTRIBUTE_PREFIX - + "login-time"; - - private static final String ATTRIBUTE_DATA_CONNECTION = ATTRIBUTE_PREFIX - + "data-connection"; - - private static final String ATTRIBUTE_FILE_SYSTEM = ATTRIBUTE_PREFIX - + "file-system"; - - private static final String ATTRIBUTE_RENAME_FROM = ATTRIBUTE_PREFIX - + "rename-from"; - - private static final String ATTRIBUTE_FILE_OFFSET = ATTRIBUTE_PREFIX - + "file-offset"; - - private static final String ATTRIBUTE_DATA_TYPE = ATTRIBUTE_PREFIX - + "data-type"; - - private static final String ATTRIBUTE_STRUCTURE = ATTRIBUTE_PREFIX - + "structure"; - - private static final String ATTRIBUTE_FAILED_LOGINS = ATTRIBUTE_PREFIX - + "failed-logins"; - - private static final String ATTRIBUTE_LISTENER = ATTRIBUTE_PREFIX - + "listener"; - - private static final String ATTRIBUTE_MAX_IDLE_TIME = ATTRIBUTE_PREFIX - + "max-idle-time"; - - private static final String ATTRIBUTE_LAST_ACCESS_TIME = ATTRIBUTE_PREFIX - + "last-access-time"; - - private static final String ATTRIBUTE_CACHED_REMOTE_ADDRESS = ATTRIBUTE_PREFIX - + "cached-remote-address"; - - private IoSession wrappedSession; - - private FtpServerContext context; - - /** - * Last reply that was sent to the client, if any. - */ - private FtpReply lastReply = null; - - /* Begin wrapped IoSession methods */ - - /** - * @see IoSession#close() - */ - public CloseFuture close() { - return wrappedSession.close(); - } - - /** - * @see IoSession#close(boolean) - */ - public CloseFuture close(boolean immediately) { - return wrappedSession.close(immediately); - } - - /** - * @see IoSession#containsAttribute(Object) - */ - public boolean containsAttribute(Object key) { - return wrappedSession.containsAttribute(key); - } - - /** - * @see IoSession#getAttachment() - */ - @SuppressWarnings("deprecation") - public Object getAttachment() { - return wrappedSession.getAttachment(); - } - - /** - * @see IoSession#getAttribute(Object) - */ - public Object getAttribute(Object key) { - return wrappedSession.getAttribute(key); - } - - /** - * @see IoSession#getAttribute(Object, Object) - */ - public Object getAttribute(Object key, Object defaultValue) { - return wrappedSession.getAttribute(key, defaultValue); - } - - /** - * @see IoSession#getAttributeKeys() - */ - public Set getAttributeKeys() { - return wrappedSession.getAttributeKeys(); - } - - /** - * @see IoSession#getBothIdleCount() - */ - public int getBothIdleCount() { - return wrappedSession.getBothIdleCount(); - } - - /** - * @see IoSession#getCloseFuture() - */ - public CloseFuture getCloseFuture() { - return wrappedSession.getCloseFuture(); - } - - /** - * @see IoSession#getConfig() - */ - public IoSessionConfig getConfig() { - return wrappedSession.getConfig(); - } - - /** - * @see IoSession#getCreationTime() - */ - public long getCreationTime() { - return wrappedSession.getCreationTime(); - } - - /** - * @see IoSession#getFilterChain() - */ - public IoFilterChain getFilterChain() { - return wrappedSession.getFilterChain(); - } - - /** - * @see IoSession#getHandler() - */ - public IoHandler getHandler() { - return wrappedSession.getHandler(); - } - - /** - * @see IoSession#getId() - */ - public long getId() { - return wrappedSession.getId(); - } - - /** - * @see IoSession#getIdleCount(IdleStatus) - */ - public int getIdleCount(IdleStatus status) { - return wrappedSession.getIdleCount(status); - } - - /** - * @see IoSession#getLastBothIdleTime() - */ - public long getLastBothIdleTime() { - return wrappedSession.getLastBothIdleTime(); - } - - /** - * @see IoSession#getLastIdleTime(IdleStatus) - */ - public long getLastIdleTime(IdleStatus status) { - return wrappedSession.getLastIdleTime(status); - } - - /** - * @see IoSession#getLastIoTime() - */ - public long getLastIoTime() { - return wrappedSession.getLastIoTime(); - } - - /** - * @see IoSession#getLastReadTime() - */ - public long getLastReadTime() { - return wrappedSession.getLastReadTime(); - } - - /** - * @see IoSession#getLastReaderIdleTime() - */ - public long getLastReaderIdleTime() { - return wrappedSession.getLastReaderIdleTime(); - } - - /** - * @see IoSession#getLastWriteTime() - */ - public long getLastWriteTime() { - return wrappedSession.getLastWriteTime(); - } - - /** - * @see IoSession#getLastWriterIdleTime() - */ - public long getLastWriterIdleTime() { - return wrappedSession.getLastWriterIdleTime(); - } - - /** - * @see IoSession#getLocalAddress() - */ - public SocketAddress getLocalAddress() { - return wrappedSession.getLocalAddress(); - } - - /** - * @see IoSession#getReadBytes() - */ - public long getReadBytes() { - return wrappedSession.getReadBytes(); - } - - /** - * @see IoSession#getReadBytesThroughput() - */ - public double getReadBytesThroughput() { - return wrappedSession.getReadBytesThroughput(); - } - - /** - * @see IoSession#getReadMessages() - */ - public long getReadMessages() { - return wrappedSession.getReadMessages(); - } - - /** - * @see IoSession#getReadMessagesThroughput() - */ - public double getReadMessagesThroughput() { - return wrappedSession.getReadMessagesThroughput(); - } - - /** - * @see IoSession#getReaderIdleCount() - */ - public int getReaderIdleCount() { - return wrappedSession.getReaderIdleCount(); - } - - /** - * @see IoSession#getRemoteAddress() - */ - public SocketAddress getRemoteAddress() { - // when closing a socket, the remote address might be reset to null - // therefore, we attempt to keep a cached copy around - - SocketAddress address = wrappedSession.getRemoteAddress(); - if (address == null - && containsAttribute(ATTRIBUTE_CACHED_REMOTE_ADDRESS)) { - return (SocketAddress) getAttribute(ATTRIBUTE_CACHED_REMOTE_ADDRESS); - } else { - setAttribute(ATTRIBUTE_CACHED_REMOTE_ADDRESS, address); - return address; - } - } - - /** - * @see IoSession#getScheduledWriteBytes() - */ - public long getScheduledWriteBytes() { - return wrappedSession.getScheduledWriteBytes(); - } - - /** - * @see IoSession#getScheduledWriteMessages() - */ - public int getScheduledWriteMessages() { - return wrappedSession.getScheduledWriteMessages(); - } - - /** - * @see IoSession#getService() - */ - public IoService getService() { - return wrappedSession.getService(); - } - - /** - * @see IoSession#getServiceAddress() - */ - public SocketAddress getServiceAddress() { - return wrappedSession.getServiceAddress(); - } - - /** - * @see IoSession#getTransportMetadata() - */ - public TransportMetadata getTransportMetadata() { - return wrappedSession.getTransportMetadata(); - } - - /** - * @see IoSession#getWriterIdleCount() - */ - public int getWriterIdleCount() { - return wrappedSession.getWriterIdleCount(); - } - - /** - * @see IoSession#getWrittenBytes() - */ - public long getWrittenBytes() { - return wrappedSession.getWrittenBytes(); - } - - /** - * @see IoSession#getWrittenBytesThroughput() - */ - public double getWrittenBytesThroughput() { - return wrappedSession.getWrittenBytesThroughput(); - } - - /** - * @see IoSession#getWrittenMessages() - */ - public long getWrittenMessages() { - return wrappedSession.getWrittenMessages(); - } - - /** - * @see IoSession#getWrittenMessagesThroughput() - */ - public double getWrittenMessagesThroughput() { - return wrappedSession.getWrittenMessagesThroughput(); - } - - /** - * @see IoSession#isClosing() - */ - public boolean isClosing() { - return wrappedSession.isClosing(); - } - - /** - * @see IoSession#isConnected() - */ - public boolean isConnected() { - return wrappedSession.isConnected(); - } - - /** - * @see IoSession#isIdle(IdleStatus) - */ - public boolean isIdle(IdleStatus status) { - return wrappedSession.isIdle(status); - } - - /** - * @see IoSession#read() - */ - public ReadFuture read() { - return wrappedSession.read(); - } - - /** - * @see IoSession#removeAttribute(Object) - */ - public Object removeAttribute(Object key) { - return wrappedSession.removeAttribute(key); - } - - /** - * @see IoSession#removeAttribute(Object, Object) - */ - public boolean removeAttribute(Object key, Object value) { - return wrappedSession.removeAttribute(key, value); - } - - /** - * @see IoSession#replaceAttribute(Object, Object, Object) - */ - public boolean replaceAttribute(Object key, Object oldValue, Object newValue) { - return wrappedSession.replaceAttribute(key, oldValue, newValue); - } - - /** - * @see IoSession#resumeRead() - */ - public void resumeRead() { - wrappedSession.resumeRead(); - } - - /** - * @see IoSession#resumeWrite() - */ - public void resumeWrite() { - wrappedSession.resumeWrite(); - } - - /** - * @see IoSession#setAttachment(Object) - */ - @SuppressWarnings("deprecation") - public Object setAttachment(Object attachment) { - return wrappedSession.setAttachment(attachment); - } - - /** - * @see IoSession#setAttribute(Object) - */ - public Object setAttribute(Object key) { - return wrappedSession.setAttribute(key); - } - - /** - * @see IoSession#setAttribute(Object, Object) - */ - public Object setAttribute(Object key, Object value) { - return wrappedSession.setAttribute(key, value); - } - - /** - * @see IoSession#setAttributeIfAbsent(Object) - */ - public Object setAttributeIfAbsent(Object key) { - return wrappedSession.setAttributeIfAbsent(key); - } - - /** - * @see IoSession#setAttributeIfAbsent(Object, Object) - */ - public Object setAttributeIfAbsent(Object key, Object value) { - return wrappedSession.setAttributeIfAbsent(key, value); - } - - /** - * @see IoSession#suspendRead() - */ - public void suspendRead() { - wrappedSession.suspendRead(); - } - - /** - * @see IoSession#suspendWrite() - */ - public void suspendWrite() { - wrappedSession.suspendWrite(); - } - - /** - * @see IoSession#write(Object) - */ - public WriteFuture write(Object message) { - WriteFuture future = wrappedSession.write(message); - this.lastReply = (FtpReply) message; - return future; - } - - /** - * @see IoSession#write(Object, SocketAddress) - */ - public WriteFuture write(Object message, SocketAddress destination) { - WriteFuture future = wrappedSession.write(message, destination); - this.lastReply = (FtpReply) message; - return future; - } - - /* End wrapped IoSession methods */ - - public void resetState() { - removeAttribute(ATTRIBUTE_RENAME_FROM); - removeAttribute(ATTRIBUTE_FILE_OFFSET); - } - - public synchronized ServerDataConnectionFactory getDataConnection() { - if (containsAttribute(ATTRIBUTE_DATA_CONNECTION)) { - return (ServerDataConnectionFactory) getAttribute(ATTRIBUTE_DATA_CONNECTION); - } else { - IODataConnectionFactory dataCon = new IODataConnectionFactory( - context, this); - dataCon - .setServerControlAddress(((InetSocketAddress) getLocalAddress()) - .getAddress()); - setAttribute(ATTRIBUTE_DATA_CONNECTION, dataCon); - - return dataCon; - } - } - - public FileSystemView getFileSystemView() { - return (FileSystemView) getAttribute(ATTRIBUTE_FILE_SYSTEM); - } - - public User getUser() { - return (User) getAttribute(ATTRIBUTE_USER); - } - - /** - * Is logged-in - */ - public boolean isLoggedIn() { - return containsAttribute(ATTRIBUTE_USER); - } - - public Listener getListener() { - return (Listener) getAttribute(ATTRIBUTE_LISTENER); - } - - public void setListener(Listener listener) { - setAttribute(ATTRIBUTE_LISTENER, listener); - } - - public FtpSession getFtpletSession() { - return new DefaultFtpSession(this); - } - - public String getLanguage() { - return (String) getAttribute(ATTRIBUTE_LANGUAGE); - } - - public void setLanguage(String language) { - setAttribute(ATTRIBUTE_LANGUAGE, language); - - } - - public String getUserArgument() { - return (String) getAttribute(ATTRIBUTE_USER_ARGUMENT); - } - - public void setUser(User user) { - setAttribute(ATTRIBUTE_USER, user); - - } - - public void setUserArgument(String userArgument) { - setAttribute(ATTRIBUTE_USER_ARGUMENT, userArgument); - - } - - public int getMaxIdleTime() { - return (Integer) getAttribute(ATTRIBUTE_MAX_IDLE_TIME, 0); - } - - public void setMaxIdleTime(int maxIdleTime) { - setAttribute(ATTRIBUTE_MAX_IDLE_TIME, maxIdleTime); - - int listenerTimeout = getListener().getIdleTimeout(); - - // the listener timeout should be the upper limit, unless set to unlimited - if(listenerTimeout <= 0 || maxIdleTime < listenerTimeout) { - wrappedSession.getConfig().setBothIdleTime(maxIdleTime); - } - } - - public synchronized void increaseFailedLogins() { - int failedLogins = (Integer) getAttribute(ATTRIBUTE_FAILED_LOGINS, 0); - failedLogins++; - setAttribute(ATTRIBUTE_FAILED_LOGINS, failedLogins); - } - - public int getFailedLogins() { - return (Integer) getAttribute(ATTRIBUTE_FAILED_LOGINS, 0); - } - - public void setLogin(FileSystemView fsview) { - setAttribute(ATTRIBUTE_LOGIN_TIME, new Date()); - setAttribute(ATTRIBUTE_FILE_SYSTEM, fsview); - } - - public void reinitialize() { - removeAttribute(ATTRIBUTE_USER); - removeAttribute(ATTRIBUTE_USER_ARGUMENT); - removeAttribute(ATTRIBUTE_LOGIN_TIME); - removeAttribute(ATTRIBUTE_FILE_SYSTEM); - removeAttribute(ATTRIBUTE_RENAME_FROM); - removeAttribute(ATTRIBUTE_FILE_OFFSET); - } - - public void setFileOffset(long fileOffset) { - setAttribute(ATTRIBUTE_FILE_OFFSET, fileOffset); - - } - - public void setRenameFrom(FtpFile renFr) { - setAttribute(ATTRIBUTE_RENAME_FROM, renFr); - - } - - public FtpFile getRenameFrom() { - return (FtpFile) getAttribute(ATTRIBUTE_RENAME_FROM); - } - - public long getFileOffset() { - return (Long) getAttribute(ATTRIBUTE_FILE_OFFSET, 0L); - } - - public void setStructure(Structure structure) { - setAttribute(ATTRIBUTE_STRUCTURE, structure); - } - - public void setDataType(DataType dataType) { - setAttribute(ATTRIBUTE_DATA_TYPE, dataType); - - } - - /** - * @see FtpSession#getSessionId() - */ - public UUID getSessionId() { - synchronized (wrappedSession) { - if(!wrappedSession.containsAttribute(ATTRIBUTE_SESSION_ID)) { - wrappedSession.setAttribute(ATTRIBUTE_SESSION_ID, UUID.randomUUID()); - } - return (UUID) wrappedSession.getAttribute(ATTRIBUTE_SESSION_ID); - } - } - - public FtpIoSession(IoSession wrappedSession, FtpServerContext context) { - this.wrappedSession = wrappedSession; - this.context = context; - } - - public Structure getStructure() { - return (Structure) getAttribute(ATTRIBUTE_STRUCTURE, Structure.FILE); - } - - public DataType getDataType() { - return (DataType) getAttribute(ATTRIBUTE_DATA_TYPE, DataType.ASCII); - } - - public Date getLoginTime() { - return (Date) getAttribute(ATTRIBUTE_LOGIN_TIME); - } - - public Date getLastAccessTime() { - return (Date) getAttribute(ATTRIBUTE_LAST_ACCESS_TIME); - } - - public Certificate[] getClientCertificates() { - if (getFilterChain().contains(SslFilter.class)) { - SslFilter sslFilter = (SslFilter) getFilterChain().get( - SslFilter.class); - - SSLSession sslSession = sslFilter.getSslSession(this); - - if (sslSession != null) { - try { - return sslSession.getPeerCertificates(); - } catch (SSLPeerUnverifiedException e) { - // ignore, certificate will not be available to the session - } - } - - } - - // no certificates available - return null; - - } - - public void updateLastAccessTime() { - setAttribute(ATTRIBUTE_LAST_ACCESS_TIME, new Date()); - - } - - /** - * @see IoSession#getCurrentWriteMessage() - */ - public Object getCurrentWriteMessage() { - return wrappedSession.getCurrentWriteMessage(); - } - - /** - * @see IoSession#getCurrentWriteRequest() - */ - public WriteRequest getCurrentWriteRequest() { - return wrappedSession.getCurrentWriteRequest(); - } - - /** - * @see IoSession#isBothIdle() - */ - public boolean isBothIdle() { - return wrappedSession.isBothIdle(); - } - - /** - * @see IoSession#isReaderIdle() - */ - public boolean isReaderIdle() { - return wrappedSession.isReaderIdle(); - } - - /** - * @see IoSession#isWriterIdle() - */ - public boolean isWriterIdle() { - return wrappedSession.isWriterIdle(); - } - - /** - * Indicates whether the control socket for this session is secure, that is, - * running over SSL/TLS - * - * @return true if the control socket is secured - */ - public boolean isSecure() { - return getFilterChain().contains(SslFilter.class); - } - - /** - * Increase the number of bytes written on the data connection - * @param increment The number of bytes written - */ - public void increaseWrittenDataBytes(int increment) { - if (wrappedSession instanceof AbstractIoSession) { - ((AbstractIoSession) wrappedSession) - .increaseScheduledWriteBytes(increment); - ((AbstractIoSession) wrappedSession).increaseWrittenBytes( - increment, System.currentTimeMillis()); - } - } - - /** - * Increase the number of bytes read on the data connection - * @param increment The number of bytes written - */ - public void increaseReadDataBytes(int increment) { - if (wrappedSession instanceof AbstractIoSession) { - ((AbstractIoSession) wrappedSession).increaseReadBytes(increment, - System.currentTimeMillis()); - } - } - - /** - * Returns the last reply that was sent to the client. - * @return the last reply that was sent to the client. - */ - public FtpReply getLastReply() { - return lastReply; - } - - /** - * @see IoSession#getWriteRequestQueue() - */ - public WriteRequestQueue getWriteRequestQueue() { - return wrappedSession.getWriteRequestQueue(); - } - - /** - * @see IoSession#isReadSuspended() - */ - public boolean isReadSuspended() { - return wrappedSession.isReadSuspended(); - } - - /** - * @see IoSession#isWriteSuspended() - */ - public boolean isWriteSuspended() { - return wrappedSession.isWriteSuspended(); - } - - /** - * @see IoSession#setCurrentWriteRequest(WriteRequest) - */ - public void setCurrentWriteRequest(WriteRequest currentWriteRequest) { - wrappedSession.setCurrentWriteRequest(currentWriteRequest); - } - - /** - * @see IoSession#updateThroughput(long, boolean) - */ - public void updateThroughput(long currentTime, boolean force) { - wrappedSession.updateThroughput(currentTime, force); - } + private static final String ATTRIBUTE_FILE_SYSTEM = ATTRIBUTE_PREFIX + + "file-system"; + + private static final String ATTRIBUTE_RENAME_FROM = ATTRIBUTE_PREFIX + + "rename-from"; + + private static final String ATTRIBUTE_FILE_OFFSET = ATTRIBUTE_PREFIX + + "file-offset"; + + private static final String ATTRIBUTE_DATA_TYPE = ATTRIBUTE_PREFIX + + "data-type"; + + private static final String ATTRIBUTE_STRUCTURE = ATTRIBUTE_PREFIX + + "structure"; + + private static final String ATTRIBUTE_FAILED_LOGINS = ATTRIBUTE_PREFIX + + "failed-logins"; + + private static final String ATTRIBUTE_LISTENER = ATTRIBUTE_PREFIX + + "listener"; + + private static final String ATTRIBUTE_MAX_IDLE_TIME = ATTRIBUTE_PREFIX + + "max-idle-time"; + + private static final String ATTRIBUTE_LAST_ACCESS_TIME = ATTRIBUTE_PREFIX + + "last-access-time"; + + private static final String ATTRIBUTE_CACHED_REMOTE_ADDRESS = ATTRIBUTE_PREFIX + + "cached-remote-address"; + + private IoSession wrappedSession; + + private FtpServerContext context; + + /** + * Last reply that was sent to the client, if any. + */ + private FtpReply lastReply = null; + + /* Begin wrapped IoSession methods */ + + /** + * @see IoSession#close() + */ + public CloseFuture close() { + return wrappedSession.close(); + } + + /** + * @see IoSession#close(boolean) + */ + public CloseFuture close(boolean immediately) { + return wrappedSession.close(immediately); + } + + /** + * @see IoSession#containsAttribute(Object) + */ + public boolean containsAttribute(Object key) { + return wrappedSession.containsAttribute(key); + } + + /** + * @see IoSession#getAttachment() + */ + @SuppressWarnings("deprecation") + public Object getAttachment() { + return wrappedSession.getAttachment(); + } + + /** + * @see IoSession#getAttribute(Object) + */ + public Object getAttribute(Object key) { + return wrappedSession.getAttribute(key); + } + + /** + * @see IoSession#getAttribute(Object, Object) + */ + public Object getAttribute(Object key, Object defaultValue) { + return wrappedSession.getAttribute(key, defaultValue); + } + + /** + * @see IoSession#getAttributeKeys() + */ + public Set getAttributeKeys() { + return wrappedSession.getAttributeKeys(); + } + + /** + * @see IoSession#getBothIdleCount() + */ + public int getBothIdleCount() { + return wrappedSession.getBothIdleCount(); + } + + /** + * @see IoSession#getCloseFuture() + */ + public CloseFuture getCloseFuture() { + return wrappedSession.getCloseFuture(); + } + + /** + * @see IoSession#getConfig() + */ + public IoSessionConfig getConfig() { + return wrappedSession.getConfig(); + } + + /** + * @see IoSession#getCreationTime() + */ + public long getCreationTime() { + return wrappedSession.getCreationTime(); + } + + /** + * @see IoSession#getFilterChain() + */ + public IoFilterChain getFilterChain() { + return wrappedSession.getFilterChain(); + } + + /** + * @see IoSession#getHandler() + */ + public IoHandler getHandler() { + return wrappedSession.getHandler(); + } + + /** + * @see IoSession#getId() + */ + public long getId() { + return wrappedSession.getId(); + } + + /** + * @see IoSession#getIdleCount(IdleStatus) + */ + public int getIdleCount(IdleStatus status) { + return wrappedSession.getIdleCount(status); + } + + /** + * @see IoSession#getLastBothIdleTime() + */ + public long getLastBothIdleTime() { + return wrappedSession.getLastBothIdleTime(); + } + + /** + * @see IoSession#getLastIdleTime(IdleStatus) + */ + public long getLastIdleTime(IdleStatus status) { + return wrappedSession.getLastIdleTime(status); + } + + /** + * @see IoSession#getLastIoTime() + */ + public long getLastIoTime() { + return wrappedSession.getLastIoTime(); + } + + /** + * @see IoSession#getLastReadTime() + */ + public long getLastReadTime() { + return wrappedSession.getLastReadTime(); + } + + /** + * @see IoSession#getLastReaderIdleTime() + */ + public long getLastReaderIdleTime() { + return wrappedSession.getLastReaderIdleTime(); + } + + /** + * @see IoSession#getLastWriteTime() + */ + public long getLastWriteTime() { + return wrappedSession.getLastWriteTime(); + } + + /** + * @see IoSession#getLastWriterIdleTime() + */ + public long getLastWriterIdleTime() { + return wrappedSession.getLastWriterIdleTime(); + } + + /** + * @see IoSession#getLocalAddress() + */ + public SocketAddress getLocalAddress() { + return wrappedSession.getLocalAddress(); + } + + /** + * @see IoSession#getReadBytes() + */ + public long getReadBytes() { + return wrappedSession.getReadBytes(); + } + + /** + * @see IoSession#getReadBytesThroughput() + */ + public double getReadBytesThroughput() { + return wrappedSession.getReadBytesThroughput(); + } + + /** + * @see IoSession#getReadMessages() + */ + public long getReadMessages() { + return wrappedSession.getReadMessages(); + } + + /** + * @see IoSession#getReadMessagesThroughput() + */ + public double getReadMessagesThroughput() { + return wrappedSession.getReadMessagesThroughput(); + } + + /** + * @see IoSession#getReaderIdleCount() + */ + public int getReaderIdleCount() { + return wrappedSession.getReaderIdleCount(); + } + + /** + * @see IoSession#getRemoteAddress() + */ + public SocketAddress getRemoteAddress() { + // when closing a socket, the remote address might be reset to null + // therefore, we attempt to keep a cached copy around + + SocketAddress address = wrappedSession.getRemoteAddress(); + if (address == null + && containsAttribute(ATTRIBUTE_CACHED_REMOTE_ADDRESS)) { + return (SocketAddress) getAttribute(ATTRIBUTE_CACHED_REMOTE_ADDRESS); + } else { + setAttribute(ATTRIBUTE_CACHED_REMOTE_ADDRESS, address); + return address; + } + } + + /** + * @see IoSession#getScheduledWriteBytes() + */ + public long getScheduledWriteBytes() { + return wrappedSession.getScheduledWriteBytes(); + } + + /** + * @see IoSession#getScheduledWriteMessages() + */ + public int getScheduledWriteMessages() { + return wrappedSession.getScheduledWriteMessages(); + } + + /** + * @see IoSession#getService() + */ + public IoService getService() { + return wrappedSession.getService(); + } + + /** + * @see IoSession#getServiceAddress() + */ + public SocketAddress getServiceAddress() { + return wrappedSession.getServiceAddress(); + } + + /** + * @see IoSession#getTransportMetadata() + */ + public TransportMetadata getTransportMetadata() { + return wrappedSession.getTransportMetadata(); + } + + /** + * @see IoSession#getWriterIdleCount() + */ + public int getWriterIdleCount() { + return wrappedSession.getWriterIdleCount(); + } + + /** + * @see IoSession#getWrittenBytes() + */ + public long getWrittenBytes() { + return wrappedSession.getWrittenBytes(); + } + + /** + * @see IoSession#getWrittenBytesThroughput() + */ + public double getWrittenBytesThroughput() { + return wrappedSession.getWrittenBytesThroughput(); + } + + /** + * @see IoSession#getWrittenMessages() + */ + public long getWrittenMessages() { + return wrappedSession.getWrittenMessages(); + } + + /** + * @see IoSession#getWrittenMessagesThroughput() + */ + public double getWrittenMessagesThroughput() { + return wrappedSession.getWrittenMessagesThroughput(); + } + + /** + * @see IoSession#isClosing() + */ + public boolean isClosing() { + return wrappedSession.isClosing(); + } + + /** + * @see IoSession#isConnected() + */ + public boolean isConnected() { + return wrappedSession.isConnected(); + } + + /** + * @see IoSession#isIdle(IdleStatus) + */ + public boolean isIdle(IdleStatus status) { + return wrappedSession.isIdle(status); + } + + /** + * @see IoSession#read() + */ + public ReadFuture read() { + return wrappedSession.read(); + } + + /** + * @see IoSession#removeAttribute(Object) + */ + public Object removeAttribute(Object key) { + return wrappedSession.removeAttribute(key); + } + + /** + * @see IoSession#removeAttribute(Object, Object) + */ + public boolean removeAttribute(Object key, Object value) { + return wrappedSession.removeAttribute(key, value); + } + + /** + * @see IoSession#replaceAttribute(Object, Object, Object) + */ + public boolean replaceAttribute(Object key, Object oldValue, Object newValue) { + return wrappedSession.replaceAttribute(key, oldValue, newValue); + } + + /** + * @see IoSession#resumeRead() + */ + public void resumeRead() { + wrappedSession.resumeRead(); + } + + /** + * @see IoSession#resumeWrite() + */ + public void resumeWrite() { + wrappedSession.resumeWrite(); + } + + /** + * @see IoSession#setAttachment(Object) + */ + @SuppressWarnings("deprecation") + public Object setAttachment(Object attachment) { + return wrappedSession.setAttachment(attachment); + } + + /** + * @see IoSession#setAttribute(Object) + */ + public Object setAttribute(Object key) { + return wrappedSession.setAttribute(key); + } + + /** + * @see IoSession#setAttribute(Object, Object) + */ + public Object setAttribute(Object key, Object value) { + return wrappedSession.setAttribute(key, value); + } + + /** + * @see IoSession#setAttributeIfAbsent(Object) + */ + public Object setAttributeIfAbsent(Object key) { + return wrappedSession.setAttributeIfAbsent(key); + } + + /** + * @see IoSession#setAttributeIfAbsent(Object, Object) + */ + public Object setAttributeIfAbsent(Object key, Object value) { + return wrappedSession.setAttributeIfAbsent(key, value); + } + + /** + * @see IoSession#suspendRead() + */ + public void suspendRead() { + wrappedSession.suspendRead(); + } + + /** + * @see IoSession#suspendWrite() + */ + public void suspendWrite() { + wrappedSession.suspendWrite(); + } + + /** + * @see IoSession#write(Object) + */ + public WriteFuture write(Object message) { + WriteFuture future = wrappedSession.write(message); + this.lastReply = (FtpReply) message; + return future; + } + + /** + * @see IoSession#write(Object, SocketAddress) + */ + public WriteFuture write(Object message, SocketAddress destination) { + WriteFuture future = wrappedSession.write(message, destination); + this.lastReply = (FtpReply) message; + return future; + } + + /* End wrapped IoSession methods */ + + public void resetState() { + removeAttribute(ATTRIBUTE_RENAME_FROM); + removeAttribute(ATTRIBUTE_FILE_OFFSET); + } + + public synchronized ServerDataConnectionFactory getDataConnection() { + if (containsAttribute(ATTRIBUTE_DATA_CONNECTION)) { + return (ServerDataConnectionFactory) getAttribute(ATTRIBUTE_DATA_CONNECTION); + } else { + IODataConnectionFactory dataCon = new IODataConnectionFactory( + context, this); + dataCon + .setServerControlAddress(((InetSocketAddress) getLocalAddress()) + .getAddress()); + setAttribute(ATTRIBUTE_DATA_CONNECTION, dataCon); + + return dataCon; + } + } + + public FileSystemView getFileSystemView() { + return (FileSystemView) getAttribute(ATTRIBUTE_FILE_SYSTEM); + } + + public User getUser() { + return (User) getAttribute(ATTRIBUTE_USER); + } + + /** + * Is logged-in + */ + public boolean isLoggedIn() { + return containsAttribute(ATTRIBUTE_USER); + } + + public Listener getListener() { + return (Listener) getAttribute(ATTRIBUTE_LISTENER); + } + + public void setListener(Listener listener) { + setAttribute(ATTRIBUTE_LISTENER, listener); + } + + public FtpSession getFtpletSession() { + return new DefaultFtpSession(this); + } + + public String getLanguage() { + return (String) getAttribute(ATTRIBUTE_LANGUAGE); + } + + public void setLanguage(String language) { + setAttribute(ATTRIBUTE_LANGUAGE, language); + + } + + public String getUserArgument() { + return (String) getAttribute(ATTRIBUTE_USER_ARGUMENT); + } + + public void setUser(User user) { + setAttribute(ATTRIBUTE_USER, user); + + } + + public void setUserArgument(String userArgument) { + setAttribute(ATTRIBUTE_USER_ARGUMENT, userArgument); + + } + + public int getMaxIdleTime() { + return (Integer) getAttribute(ATTRIBUTE_MAX_IDLE_TIME, 0); + } + + public void setMaxIdleTime(int maxIdleTime) { + setAttribute(ATTRIBUTE_MAX_IDLE_TIME, maxIdleTime); + + int listenerTimeout = getListener().getIdleTimeout(); + + // the listener timeout should be the upper limit, unless set to + // unlimited + // if the user limit is set to be unlimited, use the listener value is + // the threshold + // (already used as the default for all sessions) + // else, if the user limit is less than the listener idle time, use the + // user limit + if (listenerTimeout <= 0 + || (maxIdleTime > 0 && maxIdleTime < listenerTimeout)) { + wrappedSession.getConfig().setBothIdleTime(maxIdleTime); + } + } + + public synchronized void increaseFailedLogins() { + int failedLogins = (Integer) getAttribute(ATTRIBUTE_FAILED_LOGINS, 0); + failedLogins++; + setAttribute(ATTRIBUTE_FAILED_LOGINS, failedLogins); + } + + public int getFailedLogins() { + return (Integer) getAttribute(ATTRIBUTE_FAILED_LOGINS, 0); + } + + public void setLogin(FileSystemView fsview) { + setAttribute(ATTRIBUTE_LOGIN_TIME, new Date()); + setAttribute(ATTRIBUTE_FILE_SYSTEM, fsview); + } + + public void reinitialize() { + logoutUser(); + removeAttribute(ATTRIBUTE_USER); + removeAttribute(ATTRIBUTE_USER_ARGUMENT); + removeAttribute(ATTRIBUTE_LOGIN_TIME); + removeAttribute(ATTRIBUTE_FILE_SYSTEM); + removeAttribute(ATTRIBUTE_RENAME_FROM); + removeAttribute(ATTRIBUTE_FILE_OFFSET); + } + + public void logoutUser() { + ServerFtpStatistics stats = ((ServerFtpStatistics) context + .getFtpStatistics()); + if (stats != null) { + stats.setLogout(this); + LoggerFactory.getLogger(this.getClass()).debug( + "Statistics login decreased due to user logout"); + } else { + LoggerFactory + .getLogger(this.getClass()) + .warn( + "Statistics not available in session, can not decrease login count"); + } + } + + public void setFileOffset(long fileOffset) { + setAttribute(ATTRIBUTE_FILE_OFFSET, fileOffset); + + } + + public void setRenameFrom(FtpFile renFr) { + setAttribute(ATTRIBUTE_RENAME_FROM, renFr); + + } + + public FtpFile getRenameFrom() { + return (FtpFile) getAttribute(ATTRIBUTE_RENAME_FROM); + } + + public long getFileOffset() { + return (Long) getAttribute(ATTRIBUTE_FILE_OFFSET, 0L); + } + + public void setStructure(Structure structure) { + setAttribute(ATTRIBUTE_STRUCTURE, structure); + } + + public void setDataType(DataType dataType) { + setAttribute(ATTRIBUTE_DATA_TYPE, dataType); + + } + + /** + * @see FtpSession#getSessionId() + */ + public UUID getSessionId() { + synchronized (wrappedSession) { + if (!wrappedSession.containsAttribute(ATTRIBUTE_SESSION_ID)) { + wrappedSession.setAttribute(ATTRIBUTE_SESSION_ID, UUID + .randomUUID()); + } + return (UUID) wrappedSession.getAttribute(ATTRIBUTE_SESSION_ID); + } + } + + public FtpIoSession(IoSession wrappedSession, FtpServerContext context) { + this.wrappedSession = wrappedSession; + this.context = context; + } + + public Structure getStructure() { + return (Structure) getAttribute(ATTRIBUTE_STRUCTURE, Structure.FILE); + } + + public DataType getDataType() { + return (DataType) getAttribute(ATTRIBUTE_DATA_TYPE, DataType.ASCII); + } + + public Date getLoginTime() { + return (Date) getAttribute(ATTRIBUTE_LOGIN_TIME); + } + + public Date getLastAccessTime() { + return (Date) getAttribute(ATTRIBUTE_LAST_ACCESS_TIME); + } + + public Certificate[] getClientCertificates() { + if (getFilterChain().contains(SslFilter.class)) { + SslFilter sslFilter = (SslFilter) getFilterChain().get( + SslFilter.class); + + SSLSession sslSession = sslFilter.getSslSession(this); + + if (sslSession != null) { + try { + return sslSession.getPeerCertificates(); + } catch (SSLPeerUnverifiedException e) { + // ignore, certificate will not be available to the session + } + } + + } + + // no certificates available + return null; + + } + + public void updateLastAccessTime() { + setAttribute(ATTRIBUTE_LAST_ACCESS_TIME, new Date()); + + } + + /** + * @see IoSession#getCurrentWriteMessage() + */ + public Object getCurrentWriteMessage() { + return wrappedSession.getCurrentWriteMessage(); + } + + /** + * @see IoSession#getCurrentWriteRequest() + */ + public WriteRequest getCurrentWriteRequest() { + return wrappedSession.getCurrentWriteRequest(); + } + + /** + * @see IoSession#isBothIdle() + */ + public boolean isBothIdle() { + return wrappedSession.isBothIdle(); + } + + /** + * @see IoSession#isReaderIdle() + */ + public boolean isReaderIdle() { + return wrappedSession.isReaderIdle(); + } + + /** + * @see IoSession#isWriterIdle() + */ + public boolean isWriterIdle() { + return wrappedSession.isWriterIdle(); + } + + /** + * Indicates whether the control socket for this session is secure, that is, + * running over SSL/TLS + * + * @return true if the control socket is secured + */ + public boolean isSecure() { + return getFilterChain().contains(SslFilter.class); + } + + /** + * Increase the number of bytes written on the data connection + * + * @param increment + * The number of bytes written + */ + public void increaseWrittenDataBytes(int increment) { + if (wrappedSession instanceof AbstractIoSession) { + ((AbstractIoSession) wrappedSession) + .increaseScheduledWriteBytes(increment); + ((AbstractIoSession) wrappedSession).increaseWrittenBytes( + increment, System.currentTimeMillis()); + } + } + + /** + * Increase the number of bytes read on the data connection + * + * @param increment + * The number of bytes written + */ + public void increaseReadDataBytes(int increment) { + if (wrappedSession instanceof AbstractIoSession) { + ((AbstractIoSession) wrappedSession).increaseReadBytes(increment, + System.currentTimeMillis()); + } + } + + /** + * Returns the last reply that was sent to the client. + * + * @return the last reply that was sent to the client. + */ + public FtpReply getLastReply() { + return lastReply; + } + + /** + * @see IoSession#getWriteRequestQueue() + */ + public WriteRequestQueue getWriteRequestQueue() { + return wrappedSession.getWriteRequestQueue(); + } + + /** + * @see IoSession#isReadSuspended() + */ + public boolean isReadSuspended() { + return wrappedSession.isReadSuspended(); + } + + /** + * @see IoSession#isWriteSuspended() + */ + public boolean isWriteSuspended() { + return wrappedSession.isWriteSuspended(); + } + + /** + * @see IoSession#setCurrentWriteRequest(WriteRequest) + */ + public void setCurrentWriteRequest(WriteRequest currentWriteRequest) { + wrappedSession.setCurrentWriteRequest(currentWriteRequest); + } + + /** + * @see IoSession#updateThroughput(long, boolean) + */ + public void updateThroughput(long currentTime, boolean force) { + wrappedSession.updateThroughput(currentTime, force); + } } diff --git a/core/src/main/java/org/apache/ftpserver/impl/FtpServerContext.java b/core/src/main/java/org/apache/ftpserver/impl/FtpServerContext.java index 8d0349f5..a5eb1459 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/FtpServerContext.java +++ b/core/src/main/java/org/apache/ftpserver/impl/FtpServerContext.java @@ -20,6 +20,7 @@ package org.apache.ftpserver.impl; import java.util.Map; +import java.util.concurrent.ThreadPoolExecutor; import org.apache.ftpserver.ConnectionConfig; import org.apache.ftpserver.command.CommandFactory; @@ -34,8 +35,7 @@ * This is basically org.apache.ftpserver.ftplet.FtpletContext with * added connection manager, message resource functionalities. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FtpServerContext extends FtpletContext { @@ -64,4 +64,10 @@ public interface FtpServerContext extends FtpletContext { * Release all components. */ void dispose(); + + /** + * Returns the thread pool executor for this context. + * @return the thread pool executor for this context. + */ + ThreadPoolExecutor getThreadPoolExecutor(); } 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 25ff65c9..00d6e7a2 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/IODataConnection.java +++ b/core/src/main/java/org/apache/ftpserver/impl/IODataConnection.java @@ -35,20 +35,25 @@ import org.apache.ftpserver.ftplet.FtpSession; import org.apache.ftpserver.usermanager.impl.TransferRateRequest; import org.apache.ftpserver.util.IoUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Internal class, do not use directly. - * + * * An active open data connection, used for transfering data over the data * connection. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class IODataConnection implements DataConnection { + private final Logger LOG = LoggerFactory + .getLogger(IODataConnection.class); + + private static final byte[] EOL = System.getProperty("line.separator").getBytes(); - + private FtpIoSession session; private Socket socket; @@ -112,7 +117,7 @@ private OutputStream getDataOutputStream() throws IOException { /* * (non-Javadoc) - * + * * @seeorg.apache.ftpserver.FtpDataConnection2#transferFromClient(java.io. * OutputStream) */ @@ -136,7 +141,7 @@ public final long transferFromClient(FtpSession session, /* * (non-Javadoc) - * + * * @see * org.apache.ftpserver.FtpDataConnection2#transferToClient(java.io.InputStream * ) @@ -161,7 +166,7 @@ public final long transferToClient(FtpSession session, final InputStream in) /* * (non-Javadoc) - * + * * @see * org.apache.ftpserver.FtpDataConnection2#transferToClient(java.lang.String * ) @@ -259,13 +264,17 @@ private final long transfer(FtpSession session, boolean isWrite, if (b == '\n' && lastByte != '\r') { bos.write('\r'); } - + bos.write(b); } else { if(b == '\n') { // for reads, we should always get \r\n - // so what we do here is to ignore \n bytes + // so what we do here is to ignore \n bytes // and on \r dump the system local line ending + // Some clients won't transform new lines into \r\n so we make sure we don't delete new lines + if (lastByte != '\r'){ + bos.write(EOL); + } } else if(b == '\r') { bos.write(EOL); } else { @@ -284,6 +293,14 @@ private final long transfer(FtpSession session, boolean isWrite, notifyObserver(); } + } catch(IOException e) { + LOG.warn("Exception during data transfer, closing data connection socket", e); + factory.closeDataConnection(); + throw e; + } catch(RuntimeException e) { + LOG.warn("Exception during data transfer, closing data connection socket", e); + factory.closeDataConnection(); + throw e; } finally { if (bos != null) { bos.flush(); 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 e84221bd..323a6e1f 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java +++ b/core/src/main/java/org/apache/ftpserver/impl/IODataConnectionFactory.java @@ -41,12 +41,11 @@ /** * Internal class, do not use directly. - * + * * We can get the FTP data connection using this class. It uses either PORT or * PASV command. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class IODataConnectionFactory implements ServerDataConnectionFactory { @@ -87,6 +86,7 @@ public IODataConnectionFactory(final FtpServerContext serverContext, /** * Close data socket. + * This method must be idempotent as we might call it multiple times during disconnect. */ public synchronized void closeDataConnection() { @@ -108,9 +108,7 @@ public synchronized void closeDataConnection() { LOG.warn("FtpDataConnection.closeDataSocket()", ex); } - FtpServerContext ctx = serverContext; - - if (ctx != null) { + if (session != null) { DataConnectionConfiguration dcc = session.getListener() .getDataConnectionConfiguration(); if (dcc != null) { @@ -156,8 +154,7 @@ private SslConfiguration getSslConfiguration() { } /** - * Initiate a data connection in passive mode (server listening). It returns - * the success flag. + * Initiate a data connection in passive mode (server listening). */ public synchronized InetSocketAddress initPassiveDataConnection() throws DataConnectionException { @@ -198,7 +195,7 @@ public synchronized InetSocketAddress initPassiveDataConnection() "Data connection SSL required but not configured."); } - // this method does not actually create the SSL socket, due to a JVM bug + // this method does not actually create the SSL socket, due to a JVM bug // (https://issues.apache.org/jira/browse/FTPSERVER-241). // Instead, it creates a regular // ServerSocket that will be wrapped as a SSL socket in createDataSocket() @@ -237,7 +234,7 @@ public synchronized InetSocketAddress initPassiveDataConnection() /* * (non-Javadoc) - * + * * @see org.apache.ftpserver.FtpDataConnectionFactory2#getInetAddress() */ public InetAddress getInetAddress() { @@ -246,7 +243,7 @@ public InetAddress getInetAddress() { /* * (non-Javadoc) - * + * * @see org.apache.ftpserver.FtpDataConnectionFactory2#getPort() */ public int getPort() { @@ -255,7 +252,7 @@ public int getPort() { /* * (non-Javadoc) - * + * * @see org.apache.ftpserver.FtpDataConnectionFactory2#openConnection() */ public DataConnection openConnection() throws Exception { @@ -307,10 +304,10 @@ private synchronized Socket createDataSocket() throws Exception { // if no local address has been configured, make sure we use the same as the client connects from if(localAddr == null) { localAddr = ((InetSocketAddress)session.getLocalAddress()).getAddress(); - } + } SocketAddress localSocketAddress = new InetSocketAddress(localAddr, dataConfig.getActiveLocalPort()); - + LOG.debug("Binding active data connection to {}", localSocketAddress); dataSoc.bind(localSocketAddress); @@ -319,12 +316,12 @@ private synchronized Socket createDataSocket() throws Exception { if (secure) { LOG.debug("Opening secure passive data connection"); - // this is where we wrap the unsecured socket as a SSLSocket. This is + // this is where we wrap the unsecured socket as a SSLSocket. This is // due to the JVM bug described in FTPSERVER-241. // get server socket factory SslConfiguration ssl = getSslConfiguration(); - + // we've already checked this, but let's do it again if (ssl == null) { throw new FtpException( @@ -339,7 +336,7 @@ private synchronized Socket createDataSocket() throws Exception { SSLSocket sslSocket = (SSLSocket) ssocketFactory .createSocket(serverSocket, serverSocket .getInetAddress().getHostName(), - serverSocket.getPort(), false); + serverSocket.getPort(), true); sslSocket.setUseClientMode(false); // initialize server socket @@ -360,6 +357,10 @@ private synchronized Socket createDataSocket() throws Exception { dataSoc = servSoc.accept(); } + DataConnectionConfiguration dataCfg = session.getListener() + .getDataConnectionConfiguration(); + + dataSoc.setSoTimeout(dataCfg.getIdleTime() * 1000); LOG.debug("Passive data connection opened"); } } catch (Exception ex) { @@ -398,7 +399,7 @@ private InetAddress resolveAddress(String host) /* * (non-Javadoc) - * + * * @see org.apache.ftpserver.DataConnectionFactory#isSecure() */ public boolean isSecure() { @@ -414,7 +415,7 @@ public void setSecure(final boolean secure) { /* * (non-Javadoc) - * + * * @see org.apache.ftpserver.DataConnectionFactory#isZipMode() */ public boolean isZipMode() { 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 3471c5b0..ec7def47 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/LocalizedFtpReply.java +++ b/core/src/main/java/org/apache/ftpserver/impl/LocalizedFtpReply.java @@ -35,8 +35,7 @@ * * FTP reply translator. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class LocalizedFtpReply extends DefaultFtpReply { @@ -142,7 +141,7 @@ private static String replaceVariables(FtpIoSession session, return str; } - StringBuffer sb = new StringBuffer(128); + StringBuilder sb = new StringBuilder(128); sb.append(str.substring(startIndex, openIndex)); while (true) { String varName = str.substring(openIndex + 1, closeIndex); 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 4f0c7fb8..031b138e 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/PassivePorts.java +++ b/core/src/main/java/org/apache/ftpserver/impl/PassivePorts.java @@ -19,30 +19,44 @@ package org.apache.ftpserver.impl; +import java.io.IOException; +import java.net.ServerSocket; import java.util.ArrayList; -import java.util.Iterator; +import java.util.HashSet; import java.util.List; +import java.util.Random; +import java.util.Set; import java.util.StringTokenizer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Internal class, do not use directly. * * Provides support for parsing a passive ports string as well as keeping track * of reserved passive ports. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class PassivePorts { + private Logger log = LoggerFactory.getLogger(PassivePorts.class); + private static final int MAX_PORT = 65535; - private int[] passivePorts; + private static final Integer MAX_PORT_INTEGER = Integer.valueOf(MAX_PORT); + + private Set freeList; + + private Set usedList; - private boolean[] reservedPorts; + private Random r = new Random(); private String passivePortsString; + private boolean checkIfBound; + /** * Parse a string containing passive ports * @@ -52,27 +66,27 @@ public class PassivePorts { * 123,124,125) or ranges of ports, including open ended ranges * (e.g. 123-125, 30000-, -1023). Combinations for single ports * and ranges is also supported. - * @return An instance of {@link PassivePorts} based on the parsed string + * @return A list of Integer objects, based on the parsed string * @throws IllegalArgumentException * If any of of the ports in the string is invalid (e.g. not an * integer or too large for a port number) */ - private static int[] parse(final String portsString) { - List passivePortsList = new ArrayList(); + private static Set parse(final String portsString) { + Set passivePortsList = new HashSet(); boolean inRange = false; - Integer lastPort = 1; + Integer lastPort = Integer.valueOf(1); StringTokenizer st = new StringTokenizer(portsString, ",;-", true); while (st.hasMoreTokens()) { String token = st.nextToken().trim(); if (",".equals(token) || ";".equals(token)) { if (inRange) { - fillRange(passivePortsList, lastPort, MAX_PORT); + fillRange(passivePortsList, lastPort, MAX_PORT_INTEGER); } // reset state - lastPort = 1; + lastPort = Integer.valueOf(1); inRange = false; } else if ("-".equals(token)) { inRange = true; @@ -81,7 +95,7 @@ private static int[] parse(final String portsString) { } else { Integer port = Integer.valueOf(token); - verifyPort(port.intValue()); + verifyPort(port); if (inRange) { // add all numbers from last int @@ -97,41 +111,26 @@ private static int[] parse(final String portsString) { } if (inRange) { - fillRange(passivePortsList, lastPort, MAX_PORT); - } - - int[] passivePorts = new int[passivePortsList.size()]; - - Iterator iter = passivePortsList.iterator(); - - int counter = 0; - while (iter.hasNext()) { - Integer port = iter.next(); - passivePorts[counter] = port.intValue(); - counter++; + fillRange(passivePortsList, lastPort, MAX_PORT_INTEGER); } - return passivePorts; + return passivePortsList; } /** * Fill a range of ports */ - private static void fillRange(final List passivePortsList, - final Integer beginPort, final Integer endPort) { - for (int i = beginPort.intValue(); i <= endPort.intValue(); i++) { - addPort(passivePortsList, i); + private static void fillRange(final Set passivePortsList, final Integer beginPort, final Integer endPort) { + for (int i = beginPort; i <= endPort; i++) { + addPort(passivePortsList, Integer.valueOf(i)); } } /** * Add a single port if not already in list */ - private static void addPort(final List passivePortsList, - final Integer rangePort) { - if (!passivePortsList.contains(rangePort)) { - passivePortsList.add(rangePort); - } + private static void addPort(final Set passivePortsList, final Integer port) { + passivePortsList.add(port); } /** @@ -139,49 +138,108 @@ private static void addPort(final List passivePortsList, */ private static void verifyPort(final int port) { if (port < 0) { - throw new IllegalArgumentException("Port can not be negative: " - + port); + throw new IllegalArgumentException("Port can not be negative: " + port); } else if (port > MAX_PORT) { throw new IllegalArgumentException("Port too large: " + port); } } - public PassivePorts(final String passivePorts) { - this(parse(passivePorts)); + public PassivePorts(final String passivePorts, boolean checkIfBound) { + this(parse(passivePorts), checkIfBound); this.passivePortsString = passivePorts; } - public PassivePorts(final int[] passivePorts) { - if (passivePorts != null) { - this.passivePorts = passivePorts.clone(); - } else { - this.passivePorts = null; + public PassivePorts(Set passivePorts, boolean checkIfBound) { + if (passivePorts == null) { + throw new NullPointerException("passivePorts can not be null"); + } else if(passivePorts.isEmpty()) { + passivePorts = new HashSet(); + passivePorts.add(0); } - reservedPorts = new boolean[passivePorts.length]; + this.freeList = new HashSet(passivePorts); + this.usedList = new HashSet(passivePorts.size()); + + this.checkIfBound = checkIfBound; } - public int reserveNextPort() { - // search for a free port - for (int i = 0; i < passivePorts.length; i++) { - if (!reservedPorts[i]) { - if (passivePorts[i] != 0) { - reservedPorts[i] = true; + /** + * Checks that the port of not bound by another application + */ + private boolean checkPortUnbound(int port) { + // is this check disabled? + if (!checkIfBound) { + return true; + } + + // if using 0 port, it will always be available + if (port == 0) { + return true; + } + + ServerSocket ss = null; + try { + ss = new ServerSocket(port); + ss.setReuseAddress(true); + return true; + } catch (IOException e) { + // port probably in use, check next + return false; + } finally { + if (ss != null) { + try { + ss.close(); + } catch (IOException e) { + // could not close, check next + return false; } - return passivePorts[i]; + } + } + } + + 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); + + // Loop until we have found a port, or exhausted all available ports + while (freeCopy.size() > 0) { + // Otherwise, pick one at random + int i = r.nextInt(freeCopy.size()); + Integer ret = freeCopy.get(i); + + if (ret == 0) { + // "Any" port should not be removed from our free list, + // nor added to the used list + return 0; + + } else if (checkPortUnbound(ret)) { + // Not used by someone else, so lets reserve it and return it + freeList.remove(ret); + usedList.add(ret); + return ret; + + } else { + freeCopy.remove(ret); + // log port unavailable, but left in pool + log.warn("Passive port in use by another process: " + ret); } } return -1; } - public void releasePort(final int port) { - for (int i = 0; i < passivePorts.length; i++) { - if (passivePorts[i] == port) { - reservedPorts[i] = false; - break; - } + public synchronized void releasePort(final int port) { + if (port == 0) { + // Ignore port 0 being released, + // since its not put on the used list + + } else if (usedList.remove(port)) { + freeList.add(port); + + } else { + // log attempt to release unused port + log.warn("Releasing unreserved passive port: " + port); } } @@ -189,17 +247,17 @@ public void releasePort(final int port) { public String toString() { if (passivePortsString != null) { return passivePortsString; - } else { - StringBuffer sb = new StringBuffer(); + } - for (int port : passivePorts) { - sb.append(port); - sb.append(","); - } - // remove the last , - sb.deleteCharAt(sb.length() - 1); - return sb.toString(); + StringBuilder sb = new StringBuilder(); + + for (Integer port : freeList) { + sb.append(port); + sb.append(","); } + // remove the last , + sb.deleteCharAt(sb.length() - 1); + return sb.toString(); } } \ No newline at end of file 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 265a0f57..cf882531 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/ServerDataConnectionFactory.java +++ b/core/src/main/java/org/apache/ftpserver/impl/ServerDataConnectionFactory.java @@ -28,9 +28,7 @@ /** * Internal class, do not use directly. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public interface ServerDataConnectionFactory extends DataConnectionFactory { @@ -40,7 +38,7 @@ public interface ServerDataConnectionFactory extends DataConnectionFactory { void initActiveDataConnection(InetSocketAddress address); /** - * Initate the passive data connection. + * Initiate the passive data connection. * * @return The {@link InetSocketAddress} on which the data connection if * bound. diff --git a/core/src/main/java/org/apache/ftpserver/impl/ServerFtpStatistics.java b/core/src/main/java/org/apache/ftpserver/impl/ServerFtpStatistics.java index b4e10eb2..a174ed09 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/ServerFtpStatistics.java +++ b/core/src/main/java/org/apache/ftpserver/impl/ServerFtpStatistics.java @@ -28,8 +28,7 @@ * This is same as org.apache.ftpserver.ftplet.FtpStatistics with * added observer and setting values functionalities. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface ServerFtpStatistics extends FtpStatistics { diff --git a/core/src/main/java/org/apache/ftpserver/impl/StatisticsObserver.java b/core/src/main/java/org/apache/ftpserver/impl/StatisticsObserver.java index d8d43789..5ee95936 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/StatisticsObserver.java +++ b/core/src/main/java/org/apache/ftpserver/impl/StatisticsObserver.java @@ -26,8 +26,7 @@ * * FTP statistics observer interface. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface StatisticsObserver { diff --git a/core/src/main/java/org/apache/ftpserver/impl/package.html b/core/src/main/java/org/apache/ftpserver/impl/package.html index fe172dce..42822ef5 100644 --- a/core/src/main/java/org/apache/ftpserver/impl/package.html +++ b/core/src/main/java/org/apache/ftpserver/impl/package.html @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + + + + + Internal classes, do not use directly! - - + + diff --git a/core/src/main/java/org/apache/ftpserver/ipfilter/DefaultIpFilter.java b/core/src/main/java/org/apache/ftpserver/ipfilter/DefaultIpFilter.java new file mode 100644 index 00000000..ef97b51f --- /dev/null +++ b/core/src/main/java/org/apache/ftpserver/ipfilter/DefaultIpFilter.java @@ -0,0 +1,217 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.ipfilter; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Collection; +import java.util.HashSet; +import java.util.concurrent.CopyOnWriteArraySet; + +import org.apache.mina.filter.firewall.Subnet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Default implementation of the IpFilter interface, which uses + * specific IP addresses or ranges of IP addresses that can be blocked or + * allowed. + * + * @author Apache MINA Project + * + */ + +public class DefaultIpFilter extends CopyOnWriteArraySet implements + IpFilter { + + /** + * Logger + */ + Logger LOGGER = LoggerFactory.getLogger(DefaultIpFilter.class); + + /** + * Serial version UID + */ + private static final long serialVersionUID = 4887092372700628783L; + + /** + * filter type + */ + private IpFilterType type = null; + + /** + * Creates a new instance of DefaultIpFilter. + * + * @param type + * the filter type + */ + public DefaultIpFilter(IpFilterType type) { + this(type, new HashSet(0)); + } + + /** + * Creates a new instance of DefaultIpFilter. + * + * @param type + * the filter type + * @param collection + * a collection of Subnets to filter out/in. + */ + public DefaultIpFilter(IpFilterType type, + Collection collection) { + super(collection); + this.type = type; + } + + /** + * Creates a new instance of DefaultIpFilter. + * + * @param type + * the filter type + * @param addresses + * a comma, space, tab, LF separated list of IP addresses/CIDRs. + * @throws UnknownHostException + * propagated + * @throws NumberFormatException + * propagated + */ + public DefaultIpFilter(IpFilterType type, String addresses) + throws NumberFormatException, UnknownHostException { + super(); + this.type = type; + if (addresses != null) { + String[] tokens = addresses.split("[\\s,]+"); + for (String token : tokens) { + if (token.trim().length() > 0) { + add(token); + } + } + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Created DefaultIpFilter of type {} with the subnets {}", type, + this); + } + } + + /** + * Returns the type of this filter. + * + * @return the type of this filter. + */ + public IpFilterType getType() { + return type; + } + + /** + * Sets the type of this filter. + * + * @param type + * the type of this filter. + */ + // TODO should we allow changing the filter type once it is created? I don't + // think we should. + public void setType(IpFilterType type) { + this.type = type; + } + + /** + * Adds the given string representation of InetAddress or CIDR notation to + * this filter. + * + * @param str + * the string representation of InetAddress or CIDR notation + * @return if the given element was added or not. true, if the + * given element was added to the filter; false, if the + * element already exists in the filter. + * @throws NumberFormatException + * propagated + * @throws UnknownHostException + * propagated + */ + public boolean add(String str) throws NumberFormatException, + UnknownHostException { + // This is required so we do not block loopback address if some one adds + // a string with blanks as the InetAddress class assumes loopback + // address on blank string. + if (str.trim().length() < 1) { + throw new IllegalArgumentException("Invalid IP Address or Subnet: " + + str); + } + String[] tokens = str.split("/"); + if (tokens.length == 2) { + return add(new Subnet(InetAddress.getByName(tokens[0]), + Integer.parseInt(tokens[1]))); + } + else { + return add(new Subnet(InetAddress.getByName(tokens[0]), 32)); + } + } + + public boolean accept(InetAddress address) { + switch (type) { + case ALLOW: + for (Subnet subnet : this) { + if (subnet.inSubnet(address)) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Allowing connection from {} because it matches with the whitelist subnet {}", + new Object[] { address, subnet }); + } + return true; + } + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Denying connection from {} because it does not match any of the whitelist subnets", + new Object[] { address }); + } + return false; + case DENY: + if (isEmpty()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Allowing connection from {} because blacklist is empty", + new Object[] { address }); + } + return true; + } + for (Subnet subnet : this) { + if (subnet.inSubnet(address)) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Denying connection from {} because it matches with the blacklist subnet {}", + new Object[] { address, subnet }); + } + return false; + } + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Allowing connection from {} because it does not match any of the blacklist subnets", + new Object[] { address }); + } + return true; + default: + throw new RuntimeException( + "Unknown or unimplemented filter type: " + type); + } + } +} diff --git a/core/src/main/java/org/apache/ftpserver/ipfilter/IpFilter.java b/core/src/main/java/org/apache/ftpserver/ipfilter/IpFilter.java new file mode 100644 index 00000000..88cbbb87 --- /dev/null +++ b/core/src/main/java/org/apache/ftpserver/ipfilter/IpFilter.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.ipfilter; + +import java.net.InetAddress; + +/** + * The interface for filtering connections based on the client's IP address. + * + * @author Apache MINA Project + * + */ + +public interface IpFilter { + + /** + * Tells whether or not the given IP address is accepted by this filter. + * + * @param address + * the IP address to check + * @return true, if the given IP address is accepted by this + * filter; false, otherwise. + */ + public boolean accept(InetAddress address); + +} diff --git a/core/src/main/java/org/apache/ftpserver/ipfilter/IpFilterType.java b/core/src/main/java/org/apache/ftpserver/ipfilter/IpFilterType.java new file mode 100644 index 00000000..569417d8 --- /dev/null +++ b/core/src/main/java/org/apache/ftpserver/ipfilter/IpFilterType.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.ipfilter; + +/** + * Defines various types of IP Filters. + * + * @author Apache MINA Project + * + */ +public enum IpFilterType { + + /** + * filter type that allows a set of predefined IP addresses, also known as a + * white list. + */ + ALLOW, + + /** + * filter type that blocks a set of predefined IP addresses, also known as a + * black list. + */ + DENY; + + /** + * Parses the given string into its equivalent enum. + * + * @param value + * the string value to parse. + * @return the equivalent enum + */ + public static IpFilterType parse(String value) { + for (IpFilterType type : values()) { + if (type.name().equalsIgnoreCase(value)) { + return type; + } + } + throw new IllegalArgumentException("Invalid IpFilterType: " + value); + } + +} diff --git a/core/src/main/java/org/apache/ftpserver/ipfilter/MinaIpFilter.java b/core/src/main/java/org/apache/ftpserver/ipfilter/MinaIpFilter.java new file mode 100644 index 00000000..1276c084 --- /dev/null +++ b/core/src/main/java/org/apache/ftpserver/ipfilter/MinaIpFilter.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.ipfilter; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +import org.apache.mina.core.filterchain.IoFilterAdapter; +import org.apache.mina.core.session.IoSession; + +/** + * An implementation of Mina Filter to filter clients based on the originating + * IP address. + * + * @author Apache MINA Project + * + */ + +public class MinaIpFilter extends IoFilterAdapter { + + /** + * The actual IpFilter used by this filter. + */ + private IpFilter filter = null; + + /** + * Creates a new instance of MinaIpFilter. + * + * @param filter + * the filter + */ + public MinaIpFilter(IpFilter filter) { + this.filter = filter; + } + + @Override + public void sessionCreated(NextFilter nextFilter, IoSession session) { + SocketAddress remoteAddress = session.getRemoteAddress(); + if (remoteAddress instanceof InetSocketAddress) { + InetAddress ipAddress = ((InetSocketAddress) remoteAddress).getAddress(); + // TODO we probably have to check if the InetAddress is a version 4 + // address, or else, the result would probably be unknown. + if (!filter.accept(ipAddress)) { + session.close(true); + } + else { + nextFilter.sessionCreated(session); + } + } + } +} diff --git a/core/src/main/java/org/apache/ftpserver/listener/Listener.java b/core/src/main/java/org/apache/ftpserver/listener/Listener.java index 5a3af405..c078982f 100644 --- a/core/src/main/java/org/apache/ftpserver/listener/Listener.java +++ b/core/src/main/java/org/apache/ftpserver/listener/Listener.java @@ -26,6 +26,7 @@ import org.apache.ftpserver.DataConnectionConfiguration; import org.apache.ftpserver.impl.FtpIoSession; import org.apache.ftpserver.impl.FtpServerContext; +import org.apache.ftpserver.ipfilter.IpFilter; import org.apache.ftpserver.ssl.SslConfiguration; import org.apache.mina.filter.firewall.Subnet; @@ -33,8 +34,7 @@ * Interface for the component responsible for waiting for incoming socket * requests and kicking off {@link FtpIoSession}s * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface Listener { @@ -59,7 +59,7 @@ public interface Listener { /** * Checks if the listener is currently started. * - * @return True if the listener is started + * @return False if the listener is started */ boolean isStopped(); @@ -139,17 +139,36 @@ public interface Listener { int getIdleTimeout(); /** - * Retrieves the {@link InetAddress} for which this listener blocks - * connections - * - * @return The list of {@link InetAddress}es - */ - List getBlockedAddresses(); + * @deprecated Replaced by IpFilter. Retrieves the {@link InetAddress} for + * which this listener blocks connections. + * + * @return The list of {@link InetAddress}es. This method returns a valid + * list if and only if there is an IpFilter set, and, + * if it is an instance of DefaultIpFilter and it is of + * type IpFilterType.DENY. This functionality is + * provided for backward compatibility purpose only. + */ + @Deprecated + List getBlockedAddresses(); /** - * Retrieves the {@link Subnet}s for this listener blocks connections + * @deprecated Replaced by IpFilter. + * Retrieves the {@link Subnet}s for this listener blocks connections. * - * @return The list of {@link Subnet}s + * @return The list of {@link Subnet}s. This method returns a valid + * list if and only if there is an IpFilter set, and, + * if it is an instance of DefaultIpFilter and it is of + * type IpFilterType.DENY. This functionality is + * provided for backward compatibility purpose only. */ List getBlockedSubnets(); + + /** + * Returns the IP filter associated with this listener. May return + * null. + * + * @return the IP filter associated with this listener. May return + * null. + */ + IpFilter getIpFilter(); } \ No newline at end of file diff --git a/core/src/main/java/org/apache/ftpserver/listener/ListenerFactory.java b/core/src/main/java/org/apache/ftpserver/listener/ListenerFactory.java index 5905036b..a2ea5140 100644 --- a/core/src/main/java/org/apache/ftpserver/listener/ListenerFactory.java +++ b/core/src/main/java/org/apache/ftpserver/listener/ListenerFactory.java @@ -26,6 +26,7 @@ import org.apache.ftpserver.DataConnectionConfiguration; import org.apache.ftpserver.DataConnectionConfigurationFactory; import org.apache.ftpserver.FtpServerConfigurationException; +import org.apache.ftpserver.ipfilter.IpFilter; import org.apache.ftpserver.listener.nio.NioListener; import org.apache.ftpserver.ssl.SslConfiguration; import org.apache.mina.filter.firewall.Subnet; @@ -34,8 +35,7 @@ * Factory for listeners. Listeners themselves are immutable and must be * created using this factory. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ListenerFactory { @@ -55,6 +55,11 @@ public class ListenerFactory { private List blockedAddresses; private List blockedSubnets; + + /** + * The IP filter + */ + private IpFilter ipFilter = null; /** * Default constructor @@ -74,8 +79,10 @@ public ListenerFactory(Listener listener) { implicitSsl = listener.isImplicitSsl(); dataConnectionConfig = listener.getDataConnectionConfiguration(); idleTimeout = listener.getIdleTimeout(); + //TODO remove the next two lines if and when we remove the deprecated methods. blockedAddresses = listener.getBlockedAddresses(); blockedSubnets = listener.getBlockedSubnets(); + this.ipFilter = listener.getIpFilter(); } /** @@ -88,9 +95,20 @@ public Listener createListener() { }catch(UnknownHostException e){ throw new FtpServerConfigurationException("Unknown host",e); } - return new NioListener(serverAddress, port, implicitSsl, ssl, - dataConnectionConfig, idleTimeout, blockedAddresses, - blockedSubnets); + //Deal with the old style black list and new IP Filter here. + if(ipFilter != null) { + if(blockedAddresses != null || blockedSubnets != null) { + throw new IllegalStateException("Usage of IPFilter in combination with blockedAddesses/subnets is not supported. "); + } + } + if(blockedAddresses != null || blockedSubnets != null) { + return new NioListener(serverAddress, port, implicitSsl, ssl, + dataConnectionConfig, idleTimeout, blockedAddresses, blockedSubnets); + } + else { + return new NioListener(serverAddress, port, implicitSsl, ssl, + dataConnectionConfig, idleTimeout, ipFilter); + } } /** @@ -214,43 +232,70 @@ public void setIdleTimeout(int idleTimeout) { } /** - * Retrives the {@link InetAddress} for which listeners created by this factory blocks + * @deprecated Replaced by the IpFilter. + * Retrieves the {@link InetAddress} for which listeners created by this factory blocks * connections * * @return The list of {@link InetAddress}es */ + @Deprecated public List getBlockedAddresses() { return blockedAddresses; } /** + * @deprecated Replaced by the IpFilter. * Sets the {@link InetAddress} that listeners created by this factory will block from * connecting * * @param blockedAddresses * The list of {@link InetAddress}es */ + @Deprecated public void setBlockedAddresses(List blockedAddresses) { this.blockedAddresses = blockedAddresses; } /** + * @deprecated Replaced by the IpFilter. * Retrives the {@link Subnet}s for which listeners created by this factory blocks connections * * @return The list of {@link Subnet}s */ + @Deprecated public List getBlockedSubnets() { return blockedSubnets; } /** + * @deprecated Replaced by the IpFilter. * Sets the {@link Subnet}s that listeners created by this factory will block from connecting * @param blockedSubnets * The list of {@link Subnet}s * @param blockedAddresses */ + @Deprecated public void setBlockedSubnets(List blockedSubnets) { this.blockedSubnets = blockedSubnets; } - + + /** + * Returns the currently configured IP filter, if any. + * + * @return the currently configured IP filter, if any. Returns + * null, if no IP filter is configured. + */ + public IpFilter getIpFilter() { + return ipFilter; + } + + /** + * Sets the IP filter to the given filter. + * + * @param ipFilter + * the IP filter. + */ + public void setIpFilter(IpFilter ipFilter) { + this.ipFilter = ipFilter; + } } \ No newline at end of file diff --git a/core/src/main/java/org/apache/ftpserver/listener/nio/AbstractListener.java b/core/src/main/java/org/apache/ftpserver/listener/nio/AbstractListener.java index 27a789db..f00d8125 100644 --- a/core/src/main/java/org/apache/ftpserver/listener/nio/AbstractListener.java +++ b/core/src/main/java/org/apache/ftpserver/listener/nio/AbstractListener.java @@ -20,11 +20,12 @@ package org.apache.ftpserver.listener.nio; import java.net.InetAddress; -import java.util.Collections; import java.util.List; import org.apache.ftpserver.DataConnectionConfiguration; -import org.apache.ftpserver.impl.DefaultDataConnectionConfiguration; +import org.apache.ftpserver.ipfilter.DefaultIpFilter; +import org.apache.ftpserver.ipfilter.IpFilter; +import org.apache.ftpserver.ipfilter.IpFilterType; import org.apache.ftpserver.listener.Listener; import org.apache.ftpserver.listener.ListenerFactory; import org.apache.ftpserver.ssl.SslConfiguration; @@ -35,8 +36,7 @@ * * Common base class for listener implementations * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public abstract class AbstractListener implements Listener { @@ -53,29 +53,62 @@ public abstract class AbstractListener implements Listener { private List blockedAddresses; private List blockedSubnets; + + private IpFilter ipFilter = null; private DataConnectionConfiguration dataConnectionConfig; /** + * @deprecated Use the constructor with IpFilter instead. * Constructor for internal use, do not use directly. Instead use {@link ListenerFactory} */ + @Deprecated public AbstractListener(String serverAddress, int port, boolean implicitSsl, SslConfiguration sslConfiguration, DataConnectionConfiguration dataConnectionConfig, int idleTimeout, List blockedAddresses, List blockedSubnets) { + this(serverAddress, port, implicitSsl, sslConfiguration, + dataConnectionConfig, idleTimeout, createBlackListFilter(blockedAddresses, blockedSubnets)); + this.blockedAddresses = blockedAddresses; + this.blockedSubnets = blockedSubnets; + } + + /** + * Constructor for internal use, do not use directly. Instead use {@link ListenerFactory} + */ + public AbstractListener(String serverAddress, int port, boolean implicitSsl, + SslConfiguration sslConfiguration, DataConnectionConfiguration dataConnectionConfig, + int idleTimeout, IpFilter ipFilter) { this.serverAddress = serverAddress; this.port = port; this.implicitSsl = implicitSsl; this.dataConnectionConfig = dataConnectionConfig; this.ssl = sslConfiguration; this.idleTimeout = idleTimeout; - - if(blockedAddresses != null) { - this.blockedAddresses = Collections.unmodifiableList(blockedAddresses); - } - if(blockedSubnets != null) { - this.blockedSubnets = Collections.unmodifiableList(blockedSubnets); - } - + this.ipFilter = ipFilter; + } + + /** + * Creates an IpFilter that blacklists the given IP addresses and/or Subnets. + * @param blockedAddresses the addresses to block + * @param blockedSubnets the subnets to block + * @return an IpFilter that blacklists the given IP addresses and/or Subnets. + */ + private static IpFilter createBlackListFilter(List blockedAddresses, + List blockedSubnets) { + if(blockedAddresses == null && blockedSubnets == null) { + return null; + } + //Initialize the IP filter with Deny type + DefaultIpFilter ipFilter = new DefaultIpFilter(IpFilterType.DENY); + if(blockedSubnets != null) { + ipFilter.addAll(blockedSubnets); + } + if(blockedAddresses != null) { + for(InetAddress address:blockedAddresses) { + ipFilter.add(new Subnet(address, 32)); + } + } + return ipFilter; } /** @@ -148,4 +181,8 @@ public List getBlockedAddresses() { public List getBlockedSubnets() { return blockedSubnets; } + + public IpFilter getIpFilter() { + return ipFilter; + } } 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 f182d191..5899784f 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 @@ -19,8 +19,6 @@ */ package org.apache.ftpserver.listener.nio; -import java.util.UUID; - import org.apache.ftpserver.ftplet.FtpReply; import org.apache.ftpserver.ftplet.FtpRequest; import org.apache.ftpserver.impl.DefaultFtpRequest; @@ -37,9 +35,7 @@ * * Adapter between MINA handler and the {@link FtpHandler} interface * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class FtpHandlerAdapter implements IoHandler { private FtpServerContext context; 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 ccea6c93..fba9f313 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 @@ -19,9 +19,7 @@ package org.apache.ftpserver.listener.nio; -import org.apache.mina.core.session.IoEventType; import org.apache.mina.core.session.IoSession; -import org.apache.mina.filter.logging.LogLevel; import org.apache.mina.filter.logging.LoggingFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,8 +29,7 @@ * * Specialized @see {@link LoggingFilter} that optionally masks FTP passwords. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class FtpLoggingFilter extends LoggingFilter { @@ -75,9 +72,7 @@ public void messageReceived(NextFilter nextFilter, IoSession session, String logMessage; if (maskPassword) { - request = request.trim().toUpperCase(); - - if (request.startsWith("PASS ")) { + if (request.trim().toUpperCase().startsWith("PASS ")) { logMessage = "PASS *****"; } else { logMessage = request; 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 6bc11f02..4c4b884f 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 @@ -34,8 +34,7 @@ * * A {@link MessageEncoder} that encodes {@link FtpReply}. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class FtpResponseEncoder extends ProtocolEncoderAdapter { private static final CharsetEncoder ENCODER = Charset.forName("UTF-8") 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 ee4e9847..92da13d8 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 @@ -32,8 +32,7 @@ * * Factory for creating decoders and encoders * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class FtpServerProtocolCodecFactory implements ProtocolCodecFactory { private ProtocolDecoder decoder = new TextLineDecoder(Charset 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 0af3f25b..91614039 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 @@ -23,7 +23,6 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.security.GeneralSecurityException; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -37,6 +36,8 @@ import org.apache.ftpserver.impl.FtpHandler; import org.apache.ftpserver.impl.FtpIoSession; import org.apache.ftpserver.impl.FtpServerContext; +import org.apache.ftpserver.ipfilter.IpFilter; +import org.apache.ftpserver.ipfilter.MinaIpFilter; import org.apache.ftpserver.listener.Listener; import org.apache.ftpserver.listener.ListenerFactory; import org.apache.ftpserver.ssl.ClientAuth; @@ -46,7 +47,6 @@ import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.executor.ExecutorFilter; import org.apache.mina.filter.executor.OrderedThreadPoolExecutor; -import org.apache.mina.filter.firewall.BlacklistFilter; import org.apache.mina.filter.firewall.Subnet; import org.apache.mina.filter.logging.MdcInjectionFilter; import org.apache.mina.filter.ssl.SslFilter; @@ -61,8 +61,7 @@ * * The default {@link Listener} implementation. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class NioListener extends AbstractListener { @@ -74,15 +73,15 @@ public class NioListener extends AbstractListener { boolean suspended = false; - private ExecutorService filterExecutor = new OrderedThreadPoolExecutor(); - private FtpHandler handler = new DefaultFtpHandler(); private FtpServerContext context; /** + * @deprecated Use the constructor with IpFilter instead. * Constructor for internal use, do not use directly. Instead use {@link ListenerFactory} */ + @Deprecated public NioListener(String serverAddress, int port, boolean implicitSsl, SslConfiguration sslConfiguration, @@ -90,33 +89,29 @@ public NioListener(String serverAddress, int port, int idleTimeout, List blockedAddresses, List blockedSubnets) { super(serverAddress, port, implicitSsl, sslConfiguration, dataConnectionConfig, idleTimeout, blockedAddresses, blockedSubnets); - - updateBlacklistFilter(); } - private void updateBlacklistFilter() { - if (acceptor != null) { - BlacklistFilter filter = (BlacklistFilter) acceptor - .getFilterChain().get("ipFilter"); - - if (filter != null) { - if (getBlockedAddresses() != null) { - filter.setBlacklist(getBlockedAddresses()); - } else if (getBlockedSubnets() != null) { - filter.setSubnetBlacklist(getBlockedSubnets()); - } else { - // an empty list clears the blocked addresses - filter.setSubnetBlacklist(new ArrayList()); - } - - } - } + /** + * Constructor for internal use, do not use directly. Instead use {@link ListenerFactory} + */ + public NioListener(String serverAddress, int port, + boolean implicitSsl, + SslConfiguration sslConfiguration, + DataConnectionConfiguration dataConnectionConfig, + int idleTimeout, IpFilter ipFilter) { + super(serverAddress, port, implicitSsl, sslConfiguration, dataConnectionConfig, + idleTimeout, ipFilter); } /** * @see Listener#start(FtpServerContext) */ public synchronized void start(FtpServerContext context) { + if(!isStopped()) { + // listener already started, don't allow + throw new IllegalStateException("Listener already started"); + } + try { this.context = context; @@ -142,12 +137,14 @@ public synchronized void start(FtpServerContext context) { acceptor.getFilterChain().addLast("mdcFilter", mdcFilter); - // add and update the blacklist filter - acceptor.getFilterChain().addLast("ipFilter", new BlacklistFilter()); - updateBlacklistFilter(); + IpFilter ipFilter = getIpFilter(); + if(ipFilter != null) { + // add and IP filter to the filter chain. + acceptor.getFilterChain().addLast("ipFilter", new MinaIpFilter(ipFilter)); + } acceptor.getFilterChain().addLast("threadPool", - new ExecutorFilter(filterExecutor)); + new ExecutorFilter(context.getThreadPoolExecutor())); acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new FtpServerProtocolCodecFactory())); acceptor.getFilterChain().addLast("mdcFilter2", mdcFilter); @@ -183,9 +180,9 @@ public synchronized void start(FtpServerContext context) { } catch (IOException e) { throw new FtpServerConfigurationException("Failed to bind to address " + address + ", check configuration", e); } + + updatePort(); - // update the port to the real port bound by the listener - setPort(acceptor.getLocalAddress().getPort()); } catch(RuntimeException e) { // clean up if we fail to start stop(); @@ -193,6 +190,11 @@ public synchronized void start(FtpServerContext context) { throw e; } } + + private void updatePort() { + // update the port to the real port bound by the listener + setPort(acceptor.getLocalAddress().getPort()); + } /** * @see Listener#stop() @@ -204,17 +206,6 @@ public synchronized void stop() { acceptor.dispose(); acceptor = null; } - - if (filterExecutor != null) { - filterExecutor.shutdown(); - try { - filterExecutor.awaitTermination(5000, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - } finally { - // TODO: how to handle? - } - } - context = null; } @@ -242,6 +233,10 @@ public synchronized void resume() { LOG.debug("Resuming listener"); acceptor.bind(address); LOG.debug("Listener resumed"); + + updatePort(); + + suspended = false; } catch (IOException e) { LOG.error("Failed to resume listener", e); } diff --git a/core/src/main/java/org/apache/ftpserver/listener/nio/package.html b/core/src/main/java/org/apache/ftpserver/listener/nio/package.html index 95f1bfd0..324c7294 100644 --- a/core/src/main/java/org/apache/ftpserver/listener/nio/package.html +++ b/core/src/main/java/org/apache/ftpserver/listener/nio/package.html @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + + + + + Internal classes, do not use directly! -

NIO based listener

- - +

NIO based listener

+ + diff --git a/core/src/main/java/org/apache/ftpserver/main/AddUser.java b/core/src/main/java/org/apache/ftpserver/main/AddUser.java index b8be8c95..38f07be2 100644 --- a/core/src/main/java/org/apache/ftpserver/main/AddUser.java +++ b/core/src/main/java/org/apache/ftpserver/main/AddUser.java @@ -39,8 +39,7 @@ /** * Used to add users to the user manager for a particular FtpServer configuration * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class AddUser extends CommandLine { diff --git a/core/src/main/java/org/apache/ftpserver/main/CommandLine.java b/core/src/main/java/org/apache/ftpserver/main/CommandLine.java index 3eb85d71..89a05391 100644 --- a/core/src/main/java/org/apache/ftpserver/main/CommandLine.java +++ b/core/src/main/java/org/apache/ftpserver/main/CommandLine.java @@ -21,15 +21,13 @@ import org.apache.ftpserver.FtpServer; import org.apache.ftpserver.FtpServerFactory; -import org.apache.ftpserver.impl.DefaultFtpServer; import org.springframework.context.support.FileSystemXmlApplicationContext; /** * This class is the starting point for the FtpServer when it is started using * the command line mode. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class CommandLine { 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 acbfe8ad..dfc12ae2 100644 --- a/core/src/main/java/org/apache/ftpserver/main/Daemon.java +++ b/core/src/main/java/org/apache/ftpserver/main/Daemon.java @@ -22,7 +22,6 @@ import org.apache.ftpserver.FtpServer; import org.apache.ftpserver.FtpServerFactory; import org.apache.ftpserver.ftplet.FtpException; -import org.apache.ftpserver.impl.DefaultFtpServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.support.FileSystemXmlApplicationContext; @@ -31,8 +30,7 @@ * Invokes FtpServer as a daemon, running in the background. Used for example * for the Windows service. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class Daemon { diff --git a/core/src/main/java/org/apache/ftpserver/message/MessageResource.java b/core/src/main/java/org/apache/ftpserver/message/MessageResource.java index 477ac400..924fa1a8 100644 --- a/core/src/main/java/org/apache/ftpserver/message/MessageResource.java +++ b/core/src/main/java/org/apache/ftpserver/message/MessageResource.java @@ -21,13 +21,11 @@ import java.util.List; import java.util.Map; -import java.util.Properties; /** * This is message resource interface. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface MessageResource { 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 b1554187..a55c7d3b 100644 --- a/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java +++ b/core/src/main/java/org/apache/ftpserver/message/MessageResourceFactory.java @@ -27,8 +27,7 @@ /** * Factory for creating message resource implementation * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 693604 $, $Date: 2008-09-09 22:55:19 +0200 (Tue, 09 Sep 2008) $ + * @author Apache MINA Project */ public class MessageResourceFactory { diff --git a/core/src/main/java/org/apache/ftpserver/message/impl/DefaultMessageResource.java b/core/src/main/java/org/apache/ftpserver/message/impl/DefaultMessageResource.java index 5a0c1ba0..2b0fffa4 100644 --- a/core/src/main/java/org/apache/ftpserver/message/impl/DefaultMessageResource.java +++ b/core/src/main/java/org/apache/ftpserver/message/impl/DefaultMessageResource.java @@ -23,9 +23,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URL; import java.util.Collections; -import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -50,8 +48,7 @@ * Custom Language Specific Messages -> Default Language Specific Messages -> * Custom Common Messages -> Default Common Messages -> null (not found) * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultMessageResource implements MessageResource { diff --git a/core/src/main/java/org/apache/ftpserver/message/impl/package.html b/core/src/main/java/org/apache/ftpserver/message/impl/package.html index 2e2d7a0e..ce5c9017 100644 --- a/core/src/main/java/org/apache/ftpserver/message/impl/package.html +++ b/core/src/main/java/org/apache/ftpserver/message/impl/package.html @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + + + + + Internal classes, do not use directly! -

Message resource implementation

- - +

Message resource implementation

+ + diff --git a/core/src/main/java/org/apache/ftpserver/ssl/ClientAuth.java b/core/src/main/java/org/apache/ftpserver/ssl/ClientAuth.java index e0a5e1f6..a9335d3e 100644 --- a/core/src/main/java/org/apache/ftpserver/ssl/ClientAuth.java +++ b/core/src/main/java/org/apache/ftpserver/ssl/ClientAuth.java @@ -20,8 +20,7 @@ * Enumeration of possible levels of client authentication during an SSL * session. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public enum ClientAuth { 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 537f72cc..6665c5b9 100644 --- a/core/src/main/java/org/apache/ftpserver/ssl/SslConfiguration.java +++ b/core/src/main/java/org/apache/ftpserver/ssl/SslConfiguration.java @@ -26,8 +26,7 @@ /** * SSL configuration * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface SslConfiguration { 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 8aeb8e13..c36ca3ba 100644 --- a/core/src/main/java/org/apache/ftpserver/ssl/SslConfigurationFactory.java +++ b/core/src/main/java/org/apache/ftpserver/ssl/SslConfigurationFactory.java @@ -39,8 +39,7 @@ * Used to configure the SSL settings for the control channel or the data * channel. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 693604 $, $Date: 2008-09-09 22:55:19 +0200 (Tue, 09 Sep 2008) $ + * @author Apache MINA Project */ public class SslConfigurationFactory { @@ -53,7 +52,7 @@ public class SslConfigurationFactory { private String keystoreType = KeyStore.getDefaultType(); - private String keystoreAlgorithm = "SunX509"; + private String keystoreAlgorithm = KeyManagerFactory.getDefaultAlgorithm(); private File trustStoreFile; @@ -61,7 +60,7 @@ public class SslConfigurationFactory { private String trustStoreType = KeyStore.getDefaultType(); - private String trustStoreAlgorithm = "SunX509"; + private String trustStoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); private String sslProtocol = "TLS"; diff --git a/core/src/main/java/org/apache/ftpserver/ssl/impl/AliasKeyManager.java b/core/src/main/java/org/apache/ftpserver/ssl/impl/AliasKeyManager.java index 6f01dc5c..7ed739d4 100644 --- a/core/src/main/java/org/apache/ftpserver/ssl/impl/AliasKeyManager.java +++ b/core/src/main/java/org/apache/ftpserver/ssl/impl/AliasKeyManager.java @@ -36,8 +36,7 @@ * * Based of org.apache.tomcat.util.net.jsse.JSSEKeyManager. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public final class AliasKeyManager implements X509KeyManager { 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 e0cef336..6e752473 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 @@ -40,8 +40,7 @@ * * Internal class, do not use directly. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultSslConfiguration implements SslConfiguration { diff --git a/core/src/main/java/org/apache/ftpserver/ssl/impl/ExtendedAliasKeyManager.java b/core/src/main/java/org/apache/ftpserver/ssl/impl/ExtendedAliasKeyManager.java index 1dcb3ae8..936e7dd9 100644 --- a/core/src/main/java/org/apache/ftpserver/ssl/impl/ExtendedAliasKeyManager.java +++ b/core/src/main/java/org/apache/ftpserver/ssl/impl/ExtendedAliasKeyManager.java @@ -34,8 +34,7 @@ * * Based of org.apache.tomcat.util.net.jsse.JSSEKeyManager. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public final class ExtendedAliasKeyManager extends X509ExtendedKeyManager { diff --git a/core/src/main/java/org/apache/ftpserver/ssl/impl/package.html b/core/src/main/java/org/apache/ftpserver/ssl/impl/package.html index 309251ec..9db0d2b7 100644 --- a/core/src/main/java/org/apache/ftpserver/ssl/impl/package.html +++ b/core/src/main/java/org/apache/ftpserver/ssl/impl/package.html @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - - + + + + + Internal classes, do not use directly! -

SSL support implementation

- - +

SSL support implementation

+ + diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/AnonymousAuthentication.java b/core/src/main/java/org/apache/ftpserver/usermanager/AnonymousAuthentication.java index 23675800..797f64d5 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/AnonymousAuthentication.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/AnonymousAuthentication.java @@ -25,8 +25,7 @@ /** * Class representing an anonymous authentication attempt * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class AnonymousAuthentication implements Authentication { 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 4f0f1436..e9dc49e7 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/ClearTextPasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/ClearTextPasswordEncryptor.java @@ -26,8 +26,7 @@ * Password encryptor that does no encryption, that is, keps the * password in clear text * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ClearTextPasswordEncryptor implements PasswordEncryptor { 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 e60dd69f..e64823d1 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/DbUserManagerFactory.java @@ -28,8 +28,7 @@ /** * Factory for database backed {@link UserManager} instances. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 689495 $, $Date: 2008-08-27 16:58:52 +0200 (Wed, 27 Aug 2008) $ + * @author Apache MINA Project */ public class DbUserManagerFactory implements UserManagerFactory { 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 80e17a1c..3401eb2f 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/Md5PasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/Md5PasswordEncryptor.java @@ -26,8 +26,7 @@ * Password encryptor that hashes the password using MD5. Please note that this form * of encryption is sensitive to lookup attacks. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class Md5PasswordEncryptor implements PasswordEncryptor { diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/PasswordEncryptor.java b/core/src/main/java/org/apache/ftpserver/usermanager/PasswordEncryptor.java index f083127c..5881aa4e 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/PasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/PasswordEncryptor.java @@ -24,8 +24,7 @@ * Strategy used for encrypting and matching encrypted passwords. * The purpose is to make the password encryption possible to extend. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface PasswordEncryptor { 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 948a24d5..b3ddc7e6 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/PropertiesUserManagerFactory.java @@ -28,8 +28,7 @@ /** * Factory for the properties file based UserManager implementation. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 689495 $, $Date: 2008-08-27 16:58:52 +0200 (Wed, 27 Aug 2008) $ + * @author Apache MINA Project */ public class PropertiesUserManagerFactory implements UserManagerFactory { 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 197647c3..1cd1bf5b 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/SaltedPasswordEncryptor.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/SaltedPasswordEncryptor.java @@ -31,8 +31,7 @@ * The algorithm is based on the principles described in * http://www.jasypt.org/howtoencryptuserpasswords.html * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SaltedPasswordEncryptor implements PasswordEncryptor { diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/UserFactory.java b/core/src/main/java/org/apache/ftpserver/usermanager/UserFactory.java new file mode 100644 index 00000000..89b1a3f5 --- /dev/null +++ b/core/src/main/java/org/apache/ftpserver/usermanager/UserFactory.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.usermanager; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.ftpserver.ftplet.Authority; +import org.apache.ftpserver.ftplet.User; +import org.apache.ftpserver.usermanager.impl.BaseUser; + +/** + * Factory for {@link User} instances. + * + * @author Apache MINA Project + */ +public class UserFactory { + + private String name = null; + + private String password = null; + + private int maxIdleTimeSec = 0; // no limit + + private String homeDir = null; + + private boolean isEnabled = true; + + private List authorities = new ArrayList(); + + /** + * Creates a user based on the configuration set on the factory + * @return The created user + */ + public User createUser() { + BaseUser user = new BaseUser(); + user.setName(name); + user.setPassword(password); + user.setHomeDirectory(homeDir); + user.setEnabled(isEnabled); + user.setAuthorities(authorities); + user.setMaxIdleTime(maxIdleTimeSec); + + return user; + } + + /** + * Get the user name for users created by this factory + * @return The user name + */ + public String getName() { + return name; + } + + /** + * Set the user name for users created by this factory + * @param name The user name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Get the password for users created by this factory + * @return The password + */ + public String getPassword() { + return password; + } + + /** + * Set the user name for users created by this factory + * @param password The password + */ + public void setPassword(String password) { + this.password = password; + } + + /** + * Get the max idle time for users created by this factory + * @return The max idle time in seconds + */ + public int getMaxIdleTime() { + return maxIdleTimeSec; + } + + /** + * Set the user name for users created by this factory + * @param maxIdleTimeSec The max idle time in seconds + */ + public void setMaxIdleTime(int maxIdleTimeSec) { + this.maxIdleTimeSec = maxIdleTimeSec; + } + + /** + * Get the home directory for users created by this factory + * @return The home directory path + */ + public String getHomeDirectory() { + return homeDir; + } + + /** + * Set the user name for users created by this factory + * @param homeDir The home directory path + */ + public void setHomeDirectory(String homeDir) { + this.homeDir = 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() { + return 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) { + this.isEnabled = isEnabled; + } + + /** + * Get the authorities for users created by this factory + * @return The authorities + */ + public List getAuthorities() { + return authorities; + } + + /** + * Set the authorities for users created by this factory + * @param authorities The authorities + */ + public void setAuthorities(List authorities) { + this.authorities = authorities; + } +} \ No newline at end of file diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/UserManagerFactory.java b/core/src/main/java/org/apache/ftpserver/usermanager/UserManagerFactory.java index 85c49a6c..5c3686c9 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/UserManagerFactory.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/UserManagerFactory.java @@ -24,8 +24,7 @@ /** * Interface for user manager factories * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev: 689495 $, $Date: 2008-08-27 16:58:52 +0200 (Wed, 27 Aug 2008) $ + * @author Apache MINA Project */ public interface UserManagerFactory { diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/UsernamePasswordAuthentication.java b/core/src/main/java/org/apache/ftpserver/usermanager/UsernamePasswordAuthentication.java index 44176876..546b6c57 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/UsernamePasswordAuthentication.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/UsernamePasswordAuthentication.java @@ -26,8 +26,7 @@ * Class representing a normal authentication attempt using username and * password * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class UsernamePasswordAuthentication implements Authentication { 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 95b172b4..ed02b01c 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 @@ -29,8 +29,7 @@ * * Abstract common base type for {@link UserManager} implementations * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public abstract class AbstractUserManager implements UserManager { diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/BaseUser.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/BaseUser.java index f08d6ab0..c303a300 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/BaseUser.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/BaseUser.java @@ -42,8 +42,7 @@ *
  • downloadrate
  • * * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class BaseUser implements User { 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 409bcfb2..ab9ff6f7 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 @@ -27,8 +27,7 @@ * * The max upload rate permission * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ConcurrentLoginPermission implements Authority { 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 349f88c5..c2573431 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 @@ -26,8 +26,7 @@ * * Class representing a request to log in a number of concurrent times * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ConcurrentLoginRequest implements AuthorizationRequest { 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 6c6ff1a8..56bb58a9 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 @@ -52,8 +52,7 @@ * All the user attributes are replaced during run-time. So we can use your * database schema. Then you need to modify the SQLs in the configuration file. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DbUserManager extends AbstractUserManager { @@ -93,15 +92,18 @@ public DbUserManager(DataSource dataSource, String selectAllStmt, this.authenticateStmt = authenticateStmt; this.isAdminStmt = isAdminStmt; - try { - // test the connection - createConnection(); - - LOG.info("Database connection opened."); - } catch (SQLException ex) { - LOG.error("Failed to open connection to user database", ex); - throw new FtpServerConfigurationException( - "Failed to open connection to user database", ex); + Connection con = null; + try { + // test the connection + con = createConnection(); + + LOG.info("Database connection opened."); + } catch (SQLException ex) { + LOG.error("Failed to open connection to user database", ex); + throw new FtpServerConfigurationException( + "Failed to open connection to user database", ex); + } finally{ + closeQuitely(con); } } @@ -683,7 +685,7 @@ private String escapeString(String input) { return input; } - StringBuffer valBuf = new StringBuffer(input); + StringBuilder valBuf = new StringBuilder(input); for (int i = 0; i < valBuf.length(); i++) { char ch = valBuf.charAt(i); if (ch == '\'' || ch == '\\' || ch == '$' || ch == '^' || ch == '[' diff --git a/core/src/main/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManager.java b/core/src/main/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManager.java index ad9ec752..8faf5f3d 100644 --- a/core/src/main/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManager.java +++ b/core/src/main/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManager.java @@ -112,8 +112,7 @@ * ftpserver.user.admin.uploadrate=0 * ftpserver.user.admin.downloadrate=0 * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class PropertiesUserManager extends AbstractUserManager { 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 e3d0700b..066901cc 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 @@ -27,8 +27,7 @@ * * The max upload rate permission * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class TransferRatePermission implements Authority { 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 27fb04b8..99d920dc 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 @@ -26,8 +26,7 @@ * * Request for getting the maximum allowed transfer rates for a user * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class TransferRateRequest implements AuthorizationRequest { 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 57b839e8..d978e19c 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 @@ -27,8 +27,7 @@ * * User metadata used during authentication * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class UserMetadata { 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 68ea0ff2..16b62dce 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 @@ -27,8 +27,7 @@ * * Class representing a write permission * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class WritePermission implements Authority { 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 aac95e13..32a828b4 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 @@ -26,8 +26,7 @@ * * Class representing a write request * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class WriteRequest implements AuthorizationRequest { diff --git a/core/src/main/java/org/apache/ftpserver/util/BaseProperties.java b/core/src/main/java/org/apache/ftpserver/util/BaseProperties.java index 3bd73279..0761c891 100644 --- a/core/src/main/java/org/apache/ftpserver/util/BaseProperties.java +++ b/core/src/main/java/org/apache/ftpserver/util/BaseProperties.java @@ -37,8 +37,7 @@ * This class encapsulates java.util.Properties to add java * primitives and some other java classes. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class BaseProperties extends Properties { 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 10f999c0..541ca39b 100644 --- a/core/src/main/java/org/apache/ftpserver/util/ClassUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/ClassUtils.java @@ -22,9 +22,7 @@ /** * Internal class, do not use directly. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class ClassUtils { 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 94a94923..79d5e687 100644 --- a/core/src/main/java/org/apache/ftpserver/util/DateUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/DateUtils.java @@ -32,11 +32,12 @@ * * Standard date related utility methods. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DateUtils { + private static final TimeZone TIME_ZONE_UTC = TimeZone.getTimeZone("UTC"); + private final static String[] MONTHS = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; @@ -64,7 +65,7 @@ public final static String getUnixDate(long millis) { return "------------"; } - StringBuffer sb = new StringBuffer(16); + StringBuilder sb = new StringBuilder(16); Calendar cal = new GregorianCalendar(); cal.setTimeInMillis(millis); @@ -112,7 +113,7 @@ public final static String getUnixDate(long millis) { * Get ISO 8601 timestamp. */ public final static String getISO8601Date(long millis) { - StringBuffer sb = new StringBuffer(19); + StringBuilder sb = new StringBuilder(19); Calendar cal = new GregorianCalendar(); cal.setTimeInMillis(millis); @@ -166,9 +167,12 @@ public final static String getISO8601Date(long millis) { * Get FTP date. */ public final static String getFtpDate(long millis) { - StringBuffer sb = new StringBuffer(20); - Calendar cal = new GregorianCalendar(); + StringBuilder sb = new StringBuilder(20); + + // MLST should use UTC + Calendar cal = new GregorianCalendar(TIME_ZONE_UTC); cal.setTimeInMillis(millis); + // year sb.append(cal.get(Calendar.YEAR)); 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 228d0de7..77077262 100644 --- a/core/src/main/java/org/apache/ftpserver/util/EncryptUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/EncryptUtils.java @@ -27,8 +27,7 @@ * * String encryption utility methods. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class EncryptUtils { diff --git a/core/src/main/java/org/apache/ftpserver/util/FileRegularFilter.java b/core/src/main/java/org/apache/ftpserver/util/FileRegularFilter.java index 7c454a4d..3a572d26 100644 --- a/core/src/main/java/org/apache/ftpserver/util/FileRegularFilter.java +++ b/core/src/main/java/org/apache/ftpserver/util/FileRegularFilter.java @@ -27,8 +27,7 @@ * * This is regular expression filename filter. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class FileRegularFilter implements FilenameFilter { 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 2d74681a..6e2e5c19 100644 --- a/core/src/main/java/org/apache/ftpserver/util/IllegalInetAddressException.java +++ b/core/src/main/java/org/apache/ftpserver/util/IllegalInetAddressException.java @@ -25,8 +25,7 @@ * Thrown if the provided string representation does not match a valid IP * address * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class IllegalInetAddressException extends IllegalArgumentException { 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 f7036f99..1f0f4530 100644 --- a/core/src/main/java/org/apache/ftpserver/util/IllegalPortException.java +++ b/core/src/main/java/org/apache/ftpserver/util/IllegalPortException.java @@ -24,8 +24,7 @@ * * Thrown if the provided string representation does not match a valid IP port * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class IllegalPortException extends IllegalArgumentException { 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 41bb07f7..75e47ad1 100644 --- a/core/src/main/java/org/apache/ftpserver/util/IoUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/IoUtils.java @@ -44,8 +44,7 @@ * commons-io library we prefer to our own implementation to, using a external * library might cause additional constraints on users embedding FtpServer. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class IoUtils { 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 7bae9fd5..952c8fa9 100644 --- a/core/src/main/java/org/apache/ftpserver/util/OS.java +++ b/core/src/main/java/org/apache/ftpserver/util/OS.java @@ -1,18 +1,20 @@ -/* - * Copyright 2005 The Apache Software Foundation +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ package org.apache.ftpserver.util; @@ -24,8 +26,7 @@ * * Condition that tests the OS type. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public final class OS { private static final String FAMILY_OS_400 = "os/400"; diff --git a/core/src/main/java/org/apache/ftpserver/util/RegularExpr.java b/core/src/main/java/org/apache/ftpserver/util/RegularExpr.java index 60f75f89..22169bde 100644 --- a/core/src/main/java/org/apache/ftpserver/util/RegularExpr.java +++ b/core/src/main/java/org/apache/ftpserver/util/RegularExpr.java @@ -25,8 +25,7 @@ * This is a simplified regular character mattching class. Supports *?^[]- * pattern characters. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class RegularExpr { 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 c2e977b7..5b1c68a5 100644 --- a/core/src/main/java/org/apache/ftpserver/util/SocketAddressEncoder.java +++ b/core/src/main/java/org/apache/ftpserver/util/SocketAddressEncoder.java @@ -30,8 +30,7 @@ * Encodes and decodes socket addresses (IP and port) from and to the format * used with for example the PORT and PASV command * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class SocketAddressEncoder { @@ -54,7 +53,7 @@ public static InetSocketAddress decode(String str) throw new IllegalInetAddressException("Illegal amount of tokens"); } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); try { sb.append(convertAndValidateNumber(st.nextToken())); sb.append('.'); 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 55e5465b..a8635997 100644 --- a/core/src/main/java/org/apache/ftpserver/util/StringUtils.java +++ b/core/src/main/java/org/apache/ftpserver/util/StringUtils.java @@ -26,8 +26,7 @@ * * String utility methods. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class StringUtils { @@ -36,7 +35,7 @@ public class StringUtils { */ public final static String replaceString(String source, String oldStr, String newStr) { - StringBuffer sb = new StringBuffer(source.length()); + StringBuilder sb = new StringBuilder(source.length()); int sind = 0; int cind = 0; while ((cind = source.indexOf(oldStr, sind)) != -1) { @@ -63,7 +62,7 @@ public final static String replaceString(String source, Object[] args) { return source; } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(source.substring(startIndex, openIndex)); while (true) { String intStr = source.substring(openIndex + 1, closeIndex); @@ -103,7 +102,7 @@ public final static String replaceString(String source, return source; } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(source.substring(startIndex, openIndex)); while (true) { String key = source.substring(openIndex + 1, closeIndex); @@ -141,7 +140,7 @@ public final static String replaceString(String source, public final static String formatHtml(String source, boolean bReplaceNl, boolean bReplaceTag, boolean bReplaceQuote) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); int len = source.length(); for (int i = 0; i < len; i++) { char c = source.charAt(i); @@ -205,7 +204,7 @@ public final static String pad(String src, char padChar, boolean rightPad, } int padLength = totalLength - srcLength; - StringBuffer sb = new StringBuffer(padLength); + StringBuilder sb = new StringBuilder(padLength); for (int i = 0; i < padLength; ++i) { sb.append(padChar); } @@ -221,11 +220,11 @@ public final static String pad(String src, char padChar, boolean rightPad, * Get hex string from byte array */ public final static String toHexString(byte[] res) { - StringBuffer sb = new StringBuffer(res.length << 1); + StringBuilder sb = new StringBuilder(res.length << 1); for (int i = 0; i < res.length; i++) { String digit = Integer.toHexString(0xFF & res[i]); if (digit.length() == 1) { - digit = '0' + digit; + sb.append('0'); } sb.append(digit); } diff --git a/core/src/main/resources/org/apache/ftpserver/config/spring/ftpserver-1.0.xsd b/core/src/main/resources/org/apache/ftpserver/config/spring/ftpserver-1.0.xsd index 872c7770..ca735529 100644 --- a/core/src/main/resources/org/apache/ftpserver/config/spring/ftpserver-1.0.xsd +++ b/core/src/main/resources/org/apache/ftpserver/config/spring/ftpserver-1.0.xsd @@ -52,6 +52,7 @@ + @@ -99,6 +100,24 @@ + + + + + + + + + + + + + + + + + + @@ -129,6 +148,7 @@ + diff --git a/core/src/main/resources/org/apache/ftpserver/message/FtpStatus.properties b/core/src/main/resources/org/apache/ftpserver/message/FtpStatus.properties index 53944a2e..5f497f63 100644 --- a/core/src/main/resources/org/apache/ftpserver/message/FtpStatus.properties +++ b/core/src/main/resources/org/apache/ftpserver/message/FtpStatus.properties @@ -57,11 +57,10 @@ 450.DELE=Can't delete file {output.msg}. 501.EPRT=Syntax error in parameters or arguments. -510.EPRT=Syntax error in parameters. -510.EPRT.disabled=EPRT is disabled. -510.EPRT.mismatch=EPRT IP is not same as {client.ip}. -553.EPRT.host=Host unknown. -552.EPRT.invalid=Not a valid port number. +501.EPRT.disabled=EPRT is disabled. +501.EPRT.mismatch=EPRT IP is not same as {client.ip}. +501.EPRT.host=Host unknown. +501.EPRT.invalid=Not a valid port number. 200.EPRT=Command EPRT okay. 425.EPSV=Can't open passive connection. @@ -167,11 +166,10 @@ 200.PBSZ=Command PBSZ okay. 501.PORT=Syntax error in parameters or arguments. -510.PORT=Syntax error in parameters. -510.PORT.disabled=PORT is disabled. -510.PORT.mismatch=PORT IP is not same as {client.ip}. -553.PORT.host=Host unknown. -552.PORT.invalid=Not a valid port number. +501.PORT.disabled=PORT is disabled. +501.PORT.mismatch=PORT IP is not same as {client.ip}. +501.PORT.host=Host unknown. +501.PORT.invalid=Not a valid port number. 200.PORT=Command PORT okay. 501.PROT=Syntax error in parameters or arguments. @@ -234,6 +232,9 @@ 213.SIZE={output.msg} 211.STAT=Apache FtpServer\nConnected to {server.ip}\nConnected from {client.ip}\nLogged in as {client.login.name}\nEnd of status. +212.STAT=\n{output.msg}End of status. +213.STAT=\n{output.msg}End of status. +450.STAT=Non-existing file 501.STOR=Syntax error in parameters or arguments. 550.STOR.invalid={output.msg}\: Invalid path. diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/ActiveModeReplyTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/ActiveModeReplyTest.java index 876ac761..0fae2549 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/ActiveModeReplyTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/ActiveModeReplyTest.java @@ -1,79 +1,78 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.ftpserver.clienttests; - -import java.io.File; -import java.io.IOException; - -import org.apache.commons.net.ftp.FTPClient; -import org.apache.commons.net.ftp.FTPClientConfig; -import org.apache.ftpserver.test.TestUtil; - -/** -* -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* -*/ -public class ActiveModeReplyTest extends ClientTestTemplate { - private static final File TEST_TMP_DIR = new File("test-tmp"); - - private static final File TEST_FILE = new File(ROOT_DIR, "test.txt"); - - private static final File TEST_FILE1 = new File(TEST_TMP_DIR, "test1.txt"); - - private static byte[] testData; - - protected void setUp() throws Exception { - super.setUp(); - - TEST_FILE1.createNewFile(); - assertTrue(TEST_FILE1.exists()); - - testData = ("TESTDATA").getBytes("UTF-8"); - TestUtil.writeDataToFile(TEST_FILE, testData); - assertTrue(TEST_FILE.exists()); - - FTPClientConfig config = new FTPClientConfig("UNIX"); - client.configure(config); - - client.login(ADMIN_USERNAME, ADMIN_PASSWORD); - } - - public void testStoreInActiveModeIfNotAllowed() throws Exception { - assertTrue(client.getDataConnectionMode() == FTPClient.ACTIVE_LOCAL_DATA_CONNECTION_MODE); - - sendCommand("APPE " + TEST_FILE1.getAbsolutePath()); - sendCommand("LIST"); - sendCommand("MLSD"); - sendCommand("NLST"); - sendCommand("RETR " + TEST_FILE.getName()); - sendCommand("STOR " + TEST_FILE1.getAbsolutePath()); - sendCommand("STOU"); - } - - private void sendCommand(final String command) throws IOException { - final int returnCode = client.sendCommand(command); - assertEquals(503, returnCode); - assertEquals("503 PORT or PASV must be issued first", client - .getReplyString().trim()); - } - -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.clienttests; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.net.ftp.FTPClient; +import org.apache.commons.net.ftp.FTPClientConfig; +import org.apache.ftpserver.test.TestUtil; + +/** +* +* @author Apache MINA Project +* +*/ +public class ActiveModeReplyTest extends ClientTestTemplate { + private static final File TEST_TMP_DIR = new File("test-tmp"); + + private static final File TEST_FILE = new File(ROOT_DIR, "test.txt"); + + private static final File TEST_FILE1 = new File(TEST_TMP_DIR, "test1.txt"); + + private static byte[] testData; + + protected void setUp() throws Exception { + super.setUp(); + + TEST_FILE1.createNewFile(); + assertTrue(TEST_FILE1.exists()); + + testData = ("TESTDATA").getBytes("UTF-8"); + TestUtil.writeDataToFile(TEST_FILE, testData); + assertTrue(TEST_FILE.exists()); + + FTPClientConfig config = new FTPClientConfig("UNIX"); + client.configure(config); + + client.login(ADMIN_USERNAME, ADMIN_PASSWORD); + } + + public void testStoreInActiveModeIfNotAllowed() throws Exception { + assertTrue(client.getDataConnectionMode() == FTPClient.ACTIVE_LOCAL_DATA_CONNECTION_MODE); + + sendCommand("APPE " + TEST_FILE1.getAbsolutePath()); + sendCommand("LIST"); + sendCommand("MLSD"); + sendCommand("NLST"); + sendCommand("RETR " + TEST_FILE.getName()); + sendCommand("STOR " + TEST_FILE1.getAbsolutePath()); + sendCommand("STOU"); + } + + private void sendCommand(final String command) throws IOException { + final int returnCode = client.sendCommand(command); + assertEquals(503, returnCode); + assertEquals("503 PORT or PASV must be issued first", client + .getReplyString().trim()); + } + +} diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/BindExceptionParallelTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/BindExceptionParallelTest.java deleted file mode 100644 index 62ae3391..00000000 --- a/core/src/test/java/org/apache/ftpserver/clienttests/BindExceptionParallelTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.ftpserver.clienttests; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.net.ftp.FTPClient; -import org.apache.ftpserver.ConnectionConfigFactory; -import org.apache.ftpserver.DataConnectionConfigurationFactory; -import org.apache.ftpserver.test.TestUtil; - -/** -* -* From FTPSERVER-250 -* -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* -*/ -public class BindExceptionParallelTest extends ClientTestTemplate { - private static final int NUMBER_OF_CLIENTS = 2; - private List clients; - - private int port = TestUtil.findFreePort(2020); - - public BindExceptionParallelTest() throws IOException { - // default cstr - } - - @Override - protected FTPClient createFTPClient() throws Exception { - FTPClient c = super.createFTPClient(); - c.setDataTimeout(1000); - return c; - } - - @Override - protected void connectClient() throws Exception { - clients = new ArrayList(); - - for (int i = 0; i < NUMBER_OF_CLIENTS; i++) { - super.connectClient(); - client.login(ADMIN_USERNAME, ADMIN_PASSWORD); - clients.add(client); - } - - client = null; - } - - @Override - protected ConnectionConfigFactory createConnectionConfigFactory() { - ConnectionConfigFactory factory = super.createConnectionConfigFactory(); - factory.setMaxLogins(0); - return factory; - } - - @Override - protected DataConnectionConfigurationFactory createDataConnectionConfigurationFactory() { - DataConnectionConfigurationFactory factory = super.createDataConnectionConfigurationFactory(); - factory.setActiveLocalPort(port); - factory.setActiveLocalAddress("localhost"); - return factory; - } - - public void testParallelExecution() throws Exception { - final BindExceptionTestFailStatus testFailStatus = new BindExceptionTestFailStatus(); - for (int i = 0; i < NUMBER_OF_CLIENTS; i++) { - final int c = i; - new Thread("client" + (i + 1)) { - @Override - public void run() { - try { - System.out.println(" -- " + getName() + " before command"); - System.out.println("--> " + getName() + " " + Arrays.asList(clients.get(c).listFiles())); - System.out.println(" -- " + getName() + " command ok"); - } catch (IOException e) { - System.err.println(" xx " + getName() + " command ko"); - e.printStackTrace(); - testFailStatus.failed = true; - } - } - }.start(); - } - - // make time to threads to finish its work - Thread.sleep(3000); - - assertFalse(testFailStatus.failed); - } - - @Override - protected void tearDown() throws Exception { - for (int i = 1; i < NUMBER_OF_CLIENTS; i++) - if (isConnectClient()) { - try { - clients.get(i).quit(); - } catch (Exception e) { - // ignore - } - } - client = clients.get(0); - super.tearDown(); - } - - private static final class BindExceptionTestFailStatus { - public boolean failed = false; - } -} \ No newline at end of file diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/BindExceptionSerialTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/BindExceptionSerialTest.java index 3a487c90..29ad5667 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/BindExceptionSerialTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/BindExceptionSerialTest.java @@ -19,19 +19,17 @@ package org.apache.ftpserver.clienttests; -import org.apache.commons.net.ftp.FTPClient; -import org.apache.ftpserver.DataConnectionConfigurationFactory; - import java.io.IOException; import java.util.Arrays; +import org.apache.commons.net.ftp.FTPClient; +import org.apache.ftpserver.DataConnectionConfigurationFactory; + /** * * From FTPSERVER-250 * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class BindExceptionSerialTest extends ClientTestTemplate { @Override diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/CdCaseInsensitiveTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/CdCaseInsensitiveTest.java index 888a4926..b51dc7c0 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/CdCaseInsensitiveTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/CdCaseInsensitiveTest.java @@ -24,9 +24,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class CdCaseInsensitiveTest extends CdTest { protected FtpServerFactory createServer() throws Exception { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/CdTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/CdTest.java index 6ca8748b..86dd6b50 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/CdTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/CdTest.java @@ -23,9 +23,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class CdTest extends ClientTestTemplate { protected static final File TEST_DIR1 = new File(ROOT_DIR, "dir1"); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/ClientTestTemplate.java b/core/src/test/java/org/apache/ftpserver/clienttests/ClientTestTemplate.java index 739e13d5..23c9ea14 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/ClientTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/ClientTestTemplate.java @@ -43,9 +43,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public abstract class ClientTestTemplate extends TestCase { @@ -68,8 +66,6 @@ public abstract class ClientTestTemplate extends TestCase { protected DefaultFtpServer server; - protected int port = -1; - protected FTPClient client; private static final File USERS_FILE = new File(TestUtil.getBaseDir(), @@ -90,7 +86,7 @@ protected FtpServerFactory createServer() throws Exception { ListenerFactory listenerFactory = new ListenerFactory(); - listenerFactory.setPort(port); + listenerFactory.setPort(0); listenerFactory .setDataConnectionConfiguration(createDataConnectionConfigurationFactory() @@ -144,8 +140,6 @@ protected void initDirs() throws IOException { * @throws Exception */ protected void initServer() throws IOException, Exception { - initPort(); - // cast to internal class to get access to getters server = (DefaultFtpServer) createServer().createServer(); @@ -154,12 +148,18 @@ protected void initServer() throws IOException, Exception { } } + protected int getListenerPort() { + return server.getListener("default").getPort(); + } + protected boolean isStartServer() { return true; } protected FTPClient createFTPClient() throws Exception { - return new FTPClient(); + FTPClient client = new FTPClient(); + client.setDefaultTimeout(10000); + return client; } /** @@ -186,11 +186,11 @@ public void protocolReplyReceived(ProtocolCommandEvent event) { protected void doConnect() throws Exception { try { - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); } catch (FTPConnectionClosedException e) { // try again Thread.sleep(200); - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); } } @@ -198,19 +198,6 @@ protected boolean isConnectClient() { return true; } - /** - * Attempts to find a free port or fallback to a default - * - * @throws IOException - * - * @throws IOException - */ - private void initPort() throws IOException { - if (port == -1) { - port = TestUtil.findFreePort(); - } - } - protected void cleanTmpDirs() throws IOException { if (TEST_TMP_DIR.exists()) { IoUtils.delete(TEST_TMP_DIR); @@ -237,7 +224,12 @@ protected void tearDown() throws Exception { } if (server != null) { - server.stop(); + try { + server.stop(); + } catch(NullPointerException e) { + // a bug in the IBM JVM might cause Thread.interrupt() to throw an NPE + // see http://www-01.ibm.com/support/docview.wss?uid=swg1IZ52037&wv=1 + } } cleanTmpDirs(); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/ConcatedCommandsTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/ConcatedCommandsTest.java index 661a5260..34f250ed 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/ConcatedCommandsTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/ConcatedCommandsTest.java @@ -24,9 +24,7 @@ /** * Tests that commands sent simultaniously are handled correctly. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class ConcatedCommandsTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/ConnectPickPortTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/ConnectPickPortTest.java index 4752c74a..db53557f 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/ConnectPickPortTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/ConnectPickPortTest.java @@ -20,15 +20,12 @@ package org.apache.ftpserver.clienttests; import org.apache.ftpserver.FtpServerFactory; -import org.apache.ftpserver.impl.DefaultFtpServer; import org.apache.ftpserver.listener.ListenerFactory; import org.apache.ftpserver.listener.nio.NioListener; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ConnectPickPortTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/ConnectTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/ConnectTest.java index 109ec858..6a8c1335 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/ConnectTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/ConnectTest.java @@ -23,9 +23,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ConnectTest extends ClientTestTemplate { @@ -40,13 +38,13 @@ protected boolean isStartServer() { } public void testPort() throws Exception { - assertEquals(port, ((NioListener) server.getServerContext() + assertEquals(0, ((NioListener) server .getListener("default")).getPort()); server.start(); - assertEquals(port, ((NioListener) server.getServerContext() - .getListener("default")).getPort()); + assertTrue(((NioListener) server + .getListener("default")).getPort() > 0); } } diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/CustomMaxLoginTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/CustomMaxLoginTest.java index cdcdf85e..9774ee3c 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/CustomMaxLoginTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/CustomMaxLoginTest.java @@ -27,9 +27,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class CustomMaxLoginTest extends ClientTestTemplate { private static final String UNKNOWN_USERNAME = "foo"; diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/DataTransferTimeoutTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/DataTransferTimeoutTest.java index c83acac3..91b8f483 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/DataTransferTimeoutTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/DataTransferTimeoutTest.java @@ -20,21 +20,16 @@ package org.apache.ftpserver.clienttests; import java.io.File; -import java.io.InputStream; import java.io.OutputStream; -import java.util.Arrays; import org.apache.ftpserver.FtpServerFactory; import org.apache.ftpserver.listener.ListenerFactory; -import org.apache.ftpserver.test.TestUtil; /** * * Test for FTPSERVER-170 * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class DataTransferTimeoutTest extends ClientTestTemplate { private static final String TEST_FILENAME = "test.txt"; diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/DecoderTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/DecoderTest.java new file mode 100644 index 00000000..e3dbbaaa --- /dev/null +++ b/core/src/test/java/org/apache/ftpserver/clienttests/DecoderTest.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.clienttests; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.MalformedInputException; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.net.ftp.FTPClient; + + +/** +* +* @author Apache MINA Project* +*/ +public class DecoderTest extends ClientTestTemplate { + private String dump = "4C 49 53 54 20 61 62 63 64 AE 2E 0D 0A".replace(" ", ""); + + byte[] b; + + public DecoderTest() throws DecoderException { + b = Hex.decodeHex(dump.toCharArray()); + } + + public void testDecodeError() throws CharacterCodingException { + CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); + ByteBuffer buffer = ByteBuffer.wrap(b); + + try { + decoder.decode(buffer); + fail("Must throw MalformedInputException"); + } catch (MalformedInputException e) { + // OK + } + } + + private static class MyFTPClient extends FTPClient { + public void sendRawCommand(byte[] b) throws IOException { + OutputStream out =_socket_.getOutputStream(); + out.write(b); + } + } + + protected FTPClient createFTPClient() throws Exception { + FTPClient client = new MyFTPClient(); + client.setDefaultTimeout(10000); + return client; + } + + public void testInvalidCharacter() throws Exception { + client.login(ADMIN_USERNAME, ADMIN_PASSWORD); + + ((MyFTPClient)client).sendRawCommand(b); + client.completePendingCommand(); + + assertEquals(501, client.getReplyCode()); + } + +} diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/DefaultMaxLoginTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/DefaultMaxLoginTest.java index b41b06a9..4b4fa784 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/DefaultMaxLoginTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/DefaultMaxLoginTest.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class DefaultMaxLoginTest extends ClientTestTemplate { private static final String UNKNOWN_USERNAME = "foo"; diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/DeleteTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/DeleteTest.java index b88cdf5a..e6c5d4cd 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/DeleteTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/DeleteTest.java @@ -23,9 +23,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class DeleteTest extends ClientTestTemplate { private static final File TEST_FILE1 = new File(ROOT_DIR, "test1.txt"); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/DirectoryTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/DirectoryTest.java index bbba617e..c17e7684 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/DirectoryTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/DirectoryTest.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class DirectoryTest extends ClientTestTemplate { private static final File TEST_DIR1 = new File(ROOT_DIR, "dir1"); @@ -58,10 +56,6 @@ public void testMkdirNoDirectoryName() throws Exception { assertEquals(501, client.sendCommand("MKD")); } - public void testMkdirInValidDirectoryName() throws Exception { - assertEquals(501, client.sendCommand("MKD foo:bar;foo")); - } - /** * FTPSERVER-233, we should not recursively create directories */ diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/FeatTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/FeatTest.java index 655adb3d..38a5a40f 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/FeatTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/FeatTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FeatTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/FtpMd5Test.java b/core/src/test/java/org/apache/ftpserver/clienttests/FtpMd5Test.java index 398a67ca..d3adef35 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/FtpMd5Test.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/FtpMd5Test.java @@ -28,9 +28,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpMd5Test extends ClientTestTemplate { private static final File TEST_FILE1 = new File(ROOT_DIR, "test1.txt"); @@ -192,6 +190,9 @@ private Map parseReplyHash(String reply) { int hashStart = token.lastIndexOf(' '); String fileName = token.substring(0, hashStart).trim(); + if(fileName.startsWith("\"") && fileName.endsWith("\"")) { + fileName = fileName.substring(1, fileName.length() - 1); + } String hash = token.substring(hashStart).trim(); result.put(fileName, hash); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/HelpTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/HelpTest.java index 939c1f92..c03f4917 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/HelpTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/HelpTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class HelpTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/I18NTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/I18NTest.java index e58920ee..632e1fc4 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/I18NTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/I18NTest.java @@ -28,9 +28,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class I18NTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/InetAddressBlacklistTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/InetAddressBlacklistTest.java index 54b9732c..06cee742 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/InetAddressBlacklistTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/InetAddressBlacklistTest.java @@ -25,14 +25,11 @@ import org.apache.commons.net.ftp.FTPConnectionClosedException; import org.apache.ftpserver.FtpServerFactory; -import org.apache.ftpserver.impl.DefaultFtpServer; import org.apache.ftpserver.listener.ListenerFactory; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class InetAddressBlacklistTest extends ClientTestTemplate { protected FtpServerFactory createServer() throws Exception { @@ -56,7 +53,7 @@ protected boolean isConnectClient() { public void testConnect() throws Exception { try { - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); fail("Must throw"); } catch (FTPConnectionClosedException e) { // OK diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/IpFilterTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/IpFilterTest.java new file mode 100644 index 00000000..3f3c02cd --- /dev/null +++ b/core/src/test/java/org/apache/ftpserver/clienttests/IpFilterTest.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.clienttests; + +import java.net.InetAddress; + +import org.apache.commons.net.ftp.FTPConnectionClosedException; +import org.apache.ftpserver.FtpServerFactory; +import org.apache.ftpserver.ipfilter.DefaultIpFilter; +import org.apache.ftpserver.ipfilter.IpFilterType; +import org.apache.ftpserver.listener.ListenerFactory; +import org.apache.mina.filter.firewall.Subnet; +import org.springframework.context.annotation.FilterType; + +/** +* +* @author Apache MINA Project +* +*/ +public class IpFilterTest extends ClientTestTemplate { + + private DefaultIpFilter filter = new DefaultIpFilter(IpFilterType.DENY); + + protected FtpServerFactory createServer() throws Exception { + FtpServerFactory server = super.createServer(); + + ListenerFactory factory = new ListenerFactory(server.getListener("default")); + + factory.setIpFilter(filter); + server.addListener("default", factory.createListener()); + + return server; + } + + protected boolean isConnectClient() { + return false; + } + + public void testDenyBlackList() throws Exception { + filter.clear(); + filter.setType(IpFilterType.DENY); + filter.add(new Subnet(InetAddress.getByName("localhost"), 32)); + try { + client.connect("localhost", getListenerPort()); + fail("Must throw"); + } catch (FTPConnectionClosedException e) { + // OK + } + } + + public void testDenyEmptyWhiteList() throws Exception { + filter.clear(); + filter.setType(IpFilterType.ALLOW); + try { + client.connect("localhost", getListenerPort()); + fail("Must throw"); + } catch (FTPConnectionClosedException e) { + // OK + } + } + + public void testWhiteList() throws Exception { + filter.clear(); + filter.setType(IpFilterType.ALLOW); + filter.add(new Subnet(InetAddress.getByName("localhost"), 32)); + client.connect("localhost", getListenerPort()); + } +} diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/LangTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/LangTest.java index 058d2cdd..2edbc201 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/LangTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/LangTest.java @@ -26,9 +26,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class LangTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/ListPassiveTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/ListPassiveTest.java index 229b0235..f1dbbcad 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/ListPassiveTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/ListPassiveTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ListPassiveTest extends ListTest { /* diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/ListTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/ListTest.java index daecc4c3..59275fc6 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/ListTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/ListTest.java @@ -20,6 +20,7 @@ package org.apache.ftpserver.clienttests; import java.io.File; +import java.util.Calendar; import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPFile; @@ -29,9 +30,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ListTest extends ClientTestTemplate { private static final File TEST_FILE1 = new File(ROOT_DIR, "test1.txt"); @@ -114,6 +113,14 @@ public void testListFile() throws Exception { assertEquals("user", file.getUser()); assertTrue(file.isFile()); assertFalse(file.isDirectory()); + + Calendar expectedTimestamp = Calendar.getInstance(); + expectedTimestamp.setTimeInMillis(TEST_FILE1.lastModified()); + // server does not supply seconds and milliseconds + expectedTimestamp.clear(Calendar.SECOND); + expectedTimestamp.clear(Calendar.MILLISECOND); + + assertEquals(expectedTimestamp, file.getTimestamp()); } public void testListFileNoArgument() throws Exception { @@ -237,13 +244,66 @@ public void testOPTSMLST() throws Exception { + TEST_FILE1.getName(), reply[1]); } - public void testOPTSMLSTInvalidType() throws Exception { + public void testOPTSMLSTCaseInsensitive() throws Exception { TEST_FILE1.createNewFile(); + + assertTrue(FTPReply.isPositiveCompletion(client + .sendCommand("OPTS MLST size;Modify"))); + assertTrue(FTPReply.isPositiveCompletion(client.sendCommand("MLST " + + TEST_FILE1.getName()))); + + String[] reply = client.getReplyString().split("\\r\\n"); + + assertEquals("Size=0;Modify=" + + DateUtils.getFtpDate(TEST_FILE1.lastModified()) + "; " + + TEST_FILE1.getName(), reply[1]); + } - assertTrue(FTPReply.isNegativePermanent(client + /** + * "Facts requested that are not + * supported, or that are inappropriate to the file or directory being + * listed should simply be omitted from the MLSx output." + * + * http://tools.ietf.org/html/rfc3659#section-7.9 + */ + public void testOPTSMLSTUnknownFact() throws Exception { + TEST_FILE1.createNewFile(); + + assertTrue(FTPReply.isPositiveCompletion(client .sendCommand("OPTS MLST Foo;Size"))); + + assertTrue(FTPReply.isPositiveCompletion(client.sendCommand("MLST " + + TEST_FILE1.getName()))); + + String[] reply = client.getReplyString().split("\\r\\n"); + + assertEquals("Size=0; " + + TEST_FILE1.getName(), reply[1]); } + /** + * "Facts requested that are not + * supported, or that are inappropriate to the file or directory being + * listed should simply be omitted from the MLSx output." + * + * http://tools.ietf.org/html/rfc3659#section-7.9 + */ + public void testOPTSMLSTNoFacts() throws Exception { + TEST_FILE1.createNewFile(); + + assertTrue(FTPReply.isPositiveCompletion(client + .sendCommand("OPTS MLST"))); + + assertTrue(FTPReply.isPositiveCompletion(client.sendCommand("MLST " + + TEST_FILE1.getName()))); + + String[] reply = client.getReplyString().split("\\r\\n"); + + assertEquals(" " + + TEST_FILE1.getName(), reply[1]); + } + + private FTPFile getFile(FTPFile[] files, String name) { for (int i = 0; i < files.length; i++) { FTPFile file = files[i]; diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/LoginNoAnonTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/LoginNoAnonTest.java index a9c50699..89a91cd7 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/LoginNoAnonTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/LoginNoAnonTest.java @@ -21,13 +21,10 @@ import org.apache.ftpserver.ConnectionConfigFactory; import org.apache.ftpserver.FtpServerFactory; -import org.apache.ftpserver.impl.DefaultConnectionConfig; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class LoginNoAnonTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/LoginTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/LoginTest.java index 54807f08..6d0db26b 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/LoginTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/LoginTest.java @@ -24,12 +24,11 @@ import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPConnectionClosedException; import org.apache.commons.net.ftp.FTPReply; +import org.apache.ftpserver.ftplet.FtpStatistics; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class LoginTest extends ClientTestTemplate { private static final String UNKNOWN_USERNAME = "foo"; @@ -49,6 +48,10 @@ public void testLoginNoUser() throws Exception { assertFalse(client.login(null, null)); } + public void testLoginDisabledUser() throws Exception { + assertFalse(client.login("testuser4", "password")); + } + public void testLoginWithAccount() throws Exception { assertTrue(client.login(ADMIN_USERNAME, ADMIN_PASSWORD)); @@ -86,8 +89,8 @@ public void testDoubleLoginDifferentUser() throws Exception { } public void testREIN() throws Exception { - assertTrue(client.login(ADMIN_USERNAME, ADMIN_PASSWORD)); - assertTrue(FTPReply.isPositiveCompletion(client.rein())); + assertTrue(client.login(ADMIN_USERNAME, ADMIN_PASSWORD)); + assertTrue(FTPReply.isPositiveCompletion(client.rein())); assertTrue(client.login(TESTUSER1_USERNAME, TESTUSER_PASSWORD)); } @@ -118,6 +121,15 @@ public void testLoginAnon() throws Exception { public void testLoginUnknownUser() throws Exception { assertFalse(client.login(UNKNOWN_USERNAME, UNKNOWN_PASSWORD)); } + public void testLoginCount() throws Exception { + FtpStatistics stats = server.getServerContext().getFtpStatistics(); + assertTrue(client.login(ADMIN_USERNAME, ADMIN_PASSWORD)); + int n =stats.getCurrentLoginNumber(); + assertEquals(1,n ); + client.rein(); + client.logout(); + assertEquals(0, stats.getCurrentLoginNumber()); + } /* * public void testLoginWithMaxConnectionsPerIp() throws Exception { @@ -152,10 +164,10 @@ public void testLoginWithMaxConnections() throws Exception { FTPClient client4 = new FTPClient(); try { - client1.connect("localhost", port); - client2.connect("localhost", port); - client3.connect("localhost", port); - client4.connect("localhost", port); + client1.connect("localhost", getListenerPort()); + client2.connect("localhost", getListenerPort()); + client3.connect("localhost", getListenerPort()); + client4.connect("localhost", getListenerPort()); assertTrue(client1.login(TESTUSER1_USERNAME, TESTUSER_PASSWORD)); assertTrue(client2.login(TESTUSER1_USERNAME, TESTUSER_PASSWORD)); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/MDTMTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/MDTMTest.java index 3205ad90..d67e6596 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/MDTMTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/MDTMTest.java @@ -21,18 +21,21 @@ import java.io.File; import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; +import java.util.TimeZone; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MDTMTest extends ClientTestTemplate { private static final SimpleDateFormat FTP_DATE_FORMAT = new SimpleDateFormat( "yyyyMMddHHmmss.SSS"); - + static { + FTP_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); + } + private static final File TEST_FILE1 = new File(ROOT_DIR, "test1.txt"); private static final File TEST_DIR1 = new File(ROOT_DIR, "dir1"); @@ -52,11 +55,15 @@ public void testMDTMForFile() throws Exception { assertFalse(TEST_FILE1.exists()); assertTrue(TEST_FILE1.createNewFile()); - Date expected = new Date(TEST_FILE1.lastModified()); + Calendar expected = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + expected.clear(); + expected.setTimeInMillis(TEST_FILE1.lastModified()); assertEquals(213, client.sendCommand("MDTM " + TEST_FILE1.getName())); - Date actual = FTP_DATE_FORMAT.parse(client.getReplyString() - .substring(4).trim()); + Calendar actual = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + actual.clear(); + actual.setTime(FTP_DATE_FORMAT.parse(client.getReplyString() + .substring(4).trim())); assertEquals(expected, actual); } diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/MFMTTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/MFMTTest.java index 8678b6f1..64c12249 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/MFMTTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/MFMTTest.java @@ -20,18 +20,13 @@ package org.apache.ftpserver.clienttests; import java.io.File; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Calendar; -import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MFMTTest extends ClientTestTemplate { private static final File TEST_FILE1 = new File(ROOT_DIR, "test1.txt"); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/PasvAddressTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/PasvAddressTest.java index c00117c7..653e67e6 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/PasvAddressTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/PasvAddressTest.java @@ -31,9 +31,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class PasvAddressTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/PasvAddressWithHostnameTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/PasvAddressWithHostnameTest.java index dacc43d2..38c6e827 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/PasvAddressWithHostnameTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/PasvAddressWithHostnameTest.java @@ -19,20 +19,15 @@ package org.apache.ftpserver.clienttests; -import java.net.InetAddress; - import org.apache.ftpserver.DataConnectionConfigurationFactory; import org.apache.ftpserver.FtpServerFactory; -import org.apache.ftpserver.impl.DefaultDataConnectionConfiguration; import org.apache.ftpserver.listener.ListenerFactory; /** * Test for external passive address configured as hostname rather than IP * address. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class PasvAddressWithHostnameTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/PasvPortUnavailableTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/PasvPortUnavailableTest.java new file mode 100644 index 00000000..61c535dc --- /dev/null +++ b/core/src/test/java/org/apache/ftpserver/clienttests/PasvPortUnavailableTest.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.clienttests; + +import java.net.ServerSocket; + +import org.apache.ftpserver.DataConnectionConfigurationFactory; +import org.apache.ftpserver.FtpServerFactory; +import org.apache.ftpserver.listener.ListenerFactory; +import org.apache.ftpserver.test.TestUtil; +import org.apache.commons.net.ftp.FTPClient; +import org.apache.commons.net.ftp.FTPConnectionClosedException; + + +/** +* +* @author Apache MINA Project +* +*/ +public class PasvPortUnavailableTest extends ClientTestTemplate { + + private int passivePort; + + @Override + protected FtpServerFactory createServer() throws Exception { + FtpServerFactory server = super.createServer(); + + ListenerFactory listenerFactory = new ListenerFactory(server + .getListener("default")); + + DataConnectionConfigurationFactory dccFactory = new DataConnectionConfigurationFactory(); + + passivePort = TestUtil.findFreePort(12444); + + dccFactory.setPassivePorts(String.valueOf(passivePort)); + + listenerFactory.setDataConnectionConfiguration(dccFactory + .createDataConnectionConfiguration()); + + server.addListener("default", listenerFactory.createListener()); + + return server; + } + + public void testPasvPortUnavailable() throws Exception { + FTPClient[] clients = new FTPClient[3]; + for(int i = 0; i < 3; i ++) { + clients[i] = createFTPClient(); + clients[i] .connect("localhost", getListenerPort()); + clients[i].login(ADMIN_USERNAME, ADMIN_PASSWORD); + clients[i].pasv(); + if(i < 1) { + assertTrue(clients[i].getReplyString(), clients[i].getReplyString().trim().startsWith("227")); + } + else { + assertTrue(clients[i].getReplyString(), clients[i].getReplyString().trim().startsWith("425")); + } + } + for(int i = 0; i < 3; i ++) { + if(clients[i] != null) { + clients[i].disconnect(); + } + } + } +} diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/PasvTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/PasvTest.java index a59e6bf3..9e97918f 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/PasvTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/PasvTest.java @@ -27,9 +27,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class PasvTest extends ClientTestTemplate { @@ -58,7 +56,7 @@ protected FtpServerFactory createServer() throws Exception { public void testMultiplePasv() throws Exception { for (int i = 0; i < 5; i++) { - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); client.login(ADMIN_USERNAME, ADMIN_PASSWORD); client.pasv(); @@ -84,11 +82,11 @@ public void testPasvIp() throws Exception { if (!ip.startsWith("0.")) { try { - client.connect(ip, port); + client.connect(ip, getListenerPort()); } catch (FTPConnectionClosedException e) { // try again Thread.sleep(200); - client.connect(ip, port); + client.connect(ip, getListenerPort()); } client.login(ADMIN_USERNAME, ADMIN_PASSWORD); client.pasv(); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/PasvUsedPortTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/PasvUsedPortTest.java new file mode 100644 index 00000000..ab3635ba --- /dev/null +++ b/core/src/test/java/org/apache/ftpserver/clienttests/PasvUsedPortTest.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.clienttests; + +import java.net.ServerSocket; + +import org.apache.ftpserver.DataConnectionConfigurationFactory; +import org.apache.ftpserver.FtpServerFactory; +import org.apache.ftpserver.listener.ListenerFactory; +import org.apache.ftpserver.test.TestUtil; + +/** +* +* @author Apache MINA Project +* +*/ +public class PasvUsedPortTest extends ClientTestTemplate { + + private int passivePort; + + @Override + protected FtpServerFactory createServer() throws Exception { + FtpServerFactory server = super.createServer(); + + ListenerFactory listenerFactory = new ListenerFactory(server + .getListener("default")); + + DataConnectionConfigurationFactory dccFactory = new DataConnectionConfigurationFactory(); + + passivePort = TestUtil.findFreePort(12444); + + dccFactory.setPassivePorts(passivePort + "-" + (passivePort + 1)); + + listenerFactory.setDataConnectionConfiguration(dccFactory + .createDataConnectionConfiguration()); + + server.addListener("default", listenerFactory.createListener()); + + return server; + } + + public void testPasvWithUsedPort() throws Exception { + // bind to the first available passive port + ServerSocket ss = new ServerSocket(passivePort); + + client.login(ADMIN_USERNAME, ADMIN_PASSWORD); + client.pasv(); + assertEquals("227 Entering Passive Mode (127,0,0,1,48,157)", client.getReplyString().trim()); + client.quit(); + client.disconnect(); + + // close blocking socket + ss.close(); + } +} diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/PortTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/PortTest.java new file mode 100644 index 00000000..069b97d3 --- /dev/null +++ b/core/src/test/java/org/apache/ftpserver/clienttests/PortTest.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.clienttests; + +import java.net.InetAddress; + +/** +* +* @author Apache MINA Project +* +*/ +public class PortTest extends ClientTestTemplate { + + protected void setUp() throws Exception { + super.setUp(); + + client.login(ADMIN_USERNAME, ADMIN_PASSWORD); + } + + public void testInvalidIpAndPort() throws Exception { + assertEquals(501, client.port(InetAddress.getByName("0.0.0.0"), 0)); + } + +} diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/RenameTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/RenameTest.java index 1f88895c..73964e10 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/RenameTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/RenameTest.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class RenameTest extends ClientTestTemplate { private static final File TEST_FILE1 = new File(ROOT_DIR, "test1.txt"); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/RetrievePassiveTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/RetrievePassiveTest.java index d2fc83a4..d22a96b8 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/RetrievePassiveTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/RetrievePassiveTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class RetrievePassiveTest extends RetrieveTest { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/RetrieveTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/RetrieveTest.java index 78d092aa..f8679fdd 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/RetrieveTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/RetrieveTest.java @@ -26,9 +26,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class RetrieveTest extends ClientTestTemplate { private static final String TEST_FILENAME = "test.txt"; diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/RmDirTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/RmDirTest.java index e18a63f9..519a36ee 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/RmDirTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/RmDirTest.java @@ -22,9 +22,7 @@ /** * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class RmDirTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/SiteTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/SiteTest.java index 8efade0e..7eb22424 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/SiteTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/SiteTest.java @@ -28,9 +28,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class SiteTest extends ClientTestTemplate { @@ -81,7 +79,7 @@ public void testSiteStat() throws Exception { // let's generate some stats FTPClient client1 = new FTPClient(); - client1.connect("localhost", port); + client1.connect("localhost", getListenerPort()); assertTrue(client1.login(ADMIN_USERNAME, ADMIN_PASSWORD)); assertTrue(client1.makeDirectory("foo")); @@ -96,12 +94,12 @@ public void testSiteStat() throws Exception { client1.disconnect(); FTPClient client2 = new FTPClient(); - client2.connect("localhost", port); + client2.connect("localhost", getListenerPort()); assertTrue(client2.login(ANONYMOUS_USERNAME, ANONYMOUS_PASSWORD)); // done setting up stats - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); client.login(ADMIN_USERNAME, ADMIN_PASSWORD); client.sendCommand("SITE STAT"); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/SizeTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/SizeTest.java index 7fa2aa7c..b80f7caf 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/SizeTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/SizeTest.java @@ -26,9 +26,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class SizeTest extends ClientTestTemplate { protected static final File TEST_DIR1 = new File(ROOT_DIR, "dir1"); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/StatTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/StatTest.java new file mode 100644 index 00000000..08e8b740 --- /dev/null +++ b/core/src/test/java/org/apache/ftpserver/clienttests/StatTest.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.clienttests; + +import java.io.File; +import java.util.regex.Pattern; + + +/** +* +* @author Apache MINA Project +* +*/ +public class StatTest extends ClientTestTemplate { + + private static final String PATTERN = "^-rw-------\\s\\s\\s1\\suser\\sgroup\\s{12}0\\s[A-Za-z0-9\\s]{6}\\s\\d\\d:\\d\\d\\stest\\d.txt$"; + + private static final File TEST_DIR = new File(ROOT_DIR, "test"); + private static final File TEST_FILE1 = new File(TEST_DIR, "test1.txt"); + private static final File TEST_FILE2 = new File(TEST_DIR, "test2.txt"); + + public void testStatDir() throws Exception { + assertTrue(TEST_DIR.mkdir()); + assertTrue(TEST_FILE1.createNewFile()); + assertTrue(TEST_FILE2.createNewFile()); + + client.login(ADMIN_USERNAME, ADMIN_PASSWORD); + + assertEquals(212, client.stat(TEST_DIR.getName())); + String[] reply = client.getReplyString().split("\r\n"); + + assertTrue(reply[1], Pattern.matches(PATTERN, reply[1])); + assertTrue(reply[2], Pattern.matches(PATTERN, reply[2])); + } + + public void testStatFile() throws Exception { + assertTrue(TEST_DIR.mkdir()); + assertTrue(TEST_FILE1.createNewFile()); + + client.login(ADMIN_USERNAME, ADMIN_PASSWORD); + + assertEquals(213, client.stat(TEST_DIR.getName() + "/" + TEST_FILE1.getName())); + String[] reply = client.getReplyString().split("\r\n"); + + assertTrue(reply[1], Pattern.matches(PATTERN, reply[1])); + } + + public void testStat() throws Exception { + client.login(ADMIN_USERNAME, ADMIN_PASSWORD); + + client.stat(); + String[] reply = client.getReplyString().split("\r\n"); + + assertEquals("211-Apache FtpServer", reply[0]); + assertEquals("Connected to 127.0.0.1", reply[1]); + assertEquals("Connected from 127.0.0.1", reply[2]); + assertEquals("Logged in as admin", reply[3]); + assertEquals("211 End of status.", reply[4]); + } + +} diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/StorePassiveTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/StorePassiveTest.java index 7a39d4a7..2764edee 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/StorePassiveTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/StorePassiveTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class StorePassiveTest extends StoreTest { /* diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/StoreTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/StoreTest.java index ac18a249..9846e999 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/StoreTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/StoreTest.java @@ -27,9 +27,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class StoreTest extends ClientTestTemplate { private static final String EOL = System.getProperty("line.separator"); diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/SubnetBlacklistTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/SubnetBlacklistTest.java index cc5f1496..2ba440b3 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/SubnetBlacklistTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/SubnetBlacklistTest.java @@ -30,9 +30,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class SubnetBlacklistTest extends ClientTestTemplate { protected FtpServerFactory createServer() throws Exception { @@ -56,7 +54,7 @@ protected boolean isConnectClient() { public void testConnect() throws Exception { try { - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); fail("Must throw"); } catch (FTPConnectionClosedException e) { // OK diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/SuspendResumeTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/SuspendResumeTest.java index bdcd64df..6c8804f6 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/SuspendResumeTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/SuspendResumeTest.java @@ -24,9 +24,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class SuspendResumeTest extends ClientTestTemplate { @@ -37,13 +35,13 @@ protected boolean isConnectClient() { public void testSuspendResumeServer() throws Exception { // connect should work as expected - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); client.disconnect(); server.suspend(); try { - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); fail("Must throw IOException"); } catch(IOException e) { // OK @@ -54,19 +52,19 @@ public void testSuspendResumeServer() throws Exception { server.resume(); // connect should work again - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); client.disconnect(); } public void testSuspendResumeListener() throws Exception { // connect should work as expected - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); client.disconnect(); server.getListener("default").suspend(); try { - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); fail("Must throw IOException"); } catch(IOException e) { // OK @@ -77,7 +75,7 @@ public void testSuspendResumeListener() throws Exception { server.getListener("default").resume(); // connect should work again - client.connect("localhost", port); + client.connect("localhost", getListenerPort()); client.disconnect(); } diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/SystTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/SystTest.java index c1b9af7e..75b6368b 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/SystTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/SystTest.java @@ -23,9 +23,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class SystTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/TypeTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/TypeTest.java index 4798133b..b85e7abe 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/TypeTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/TypeTest.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class TypeTest extends ClientTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/clienttests/UnlimitedMaxLoginTest.java b/core/src/test/java/org/apache/ftpserver/clienttests/UnlimitedMaxLoginTest.java index b244adb6..ebfa2fb3 100644 --- a/core/src/test/java/org/apache/ftpserver/clienttests/UnlimitedMaxLoginTest.java +++ b/core/src/test/java/org/apache/ftpserver/clienttests/UnlimitedMaxLoginTest.java @@ -24,9 +24,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class UnlimitedMaxLoginTest extends ClientTestTemplate { private static final String UNKNOWN_USERNAME = "foo"; diff --git a/core/src/test/java/org/apache/ftpserver/commands/impl/DefaultCommandFactoryTest.java b/core/src/test/java/org/apache/ftpserver/commands/impl/DefaultCommandFactoryTest.java index ef71b7cf..c4e731fc 100644 --- a/core/src/test/java/org/apache/ftpserver/commands/impl/DefaultCommandFactoryTest.java +++ b/core/src/test/java/org/apache/ftpserver/commands/impl/DefaultCommandFactoryTest.java @@ -30,9 +30,7 @@ /** * * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class DefaultCommandFactoryTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/DirectoryListerTest.java b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/DirectoryListerTest.java index 2317f98b..dfd82c6e 100644 --- a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/DirectoryListerTest.java +++ b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/DirectoryListerTest.java @@ -1,103 +1,102 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.ftpserver.commands.impl.listing; - -import java.io.File; - -import junit.framework.TestCase; - -import org.apache.ftpserver.command.impl.listing.DirectoryLister; -import org.apache.ftpserver.command.impl.listing.FileFormater; -import org.apache.ftpserver.command.impl.listing.ListArgument; -import org.apache.ftpserver.command.impl.listing.NLSTFileFormater; -import org.apache.ftpserver.filesystem.nativefs.impl.NativeFileSystemView; -import org.apache.ftpserver.ftplet.FileSystemView; -import org.apache.ftpserver.test.TestUtil; -import org.apache.ftpserver.usermanager.impl.BaseUser; -import org.apache.ftpserver.util.IoUtils; - -/** -* -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* -*/ -public class DirectoryListerTest extends TestCase { - private static final File TEST_TMP_DIR = new File("test-tmp"); - - protected static final File ROOT_DIR = new File(TEST_TMP_DIR, "ftproot"); - - private static final File TEST_FILE1 = new File(ROOT_DIR, "test1.txt"); - - private static final File TEST_DIR1 = new File(ROOT_DIR, "dir1"); - - private static final File TEST_DIR2 = new File(ROOT_DIR, "dir2"); - - private static final File TEST_FILE1_IN_DIR1 = new File(TEST_DIR1, - "test3.txt"); - - private static final File TEST_FILE2_IN_DIR1 = new File(TEST_DIR1, - "test4.txt"); - - private static final File TEST_DIR_IN_DIR1 = new File(TEST_DIR1, "dir3"); - - private static final byte[] TEST_DATA = "TESTDATA".getBytes(); - - private DirectoryLister directoryLister; - - private FileSystemView fileSystemView; - - protected void setUp() throws Exception { - BaseUser baseUser = new BaseUser(); - baseUser.setHomeDirectory(ROOT_DIR.getAbsolutePath()); - fileSystemView = new NativeFileSystemView(baseUser) { - }; - directoryLister = new DirectoryLister(); - - assertTrue(ROOT_DIR.mkdirs()); - assertTrue(TEST_DIR1.mkdirs()); - assertTrue(TEST_DIR2.mkdirs()); - TestUtil.writeDataToFile(TEST_FILE1, TEST_DATA); - TestUtil.writeDataToFile(TEST_FILE1_IN_DIR1, TEST_DATA); - TEST_FILE2_IN_DIR1.createNewFile(); - assertTrue(TEST_DIR_IN_DIR1.mkdir()); - } - - public void testListFiles() throws Exception { - ListArgument arg = new ListArgument(TEST_DIR1.getName(), null, null); - FileFormater formater = new NLSTFileFormater(); - - String actual = directoryLister - .listFiles(arg, fileSystemView, formater); - - assertEquals("dir3\r\ntest3.txt\r\ntest4.txt\r\n", actual); - } - - /* - * (non-Javadoc) - * - * @see junit.framework.TestCase#tearDown() - */ - protected void tearDown() throws Exception { - if (TEST_TMP_DIR.exists()) { - IoUtils.delete(TEST_TMP_DIR); - } - } +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.commands.impl.listing; + +import java.io.File; + +import junit.framework.TestCase; + +import org.apache.ftpserver.command.impl.listing.DirectoryLister; +import org.apache.ftpserver.command.impl.listing.FileFormater; +import org.apache.ftpserver.command.impl.listing.ListArgument; +import org.apache.ftpserver.command.impl.listing.NLSTFileFormater; +import org.apache.ftpserver.filesystem.nativefs.impl.NativeFileSystemView; +import org.apache.ftpserver.ftplet.FileSystemView; +import org.apache.ftpserver.test.TestUtil; +import org.apache.ftpserver.usermanager.impl.BaseUser; +import org.apache.ftpserver.util.IoUtils; + +/** +* +* @author Apache MINA Project +* +*/ +public class DirectoryListerTest extends TestCase { + private static final File TEST_TMP_DIR = new File("test-tmp"); + + protected static final File ROOT_DIR = new File(TEST_TMP_DIR, "ftproot"); + + private static final File TEST_FILE1 = new File(ROOT_DIR, "test1.txt"); + + private static final File TEST_DIR1 = new File(ROOT_DIR, "dir1"); + + private static final File TEST_DIR2 = new File(ROOT_DIR, "dir2"); + + private static final File TEST_FILE1_IN_DIR1 = new File(TEST_DIR1, + "test3.txt"); + + private static final File TEST_FILE2_IN_DIR1 = new File(TEST_DIR1, + "test4.txt"); + + private static final File TEST_DIR_IN_DIR1 = new File(TEST_DIR1, "dir3"); + + private static final byte[] TEST_DATA = "TESTDATA".getBytes(); + + private DirectoryLister directoryLister; + + private FileSystemView fileSystemView; + + protected void setUp() throws Exception { + BaseUser baseUser = new BaseUser(); + baseUser.setHomeDirectory(ROOT_DIR.getAbsolutePath()); + fileSystemView = new NativeFileSystemView(baseUser) { + }; + directoryLister = new DirectoryLister(); + + assertTrue(ROOT_DIR.mkdirs()); + assertTrue(TEST_DIR1.mkdirs()); + assertTrue(TEST_DIR2.mkdirs()); + TestUtil.writeDataToFile(TEST_FILE1, TEST_DATA); + TestUtil.writeDataToFile(TEST_FILE1_IN_DIR1, TEST_DATA); + TEST_FILE2_IN_DIR1.createNewFile(); + assertTrue(TEST_DIR_IN_DIR1.mkdir()); + } + + public void testListFiles() throws Exception { + ListArgument arg = new ListArgument(TEST_DIR1.getName(), null, null); + FileFormater formater = new NLSTFileFormater(); + + String actual = directoryLister + .listFiles(arg, fileSystemView, formater); + + assertEquals("dir3\r\ntest3.txt\r\ntest4.txt\r\n", actual); + } + + /* + * (non-Javadoc) + * + * @see junit.framework.TestCase#tearDown() + */ + protected void tearDown() throws Exception { + if (TEST_TMP_DIR.exists()) { + IoUtils.delete(TEST_TMP_DIR); + } + } } \ No newline at end of file diff --git a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/LISTFileFormaterTest.java b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/LISTFileFormaterTest.java index 79005ef4..de6f80a8 100644 --- a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/LISTFileFormaterTest.java +++ b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/LISTFileFormaterTest.java @@ -32,9 +32,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ @SuppressWarnings("deprecation") public class LISTFileFormaterTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/ListArgumentParserTest.java b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/ListArgumentParserTest.java index 76d70acb..cf757232 100644 --- a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/ListArgumentParserTest.java +++ b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/ListArgumentParserTest.java @@ -26,9 +26,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ListArgumentParserTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/ListArgumentTest.java b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/ListArgumentTest.java index f5b3b0e0..311392a9 100644 --- a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/ListArgumentTest.java +++ b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/ListArgumentTest.java @@ -27,9 +27,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ListArgumentTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/MLSTFileFormaterTest.java b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/MLSTFileFormaterTest.java index ed998d06..5e0e2b10 100644 --- a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/MLSTFileFormaterTest.java +++ b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/MLSTFileFormaterTest.java @@ -22,8 +22,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.Date; +import java.util.Calendar; import java.util.List; +import java.util.TimeZone; import junit.framework.TestCase; @@ -32,14 +33,16 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ @SuppressWarnings("deprecation") public class MLSTFileFormaterTest extends TestCase { - private static final Date LAST_MODIFIED_IN_2005 = new Date(105, 1, 2, 3, 4); + private static final Calendar LAST_MODIFIED_IN_2005 = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + static { + LAST_MODIFIED_IN_2005.clear(); + LAST_MODIFIED_IN_2005.set(2005, Calendar.JANUARY, 2, 3, 4, 5); + } private static final FtpFile TEST_FILE = new MockFileObject(); @@ -71,7 +74,7 @@ public String getGroupName() { } public long getLastModified() { - return LAST_MODIFIED_IN_2005.getTime(); + return LAST_MODIFIED_IN_2005.getTimeInMillis(); } public int getLinkCount() { @@ -133,7 +136,8 @@ public boolean setLastModified(long time) { } public void testSingleFile() { - assertEquals("Size=13;Modify=20050202030400.000;Type=file; short\r\n", + // time should be in UTC + assertEquals("Size=13;Modify=20050102030405.000;Type=file; short\r\n", formater.format(TEST_FILE)); } @@ -153,8 +157,8 @@ public long getSize() { }; - assertEquals("Size=0;Modify=20050202030400.000;Type=dir; short\r\n", + // time should be in UTC + assertEquals("Size=0;Modify=20050102030405.000;Type=dir; short\r\n", formater.format(dir)); } - } \ No newline at end of file diff --git a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/NLSTFileFormaterTest.java b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/NLSTFileFormaterTest.java index 61f092b3..1a2a2f91 100644 --- a/core/src/test/java/org/apache/ftpserver/commands/impl/listing/NLSTFileFormaterTest.java +++ b/core/src/test/java/org/apache/ftpserver/commands/impl/listing/NLSTFileFormaterTest.java @@ -31,9 +31,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class NLSTFileFormaterTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/config/spring/DbUserManagerConfigTest.java b/core/src/test/java/org/apache/ftpserver/config/spring/DbUserManagerConfigTest.java index 8f357447..5ef50318 100644 --- a/core/src/test/java/org/apache/ftpserver/config/spring/DbUserManagerConfigTest.java +++ b/core/src/test/java/org/apache/ftpserver/config/spring/DbUserManagerConfigTest.java @@ -19,7 +19,6 @@ package org.apache.ftpserver.config.spring; -import org.apache.ftpserver.FtpServer; import org.apache.ftpserver.impl.DefaultFtpServer; import org.apache.ftpserver.usermanager.SaltedPasswordEncryptor; import org.apache.ftpserver.usermanager.impl.DbUserManager; @@ -27,9 +26,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class DbUserManagerConfigTest extends SpringConfigTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/config/spring/FileUserManagerConfigTest.java b/core/src/test/java/org/apache/ftpserver/config/spring/FileUserManagerConfigTest.java index 4465391f..07077b00 100644 --- a/core/src/test/java/org/apache/ftpserver/config/spring/FileUserManagerConfigTest.java +++ b/core/src/test/java/org/apache/ftpserver/config/spring/FileUserManagerConfigTest.java @@ -21,7 +21,6 @@ import java.io.File; -import org.apache.ftpserver.FtpServer; import org.apache.ftpserver.impl.DefaultFtpServer; import org.apache.ftpserver.usermanager.ClearTextPasswordEncryptor; import org.apache.ftpserver.usermanager.Md5PasswordEncryptor; @@ -30,9 +29,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FileUserManagerConfigTest extends SpringConfigTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/config/spring/FtpletsConfigTest.java b/core/src/test/java/org/apache/ftpserver/config/spring/FtpletsConfigTest.java index 8abdf6b2..609af8c7 100644 --- a/core/src/test/java/org/apache/ftpserver/config/spring/FtpletsConfigTest.java +++ b/core/src/test/java/org/apache/ftpserver/config/spring/FtpletsConfigTest.java @@ -19,23 +19,14 @@ package org.apache.ftpserver.config.spring; -import java.io.File; import java.util.Map; -import org.apache.ftpserver.FtpServer; import org.apache.ftpserver.ftplet.Ftplet; -import org.apache.ftpserver.ftpletcontainer.FtpletContainer; import org.apache.ftpserver.impl.DefaultFtpServer; -import org.apache.ftpserver.usermanager.ClearTextPasswordEncryptor; -import org.apache.ftpserver.usermanager.Md5PasswordEncryptor; -import org.apache.ftpserver.usermanager.SaltedPasswordEncryptor; -import org.apache.ftpserver.usermanager.impl.PropertiesUserManager; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpletsConfigTest extends SpringConfigTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/config/spring/MockUserManager.java b/core/src/test/java/org/apache/ftpserver/config/spring/MockUserManager.java index cd80b395..5ee00e21 100644 --- a/core/src/test/java/org/apache/ftpserver/config/spring/MockUserManager.java +++ b/core/src/test/java/org/apache/ftpserver/config/spring/MockUserManager.java @@ -25,6 +25,9 @@ import org.apache.ftpserver.ftplet.User; import org.apache.ftpserver.ftplet.UserManager; +/** +* @author Apache MINA Project* +*/ public class MockUserManager implements UserManager { public User authenticate(Authentication authentication) diff --git a/core/src/test/java/org/apache/ftpserver/config/spring/MyCustomListener.java b/core/src/test/java/org/apache/ftpserver/config/spring/MyCustomListener.java index 52a838ca..8c515d39 100644 --- a/core/src/test/java/org/apache/ftpserver/config/spring/MyCustomListener.java +++ b/core/src/test/java/org/apache/ftpserver/config/spring/MyCustomListener.java @@ -26,6 +26,7 @@ import org.apache.ftpserver.DataConnectionConfiguration; import org.apache.ftpserver.impl.FtpIoSession; import org.apache.ftpserver.impl.FtpServerContext; +import org.apache.ftpserver.ipfilter.IpFilter; import org.apache.ftpserver.listener.Listener; import org.apache.ftpserver.ssl.SslConfiguration; import org.apache.mina.filter.firewall.Subnet; @@ -33,9 +34,7 @@ /** * Used for testing creation of custom listeners from Spring config * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class MyCustomListener implements Listener { @@ -105,4 +104,8 @@ public List getBlockedSubnets() { return null; } + public IpFilter getIpFilter() { + return null; + } + } diff --git a/core/src/test/java/org/apache/ftpserver/config/spring/PropertyPlaceholderTest.java b/core/src/test/java/org/apache/ftpserver/config/spring/PropertyPlaceholderTest.java index dcbc9ab9..995ee4e2 100644 --- a/core/src/test/java/org/apache/ftpserver/config/spring/PropertyPlaceholderTest.java +++ b/core/src/test/java/org/apache/ftpserver/config/spring/PropertyPlaceholderTest.java @@ -26,9 +26,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class PropertyPlaceholderTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTest.java b/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTest.java index 1c701ee2..12be3f97 100644 --- a/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTest.java +++ b/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTest.java @@ -30,6 +30,7 @@ import org.apache.ftpserver.command.impl.STAT; import org.apache.ftpserver.filesystem.nativefs.NativeFileSystemFactory; import org.apache.ftpserver.impl.DefaultFtpServer; +import org.apache.ftpserver.ipfilter.DefaultIpFilter; import org.apache.ftpserver.listener.Listener; import org.apache.ftpserver.listener.nio.NioListener; import org.apache.mina.filter.firewall.Subnet; @@ -38,9 +39,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project */ public class SpringConfigTest extends TestCase { @@ -79,15 +78,11 @@ public void test() throws Throwable { assertEquals("123-125", ((NioListener) listener) .getDataConnectionConfiguration().getPassivePorts()); - List subnets = ((NioListener) listener).getBlockedSubnets(); - assertEquals(3, subnets.size()); - assertEquals(new Subnet(InetAddress.getByName("1.2.3.0"), 16), subnets - .get(0)); - assertEquals(new Subnet(InetAddress.getByName("1.2.4.0"), 16), subnets - .get(1)); - assertEquals(new Subnet(InetAddress.getByName("1.2.3.4"), 32), subnets - .get(2)); - + DefaultIpFilter filter = (DefaultIpFilter) listener.getIpFilter(); + assertEquals(3, filter.size()); + assertTrue(filter.contains(new Subnet(InetAddress.getByName("1.2.3.0"), 16))); + assertTrue(filter.contains(new Subnet(InetAddress.getByName("1.2.4.0"), 16))); + assertTrue(filter.contains(new Subnet(InetAddress.getByName("1.2.3.4"), 32))); listener = listeners.get("listener1"); assertNotNull(listener); assertTrue(listener instanceof MyCustomListener); diff --git a/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTestTemplate.java b/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTestTemplate.java index b58e4067..1fefa9cb 100644 --- a/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/config/spring/SpringConfigTestTemplate.java @@ -27,9 +27,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public abstract class SpringConfigTestTemplate extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/config/spring/TestFtplet.java b/core/src/test/java/org/apache/ftpserver/config/spring/TestFtplet.java index 22403286..e7290226 100644 --- a/core/src/test/java/org/apache/ftpserver/config/spring/TestFtplet.java +++ b/core/src/test/java/org/apache/ftpserver/config/spring/TestFtplet.java @@ -23,9 +23,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class TestFtplet extends DefaultFtplet { diff --git a/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/FileSystemViewTemplate.java b/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/FileSystemViewTemplate.java index a0aa7573..bf34fc0c 100644 --- a/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/FileSystemViewTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/FileSystemViewTemplate.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public abstract class FileSystemViewTemplate extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/FtpFileTestTemplate.java b/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/FtpFileTestTemplate.java index aab9ec31..38994208 100644 --- a/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/FtpFileTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/FtpFileTestTemplate.java @@ -30,9 +30,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public abstract class FtpFileTestTemplate extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileObjectTest.java b/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileObjectTest.java index f94d70ce..fd8c8bcc 100644 --- a/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileObjectTest.java +++ b/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileObjectTest.java @@ -30,9 +30,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class NativeFileObjectTest extends FtpFileTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileSystemViewTest.java b/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileSystemViewTest.java index 500b1ae6..6178d86b 100644 --- a/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileSystemViewTest.java +++ b/core/src/test/java/org/apache/ftpserver/filesystem/nativefs/impl/NativeFileSystemViewTest.java @@ -27,9 +27,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class NativeFileSystemViewTest extends FileSystemViewTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/DefaultFtpLetContainerTest.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/DefaultFtpLetContainerTest.java index 4477ac49..8d4bb702 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/DefaultFtpLetContainerTest.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/DefaultFtpLetContainerTest.java @@ -26,9 +26,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class DefaultFtpLetContainerTest extends FtpLetContainerTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetContainerTestTemplate.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetContainerTestTemplate.java index 40435747..d9e49e48 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetContainerTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetContainerTestTemplate.java @@ -40,6 +40,9 @@ import org.apache.ftpserver.impl.DefaultFtpRequest; import org.apache.ftpserver.impl.DefaultFtpSession; +/** +* @author Apache MINA Project* +*/ public abstract class FtpLetContainerTestTemplate extends TestCase { private final List calls = new ArrayList(); diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetOnConnectTest.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetOnConnectTest.java new file mode 100644 index 00000000..63ce9b65 --- /dev/null +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetOnConnectTest.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.ftpletcontainer; + +import java.io.File; +import java.io.IOException; +import java.net.SocketException; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.commons.net.ftp.FTPConnectionClosedException; +import org.apache.ftpserver.FtpServerFactory; +import org.apache.ftpserver.clienttests.ClientTestTemplate; +import org.apache.ftpserver.ftplet.FtpException; +import org.apache.ftpserver.ftplet.FtpSession; +import org.apache.ftpserver.ftplet.Ftplet; +import org.apache.ftpserver.ftplet.FtpletResult; + +/** +* +* @author Apache MINA Project* +*/ +public class FtpLetOnConnectTest extends ClientTestTemplate { + private static final byte[] TESTDATA = "TESTDATA".getBytes(); + + private static final byte[] DOUBLE_TESTDATA = "TESTDATATESTDATA".getBytes(); + + private static final File TEST_FILE1 = new File(ROOT_DIR, "test1.txt"); + + private static final File TEST_FILE2 = new File(ROOT_DIR, "test2.txt"); + + private static final File TEST_DIR1 = new File(ROOT_DIR, "dir1"); + + protected FtpletResult mockReturnValue = FtpletResult.DISCONNECT; + + /* + * (non-Javadoc) + * + * @see org.apache.ftpserver.clienttests.ClientTestTemplate#setUp() + */ + protected void setUp() throws Exception { + MockFtplet.callback = new MockFtpletCallback(); + + initDirs(); + + initServer(); + } + + protected FtpServerFactory createServer() throws Exception { + FtpServerFactory server = super.createServer(); + + Map ftplets = new LinkedHashMap(); + ftplets.put("f1", new MockFtplet()); + server.setFtplets(ftplets); + + return server; + } + + public void testDisconnectOnConnect() throws Exception { + MockFtplet.callback = new MockFtpletCallback() { + public FtpletResult onConnect(FtpSession session) + throws FtpException, IOException { + return mockReturnValue; + } + }; + + try { + connectClient(); + fail("Must throw FTPConnectionClosedException"); + } catch (FTPConnectionClosedException e) { + // OK + } catch (SocketException e) { + // OK + } + } + + public void testExceptionOnConnect() throws Exception { + MockFtplet.callback = new MockFtpletCallback() { + public FtpletResult onConnect(FtpSession session) + throws FtpException, IOException { + throw new FtpException(); + } + }; + + try { + connectClient(); + fail("Must throw FTPConnectionClosedException"); + } catch (FTPConnectionClosedException e) { + // OK + } catch (SocketException e) { + // OK + } + } + + protected void doConnect() throws Exception { + client.connect("localhost", getListenerPort()); + } +} diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnDefaultTest.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnDefaultTest.java index 71cf7cf9..d76f7f12 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnDefaultTest.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnDefaultTest.java @@ -25,6 +25,8 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; import org.apache.commons.net.ftp.FTPReply; import org.apache.ftpserver.FtpServerFactory; @@ -34,14 +36,12 @@ import org.apache.ftpserver.ftplet.FtpSession; import org.apache.ftpserver.ftplet.Ftplet; import org.apache.ftpserver.ftplet.FtpletResult; -import org.apache.ftpserver.impl.DefaultFtpServer; +import org.apache.ftpserver.ftplet.User; import org.apache.ftpserver.test.TestUtil; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpLetReturnDefaultTest extends ClientTestTemplate { private static final byte[] TESTDATA = "TESTDATA".getBytes(); @@ -83,11 +83,13 @@ protected FtpServerFactory createServer() throws Exception { } public void testLogin() throws Exception { + final LinkedBlockingQueue loggedInUser = new LinkedBlockingQueue(); + MockFtplet.callback = new MockFtpletCallback() { public FtpletResult onLogin(FtpSession session, FtpRequest request) throws FtpException, IOException { - assertNotNull(session.getUserArgument()); - + loggedInUser.add(session.getUser()); + return super.onLogin(session, request); } @@ -95,6 +97,8 @@ public FtpletResult onLogin(FtpSession session, FtpRequest request) MockFtpletCallback.returnValue = FtpletResult.DEFAULT; assertTrue(client.login(ADMIN_USERNAME, ADMIN_PASSWORD)); + + assertNotNull(loggedInUser.poll(2000, TimeUnit.MILLISECONDS)); } public void testDelete() throws Exception { diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnDisconnectTest.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnDisconnectTest.java index b4949079..7d295377 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnDisconnectTest.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnDisconnectTest.java @@ -35,14 +35,11 @@ import org.apache.ftpserver.ftplet.FtpSession; import org.apache.ftpserver.ftplet.Ftplet; import org.apache.ftpserver.ftplet.FtpletResult; -import org.apache.ftpserver.impl.DefaultFtpServer; import org.apache.ftpserver.test.TestUtil; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpLetReturnDisconnectTest extends ClientTestTemplate { private static final byte[] TESTDATA = "TESTDATA".getBytes(); diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnSkipTest.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnSkipTest.java index d8bad60d..1431a427 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnSkipTest.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetReturnSkipTest.java @@ -36,14 +36,11 @@ import org.apache.ftpserver.ftplet.FtpSession; import org.apache.ftpserver.ftplet.Ftplet; import org.apache.ftpserver.ftplet.FtpletResult; -import org.apache.ftpserver.impl.DefaultFtpServer; import org.apache.ftpserver.test.TestUtil; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpLetReturnSkipTest extends ClientTestTemplate { private static final byte[] TESTDATA = "TESTDATA".getBytes(); diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowFtpExceptionTest.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowFtpExceptionTest.java index 8787d45e..b85a62ab 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowFtpExceptionTest.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowFtpExceptionTest.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpLetThrowFtpExceptionTest extends FtpLetReturnDisconnectTest { diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowIOExceptionTest.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowIOExceptionTest.java index 621f27e0..cd1ef78f 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowIOExceptionTest.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowIOExceptionTest.java @@ -23,9 +23,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpLetThrowIOExceptionTest extends FtpLetThrowFtpExceptionTest { protected void throwException() throws IOException { diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowRuntimeExceptionTest.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowRuntimeExceptionTest.java index fd385051..d7ca8ede 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowRuntimeExceptionTest.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/FtpLetThrowRuntimeExceptionTest.java @@ -23,9 +23,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpLetThrowRuntimeExceptionTest extends FtpLetThrowFtpExceptionTest { diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/MockFtplet.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/MockFtplet.java index 3dc2ea42..2d5dc2c0 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/MockFtplet.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/MockFtplet.java @@ -30,9 +30,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MockFtplet extends DefaultFtplet { diff --git a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/MockFtpletCallback.java b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/MockFtpletCallback.java index 0d35c276..c3c0aeef 100644 --- a/core/src/test/java/org/apache/ftpserver/ftpletcontainer/MockFtpletCallback.java +++ b/core/src/test/java/org/apache/ftpserver/ftpletcontainer/MockFtpletCallback.java @@ -30,9 +30,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MockFtpletCallback extends DefaultFtplet { diff --git a/core/src/test/java/org/apache/ftpserver/impl/DefaultFtpServerTest.java b/core/src/test/java/org/apache/ftpserver/impl/DefaultFtpServerTest.java index 21f7c127..17f57627 100644 --- a/core/src/test/java/org/apache/ftpserver/impl/DefaultFtpServerTest.java +++ b/core/src/test/java/org/apache/ftpserver/impl/DefaultFtpServerTest.java @@ -19,9 +19,10 @@ package org.apache.ftpserver.impl; -import java.io.IOException; import java.net.BindException; +import junit.framework.TestCase; + import org.apache.ftpserver.FtpServer; import org.apache.ftpserver.FtpServerConfigurationException; import org.apache.ftpserver.FtpServerFactory; @@ -29,13 +30,9 @@ import org.apache.ftpserver.listener.ListenerFactory; import org.apache.ftpserver.test.TestUtil; -import junit.framework.TestCase; - /** * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ - * + * @author Apache MINA Project * */ public class DefaultFtpServerTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/impl/FtpRequestImplTest.java b/core/src/test/java/org/apache/ftpserver/impl/FtpRequestImplTest.java index a8644758..812c28c6 100644 --- a/core/src/test/java/org/apache/ftpserver/impl/FtpRequestImplTest.java +++ b/core/src/test/java/org/apache/ftpserver/impl/FtpRequestImplTest.java @@ -23,9 +23,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpRequestImplTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/impl/FtpStatisticsImplTest.java b/core/src/test/java/org/apache/ftpserver/impl/FtpStatisticsImplTest.java index 917cc949..707e8c2a 100644 --- a/core/src/test/java/org/apache/ftpserver/impl/FtpStatisticsImplTest.java +++ b/core/src/test/java/org/apache/ftpserver/impl/FtpStatisticsImplTest.java @@ -22,9 +22,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class FtpStatisticsImplTest extends ServerFtpStatisticsTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/impl/PassivePortsTest.java b/core/src/test/java/org/apache/ftpserver/impl/PassivePortsTest.java index 06c21c15..3c48944a 100644 --- a/core/src/test/java/org/apache/ftpserver/impl/PassivePortsTest.java +++ b/core/src/test/java/org/apache/ftpserver/impl/PassivePortsTest.java @@ -19,32 +19,37 @@ package org.apache.ftpserver.impl; +import java.io.IOException; +import java.net.ServerSocket; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.AssertionFailedError; import junit.framework.TestCase; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ +* @author Apache MINA Project * */ public class PassivePortsTest extends TestCase { public void testParseSingleValue() { - PassivePorts ports = new PassivePorts("123"); + PassivePorts ports = new PassivePorts("123", false); assertEquals(123, ports.reserveNextPort()); assertEquals(-1, ports.reserveNextPort()); } public void testParseMaxValue() { - PassivePorts ports = new PassivePorts("65535"); + PassivePorts ports = new PassivePorts("65535", false); assertEquals(65535, ports.reserveNextPort()); assertEquals(-1, ports.reserveNextPort()); } public void testParseMinValue() { - PassivePorts ports = new PassivePorts("0"); + PassivePorts ports = new PassivePorts("0", false); assertEquals(0, ports.reserveNextPort()); assertEquals(0, ports.reserveNextPort()); @@ -55,7 +60,7 @@ public void testParseMinValue() { public void testParseTooLargeValue() { try { - new PassivePorts("65536"); + new PassivePorts("65536", false); fail("Must fail due to too high port number"); } catch (IllegalArgumentException e) { // ok @@ -64,144 +69,115 @@ public void testParseTooLargeValue() { public void testParseNonNumericValue() { try { - new PassivePorts("foo"); + new PassivePorts("foo", false); fail("Must fail due to non numerical port number"); } catch (IllegalArgumentException e) { // ok } } + + private void assertContains( List valid, Integer testVal ){ + if( !valid.remove(testVal) ){ + throw new AssertionFailedError( "Did not find "+testVal+" in valid list "+valid ); + } + } + + private void assertReserveAll(String portString, int... validPorts) { + PassivePorts ports = new PassivePorts(portString, false); + + List valid = valid(validPorts); - public void testParseListOfValues() { - PassivePorts ports = new PassivePorts("123, 456,\t\n789"); - - assertEquals(123, ports.reserveNextPort()); - assertEquals(456, ports.reserveNextPort()); - assertEquals(789, ports.reserveNextPort()); + int len = valid.size(); + for(int i = 0; i valid(int... ints) { + List valid = new ArrayList(); + for(int i : ints) { + valid.add(i); + } + return valid; + } - assertEquals(123, ports.reserveNextPort()); - assertEquals(789, ports.reserveNextPort()); - assertEquals(456, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + public void testParseListOfValues() { + assertReserveAll("123, 456,\t\n789", 123, 456, 789); } public void testParseListOfValuesDuplicate() { - PassivePorts ports = new PassivePorts("123, 789, 456, 789"); - - assertEquals(123, ports.reserveNextPort()); - assertEquals(789, ports.reserveNextPort()); - assertEquals(456, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + assertReserveAll("123, 789, 456, 789", 123, 456, 789); } public void testParseSimpleRange() { - PassivePorts ports = new PassivePorts("123-125"); - - assertEquals(123, ports.reserveNextPort()); - assertEquals(124, ports.reserveNextPort()); - assertEquals(125, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + assertReserveAll("123-125", 123, 124, 125); } public void testParseMultipleRanges() { - PassivePorts ports = new PassivePorts("123-125, 127-128, 130-132"); - - assertEquals(123, ports.reserveNextPort()); - assertEquals(124, ports.reserveNextPort()); - assertEquals(125, ports.reserveNextPort()); - assertEquals(127, ports.reserveNextPort()); - assertEquals(128, ports.reserveNextPort()); - assertEquals(130, ports.reserveNextPort()); - assertEquals(131, ports.reserveNextPort()); - assertEquals(132, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + assertReserveAll("123-125, 127-128, 130-132", 123, 124, 125, 127, 128, 130, 131, 132); } public void testParseMixedRangeAndSingle() { - PassivePorts ports = new PassivePorts("123-125, 126, 128-129"); - - assertEquals(123, ports.reserveNextPort()); - assertEquals(124, ports.reserveNextPort()); - assertEquals(125, ports.reserveNextPort()); - assertEquals(126, ports.reserveNextPort()); - assertEquals(128, ports.reserveNextPort()); - assertEquals(129, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + assertReserveAll("123-125, 126, 128-129", 123, 124, 125, 126, 128, 129); } public void testParseOverlapingRanges() { - PassivePorts ports = new PassivePorts("123-125, 124-126"); - - assertEquals(123, ports.reserveNextPort()); - assertEquals(124, ports.reserveNextPort()); - assertEquals(125, ports.reserveNextPort()); - assertEquals(126, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + assertReserveAll("123-125, 124-126", 123, 124, 125, 126); } public void testParseOverlapingRangesorder() { - PassivePorts ports = new PassivePorts("124-126, 123-125"); - - assertEquals(124, ports.reserveNextPort()); - assertEquals(125, ports.reserveNextPort()); - assertEquals(126, ports.reserveNextPort()); - assertEquals(123, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + assertReserveAll("124-126, 123-125", 123, 124, 125, 126); } public void testParseOpenLowerRange() { - PassivePorts ports = new PassivePorts("9, -3"); - - assertEquals(9, ports.reserveNextPort()); - assertEquals(1, ports.reserveNextPort()); - assertEquals(2, ports.reserveNextPort()); - assertEquals(3, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + assertReserveAll("9, -3", 1, 2, 3, 9); } public void testParseOpenUpperRange() { - PassivePorts ports = new PassivePorts("65533-"); - - assertEquals(65533, ports.reserveNextPort()); - assertEquals(65534, ports.reserveNextPort()); - assertEquals(65535, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + assertReserveAll("65533-", 65533, 65534, 65535); } public void testParseOpenUpperRange3() { - PassivePorts ports = new PassivePorts("65533-, 65532-"); - - assertEquals(65533, ports.reserveNextPort()); - assertEquals(65534, ports.reserveNextPort()); - assertEquals(65535, ports.reserveNextPort()); - assertEquals(65532, ports.reserveNextPort()); - assertEquals(-1, ports.reserveNextPort()); + assertReserveAll("65533-, 65532-", 65532, 65533, 65534, 65535); } public void testParseOpenUpperRange2() { - PassivePorts ports = new PassivePorts("65533-, 1"); + assertReserveAll("65533-, 1", 1, 65533, 65534, 65535); + } + + public void testReserveNextPortBound() throws IOException { + ServerSocket ss = new ServerSocket(0); + + PassivePorts ports = new PassivePorts(Integer.toString(ss.getLocalPort()), true); - assertEquals(65533, ports.reserveNextPort()); - assertEquals(65534, ports.reserveNextPort()); - assertEquals(65535, ports.reserveNextPort()); - assertEquals(1, ports.reserveNextPort()); assertEquals(-1, ports.reserveNextPort()); + + ss.close(); + + assertEquals(ss.getLocalPort(), ports.reserveNextPort()); } + public void testParseRelease() { - PassivePorts ports = new PassivePorts("123, 456,789"); + PassivePorts ports = new PassivePorts("123, 456,789", false); - assertEquals(123, ports.reserveNextPort()); - assertEquals(456, ports.reserveNextPort()); - ports.releasePort(456); - assertEquals(456, ports.reserveNextPort()); + List valid = valid(123, 456, 789); + + assertContains(valid, ports.reserveNextPort()); + + int port = ports.reserveNextPort(); + assertContains(valid, port); + ports.releasePort(port); + valid.add(port); + assertContains(valid, ports.reserveNextPort()); + + assertContains(valid, ports.reserveNextPort()); - assertEquals(789, ports.reserveNextPort()); assertEquals(-1, ports.reserveNextPort()); + assertEquals(0, valid.size()); } -} +} \ No newline at end of file diff --git a/core/src/test/java/org/apache/ftpserver/impl/ServerFtpStatisticsTestTemplate.java b/core/src/test/java/org/apache/ftpserver/impl/ServerFtpStatisticsTestTemplate.java index e92b8166..983e21ba 100644 --- a/core/src/test/java/org/apache/ftpserver/impl/ServerFtpStatisticsTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/impl/ServerFtpStatisticsTestTemplate.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public abstract class ServerFtpStatisticsTestTemplate extends TestCase { 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 cbefd3b8..a8406fab 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/ExplicitSecurityTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/ExplicitSecurityTestTemplate.java @@ -29,9 +29,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public abstract class ExplicitSecurityTestTemplate extends SSLTestTemplate { @@ -47,12 +45,19 @@ protected void setUp() throws Exception { client.login(ADMIN_USERNAME, ADMIN_PASSWORD); } + protected boolean expectDataConnectionSecure() { + return getAuthValue().equals("SSL") && !useImplicit(); + } + /** * Tests that we can send command over the command channel. This is, in fact * already tested by login in setup but an explicit test is good anyways. */ public void testCommandChannel() throws Exception { assertTrue(getActiveSession().isSecure()); + + assertEquals(expectDataConnectionSecure(), getActiveSession().getDataConnection().isSecure()); + assertTrue(FTPReply.isPositiveCompletion(client.noop())); } diff --git a/core/src/test/java/org/apache/ftpserver/ssl/ImplicitSecurityTestTemplate.java b/core/src/test/java/org/apache/ftpserver/ssl/ImplicitSecurityTestTemplate.java index 00ae3c1a..009c4459 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/ImplicitSecurityTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/ImplicitSecurityTestTemplate.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public abstract class ImplicitSecurityTestTemplate extends ExplicitSecurityTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/ssl/MinaCipherSuitesTest.java b/core/src/test/java/org/apache/ftpserver/ssl/MinaCipherSuitesTest.java index 236dedd5..289a0bff 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/MinaCipherSuitesTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/MinaCipherSuitesTest.java @@ -1,88 +1,82 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.ftpserver.ssl; - -import javax.net.ssl.SSLHandshakeException; - -import org.apache.commons.net.ftp.FTPSClient; -import org.apache.ftpserver.FtpServerFactory; -import org.apache.ftpserver.impl.DefaultFtpServerContext; -import org.apache.ftpserver.impl.DefaultFtpServer; -import org.apache.ftpserver.listener.nio.NioListener; -import org.apache.ftpserver.ssl.impl.DefaultSslConfiguration; - -/** -* -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* -*/ -public class MinaCipherSuitesTest extends SSLTestTemplate { - - protected String getAuthValue() { - return "TLS"; - } - - protected boolean useImplicit() { - return true; - } - - protected SslConfigurationFactory createSslConfiguration() { - SslConfigurationFactory sslConfigFactory = super.createSslConfiguration(); - - sslConfigFactory - .setEnabledCipherSuites(new String[] { "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA" }); - - return sslConfigFactory; - } - - protected FTPSClient createFTPClient() throws Exception { - return new FTPSClient(true); - } - - protected boolean isConnectClient() { - return false; - } - - /* - * Only certain cipher suites will work with the keys and protocol we're - * using for this test. Two suites known to work is: - * SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA - */ - public void testEnabled() throws Exception { - - ((FTPSClient) client) - .setEnabledCipherSuites(new String[] { "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA" }); - - connectClient(); - } - - public void testDisabled() throws Exception { - ((FTPSClient) client) - .setEnabledCipherSuites(new String[] { "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" }); - - try { - doConnect(); - fail("Must throw SSLHandshakeException"); - } catch (SSLHandshakeException e) { - // OK - } - } -} +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.ftpserver.ssl; + +import javax.net.ssl.SSLHandshakeException; + +import org.apache.commons.net.ftp.FTPSClient; + +/** +* +* @author Apache MINA Project +* +*/ +public class MinaCipherSuitesTest extends SSLTestTemplate { + + protected String getAuthValue() { + return "TLS"; + } + + protected boolean useImplicit() { + return true; + } + + protected SslConfigurationFactory createSslConfiguration() { + SslConfigurationFactory sslConfigFactory = super.createSslConfiguration(); + + sslConfigFactory + .setEnabledCipherSuites(new String[] { "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA" }); + + return sslConfigFactory; + } + + protected FTPSClient createFTPClient() throws Exception { + return new FTPSClient(true); + } + + protected boolean isConnectClient() { + return false; + } + + /* + * Only certain cipher suites will work with the keys and protocol we're + * using for this test. Two suites known to work is: + * SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA + */ + public void testEnabled() throws Exception { + + ((FTPSClient) client) + .setEnabledCipherSuites(new String[] { "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA" }); + + connectClient(); + } + + public void testDisabled() throws Exception { + ((FTPSClient) client) + .setEnabledCipherSuites(new String[] { "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" }); + + try { + doConnect(); + fail("Must throw SSLHandshakeException"); + } catch (SSLHandshakeException e) { + // OK + } + } +} diff --git a/core/src/test/java/org/apache/ftpserver/ssl/MinaClientAuthTest.java b/core/src/test/java/org/apache/ftpserver/ssl/MinaClientAuthTest.java index c8c66f94..a624f833 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/MinaClientAuthTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/MinaClientAuthTest.java @@ -31,9 +31,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MinaClientAuthTest extends SSLTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/ssl/MinaExplicitSSLTest.java b/core/src/test/java/org/apache/ftpserver/ssl/MinaExplicitSSLTest.java index 891365c4..e720025a 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/MinaExplicitSSLTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/MinaExplicitSSLTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MinaExplicitSSLTest extends ExplicitSecurityTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/ssl/MinaExplicitTLSTest.java b/core/src/test/java/org/apache/ftpserver/ssl/MinaExplicitTLSTest.java index 7a1cd031..d7a49440 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/MinaExplicitTLSTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/MinaExplicitTLSTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MinaExplicitTLSTest extends ExplicitSecurityTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitClientAuthTest.java b/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitClientAuthTest.java index 345dbba2..394c693d 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitClientAuthTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitClientAuthTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MinaImplicitClientAuthTest extends MinaClientAuthTest { diff --git a/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitDataChannelTest.java b/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitDataChannelTest.java index 928d96e0..52d7788c 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitDataChannelTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitDataChannelTest.java @@ -34,8 +34,7 @@ import org.apache.ftpserver.impl.ServerDataConnectionFactory; /** -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ +* @author Apache MINA Project */ public class MinaImplicitDataChannelTest extends ImplicitSecurityTestTemplate { @@ -58,6 +57,10 @@ protected boolean useImplicit() { return true; } + protected boolean expectDataConnectionSecure() { + return true; + } + /** * Simple test that the {@link ServerDataConnectionFactory#isSecure()} * works as expected diff --git a/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitSSLTest.java b/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitSSLTest.java index b2c3e74f..a5895e61 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitSSLTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitSSLTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MinaImplicitSSLTest extends ImplicitSecurityTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitTLSTest.java b/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitTLSTest.java index 5212647d..a5546d12 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitTLSTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/MinaImplicitTLSTest.java @@ -21,9 +21,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class MinaImplicitTLSTest extends ImplicitSecurityTestTemplate { 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 b383a8c2..b79d9686 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/SSLTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/SSLTestTemplate.java @@ -31,21 +31,15 @@ import javax.net.ssl.TrustManagerFactory; import org.apache.commons.net.ftp.FTPSClient; -import org.apache.ftpserver.DataConnectionConfigurationFactory; import org.apache.ftpserver.FtpServerFactory; import org.apache.ftpserver.clienttests.ClientTestTemplate; -import org.apache.ftpserver.impl.DefaultDataConnectionConfiguration; -import org.apache.ftpserver.impl.DefaultFtpServerContext; -import org.apache.ftpserver.impl.DefaultFtpServer; import org.apache.ftpserver.listener.ListenerFactory; import org.apache.ftpserver.test.TestUtil; import org.apache.ftpserver.util.IoUtils; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public abstract class SSLTestTemplate extends ClientTestTemplate { @@ -104,12 +98,12 @@ protected FTPSClient createFTPClient() throws Exception { // initialize key manager factory KeyManagerFactory keyManagerFactory = KeyManagerFactory - .getInstance("SunX509"); + .getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(store, KEYSTORE_PASSWORD.toCharArray()); // initialize trust manager factory TrustManagerFactory trustManagerFactory = TrustManagerFactory - .getInstance("SunX509"); + .getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(store); @@ -122,6 +116,10 @@ protected FTPSClient createFTPClient() throws Exception { String auth = getAuthValue(); if (auth != null) { ftpsClient.setAuthValue(auth); + + if(auth.equals("SSL")) { + ftpsClient.setEnabledProtocols(new String[]{"SSLv3"}); + } } return ftpsClient; } diff --git a/core/src/test/java/org/apache/ftpserver/ssl/impl/AliasKeymanagerTest.java b/core/src/test/java/org/apache/ftpserver/ssl/impl/AliasKeymanagerTest.java index c5417c84..9ee1a378 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/impl/AliasKeymanagerTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/impl/AliasKeymanagerTest.java @@ -29,9 +29,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class AliasKeymanagerTest extends TestCase { @@ -44,7 +42,7 @@ protected void setUp() throws Exception { "src/test/resources/keymanager-test.jks"); ks.load(fis, "".toCharArray()); - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, "".toCharArray()); km = kmf.getKeyManagers()[0]; diff --git a/core/src/test/java/org/apache/ftpserver/ssl/impl/ExtendedAliasKeymanagerTest.java b/core/src/test/java/org/apache/ftpserver/ssl/impl/ExtendedAliasKeymanagerTest.java index 2c23b7c9..4bccdc3c 100644 --- a/core/src/test/java/org/apache/ftpserver/ssl/impl/ExtendedAliasKeymanagerTest.java +++ b/core/src/test/java/org/apache/ftpserver/ssl/impl/ExtendedAliasKeymanagerTest.java @@ -29,9 +29,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ExtendedAliasKeymanagerTest extends TestCase { @@ -44,7 +42,7 @@ protected void setUp() throws Exception { "src/test/resources/keymanager-test.jks"); ks.load(fis, "".toCharArray()); - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, "".toCharArray()); km = kmf.getKeyManagers()[0]; 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 ddd124db..c66dbbf6 100644 --- a/core/src/test/java/org/apache/ftpserver/test/TestUtil.java +++ b/core/src/test/java/org/apache/ftpserver/test/TestUtil.java @@ -37,9 +37,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class TestUtil { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/UsernamePasswordAuthenticationTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/UsernamePasswordAuthenticationTest.java index 8539c411..f4b01eb6 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/UsernamePasswordAuthenticationTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/UsernamePasswordAuthenticationTest.java @@ -19,15 +19,11 @@ package org.apache.ftpserver.usermanager; -import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication; - import junit.framework.TestCase; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class UsernamePasswordAuthenticationTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/BaseUserTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/BaseUserTest.java index c85f9233..f315e277 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/BaseUserTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/BaseUserTest.java @@ -26,13 +26,10 @@ import org.apache.ftpserver.ftplet.Authority; import org.apache.ftpserver.ftplet.AuthorizationRequest; -import org.apache.ftpserver.usermanager.impl.BaseUser; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class BaseUserTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/ClearTextDbUserManagerTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/ClearTextDbUserManagerTest.java index b8c88768..945873df 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/ClearTextDbUserManagerTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/ClearTextDbUserManagerTest.java @@ -29,9 +29,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ClearTextDbUserManagerTest extends DbUserManagerTest { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/ClearTextPasswordEncryptorTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/ClearTextPasswordEncryptorTest.java index d899bf62..da60ffe8 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/ClearTextPasswordEncryptorTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/ClearTextPasswordEncryptorTest.java @@ -26,9 +26,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ClearTextPasswordEncryptorTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginPermissionTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginPermissionTest.java index 129b7e7f..0b913ccc 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginPermissionTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/ConcurrentLoginPermissionTest.java @@ -21,14 +21,9 @@ import junit.framework.TestCase; -import org.apache.ftpserver.usermanager.impl.ConcurrentLoginPermission; -import org.apache.ftpserver.usermanager.impl.ConcurrentLoginRequest; - /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class ConcurrentLoginPermissionTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/DbUserManagerTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/DbUserManagerTest.java index 94002a26..733a1f4f 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/DbUserManagerTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/DbUserManagerTest.java @@ -33,9 +33,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class DbUserManagerTest extends UserManagerTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/Md5PasswordEncryptorTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/Md5PasswordEncryptorTest.java index 59d83fdf..8ce31a4b 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/Md5PasswordEncryptorTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/Md5PasswordEncryptorTest.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class Md5PasswordEncryptorTest extends ClearTextPasswordEncryptorTest { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManagerTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManagerTest.java index a631ffb6..3f860621 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManagerTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/PropertiesUserManagerTest.java @@ -35,9 +35,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class PropertiesUserManagerTest extends UserManagerTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/SaltedPasswordEncryptorTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/SaltedPasswordEncryptorTest.java index adddfc8d..1dd46920 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/SaltedPasswordEncryptorTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/SaltedPasswordEncryptorTest.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class SaltedPasswordEncryptorTest extends ClearTextPasswordEncryptorTest { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/UserManagerTestTemplate.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/UserManagerTestTemplate.java index 640540a0..719afd74 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/UserManagerTestTemplate.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/UserManagerTestTemplate.java @@ -31,19 +31,10 @@ import org.apache.ftpserver.ftplet.UserManager; import org.apache.ftpserver.usermanager.UserManagerFactory; import org.apache.ftpserver.usermanager.UsernamePasswordAuthentication; -import org.apache.ftpserver.usermanager.impl.BaseUser; -import org.apache.ftpserver.usermanager.impl.ConcurrentLoginPermission; -import org.apache.ftpserver.usermanager.impl.ConcurrentLoginRequest; -import org.apache.ftpserver.usermanager.impl.TransferRatePermission; -import org.apache.ftpserver.usermanager.impl.TransferRateRequest; -import org.apache.ftpserver.usermanager.impl.WritePermission; -import org.apache.ftpserver.usermanager.impl.WriteRequest; /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public abstract class UserManagerTestTemplate extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/VolatilePropertiesUserManagerTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/VolatilePropertiesUserManagerTest.java index 2211eb9b..90b8dec4 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/VolatilePropertiesUserManagerTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/VolatilePropertiesUserManagerTest.java @@ -30,9 +30,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class VolatilePropertiesUserManagerTest extends UserManagerTestTemplate { diff --git a/core/src/test/java/org/apache/ftpserver/usermanager/impl/WritePermissionTest.java b/core/src/test/java/org/apache/ftpserver/usermanager/impl/WritePermissionTest.java index 0772b909..14aebea9 100644 --- a/core/src/test/java/org/apache/ftpserver/usermanager/impl/WritePermissionTest.java +++ b/core/src/test/java/org/apache/ftpserver/usermanager/impl/WritePermissionTest.java @@ -21,14 +21,9 @@ import junit.framework.TestCase; -import org.apache.ftpserver.usermanager.impl.WritePermission; -import org.apache.ftpserver.usermanager.impl.WriteRequest; - /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class WritePermissionTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/util/BasePropertiesTest.java b/core/src/test/java/org/apache/ftpserver/util/BasePropertiesTest.java index 76d69746..517c04dd 100644 --- a/core/src/test/java/org/apache/ftpserver/util/BasePropertiesTest.java +++ b/core/src/test/java/org/apache/ftpserver/util/BasePropertiesTest.java @@ -33,9 +33,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class BasePropertiesTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/util/EncryptUtilsTest.java b/core/src/test/java/org/apache/ftpserver/util/EncryptUtilsTest.java index 72a18842..aa59a14c 100644 --- a/core/src/test/java/org/apache/ftpserver/util/EncryptUtilsTest.java +++ b/core/src/test/java/org/apache/ftpserver/util/EncryptUtilsTest.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class EncryptUtilsTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/util/RegularExprTest.java b/core/src/test/java/org/apache/ftpserver/util/RegularExprTest.java index 141e83f1..08c96bf5 100644 --- a/core/src/test/java/org/apache/ftpserver/util/RegularExprTest.java +++ b/core/src/test/java/org/apache/ftpserver/util/RegularExprTest.java @@ -23,9 +23,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class RegularExprTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/util/SocketAddressEncoderTest.java b/core/src/test/java/org/apache/ftpserver/util/SocketAddressEncoderTest.java index 69ef5ceb..1c812531 100644 --- a/core/src/test/java/org/apache/ftpserver/util/SocketAddressEncoderTest.java +++ b/core/src/test/java/org/apache/ftpserver/util/SocketAddressEncoderTest.java @@ -25,9 +25,7 @@ /** * -* @author The Apache MINA Project (dev@mina.apache.org) -* @version $Rev$, $Date$ -* +* @author Apache MINA Project* */ public class SocketAddressEncoderTest extends TestCase { diff --git a/core/src/test/resources/users.properties b/core/src/test/resources/users.properties index 7cf2ec20..348eef86 100644 --- a/core/src/test/resources/users.properties +++ b/core/src/test/resources/users.properties @@ -1,53 +1,57 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -#Generated file - don't edit (please) -#Wed Feb 07 20:58:22 CET 2007 - -ftpserver.user.admin.userpassword=admin -ftpserver.user.admin.homedirectory=./test-tmp/ftproot -ftpserver.user.admin.maxloginperip=0 -ftpserver.user.admin.idletime=0 -ftpserver.user.admin.enableflag=true -ftpserver.user.admin.writepermission=true -ftpserver.user.admin.maxloginnumber=0 -ftpserver.user.admin.uploadrate=0 -ftpserver.user.admin.downloadrate=0 - -ftpserver.user.testuser1.homedirectory=./test-tmp/ftproot -ftpserver.user.testuser1.maxloginnumber=3 -ftpserver.user.testuser1.writepermission=true -ftpserver.user.testuser1.userpassword=password - -ftpserver.user.testuser2.userpassword=password -ftpserver.user.testuser2.writepermission=true -ftpserver.user.testuser2.homedirectory=./test-tmp/ftproot -ftpserver.user.testuser2.maxloginperip=2 - -ftpserver.user.testuser3.userpassword= -ftpserver.user.testuser3.writepermission=true -ftpserver.user.testuser3.homedirectory=./test-tmp/ftproot - -ftpserver.user.anonymous.userpassword= -ftpserver.user.anonymous.maxloginperip=2 -ftpserver.user.anonymous.uploadrate=4800 -ftpserver.user.anonymous.writepermission=false -ftpserver.user.anonymous.maxloginnumber=20 -ftpserver.user.anonymous.enableflag=true -ftpserver.user.anonymous.homedirectory=./test-tmp/ftproot -ftpserver.user.anonymous.idletime=300 -ftpserver.user.anonymous.downloadrate=4800 +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +#Generated file - don't edit (please) +#Wed Feb 07 20:58:22 CET 2007 + +ftpserver.user.admin.userpassword=admin +ftpserver.user.admin.homedirectory=./test-tmp/ftproot +ftpserver.user.admin.maxloginperip=0 +ftpserver.user.admin.idletime=0 +ftpserver.user.admin.enableflag=true +ftpserver.user.admin.writepermission=true +ftpserver.user.admin.maxloginnumber=0 +ftpserver.user.admin.uploadrate=0 +ftpserver.user.admin.downloadrate=0 + +ftpserver.user.testuser1.homedirectory=./test-tmp/ftproot +ftpserver.user.testuser1.maxloginnumber=3 +ftpserver.user.testuser1.writepermission=true +ftpserver.user.testuser1.userpassword=password + +ftpserver.user.testuser2.userpassword=password +ftpserver.user.testuser2.writepermission=true +ftpserver.user.testuser2.homedirectory=./test-tmp/ftproot +ftpserver.user.testuser2.maxloginperip=2 + +ftpserver.user.testuser3.userpassword= +ftpserver.user.testuser3.writepermission=true +ftpserver.user.testuser3.homedirectory=./test-tmp/ftproot + +ftpserver.user.testuser4.userpassword=password +ftpserver.user.testuser4.enableflag=false +ftpserver.user.testuser4.homedirectory=./test-tmp/ftproot + +ftpserver.user.anonymous.userpassword= +ftpserver.user.anonymous.maxloginperip=2 +ftpserver.user.anonymous.uploadrate=4800 +ftpserver.user.anonymous.writepermission=false +ftpserver.user.anonymous.maxloginnumber=20 +ftpserver.user.anonymous.enableflag=true +ftpserver.user.anonymous.homedirectory=./test-tmp/ftproot +ftpserver.user.anonymous.idletime=300 +ftpserver.user.anonymous.downloadrate=4800 diff --git a/distribution/LICENSE.springframework.txt b/distribution/LICENSE.springframework.txt index 32af2891..66a27ec5 100644 --- a/distribution/LICENSE.springframework.txt +++ b/distribution/LICENSE.springframework.txt @@ -1,177 +1,177 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/distribution/README.txt b/distribution/README.txt index a619f405..e609542b 100644 --- a/distribution/README.txt +++ b/distribution/README.txt @@ -1,5 +1,5 @@ The Apache FtpServer project team is proud to announce the release of -Apache FtpServer, version 1.0-M2 +Apache FtpServer, version 1.0.4 The Apache FTP Server is a 100% pure Java FTP server. It's designed to be a complete and portable FTP server engine solution based on currently @@ -13,11 +13,61 @@ you write Java code to process FTP event notifications that we call the Ftplet API. Apache FtpServer provides an implementation of FTP server to support this API. -1.0-M2 +1.0.6 -------------------------------- -This is the very first release of Apache FtpServer. +Bug fix release which closes 19 issues since the 1.0.5 release, for example an overhaul of the passive port reservation handling. See full change log at: https://issues.apache.org/jira/browse/FTPSERVER/fixforversion/12315314 + +1.0.5 +-------------------------------- +Bug fix release that fixes important issues found since the 1.0.4 release. +See full change log at https://issues.apache.org/jira/browse/FTPSERVER/fixforversion/12314821 + +1.0.4 +-------------------------------- +Bug fix release that fixes important issues found since the 1.0.3 release. +See full change log at https://issues.apache.org/jira/browse/FTPSERVER/fixforversion/12314283 + +1.0.3 +-------------------------------- +Bug fix release that fixes important issues found since the 1.0.2 release. +See full change log at https://issues.apache.org/jira/browse/FTPSERVER/fixforversion/12314039 + +1.0.2 +-------------------------------- +Bug fix release that fixes important issues found since the 1.0.1 release. +See full change log at https://issues.apache.org/jira/browse/FTPSERVER/fixforversion/12313952 + +1.0.1 +-------------------------------- +Bug fix release that fixes important issues found since the 1.0.0 release. https://issues.apache.org/jira/browse/FTPSERVER/fixforversion/12313619 +1.0.0 +-------------------------------- +This is the first major release of FtpServer and we now recommend this version +for production usage. The release contains a few minor bug fixes found since the +last release candidate. + +1.0.0-RC2 +-------------------------------- +The release contains fixes to a small set of bugs found in 1.0.0-RC1. -The Apache Incubator FtpServer project team is always open for your feedback. -Please let us know what you think about FtpServer via our mailing -list +1.0.0-RC1 +-------------------------------- +This release focuses on stabilizing the code base and fixing reported bugs. No major +additions or other improvements was included in this version. + +1.0.0-M4 +-------------------------------- +The FtpServer API is now stabilized for the upcoming 1.0.0 release. The release +also contains a large number of bug fixes and minor improvements as well as +complete Javadoc documentation for our API. + +1.0.0-M3 +-------------------------------- +This release fixes a number of bugs found since the release of 1.0.0-M2. +We have also made some major improvements, especially to Ftplets which are now +able to intercept any FTP command. + +1.0.0-M2 +-------------------------------- +This is the very first release of Apache FtpServer. diff --git a/distribution/pom.xml b/distribution/pom.xml index 4b279999..bf8914c7 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -22,14 +22,14 @@ ftpserver-parent org.apache.ftpserver - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT 4.0.0 org.apache.ftpserver ftpserver pom Apache FtpServer - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT scm:svn:http://svn.apache.org/repos/asf/mina/ftpserver/trunk/distribution scm:svn:https://svn.apache.org/repos/asf/mina/ftpserver/trunk/distribution @@ -131,8 +131,8 @@ Downloading Manual - - + + diff --git a/distribution/res/conf/ftpd-full.xml b/distribution/res/conf/ftpd-full.xml index f17265bb..f31722ae 100644 --- a/distribution/res/conf/ftpd-full.xml +++ b/distribution/res/conf/ftpd-full.xml @@ -24,75 +24,80 @@ Use this section to define custom listeners, or to redefine the default listener, aptly named "default" --> - - + - - + - - - - + + + - - - 1.2.3.0/16, 1.2.4.0/16, 1.2.3.4 - - + + + 1.2.3.0/16, 1.2.4.0/16, 1.2.3.4 + + - - - - - - - + + + + + + + - - - - - - INSERT INTO FTP_USER (userid, userpassword, + - - - - - - + + + + + - + \ No newline at end of file diff --git a/distribution/res/conf/users.properties b/distribution/res/conf/users.properties index 9dc67144..f52442ef 100644 --- a/distribution/res/conf/users.properties +++ b/distribution/res/conf/users.properties @@ -1,37 +1,37 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# Password is "admin" -ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3 -ftpserver.user.admin.homedirectory=./res/home -ftpserver.user.admin.enableflag=true -ftpserver.user.admin.writepermission=true -ftpserver.user.admin.maxloginnumber=0 -ftpserver.user.admin.maxloginperip=0 -ftpserver.user.admin.idletime=0 -ftpserver.user.admin.uploadrate=0 -ftpserver.user.admin.downloadrate=0 - -ftpserver.user.anonymous.userpassword= -ftpserver.user.anonymous.homedirectory=./res/home -ftpserver.user.anonymous.enableflag=true -ftpserver.user.anonymous.writepermission=false -ftpserver.user.anonymous.maxloginnumber=20 -ftpserver.user.anonymous.maxloginperip=2 -ftpserver.user.anonymous.idletime=300 -ftpserver.user.anonymous.uploadrate=4800 -ftpserver.user.anonymous.downloadrate=4800 +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Password is "admin" +ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3 +ftpserver.user.admin.homedirectory=./res/home +ftpserver.user.admin.enableflag=true +ftpserver.user.admin.writepermission=true +ftpserver.user.admin.maxloginnumber=0 +ftpserver.user.admin.maxloginperip=0 +ftpserver.user.admin.idletime=0 +ftpserver.user.admin.uploadrate=0 +ftpserver.user.admin.downloadrate=0 + +ftpserver.user.anonymous.userpassword= +ftpserver.user.anonymous.homedirectory=./res/home +ftpserver.user.anonymous.enableflag=true +ftpserver.user.anonymous.writepermission=false +ftpserver.user.anonymous.maxloginnumber=20 +ftpserver.user.anonymous.maxloginperip=2 +ftpserver.user.anonymous.idletime=300 +ftpserver.user.anonymous.uploadrate=4800 +ftpserver.user.anonymous.downloadrate=4800 diff --git a/distribution/res/ftp-db.sql b/distribution/res/ftp-db.sql index 3f874ba1..8243b271 100644 --- a/distribution/res/ftp-db.sql +++ b/distribution/res/ftp-db.sql @@ -1,4 +1,4 @@ -managermanager-- Licensed to the Apache Software Foundation (ASF) under one +-- Licensed to the Apache Software Foundation (ASF) under one -- or more contributor license agreements. See the NOTICE file -- distributed with this work for additional information -- regarding copyright ownership. The ASF licenses this file diff --git a/distribution/res/ftpserver.jks b/distribution/res/ftpserver.jks index 5de00f92..c9487a9f 100644 Binary files a/distribution/res/ftpserver.jks and b/distribution/res/ftpserver.jks differ diff --git a/distribution/src/main/assemblies/bin.xml b/distribution/src/main/assemblies/bin.xml index e1ce61a0..61b7a3bf 100644 --- a/distribution/src/main/assemblies/bin.xml +++ b/distribution/src/main/assemblies/bin.xml @@ -22,6 +22,7 @@ zip tar.gz + tar.bz2 true diff --git a/distribution/src/main/assemblies/src.xml b/distribution/src/main/assemblies/src.xml index 75d4c77f..2e9b2338 100644 --- a/distribution/src/main/assemblies/src.xml +++ b/distribution/src/main/assemblies/src.xml @@ -22,6 +22,7 @@ zip tar.gz + tar.bz2 diff --git a/examples/ftpserver-example-spring-war/pom.xml b/examples/ftpserver-example-spring-war/pom.xml index 60449565..06127de3 100644 --- a/examples/ftpserver-example-spring-war/pom.xml +++ b/examples/ftpserver-example-spring-war/pom.xml @@ -18,7 +18,7 @@ ftpserver-parent org.apache.ftpserver - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT ../../pom.xml @@ -27,7 +27,7 @@ ftpserver-spring-war FtpServer Spring web project example war - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT org.springframework @@ -37,7 +37,7 @@ org.apache.ftpserver ftpserver-core - ${pom.version} + ${project.version} javax.servlet diff --git a/examples/ftpserver-example-spring-war/src/main/java/org/apache/ftpserver/example/springwar/FtpServerListener.java b/examples/ftpserver-example-spring-war/src/main/java/org/apache/ftpserver/example/springwar/FtpServerListener.java index 35b20ae2..5f2b8c92 100644 --- a/examples/ftpserver-example-spring-war/src/main/java/org/apache/ftpserver/example/springwar/FtpServerListener.java +++ b/examples/ftpserver-example-spring-war/src/main/java/org/apache/ftpserver/example/springwar/FtpServerListener.java @@ -26,6 +26,9 @@ import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +/** +* @author Apache MINA Project* +*/ public class FtpServerListener implements ServletContextListener { public static final String FTPSERVER_CONTEXT_NAME = "org.apache.ftpserver"; diff --git a/examples/ftpserver-example-spring-war/src/main/java/org/apache/ftpserver/example/springwar/FtpServerServlet.java b/examples/ftpserver-example-spring-war/src/main/java/org/apache/ftpserver/example/springwar/FtpServerServlet.java index 9abe0ff0..28622fff 100644 --- a/examples/ftpserver-example-spring-war/src/main/java/org/apache/ftpserver/example/springwar/FtpServerServlet.java +++ b/examples/ftpserver-example-spring-war/src/main/java/org/apache/ftpserver/example/springwar/FtpServerServlet.java @@ -29,6 +29,9 @@ import org.apache.ftpserver.FtpServer; +/** +* @author Apache MINA Project* +*/ public class FtpServerServlet extends HttpServlet { private static final long serialVersionUID = 5539642787624981705L; diff --git a/examples/ftpserver-example-spring-war/src/main/resources/users.properties b/examples/ftpserver-example-spring-war/src/main/resources/users.properties index 2aed0d15..52899ce7 100644 --- a/examples/ftpserver-example-spring-war/src/main/resources/users.properties +++ b/examples/ftpserver-example-spring-war/src/main/resources/users.properties @@ -1,37 +1,37 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# Password is "admin" -ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3 -ftpserver.user.admin.homedirectory=/tmp -ftpserver.user.admin.enableflag=true -ftpserver.user.admin.writepermission=true -ftpserver.user.admin.maxloginnumber=0 -ftpserver.user.admin.maxloginperip=0 -ftpserver.user.admin.idletime=0 -ftpserver.user.admin.uploadrate=0 -ftpserver.user.admin.downloadrate=0 - -ftpserver.user.anonymous.userpassword= -ftpserver.user.anonymous.homedirectory=/tmp -ftpserver.user.anonymous.enableflag=true -ftpserver.user.anonymous.writepermission=false -ftpserver.user.anonymous.maxloginnumber=20 -ftpserver.user.anonymous.maxloginperip=2 -ftpserver.user.anonymous.idletime=300 -ftpserver.user.anonymous.uploadrate=4800 -ftpserver.user.anonymous.downloadrate=4800 +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Password is "admin" +ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3 +ftpserver.user.admin.homedirectory=/tmp +ftpserver.user.admin.enableflag=true +ftpserver.user.admin.writepermission=true +ftpserver.user.admin.maxloginnumber=0 +ftpserver.user.admin.maxloginperip=0 +ftpserver.user.admin.idletime=0 +ftpserver.user.admin.uploadrate=0 +ftpserver.user.admin.downloadrate=0 + +ftpserver.user.anonymous.userpassword= +ftpserver.user.anonymous.homedirectory=/tmp +ftpserver.user.anonymous.enableflag=true +ftpserver.user.anonymous.writepermission=false +ftpserver.user.anonymous.maxloginnumber=20 +ftpserver.user.anonymous.maxloginperip=2 +ftpserver.user.anonymous.idletime=300 +ftpserver.user.anonymous.uploadrate=4800 +ftpserver.user.anonymous.downloadrate=4800 diff --git a/examples/ftpserver-osgi-ftplet-service/pom.xml b/examples/ftpserver-osgi-ftplet-service/pom.xml index 8b28132d..a3fef736 100644 --- a/examples/ftpserver-osgi-ftplet-service/pom.xml +++ b/examples/ftpserver-osgi-ftplet-service/pom.xml @@ -19,7 +19,7 @@ ftpserver-parent org.apache.ftpserver - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT ../../pom.xml 4.0.0 @@ -27,12 +27,12 @@ ftpserver-osgi-ftplet-service FtpServer OSGi Ftplet service example bundle - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT org.apache.ftpserver ftplet-api - ${pom.version} + ${project.version} org.osgi @@ -46,7 +46,7 @@ org.apache.felix maven-bundle-plugin - 1.4.1 + 2.3.4 true diff --git a/examples/ftpserver-osgi-ftplet-service/src/main/java/org/apache/ftpserver/example/ftpletservice/MyFtplet.java b/examples/ftpserver-osgi-ftplet-service/src/main/java/org/apache/ftpserver/example/ftpletservice/MyFtplet.java index 9bd4ef5f..5ed348b2 100644 --- a/examples/ftpserver-osgi-ftplet-service/src/main/java/org/apache/ftpserver/example/ftpletservice/MyFtplet.java +++ b/examples/ftpserver-osgi-ftplet-service/src/main/java/org/apache/ftpserver/example/ftpletservice/MyFtplet.java @@ -27,6 +27,9 @@ import org.apache.ftpserver.ftplet.FtpSession; import org.apache.ftpserver.ftplet.FtpletResult; +/** +* @author Apache MINA Project* +*/ public class MyFtplet extends DefaultFtplet { @Override diff --git a/examples/ftpserver-osgi-ftplet-service/src/main/java/org/apache/ftpserver/example/ftpletservice/impl/Activator.java b/examples/ftpserver-osgi-ftplet-service/src/main/java/org/apache/ftpserver/example/ftpletservice/impl/Activator.java index 3e69f7b4..61f0e6de 100644 --- a/examples/ftpserver-osgi-ftplet-service/src/main/java/org/apache/ftpserver/example/ftpletservice/impl/Activator.java +++ b/examples/ftpserver-osgi-ftplet-service/src/main/java/org/apache/ftpserver/example/ftpletservice/impl/Activator.java @@ -27,6 +27,9 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +/** +* @author Apache MINA Project* +*/ public class Activator implements BundleActivator { public void start(BundleContext context) throws Exception { diff --git a/examples/ftpserver-osgi-spring-service/pom.xml b/examples/ftpserver-osgi-spring-service/pom.xml index 7a4c3fcb..0992bbea 100644 --- a/examples/ftpserver-osgi-spring-service/pom.xml +++ b/examples/ftpserver-osgi-spring-service/pom.xml @@ -19,7 +19,7 @@ ftpserver-parent org.apache.ftpserver - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT ../../pom.xml 4.0.0 @@ -27,12 +27,12 @@ ftpserver-osgi-spring-service FtpServer OSGi Spring-DM example bundle - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT org.apache.ftpserver ftpserver-core - ${pom.version} + ${project.version} @@ -40,7 +40,7 @@ org.apache.felix maven-bundle-plugin - 1.4.1 + 2.3.4 true diff --git a/examples/ftpserver-osgi-spring-service/src/main/java/org/apache/ftpserver/example/osgiservice/impl/FtpServerLifecycle.java b/examples/ftpserver-osgi-spring-service/src/main/java/org/apache/ftpserver/example/osgiservice/impl/FtpServerLifecycle.java index 0e97a6ef..19794ddc 100644 --- a/examples/ftpserver-osgi-spring-service/src/main/java/org/apache/ftpserver/example/osgiservice/impl/FtpServerLifecycle.java +++ b/examples/ftpserver-osgi-spring-service/src/main/java/org/apache/ftpserver/example/osgiservice/impl/FtpServerLifecycle.java @@ -22,6 +22,9 @@ import org.apache.ftpserver.FtpServer; +/** +* @author Apache MINA Project* +*/ public class FtpServerLifecycle { private FtpServer server; diff --git a/examples/ftpserver-osgi-spring-service/src/main/resources/org/apache/ftpserver/example/osgiservice/users.properties b/examples/ftpserver-osgi-spring-service/src/main/resources/org/apache/ftpserver/example/osgiservice/users.properties index 2aed0d15..52899ce7 100644 --- a/examples/ftpserver-osgi-spring-service/src/main/resources/org/apache/ftpserver/example/osgiservice/users.properties +++ b/examples/ftpserver-osgi-spring-service/src/main/resources/org/apache/ftpserver/example/osgiservice/users.properties @@ -1,37 +1,37 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -# Password is "admin" -ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3 -ftpserver.user.admin.homedirectory=/tmp -ftpserver.user.admin.enableflag=true -ftpserver.user.admin.writepermission=true -ftpserver.user.admin.maxloginnumber=0 -ftpserver.user.admin.maxloginperip=0 -ftpserver.user.admin.idletime=0 -ftpserver.user.admin.uploadrate=0 -ftpserver.user.admin.downloadrate=0 - -ftpserver.user.anonymous.userpassword= -ftpserver.user.anonymous.homedirectory=/tmp -ftpserver.user.anonymous.enableflag=true -ftpserver.user.anonymous.writepermission=false -ftpserver.user.anonymous.maxloginnumber=20 -ftpserver.user.anonymous.maxloginperip=2 -ftpserver.user.anonymous.idletime=300 -ftpserver.user.anonymous.uploadrate=4800 -ftpserver.user.anonymous.downloadrate=4800 +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Password is "admin" +ftpserver.user.admin.userpassword=21232F297A57A5A743894A0E4A801FC3 +ftpserver.user.admin.homedirectory=/tmp +ftpserver.user.admin.enableflag=true +ftpserver.user.admin.writepermission=true +ftpserver.user.admin.maxloginnumber=0 +ftpserver.user.admin.maxloginperip=0 +ftpserver.user.admin.idletime=0 +ftpserver.user.admin.uploadrate=0 +ftpserver.user.admin.downloadrate=0 + +ftpserver.user.anonymous.userpassword= +ftpserver.user.anonymous.homedirectory=/tmp +ftpserver.user.anonymous.enableflag=true +ftpserver.user.anonymous.writepermission=false +ftpserver.user.anonymous.maxloginnumber=20 +ftpserver.user.anonymous.maxloginperip=2 +ftpserver.user.anonymous.idletime=300 +ftpserver.user.anonymous.uploadrate=4800 +ftpserver.user.anonymous.downloadrate=4800 diff --git a/examples/pom.xml b/examples/pom.xml index 5d446d7e..b7cc5230 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -21,14 +21,14 @@ ftpserver-parent org.apache.ftpserver - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT 4.0.0 - org.apache.ftpserverr + org.apache.ftpserver ftpserver-examples pom Apache FtpServer Examples - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT ftpserver-example-spring-war ftpserver-osgi-ftplet-service diff --git a/ftplet-api/pom.xml b/ftplet-api/pom.xml index 5b9a00c2..e4d0d5b0 100644 --- a/ftplet-api/pom.xml +++ b/ftplet-api/pom.xml @@ -17,12 +17,12 @@ ftpserver-parent org.apache.ftpserver - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT 4.0.0 org.apache.ftpserver ftplet-api - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT bundle Apache Ftplet API Ftplets are, similar to servlets, an API to plug into the @@ -46,13 +46,13 @@ org.apache.felix maven-bundle-plugin - 1.4.1 + 2.3.4 true ${artifactId} The Apache Software Foundation - org.apache.ftpserver.ftplet;version=${pom.version} + org.apache.ftpserver.ftplet;version=${project.version} diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Authentication.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Authentication.java index 46406c3d..296551a3 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Authentication.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Authentication.java @@ -23,8 +23,7 @@ * Represents a type of authentication request, typically anonymous or a * username and password combination * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface Authentication { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/AuthenticationFailedException.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/AuthenticationFailedException.java index 1ece1ed0..d9dc1c72 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/AuthenticationFailedException.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/AuthenticationFailedException.java @@ -22,8 +22,7 @@ /** * Thrown if an authentication request fails * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class AuthenticationFailedException extends FtpException { private static final long serialVersionUID = -1328383839915898987L; @@ -66,6 +65,6 @@ public AuthenticationFailedException(Throwable th) { * The original cause */ public AuthenticationFailedException(String msg, Throwable th) { - super(msg); + super(msg, th); } } diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Authority.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Authority.java index 86fd7643..42ae1b0a 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Authority.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Authority.java @@ -23,8 +23,7 @@ * Interface for an authority granted to the user, typical example is write * access or the number of concurrent logins * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface Authority { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/AuthorizationRequest.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/AuthorizationRequest.java index cdae3d60..e99d47a1 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/AuthorizationRequest.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/AuthorizationRequest.java @@ -22,8 +22,7 @@ /** * A request for authorization for a specific task, for example write access. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface AuthorizationRequest { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataConnection.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataConnection.java index 9281a891..9a8a5b5b 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataConnection.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataConnection.java @@ -25,8 +25,7 @@ /** * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface DataConnection { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataConnectionFactory.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataConnectionFactory.java index 71ebb41d..90a0cf2b 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataConnectionFactory.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataConnectionFactory.java @@ -21,8 +21,7 @@ /** * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface DataConnectionFactory { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataType.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataType.java index db48f4cc..89effc18 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataType.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DataType.java @@ -22,8 +22,7 @@ /** * Type safe enum for describing the data type * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public enum DataType { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DefaultFtpReply.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DefaultFtpReply.java index 285fce18..f8274a0a 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DefaultFtpReply.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DefaultFtpReply.java @@ -19,11 +19,11 @@ package org.apache.ftpserver.ftplet; + /** * FTP reply object. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultFtpReply implements FtpReply { @@ -73,6 +73,10 @@ public String getMessage() { return message; } + private boolean isDigit(char c) { + return c >= 48 && c <= 57; + } + /* * (non-Javadoc) * @@ -87,14 +91,23 @@ public String toString() { StringBuffer sb = new StringBuffer(); + // remove any carriage returns + notNullMessage = notNullMessage.replace("\r", ""); + + // remove trailing line feeds + if(notNullMessage.endsWith("\n")) { + notNullMessage = notNullMessage.substring(0, notNullMessage.length() - 1); + } + + String[] lines = notNullMessage.split("\n"); + // no newline - if (notNullMessage.indexOf('\n') == -1) { + if (lines.length == 1) { sb.append(code); sb.append(" "); sb.append(notNullMessage); sb.append(CRLF); } else { - String[] lines = notNullMessage.split("\n"); sb.append(code); sb.append("-"); @@ -107,6 +120,17 @@ public String toString() { sb.append(" "); } + // "If an intermediary line begins with a 3-digit number, the Server + // must pad the front to avoid confusion. + if(i > 0 + && i + 1 < lines.length + && line.length() > 2 + && isDigit(line.charAt(0)) + && isDigit(line.charAt(1)) + && isDigit(line.charAt(2)) + ) { + sb.append(" "); + } sb.append(line); sb.append(CRLF); } diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DefaultFtplet.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DefaultFtplet.java index 95514883..8e1d8e16 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DefaultFtplet.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/DefaultFtplet.java @@ -26,8 +26,7 @@ * just an empty implementation. You can derive your ftplet implementation from * this class. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DefaultFtplet implements Ftplet { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FileSystemFactory.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FileSystemFactory.java index 53b95a10..38e07abf 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FileSystemFactory.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FileSystemFactory.java @@ -22,8 +22,7 @@ /** * Factory for file system implementations - it returns the file system view for user. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FileSystemFactory { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FileSystemView.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FileSystemView.java index f9423938..95d88e98 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FileSystemView.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FileSystemView.java @@ -22,8 +22,7 @@ /** * This is an abstraction over the user file system view. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FileSystemView { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpException.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpException.java index f185b9be..67b156e3 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpException.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpException.java @@ -19,21 +19,16 @@ package org.apache.ftpserver.ftplet; -import java.io.PrintStream; -import java.io.PrintWriter; /** * Ftplet exception class. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class FtpException extends Exception { private static final long serialVersionUID = -1328383839915898987L; - private Throwable throwable = null; - /** * Default constructor. */ @@ -60,7 +55,6 @@ public FtpException(String msg) { */ public FtpException(Throwable th) { super(th.getMessage()); - throwable = th; } /** @@ -73,47 +67,14 @@ public FtpException(Throwable th) { */ public FtpException(String msg, Throwable th) { super(msg); - throwable = th; } /** * Get the root cause. * @return The root cause + * @deprecated Use {@link Exception#getCause()} instead */ public Throwable getRootCause() { - return throwable; - } - - /** - * Print stack trace. - */ - public void printStackTrace(PrintWriter pw) { - if (throwable == null) { - super.printStackTrace(pw); - } else { - throwable.printStackTrace(pw); - } - } - - /** - * Print stack trace. - */ - public void printStackTrace(PrintStream ps) { - if (throwable == null) { - super.printStackTrace(ps); - } else { - throwable.printStackTrace(ps); - } - } - - /** - * Print stack trace. - */ - public void printStackTrace() { - if (throwable == null) { - super.printStackTrace(); - } else { - throwable.printStackTrace(); - } + return getCause(); } } diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpFile.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpFile.java index 5fc5a6b3..343f994d 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpFile.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpFile.java @@ -28,8 +28,7 @@ /** * This is the file abstraction used by the server. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FtpFile { @@ -107,7 +106,7 @@ public interface FtpFile { int getLinkCount(); /** - * Get last modified time. + * Get last modified time in UTC. * @return The timestamp of the last modified time for the {@link FtpFile} */ long getLastModified(); diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpReply.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpReply.java index d61e587e..6081980d 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpReply.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpReply.java @@ -22,8 +22,7 @@ /** * Interface for a reply to an FTP request. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FtpReply { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpRequest.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpRequest.java index 5c31be32..a4fee35e 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpRequest.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpRequest.java @@ -22,8 +22,7 @@ /** * One FtpRequest made by the client. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FtpRequest { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpSession.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpSession.java index f7901481..793832d6 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpSession.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpSession.java @@ -32,8 +32,7 @@ * attributes set by setAttribute() will be always available later * unless that attribute is removed or the client disconnects. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FtpSession { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpStatistics.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpStatistics.java index 3d49a20e..39a95571 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpStatistics.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpStatistics.java @@ -25,8 +25,7 @@ /** * This interface holds all the ftp server statistical information. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FtpStatistics { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Ftplet.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Ftplet.java index 4702d3da..828ffac5 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Ftplet.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Ftplet.java @@ -44,8 +44,7 @@ * FtpletEnum.DEFAULT will be assumed. If any ftplet callback method throws * exception, that particular connection will be disconnected. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface Ftplet { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpletContext.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpletContext.java index a7f1e9a1..afe1742b 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpletContext.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpletContext.java @@ -24,8 +24,7 @@ * information to a ftplet during initialization. The configuration information * contains initialization parameters. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface FtpletContext { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpletResult.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpletResult.java index 9cd84737..fa653fa9 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpletResult.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/FtpletResult.java @@ -24,8 +24,7 @@ * * DEFAULT < NO_FTPLET < SKIP < DISCONNECT * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public enum FtpletResult { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Structure.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Structure.java index f1d7c16f..1a62481e 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Structure.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/Structure.java @@ -22,8 +22,7 @@ /** * Type safe enum for describing the structure * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public enum Structure { diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/User.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/User.java index c51c557b..0f94fb9b 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/User.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/User.java @@ -24,8 +24,7 @@ /** * Basic user interface. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface User { @@ -79,7 +78,7 @@ public interface User { boolean getEnabled(); /** - * gGet the user home directory + * Get the user home directory * @return The path to the home directory for the user */ String getHomeDirectory(); diff --git a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/UserManager.java b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/UserManager.java index f100af8b..16b35534 100644 --- a/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/UserManager.java +++ b/ftplet-api/src/main/java/org/apache/ftpserver/ftplet/UserManager.java @@ -22,8 +22,7 @@ /** * User manager interface. * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public interface UserManager { diff --git a/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/DataTypeTest.java b/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/DataTypeTest.java index d5b2e538..7e3826ec 100644 --- a/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/DataTypeTest.java +++ b/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/DataTypeTest.java @@ -23,8 +23,7 @@ /** * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class DataTypeTest extends TestCase { diff --git a/core/src/test/java/org/apache/ftpserver/impl/DefaultFtpReplyTest.java b/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/DefaultFtpReplyTest.java similarity index 62% rename from core/src/test/java/org/apache/ftpserver/impl/DefaultFtpReplyTest.java rename to ftplet-api/src/test/java/org/apache/ftpserver/ftplet/DefaultFtpReplyTest.java index f07ba5e6..8c61bbc4 100644 --- a/core/src/test/java/org/apache/ftpserver/impl/DefaultFtpReplyTest.java +++ b/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/DefaultFtpReplyTest.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.ftpserver.impl; +package org.apache.ftpserver.ftplet; import junit.framework.TestCase; @@ -25,8 +25,7 @@ /** * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project * */ public class DefaultFtpReplyTest extends TestCase { @@ -36,7 +35,19 @@ public void testSingleLineToString() { assertEquals("123 foo bar\r\n", response.toString()); } + + public void testSingleLineWithTrailingLineFeedToString() { + DefaultFtpReply response = new DefaultFtpReply(123, "foo bar\n"); + assertEquals("123 foo bar\r\n", response.toString()); + } + + public void testCarriageReturnToString() { + DefaultFtpReply response = new DefaultFtpReply(123, "foo \rbar\r\n"); + + assertEquals("123 foo bar\r\n", response.toString()); + } + public void testNullToString() { DefaultFtpReply response = new DefaultFtpReply(123, (String) null); @@ -73,4 +84,29 @@ public void testMultipleLinesToStringSpaceFirst() { assertEquals("123-foo\r\n bar\r\n123 baz\r\n", response.toString()); } + + public void testMultipleLinesToStringThreeNumbers() { + DefaultFtpReply response = new DefaultFtpReply(123, "foo\n234bar\nbaz"); + + assertEquals("123-foo\r\n 234bar\r\n123 baz\r\n", response.toString()); + } + + public void testMultipleLinesToStringThreeNumbersOnFirstLine() { + DefaultFtpReply response = new DefaultFtpReply(123, "234foo\nbar\nbaz"); + + assertEquals("123-234foo\r\nbar\r\n123 baz\r\n", response.toString()); + } + + public void testMultipleLinesToStringThreeNumbersOnLastLine() { + DefaultFtpReply response = new DefaultFtpReply(123, "foo\nbar\n234baz"); + + assertEquals("123-foo\r\nbar\r\n123 234baz\r\n", response.toString()); + } + + public void testMultipleLinesToStringSingleNumberOnLine() { + DefaultFtpReply response = new DefaultFtpReply(123, "foo\n2bar\nbaz"); + + assertEquals("123-foo\r\n2bar\r\n123 baz\r\n", response.toString()); + } + } diff --git a/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/ExampleFtplet.java b/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/ExampleFtplet.java index ff47f9d5..266a2968 100644 --- a/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/ExampleFtplet.java +++ b/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/ExampleFtplet.java @@ -23,8 +23,7 @@ /** * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class ExampleFtplet extends DefaultFtplet { diff --git a/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/StructureTest.java b/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/StructureTest.java index fb81e544..7c25ea4e 100644 --- a/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/StructureTest.java +++ b/ftplet-api/src/test/java/org/apache/ftpserver/ftplet/StructureTest.java @@ -23,8 +23,7 @@ /** * - * @author The Apache MINA Project (dev@mina.apache.org) - * @version $Rev$, $Date$ + * @author Apache MINA Project */ public class StructureTest extends TestCase { public void testParseF() { diff --git a/pom.xml b/pom.xml index 21153e81..f66956ba 100644 --- a/pom.xml +++ b/pom.xml @@ -7,28 +7,28 @@ to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations - under the License. --> + under the License. --> apache org.apache - 4 + 9 4.0.0 - org.apache.ftpserverr + org.apache.ftpserver ftpserver-parent pom Apache FtpServer Parent - 1.0.0-RC3-SNAPSHOT + 1.0.7-SNAPSHOT http://mina.apache.org/ftpserver Jira @@ -136,21 +136,21 @@ - ${groupId} + ${project.groupId} ftplet-api - ${pom.version} + ${project.version} - ${groupId} + ${project.groupId} ftpserver-core - ${pom.version} + ${project.version} org.apache.mina mina-core - 2.0.0-M4 + 2.0.4 org.easymock @@ -160,7 +160,7 @@ org.easymock easymockclassextension - + @@ -172,21 +172,21 @@ commons-logging commons-logging - - + + org.slf4j slf4j-api - 1.5.2 + 1.6.4 org.slf4j jcl-over-slf4j - 1.5.2 + 1.6.4 @@ -195,7 +195,7 @@ junit 3.8.2 - + commons-net commons-net @@ -205,9 +205,9 @@ org.slf4j slf4j-log4j12 - 1.5.2 + 1.6.4 - + log4j log4j @@ -220,12 +220,6 @@ 1.3 - - oro - oro - 2.0.8 - - hsqldb hsqldb @@ -268,6 +262,7 @@ 2.5.1 true + [artifactId]-1.0.x @@ -344,27 +339,19 @@ + + org.apache.maven.plugins + maven-war-plugin + 2.0.2 + - release + apache-release - - maven-gpg-plugin - 1.0-alpha-4 - - - sign-artifacts - verify - - sign - - - - maven-javadoc-plugin 2.5 @@ -418,15 +405,8 @@ ftplet-api core distribution - examples + examples - - - apache.snapshots - Apache Development Snapshot Repository - scp://people.apache.org/www/people.apache.org/repo/m2-incubating-repository/ - - @@ -436,14 +416,6 @@ examples - - - dummy - Dummy to avoid accidental deploys - - - - 1.5 1.5