summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/net/imap.rb34
-rw-r--r--test/net/imap/test_imap_response_parser.rb54
2 files changed, 87 insertions, 1 deletions
diff --git a/lib/net/imap.rb b/lib/net/imap.rb
index 8b7529d79..3a8145e03 100644
--- a/lib/net/imap.rb
+++ b/lib/net/imap.rb
@@ -270,6 +270,16 @@ module Net
return @@debug = val
end
+ # Returns the max number of flags interned to symbols.
+ def self.max_flag_count
+ return @@max_flag_count
+ end
+
+ # Sets the max number of flags interned to symbols.
+ def self.max_flag_count=(count)
+ @@max_flag_count = count
+ end
+
# Adds an authenticator for Net::IMAP#authenticate. +auth_type+
# is the type of authentication this authenticator supports
# (for instance, "LOGIN"). The +authenticator+ is an object
@@ -929,6 +939,7 @@ module Net
@@debug = false
@@authenticators = {}
+ @@max_flag_count = 10000
# call-seq:
# Net::IMAP.new(host, options = {})
@@ -1929,6 +1940,14 @@ module Net
end
class ResponseParser # :nodoc:
+ def initialize
+ @str = nil
+ @pos = nil
+ @lex_state = nil
+ @token = nil
+ @flag_symbols = {}
+ end
+
def parse(str)
@str = str
@pos = 0
@@ -2939,7 +2958,16 @@ module Net
if @str.index(/\(([^)]*)\)/ni, @pos)
@pos = $~.end(0)
return $1.scan(FLAG_REGEXP).collect { |flag, atom|
- atom || flag.capitalize.intern
+ if atom
+ atom
+ else
+ symbol = flag.capitalize.untaint.intern
+ @flag_symbols[symbol] = true
+ if @flag_symbols.length > IMAP.max_flag_count
+ raise FlagCountError, "number of flag symbols exceeded"
+ end
+ symbol
+ end
}
else
parse_error("invalid flag list")
@@ -3410,6 +3438,10 @@ module Net
# out due to inactivity.
class ByeResponseError < ResponseError
end
+
+ # Error raised when too many flags are interned to symbols.
+ class FlagCountError < Error
+ end
end
end
diff --git a/test/net/imap/test_imap_response_parser.rb b/test/net/imap/test_imap_response_parser.rb
new file mode 100644
index 000000000..5c122dd59
--- /dev/null
+++ b/test/net/imap/test_imap_response_parser.rb
@@ -0,0 +1,54 @@
+require "net/imap"
+require "test/unit"
+
+class IMAPResponseParserTest < Test::Unit::TestCase
+ def setup
+ @do_not_reverse_lookup = Socket.do_not_reverse_lookup
+ Socket.do_not_reverse_lookup = true
+ @max_flag_count = Net::IMAP.max_flag_count
+ Net::IMAP.max_flag_count = 3
+ end
+
+ def teardown
+ Socket.do_not_reverse_lookup = @do_not_reverse_lookup
+ Net::IMAP.max_flag_count = @max_flag_count
+ end
+
+ def test_flag_list_safe
+ parser = Net::IMAP::ResponseParser.new
+ response = lambda {
+ $SAFE = 1
+ parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* LIST (\\HasChildren) "." "INBOX"
+EOF
+ }.call
+ assert_equal [:Haschildren], response.data.attr
+ end
+
+ def test_flag_list_too_many_flags
+ parser = Net::IMAP::ResponseParser.new
+ assert_nothing_raised do
+ 3.times do |i|
+ parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* LIST (\\Foo#{i}) "." "INBOX"
+EOF
+ end
+ end
+ assert_raise(Net::IMAP::FlagCountError) do
+ parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* LIST (\\Foo3) "." "INBOX"
+EOF
+ end
+ end
+
+ def test_flag_list_many_same_flags
+ parser = Net::IMAP::ResponseParser.new
+ assert_nothing_raised do
+ 100.times do
+ parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
+* LIST (\\Foo) "." "INBOX"
+EOF
+ end
+ end
+ end
+end