- 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)
FEAT
support- Connection
- FTP command collection
File system changes
There are two important changes:
IFileSystemClassFactory.Create
now requires anIAccountInformation
parameter- The
IUnixFileSystemEntry
doesn't contain theFileSystem
property 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 CommandContext
s
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:
ActiveDataConnectionFeatureFactory
for active data connections (PORT
/EPRT
commands)PassiveDataConnectionFeatureFactory
for passive data connections (PASV
/EPSV
commands)
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
:
FtpConnectionEstablishedCheck
checks if the TCP connection is still establishedFtpConnectionIdleCheck
checks 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
:
DisableChecks
disables all checks (the default ones and the ones manually enabled before)EnableDefaultChecks
enables all default checks (see above)EnableIdleCheck
enables the check for an idle connectionEnableConnectionCheck
enables the check for an establised TCP connectionDisableIdleCheck
enables the check for an idle connectionDisableConnectionCheck
disables 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
IFtpCommandHandlerScanner
or reuseAssemblyFtpCommandHandlerScanner
- New
IFtpCommandHandlerScanner
which scans for types that may implement FTP command handlers - New
IFtpCommandHandlerProvider
which returns information for all found FTP command handler types
- Removed commands from DI container
- Attributes for command information
FtpCommandHandlerAttribute
which 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
IFtpCommandActivator
service
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
IFtpCommandHandlerExtensionScanner
or reuseAssemblyFtpCommandHandlerExtensionScanner
- New
IFtpCommandHandlerExtensionScanner
which scans for types that may implement FTP command handler extensions - New
IFtpCommandHandlerExtensionProvider
which returns information for all found FTP command handler extension types
- Removed command extensions from DI container
- Attributes for command extension information
FtpCommandHandlerExtensionAttribute
which 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
IFtpCommandActivator
service
FEAT
support
There are two new attributes to get the string to be returned by a FEAT
command:
FtpFeatureTextAttribute
contains the feature text itselfFtpFeatureFunctionAttribute
contains 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
IFtpServerHost
interface - New
IFtpService
interface which allows easy integration into ASP.NET Core - New
IAccountInformation
interface - New
IAnonymousFtpUser
interface - New RFC 2228 compliant authentication/authorization
- Root and home directories for an account can be queried
- New
IFtpMiddleware
interface for custom request middleware - New
IFtpCommandMiddleware
interface 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
ReadOnlySpan
in the FTP command collector - BREAKING:
IFileSystemClassFactory.Create
takes anIAccountInformation
- BREAKING: The
IMembershipProvider
is now asynchronous - BREAKING:
FtpConnectionData.IsAnonymous
is obsolete, the anonymous user is now of typeIAnonymousFtpUser
- BREAKING: Moved
PromiscuousPasv
intoPasvCommandOptions
- BREAKING: Removed property
PortAddress
,TransferTypeCommandUsed
, andPassiveSocketClient
fromFtpConnectionData
, because we're using a newIFtpDataConnection
abstraction
What's fixed?
- AUTH TLS fails gracefully when no SSL certificate is configured
SITE BLST
works 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