22
33require "net/imap"
44require "test/unit"
5- require_relative "fake_server"
65
76class IMAPMaxResponseSizeTest < Test ::Unit ::TestCase
8- include Net ::IMAP ::FakeServer ::TestHelper
97
108 def setup
11- Net ::IMAP . config . reset
129 @do_not_reverse_lookup = Socket . do_not_reverse_lookup
1310 Socket . do_not_reverse_lookup = true
1411 @threads = [ ]
@@ -23,45 +20,95 @@ def teardown
2320 end
2421
2522 test "#max_response_size reading literals" do
26- with_fake_server ( preauth : true ) do |server , imap |
23+ _ , port = with_server_socket do |sock |
24+ sock . gets # => NOOP
25+ sock . print ( "RUBY0001 OK done\r \n " )
26+ sock . gets # => NOOP
27+ sock . print ( "* 1 FETCH (BODY[] {12345}\r \n " + "a" * 12_345 + ")\r \n " )
28+ sock . print ( "RUBY0002 OK done\r \n " )
29+ "RUBY0003"
30+ end
31+ Timeout . timeout ( 5 ) do
32+ imap = Net ::IMAP . new ( "localhost" , port : port , max_response_size : 640 << 20 )
33+ assert_equal 640 << 20 , imap . max_response_size
2734 imap . max_response_size = 12_345 + 30
28- server . on ( "NOOP" ) do |resp |
29- resp . untagged ( "1 FETCH (BODY[] {12345}\r \n " + "a" * 12_345 + ")" )
30- resp . done_ok
31- end
32- imap . noop
33- assert_equal "a" * 12_345 , imap . responses ( "FETCH" ) . first . message
35+ assert_equal 12_345 + 30 , imap . max_response_size
36+ imap . noop # to reset the get_response limit
37+ imap . noop # to send the FETCH
38+ assert_equal "a" * 12_345 , imap . responses [ "FETCH" ] . first . attr [ "BODY[]" ]
39+ ensure
40+ imap . logout rescue nil
41+ imap . disconnect rescue nil
3442 end
3543 end
3644
3745 test "#max_response_size closes connection for too long line" do
38- Net :: IMAP . config . max_response_size = 10
39- run_fake_server_in_thread ( preauth : false , ignore_io_error : true ) do | server |
40- assert_raise_with_message (
41- Net :: IMAP :: ResponseTooLargeError , /exceeds max_response_size .* \b 10B \b /
42- ) do
43- with_client ( "localhost" , port : server . port ) do
44- fail "should not get here (greeting longer than max_response_size)"
45- end
46- end
46+ _ , port = with_server_socket do | sock |
47+ sock . gets or next # => never called
48+ fail "client disconnects first"
49+ end
50+ assert_raise_with_message (
51+ Net :: IMAP :: ResponseTooLargeError , /exceeds max_response_size .* \b 10B \b /
52+ ) do
53+ Net :: IMAP . new ( "localhost" , port : port , max_response_size : 10 )
54+ fail "should not get here (greeting longer than max_response_size)"
4755 end
4856 end
4957
5058 test "#max_response_size closes connection for too long literal" do
51- Net ::IMAP . config . max_response_size = 1 <<20
52- with_fake_server ( preauth : false , ignore_io_error : true ) do |server , client |
53- client . max_response_size = 50
54- server . on ( "NOOP" ) do |resp |
55- resp . untagged ( "1 FETCH (BODY[] {1000}\r \n " + "a" * 1000 + ")" )
56- end
57- assert_raise_with_message (
58- Net ::IMAP ::ResponseTooLargeError ,
59- /\d +B read \+ 1000B literal.* exceeds max_response_size .*\b 50B\b /
60- ) do
61- client . noop
62- fail "should not get here (FETCH literal longer than max_response_size)"
59+ _ , port = with_server_socket ( ignore_io_error : true ) do |sock |
60+ sock . gets # => NOOP
61+ sock . print "* 1 FETCH (BODY[] {1000}\r \n " + "a" * 1000 + ")\r \n "
62+ sock . print ( "RUBY0001 OK done\r \n " )
63+ end
64+ client = Net ::IMAP . new ( "localhost" , port : port , max_response_size : 1000 )
65+ assert_equal 1000 , client . max_response_size
66+ client . max_response_size = 50
67+ assert_equal 50 , client . max_response_size
68+ assert_raise_with_message (
69+ Net ::IMAP ::ResponseTooLargeError ,
70+ /\d +B read \+ 1000B literal.* exceeds max_response_size .*\b 50B\b /
71+ ) do
72+ client . noop
73+ fail "should not get here (FETCH literal longer than max_response_size)"
74+ end
75+ end
76+
77+ def with_server_socket ( ignore_io_error : false )
78+ server = create_tcp_server
79+ port = server . addr [ 1 ]
80+ start_server do
81+ Timeout . timeout ( 5 ) do
82+ sock = server . accept
83+ sock . print ( "* OK connection established\r \n " )
84+ logout_tag = yield sock if block_given?
85+ sock . gets # => LOGOUT
86+ sock . print ( "* BYE terminating connection\r \n " )
87+ sock . print ( "#{ logout_tag } OK LOGOUT completed\r \n " ) if logout_tag
88+ rescue IOError , EOFError , Errno ::ECONNABORTED , Errno ::ECONNRESET ,
89+ Errno ::EPIPE , Errno ::ETIMEDOUT
90+ ignore_io_error or raise
91+ ensure
92+ sock . close rescue nil
93+ server . close rescue nil
6394 end
6495 end
96+ return server , port
97+ end
98+
99+ def start_server
100+ th = Thread . new do
101+ yield
102+ end
103+ @threads << th
104+ sleep 0.1 until th . stop?
65105 end
66106
107+ def create_tcp_server
108+ return TCPServer . new ( server_addr , 0 )
109+ end
110+
111+ def server_addr
112+ Addrinfo . tcp ( "localhost" , 0 ) . ip_address
113+ end
67114end
0 commit comments