rims 0.2.9 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d256a00569dbf130c60b1ce0a2e81eaaaee80c8f05bd539951044050d8730ed8
4
- data.tar.gz: dadb9184722598429f498a3c024bb911717f2cacd28e8b2b72073704401c6af1
3
+ metadata.gz: 302a70ed845d6af656e11c2a6fde78cfda71a33b1d5673654594634b7fe92f63
4
+ data.tar.gz: 468e136c3796d1ea15d9e554be3f6dd38b5d34fe3089c7db71a0d7a87d73e9cb
5
5
  SHA512:
6
- metadata.gz: d630fcd4aea66809516f8878d5b0f9511331c3afaf1fc71a6f0ac08f5a4329345868f5a5cf2665e54a9985dd7939c7b478da2c8f7cfe1a686603f621519cef75
7
- data.tar.gz: 6a34c95ce5f6a6012da5e790326e2e991ecccc0cb186ac53fd8c6b2b1f829df0b41c8087fa567970dbf912295901ed4e4a83865117e1c564df90da43b7874807
6
+ metadata.gz: 96c2d58c1990e724743581436c0e373bcb147e4afd799f8c9860146cf2c4fa33b5652a2937a4185590a5b7a79c2309bf899d16268eeed92765b08572c74d3884
7
+ data.tar.gz: 816e5242fbf6c361d81306f516c27eab7046d73829ae7a08065a44788ef28afba71923b0eb6b200d7a0b6f2791fda24e8f7c4a6d481ff9502333fa4fc2179c03
@@ -1,6 +1,29 @@
1
1
  Change Log
2
2
  ==========
3
3
 
4
+ <!--
5
+ subsections:
6
+ ### Added
7
+ ### Changed
8
+ ### Removed
9
+ ### Fixed
10
+ -->
11
+
12
+ 0.3.0
13
+ -----
14
+
15
+ ### Added
16
+ - Input size limits.
17
+ [#34](https://github.com/y10k/rims/issues/34)
18
+ - Configurable bulk_response_size parameter.
19
+ [#36](https://github.com/y10k/rims/issues/36)
20
+
21
+ ### Changed
22
+ - Ready to Ruby 2.7.
23
+ [#35](https://github.com/y10k/rims/issues/35)
24
+ - Semantic versioning.
25
+ [#37](https://github.com/y10k/rims/issues/37)
26
+
4
27
  0.2.9
5
28
  -----
6
29
  Released on 2019-12-12.
@@ -5,35 +5,37 @@ require "rims/version"
5
5
  autoload :OpenSSL, 'openssl'
6
6
 
7
7
  module RIMS
8
- autoload :Authentication, 'rims/auth'
9
- autoload :Checksum_KeyValueStore, 'rims/cksum_kvs'
10
- autoload :Cmd, 'rims/cmd'
11
- autoload :DB, 'rims/db'
12
- autoload :Error, 'rims/error'
13
- autoload :GDBM_KeyValueStore, 'rims/gdbm_kvs'
14
- autoload :GlobalDB, 'rims/db'
15
- autoload :Hash_KeyValueStore, 'rims/hash_kvs'
16
- autoload :IllegalLockError, 'rims/lock'
17
- autoload :KeyValueStore, 'rims/kvs'
18
- autoload :LockError, 'rims/lock'
19
- autoload :MailFolder, 'rims/mail_store'
20
- autoload :MailStore, 'rims/mail_store'
21
- autoload :MailboxDB, 'rims/db'
22
- autoload :MessageDB, 'rims/db'
23
- autoload :MessageSetSyntaxError, 'rims/protocol'
24
- autoload :Password, 'rims/passwd'
25
- autoload :Protocol, 'rims/protocol'
26
- autoload :ProtocolError, 'rims/protocol'
27
- autoload :RFC822, 'rims/rfc822'
28
- autoload :ReadLockError, 'rims/lock'
29
- autoload :ReadLockTimeoutError, 'rims/lock'
30
- autoload :ReadWriteLock, 'rims/lock'
31
- autoload :ServerResponseChannel, 'rims/channel'
32
- autoload :Service, 'rims/service'
33
- autoload :SyntaxError, 'rims/protocol'
34
- autoload :Test, 'rims/test'
35
- autoload :WriteLockError, 'rims/lock'
36
- autoload :WriteLockTimeoutError, 'rims/lock'
8
+ autoload :Authentication, 'rims/auth'
9
+ autoload :Checksum_KeyValueStore, 'rims/cksum_kvs'
10
+ autoload :Cmd, 'rims/cmd'
11
+ autoload :CommandSizeTooLargeError, 'rims/protocol'
12
+ autoload :DB, 'rims/db'
13
+ autoload :Error, 'rims/error'
14
+ autoload :GDBM_KeyValueStore, 'rims/gdbm_kvs'
15
+ autoload :Hash_KeyValueStore, 'rims/hash_kvs'
16
+ autoload :IllegalLockError, 'rims/lock'
17
+ autoload :KeyValueStore, 'rims/kvs'
18
+ autoload :LineTooLongError, 'rims/protocol'
19
+ autoload :LiteralSizeTooLargeError, 'rims/protocol'
20
+ autoload :LockError, 'rims/lock'
21
+ autoload :MailFolder, 'rims/mail_store'
22
+ autoload :MailStore, 'rims/mail_store'
23
+ autoload :MessageSetSyntaxError, 'rims/protocol'
24
+ autoload :Password, 'rims/passwd'
25
+ autoload :Protocol, 'rims/protocol'
26
+ autoload :ProtocolError, 'rims/protocol'
27
+ autoload :RFC822, 'rims/rfc822'
28
+ autoload :ReadLockError, 'rims/lock'
29
+ autoload :ReadLockTimeoutError, 'rims/lock'
30
+ autoload :ReadSizeError, 'rims/protocol'
31
+ autoload :ReadWriteLock, 'rims/lock'
32
+ autoload :RecoverableReadSizeError, 'rims/protocol'
33
+ autoload :ServerResponseChannel, 'rims/channel'
34
+ autoload :Service, 'rims/service'
35
+ autoload :SyntaxError, 'rims/protocol'
36
+ autoload :Test, 'rims/test'
37
+ autoload :WriteLockError, 'rims/lock'
38
+ autoload :WriteLockTimeoutError, 'rims/lock'
37
39
  end
38
40
 
39
41
  # Local Variables:
@@ -472,6 +472,33 @@ module RIMS
472
472
  })
473
473
  }
474
474
  end
475
+ options.on('--line-length-limit=SIZE',
476
+ Integer
477
+ ) do |size|
478
+ build.chain{|c|
479
+ c.load(protocol: {
480
+ line_length_limit: size
481
+ })
482
+ }
483
+ end
484
+ options.on('--literal-size-limit=SIZE',
485
+ Integer
486
+ ) do |size|
487
+ build.chain{|c|
488
+ c.load(protocol: {
489
+ literal_size_limit: size
490
+ })
491
+ }
492
+ end
493
+ options.on('--command-size-limit=SIZE',
494
+ Integer
495
+ ) do |size|
496
+ build.chain{|c|
497
+ c.load(protocol: {
498
+ command_size_limit: size
499
+ })
500
+ }
501
+ end
475
502
  options.on('--[no-]use-default-charset-aliases'
476
503
  ) do |use_default_aliases|
477
504
  build.chain{|c|
@@ -533,7 +560,7 @@ module RIMS
533
560
  })
534
561
  }
535
562
  end
536
- options.on('--drb-load-limit=NUMBER',
563
+ options.on('--drb-load-limit=SIZE',
537
564
  Integer
538
565
  ) do |size|
539
566
  build.chain{|c|
@@ -552,6 +579,16 @@ module RIMS
552
579
  })
553
580
  }
554
581
  end
582
+ options.on('--bulk-response-size=SIZE',
583
+ Integer) do |size|
584
+ build.chain{|c|
585
+ c.load(drb_services: {
586
+ engine: {
587
+ bulk_response_size: size
588
+ }
589
+ })
590
+ }
591
+ end
555
592
  options.on('--read-lock-timeout=SECONDS',
556
593
  Float
557
594
  ) do |seconds|
@@ -4,6 +4,27 @@ module RIMS
4
4
  class ProtocolError < Error
5
5
  end
6
6
 
7
+ class ReadSizeError < ProtocolError
8
+ end
9
+
10
+ class LineTooLongError < ReadSizeError
11
+ end
12
+
13
+ class RecoverableReadSizeError < ReadSizeError
14
+ def initialize(message=nil, command_tag=nil, **kw_args)
15
+ super(message, **kw_args)
16
+ @command_tag = command_tag
17
+ end
18
+
19
+ attr_reader :command_tag
20
+ end
21
+
22
+ class LiteralSizeTooLargeError < RecoverableReadSizeError
23
+ end
24
+
25
+ class CommandSizeTooLargeError < RecoverableReadSizeError
26
+ end
27
+
7
28
  class SyntaxError < ProtocolError
8
29
  end
9
30
 
@@ -57,14 +78,14 @@ module RIMS
57
78
  end
58
79
  module_function :decode_base64
59
80
 
60
- autoload :FetchBody, 'rims/protocol/parser'
61
- autoload :RequestReader, 'rims/protocol/parser'
81
+ autoload :FetchBody, 'rims/protocol/parser'
82
+ autoload :RequestReader, 'rims/protocol/parser'
62
83
  autoload :AuthenticationReader, 'rims/protocol/parser'
63
- autoload :SearchParser, 'rims/protocol/parser'
64
- autoload :FetchParser, 'rims/protocol/parser'
65
- autoload :ConnectionLimits, 'rims/protocol/connection'
66
- autoload :ConnectionTimer, 'rims/protocol/connection'
67
- autoload :Decoder, 'rims/protocol/decoder'
84
+ autoload :SearchParser, 'rims/protocol/parser'
85
+ autoload :FetchParser, 'rims/protocol/parser'
86
+ autoload :ConnectionLimits, 'rims/protocol/connection'
87
+ autoload :ConnectionTimer, 'rims/protocol/connection'
88
+ autoload :Decoder, 'rims/protocol/decoder'
68
89
 
69
90
  def body(symbol: nil, option: nil, section: nil, section_list: nil, partial_origin: nil, partial_size: nil)
70
91
  FetchBody.new(symbol, option, section, section_list, partial_origin, partial_size)
@@ -37,7 +37,6 @@ module RIMS
37
37
  end
38
38
 
39
39
  def self.repl(decoder, limits, input, output, logger)
40
- input_gets = input.method(:gets)
41
40
  output_write = lambda{|data|
42
41
  begin
43
42
  if (data == :flush) then
@@ -85,90 +84,112 @@ module RIMS
85
84
  apply_imap_command.call(:ok_greeting)
86
85
 
87
86
  conn_timer = ConnectionTimer.new(limits, input.to_io)
88
- request_reader = RequestReader.new(input, output, logger)
87
+ request_reader = decoder.make_requrest_reader(input, output)
88
+ input_gets = request_reader.method(:gets)
89
89
 
90
- until (conn_timer.command_wait_timeout?)
91
- conn_timer.command_wait or break
90
+ begin
91
+ until (conn_timer.command_wait_timeout?)
92
+ conn_timer.command_wait or break
92
93
 
93
- begin
94
- atom_list = request_reader.read_command
95
- rescue
96
- logger.error('invalid client command.')
97
- logging_error_chain($!, logger)
98
- response_write.call("* BAD client command syntax error\r\n")
99
- next
100
- end
94
+ begin
95
+ atom_list = request_reader.read_command
96
+ rescue LineTooLongError
97
+ raise
98
+ rescue LiteralSizeTooLargeError
99
+ logger.error('literal size too large error.')
100
+ logging_error_chain($!, logger)
101
+ response_write.call("#{request_reader.command_tag || '*'} BAD literal size too large\r\n")
102
+ next
103
+ rescue CommandSizeTooLargeError
104
+ logger.error('command size too large error.')
105
+ logging_error_chain($!, logger)
106
+ response_write.call("#{request_reader.command_tag || '*'} BAD command size too large\r\n")
107
+ next
108
+ rescue
109
+ logger.error('invalid client command.')
110
+ logging_error_chain($!, logger)
111
+ response_write.call("#{request_reader.command_tag || '*'} BAD client command syntax error\r\n")
112
+ next
113
+ end
101
114
 
102
- break unless atom_list
115
+ break unless atom_list
103
116
 
104
- tag, command, *opt_args = atom_list
105
- normalized_command = imap_command_normalize(command)
106
- logger.info("client command: #{tag} #{command}")
107
- if (logger.debug?) then
108
- case (normalized_command)
109
- when 'LOGIN'
110
- log_opt_args = opt_args.dup
111
- log_opt_args[-1] = '********'
112
- when 'AUTHENTICATE'
113
- if (opt_args[1]) then
117
+ tag, command, *opt_args = atom_list
118
+ normalized_command = imap_command_normalize(command)
119
+ logger.info("client command: #{tag} #{command}")
120
+ if (logger.debug?) then
121
+ case (normalized_command)
122
+ when 'LOGIN'
114
123
  log_opt_args = opt_args.dup
115
- log_opt_args[1] = '********'
124
+ log_opt_args[-1] = '********'
125
+ when 'AUTHENTICATE'
126
+ if (opt_args[1]) then
127
+ log_opt_args = opt_args.dup
128
+ log_opt_args[1] = '********'
129
+ else
130
+ log_opt_args = opt_args
131
+ end
116
132
  else
117
133
  log_opt_args = opt_args
118
134
  end
119
- else
120
- log_opt_args = opt_args
135
+ logger.debug("client command parameter: #{log_opt_args.inspect}")
121
136
  end
122
- logger.debug("client command parameter: #{log_opt_args.inspect}")
123
- end
124
137
 
125
- begin
126
- if (name = IMAP_CMDs[normalized_command]) then
127
- case (name)
128
- when :uid
129
- unless (opt_args.empty?) then
130
- uid_command, *uid_args = opt_args
131
- logger.info("uid command: #{uid_command}")
132
- logger.debug("uid parameter: #{uid_args}") if logger.debug?
133
- if (uid_name = UID_CMDs[imap_command_normalize(uid_command)]) then
134
- apply_imap_command.call(uid_name, tag, *uid_args, uid: true)
138
+ begin
139
+ if (name = IMAP_CMDs[normalized_command]) then
140
+ case (name)
141
+ when :uid
142
+ unless (opt_args.empty?) then
143
+ uid_command, *uid_args = opt_args
144
+ logger.info("uid command: #{uid_command}")
145
+ logger.debug("uid parameter: #{uid_args}") if logger.debug?
146
+ if (uid_name = UID_CMDs[imap_command_normalize(uid_command)]) then
147
+ apply_imap_command.call(uid_name, tag, *uid_args, uid: true)
148
+ else
149
+ logger.error("unknown uid command: #{uid_command}")
150
+ response_write.call("#{tag} BAD unknown uid command\r\n")
151
+ end
135
152
  else
136
- logger.error("unknown uid command: #{uid_command}")
137
- response_write.call("#{tag} BAD unknown uid command\r\n")
153
+ logger.error('empty uid parameter.')
154
+ response_write.call("#{tag} BAD empty uid parameter\r\n")
138
155
  end
156
+ when :authenticate
157
+ apply_imap_command.call(:authenticate, tag, input_gets, server_output_write, *opt_args)
158
+ when :idle
159
+ apply_imap_command.call(:idle, tag, input_gets, server_output_write, conn_timer, *opt_args)
139
160
  else
140
- logger.error('empty uid parameter.')
141
- response_write.call("#{tag} BAD empty uid parameter\r\n")
161
+ apply_imap_command.call(name, tag, *opt_args)
142
162
  end
143
- when :authenticate
144
- apply_imap_command.call(:authenticate, tag, input_gets, server_output_write, *opt_args)
145
- when :idle
146
- apply_imap_command.call(:idle, tag, input_gets, server_output_write, conn_timer, *opt_args)
147
163
  else
148
- apply_imap_command.call(name, tag, *opt_args)
164
+ logger.error("unknown command: #{command}")
165
+ response_write.call("#{tag} BAD unknown command\r\n")
149
166
  end
150
- else
151
- logger.error("unknown command: #{command}")
152
- response_write.call("#{tag} BAD unknown command\r\n")
167
+ rescue LineTooLongError
168
+ raise
169
+ rescue
170
+ logger.error('unexpected error.')
171
+ logging_error_chain($!, logger)
172
+ response_write.call("#{tag} BAD unexpected error\r\n")
153
173
  end
154
- rescue
155
- logger.error('unexpected error.')
156
- logging_error_chain($!, logger)
157
- response_write.call("#{tag} BAD unexpected error\r\n")
158
- end
159
-
160
- if (normalized_command == 'LOGOUT') then
161
- break
162
- end
163
174
 
164
- decoder = decoder.next_decoder
165
- end
175
+ if (normalized_command == 'LOGOUT') then
176
+ break
177
+ end
166
178
 
167
- if (conn_timer.command_wait_timeout?) then
168
- if (limits.command_wait_timeout_seconds > 0) then
169
- response_write.call("* BYE server autologout: idle for too long\r\n")
170
- else
171
- response_write.call("* BYE server autologout: shutdown\r\n")
179
+ decoder = decoder.next_decoder
180
+ end
181
+ rescue LineTooLongError
182
+ logger.error('line too long error.')
183
+ logging_error_chain($!, logger)
184
+ response_write.call("* BAD line too long\r\n")
185
+ response_write.call("* BYE server autologout: connection terminated\r\n")
186
+ else
187
+ if (conn_timer.command_wait_timeout?) then
188
+ if (limits.command_wait_timeout_seconds > 0) then
189
+ response_write.call("* BYE server autologout: idle for too long\r\n")
190
+ else
191
+ response_write.call("* BYE server autologout: shutdown\r\n")
192
+ end
172
193
  end
173
194
  end
174
195
 
@@ -198,6 +219,8 @@ module RIMS
198
219
  else
199
220
  __send__(imap_command, tag, *args, **kw_args, &block)
200
221
  end
222
+ rescue LineTooLongError
223
+ raise
201
224
  rescue SyntaxError
202
225
  @logger.error('client command syntax error.')
203
226
  logging_error_chain($!)
@@ -334,13 +357,26 @@ module RIMS
334
357
  end
335
358
 
336
359
  def initialize(drb_services, auth, logger,
337
- mail_delivery_user: Service::DEFAULT_CONFIG.mail_delivery_user)
360
+ mail_delivery_user: Service::DEFAULT_CONFIG.mail_delivery_user,
361
+ line_length_limit: Service::DEFAULT_CONFIG.protocol_line_length_limit,
362
+ literal_size_limit: Service::DEFAULT_CONFIG.protocol_literal_size_limit,
363
+ command_size_limit: Service::DEFAULT_CONFIG.protocol_command_size_limit)
338
364
  super(auth, logger)
339
365
  @drb_services = drb_services
340
366
  @mail_delivery_user = mail_delivery_user
367
+ @line_length_limit = line_length_limit
368
+ @literal_size_limit = literal_size_limit
369
+ @command_size_limit = command_size_limit
341
370
  @logger.debug("RIMS::Protocol::InitialDecoder#initialize at #{self}") if @logger.debug?
342
371
  end
343
372
 
373
+ def make_requrest_reader(input, output)
374
+ RequestReader.new(input, output, @logger,
375
+ line_length_limit: @line_length_limit,
376
+ literal_size_limit: @literal_size_limit,
377
+ command_size_limit: @command_size_limit)
378
+ end
379
+
344
380
  def auth?
345
381
  false
346
382
  end
@@ -868,22 +904,40 @@ module RIMS
868
904
 
869
905
  class << self
870
906
  def imap_command_authenticated(name, **guard_optional)
907
+ name = name.to_sym
871
908
  orig_name = "_#{name}".to_sym
872
909
  alias_method orig_name, name
873
- define_method name, lambda{|token, tag, *args, **kw_args, &block|
874
- guard_authenticated(orig_name, token, tag, *args, **kw_args, **guard_optional, &block)
875
- }
876
- name.to_sym
910
+
911
+ guard_options_name = "_#{name}_guard_options".to_sym
912
+ define_method guard_options_name, lambda{ guard_optional }
913
+ private guard_options_name
914
+
915
+ class_eval(<<-EOF, __FILE__, __LINE__ + 1)
916
+ def #{name}(token, tag, *args, **kw_args, &block)
917
+ guard_authenticated(:#{orig_name}, token, tag, *args, **kw_args, **#{guard_options_name}, &block)
918
+ end
919
+ EOF
920
+
921
+ name
877
922
  end
878
923
  private :imap_command_authenticated
879
924
 
880
925
  def imap_command_selected(name, **guard_optional)
926
+ name = name.to_sym
881
927
  orig_name = "_#{name}".to_sym
882
928
  alias_method orig_name, name
883
- define_method name, lambda{|token, tag, *args, **kw_args, &block|
884
- guard_selected(orig_name, token, tag, *args, **kw_args, **guard_optional, &block)
885
- }
886
- name.to_sym
929
+
930
+ guard_options_name = "_#{name}_guard_options".to_sym
931
+ define_method guard_options_name, lambda{ guard_optional }
932
+ private guard_options_name
933
+
934
+ class_eval(<<-EOF, __FILE__, __LINE__ + 1)
935
+ def #{name}(token, tag, *args, **kw_args, &block)
936
+ guard_selected(:#{orig_name}, token, tag, *args, **kw_args, **#{guard_options_name}, &block)
937
+ end
938
+ EOF
939
+
940
+ name
887
941
  end
888
942
  private :imap_command_selected
889
943
  end
@@ -1884,7 +1938,7 @@ module RIMS
1884
1938
  end
1885
1939
  imap_command :check
1886
1940
 
1887
- def close(tag, &block)
1941
+ def close(tag)
1888
1942
  ret_val = nil
1889
1943
  old_token = @token
1890
1944
  @token = nil
@@ -1946,7 +2000,7 @@ module RIMS
1946
2000
  end
1947
2001
  imap_command :store
1948
2002
 
1949
- def copy(tag, msg_set, mbox_name, uid: false, &block)
2003
+ def copy(tag, msg_set, mbox_name, uid: false)
1950
2004
  ret_val = nil
1951
2005
  @engine.copy(@token, tag, msg_set, mbox_name, uid: uid) {|res|
1952
2006
  for response in res
@@ -1958,7 +2012,7 @@ module RIMS
1958
2012
  end
1959
2013
  imap_command :copy
1960
2014
 
1961
- def idle(tag, client_input_gets, server_output_write, connection_timer, &block)
2015
+ def idle(tag, client_input_gets, server_output_write, connection_timer)
1962
2016
  ret_val = nil
1963
2017
  @engine.idle(@token, tag, client_input_gets, server_output_write, connection_timer) {|res|
1964
2018
  for response in res