2
2
3
3
require "net/imap"
4
4
require "test/unit"
5
- require_relative "fake_server"
6
5
7
6
class IMAPMaxResponseSizeTest < Test ::Unit ::TestCase
8
- include Net ::IMAP ::FakeServer ::TestHelper
9
7
10
8
def setup
11
- Net ::IMAP . config . reset
12
9
@do_not_reverse_lookup = Socket . do_not_reverse_lookup
13
10
Socket . do_not_reverse_lookup = true
14
11
@threads = [ ]
@@ -23,45 +20,95 @@ def teardown
23
20
end
24
21
25
22
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
27
34
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
34
42
end
35
43
end
36
44
37
45
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)"
47
55
end
48
56
end
49
57
50
58
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
63
94
end
64
95
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?
65
105
end
66
106
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
67
114
end
0 commit comments