FTP command with argument
コード例 #1
0
        private Tuple <FtpCommand, IFtpCommandBase, bool> FindCommandHandler(FtpCommand command)
        {
            if (!CommandHandlers.TryGetValue(command.Name, out var handler))
            {
                return(null);
            }

            if (!string.IsNullOrWhiteSpace(command.Argument) && handler is IFtpCommandHandlerExtensionHost extensionHost)
            {
                var extensionCommand = FtpCommand.Parse(command.Argument);
                if (extensionHost.Extensions.TryGetValue(extensionCommand.Name, out var extension))
                {
                    return(Tuple.Create(extensionCommand, (IFtpCommandBase)extension, extension.IsLoginRequired ?? handler.IsLoginRequired));
                }
            }

            return(Tuple.Create(command, (IFtpCommandBase)handler, handler.IsLoginRequired));
        }
コード例 #2
0
        private Tuple <FtpCommand, FtpCommandHandlerBase, bool> FindCommandHandler(FtpCommand command)
        {
            FtpCommandHandler handler;

            if (!CommandHandlers.TryGetValue(command.Name, out handler))
            {
                return(null);
            }
            var extensionHost = handler as IFtpCommandHandlerExtensionHost;

            if (!string.IsNullOrWhiteSpace(command.Argument) && extensionHost != null)
            {
                var extensionCommand = FtpCommand.Parse(command.Argument);
                FtpCommandHandlerExtension extension;
                if (extensionHost.Extensions.TryGetValue(extensionCommand.Name, out extension))
                {
                    return(Tuple.Create(extensionCommand, (FtpCommandHandlerBase)extension, extension.IsLoginRequired ?? handler.IsLoginRequired));
                }
            }
            return(Tuple.Create(command, (FtpCommandHandlerBase)handler, handler.IsLoginRequired));
        }
コード例 #3
0
        /// <inheritdoc />
        protected override Task <IFtpResponse> ExecuteCommandAsync(FtpCommand ftpCommand, CancellationToken cancellationToken = default)
        {
            switch (ftpCommand.Name.Trim().ToUpperInvariant())
            {
            case "AUTH":
                return(HandleAuthAsync(ftpCommand.Argument, cancellationToken));

            case "ADAT":
                return(HandleAdatAsync(ftpCommand.Argument, cancellationToken));

            case "USER":
                return(HandleUserAsync(ftpCommand.Argument, cancellationToken));

            case "PASS":
                return(HandlePassAsync(ftpCommand.Argument, cancellationToken));

            case "ACCT":
                return(HandleAcctAsync(ftpCommand.Argument, cancellationToken));

            default:
                return(UnhandledCommandAsync(ftpCommand, cancellationToken));
            }
        }
コード例 #4
0
        /// <summary>
        /// Executes the given FTP command.
        /// </summary>
        /// <param name="ftpCommand">The FTP command to execute.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task returning the response.</returns>
        public async Task <IFtpResponse> ExecuteAsync(FtpCommand ftpCommand, CancellationToken cancellationToken = default)
        {
            var commandTransitions = _possibleTransitions
                                     .Where(x => x.IsMatch(ftpCommand.Name))
                                     .ToList();

            if (commandTransitions.Count == 0)
            {
                return(new FtpResponse(503, T("Bad sequence of commands")));
            }

            var response = await ExecuteCommandAsync(ftpCommand, cancellationToken)
                           .ConfigureAwait(false);

            if (response == null)
            {
                return(new FtpResponse(421, T("Service not available")));
            }

            var foundStatus = commandTransitions.SingleOrDefault(x => x.IsMatch(ftpCommand.Name, response.Code));

            if (foundStatus == null)
            {
                return(new FtpResponse(421, T("Service not available")));
            }

            SetStatus(foundStatus.Target);

            // Ugh ... this is a hack, but I have to fix this later.
            if (response is FtpResponse ftpResponse && ftpResponse.Message == null)
            {
                return(null);
            }

            return(response);
        }
コード例 #5
0
        private FtpCommand CreateFtpCommand(byte[] command)
        {
            var message = Encoding.GetString(command, 0, command.Length);

            return(FtpCommand.Parse(message));
        }
コード例 #6
0
 /// <summary>
 /// Execute the command. All status checks are already done.
 /// </summary>
 /// <param name="ftpCommand">The FTP command to execute.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 /// <returns>The task returning the response.</returns>
 protected abstract Task <IFtpResponse> ExecuteCommandAsync([NotNull] FtpCommand ftpCommand, CancellationToken cancellationToken = default);
コード例 #7
0
        /// <summary>
        /// Executes some code with error handling.
        /// </summary>
        /// <param name="connection">The connection to execute the code for.</param>
        /// <param name="command">The command to execute the code for.</param>
        /// <param name="commandAction">The action to be executed.</param>
        /// <param name="logger">The logger to be used for logging.</param>
        /// <param name="cancellationToken">The cancellation token to signal command abortion.</param>
        /// <returns>The task with the (optional) response.</returns>
        public static async Task <IFtpResponse?> ExecuteCommand(
            this IFtpConnection connection,
            FtpCommand command,
            Func <FtpCommand, CancellationToken, Task <IFtpResponse?> > commandAction,
            ILogger?logger,
            CancellationToken cancellationToken)
        {
            var          localizationFeature = connection.Features.Get <ILocalizationFeature>();
            IFtpResponse?response;

            try
            {
                response = await commandAction(command, cancellationToken)
                           .ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                var exception = ex;
                while (exception is AggregateException aggregateException)
                {
                    exception = aggregateException.InnerException;
                }

                switch (exception)
                {
                case ValidationException validationException:
                    response = new FtpResponse(
                        425,
                        validationException.Message);
                    logger?.LogWarning(validationException.Message);
                    break;

#if !NETSTANDARD1_3
                case SocketException se when se.ErrorCode == (int)SocketError.ConnectionAborted:
#endif
                case OperationCanceledException _:
                    response = new FtpResponse(426, localizationFeature.Catalog.GetString("Connection closed; transfer aborted."));
                    logger?.LogTrace("Command {command} cancelled with response {response}", command, response);
                    break;

                case FileSystemException fse:
                {
                    var message = fse.Message != null ? $"{fse.FtpErrorName}: {fse.Message}" : fse.FtpErrorName;
                    logger?.LogInformation("Rejected command ({command}) with error {code} {message}", command, fse.FtpErrorCode, message);
                    response = new FtpResponse(fse.FtpErrorCode, message);
                    break;
                }

                case NotSupportedException nse:
                {
                    var message = nse.Message ?? localizationFeature.Catalog.GetString("Command {command} not supported", command);
                    logger?.LogInformation(message);
                    response = new FtpResponse(502, message);
                    break;
                }

                default:
                    logger?.LogError(0, ex, "Failed to process message ({command})", command);
                    response = new FtpResponse(501, localizationFeature.Catalog.GetString("Syntax error in parameters or arguments."));
                    break;
                }
            }

            return(response);
        }
コード例 #8
0
        private async Task ProcessMessage(FtpCommand command)
        {
            FtpResponse response;

            Log?.Trace(command);
            var result = FindCommandHandler(command);

            if (result != null)
            {
                var handler         = result.Item2;
                var handlerCommand  = result.Item1;
                var isLoginRequired = result.Item3;
                if (isLoginRequired && !Data.IsLoggedIn)
                {
                    response = new FtpResponse(530, "Not logged in.");
                }
                else
                {
                    try
                    {
                        var cmdHandler  = handler as FtpCommandHandler;
                        var isAbortable = cmdHandler?.IsAbortable ?? false;
                        if (isAbortable)
                        {
                            var newBackgroundTask = Data.BackgroundCommandHandler.Execute(handler, handlerCommand);
                            if (newBackgroundTask != null)
                            {
                                _activeBackgroundTask = newBackgroundTask;
                                response = null;
                            }
                            else
                            {
                                response = new FtpResponse(503, "Parallel commands aren't allowed.");
                            }
                        }
                        else
                        {
                            response = await handler.Process(handlerCommand, _cancellationTokenSource.Token)
                                       .ConfigureAwait(false);
                        }
                    }
                    catch (FileSystemException fse)
                    {
                        var message = fse.Message != null ? $"{fse.FtpErrorName}: {fse.Message}" : fse.FtpErrorName;
                        Log?.LogInformation($"Rejected command ({command}) with error {fse.FtpErrorCode} {message}");
                        response = new FtpResponse(fse.FtpErrorCode, message);
                    }
                    catch (NotSupportedException nse)
                    {
                        var message = nse.Message ?? $"Command {command} not supported";
                        Log?.LogInformation(message);
                        response = new FtpResponse(502, message);
                    }
                    catch (Exception ex)
                    {
                        Log?.LogError(ex, "Failed to process message ({0})", command);
                        response = new FtpResponse(501, "Syntax error in parameters or arguments.");
                    }
                }
            }
            else
            {
                response = new FtpResponse(500, "Syntax error, command unrecognized.");
            }
            if (response != null)
            {
                await WriteAsync(response, _cancellationTokenSource.Token).ConfigureAwait(false);
            }
        }
コード例 #9
0
 /// <summary>
 /// Called when the command couldn't be handled.
 /// </summary>
 /// <param name="ftpCommand">The FTP command causing the problem.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 /// <returns>The FTP response to be returned.</returns>
 protected virtual Task <IFtpResponse> UnhandledCommandAsync(FtpCommand ftpCommand, CancellationToken cancellationToken)
 {
     return(Task.FromResult <IFtpResponse>(new FtpResponse(421, T("Service not available"))));
 }
コード例 #10
0
 private Tuple<FtpCommand, FtpCommandHandlerBase, bool> FindCommandHandler(FtpCommand command)
 {
     FtpCommandHandler handler;
     if (!CommandHandlers.TryGetValue(command.Name, out handler))
         return null;
     var extensionHost = handler as IFtpCommandHandlerExtensionHost;
     if (!string.IsNullOrWhiteSpace(command.Argument) && extensionHost != null)
     {
         var extensionCommand = FtpCommand.Parse(command.Argument);
         FtpCommandHandlerExtension extension;
         if (extensionHost.Extensions.TryGetValue(extensionCommand.Name, out extension))
         {
             return Tuple.Create(extensionCommand, (FtpCommandHandlerBase)extension, extension.IsLoginRequired ?? handler.IsLoginRequired);
         }
     }
     return Tuple.Create(command, (FtpCommandHandlerBase)handler, handler.IsLoginRequired);
 }
コード例 #11
0
 private async Task ProcessMessage(FtpCommand command)
 {
     FtpResponse response;
     Log?.Trace(command);
     var result = FindCommandHandler(command);
     if (result != null)
     {
         var handler = result.Item2;
         var handlerCommand = result.Item1;
         var isLoginRequired = result.Item3;
         if (isLoginRequired && !Data.IsLoggedIn)
         {
             response = new FtpResponse(530, "Not logged in.");
         }
         else
         {
             try
             {
                 var cmdHandler = handler as FtpCommandHandler;
                 var isAbortable = cmdHandler?.IsAbortable ?? false;
                 if (isAbortable)
                 {
                     var newBackgroundTask = Data.BackgroundCommandHandler.Execute(handler, handlerCommand);
                     if (newBackgroundTask != null)
                     {
                         _activeBackgroundTask = newBackgroundTask;
                         response = null;
                     }
                     else
                     {
                         response = new FtpResponse(503, "Parallel commands aren't allowed.");
                     }
                 }
                 else
                 {
                     response = await handler.Process(handlerCommand, _cancellationTokenSource.Token);
                 }
             }
             catch (Exception ex)
             {
                 Log?.Error(ex, "Failed to process message ({0})", command);
                 response = new FtpResponse(501, "Syntax error in parameters or arguments.");
             }
         }
     }
     else
     {
         response = new FtpResponse(500, "Syntax error, command unrecognized.");
     }
     if (response != null)
         await WriteAsync(response, _cancellationTokenSource.Token);
 }
コード例 #12
0
 /// <summary>
 /// Logs a trace message with the data of the <see cref="FtpCommand"/>
 /// </summary>
 /// <param name="log">The <see cref="IFtpLog"/> to use</param>
 /// <param name="command">The <see cref="FtpCommand"/> to log</param>
 public static void Trace([NotNull] this IFtpLog log, [NotNull] FtpCommand command)
 {
     log.Trace("{0}", command);
 }
コード例 #13
0
 public abstract Task <FtpResponse> Process([NotNull] FtpCommand command, CancellationToken cancellationToken);
コード例 #14
0
        public Task <FtpResponse> Execute([NotNull] FtpCommandHandlerBase handler, [NotNull] FtpCommand command)
        {
            Contract.Ensures(Contract.Result <Task <FtpResponse> >() != null);
            lock (_syncRoot)
            {
                if (_handlerTask != null)
                {
                    return(null);
                }

                _cancellationTokenSource = new CancellationTokenSource();
                _handlerTask             = handler.Process(command, _cancellationTokenSource.Token);
            }

            var taskCanceled = _handlerTask
                               .ContinueWith(
                t =>
            {
                var response = new FtpResponse(426, "Connection closed; transfer aborted.");
                Debug.WriteLine($"Background task cancelled with response {response}");
                return(response);
            },
                TaskContinuationOptions.OnlyOnCanceled);

            var taskCompleted = _handlerTask
                                .ContinueWith(
                t =>
            {
                var response = t.Result;
                Debug.WriteLine($"{DateTimeOffset.UtcNow} Background task finished successfully with response {response}");
                return(response);
            },
                TaskContinuationOptions.OnlyOnRanToCompletion);

            var taskFaulted = _handlerTask
                              .ContinueWith(
                t =>
            {
                var ex = t.Exception;
                _connection.Log?.Error(ex, "Error while processing background command {0}", command);
                var response = new FtpResponse(501, "Syntax error in parameters or arguments.");
                Debug.WriteLine($"Background task failed with response {response}");
                return(response);
            },
                TaskContinuationOptions.OnlyOnFaulted);

            taskFaulted.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled);
            taskCompleted.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled);
            taskCanceled.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled);

            return(Task.Run(
                       () =>
            {
                var tasks = new List <Task <FtpResponse> > {
                    taskCompleted, taskCanceled, taskFaulted
                };

                do
                {
                    try
                    {
                        var waitTasks = tasks.Where(x => !x.IsCompleted).Cast <Task>().ToArray();
                        if (waitTasks.Length != 0)
                        {
                            Debug.WriteLine($"Waiting for {waitTasks.Length} background tasks");
                            Task.WaitAll(waitTasks);
                        }
                    }
                    catch (AggregateException ex)
                    {
                        ex.Handle(e => e is TaskCanceledException);
                    }
                }while (tasks.Any(t => !t.IsCompleted));

                var response = tasks.Single(x => x.Status == TaskStatus.RanToCompletion).Result;
                Debug.WriteLine($"{DateTimeOffset.UtcNow} Background task finished with response {response}");

                lock (_syncRoot)
                    _handlerTask = null;

                return response;
            }));
        }