net-sftp 4.0.1 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -68,6 +68,10 @@ module Net; module SFTP
68
68
  # the server has not yet responded to will be represented here.
69
69
  attr_reader :pending_requests
70
70
 
71
+ # The extensions the server advertised in its FXP_VERSION packet, as a
72
+ # hash of name => data (e.g. "posix-rename@openssh.com" => "1").
73
+ attr_reader :extensions
74
+
71
75
  # Creates a new Net::SFTP instance atop the given Net::SSH connection.
72
76
  # This will return immediately, before the SFTP connection has been properly
73
77
  # initialized. Once the connection is ready, the given block will be called.
@@ -81,6 +85,7 @@ module Net; module SFTP
81
85
  @input = Net::SSH::Buffer.new
82
86
  self.logger = session.logger
83
87
  @state = :closed
88
+ @extensions = {}
84
89
  @pending_requests = {}
85
90
 
86
91
  connect(&block)
@@ -269,6 +274,10 @@ module Net; module SFTP
269
274
  # Request object. If a block is given, it will be invoked when the
270
275
  # server responds.
271
276
  #
277
+ # +data+ is sent as a single request, so it must stay within the
278
+ # server's packet limit (OpenSSH drops the connection on packets over
279
+ # 256 KiB). Net::SFTP::Operations::File#write splits large data for you.
280
+ #
272
281
  # request = sftp.write(handle, 0, "hello, world!\n")
273
282
  # request.wait
274
283
  def write(handle, offset, data, &callback)
@@ -772,6 +781,7 @@ module Net; module SFTP
772
781
  when :closed
773
782
  @state = :opening
774
783
  @channel = session.open_channel(&method(:when_channel_confirmed))
784
+ @input = Net::SSH::Buffer.new
775
785
  @packet_length = nil
776
786
  @protocol = nil
777
787
  @on_ready = Array(block)
@@ -919,19 +929,27 @@ module Net; module SFTP
919
929
  # version negotiation, instantiating the appropriate Protocol instance
920
930
  # and invoking the callback given to #connect, if any.
921
931
  def do_version(packet)
932
+ # Negotiation happens once. A later FXP_VERSION would swap the protocol
933
+ # driver and drop every pending request.
934
+ unless state == :init
935
+ raise Net::SFTP::Exception, "unexpected FXP_VERSION packet while session is #{state}"
936
+ end
937
+
922
938
  debug { "negotiating sftp protocol version, mine is #{HIGHEST_PROTOCOL_VERSION_SUPPORTED}" }
923
939
 
924
940
  server_version = packet.read_long
925
941
  debug { "server reports sftp version #{server_version}" }
926
942
 
927
- negotiated_version = [server_version, HIGHEST_PROTOCOL_VERSION_SUPPORTED].min
943
+ # Servers reply with their own version whatever we offered (OpenSSH
944
+ # always says 3), so cap at the version we offered as well.
945
+ negotiated_version = [server_version, @version, HIGHEST_PROTOCOL_VERSION_SUPPORTED].compact.min
928
946
  info { "negotiated version is #{negotiated_version}" }
929
947
 
930
- extensions = {}
948
+ @extensions = {}
931
949
  until packet.eof?
932
950
  name = packet.read_string
933
951
  data = packet.read_string
934
- extensions[name] = data
952
+ @extensions[name] = data
935
953
  end
936
954
 
937
955
  @protocol = Protocol.load(self, negotiated_version)
@@ -49,10 +49,10 @@ module Net
49
49
  MAJOR = 4
50
50
 
51
51
  # The minor component of this version of the Net::SFTP library
52
- MINOR = 0
52
+ MINOR = 1
53
53
 
54
54
  # The tiny component of this version of the Net::SFTP library
55
- TINY = 1
55
+ TINY = 0
56
56
 
57
57
  # The prerelease component of this version of the Net::SFTP library
58
58
  # nil allowed
data/lib/net/sftp.rb CHANGED
@@ -34,18 +34,24 @@ module Net
34
34
  # set the SFTP protocol version to be used)
35
35
  def self.start(host, user, ssh_options={}, sftp_options={}, &block)
36
36
  session = Net::SSH.start(host, user, ssh_options)
37
- # We only use a single option here, but this leaves room for more later
38
- # without breaking the external API.
39
- version = sftp_options.fetch(:version, nil)
40
- sftp = Net::SFTP::Session.new(session, version, &block).connect!
37
+ begin
38
+ # We only use a single option here, but this leaves room for more later
39
+ # without breaking the external API.
40
+ version = sftp_options.fetch(:version, nil)
41
+ sftp = Net::SFTP::Session.new(session, version, &block).connect!
41
42
 
42
- if block_given?
43
- sftp.loop
44
- session.close
45
- return nil
46
- end
43
+ if block_given?
44
+ sftp.loop
45
+ return nil
46
+ end
47
47
 
48
- sftp
48
+ sftp
49
+ rescue Object
50
+ failed = true
51
+ raise
52
+ ensure
53
+ session.close if block_given? && !failed
54
+ end
49
55
  rescue Object => anything
50
56
  begin
51
57
  session.shutdown!
data/net-sftp.gemspec CHANGED
@@ -16,6 +16,7 @@ Gem::Specification.new do |spec|
16
16
  spec.homepage = "https://github.com/net-ssh/net-sftp"
17
17
  spec.license = "MIT"
18
18
  spec.required_rubygems_version = Gem::Requirement.new(">= 0") if spec.respond_to? :required_rubygems_version=
19
+ spec.required_ruby_version = ">= 2.6"
19
20
 
20
21
  spec.extra_rdoc_files = [
21
22
  "LICENSE.txt",
data.tar.gz.sig CHANGED
@@ -1,3 +1 @@
1
- �>N٤/)� ����h�Gٟ7��H+l}H�\ �Kij
2
- ��}h��tk14�_��08���H���+�0�k�D/��R�*������� H��A��/犅-/0ƛ|�^w�ʿ��p� �`���F�
3
- K @nK�A��kxx*���_Zk�5!5���$�K5�q�Ԯ@�zP�������r�
1
+ l{������G���>~��g�� ���w} �Z
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-sftp
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.1
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamis Buck
@@ -32,7 +32,7 @@ cert_chain:
32
32
  mMdUtmMoVbjbik3hqkY/18G03c3PoFNpL38VLKuyyROYz1DaCqOaRju3sbOoirD+
33
33
  piQTZDCWxeKuX0Iuxq02uxkYHfoGB6In0y3OOQ==
34
34
  -----END CERTIFICATE-----
35
- date: 2026-10-22 00:00:00.000000000 Z
35
+ date: 2026-10-27 00:00:00.000000000 Z
36
36
  dependencies:
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: net-ssh
@@ -91,14 +91,18 @@ extra_rdoc_files:
91
91
  - LICENSE.txt
92
92
  - README.rdoc
93
93
  files:
94
+ - ".github/pull_request_template.md"
95
+ - ".github/workflows/changelog.yml"
94
96
  - ".github/workflows/ci.yml"
95
97
  - ".gitignore"
96
98
  - CHANGES.txt
99
+ - CONTRIBUTING.md
97
100
  - Gemfile
98
101
  - LICENSE.txt
99
102
  - Manifest
100
103
  - README.rdoc
101
104
  - Rakefile
105
+ - changelog.d/README.md
102
106
  - lib/net/sftp.rb
103
107
  - lib/net/sftp/constants.rb
104
108
  - lib/net/sftp/errors.rb
@@ -121,6 +125,7 @@ files:
121
125
  - lib/net/sftp/protocol/06/attributes.rb
122
126
  - lib/net/sftp/protocol/06/base.rb
123
127
  - lib/net/sftp/protocol/base.rb
128
+ - lib/net/sftp/protocol/bounded_read.rb
124
129
  - lib/net/sftp/request.rb
125
130
  - lib/net/sftp/response.rb
126
131
  - lib/net/sftp/session.rb
@@ -140,7 +145,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
140
145
  requirements:
141
146
  - - ">="
142
147
  - !ruby/object:Gem::Version
143
- version: '0'
148
+ version: '2.6'
144
149
  required_rubygems_version: !ruby/object:Gem::Requirement
145
150
  requirements:
146
151
  - - ">="
metadata.gz.sig CHANGED
Binary file