mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
net/imap: Net::IMAP#append should not block when NO response is received
[ruby-dev:50129] [Bug#13579] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58792 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
3c5344bf30
commit
84c1596342
2 changed files with 113 additions and 14 deletions
|
@ -1098,6 +1098,7 @@ module Net
|
||||||
@tagged_responses = {}
|
@tagged_responses = {}
|
||||||
@response_handlers = []
|
@response_handlers = []
|
||||||
@tagged_response_arrival = new_cond
|
@tagged_response_arrival = new_cond
|
||||||
|
@continued_command_tag = nil
|
||||||
@continuation_request_arrival = new_cond
|
@continuation_request_arrival = new_cond
|
||||||
@idle_done_cond = nil
|
@idle_done_cond = nil
|
||||||
@logout_command_tag = nil
|
@logout_command_tag = nil
|
||||||
|
@ -1160,8 +1161,12 @@ module Net
|
||||||
when TaggedResponse
|
when TaggedResponse
|
||||||
@tagged_responses[resp.tag] = resp
|
@tagged_responses[resp.tag] = resp
|
||||||
@tagged_response_arrival.broadcast
|
@tagged_response_arrival.broadcast
|
||||||
if resp.tag == @logout_command_tag
|
case resp.tag
|
||||||
|
when @logout_command_tag
|
||||||
return
|
return
|
||||||
|
when @continued_command_tag
|
||||||
|
@exception = RESPONSE_ERRORS[resp.name].new(resp)
|
||||||
|
@continuation_request_arrival.signal
|
||||||
end
|
end
|
||||||
when UntaggedResponse
|
when UntaggedResponse
|
||||||
record_response(resp.name, resp.data)
|
record_response(resp.name, resp.data)
|
||||||
|
@ -1251,7 +1256,7 @@ module Net
|
||||||
put_string(tag + " " + cmd)
|
put_string(tag + " " + cmd)
|
||||||
args.each do |i|
|
args.each do |i|
|
||||||
put_string(" ")
|
put_string(" ")
|
||||||
send_data(i)
|
send_data(i, tag)
|
||||||
end
|
end
|
||||||
put_string(CRLF)
|
put_string(CRLF)
|
||||||
if cmd == "LOGOUT"
|
if cmd == "LOGOUT"
|
||||||
|
@ -1307,7 +1312,7 @@ module Net
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_data(data)
|
def send_data(data, tag = nil)
|
||||||
case data
|
case data
|
||||||
when nil
|
when nil
|
||||||
put_string("NIL")
|
put_string("NIL")
|
||||||
|
@ -1322,7 +1327,7 @@ module Net
|
||||||
when Symbol
|
when Symbol
|
||||||
send_symbol_data(data)
|
send_symbol_data(data)
|
||||||
else
|
else
|
||||||
data.send_data(self)
|
data.send_data(self, tag)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1345,11 +1350,16 @@ module Net
|
||||||
put_string('"' + str.gsub(/["\\]/n, "\\\\\\&") + '"')
|
put_string('"' + str.gsub(/["\\]/n, "\\\\\\&") + '"')
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_literal(str)
|
def send_literal(str, tag)
|
||||||
put_string("{" + str.bytesize.to_s + "}" + CRLF)
|
put_string("{" + str.bytesize.to_s + "}" + CRLF)
|
||||||
@continuation_request_arrival.wait
|
@continued_command_tag = tag
|
||||||
raise @exception if @exception
|
begin
|
||||||
put_string(str)
|
@continuation_request_arrival.wait
|
||||||
|
raise @exception if @exception
|
||||||
|
put_string(str)
|
||||||
|
ensure
|
||||||
|
@continued_command_tag = nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_number_data(num)
|
def send_number_data(num)
|
||||||
|
@ -1510,7 +1520,7 @@ module Net
|
||||||
end
|
end
|
||||||
|
|
||||||
class RawData # :nodoc:
|
class RawData # :nodoc:
|
||||||
def send_data(imap)
|
def send_data(imap, tag)
|
||||||
imap.send(:put_string, @data)
|
imap.send(:put_string, @data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1525,7 +1535,7 @@ module Net
|
||||||
end
|
end
|
||||||
|
|
||||||
class Atom # :nodoc:
|
class Atom # :nodoc:
|
||||||
def send_data(imap)
|
def send_data(imap, tag)
|
||||||
imap.send(:put_string, @data)
|
imap.send(:put_string, @data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1540,7 +1550,7 @@ module Net
|
||||||
end
|
end
|
||||||
|
|
||||||
class QuotedString # :nodoc:
|
class QuotedString # :nodoc:
|
||||||
def send_data(imap)
|
def send_data(imap, tag)
|
||||||
imap.send(:send_quoted_string, @data)
|
imap.send(:send_quoted_string, @data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1555,8 +1565,8 @@ module Net
|
||||||
end
|
end
|
||||||
|
|
||||||
class Literal # :nodoc:
|
class Literal # :nodoc:
|
||||||
def send_data(imap)
|
def send_data(imap, tag)
|
||||||
imap.send(:send_literal, @data)
|
imap.send(:send_literal, @data, tag)
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate
|
def validate
|
||||||
|
@ -1570,7 +1580,7 @@ module Net
|
||||||
end
|
end
|
||||||
|
|
||||||
class MessageSet # :nodoc:
|
class MessageSet # :nodoc:
|
||||||
def send_data(imap)
|
def send_data(imap, tag)
|
||||||
imap.send(:put_string, format_internal(@data))
|
imap.send(:put_string, format_internal(@data))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -3653,6 +3663,10 @@ module Net
|
||||||
# out due to inactivity.
|
# out due to inactivity.
|
||||||
class ByeResponseError < ResponseError
|
class ByeResponseError < ResponseError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
RESPONSE_ERRORS = Hash.new(ResponseError)
|
||||||
|
RESPONSE_ERRORS["NO"] = NoResponseError
|
||||||
|
RESPONSE_ERRORS["BAD"] = BadResponseError
|
||||||
|
|
||||||
# Error raised when too many flags are interned to symbols.
|
# Error raised when too many flags are interned to symbols.
|
||||||
class FlagCountError < Error
|
class FlagCountError < Error
|
||||||
|
|
|
@ -559,6 +559,91 @@ class IMAPTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_append
|
||||||
|
server = create_tcp_server
|
||||||
|
port = server.addr[1]
|
||||||
|
mail = <<EOF.gsub(/\n/, "\r\n")
|
||||||
|
From: shugo@example.com
|
||||||
|
To: matz@example.com
|
||||||
|
Subject: hello
|
||||||
|
|
||||||
|
hello world
|
||||||
|
EOF
|
||||||
|
requests = []
|
||||||
|
received_mail = nil
|
||||||
|
@threads << Thread.start do
|
||||||
|
sock = server.accept
|
||||||
|
begin
|
||||||
|
sock.print("* OK test server\r\n")
|
||||||
|
line = sock.gets
|
||||||
|
requests.push(line)
|
||||||
|
size = line.slice(/{(\d+)}\r\n/, 1).to_i
|
||||||
|
sock.print("+ Ready for literal data\r\n")
|
||||||
|
received_mail = sock.read(size)
|
||||||
|
sock.gets
|
||||||
|
sock.print("RUBY0001 OK APPEND completed\r\n")
|
||||||
|
sock.gets
|
||||||
|
sock.print("* BYE terminating connection\r\n")
|
||||||
|
sock.print("RUBY0002 OK LOGOUT completed\r\n")
|
||||||
|
ensure
|
||||||
|
sock.close
|
||||||
|
server.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
imap = Net::IMAP.new(SERVER_ADDR, :port => port)
|
||||||
|
resp = imap.append("INBOX", mail)
|
||||||
|
assert_equal(1, requests.length)
|
||||||
|
assert_equal("RUBY0001 APPEND INBOX {#{mail.size}}\r\n", requests[0])
|
||||||
|
assert_equal(mail, received_mail)
|
||||||
|
imap.logout
|
||||||
|
ensure
|
||||||
|
imap.disconnect if imap
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_append_fail
|
||||||
|
server = create_tcp_server
|
||||||
|
port = server.addr[1]
|
||||||
|
mail = <<EOF.gsub(/\n/, "\r\n")
|
||||||
|
From: shugo@example.com
|
||||||
|
To: matz@example.com
|
||||||
|
Subject: hello
|
||||||
|
|
||||||
|
hello world
|
||||||
|
EOF
|
||||||
|
requests = []
|
||||||
|
received_mail = nil
|
||||||
|
@threads << Thread.start do
|
||||||
|
sock = server.accept
|
||||||
|
begin
|
||||||
|
sock.print("* OK test server\r\n")
|
||||||
|
line = sock.gets
|
||||||
|
requests.push(line)
|
||||||
|
sock.print("RUBY0001 NO Mailbox doesn't exist\r\n")
|
||||||
|
sock.gets
|
||||||
|
sock.print("* BYE terminating connection\r\n")
|
||||||
|
sock.print("RUBY0002 OK LOGOUT completed\r\n")
|
||||||
|
ensure
|
||||||
|
sock.close
|
||||||
|
server.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
imap = Net::IMAP.new(SERVER_ADDR, :port => port)
|
||||||
|
assert_raise(Net::IMAP::NoResponseError) do
|
||||||
|
imap.append("INBOX", mail)
|
||||||
|
end
|
||||||
|
assert_equal(1, requests.length)
|
||||||
|
assert_equal("RUBY0001 APPEND INBOX {#{mail.size}}\r\n", requests[0])
|
||||||
|
imap.logout
|
||||||
|
ensure
|
||||||
|
imap.disconnect if imap
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def imaps_test
|
def imaps_test
|
||||||
|
|
Loading…
Reference in a new issue