- Overview
- File system changes
- Authorization/authentication as per RFC 2228
- Connection
- FTP middleware
- Server commands
- FTP command execution
- Internals
- Changelog
- A look into the future
Overview
After the upgrade 3.0, you'll see that the IFtpServer.Start and IFtpServer.Stop functions are
deprecated. Please query the IFtpServerHost instead and
use the StartAsync
and StopAsync functions instead.
You will notice breaking changes in the following areas:
- File system
- Membership provider
- Command handlers (and attributes)
- Command extensions (and attributes)
FEATsupport- Connection
- FTP command collection
File system changes
There are two important changes:
IFileSystemClassFactory.Createnow requires anIAccountInformationparameter- The
IUnixFileSystemEntrydoesn't contain theFileSystemproperty anymore.
Authorization/authentication as per RFC 2228
The authorization/authentication stack is new and implemented as specified in the RFC 2228.
This results in additional interfaces/extension points, like
There is also a new extension point for actions to be called when
the user is fully authorized: IAuthorizationAction. You can develop
your own action, but you should only use an IAuthorizationAction.Level
below 1000. The values from 1000 (incl.) to 2000 (incl.) are reserved by
the FTP server and are used to initialize the FTP connection data.
Account directories queryable
A new interface has been introduced to get the root and home directories for a given user.
| Type name | Description |
|---|---|
SingleRootWithoutHomeAccountDirectoryQuery |
Provides a single root for all users. |
RootPerUserAccountDirectoryQuery |
Gives every user its own root directory. Useful, when - for example - the file system root was set to /home. |
PamAccountDirectoryQuery |
Uses home directory information from PAM. The home directory can be configured to be the root instead. |
Membership provider changes
The membership provider is now asynchronous which means that the ValidateUser function was
renamed to ValidateUserAsync.
Everything else is the same.
Connection
The IFtpConnection API was heavily overhauled to use a feature collection,
where the features can be queried through the Features property. Using the WriteAsync
function is obsolete. The FTP command handlers should use the CommandContexts
ServerCommandWriter
if they need to send out-of-band responses.
| Obsolete property | Target feature |
|---|---|
| Encoding | IEncodingFeature |
| OriginalStream | ISecureConnectionFeature |
| SocketStream | ISecureConnectionFeature |
| IsSecure | ISecureConnectionFeature |
| Obsolete method | New home |
|---|---|
| WriteAsync | FtpCommandHandler.CommandContext.ResponseWriter or FtpCommandHandlerExtension.CommandContext.ResponseWriter |
Connection data changes
The whole FtpConnectionData class is marked as obsolete.
The connection datas IsAnonymous property is obsolete. An anonymous user is now detected by testing if
the FtpConnectionData.User
implements IAnonymousFtpUser.
Most of the properties of IFtpConnection.Data were moved to a corresponding
feature.
| Obsolete property | Target feature |
|---|---|
| NlstEncoding | IEncodingFeature |
| User | IAuthorizationInformationFeature |
| FileSystem | IFileSystemFeature |
| Path | IFileSystemFeature |
| CurrentDirectory | IFileSystemFeature |
| Language | ILocalizationFeature |
| Catalog | ILocalizationFeature |
| TransferMode | ITransferConfigurationFeature |
| PortAddress | Removed |
| TransferTypeCommandUsed | Removed |
| RestartPosition | IRestCommandFeature |
| RenameFrom | IRenameCommandFeature |
| ActiveMlstFacts | IMlstFactsFeature |
| PassiveSocketClient | Removed |
| BackgroundCommandHandler | IBackgroundTaskLifetimeFeature |
| CreateEncryptedStream | ISecureConnectionFeature |
There's no direct replacement for the UserData property, but you can use the feature collection too.
Data connections
We're now using two factories to create data connections:
ActiveDataConnectionFeatureFactoryfor active data connections (PORT/EPRTcommands)PassiveDataConnectionFeatureFactoryfor passive data connections (PASV/EPSVcommands)
This factories create a IFtpDataConnectionFeature which is used to create IFtpDataConnection implementations. This allows us to abstract away the differences between active and passive data connections.
The function IFtpConnection.CreateResponseSocket was replaced by DataConnectionServerCommand server command.
The passed AsyncDataConnectionDelegate gets an
IFtpDataConnection implementation and may return a response.
This function also takes care of SSL/TLS encryption as it wraps the IFtpDataConnection
implementation returned by the IFtpDataConnectionFeature into
a new IFtpDataConnection implementation with the help of
the SecureDataConnectionWrapper.
The extension method SendResponseAsync on the IFtpConnection was replaced by the DataConnectionServerCommand
server command and takes care of closing the IFtpDataConnection.
Connection checks
The FTP server allows to check if a connection is still active. It ensures that the server doesn't get filled with dead connections, where the server didn't recognize that the client is gone (e.g. client crash, aborted TCP connection, etc...).
This was made possible by using the following two implementations for IFtpConnectionCheck:
FtpConnectionEstablishedCheckchecks if the TCP connection is still establishedFtpConnectionIdleCheckchecks if the connection is idle for too long
This checks are enabled by default and can be disabled and reenabled by the following extension methods for
the IFtpServerBuilder:
DisableChecksdisables all checks (the default ones and the ones manually enabled before)EnableDefaultChecksenables all default checks (see above)EnableIdleCheckenables the check for an idle connectionEnableConnectionCheckenables the check for an establised TCP connectionDisableIdleCheckenables the check for an idle connectionDisableConnectionCheckdisables the check for an establised TCP connection
The checks above are enabled by default.
Idle check
The idle check determines if the connection was idle for too long. The default timeout is 5 minutes, configured through FtpConnectionOptions.InactivityTimeout.
Connection check
This determines if the TCP connection is still established by sending an empty data packet to the client.
FTP middleware
There are two types of middlewares:
- FTP request middleware (between FTP command collection and dispatch)
- FTP command execution middleware (between FTP command dispatch and execution)
FTP request middleware
This middleware allows interception and modification of the received
FTP commands. You must implement and register the
IFtpMiddleware interface as
service in your dependency injection container.
FTP command execution middleware
The difference between this and the former middleware is, that the FTP command handler for the FTP command is already selected and you can only intercept the FTP commands or do something special.
You must implement and register the
IFtpCommandMiddleware interface as
service in your dependency injection container.
An example is the FsIdChanger in the TestFtpServer project. This middleware
sets - for every authenticated user - the UID/GID for file system access.
Server commands
We're now supporting custom FTP server commands. Those commands must implement
IServerCommand and
must have a corresponding handler (IServerCommandHandler<TCommand>).
CloseConnectionServerCommand
This command closes the FTP connection.
SendResponseServerCommand
This command sends a response to the client.
FTP command execution
Massive changes were done to the FTP command execution. The center
of this changes is the new FtpContext
which provides a new way to access all necessary information like
the FTP connection, the command information and a channel to send
server commands (which replaces IFtpConnection.WriteAsync).
FtpContext
The new FtpContext is the FTP
servers equivalent of ASP.NET Core's HttpContext and provides access
to all information required to execute the FTP commands.
Command handlers (and attributes)
The command handlers were overhauled in the following areas:
- Lazy initialization
- Removed commands from DI container
- You can still add your FTP command handlers to the DI container, but those may (most likely) be ignored from version 4.0 and up.
- Implement your own
IFtpCommandHandlerScanneror reuseAssemblyFtpCommandHandlerScanner
- New
IFtpCommandHandlerScannerwhich scans for types that may implement FTP command handlers - New
IFtpCommandHandlerProviderwhich returns information for all found FTP command handler types
- Removed commands from DI container
- Attributes for command information
FtpCommandHandlerAttributewhich gives the FTP command handler a name and defines if it needs a successful login or if it's abortable
- Simplified constructor due to
CommandContext(typeFtpCommandHandlerContext) property injection - Activated (read: instantiated with property injection) by command name using the
IFtpCommandActivatorservice
Command extensions (and attributes)
The command extensions cannot be returned by IFtpCommandHandler.GetExtensions() anymore. The extensions were moved to
their own file and the default extensions are automatically registered as service.
- Lazy initialization
- Removed command extensions from DI container
- You can still add your FTP command handler extensions to the DI container, but those may (most likely) be ignored from version 4.0 and up.
- Implement your own
IFtpCommandHandlerExtensionScanneror reuseAssemblyFtpCommandHandlerExtensionScanner
- New
IFtpCommandHandlerExtensionScannerwhich scans for types that may implement FTP command handler extensions - New
IFtpCommandHandlerExtensionProviderwhich returns information for all found FTP command handler extension types
- Removed command extensions from DI container
- Attributes for command extension information
FtpCommandHandlerExtensionAttributewhich gives the FTP command handler extension a name and defines the command it extends and if it needs a successful login
- Simplified constructor due to
CommandContext(typeFtpCommandHandlerContext) property injection - Automatic indirect activation (read: instantiation with property injection) for the command it belongs to through the
IFtpCommandActivatorservice
FEAT support
There are two new attributes to get the string to be returned by a FEAT command:
FtpFeatureTextAttributecontains the feature text itselfFtpFeatureFunctionAttributecontains the name of the static function to be called to get the feature text
Internals
FTP command collection changes
We're now using ReadOnlySpan for both TelnetInputParser
and FtpCommandCollector.
Changelog
What's new?
- In-memory file system
- Unix file system
- Passive data connection port range (contribution from 40three GmbH)
- New
IFtpServerHostinterface - New
IFtpServiceinterface which allows easy integration into ASP.NET Core - New
IAccountInformationinterface - New
IAnonymousFtpUserinterface - New RFC 2228 compliant authentication/authorization
- Root and home directories for an account can be queried
- New
IFtpMiddlewareinterface for custom request middleware - New
IFtpCommandMiddlewareinterface for custom command execution middleware - New FTP connection checks
What's changed?
- Google drive upload without background uploader
- The
IFtpCommandHandler.GetExtensions()is now deprecated as all extensions that were previously returned here have their own implementation now - BREAKING: Usage of
ReadOnlySpanin the FTP command collector - BREAKING:
IFileSystemClassFactory.Createtakes anIAccountInformation - BREAKING: The
IMembershipProvideris now asynchronous - BREAKING:
FtpConnectionData.IsAnonymousis obsolete, the anonymous user is now of typeIAnonymousFtpUser - BREAKING: Moved
PromiscuousPasvintoPasvCommandOptions - BREAKING: Removed property
PortAddress,TransferTypeCommandUsed, andPassiveSocketClientfromFtpConnectionData, because we're using a newIFtpDataConnectionabstraction
What's fixed?
- AUTH TLS fails gracefully when no SSL certificate is configured
SITE BLSTworks again- Fixed deadlock in
MultiBindingTcpListener - Thread safe increment/decrement for connection counter (fixes #68)
- The
.directory will be returned again (fixes #56)
A look into the future
The 4.x version will drop support for .NET Standard 1.3 and - most likely - .NET 4.6.1 as
the FTP Server will be reimplemented as ConnectionHandler which will result into the following
improvements:
- Easy hosting in an ASP.NET Core application
- Using the ASP.NET Core connection state management