mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
34a0e098f7
CR or LF is included in a line. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55579 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1669 lines
53 KiB
Ruby
1669 lines
53 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "net/ftp"
|
|
require "test/unit"
|
|
require "ostruct"
|
|
require "stringio"
|
|
require "tempfile"
|
|
|
|
class FTPTest < Test::Unit::TestCase
|
|
SERVER_ADDR = "127.0.0.1"
|
|
|
|
def setup
|
|
@thread = nil
|
|
@default_passive = Net::FTP.default_passive
|
|
Net::FTP.default_passive = false
|
|
end
|
|
|
|
def teardown
|
|
Net::FTP.default_passive = @default_passive
|
|
if @thread
|
|
@thread.join
|
|
end
|
|
end
|
|
|
|
def test_not_connected
|
|
ftp = Net::FTP.new
|
|
assert_raise(Net::FTPConnectionError) do
|
|
ftp.quit
|
|
end
|
|
end
|
|
|
|
def test_closed_when_not_connected
|
|
ftp = Net::FTP.new
|
|
assert_equal(true, ftp.closed?)
|
|
assert_nothing_raised(Net::FTPConnectionError) do
|
|
ftp.close
|
|
end
|
|
end
|
|
|
|
def test_connect_fail
|
|
server = create_ftp_server { |sock|
|
|
sock.print("421 Service not available, closing control connection.\r\n")
|
|
}
|
|
begin
|
|
ftp = Net::FTP.new
|
|
assert_raise(Net::FTPTempError){ ftp.connect(SERVER_ADDR, server.port) }
|
|
ensure
|
|
ftp.close if ftp
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_parse227
|
|
ftp = Net::FTP.new
|
|
host, port = ftp.send(:parse227, "227 Entering Passive Mode (192,168,0,1,12,34)")
|
|
assert_equal("192.168.0.1", host)
|
|
assert_equal(3106, port)
|
|
assert_raise(Net::FTPReplyError) do
|
|
ftp.send(:parse227, "500 Syntax error")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse227, "227 Entering Passive Mode")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse227, "227 Entering Passive Mode (192,168,0,1,12,34,56)")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse227, "227 Entering Passive Mode (192,168,0,1)")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse227, "227 ) foo bar (")
|
|
end
|
|
end
|
|
|
|
def test_parse228
|
|
ftp = Net::FTP.new
|
|
host, port = ftp.send(:parse228, "228 Entering Long Passive Mode (4,4,192,168,0,1,2,12,34)")
|
|
assert_equal("192.168.0.1", host)
|
|
assert_equal(3106, port)
|
|
host, port = ftp.send(:parse228, "228 Entering Long Passive Mode (6,16,16,128,0,0,0,0,0,0,0,8,8,0,32,12,65,122,2,12,34)")
|
|
assert_equal("1080:0000:0000:0000:0008:0800:200c:417a", host)
|
|
assert_equal(3106, port)
|
|
assert_raise(Net::FTPReplyError) do
|
|
ftp.send(:parse228, "500 Syntax error")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse228, "228 Entering Passive Mode")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse228, "228 Entering Long Passive Mode (6,4,192,168,0,1,2,12,34)")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse228, "228 Entering Long Passive Mode (4,4,192,168,0,1,3,12,34,56)")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse228, "228 Entering Long Passive Mode (4,16,16,128,0,0,0,0,0,0,0,8,8,0,32,12,65,122,2,12,34)")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse228, "228 Entering Long Passive Mode (6,16,16,128,0,0,0,0,0,0,0,8,8,0,32,12,65,122,3,12,34,56)")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse228, "228 Entering Long Passive Mode (6,16,16,128,0,0,0,0,0,0,0,8,8,0,32,12,65,122,2,12,34,56)")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse227, "227 ) foo bar (")
|
|
end
|
|
end
|
|
|
|
def test_parse229
|
|
ftp = Net::FTP.new
|
|
sock = OpenStruct.new
|
|
sock.peeraddr = [nil, nil, nil, "1080:0000:0000:0000:0008:0800:200c:417a"]
|
|
ftp.instance_variable_set(:@sock, sock)
|
|
host, port = ftp.send(:parse229, "229 Entering Passive Mode (|||3106|)")
|
|
assert_equal("1080:0000:0000:0000:0008:0800:200c:417a", host)
|
|
assert_equal(3106, port)
|
|
host, port = ftp.send(:parse229, "229 Entering Passive Mode (!!!3106!)")
|
|
assert_equal("1080:0000:0000:0000:0008:0800:200c:417a", host)
|
|
assert_equal(3106, port)
|
|
host, port = ftp.send(:parse229, "229 Entering Passive Mode (~~~3106~)")
|
|
assert_equal("1080:0000:0000:0000:0008:0800:200c:417a", host)
|
|
assert_equal(3106, port)
|
|
assert_raise(Net::FTPReplyError) do
|
|
ftp.send(:parse229, "500 Syntax error")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse229, "229 Entering Passive Mode")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse229, "229 Entering Passive Mode (|!!3106!)")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse229, "229 Entering Passive Mode ( 3106 )")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse229, "229 Entering Passive Mode (\x7f\x7f\x7f3106\x7f)")
|
|
end
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.send(:parse229, "229 ) foo bar (")
|
|
end
|
|
end
|
|
|
|
def test_parse_pasv_port
|
|
ftp = Net::FTP.new
|
|
assert_equal(12, ftp.send(:parse_pasv_port, "12"))
|
|
assert_equal(3106, ftp.send(:parse_pasv_port, "12,34"))
|
|
assert_equal(795192, ftp.send(:parse_pasv_port, "12,34,56"))
|
|
assert_equal(203569230, ftp.send(:parse_pasv_port, "12,34,56,78"))
|
|
end
|
|
|
|
def test_login
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_login_fail1
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("502 Command not implemented.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
assert_raise(Net::FTPPermError){ ftp.login }
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_login_fail2
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("530 Not logged in.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
assert_raise(Net::FTPPermError){ ftp.login }
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
# TODO: How can we test open_timeout? sleep before accept cannot delay
|
|
# connections.
|
|
def _test_open_timeout_exceeded
|
|
commands = []
|
|
server = create_ftp_server(0.2) { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.open_timeout = 0.1
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
assert_raise(Net::OpenTimeout) do
|
|
ftp.login
|
|
end
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_read_timeout_exceeded
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sleep(0.1)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sleep(0.3)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sleep(0.1)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
assert_raise(Net::ReadTimeout) do
|
|
ftp.login
|
|
end
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_read_timeout_not_exceeded
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sleep(0.1)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sleep(0.1)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sleep(0.1)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close
|
|
assert_equal(0.2, ftp.read_timeout)
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_list_read_timeout_exceeded
|
|
commands = []
|
|
list_lines = [
|
|
"-rw-r--r-- 1 0 0 0 Mar 30 11:22 foo.txt",
|
|
"-rw-r--r-- 1 0 0 0 Mar 30 11:22 bar.txt",
|
|
"-rw-r--r-- 1 0 0 0 Mar 30 11:22 baz.txt"
|
|
]
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to ASCII mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Here comes the directory listing.\r\n")
|
|
begin
|
|
conn = TCPSocket.new(host, port)
|
|
list_lines.each_with_index do |l, i|
|
|
if i == 1
|
|
sleep(0.5)
|
|
else
|
|
sleep(0.1)
|
|
end
|
|
conn.print(l, "\r\n")
|
|
end
|
|
rescue Errno::EPIPE
|
|
ensure
|
|
assert_nil($!)
|
|
conn.close
|
|
end
|
|
sock.print("226 Directory send OK.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_raise(Net::ReadTimeout) do
|
|
ftp.list
|
|
end
|
|
assert_equal("TYPE A\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("LIST\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_list_read_timeout_not_exceeded
|
|
commands = []
|
|
list_lines = [
|
|
"-rw-r--r-- 1 0 0 0 Mar 30 11:22 foo.txt",
|
|
"-rw-r--r-- 1 0 0 0 Mar 30 11:22 bar.txt",
|
|
"-rw-r--r-- 1 0 0 0 Mar 30 11:22 baz.txt"
|
|
]
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to ASCII mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Here comes the directory listing.\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
list_lines.each do |l|
|
|
sleep(0.1)
|
|
conn.print(l, "\r\n")
|
|
end
|
|
conn.close
|
|
sock.print("226 Directory send OK.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(list_lines, ftp.list)
|
|
assert_equal("TYPE A\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("LIST\r\n", commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_list_fail
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to ASCII mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("553 Requested action not taken.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_raise(Net::FTPPermError){ ftp.list }
|
|
assert_equal("TYPE A\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("LIST\r\n", commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_open_data_port_fail_no_leak
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to ASCII mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
sock.print("421 Service not available, closing control connection.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_raise(Net::FTPTempError){ ftp.list }
|
|
assert_equal("TYPE A\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_retrbinary_read_timeout_exceeded
|
|
commands = []
|
|
binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
sleep(0.1)
|
|
conn.print(binary_data[0,1024])
|
|
sleep(0.5)
|
|
conn.print(binary_data[1024, 1024]) rescue nil # may raise EPIPE or something
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
buf = String.new
|
|
assert_raise(Net::ReadTimeout) do
|
|
ftp.retrbinary("RETR foo", 1024) do |s|
|
|
buf << s
|
|
end
|
|
end
|
|
assert_equal(1024, buf.bytesize)
|
|
assert_equal(binary_data[0, 1024], buf)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR foo\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close unless ftp.closed?
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_retrbinary_read_timeout_not_exceeded
|
|
commands = []
|
|
binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
binary_data.scan(/.{1,1024}/nm) do |s|
|
|
sleep(0.1)
|
|
conn.print(s)
|
|
end
|
|
conn.shutdown(Socket::SHUT_WR)
|
|
conn.read
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
buf = String.new
|
|
ftp.retrbinary("RETR foo", 1024) do |s|
|
|
buf << s
|
|
end
|
|
assert_equal(binary_data.bytesize, buf.bytesize)
|
|
assert_equal(binary_data, buf)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR foo\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_retrbinary_fail
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("550 Requested action not taken.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_raise(Net::FTPPermError){ ftp.retrbinary("RETR foo", 1024) }
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR foo\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_getbinaryfile
|
|
commands = []
|
|
binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
binary_data.scan(/.{1,1024}/nm) do |s|
|
|
conn.print(s)
|
|
end
|
|
conn.shutdown(Socket::SHUT_WR)
|
|
conn.read
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
buf = ftp.getbinaryfile("foo", nil)
|
|
assert_equal(binary_data, buf)
|
|
assert_equal(Encoding::ASCII_8BIT, buf.encoding)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR foo\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_getbinaryfile_empty
|
|
commands = []
|
|
binary_data = ""
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
conn.shutdown(Socket::SHUT_WR)
|
|
conn.read
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
buf = ftp.getbinaryfile("foo", nil)
|
|
assert_equal(binary_data, buf)
|
|
assert_equal(Encoding::ASCII_8BIT, buf.encoding)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR foo\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_getbinaryfile_with_filename_and_block
|
|
commands = []
|
|
binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
binary_data.scan(/.{1,1024}/nm) do |s|
|
|
conn.print(s)
|
|
end
|
|
conn.shutdown(Socket::SHUT_WR)
|
|
conn.read
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
Tempfile.create("foo", external_encoding: "ASCII-8BIT") do |f|
|
|
f.binmode
|
|
buf = String.new
|
|
res = ftp.getbinaryfile("foo", f.path) { |s|
|
|
buf << s
|
|
}
|
|
assert_equal(nil, res)
|
|
assert_equal(binary_data, buf)
|
|
assert_equal(Encoding::ASCII_8BIT, buf.encoding)
|
|
assert_equal(binary_data, f.read)
|
|
end
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR foo\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_storbinary
|
|
commands = []
|
|
binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3
|
|
stored_data = nil
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening BINARY mode data connection for foo\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
stored_data = conn.read
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
ftp.storbinary("STOR foo", StringIO.new(binary_data), 1024)
|
|
assert_equal(binary_data, stored_data)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("STOR foo\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_storbinary_fail
|
|
commands = []
|
|
binary_data = (0..0xff).map {|i| i.chr}.join * 4 * 3
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("452 Requested file action aborted.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_raise(Net::FTPTempError){ ftp.storbinary("STOR foo", StringIO.new(binary_data), 1024) }
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("STOR foo\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_retrlines
|
|
commands = []
|
|
text_data = <<EOF.gsub(/\n/, "\r\n")
|
|
foo
|
|
bar
|
|
baz
|
|
EOF
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to ASCII mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening TEXT mode data connection for foo (#{text_data.size} bytes)\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
text_data.each_line do |line|
|
|
conn.print(line)
|
|
end
|
|
conn.shutdown(Socket::SHUT_WR)
|
|
conn.read
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
buf = String.new
|
|
ftp.retrlines("RETR foo") do |line|
|
|
buf << line + "\r\n"
|
|
end
|
|
assert_equal(text_data.bytesize, buf.bytesize)
|
|
assert_equal(text_data, buf)
|
|
assert_equal("TYPE A\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR foo\r\n", commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_gettextfile
|
|
commands = []
|
|
text_data = <<EOF.gsub(/\n/, "\r\n")
|
|
foo
|
|
bar
|
|
baz
|
|
EOF
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to ASCII mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening TEXT mode data connection for foo (#{text_data.size} bytes)\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
text_data.each_line do |line|
|
|
conn.print(line)
|
|
end
|
|
conn.shutdown(Socket::SHUT_WR)
|
|
conn.read
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
buf = ftp.gettextfile("foo", nil)
|
|
assert_equal(text_data.gsub(/\r\n/, "\n"), buf)
|
|
assert_equal(Encoding::ASCII_8BIT, buf.encoding)
|
|
assert_equal("TYPE A\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR foo\r\n", commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_gettextfile_with_filename_and_block
|
|
commands = []
|
|
text_data = <<EOF.gsub(/\n/, "\r\n")
|
|
foo
|
|
bar
|
|
baz
|
|
EOF
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to ASCII mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening TEXT mode data connection for foo (#{text_data.size} bytes)\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
text_data.each_line do |line|
|
|
conn.print(line)
|
|
end
|
|
conn.shutdown(Socket::SHUT_WR)
|
|
conn.read
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
Tempfile.create("foo", external_encoding: "ascii-8bit") do |f|
|
|
buf = String.new
|
|
res = ftp.gettextfile("foo", f.path) { |s|
|
|
buf << s << "\n"
|
|
}
|
|
assert_equal(nil, res)
|
|
assert_equal(text_data.gsub(/\r\n/, "\n"), buf)
|
|
assert_equal(Encoding::ASCII_8BIT, buf.encoding)
|
|
assert_equal(buf, f.read)
|
|
end
|
|
assert_equal("TYPE A\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR foo\r\n", commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_getbinaryfile_in_list
|
|
commands = []
|
|
binary_data = (0..0xff).map {|i| i.chr}.join
|
|
list_lines = [
|
|
"-rw-r--r-- 1 0 0 0 Mar 30 11:22 foo.txt",
|
|
"-rw-r--r-- 1 0 0 0 Mar 30 11:22 bar.txt",
|
|
"-rw-r--r-- 1 0 0 0 Mar 30 11:22 baz.bin"
|
|
]
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to ASCII mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Here comes the directory listing.\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
list_lines.each_with_index do |l, i|
|
|
conn.print(l, "\r\n")
|
|
end
|
|
conn.close
|
|
sock.print("226 Directory send OK.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Opening BINARY mode data connection for foo (#{binary_data.size} bytes)\r\n")
|
|
conn = TCPSocket.new(host, port)
|
|
conn.print(binary_data)
|
|
conn.close
|
|
sock.print("226 Transfer complete.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
ftp.list do |line|
|
|
file = line.slice(/(\S*\.bin)\z/)
|
|
if file
|
|
data = ftp.getbinaryfile(file, nil)
|
|
assert_equal(binary_data, data)
|
|
end
|
|
end
|
|
assert_equal("TYPE A\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("LIST\r\n", commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_equal("RETR baz.bin\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_abort
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("225 No transfer to ABOR.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
#ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
ftp.abort
|
|
assert_equal("ABOR\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_status
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("211 End of status\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.read_timeout = 0.2
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
ftp.status
|
|
assert_equal("STAT\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_pathnames
|
|
require 'pathname'
|
|
|
|
commands = []
|
|
server = create_ftp_server(0.2) { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("257 'foo' directory created.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("250 CWD command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("250 CWD command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("250 RMD command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 test.txt Fri, 11 Jan 2013 11:20:41 -0500.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 test.txt 16.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("350 File exists, ready for destination name\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("250 RNTO command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("250 DELE command successful.\r\n")
|
|
}
|
|
|
|
begin
|
|
begin
|
|
dir = Pathname.new("foo")
|
|
file = Pathname.new("test.txt")
|
|
file2 = Pathname.new("test2.txt")
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
ftp.mkdir(dir)
|
|
ftp.chdir(dir)
|
|
ftp.chdir("..")
|
|
ftp.rmdir(dir)
|
|
ftp.mdtm(file)
|
|
ftp.size(file)
|
|
ftp.rename(file, file2)
|
|
ftp.delete(file)
|
|
|
|
# TODO: These commented tests below expose the error but don't test anything:
|
|
# TypeError: no implicit conversion of Pathname into String
|
|
# ftp.nlst(dir)
|
|
# ftp.putbinaryfile(Pathname.new("/etc/hosts"), file2)
|
|
# ftp.puttextfile(Pathname.new("/etc/hosts"), file2)
|
|
# ftp.gettextfile(Pathname.new("/etc/hosts"), file2)
|
|
# ftp.getbinaryfile(Pathname.new("/etc/hosts"), file2)
|
|
# ftp.list(dir, dir, dir)
|
|
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_match(/\ATYPE /, commands.shift)
|
|
assert_match(/\AMKD /, commands.shift)
|
|
assert_match(/\ACWD /, commands.shift)
|
|
assert_match(/\ACDUP/, commands.shift)
|
|
assert_match(/\ARMD /, commands.shift)
|
|
assert_match(/\AMDTM /, commands.shift)
|
|
assert_match(/\ASIZE /, commands.shift)
|
|
assert_match(/\ARNFR /, commands.shift)
|
|
assert_match(/\ARNTO /, commands.shift)
|
|
assert_match(/\ADELE /, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_getmultiline
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
sock.print("123- foo\r\n")
|
|
sock.print("bar\r\n")
|
|
sock.print(" 123 baz\r\n")
|
|
sock.print("123 quux\r\n")
|
|
sock.print("123 foo\r\n")
|
|
sock.print("foo\r\n")
|
|
sock.print("\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
assert_equal("123- foo\nbar\n 123 baz\n123 quux\n",
|
|
ftp.send(:getmultiline))
|
|
assert_equal("123 foo\n", ftp.send(:getmultiline))
|
|
assert_equal("foo\n", ftp.send(:getmultiline))
|
|
assert_equal("\n", ftp.send(:getmultiline))
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_size
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 12345\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
assert_equal(12345, ftp.size("foo.txt"))
|
|
assert_match("SIZE foo.txt\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_mdtm
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 20150910161739\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
assert_equal("20150910161739", ftp.mdtm("foo.txt"))
|
|
assert_match("MDTM foo.txt\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_mtime
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 20150910161739\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 20150910161739\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 20150910161739.123456\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 20150910161739.123\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 20150910161739.123456789\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("213 2015091016173\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
assert_equal(Time.utc(2015, 9, 10, 16, 17, 39), ftp.mtime("foo.txt"))
|
|
assert_equal(Time.local(2015, 9, 10, 16, 17, 39),
|
|
ftp.mtime("foo.txt", true))
|
|
assert_equal(Time.utc(2015, 9, 10, 16, 17, 39, 123456),
|
|
ftp.mtime("bar.txt"))
|
|
assert_equal(Time.utc(2015, 9, 10, 16, 17, 39, 123000),
|
|
ftp.mtime("bar.txt"))
|
|
assert_equal(Time.utc(2015, 9, 10, 16, 17, 39,
|
|
Rational(123456789, 1000)),
|
|
ftp.mtime("bar.txt"))
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.mtime("quux.txt")
|
|
end
|
|
assert_match("MDTM foo.txt\r\n", commands.shift)
|
|
assert_match("MDTM foo.txt\r\n", commands.shift)
|
|
assert_match("MDTM bar.txt\r\n", commands.shift)
|
|
assert_match("MDTM bar.txt\r\n", commands.shift)
|
|
assert_match("MDTM bar.txt\r\n", commands.shift)
|
|
assert_match("MDTM quux.txt\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_system
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("215 UNIX Type: L8\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
assert_equal("UNIX Type: L8", ftp.system)
|
|
assert_match("SYST\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_mlst
|
|
commands = []
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("250- Listing foo\r\n")
|
|
sock.print(" Type=file;Unique=FC00U1E554A;Size=1234567;Modify=20131220035929;Perm=r;Unix.mode=0644;Unix.owner=122;Unix.group=0;Unix.ctime=20131220120140;Unix.atime=20131220131139; /foo\r\n")
|
|
sock.print("250 End\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("250 Malformed response\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("250- Listing foo\r\n")
|
|
sock.print("\r\n")
|
|
sock.print("250 End\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("250- Listing foo\r\n")
|
|
sock.print(" abc /foo\r\n")
|
|
sock.print("250 End\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
entry = ftp.mlst("foo")
|
|
assert_equal("/foo", entry.pathname)
|
|
assert_equal("file", entry.facts["type"])
|
|
assert_equal("FC00U1E554A", entry.facts["unique"])
|
|
assert_equal(1234567, entry.facts["size"])
|
|
assert_equal("r", entry.facts["perm"])
|
|
assert_equal(0644, entry.facts["unix.mode"])
|
|
assert_equal(122, entry.facts["unix.owner"])
|
|
assert_equal(0, entry.facts["unix.group"])
|
|
modify = entry.facts["modify"]
|
|
assert_equal(2013, modify.year)
|
|
assert_equal(12, modify.month)
|
|
assert_equal(20, modify.day)
|
|
assert_equal(3, modify.hour)
|
|
assert_equal(59, modify.min)
|
|
assert_equal(29, modify.sec)
|
|
assert_equal(true, modify.utc?)
|
|
ctime = entry.facts["unix.ctime"]
|
|
assert_equal(12, ctime.hour)
|
|
assert_equal(1, ctime.min)
|
|
assert_equal(40, ctime.sec)
|
|
atime = entry.facts["unix.atime"]
|
|
assert_equal(13, atime.hour)
|
|
assert_equal(11, atime.min)
|
|
assert_equal(39, atime.sec)
|
|
assert_match("MLST foo\r\n", commands.shift)
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.mlst("foo")
|
|
end
|
|
assert_match("MLST foo\r\n", commands.shift)
|
|
assert_raise(Net::FTPProtoError) do
|
|
ftp.mlst("foo")
|
|
end
|
|
assert_match("MLST foo\r\n", commands.shift)
|
|
entry = ftp.mlst("foo")
|
|
assert_equal("/foo", entry.pathname)
|
|
assert_match("MLST foo\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_mlsd
|
|
commands = []
|
|
entry_lines = [
|
|
"Type=file;Unique=FC00U1E554A;Size=1234567;Modify=20131220035929.123456;Perm=r; foo bar",
|
|
"Type=cdir;Unique=FC00U1E554B;Modify=20131220035929;Perm=flcdmpe; .",
|
|
"Type=pdir;Unique=FC00U1E554C;Modify=20131220035929;Perm=flcdmpe; ..",
|
|
]
|
|
server = create_ftp_server { |sock|
|
|
sock.print("220 (test_ftp).\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("331 Please specify the password.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("230 Login successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to ASCII mode.\r\n")
|
|
line = sock.gets
|
|
commands.push(line)
|
|
port_args = line.slice(/\APORT (.*)/, 1).split(/,/)
|
|
host = port_args[0, 4].join(".")
|
|
port = port_args[4, 2].map(&:to_i).inject {|x, y| (x << 8) + y}
|
|
sock.print("200 PORT command successful.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("150 Here comes the directory listing.\r\n")
|
|
begin
|
|
conn = TCPSocket.new(host, port)
|
|
entry_lines.each do |line|
|
|
conn.print(line, "\r\n")
|
|
end
|
|
rescue Errno::EPIPE
|
|
ensure
|
|
assert_nil($!)
|
|
conn.close
|
|
end
|
|
sock.print("226 Directory send OK.\r\n")
|
|
commands.push(sock.gets)
|
|
sock.print("200 Switching to Binary mode.\r\n")
|
|
}
|
|
begin
|
|
begin
|
|
ftp = Net::FTP.new
|
|
ftp.connect(SERVER_ADDR, server.port)
|
|
ftp.login
|
|
assert_match(/\AUSER /, commands.shift)
|
|
assert_match(/\APASS /, commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
entries = ftp.mlsd("/")
|
|
assert_equal(3, entries.size)
|
|
assert_equal("foo bar", entries[0].pathname)
|
|
assert_equal(".", entries[1].pathname)
|
|
assert_equal("..", entries[2].pathname)
|
|
assert_equal("file", entries[0].facts["type"])
|
|
assert_equal("cdir", entries[1].facts["type"])
|
|
assert_equal("pdir", entries[2].facts["type"])
|
|
assert_equal("flcdmpe", entries[1].facts["perm"])
|
|
modify = entries[0].facts["modify"]
|
|
assert_equal(2013, modify.year)
|
|
assert_equal(12, modify.month)
|
|
assert_equal(20, modify.day)
|
|
assert_equal(3, modify.hour)
|
|
assert_equal(59, modify.min)
|
|
assert_equal(29, modify.sec)
|
|
assert_equal(123456, modify.usec)
|
|
assert_equal(true, modify.utc?)
|
|
assert_equal("TYPE A\r\n", commands.shift)
|
|
assert_match(/\APORT /, commands.shift)
|
|
assert_match("MLSD /\r\n", commands.shift)
|
|
assert_equal("TYPE I\r\n", commands.shift)
|
|
assert_equal(nil, commands.shift)
|
|
ensure
|
|
ftp.close if ftp
|
|
end
|
|
ensure
|
|
server.close
|
|
end
|
|
end
|
|
|
|
def test_parse257
|
|
ftp = Net::FTP.new
|
|
assert_equal('/foo/bar',
|
|
ftp.send(:parse257, '257 "/foo/bar" directory created'))
|
|
assert_equal('/foo/bar"baz',
|
|
ftp.send(:parse257, '257 "/foo/bar""baz" directory created'))
|
|
assert_equal('/foo/x"y"z',
|
|
ftp.send(:parse257, '257 "/foo/x""y""z" directory created'))
|
|
assert_equal('/foo/bar',
|
|
ftp.send(:parse257, '257 "/foo/bar" "comment"'))
|
|
assert_equal('',
|
|
ftp.send(:parse257, '257 "" directory created'))
|
|
assert_equal('',
|
|
ftp.send(:parse257, '257 directory created'))
|
|
assert_raise(Net::FTPReplyError) do
|
|
ftp.send(:parse257, "500 Syntax error")
|
|
end
|
|
end
|
|
|
|
def test_putline_reject_crlf
|
|
ftp = Net::FTP.new
|
|
assert_raise(ArgumentError) do
|
|
ftp.send(:putline, "\r")
|
|
end
|
|
assert_raise(ArgumentError) do
|
|
ftp.send(:putline, "\n")
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def create_ftp_server(sleep_time = nil)
|
|
server = TCPServer.new(SERVER_ADDR, 0)
|
|
@thread = Thread.start do
|
|
if sleep_time
|
|
sleep(sleep_time)
|
|
end
|
|
sock = server.accept
|
|
begin
|
|
sock.setsockopt(Socket::SOL_SOCKET, Socket::SO_OOBINLINE, 1)
|
|
yield(sock)
|
|
sock.shutdown(Socket::SHUT_WR)
|
|
sock.read unless sock.eof?
|
|
ensure
|
|
sock.close
|
|
end
|
|
end
|
|
def server.port
|
|
addr[1]
|
|
end
|
|
return server
|
|
end
|
|
end
|