rims 0.2.9 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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