Jelajahi Sumber

Throw an SshException when SCP request is rejected by the remote host.

Gert Driesen 8 tahun lalu
induk
melakukan
127e3f6591

+ 111 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Channels;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse
+    {
+        private Mock<IServiceFactory> _serviceFactoryMock;
+        private Mock<ISession> _sessionMock;
+        private Mock<IChannelSession> _channelSessionMock;
+        private Mock<PipeStream> _pipeStreamMock;
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private DirectoryInfo _directoryInfo;
+        private string _path;
+        private string _quotedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            Arrange();
+            Act();
+        }
+
+        protected void Arrange()
+        {
+            var random = new Random();
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _directoryInfo = new DirectoryInfo("destination");
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _quotedPath = _path.ShellQuote();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+
+            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
+            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
+            _channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
+            _pipeStreamMock = new Mock<PipeStream>(MockBehavior.Strict);
+
+            var sequence = new MockSequence();
+            _serviceFactoryMock.InSequence(sequence)
+                .Setup(p => p.CreateSession(_connectionInfo))
+                .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _channelSessionMock.InSequence(sequence)
+                .Setup(p => p.SendExecRequest(string.Format("scp -prf {0}", _quotedPath))).Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected virtual void Act()
+        {
+            try
+            {
+                _scpClient.Download(_path, _directoryInfo);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -prf {0}", _quotedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 111 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Channels;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse
+    {
+        private Mock<IServiceFactory> _serviceFactoryMock;
+        private Mock<ISession> _sessionMock;
+        private Mock<IChannelSession> _channelSessionMock;
+        private Mock<PipeStream> _pipeStreamMock;
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private FileInfo _fileInfo;
+        private string _path;
+        private string _quotedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            Arrange();
+            Act();
+        }
+
+        protected void Arrange()
+        {
+            var random = new Random();
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _fileInfo = new FileInfo("destination");
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _quotedPath = _path.ShellQuote();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+
+            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
+            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
+            _channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
+            _pipeStreamMock = new Mock<PipeStream>(MockBehavior.Strict);
+
+            var sequence = new MockSequence();
+            _serviceFactoryMock.InSequence(sequence)
+                .Setup(p => p.CreateSession(_connectionInfo))
+                .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _channelSessionMock.InSequence(sequence)
+                .Setup(p => p.SendExecRequest(string.Format("scp -pf {0}", _quotedPath))).Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected virtual void Act()
+        {
+            try
+            {
+                _scpClient.Download(_path, _fileInfo);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -pf {0}", _quotedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 120 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Channels;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse
+    {
+        private Mock<IServiceFactory> _serviceFactoryMock;
+        private Mock<ISession> _sessionMock;
+        private Mock<IChannelSession> _channelSessionMock;
+        private Mock<PipeStream> _pipeStreamMock;
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private Stream _destination;
+        private string _path;
+        private string _quotedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            Arrange();
+            Act();
+        }
+
+        [TestCleanup]
+        public void Cleanup()
+        {
+            if (_destination != null)
+            {
+                _destination.Dispose();
+            }
+        }
+
+        protected void Arrange()
+        {
+            var random = new Random();
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _destination = new MemoryStream();
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _quotedPath = _path.ShellQuote();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+
+            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
+            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
+            _channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
+            _pipeStreamMock = new Mock<PipeStream>(MockBehavior.Strict);
+
+            var sequence = new MockSequence();
+            _serviceFactoryMock.InSequence(sequence)
+                .Setup(p => p.CreateSession(_connectionInfo))
+                .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _channelSessionMock.InSequence(sequence)
+                .Setup(p => p.SendExecRequest(string.Format("scp -f {0}", _quotedPath))).Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected virtual void Act()
+        {
+            try
+            {
+                _scpClient.Download(_path, _destination);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -f {0}", _quotedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 111 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,111 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Channels;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse
+    {
+        private Mock<IServiceFactory> _serviceFactoryMock;
+        private Mock<ISession> _sessionMock;
+        private Mock<IChannelSession> _channelSessionMock;
+        private Mock<PipeStream> _pipeStreamMock;
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private DirectoryInfo _directoryInfo;
+        private string _path;
+        private string _quotedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            Arrange();
+            Act();
+        }
+
+        protected void Arrange()
+        {
+            var random = new Random();
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _directoryInfo = new DirectoryInfo("source");
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _quotedPath = _path.ShellQuote();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+
+            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
+            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
+            _channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
+            _pipeStreamMock = new Mock<PipeStream>(MockBehavior.Strict);
+
+            var sequence = new MockSequence();
+            _serviceFactoryMock.InSequence(sequence)
+                .Setup(p => p.CreateSession(_connectionInfo))
+                .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _channelSessionMock.InSequence(sequence)
+                .Setup(p => p.SendExecRequest(string.Format("scp -rt {0}", _quotedPath))).Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected virtual void Act()
+        {
+            try
+            {
+                _scpClient.Upload(_directoryInfo, _path);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecREquestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -rt {0}", _quotedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 1 - 1
src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs

@@ -97,7 +97,7 @@ namespace Renci.SshNet.Tests.Classes
         }
 
         [TestMethod]
-        public void SendExecREquestOnChannelSessionShouldBeInvokedOnce()
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
         {
             _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _quotedPath)), Times.Once);
         }

+ 120 - 0
src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs

@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Moq;
+using Renci.SshNet.Channels;
+using Renci.SshNet.Common;
+
+namespace Renci.SshNet.Tests.Classes
+{
+    [TestClass]
+    public class ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse
+    {
+        private Mock<IServiceFactory> _serviceFactoryMock;
+        private Mock<ISession> _sessionMock;
+        private Mock<IChannelSession> _channelSessionMock;
+        private Mock<PipeStream> _pipeStreamMock;
+        private ConnectionInfo _connectionInfo;
+        private ScpClient _scpClient;
+        private Stream _source;
+        private string _path;
+        private string _quotedPath;
+        private IList<ScpUploadEventArgs> _uploadingRegister;
+        private SshException _actualException;
+
+        [TestInitialize]
+        public void Setup()
+        {
+            Arrange();
+            Act();
+        }
+
+        [TestCleanup]
+        public void Cleanup()
+        {
+            if (_source != null)
+            {
+                _source.Dispose();
+            }
+        }
+
+        protected void Arrange()
+        {
+            var random = new Random();
+            _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd"));
+            _source = new MemoryStream();
+            _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture);
+            _quotedPath = _path.ShellQuote();
+            _uploadingRegister = new List<ScpUploadEventArgs>();
+
+            _serviceFactoryMock = new Mock<IServiceFactory>(MockBehavior.Strict);
+            _sessionMock = new Mock<ISession>(MockBehavior.Strict);
+            _channelSessionMock = new Mock<IChannelSession>(MockBehavior.Strict);
+            _pipeStreamMock = new Mock<PipeStream>(MockBehavior.Strict);
+
+            var sequence = new MockSequence();
+            _serviceFactoryMock.InSequence(sequence)
+                .Setup(p => p.CreateSession(_connectionInfo))
+                .Returns(_sessionMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.Connect());
+            _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object);
+            _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Open());
+            _channelSessionMock.InSequence(sequence)
+                .Setup(p => p.SendExecRequest(string.Format("scp -t {0}", _quotedPath))).Returns(false);
+            _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose());
+            _pipeStreamMock.As<IDisposable>().InSequence(sequence).Setup(p => p.Dispose());
+
+            _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object);
+            _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args);
+            _scpClient.Connect();
+        }
+
+        protected virtual void Act()
+        {
+            try
+            {
+                _scpClient.Upload(_source, _path);
+                Assert.Fail();
+            }
+            catch (SshException ex)
+            {
+                _actualException = ex;
+            }
+        }
+
+        [TestMethod]
+        public void UploadShouldHaveThrownSshException()
+        {
+            Assert.IsNotNull(_actualException);
+            Assert.IsNull(_actualException.InnerException);
+            Assert.AreEqual("Secure copy execution request was rejected by the server. Please consult the server logs.", _actualException.Message);
+        }
+
+        [TestMethod]
+        public void SendExecRequestOnChannelSessionShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _quotedPath)), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnChannelShouldBeInvokedOnce()
+        {
+            _channelSessionMock.Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void DisposeOnPipeStreamShouldBeInvokedOnce()
+        {
+            _pipeStreamMock.As<IDisposable>().Verify(p => p.Dispose(), Times.Once);
+        }
+
+        [TestMethod]
+        public void UploadingShouldNeverHaveFired()
+        {
+            Assert.AreEqual(0, _uploadingRegister.Count);
+        }
+    }
+}

+ 5 - 0
src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj

@@ -211,8 +211,13 @@
     <Compile Include="Classes\NetConfClientTest_Dispose_Disposed.cs" />
     <Compile Include="Classes\NetConfClientTest_Finalize_Connected.cs" />
     <Compile Include="Classes\PipeStreamTest_Dispose.cs" />
+    <Compile Include="Classes\ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs" />
+    <Compile Include="Classes\ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs" />
+    <Compile Include="Classes\ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs" />
+    <Compile Include="Classes\ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs" />
     <Compile Include="Classes\ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs" />
     <Compile Include="Classes\ScpClientTest_Upload_FileInfoAndPath_Success.cs" />
+    <Compile Include="Classes\ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs" />
     <Compile Include="Classes\Security\AlgorithmTest.cs" />
     <Compile Include="Classes\Security\CertificateHostAlgorithmTest.cs" />
     <Compile Include="Classes\Security\Cryptography\BlockCipherTest.cs" />

+ 19 - 4
src/Renci.SshNet/ScpClient.NET.cs

@@ -22,6 +22,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentNullException"><paramref name="fileInfo" /> is <c>null</c>.</exception>
         /// <exception cref="ArgumentException"><paramref name="path"/> is <c>null</c> or empty.</exception>
         /// <exception cref="ScpException">A directory with the specified path exists on the remote host.</exception>
+        /// <exception cref="SshException">The secure copy execution request was rejected by the server.</exception>
         public void Upload(FileInfo fileInfo, string path)
         {
             if (fileInfo == null)
@@ -36,7 +37,9 @@ namespace Renci.SshNet
                 channel.Open();
 
                 if (!channel.SendExecRequest(string.Format("scp -t {0}", path.ShellQuote())))
-                    throw new SshException("Secure copy execution request was rejected by the server. Please consult the server logs.");
+                {
+                    throw SecureExecutionRequestRejectedException();
+                }
                 CheckReturnCode(input);
 
                 using (var source = fileInfo.OpenRead())
@@ -56,6 +59,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentNullException">fileSystemInfo</exception>
         /// <exception cref="ArgumentException"><paramref name="path"/> is <c>null</c> or empty.</exception>
         /// <exception cref="ScpException"><paramref name="path"/> exists on the remote host, and is not a directory.</exception>
+        /// <exception cref="SshException">The secure copy execution request was rejected by the server.</exception>
         public void Upload(DirectoryInfo directoryInfo, string path)
         {
             if (directoryInfo == null)
@@ -70,7 +74,10 @@ namespace Renci.SshNet
                 channel.Open();
 
                 // start recursive upload
-                channel.SendExecRequest(string.Format("scp -rt {0}", path.ShellQuote()));
+                if (!channel.SendExecRequest(string.Format("scp -rt {0}", path.ShellQuote())))
+                {
+                    throw SecureExecutionRequestRejectedException();
+                }
                 CheckReturnCode(input);
 
                 UploadTimes(channel, input, directoryInfo);
@@ -87,6 +94,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentNullException"><paramref name="fileInfo"/> is <c>null</c>.</exception>
         /// <exception cref="ArgumentException"><paramref name="filename"/> is <c>null</c> or empty.</exception>
         /// <exception cref="ScpException"><paramref name="filename"/> exists on the remote host, and is not a regular file.</exception>
+        /// <exception cref="SshException">The secure copy execution request was rejected by the server.</exception>
         public void Download(string filename, FileInfo fileInfo)
         {
             if (string.IsNullOrEmpty(filename))
@@ -101,7 +109,10 @@ namespace Renci.SshNet
                 channel.Open();
 
                 // Send channel command request
-                channel.SendExecRequest(string.Format("scp -pf {0}", filename.ShellQuote()));
+                if (!channel.SendExecRequest(string.Format("scp -pf {0}", filename.ShellQuote())))
+                {
+                    throw SecureExecutionRequestRejectedException();
+                }
                 // Send reply
                 SendSuccessConfirmation(channel);
 
@@ -117,6 +128,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentException"><paramref name="directoryName"/> is <c>null</c> or empty.</exception>
         /// <exception cref="ArgumentNullException"><paramref name="directoryInfo"/> is <c>null</c>.</exception>
         /// <exception cref="ScpException">File or directory with the specified path does not exist on the remote host.</exception>
+        /// <exception cref="SshException">The secure copy execution request was rejected by the server.</exception>
         public void Download(string directoryName, DirectoryInfo directoryInfo)
         {
             if (string.IsNullOrEmpty(directoryName))
@@ -131,7 +143,10 @@ namespace Renci.SshNet
                 channel.Open();
 
                 // Send channel command request
-                channel.SendExecRequest(string.Format("scp -prf {0}", directoryName.ShellQuote()));
+                if (!channel.SendExecRequest(string.Format("scp -prf {0}", directoryName.ShellQuote())))
+                {
+                    throw SecureExecutionRequestRejectedException();
+                }
                 // Send reply
                 SendSuccessConfirmation(channel);
 

+ 14 - 6
src/Renci.SshNet/ScpClient.cs

@@ -172,6 +172,7 @@ namespace Renci.SshNet
         /// <param name="source">The <see cref="Stream"/> to upload.</param>
         /// <param name="path">A relative or absolute path for the remote file.</param>
         /// <exception cref="ScpException">A directory with the specified path exists on the remote host.</exception>
+        /// <exception cref="SshException">The secure copy execution request was rejected by the server.</exception>
         public void Upload(Stream source, string path)
         {
             using (var input = ServiceFactory.CreatePipeStream())
@@ -183,7 +184,9 @@ namespace Renci.SshNet
                 // pass the full path to ensure the server does not create the directory part
                 // as a file in case the directory does not exist
                 if (!channel.SendExecRequest(string.Format("scp -t {0}", path.ShellQuote())))
-                    return;
+                {
+                    throw SecureExecutionRequestRejectedException();
+                }
                 CheckReturnCode(input);
 
                 // specify a zero-length file name to avoid creating a file with absolute
@@ -201,10 +204,7 @@ namespace Renci.SshNet
         /// <exception cref="ArgumentException"><paramref name="filename"/> is <c>null</c> or contains only whitespace characters.</exception>
         /// <exception cref="ArgumentNullException"><paramref name="destination"/> is <c>null</c>.</exception>
         /// <exception cref="ScpException"><paramref name="filename"/> exists on the remote host, and is not a regular file.</exception>
-        /// <remarks>
-        /// Method calls made by this method to <paramref name="destination"/>, may under certain conditions result
-        /// in exceptions thrown by the stream.
-        /// </remarks>
+        /// <exception cref="SshException">The secure copy execution request was rejected by the server.</exception>
         public void Download(string filename, Stream destination)
         {
             if (filename.IsNullOrWhiteSpace())
@@ -220,7 +220,10 @@ namespace Renci.SshNet
                 channel.Open();
 
                 //  Send channel command request
-                channel.SendExecRequest(string.Format("scp -f {0}", filename.ShellQuote()));
+                if (!channel.SendExecRequest(string.Format("scp -f {0}", filename.ShellQuote())))
+                {
+                    throw SecureExecutionRequestRejectedException();
+                }
                 SendSuccessConfirmation(channel); //  Send reply
 
                 var message = ReadString(input);
@@ -424,5 +427,10 @@ namespace Renci.SshNet
                 throw new ScpException(ConnectionInfo.Encoding.GetString(readBytes, 0, readBytes.Length));
             return ConnectionInfo.Encoding.GetString(readBytes, 0, readBytes.Length);
         }
+
+        private static SshException SecureExecutionRequestRejectedException()
+        {
+            throw new SshException("Secure copy execution request was rejected by the server. Please consult the server logs.");
+        }
     }
 }