* lib/net/ftp.rb (read_timeout=, open_timeout=): supported timeout.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35194 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
a3626110d9
commit
5f81a53fd2
@ -1,3 +1,7 @@
|
|||||||
|
Sat Mar 31 13:42:39 2012 Shugo Maeda <shugo@ruby-lang.org>
|
||||||
|
|
||||||
|
* lib/net/ftp.rb (read_timeout=, open_timeout=): supported timeout.
|
||||||
|
|
||||||
Sat Mar 31 13:20:40 2012 Sokolov Yura (funny-falcon) <funny.falcon@gmail.com>
|
Sat Mar 31 13:20:40 2012 Sokolov Yura (funny-falcon) <funny.falcon@gmail.com>
|
||||||
|
|
||||||
* hash.c: remove unnecessary checks for Qundef in hash iterations.
|
* hash.c: remove unnecessary checks for Qundef in hash iterations.
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
require "socket"
|
require "socket"
|
||||||
require "monitor"
|
require "monitor"
|
||||||
|
require "net/protocol"
|
||||||
|
|
||||||
module Net
|
module Net
|
||||||
|
|
||||||
@ -76,7 +77,7 @@ module Net
|
|||||||
# :stopdoc:
|
# :stopdoc:
|
||||||
FTP_PORT = 21
|
FTP_PORT = 21
|
||||||
CRLF = "\r\n"
|
CRLF = "\r\n"
|
||||||
DEFAULT_BLOCKSIZE = 4096
|
DEFAULT_BLOCKSIZE = BufferedIO::BUFSIZE
|
||||||
# :startdoc:
|
# :startdoc:
|
||||||
|
|
||||||
# When +true+, transfers are performed in binary mode. Default: +true+.
|
# When +true+, transfers are performed in binary mode. Default: +true+.
|
||||||
@ -93,6 +94,24 @@ module Net
|
|||||||
# transfers are resumed or restarted. Default: +false+.
|
# transfers are resumed or restarted. Default: +false+.
|
||||||
attr_accessor :resume
|
attr_accessor :resume
|
||||||
|
|
||||||
|
# Number of seconds to wait for the connection to open. Any number
|
||||||
|
# may be used, including Floats for fractional seconds. If the FTP
|
||||||
|
# object cannot open a connection in this many seconds, it raises a
|
||||||
|
# Net::OpenTimeout exception.
|
||||||
|
attr_accessor :open_timeout
|
||||||
|
|
||||||
|
# Number of seconds to wait for one block to be read (via one read(2)
|
||||||
|
# call). Any number may be used, including Floats for fractional
|
||||||
|
# seconds. If the FTP object cannot read data in this many seconds,
|
||||||
|
# it raises a TimeoutError exception.
|
||||||
|
attr_reader :read_timeout
|
||||||
|
|
||||||
|
# Setter for the read_timeout attribute.
|
||||||
|
def read_timeout=(sec)
|
||||||
|
@sock.read_timeout = sec
|
||||||
|
@read_timeout = sec
|
||||||
|
end
|
||||||
|
|
||||||
# The server's welcome message.
|
# The server's welcome message.
|
||||||
attr_reader :welcome
|
attr_reader :welcome
|
||||||
|
|
||||||
@ -135,6 +154,8 @@ module Net
|
|||||||
@resume = false
|
@resume = false
|
||||||
@sock = NullSocket.new
|
@sock = NullSocket.new
|
||||||
@logged_in = false
|
@logged_in = false
|
||||||
|
@open_timeout = nil
|
||||||
|
@read_timeout = 60
|
||||||
if host
|
if host
|
||||||
connect(host)
|
connect(host)
|
||||||
if user
|
if user
|
||||||
@ -199,12 +220,17 @@ module Net
|
|||||||
# SOCKS_SERVER, then a SOCKSSocket is returned, else a TCPSocket is
|
# SOCKS_SERVER, then a SOCKSSocket is returned, else a TCPSocket is
|
||||||
# returned.
|
# returned.
|
||||||
def open_socket(host, port) # :nodoc:
|
def open_socket(host, port) # :nodoc:
|
||||||
if defined? SOCKSSocket and ENV["SOCKS_SERVER"]
|
return Timeout.timeout(@open_timeout, Net::OpenTimeout) {
|
||||||
@passive = true
|
if defined? SOCKSSocket and ENV["SOCKS_SERVER"]
|
||||||
return SOCKSSocket.open(host, port)
|
@passive = true
|
||||||
else
|
sock = SOCKSSocket.open(host, port)
|
||||||
return TCPSocket.open(host, port)
|
else
|
||||||
end
|
sock = TCPSocket.open(host, port)
|
||||||
|
end
|
||||||
|
io = BufferedSocket.new(sock)
|
||||||
|
io.read_timeout = @read_timeout
|
||||||
|
io
|
||||||
|
}
|
||||||
end
|
end
|
||||||
private :open_socket
|
private :open_socket
|
||||||
|
|
||||||
@ -405,7 +431,8 @@ module Net
|
|||||||
if resp[0] != ?1
|
if resp[0] != ?1
|
||||||
raise FTPReplyError, resp
|
raise FTPReplyError, resp
|
||||||
end
|
end
|
||||||
conn = sock.accept
|
conn = BufferedSocket.new(sock.accept)
|
||||||
|
conn.read_timeout = @read_timeout
|
||||||
sock.close
|
sock.close
|
||||||
end
|
end
|
||||||
return conn
|
return conn
|
||||||
@ -1016,10 +1043,47 @@ module Net
|
|||||||
|
|
||||||
# :stopdoc:
|
# :stopdoc:
|
||||||
class NullSocket
|
class NullSocket
|
||||||
|
def read_timeout=(sec)
|
||||||
|
end
|
||||||
|
|
||||||
|
def close
|
||||||
|
end
|
||||||
|
|
||||||
def method_missing(mid, *args)
|
def method_missing(mid, *args)
|
||||||
raise FTPConnectionError, "not connected"
|
raise FTPConnectionError, "not connected"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class BufferedSocket < BufferedIO
|
||||||
|
[:addr, :peeraddr].each do |method|
|
||||||
|
define_method(method) { |*args|
|
||||||
|
@io.__send__(method, *args)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def read(len = nil)
|
||||||
|
if len
|
||||||
|
s = super(len, "", true)
|
||||||
|
return s.empty? ? nil : s
|
||||||
|
else
|
||||||
|
result = ""
|
||||||
|
while s = super(BUFSIZ, "", true)
|
||||||
|
result << s
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def gets
|
||||||
|
return readuntil("\n")
|
||||||
|
rescue EOFError
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def readline
|
||||||
|
return readuntil("\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
# :startdoc:
|
# :startdoc:
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
require "net/ftp"
|
require "net/ftp"
|
||||||
require "test/unit"
|
require "test/unit"
|
||||||
require "ostruct"
|
require "ostruct"
|
||||||
|
require "stringio"
|
||||||
|
|
||||||
class FTPTest < Test::Unit::TestCase
|
class FTPTest < Test::Unit::TestCase
|
||||||
|
SERVER_ADDR = "127.0.0.1"
|
||||||
|
|
||||||
def test_not_connected
|
def test_not_connected
|
||||||
ftp = Net::FTP.new
|
ftp = Net::FTP.new
|
||||||
assert_raise(Net::FTPConnectionError) do
|
assert_raise(Net::FTPConnectionError) do
|
||||||
@ -107,4 +110,430 @@ class FTPTest < Test::Unit::TestCase
|
|||||||
assert_equal(795192, ftp.send(:parse_pasv_port, "12,34,56"))
|
assert_equal(795192, ftp.send(:parse_pasv_port, "12,34,56"))
|
||||||
assert_equal(203569230, ftp.send(:parse_pasv_port, "12,34,56,78"))
|
assert_equal(203569230, ftp.send(:parse_pasv_port, "12,34,56,78"))
|
||||||
end
|
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
|
||||||
|
|
||||||
|
# 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(Timeout::Error) 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 if ftp
|
||||||
|
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")
|
||||||
|
conn = TCPSocket.new(host, port)
|
||||||
|
list_lines.each_with_index do |l, i|
|
||||||
|
if i == 1
|
||||||
|
sleep(0.3)
|
||||||
|
else
|
||||||
|
sleep(0.1)
|
||||||
|
end
|
||||||
|
conn.print(l, "\r\n")
|
||||||
|
end
|
||||||
|
conn.close
|
||||||
|
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(Timeout::Error) 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_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)
|
||||||
|
binary_data.scan(/.{1,1024}/nm).each_with_index do |s, i|
|
||||||
|
if i == 1
|
||||||
|
sleep(0.3)
|
||||||
|
else
|
||||||
|
sleep(0.1)
|
||||||
|
end
|
||||||
|
conn.print(s)
|
||||||
|
end
|
||||||
|
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 = ""
|
||||||
|
assert_raise(Timeout::Error) do
|
||||||
|
ftp.retrbinary("RETR foo", 1024) do |s|
|
||||||
|
buf << s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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 if ftp
|
||||||
|
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.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.retrbinary("RETR foo", 1024) do |s|
|
||||||
|
buf << s
|
||||||
|
end
|
||||||
|
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_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
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
|
||||||
|
def create_ftp_server(sleep_time = nil)
|
||||||
|
server = TCPServer.new(SERVER_ADDR, 0)
|
||||||
|
Thread.start do
|
||||||
|
begin
|
||||||
|
if sleep_time
|
||||||
|
sleep(sleep_time)
|
||||||
|
end
|
||||||
|
sock = server.accept
|
||||||
|
begin
|
||||||
|
yield(sock)
|
||||||
|
ensure
|
||||||
|
sock.close
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
def server.port
|
||||||
|
addr[1]
|
||||||
|
end
|
||||||
|
return server
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user