Skip to content

Commit

Permalink
Merge branch 'release/v1.1.10'
Browse files Browse the repository at this point in the history
  • Loading branch information
sparkeh9 committed Nov 24, 2016
2 parents eb66fc1 + 29160dc commit 68cdd2a
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 43 deletions.
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: 1.1.8-{build}
version: 1.1.10-{build}
pull_requests:
do_not_increment_build_number: true
configuration: Release
Expand Down
62 changes: 41 additions & 21 deletions src/CoreFtp/FtpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ public class FtpClient : IDisposable

private readonly IDnsResolver dnsResolver;
private IDirectoryProvider directoryProvider;
public FtpClientConfiguration configuration { get; }
public FtpClientConfiguration Configuration { get; }
public ILogger Logger { get; set; }
internal IEnumerable<string> Features { get; set; }
internal Socket commandSocket { get; set; }
internal Socket dataSocket { get; set; }
public bool IsConnected => ( commandSocket != null ) && commandSocket.Connected;
public bool IsAuthenticated { get; set; }
public string WorkingDirectory { get; set; }
public string WorkingDirectory { get; set; } = "/";

public FtpClient( FtpClientConfiguration configuration )
{
this.configuration = configuration;
this.Configuration = configuration;

if ( configuration.Host == null )
throw new ArgumentNullException( nameof( configuration.Host ) );
Expand All @@ -50,7 +50,9 @@ public async Task LoginAsync()
if ( IsConnected )
await LogOutAsync();

string username = configuration.Username.IsNullOrWhiteSpace() ? Constants.ANONYMOUS_USER : configuration.Username;
Configuration.BaseDirectory = $"/{Configuration.BaseDirectory.TrimStart( '/' )}";

string username = Configuration.Username.IsNullOrWhiteSpace() ? Constants.ANONYMOUS_USER : Configuration.Username;

Logger?.LogDebug( $"[FtpClient] Logging In {username}" );

Expand All @@ -66,16 +68,20 @@ public async Task LoginAsync()
var passResponse = await SendCommandAsync( new FtpCommandEnvelope
{
FtpCommand = FtpCommand.PASS,
Data = username != Constants.ANONYMOUS_USER ? configuration.Password : string.Empty
Data = username != Constants.ANONYMOUS_USER ? Configuration.Password : string.Empty
} );

await BailIfResponseNotAsync( passResponse, FtpStatusCode.LoggedInProceed );
IsAuthenticated = true;

Features = await DetermineFeaturesAsync();

await SetTransferMode( configuration.Mode, configuration.ModeSecondType );
await ChangeWorkingDirectoryAsync( configuration.BaseDirectory );
await SetTransferMode( Configuration.Mode, Configuration.ModeSecondType );

if ( Configuration.BaseDirectory != "/" )
await CreateDirectoryAsync( Configuration.BaseDirectory );

await ChangeWorkingDirectoryAsync( Configuration.BaseDirectory );

directoryProvider = DetermineDirectoryProvider();
}
Expand Down Expand Up @@ -139,7 +145,7 @@ public async Task CreateDirectoryAsync( string directory )

EnsureLoggedIn();

await CreateDirectoryStructureRecursively( directory.Split( '/' ) );
await CreateDirectoryStructureRecursively( directory.Split( '/' ), directory.StartsWith( "/" ) );
}

/// <summary>
Expand Down Expand Up @@ -181,6 +187,9 @@ public async Task DeleteDirectoryAsync( string directory )
if ( directory.IsNullOrWhiteSpace() || directory.Equals( "." ) )
throw new ArgumentOutOfRangeException( nameof( directory ), "Directory supplied was not valid" );

if ( directory == "/" )
return;

Logger?.LogDebug( $"[FtpClient] Deleting directory {directory}" );

EnsureLoggedIn();
Expand All @@ -190,6 +199,7 @@ public async Task DeleteDirectoryAsync( string directory )
FtpCommand = FtpCommand.RMD,
Data = directory
} );

switch ( rmdResponse.FtpStatusCode )
{
case FtpStatusCode.CommandOK:
Expand Down Expand Up @@ -267,10 +277,11 @@ public async Task<Stream> OpenFileReadStreamAsync( string fileName )
/// <returns></returns>
public async Task<Stream> OpenFileWriteStreamAsync( string fileName )
{
Logger?.LogDebug( $"[FtpClient] Opening file read stream for {fileName}" );
var segments = fileName.Split( '/' ).Where( x => !x.IsNullOrWhiteSpace() ).ToList();
await CreateDirectoryStructureRecursively( segments.Take( segments.Count - 1 ).ToArray() );
return new FtpWriteFileStream( await OpenFileStreamAsync( fileName, FtpCommand.STOR ), this, Logger );
string filePath = WorkingDirectory.CombineAsUriWith( fileName );
Logger?.LogDebug( $"[FtpClient] Opening file read stream for {filePath}" );
var segments = filePath.Split( '/' ).Where( x => !x.IsNullOrWhiteSpace() ).ToList();
await CreateDirectoryStructureRecursively( segments.Take( segments.Count - 1 ).ToArray(), filePath.StartsWith( "/" ) );
return new FtpWriteFileStream( await OpenFileStreamAsync( filePath, FtpCommand.STOR ), this, Logger );
}

/// <summary>
Expand Down Expand Up @@ -479,9 +490,9 @@ private IDirectoryProvider DetermineDirectoryProvider()
{
Logger?.LogDebug( "[FtpClient] Determining directory provider" );
if ( this.UsesMlsd() )
return new MlsdDirectoryProvider( this, Logger, configuration );
return new MlsdDirectoryProvider( this, Logger, Configuration );

return new ListDirectoryProvider( this, Logger, configuration );
return new ListDirectoryProvider( this, Logger, Configuration );
}

private async Task<IEnumerable<string>> DetermineFeaturesAsync()
Expand Down Expand Up @@ -509,12 +520,16 @@ private async Task<IEnumerable<string>> DetermineFeaturesAsync()
/// Creates a directory structure recursively given a path
/// </summary>
/// <param name="directories"></param>
/// <param name="isRootedPath"></param>
/// <returns></returns>
private async Task CreateDirectoryStructureRecursively( IReadOnlyCollection<string> directories )
private async Task CreateDirectoryStructureRecursively( IReadOnlyCollection<string> directories, bool isRootedPath )
{
Logger?.LogDebug( $"[FtpClient] Creating directory structure recursively {string.Join( "/", directories )}" );
string originalPath = WorkingDirectory;

if ( isRootedPath && directories.Any())
await ChangeWorkingDirectoryAsync( "/" );

if ( !directories.Any() )
return;

Expand All @@ -525,11 +540,16 @@ private async Task CreateDirectoryStructureRecursively( IReadOnlyCollection<stri
FtpCommand = FtpCommand.MKD,
Data = directories.First()
} );

await ChangeWorkingDirectoryAsync( originalPath );
return;
}

foreach ( string directory in directories )
{
if ( directory.IsNullOrWhiteSpace() )
continue;

var response = await SendCommandAsync( new FtpCommandEnvelope
{
FtpCommand = FtpCommand.CWD,
Expand Down Expand Up @@ -598,13 +618,13 @@ private async Task ConnectCommandSocketAsync()
{
try
{
Logger?.LogDebug( $"Connecting command socket, {configuration.Host}:{configuration.Port}" );
Logger?.LogDebug( $"Connecting command socket, {Configuration.Host}:{Configuration.Port}" );

var ipEndpoint = await dnsResolver.ResolveAsync( configuration.Host, configuration.Port, configuration.IpVersion );
var ipEndpoint = await dnsResolver.ResolveAsync( Configuration.Host, Configuration.Port, Configuration.IpVersion );

commandSocket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp )
{
ReceiveTimeout = configuration.TimeoutSeconds * 1000
ReceiveTimeout = Configuration.TimeoutSeconds * 1000
};
commandSocket.Connect( ipEndpoint );

Expand Down Expand Up @@ -639,13 +659,13 @@ internal async Task<Socket> ConnectDataSocketAsync()
Socket socket = null;
try
{
Logger?.LogDebug( $"Connecting data socket, {configuration.Host}:{passivePortNumber.Value}" );
Logger?.LogDebug( $"Connecting data socket, {Configuration.Host}:{passivePortNumber.Value}" );

var ipEndpoint = await dnsResolver.ResolveAsync( configuration.Host, passivePortNumber.Value, configuration.IpVersion );
var ipEndpoint = await dnsResolver.ResolveAsync( Configuration.Host, passivePortNumber.Value, Configuration.IpVersion );

socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp )
{
ReceiveTimeout = configuration.TimeoutSeconds * 1000
ReceiveTimeout = Configuration.TimeoutSeconds * 1000
};
socket.Connect( ipEndpoint );

Expand Down
16 changes: 11 additions & 5 deletions src/CoreFtp/Infrastructure/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,23 @@

public static class StringExtensions
{
public static bool IsNullOrEmpty( this string operand )
internal static bool IsNullOrEmpty( this string operand )
{
return string.IsNullOrEmpty( operand );
}

public static bool IsNullOrWhiteSpace( this string operand )
internal static bool IsNullOrWhiteSpace( this string operand )
{
return string.IsNullOrWhiteSpace( operand );
}

public static int? ExtractEpsvPortNumber( this string operand )
internal static string CombineAsUriWith( this string operand, string rightHandSide )
{
return string.Format( "{0}/{1}", operand.TrimEnd( '/' ), rightHandSide.Trim( '/' ) );
}


internal static int? ExtractEpsvPortNumber( this string operand )
{
var regex = new Regex( @"(?:\|)(?<PortNumber>\d+)(?:\|)", RegexOptions.Compiled );

Expand All @@ -29,7 +35,7 @@ public static bool IsNullOrWhiteSpace( this string operand )
return int.Parse( match.Groups[ "PortNumber" ].Value );
}

public static FtpNodeType ToNodeType( this string operand )
internal static FtpNodeType ToNodeType( this string operand )
{
switch ( operand )
{
Expand All @@ -42,7 +48,7 @@ public static FtpNodeType ToNodeType( this string operand )
return FtpNodeType.SymbolicLink;
}

public static FtpNodeInformation ToFtpNode( this string operand )
internal static FtpNodeInformation ToFtpNode( this string operand )
{
var dictionary = operand.Split( ';' )
.Select( s => s.Split( '=' ) )
Expand Down
3 changes: 2 additions & 1 deletion src/CoreFtp/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@

// The following GUID is for the ID of the typelib if this project is exposed to COM

[ assembly: Guid( "d8a3eb76-d656-40a5-af83-a1855014e051" ) ]
[ assembly: Guid( "d8a3eb76-d656-40a5-af83-a1855014e051" ) ]
[ assembly: InternalsVisibleTo( "CoreFtp.Tests.Integration" ) ]
2 changes: 1 addition & 1 deletion src/CoreFtp/project.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"title": "CoreFTP",
"version": "1.1.8-*",
"version": "1.1.10-*",
"copyright": "Nick Briscoe 2016",
"language": "en",
"packOptions": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace CoreFtp.Tests.Integration.FtpClientTests.Files
using Helpers;
using Xunit;
using Xunit.Abstractions;
using Infrastructure.Extensions;

public class When_uploading_a_file : TestBase
{
Expand All @@ -16,15 +17,14 @@ [ Fact ]
public async Task Should_upload_file()
{
using ( var sut = new FtpClient( new FtpClientConfiguration
{
Host = Program.FtpConfiguration.Host,
Username = Program.FtpConfiguration.Username,
Password = Program.FtpConfiguration.Password,
Port = Program.FtpConfiguration.Port
} ) )
{
Host = Program.FtpConfiguration.Host,
Username = Program.FtpConfiguration.Username,
Password = Program.FtpConfiguration.Password,
Port = Program.FtpConfiguration.Port
} ) )
{
sut.Logger = Logger;
string randomDirectoryName = $"{Guid.NewGuid()}";
string randomFileName = $"{Guid.NewGuid()}.jpg";

await sut.LoginAsync();
Expand All @@ -41,19 +41,21 @@ public async Task Should_upload_file()
files.Any( x => x.Name == randomFileName ).Should().BeTrue();

await sut.DeleteFileAsync( randomFileName );
await sut.ChangeWorkingDirectoryAsync( "/" );
await sut.DeleteDirectoryAsync( sut.Configuration.BaseDirectory );
}
}

[ Fact ]
public async Task Should_upload_file_to_subdirectory()
{
using ( var sut = new FtpClient( new FtpClientConfiguration
{
Host = Program.FtpConfiguration.Host,
Username = Program.FtpConfiguration.Username,
Password = Program.FtpConfiguration.Password,
Port = Program.FtpConfiguration.Port
} ) )
{
Host = Program.FtpConfiguration.Host,
Username = Program.FtpConfiguration.Username,
Password = Program.FtpConfiguration.Password,
Port = Program.FtpConfiguration.Port
} ) )
{
sut.Logger = Logger;
string randomDirectoryName = $"{Guid.NewGuid()}";
Expand All @@ -79,5 +81,40 @@ public async Task Should_upload_file_to_subdirectory()
await sut.DeleteDirectoryAsync( randomDirectoryName );
}
}

[ Fact ]
public async Task Should_upload_file_to_subdirectory_when_given_as_basepath()
{
var guid = Guid.NewGuid();
using ( var sut = new FtpClient( new FtpClientConfiguration
{
Host = Program.FtpConfiguration.Host,
Username = Program.FtpConfiguration.Username,
Password = Program.FtpConfiguration.Password,
Port = Program.FtpConfiguration.Port,
BaseDirectory = $"{guid}/abc/123/doraeme"
} ) )
{
sut.Logger = Logger;
string randomFileName = $"{guid}.jpg";

await sut.LoginAsync();
var fileinfo = ResourceHelpers.GetResourceFileInfo( "penguin.jpg" );

using ( var writeStream = await sut.OpenFileWriteStreamAsync( $"another_level/{randomFileName}" ) )
{
var fileReadStream = fileinfo.OpenRead();
await fileReadStream.CopyToAsync( writeStream );
}

await sut.ChangeWorkingDirectoryAsync( "/".CombineAsUriWith( sut.Configuration.BaseDirectory )
.CombineAsUriWith( "another_level" ) );

var files = await sut.ListFilesAsync();
files.Any( x => x.Name == randomFileName ).Should().BeTrue();

await sut.DeleteDirectoryAsync( $"/{guid}" );
}
}
}
}
2 changes: 1 addition & 1 deletion tests/CoreFtp.Tests.Integration/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"NETStandard.Library": "1.6.0",
"NSubstitute": "2.0.0-rc",
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"CoreFtp": "1.1.6-*",
"CoreFtp": "1.1.10-*",
"Microsoft.Extensions.Configuration": "1.0.0",
"Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
Expand Down

0 comments on commit 68cdd2a

Please sign in to comment.