diff --git a/lib/net/imap/response_parser.rb b/lib/net/imap/response_parser.rb index e9775c00..04e2ee2b 100644 --- a/lib/net/imap/response_parser.rb +++ b/lib/net/imap/response_parser.rb @@ -8,6 +8,8 @@ class IMAP < Protocol # Parses an \IMAP server response. class ResponseParser + MAX_UID_SET_SIZE = 10_000 + include ParserUtils extend ParserUtils::Generator @@ -1889,9 +1891,16 @@ def CopyUID(...) DeprecatedUIDPlus(...) || CopyUIDData.new(...) end # TODO: remove this code in the v0.6.0 release def DeprecatedUIDPlus(validity, src_uids = nil, dst_uids) return unless config.parser_use_deprecated_uidplus_data - src_uids &&= src_uids.each_ordered_number.to_a - dst_uids = dst_uids.each_ordered_number.to_a - UIDPlusData.new(validity, src_uids, dst_uids) + compact_uid_sets = [src_uids, dst_uids].compact + count = compact_uid_sets.map { _1.count_with_duplicates }.max + max = MAX_UID_SET_SIZE + if count <= max + src_uids &&= src_uids.each_ordered_number.to_a + dst_uids = dst_uids.each_ordered_number.to_a + UIDPlusData.new(validity, src_uids, dst_uids) + else + parse_error("uid-set is too large: %d > %d", count, max) + end end ADDRESS_REGEXP = /\G diff --git a/test/net/imap/test_imap_response_parser.rb b/test/net/imap/test_imap_response_parser.rb index e85b0b4e..695f21b9 100644 --- a/test/net/imap/test_imap_response_parser.rb +++ b/test/net/imap/test_imap_response_parser.rb @@ -206,6 +206,11 @@ def test_fetch_binary_and_binary_size parser = Net::IMAP::ResponseParser.new(config: { parser_use_deprecated_uidplus_data: true, }) + assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do + parser.parse( + "A004 OK [APPENDUID 1 10000:20000,1] Done\r\n" + ) + end response = parser.parse("A004 OK [APPENDUID 1 101:200] Done\r\n") uidplus = response.data.code.data assert_instance_of Net::IMAP::UIDPlusData, uidplus @@ -254,6 +259,11 @@ def test_fetch_binary_and_binary_size parser = Net::IMAP::ResponseParser.new(config: { parser_use_deprecated_uidplus_data: true, }) + assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do + parser.parse( + "A004 OK [copyUID 1 10000:20000,1 1:10001] Done\r\n" + ) + end response = parser.parse("A004 OK [copyUID 1 101:200 1:100] Done\r\n") uidplus = response.data.code.data assert_instance_of Net::IMAP::UIDPlusData, uidplus