Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }}
os: [ ubuntu-latest, macos-latest ]
os: [ ubuntu-latest, macos-latest, windows-latest ]
exclude:
- ruby: 2.5
os: macos-latest
Expand Down
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@ gem "net-ftp"
gem "rake"
gem "test-unit"
gem "test-unit-ruby-core"
gem "webrick"
215 changes: 215 additions & 0 deletions test/open-uri/test_ftp.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
# frozen_string_literal: true
require 'test/unit'
require 'open-uri'

class TestOpenURIFtp < Test::Unit::TestCase
def with_env(h)
begin
old = {}
h.each_key {|k| old[k] = ENV[k] }
h.each {|k, v| ENV[k] = v }
yield
ensure
h.each_key {|k| ENV[k] = old[k] }
end
end

begin
require 'net/ftp'

def test_ftp_invalid_request
assert_raise(ArgumentError) { URI("ftp://127.0.0.1/").read }
assert_raise(ArgumentError) { URI("ftp://127.0.0.1/a%0Db").read }
assert_raise(ArgumentError) { URI("ftp://127.0.0.1/a%0Ab").read }
assert_raise(ArgumentError) { URI("ftp://127.0.0.1/a%0Db/f").read }
assert_raise(ArgumentError) { URI("ftp://127.0.0.1/a%0Ab/f").read }
assert_nothing_raised(URI::InvalidComponentError) { URI("ftp://127.0.0.1/d/f;type=x") }
end

def test_ftp
TCPServer.open("127.0.0.1", 0) {|serv|
_, port, _, host = serv.addr
th = Thread.new {
s = serv.accept
begin
s.print "220 Test FTP Server\r\n"
assert_equal("USER anonymous\r\n", s.gets); s.print "331 name ok\r\n"
assert_match(/\APASS .*\r\n\z/, s.gets); s.print "230 logged in\r\n"
assert_equal("TYPE I\r\n", s.gets); s.print "200 type set to I\r\n"
assert_equal("CWD foo\r\n", s.gets); s.print "250 CWD successful\r\n"
assert_equal("PASV\r\n", s.gets)
TCPServer.open("127.0.0.1", 0) {|data_serv|
_, data_serv_port, _, _ = data_serv.addr
hi = data_serv_port >> 8
lo = data_serv_port & 0xff
s.print "227 Entering Passive Mode (127,0,0,1,#{hi},#{lo}).\r\n"
assert_equal("RETR bar\r\n", s.gets); s.print "150 file okay\r\n"
data_sock = data_serv.accept
begin
data_sock << "content"
ensure
data_sock.close
end
s.print "226 transfer complete\r\n"
assert_nil(s.gets)
}
ensure
s.close if s
end
}
begin
content = URI("ftp://#{host}:#{port}/foo/bar").read
assert_equal("content", content)
ensure
Thread.kill(th)
th.join
end
}
end

def test_ftp_active
TCPServer.open("127.0.0.1", 0) {|serv|
_, port, _, host = serv.addr
th = Thread.new {
s = serv.accept
begin
content = "content"
s.print "220 Test FTP Server\r\n"
assert_equal("USER anonymous\r\n", s.gets); s.print "331 name ok\r\n"
assert_match(/\APASS .*\r\n\z/, s.gets); s.print "230 logged in\r\n"
assert_equal("TYPE I\r\n", s.gets); s.print "200 type set to I\r\n"
assert_equal("CWD foo\r\n", s.gets); s.print "250 CWD successful\r\n"
assert(m = /\APORT 127,0,0,1,(\d+),(\d+)\r\n\z/.match(s.gets))
active_port = m[1].to_i << 8 | m[2].to_i
TCPSocket.open("127.0.0.1", active_port) {|data_sock|
s.print "200 data connection opened\r\n"
assert_equal("RETR bar\r\n", s.gets); s.print "150 file okay\r\n"
begin
data_sock << content
ensure
data_sock.close
end
s.print "226 transfer complete\r\n"
assert_nil(s.gets)
}
ensure
s.close if s
end
}
begin
content = URI("ftp://#{host}:#{port}/foo/bar").read(:ftp_active_mode=>true)
assert_equal("content", content)
ensure
Thread.kill(th)
th.join
end
}
end

def test_ftp_ascii
TCPServer.open("127.0.0.1", 0) {|serv|
_, port, _, host = serv.addr
th = Thread.new {
s = serv.accept
begin
content = "content"
s.print "220 Test FTP Server\r\n"
assert_equal("USER anonymous\r\n", s.gets); s.print "331 name ok\r\n"
assert_match(/\APASS .*\r\n\z/, s.gets); s.print "230 logged in\r\n"
assert_equal("TYPE I\r\n", s.gets); s.print "200 type set to I\r\n"
assert_equal("CWD /foo\r\n", s.gets); s.print "250 CWD successful\r\n"
assert_equal("TYPE A\r\n", s.gets); s.print "200 type set to A\r\n"
assert_equal("SIZE bar\r\n", s.gets); s.print "213 #{content.bytesize}\r\n"
assert_equal("PASV\r\n", s.gets)
TCPServer.open("127.0.0.1", 0) {|data_serv|
_, data_serv_port, _, _ = data_serv.addr
hi = data_serv_port >> 8
lo = data_serv_port & 0xff
s.print "227 Entering Passive Mode (127,0,0,1,#{hi},#{lo}).\r\n"
assert_equal("RETR bar\r\n", s.gets); s.print "150 file okay\r\n"
data_sock = data_serv.accept
begin
data_sock << content
ensure
data_sock.close
end
s.print "226 transfer complete\r\n"
assert_nil(s.gets)
}
ensure
s.close if s
end
}
begin
length = []
progress = []
content = URI("ftp://#{host}:#{port}/%2Ffoo/b%61r;type=a").read(
:content_length_proc => lambda {|n| length << n },
:progress_proc => lambda {|n| progress << n })
assert_equal("content", content)
assert_equal([7], length)
assert_equal(7, progress.inject(&:+))
ensure
Thread.kill(th)
th.join
end
}
end
rescue LoadError
# net-ftp is the bundled gems at Ruby 3.1
end

def test_ftp_over_http_proxy
TCPServer.open("127.0.0.1", 0) {|proxy_serv|
proxy_port = proxy_serv.addr[1]
th = Thread.new {
proxy_sock = proxy_serv.accept
begin
req = proxy_sock.gets("\r\n\r\n")
assert_match(%r{\AGET ftp://192.0.2.1/foo/bar }, req)
proxy_sock.print "HTTP/1.0 200 OK\r\n"
proxy_sock.print "Content-Length: 4\r\n\r\n"
proxy_sock.print "ab\r\n"
ensure
proxy_sock.close
end
}
begin
with_env('ftp_proxy'=>"http://127.0.0.1:#{proxy_port}") {
content = URI("ftp://192.0.2.1/foo/bar").read
assert_equal("ab\r\n", content)
}
ensure
Thread.kill(th)
th.join
end
}
end

def test_ftp_over_http_proxy_auth
TCPServer.open("127.0.0.1", 0) {|proxy_serv|
proxy_port = proxy_serv.addr[1]
th = Thread.new {
proxy_sock = proxy_serv.accept
begin
req = proxy_sock.gets("\r\n\r\n")
assert_match(%r{\AGET ftp://192.0.2.1/foo/bar }, req)
assert_match(%r{Proxy-Authorization: Basic #{['proxy-user:proxy-password'].pack('m').chomp}\r\n}, req)
proxy_sock.print "HTTP/1.0 200 OK\r\n"
proxy_sock.print "Content-Length: 4\r\n\r\n"
proxy_sock.print "ab\r\n"
ensure
proxy_sock.close
end
}
begin
content = URI("ftp://192.0.2.1/foo/bar").read(
:proxy_http_basic_authentication => ["http://127.0.0.1:#{proxy_port}", "proxy-user", "proxy-password"])
assert_equal("ab\r\n", content)
ensure
Thread.kill(th)
th.join
end
}
end
end
Loading