private Task ExecuteBackgroundCommandAsync( FtpContext context, IFtpCommandBase handler, CancellationToken cancellationToken) { var backgroundTaskFeature = _connection.Features.Get <IBackgroundTaskLifetimeFeature?>(); if (backgroundTaskFeature == null) { backgroundTaskFeature = new BackgroundTaskLifetimeFeature( handler, context.Command, ct => { var executionContext = new FtpExecutionContext(context, handler, ct); return(_executionDelegate(executionContext)); }, cancellationToken); _connection.Features.Set(backgroundTaskFeature); return(Task.CompletedTask); } return(SendResponseAsync( new FtpResponse(503, T("Parallel commands aren't allowed.")), cancellationToken)); }
/// <inheritdoc /> public async Task DispatchAsync(FtpContext context, CancellationToken cancellationToken) { var loginStateMachine = _loginStateMachine ?? throw new InvalidOperationException("Login state machine not initialized."); var commandHandlerContext = new FtpCommandHandlerContext(context); var result = _commandActivator.Create(commandHandlerContext); if (result == null) { await SendResponseAsync( new FtpResponse(500, T("Syntax error, command unrecognized.")), cancellationToken) .ConfigureAwait(false); return; } var handler = result.Handler; var isLoginRequired = result.Information.IsLoginRequired; if (isLoginRequired && loginStateMachine.Status != SecurityStatus.Authorized) { await SendResponseAsync( new FtpResponse(530, T("Not logged in.")), cancellationToken) .ConfigureAwait(false); return; } if (result.Information.IsAbortable) { await ExecuteBackgroundCommandAsync(context, handler, cancellationToken) .ConfigureAwait(false); } else { var executionContext = new FtpExecutionContext(context, handler, cancellationToken); await _executionDelegate(executionContext) .ConfigureAwait(false); } }
private async Task ExecuteCommandAsync( FtpExecutionContext context) { var response = await _connection.ExecuteCommand( context.Command, (command, ct) => context.CommandHandler.Process(command, ct), _logger, context.CommandAborted); if (response != null) { try { await SendResponseAsync(response, context.Connection.CancellationToken) .ConfigureAwait(false); } catch (Exception ex) when(ex.Is <OperationCanceledException>()) { _logger?.LogWarning("Sending the response cancelled: {response}", response); } } }
private async Task ExecuteCommandAsync( FtpExecutionContext context) { var localizationFeature = context.Connection.Features.Get <ILocalizationFeature>(); var command = context.Command; IFtpResponse?response; try { response = await context.CommandHandler.Process(command, context.CommandAborted) .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.")); Debug.WriteLine($"Command {command} cancelled with response {response}"); break; case FileSystemException fse: { var message = fse.Message != null ? $"{fse.FtpErrorName}: {fse.Message}" : fse.FtpErrorName; _logger?.LogInformation($"Rejected command ({command}) with error {fse.FtpErrorCode} {message}"); response = new FtpResponse(fse.FtpErrorCode, message); break; } case NotSupportedException nse: { var message = nse.Message ?? T("Command {0} not supported", command); _logger?.LogInformation(message); response = new FtpResponse(502, message); break; } default: _logger?.LogError(0, ex, "Failed to process message ({0})", command); response = new FtpResponse(501, T("Syntax error in parameters or arguments.")); break; } } if (response != null) { try { await SendResponseAsync(response, context.Connection.CancellationToken) .ConfigureAwait(false); } catch (Exception ex) when(ex.Is <OperationCanceledException>()) { _logger?.LogWarning("Sending the response cancelled: {response}", response); } } }