Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixes Session#when_channel_polled to properly account for 4 byte length

header, so that it waits for the complete packet to arrive instead of
processing an incomplete packet and loosing sync with server.

A new test method, gets_packet_in_two, enables testing of fragmentation
edge cases.  expect_file_transfer now takes a :fragment_len parameter,
allowing for DRY testing of common fragmentation cases like this one.
  • Loading branch information...
commit 044d83422193f895e0f24aa881953e123687291c 1 parent 491ddfd
@accardi accardi authored
Showing with 30 additions and 4 deletions.
  1. +1 −1  lib/net/sftp/session.rb
  2. +12 −0 test/common.rb
  3. +17 −3 test/test_download.rb
View
2  lib/net/sftp/session.rb
@@ -898,7 +898,7 @@ def when_channel_polled(channel)
@packet_length = input.read_long
end
- return unless input.length >= @packet_length
+ return unless input.length >= @packet_length + 4
packet = Net::SFTP::Packet.new(input.read(@packet_length))
input.consume!
@packet_length = nil
View
12 test/common.rb
@@ -125,6 +125,18 @@ def gets_packet(type, *args)
gets_data(sftp_packet(type, *args))
end
+ def gets_packet_in_two(fragment_len, type, *args)
+ fragment_len ||= 0
+ whole_packet = sftp_packet(type, *args)
+
+ if 0 < fragment_len && fragment_len < whole_packet.length
+ gets_data(whole_packet[0, whole_packet.length - fragment_len])
+ gets_data(whole_packet[-fragment_len..-1])
+ else
+ gets_data(whole_packet)
+ end
+ end
+
def sends_packet(type, *args)
sends_data(sftp_packet(type, *args))
end
View
20 test/test_download.rb
@@ -21,6 +21,20 @@ def test_download_file_should_transfer_remote_to_local
assert_equal text, file.string
end
+ def test_download_file_should_transfer_remote_to_local_in_spite_of_fragmentation
+ local = "/path/to/local"
+ remote = "/path/to/remote"
+ text = "this is some text\n"
+
+ expect_file_transfer(remote, text, :fragment_len => 1)
+
+ file = StringIO.new
+ File.stubs(:open).with(local, "wb").returns(file)
+
+ assert_scripted_command { sftp.download(remote, local) }
+ assert_equal text, file.string
+ end
+
def test_download_large_file_should_transfer_remote_to_local
local = "/path/to/local"
remote = "/path/to/remote"
@@ -130,12 +144,12 @@ def test_download_directory_to_buffer_should_fail
private
- def expect_file_transfer(remote, text)
+ def expect_file_transfer(remote, text, opts={})
expect_sftp_session :server_version => 3 do |channel|
channel.sends_packet(FXP_OPEN, :long, 0, :string, remote, :long, 0x01, :long, 0)
channel.gets_packet(FXP_HANDLE, :long, 0, :string, "handle")
channel.sends_packet(FXP_READ, :long, 1, :string, "handle", :int64, 0, :long, 32_000)
- channel.gets_packet(FXP_DATA, :long, 1, :string, text)
+ channel.gets_packet_in_two(opts[:fragment_len], FXP_DATA, :long, 1, :string, text)
channel.sends_packet(FXP_READ, :long, 2, :string, "handle", :int64, text.bytesize, :long, 32_000)
channel.gets_packet(FXP_STATUS, :long, 2, :long, 1)
channel.sends_packet(FXP_CLOSE, :long, 3, :string, "handle")
@@ -160,7 +174,7 @@ def prepare_large_file_download(local, remote, text, requested_chunk_size = FXP_
channel.sends_packet(FXP_CLOSE, :long, data_packet_count + 2, :string, "handle")
channel.gets_packet(FXP_STATUS, :long, data_packet_count + 2, :long, 0)
end
-
+
file = StringIO.new
File.stubs(:open).with(local, "wb").returns(file)
Please sign in to comment.
Something went wrong with that request. Please try again.