Skip to content

Commit cde3331

Browse files
authored
Introduce extensible remote path quoting mechanism
Introduce extensible remote path quoting mechanism. Fixes issues #256 and #108.
2 parents 5852a96 + 82634b4 commit cde3331

File tree

40 files changed

+3971
-327
lines changed

40 files changed

+3971
-327
lines changed

src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@
308308
<Compile Include="..\Renci.SshNet\IForwardedPort.cs">
309309
<Link>IForwardedPort.cs</Link>
310310
</Compile>
311+
<Compile Include="..\Renci.SshNet\IRemotePathTransformation.cs">
312+
<Link>IRemotePathTransformation.cs</Link>
313+
</Compile>
311314
<Compile Include="..\Renci.SshNet\IServiceFactory.cs">
312315
<Link>IServiceFactory.cs</Link>
313316
</Compile>
@@ -578,6 +581,18 @@
578581
<Compile Include="..\Renci.SshNet\ProxyTypes.cs">
579582
<Link>ProxyTypes.cs</Link>
580583
</Compile>
584+
<Compile Include="..\Renci.SshNet\RemotePathDoubleQuoteTransformation.cs">
585+
<Link>RemotePathDoubleQuoteTransformation.cs</Link>
586+
</Compile>
587+
<Compile Include="..\Renci.SshNet\RemotePathNoneTransformation.cs">
588+
<Link>RemotePathNoneTransformation.cs</Link>
589+
</Compile>
590+
<Compile Include="..\Renci.SshNet\RemotePathShellQuoteTransformation.cs">
591+
<Link>RemotePathShellQuoteTransformation.cs</Link>
592+
</Compile>
593+
<Compile Include="..\Renci.SshNet\RemotePathTransformation.cs">
594+
<Link>RemotePathTransformation.cs</Link>
595+
</Compile>
581596
<Compile Include="..\Renci.SshNet\ScpClient.cs">
582597
<Link>ScpClient.cs</Link>
583598
</Compile>

src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@
314314
<Compile Include="..\Renci.SshNet\IForwardedPort.cs">
315315
<Link>IForwardedPort.cs</Link>
316316
</Compile>
317+
<Compile Include="..\Renci.SshNet\IRemotePathTransformation.cs">
318+
<Link>IRemotePathTransformation.cs</Link>
319+
</Compile>
317320
<Compile Include="..\Renci.SshNet\IServiceFactory.cs">
318321
<Link>IServiceFactory.cs</Link>
319322
</Compile>
@@ -572,6 +575,18 @@
572575
<Compile Include="..\Renci.SshNet\ProxyTypes.cs">
573576
<Link>ProxyTypes.cs</Link>
574577
</Compile>
578+
<Compile Include="..\Renci.SshNet\RemotePathDoubleQuoteTransformation.cs">
579+
<Link>RemotePathDoubleQuoteTransformation.cs</Link>
580+
</Compile>
581+
<Compile Include="..\Renci.SshNet\RemotePathNoneTransformation.cs">
582+
<Link>RemotePathNoneTransformation.cs</Link>
583+
</Compile>
584+
<Compile Include="..\Renci.SshNet\RemotePathShellQuoteTransformation.cs">
585+
<Link>RemotePathShellQuoteTransformation.cs</Link>
586+
</Compile>
587+
<Compile Include="..\Renci.SshNet\RemotePathTransformation.cs">
588+
<Link>RemotePathTransformation.cs</Link>
589+
</Compile>
575590
<Compile Include="..\Renci.SshNet\ScpClient.cs">
576591
<Link>ScpClient.cs</Link>
577592
</Compile>
@@ -949,7 +964,7 @@
949964
<FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
950965
<SilverlightProjectProperties />
951966
</FlavorProperties>
952-
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
967+
<UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
953968
</VisualStudio>
954969
</ProjectExtensions>
955970
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,9 @@
323323
<Compile Include="..\Renci.SshNet\IForwardedPort.cs">
324324
<Link>IForwardedPort.cs</Link>
325325
</Compile>
326+
<Compile Include="..\Renci.SshNet\IRemotePathTransformation.cs">
327+
<Link>IRemotePathTransformation.cs</Link>
328+
</Compile>
326329
<Compile Include="..\Renci.SshNet\IServiceFactory.cs">
327330
<Link>IServiceFactory.cs</Link>
328331
</Compile>
@@ -581,6 +584,18 @@
581584
<Compile Include="..\Renci.SshNet\ProxyTypes.cs">
582585
<Link>ProxyTypes.cs</Link>
583586
</Compile>
587+
<Compile Include="..\Renci.SshNet\RemotePathDoubleQuoteTransformation.cs">
588+
<Link>RemotePathDoubleQuoteTransformation.cs</Link>
589+
</Compile>
590+
<Compile Include="..\Renci.SshNet\RemotePathNoneTransformation.cs">
591+
<Link>RemotePathNoneTransformation.cs</Link>
592+
</Compile>
593+
<Compile Include="..\Renci.SshNet\RemotePathShellQuoteTransformation.cs">
594+
<Link>RemotePathShellQuoteTransformation.cs</Link>
595+
</Compile>
596+
<Compile Include="..\Renci.SshNet\RemotePathTransformation.cs">
597+
<Link>RemotePathTransformation.cs</Link>
598+
</Compile>
584599
<Compile Include="..\Renci.SshNet\ScpClient.cs">
585600
<Link>ScpClient.cs</Link>
586601
</Compile>
@@ -955,7 +970,7 @@
955970
<FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
956971
<SilverlightProjectProperties />
957972
</FlavorProperties>
958-
<UserProperties ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
973+
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="2f5f8c90-0bd1-424f-997c-7bc6280919d1" />
959974
</VisualStudio>
960975
</ProjectExtensions>
961976
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,12 @@
273273
<Compile Include="..\Renci.SshNet.Tests\Classes\Common\CountdownEventTest.cs">
274274
<Link>Classes\Common\CountdownEventTest.cs</Link>
275275
</Compile>
276+
<Compile Include="..\Renci.SshNet.Tests\Classes\Common\CountdownEventTest_Dispose_NotSet.cs">
277+
<Link>Classes\Common\CountdownEventTest_Dispose_NotSet.cs</Link>
278+
</Compile>
279+
<Compile Include="..\Renci.SshNet.Tests\Classes\Common\CountdownEventTest_Dispose_Set.cs">
280+
<Link>Classes\Common\CountdownEventTest_Dispose_Set.cs</Link>
281+
</Compile>
276282
<Compile Include="..\Renci.SshNet.Tests\Classes\Common\DerDataTest.cs">
277283
<Link>Classes\Common\DerDataTest.cs</Link>
278284
</Compile>
@@ -327,6 +333,9 @@
327333
<Compile Include="..\Renci.SshNet.Tests\Classes\Common\PortForwardEventArgsTest.cs">
328334
<Link>Classes\Common\PortForwardEventArgsTest.cs</Link>
329335
</Compile>
336+
<Compile Include="..\Renci.SshNet.Tests\Classes\Common\PosixPathTest_GetFileName.cs">
337+
<Link>Classes\Common\PosixPathTest_GetFileName.cs</Link>
338+
</Compile>
330339
<Compile Include="..\Renci.SshNet.Tests\Classes\Common\ProxyExceptionTest.cs">
331340
<Link>Classes\Common\ProxyExceptionTest.cs</Link>
332341
</Compile>
@@ -765,9 +774,18 @@
765774
<Compile Include="..\Renci.SshNet.Tests\Classes\PrivateKeyFileTest.cs">
766775
<Link>Classes\PrivateKeyFileTest.cs</Link>
767776
</Compile>
777+
<Compile Include="..\Renci.SshNet.Tests\Classes\RemotePathDoubleQuoteTransformationTest.cs">
778+
<Link>Classes\RemotePathDoubleQuoteTransformationTest.cs</Link>
779+
</Compile>
780+
<Compile Include="..\Renci.SshNet.Tests\Classes\RemotePathShellQuoteTransformationTest.cs">
781+
<Link>Classes\RemotePathShellQuoteTransformationTest.cs</Link>
782+
</Compile>
768783
<Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest.cs">
769784
<Link>Classes\ScpClientTest.cs</Link>
770785
</Compile>
786+
<Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTestBase.cs">
787+
<Link>Classes\ScpClientTestBase.cs</Link>
788+
</Compile>
771789
<Compile Include="..\Renci.SshNet.Tests\Classes\ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs">
772790
<Link>Classes\ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs</Link>
773791
</Compile>
@@ -1584,7 +1602,7 @@
15841602
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
15851603
<ProjectExtensions>
15861604
<VisualStudio>
1587-
<UserProperties ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" />
1605+
<UserProperties ProjectLinkerExcludeFilter="\\?desktop(\\.*)?$;\\?silverlight(\\.*)?$;\.desktop;\.silverlight;\.xaml;^service references(\\.*)?$;\.clientconfig;^web references(\\.*)?$" ProjectLinkReference="c45379b9-17b1-4e89-bc2e-6d41726413e8" />
15881606
</VisualStudio>
15891607
</ProjectExtensions>
15901608
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs

Lines changed: 61 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Diagnostics;
43
using System.Threading;
54
using Microsoft.VisualStudio.TestTools.UnitTesting;
65
using Moq;
@@ -21,9 +20,59 @@ public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived
2120
private uint _remotePacketSize;
2221
private ChannelStub _channel;
2322
private List<ChannelEventArgs> _channelClosedRegister;
23+
private List<ChannelEventArgs> _channelEndOfDataRegister;
2424
private IList<ExceptionEventArgs> _channelExceptionRegister;
2525
private ManualResetEvent _channelClosedReceived;
2626

27+
private void SetupData()
28+
{
29+
var random = new Random();
30+
31+
_localChannelNumber = (uint) random.Next(0, int.MaxValue);
32+
_localWindowSize = (uint) random.Next(0, int.MaxValue);
33+
_localPacketSize = (uint) random.Next(0, int.MaxValue);
34+
_remoteChannelNumber = (uint) random.Next(0, int.MaxValue);
35+
_remoteWindowSize = (uint) random.Next(0, int.MaxValue);
36+
_remotePacketSize = (uint) random.Next(0, int.MaxValue);
37+
_channelClosedRegister = new List<ChannelEventArgs>();
38+
_channelEndOfDataRegister = new List<ChannelEventArgs>();
39+
_channelExceptionRegister = new List<ExceptionEventArgs>();
40+
_channelClosedReceived = new ManualResetEvent(false);
41+
}
42+
43+
private void CreateMocks()
44+
{
45+
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
46+
}
47+
48+
private void SetupMocks()
49+
{
50+
var sequence = new MockSequence();
51+
52+
_sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
53+
_sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is<ChannelCloseMessage>(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true);
54+
_sessionMock.InSequence(sequence).Setup(p => p.WaitOnHandle(It.IsAny<EventWaitHandle>()))
55+
.Callback<WaitHandle>(w =>
56+
{
57+
new Thread(() =>
58+
{
59+
Thread.Sleep(100);
60+
// raise ChannelCloseReceived event to set waithandle for receiving
61+
// SSH_MSG_CHANNEL_CLOSE message from server which is waited on after
62+
// sending the SSH_MSG_CHANNEL_CLOSE message to the server
63+
//
64+
// we're mocking the wait on the ChannelCloseMessage, but we still want
65+
// to get the channel in the state that it would have after actually receiving
66+
// the ChannelCloseMessage
67+
_sessionMock.Raise(s => s.ChannelCloseReceived += null, new MessageEventArgs<ChannelCloseMessage>(new ChannelCloseMessage(_localChannelNumber)));
68+
// signal that the ChannelCloseMessage was received; we use this to verify whether we've actually
69+
// waited on the EventWaitHandle to be set
70+
_channelClosedReceived.Set();
71+
}).Start();
72+
w.WaitOne();
73+
});
74+
}
75+
2776
[TestInitialize]
2877
public void Initialize()
2978
{
@@ -43,45 +92,13 @@ public void TearDown()
4392

4493
private void Arrange()
4594
{
46-
var random = new Random();
47-
_localChannelNumber = (uint)random.Next(0, int.MaxValue);
48-
_localWindowSize = (uint)random.Next(0, int.MaxValue);
49-
_localPacketSize = (uint)random.Next(0, int.MaxValue);
50-
_remoteChannelNumber = (uint)random.Next(0, int.MaxValue);
51-
_remoteWindowSize = (uint)random.Next(0, int.MaxValue);
52-
_remotePacketSize = (uint)random.Next(0, int.MaxValue);
53-
_channelClosedRegister = new List<ChannelEventArgs>();
54-
_channelExceptionRegister = new List<ExceptionEventArgs>();
55-
_channelClosedReceived = new ManualResetEvent(false);
56-
57-
_sessionMock = new Mock<ISession>(MockBehavior.Strict);
58-
59-
var sequence = new MockSequence();
60-
_sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true);
61-
_sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is<ChannelCloseMessage>(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true);
62-
_sessionMock.InSequence(sequence).Setup(p => p.WaitOnHandle(It.IsAny<EventWaitHandle>()))
63-
.Callback<WaitHandle>(w =>
64-
{
65-
new Thread(() =>
66-
{
67-
Thread.Sleep(100);
68-
// signal that the ChannelCloseMessage was received; we use this to verify whether we've actually
69-
// waited on the EventWaitHandle to be set
70-
_channelClosedReceived.Set();
71-
// raise ChannelCloseReceived event to set waithandle for receiving
72-
// SSH_MSG_CHANNEL_CLOSE message from server which is waited on after
73-
// sending the SSH_MSG_CHANNEL_CLOSE message to the server
74-
//
75-
// we're mocking the wait on the ChannelCloseMessage, but we still want
76-
// to get the channel in the state that it would have after actually receiving
77-
// the ChannelCloseMessage
78-
_sessionMock.Raise(s => s.ChannelCloseReceived += null, new MessageEventArgs<ChannelCloseMessage>(new ChannelCloseMessage(_localChannelNumber)));
79-
}).Start();
80-
w.WaitOne();
81-
});
95+
SetupData();
96+
CreateMocks();
97+
SetupMocks();
8298

8399
_channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize);
84100
_channel.Closed += (sender, args) => _channelClosedRegister.Add(args);
101+
_channel.EndOfData += (sender, args) => _channelEndOfDataRegister.Add(args);
85102
_channel.Exception += (sender, args) => _channelExceptionRegister.Add(args);
86103
_channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize);
87104
_channel.SetIsOpen(true);
@@ -137,6 +154,13 @@ public void ClosedEventShouldHaveFiredOnce()
137154
Assert.AreEqual(_localChannelNumber, _channelClosedRegister[0].ChannelNumber);
138155
}
139156

157+
[TestMethod]
158+
public void EndOfDataEventShouldHaveFiredOnce()
159+
{
160+
Assert.AreEqual(1, _channelEndOfDataRegister.Count);
161+
Assert.AreEqual(_localChannelNumber, _channelEndOfDataRegister[0].ChannelNumber);
162+
}
163+
140164
[TestMethod]
141165
public void ExceptionShouldNeverHaveFired()
142166
{

0 commit comments

Comments
 (0)