Skip to content

Commit

Permalink
Process error directives during download
Browse files Browse the repository at this point in the history
  • Loading branch information
John Keiser committed Dec 19, 2013
1 parent 002a77b commit 0f060f8
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
8 changes: 7 additions & 1 deletion lib/net/scp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ module Net
# * E -- terminator directive. Indicates the end of a directory, and subsequent
# files and directories should be received by the parent of the current
# directory.
# * \0 -- indicates a successful response from the other end.
# * \1 -- warning directive. Indicates a warning from the other end. Text from
# this warning will be reported if the SCP results in an error.
# * \2 -- error directive. Indicates an error from the other end. Text from
# this error will be reported if the SCP results in an error.
#
# If a 'C' directive is received, we switch over to
# Net::SCP::Download#read_data_state. If an 'E' directive is received, and
Expand Down Expand Up @@ -355,8 +360,9 @@ def start_command(mode, local, remote, options={}, &callback)
channel[:buffer ] = Net::SSH::Buffer.new
channel[:state ] = "#{mode}_start"
channel[:stack ] = []
channel[:error_string] = ''

channel.on_close { |ch| raise Net::SCP::Error, "SCP did not finish successfully (#{ch[:exit]})" if ch[:exit] != 0 }
channel.on_close { |ch| send("#{channel[:state]}_state", channel); raise Net::SCP::Error, "SCP did not finish successfully (#{channel[:exit]}): #{channel[:error_string]}" if channel[:exit] != 0 }
channel.on_data { |ch, data| channel[:buffer].append(data) }
channel.on_extended_data { |ch, type, data| debug { data.chomp } }
channel.on_request("exit-status") { |ch, data| channel[:exit] = data.read_long }
Expand Down
17 changes: 16 additions & 1 deletion lib/net/scp/download.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ def read_directive_state(channel)

directive = parse_directive(line)
case directive[:type]
when :times then
when :OK
return
when :warning
channel[:error_string] << directive[:message]
when :error
channel[:error_string] << directive[:message]
when :times
channel[:times] = directive
when :directory
read_directory(channel, directive)
Expand Down Expand Up @@ -87,6 +93,15 @@ def finish_read_state(channel)
# data.
def parse_directive(text)
case type = text[0]
when "\x00"
# Success
{ :type => :OK }
when "\x01"
{ :type => :warning,
:message => text[1..-1] }
when "\x02"
{ :type => :error,
:message => text[1..-1] }
when ?T
parts = text[1..-1].split(/ /, 4).map { |i| i.to_i }
{ :type => :times,
Expand Down
27 changes: 27 additions & 0 deletions test/test_download.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,33 @@ def test_download_with_preserve_should_send_times
assert_equal "a" * 1234, file.io.string
end

def test_download_with_error_should_respond_with_error_text
story do |session|
channel = session.opens_channel
channel.sends_exec "scp -f /path/to/remote.txt"

channel.sends_ok
channel.gets_data "\x01File not found: /path/to/remote.txt\n"
channel.sends_ok

channel.gets_eof
channel.gets_exit_status(1)
channel.gets_close
channel.sends_close
end

error = nil
assert_scripted do
begin
scp.download!("/path/to/remote.txt")
rescue
error = $!
end
end
assert_equal Net::SCP::Error, error.class
assert_equal "SCP did not finish successfully (1): File not found: /path/to/remote.txt\n", error.message
end

def test_download_with_progress_callback_should_invoke_callback
prepare_file("/path/to/local.txt", "a" * 3000 + "b" * 3000 + "c" * 3000 + "d" * 3000)

Expand Down

0 comments on commit 0f060f8

Please sign in to comment.