@@ -131,8 +131,25 @@ def self.default; @default end
131
131
def self . global ; @global if defined? ( @global ) end
132
132
133
133
# A hash of hard-coded configurations, indexed by version number or name.
134
+ # Values can be accessed with any object that responds to +to_sym+ or
135
+ # +to_r+/+to_f+ with a non-zero number.
136
+ #
137
+ # Config::[] gets named or numbered versions from this hash.
138
+ #
139
+ # For example:
140
+ # Net::IMAP::Config.version_defaults[0.5] == Net::IMAP::Config[0.5]
141
+ # Net::IMAP::Config[0.5] == Net::IMAP::Config[0.5r] # => true
142
+ # Net::IMAP::Config["current"] == Net::IMAP::Config[:current] # => true
143
+ # Net::IMAP::Config["0.5.6"] == Net::IMAP::Config[0.5r] # => true
134
144
def self . version_defaults ; @version_defaults end
135
- @version_defaults = { }
145
+ @version_defaults = Hash . new { |h , k |
146
+ # NOTE: String responds to both so the order is significant.
147
+ # And ignore non-numeric conversion to zero, because: "wat!?".to_r == 0
148
+ ( h . fetch ( k . to_r , nil ) || h . fetch ( k . to_f , nil ) if k . is_a? ( Numeric ) ) ||
149
+ ( h . fetch ( k . to_sym , nil ) if k . respond_to? ( :to_sym ) ) ||
150
+ ( h . fetch ( k . to_r , nil ) if k . respond_to? ( :to_r ) && k . to_r != 0 r) ||
151
+ ( h . fetch ( k . to_f , nil ) if k . respond_to? ( :to_f ) && k . to_f != 0.0 )
152
+ }
136
153
137
154
# :call-seq:
138
155
# Net::IMAP::Config[number] -> versioned config
@@ -155,18 +172,17 @@ def self.[](config)
155
172
elsif config . nil? && global . nil? then nil
156
173
elsif config . respond_to? ( :to_hash ) then new ( global , **config ) . freeze
157
174
else
158
- version_defaults . fetch ( config ) do
175
+ version_defaults [ config ] or
159
176
case config
160
177
when Numeric
161
178
raise RangeError , "unknown config version: %p" % [ config ]
162
- when Symbol
179
+ when String , Symbol
163
180
raise KeyError , "unknown config name: %p" % [ config ]
164
181
else
165
182
raise TypeError , "no implicit conversion of %s to %s" % [
166
183
config . class , Config
167
184
]
168
185
end
169
- end
170
186
end
171
187
end
172
188
@@ -193,10 +209,13 @@ def self.[](config)
193
209
194
210
# Seconds to wait until a connection is opened.
195
211
#
212
+ # Applied separately for establishing TCP connection and starting a TLS
213
+ # connection.
214
+ #
196
215
# If the IMAP object cannot open a connection within this time,
197
216
# it raises a Net::OpenTimeout exception.
198
217
#
199
- # See Net::IMAP.new.
218
+ # See Net::IMAP.new and Net::IMAP#starttls .
200
219
#
201
220
# The default value is +30+ seconds.
202
221
attr_accessor :open_timeout , type : Integer
@@ -245,10 +264,44 @@ def self.[](config)
245
264
# present. When capabilities are unknown, Net::IMAP will automatically
246
265
# send a +CAPABILITY+ command first before sending +LOGIN+.
247
266
#
248
- attr_accessor :enforce_logindisabled , type : [
267
+ attr_accessor :enforce_logindisabled , type : Enum [
249
268
false , :when_capabilities_cached , true
250
269
]
251
270
271
+ # The maximum allowed server response size. When +nil+, there is no limit
272
+ # on response size.
273
+ #
274
+ # The default value (512 MiB, since +v0.5.7+) is <em>very high</em> and
275
+ # unlikely to be reached. A _much_ lower value should be used with
276
+ # untrusted servers (for example, when connecting to a user-provided
277
+ # hostname). When using a lower limit, message bodies should be fetched
278
+ # in chunks rather than all at once.
279
+ #
280
+ # <em>Please Note:</em> this only limits the size per response. It does
281
+ # not prevent a flood of individual responses and it does not limit how
282
+ # many unhandled responses may be stored on the responses hash. See
283
+ # Net::IMAP@Unbounded+memory+use.
284
+ #
285
+ # Socket reads are limited to the maximum remaining bytes for the current
286
+ # response: max_response_size minus the bytes that have already been read.
287
+ # When the limit is reached, or reading a +literal+ _would_ go over the
288
+ # limit, ResponseTooLargeError is raised and the connection is closed.
289
+ #
290
+ # Note that changes will not take effect immediately, because the receiver
291
+ # thread may already be waiting for the next response using the previous
292
+ # value. Net::IMAP#noop can force a response and enforce the new setting
293
+ # immediately.
294
+ #
295
+ # ==== Versioned Defaults
296
+ #
297
+ # Net::IMAP#max_response_size <em>was added in +v0.2.5+ and +v0.3.9+ as an
298
+ # attr_accessor, and in +v0.4.20+ and +v0.5.7+ as a delegator to this
299
+ # config attribute.</em>
300
+ #
301
+ # * original: +nil+ <em>(no limit)</em>
302
+ # * +0.5+: 512 MiB
303
+ attr_accessor :max_response_size , type : Integer?
304
+
252
305
# Controls the behavior of Net::IMAP#responses when called without any
253
306
# arguments (+type+ or +block+).
254
307
#
@@ -275,7 +328,7 @@ def self.[](config)
275
328
# Raise an ArgumentError with the deprecation warning.
276
329
#
277
330
# Note: #responses_without_args is an alias for #responses_without_block.
278
- attr_accessor :responses_without_block , type : [
331
+ attr_accessor :responses_without_block , type : Enum [
279
332
:silence_deprecation_warning , :warn , :frozen_dup , :raise ,
280
333
]
281
334
@@ -320,7 +373,7 @@ def self.[](config)
320
373
#
321
374
# [+false+ <em>(planned default for +v0.6+)</em>]
322
375
# ResponseParser _only_ uses AppendUIDData and CopyUIDData.
323
- attr_accessor :parser_use_deprecated_uidplus_data , type : [
376
+ attr_accessor :parser_use_deprecated_uidplus_data , type : Enum [
324
377
true , :up_to_max_size , false
325
378
]
326
379
@@ -427,6 +480,7 @@ def defaults_hash
427
480
idle_response_timeout : 5 ,
428
481
sasl_ir : true ,
429
482
enforce_logindisabled : true ,
483
+ max_response_size : 512 << 20 , # 512 MiB
430
484
responses_without_block : :warn ,
431
485
parser_use_deprecated_uidplus_data : :up_to_max_size ,
432
486
parser_max_deprecated_uidplus_data_size : 100 ,
@@ -435,36 +489,64 @@ def defaults_hash
435
489
@global = default . new
436
490
437
491
version_defaults [ :default ] = Config [ default . send ( :defaults_hash ) ]
438
- version_defaults [ :current ] = Config [ :default ]
439
492
440
- version_defaults [ 0 ] = Config [ :current ] . dup . update (
493
+ version_defaults [ 0 r ] = Config [ :default ] . dup . update (
441
494
sasl_ir : false ,
442
495
responses_without_block : :silence_deprecation_warning ,
443
496
enforce_logindisabled : false ,
497
+ max_response_size : nil ,
444
498
parser_use_deprecated_uidplus_data : true ,
445
499
parser_max_deprecated_uidplus_data_size : 10_000 ,
446
500
) . freeze
447
- version_defaults [ 0.0 ] = Config [ 0 ]
448
- version_defaults [ 0.1 ] = Config [ 0 ]
449
- version_defaults [ 0.2 ] = Config [ 0 ]
450
- version_defaults [ 0.3 ] = Config [ 0 ]
501
+ version_defaults [ 0.0 r ] = Config [ 0 r ]
502
+ version_defaults [ 0.1 r ] = Config [ 0 r ]
503
+ version_defaults [ 0.2 r ] = Config [ 0 r ]
504
+ version_defaults [ 0.3 r ] = Config [ 0 r ]
451
505
452
- version_defaults [ 0.4 ] = Config [ 0.3 ] . dup . update (
506
+ version_defaults [ 0.4 r ] = Config [ 0.3 r ] . dup . update (
453
507
sasl_ir : true ,
454
508
parser_max_deprecated_uidplus_data_size : 1000 ,
455
509
) . freeze
456
510
457
- version_defaults [ 0.5 ] = Config [ :current ]
511
+ version_defaults [ 0.5 r] = Config [ 0.4 r] . dup . update (
512
+ enforce_logindisabled : true ,
513
+ max_response_size : 512 << 20 , # 512 MiB
514
+ responses_without_block : :warn ,
515
+ parser_use_deprecated_uidplus_data : :up_to_max_size ,
516
+ parser_max_deprecated_uidplus_data_size : 100 ,
517
+ ) . freeze
458
518
459
- version_defaults [ 0.6 ] = Config [ 0.5 ] . dup . update (
519
+ version_defaults [ 0.6 r ] = Config [ 0.5 r ] . dup . update (
460
520
responses_without_block : :frozen_dup ,
461
521
parser_use_deprecated_uidplus_data : false ,
462
522
parser_max_deprecated_uidplus_data_size : 0 ,
463
523
) . freeze
464
- version_defaults [ :next ] = Config [ 0.6 ]
465
- version_defaults [ :future ] = Config [ :next ]
524
+
525
+ version_defaults [ 0.7 r] = Config [ 0.6 r] . dup . update (
526
+ ) . freeze
527
+
528
+ # Safe conversions one way only:
529
+ # 0.6r.to_f == 0.6 # => true
530
+ # 0.6 .to_r == 0.6r # => false
531
+ version_defaults . to_a . each do |k , v |
532
+ next unless k in Rational
533
+ version_defaults [ k . to_f ] = v
534
+ end
535
+
536
+ current = VERSION . to_r
537
+ version_defaults [ :original ] = Config [ 0 ]
538
+ version_defaults [ :current ] = Config [ current ]
539
+ version_defaults [ :next ] = Config [ current + 0.1 r]
540
+ version_defaults [ :future ] = Config [ current + 0.2 r]
466
541
467
542
version_defaults . freeze
543
+
544
+ if ( $VERBOSE || $DEBUG) && self [ :current ] . to_h != self [ :default ] . to_h
545
+ warn "Misconfigured Net::IMAP::Config[:current] => %p,\n " \
546
+ " not equal to Net::IMAP::Config[:default] => %p" % [
547
+ self [ :current ] . to_h , self [ :default ] . to_h
548
+ ]
549
+ end
468
550
end
469
551
end
470
552
end
0 commit comments