rims 0.2.6 → 0.3.1
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 +4 -4
- data/.gitignore +3 -0
- data/CHANGELOG.md +97 -0
- data/ChangeLog +49 -0
- data/Rakefile +8 -4
- data/lib/rims.rb +31 -29
- data/lib/rims/channel.rb +35 -10
- data/lib/rims/cmd.rb +109 -3
- data/lib/rims/error.rb +15 -0
- data/lib/rims/protocol.rb +28 -7
- data/lib/rims/protocol/decoder.rb +727 -457
- data/lib/rims/protocol/parser.rb +190 -82
- data/lib/rims/service.rb +172 -39
- data/lib/rims/test.rb +31 -20
- data/lib/rims/version.rb +1 -1
- data/load_test/Rakefile +3 -1
- data/rims.gemspec +14 -13
- data/test/cmd/test_command.rb +21 -1
- data/test/test_channel.rb +2 -1
- data/test/test_error.rb +33 -1
- data/test/test_lock.rb +4 -4
- data/test/test_passwd.rb +1 -1
- data/test/test_protocol_decoder.rb +555 -41
- data/test/test_protocol_fetch.rb +14 -10
- data/test/test_protocol_request.rb +305 -280
- data/test/test_protocol_search.rb +771 -893
- data/test/test_service.rb +165 -0
- metadata +22 -7
data/lib/rims/protocol/parser.rb
CHANGED
@@ -33,21 +33,7 @@ module RIMS
|
|
33
33
|
end
|
34
34
|
|
35
35
|
class RequestReader
|
36
|
-
def
|
37
|
-
@input = input
|
38
|
-
@output = output
|
39
|
-
@logger = logger
|
40
|
-
end
|
41
|
-
|
42
|
-
def read_line
|
43
|
-
line = @input.gets or return
|
44
|
-
@logger.debug("read line: #{Protocol.io_data_log(line)}") if @logger.debug?
|
45
|
-
line.chomp!("\n")
|
46
|
-
line.chomp!("\r")
|
47
|
-
scan_line(line)
|
48
|
-
end
|
49
|
-
|
50
|
-
def scan_line(line)
|
36
|
+
def self.scan(line)
|
51
37
|
atom_list = line.scan(/BODY(?:\.\S+)?\[.*?\](?:<\d+\.\d+>)?|[\[\]()]|".*?"|[^\[\]()\s]+/i).map{|s|
|
52
38
|
case (s)
|
53
39
|
when '(', ')', '[', ']', /\A NIL \z/ix
|
@@ -77,22 +63,14 @@ module RIMS
|
|
77
63
|
end
|
78
64
|
}
|
79
65
|
if ((atom_list[-1].is_a? String) && (atom_list[-1] =~ /\A {\d+} \z/x)) then
|
80
|
-
|
81
|
-
|
82
|
-
@output.write("+ continue\r\n")
|
83
|
-
@output.flush
|
84
|
-
@logger.debug('continue literal.') if @logger.debug?
|
85
|
-
literal_string = @input.read(next_size) or raise 'unexpected client close.'
|
86
|
-
@logger.debug("read literal: #{Protocol.io_data_log(literal_string)}") if @logger.debug?
|
87
|
-
atom_list[-1] = literal_string
|
88
|
-
next_atom_list = read_line or raise 'unexpected client close.'
|
89
|
-
atom_list += next_atom_list
|
66
|
+
literal_size = $&[1..-2].to_i
|
67
|
+
atom_list[-1] = [ :literal, literal_size ]
|
90
68
|
end
|
91
69
|
|
92
70
|
atom_list
|
93
71
|
end
|
94
72
|
|
95
|
-
def parse(atom_list, last_atom=nil)
|
73
|
+
def self.parse(atom_list, last_atom=nil)
|
96
74
|
syntax_list = []
|
97
75
|
while (atom = atom_list.shift)
|
98
76
|
case (atom)
|
@@ -105,7 +83,7 @@ module RIMS
|
|
105
83
|
else
|
106
84
|
if ((atom.is_a? Array) && (atom[0] == :body)) then
|
107
85
|
body = atom[1]
|
108
|
-
body.section_list = parse(
|
86
|
+
body.section_list = parse(scan(body.section))
|
109
87
|
end
|
110
88
|
syntax_list.push(atom)
|
111
89
|
end
|
@@ -118,18 +96,90 @@ module RIMS
|
|
118
96
|
syntax_list
|
119
97
|
end
|
120
98
|
|
99
|
+
def initialize(input, output, logger, line_length_limit: 1024*8, literal_size_limit: (1024**2)*10, command_size_limit: (1024**2)*10)
|
100
|
+
@input = input
|
101
|
+
@output = output
|
102
|
+
@logger = logger
|
103
|
+
@line_length_limit = line_length_limit
|
104
|
+
@literal_size_limit = literal_size_limit
|
105
|
+
@command_size_limit = command_size_limit
|
106
|
+
@command_tag = nil
|
107
|
+
@read_size = 0
|
108
|
+
end
|
109
|
+
|
110
|
+
attr_reader :command_tag
|
111
|
+
|
112
|
+
def gets
|
113
|
+
if (line = @input.gets($/, @line_length_limit)) then # arguments compatible with OpenSSL::Buffering#gets
|
114
|
+
if (line.bytesize < @line_length_limit) then
|
115
|
+
line
|
116
|
+
elsif (line.bytesize == @line_length_limit && (line.end_with? $/)) then
|
117
|
+
line
|
118
|
+
else
|
119
|
+
raise LineTooLongError.new('line too long.', line_fragment: line)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def read_literal(size)
|
125
|
+
@logger.debug("found literal: #{size} octets.") if @logger.debug?
|
126
|
+
if (size > @literal_size_limit) then
|
127
|
+
raise LiteralSizeTooLargeError.new('literal size too large', @command_tag)
|
128
|
+
end
|
129
|
+
if (@read_size + size > @command_size_limit) then
|
130
|
+
raise CommandSizeTooLargeError.new('command size too large', @command_tag)
|
131
|
+
end
|
132
|
+
@output.write("+ continue\r\n")
|
133
|
+
@output.flush
|
134
|
+
@logger.debug('continue literal.') if @logger.debug?
|
135
|
+
literal_string = @input.read(size) or raise 'unexpected client close.'
|
136
|
+
@read_size += size
|
137
|
+
@logger.debug("read literal: #{Protocol.io_data_log(literal_string)}") if @logger.debug?
|
138
|
+
|
139
|
+
literal_string
|
140
|
+
end
|
141
|
+
private :read_literal
|
142
|
+
|
143
|
+
def read_line
|
144
|
+
line = gets or return
|
145
|
+
@logger.debug("read line: #{Protocol.io_data_log(line)}") if @logger.debug?
|
146
|
+
line.chomp!("\n")
|
147
|
+
line.chomp!("\r")
|
148
|
+
@read_size += line.bytesize
|
149
|
+
if (@read_size > @command_size_limit) then
|
150
|
+
raise CommandSizeTooLargeError.new('command size too large', @command_tag)
|
151
|
+
end
|
152
|
+
atom_list = self.class.scan(line)
|
153
|
+
|
154
|
+
if (@command_tag.nil? && ! atom_list.empty?) then
|
155
|
+
unless ((atom_list[0].is_a? String) && ! (atom_list[0].start_with? '*', '+')) then
|
156
|
+
raise SyntaxError, "invalid command tag: #{atom_list[0]}"
|
157
|
+
end
|
158
|
+
@command_tag = atom_list[0]
|
159
|
+
end
|
160
|
+
|
161
|
+
if ((atom_list[-1].is_a? Array) && (atom_list[-1][0] == :literal)) then
|
162
|
+
atom_list[-1] = read_literal(atom_list[-1][1])
|
163
|
+
next_atom_list = read_line or raise 'unexpected client close.'
|
164
|
+
atom_list += next_atom_list
|
165
|
+
end
|
166
|
+
|
167
|
+
atom_list
|
168
|
+
end
|
169
|
+
private :read_line
|
170
|
+
|
121
171
|
def read_command
|
172
|
+
@command_tag = nil
|
173
|
+
@read_size = 0
|
122
174
|
while (atom_list = read_line)
|
123
175
|
if (atom_list.empty?) then
|
176
|
+
@read_size = 0
|
124
177
|
next
|
125
178
|
end
|
126
179
|
if (atom_list.length < 2) then
|
127
|
-
raise 'need for tag and command.'
|
128
|
-
end
|
129
|
-
if (atom_list[0] =~ /\A [*+]/x) then
|
130
|
-
raise "invalid command tag: #{atom_list[0]}"
|
180
|
+
raise SyntaxError, 'need for tag and command.'
|
131
181
|
end
|
132
|
-
return parse(atom_list)
|
182
|
+
return self.class.parse(atom_list)
|
133
183
|
end
|
134
184
|
|
135
185
|
nil
|
@@ -228,13 +278,15 @@ module RIMS
|
|
228
278
|
end
|
229
279
|
|
230
280
|
class SearchParser
|
231
|
-
def initialize(mail_store, folder)
|
281
|
+
def initialize(mail_store, folder, charset_aliases: RFC822::DEFAULT_CHARSET_ALIASES, charset_convert_options: nil)
|
232
282
|
@mail_store = mail_store
|
233
283
|
@folder = folder
|
284
|
+
@charset_aliases = charset_aliases
|
285
|
+
@charset_convert_options = charset_convert_options || {}
|
234
286
|
@charset = nil
|
235
287
|
@mail_cache = Hash.new{|hash, uid|
|
236
288
|
if (msg_txt = @mail_store.msg_text(@folder.mbox_id, uid)) then
|
237
|
-
hash[uid] = RFC822::Message.new(msg_txt)
|
289
|
+
hash[uid] = RFC822::Message.new(msg_txt, charset_aliases: @charset_aliases)
|
238
290
|
end
|
239
291
|
}
|
240
292
|
end
|
@@ -247,47 +299,35 @@ module RIMS
|
|
247
299
|
attr_reader :charset
|
248
300
|
|
249
301
|
def charset=(new_charset)
|
250
|
-
|
302
|
+
charset_encoding = @charset_aliases[new_charset] || Encoding.find(new_charset)
|
303
|
+
if (charset_encoding.dummy?) then
|
304
|
+
# same error type as `Encoding.find'
|
305
|
+
raise ArgumentError, "not a searchable charset: #{new_charset}"
|
306
|
+
end
|
307
|
+
@charset = charset_encoding
|
251
308
|
end
|
252
309
|
|
253
|
-
def
|
310
|
+
def force_charset(string)
|
254
311
|
string = string.dup
|
255
312
|
string.force_encoding(@charset)
|
256
313
|
string.valid_encoding? or raise SyntaxError, "invalid #{@charset} string: #{string.inspect}"
|
257
314
|
string
|
258
315
|
end
|
259
|
-
private :
|
316
|
+
private :force_charset
|
260
317
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
unless (text.encoding.ascii_compatible?) then
|
265
|
-
text = text.encode('utf-8')
|
266
|
-
end
|
318
|
+
def encode_charset(string)
|
319
|
+
if (string.encoding == @charset) then
|
320
|
+
string
|
267
321
|
else
|
268
|
-
|
269
|
-
text = text.encode(@charset)
|
270
|
-
end
|
322
|
+
string.encode(@charset, **@charset_convert_options)
|
271
323
|
end
|
272
|
-
|
273
|
-
text.include? search_string
|
274
324
|
end
|
275
|
-
private :
|
325
|
+
private :encode_charset
|
276
326
|
|
277
|
-
def
|
278
|
-
|
279
|
-
body_txt = mail.body.raw_source
|
280
|
-
if (charset = mail.charset) then
|
281
|
-
if (body_txt.encoding != charset) then
|
282
|
-
body_txt = body_txt.dup.force_encoding(charset)
|
283
|
-
end
|
284
|
-
end
|
285
|
-
body_txt
|
286
|
-
else
|
287
|
-
nil
|
288
|
-
end
|
327
|
+
def compile_search_regexp(search_string)
|
328
|
+
Regexp.new(Regexp.quote(search_string), true)
|
289
329
|
end
|
290
|
-
private :
|
330
|
+
private :compile_search_regexp
|
291
331
|
|
292
332
|
def end_of_cond
|
293
333
|
proc{|msg| true }
|
@@ -322,14 +362,29 @@ module RIMS
|
|
322
362
|
private :parse_msg_flag_enabled
|
323
363
|
|
324
364
|
def parse_search_header(field_name, search_string)
|
325
|
-
|
365
|
+
if (@charset) then
|
366
|
+
search_string = force_charset(search_string)
|
367
|
+
search_regexp = compile_search_regexp(search_string)
|
368
|
+
search_header = proc{|mail|
|
369
|
+
mail.mime_decoded_header_field_value_list(field_name, @charset, charset_convert_options: @charset_convert_options).any?{|field_value|
|
370
|
+
search_regexp.match? field_value
|
371
|
+
}
|
372
|
+
}
|
373
|
+
else
|
374
|
+
search_string = search_string.b
|
375
|
+
search_regexp = compile_search_regexp(search_string)
|
376
|
+
search_header = proc{|mail|
|
377
|
+
mail.header.field_value_list(field_name).any?{|field_value|
|
378
|
+
search_regexp.match? field_value
|
379
|
+
}
|
380
|
+
}
|
381
|
+
end
|
382
|
+
|
326
383
|
proc{|next_cond|
|
327
384
|
proc{|msg|
|
328
385
|
mail = get_mail(msg)
|
329
386
|
if (mail.header.key? field_name) then
|
330
|
-
mail.
|
331
|
-
string_include?(search_string, field_value)
|
332
|
-
} && next_cond.call(msg)
|
387
|
+
search_header.call(mail) && next_cond.call(msg)
|
333
388
|
else
|
334
389
|
false
|
335
390
|
end
|
@@ -372,11 +427,40 @@ module RIMS
|
|
372
427
|
private :parse_mail_bytesize
|
373
428
|
|
374
429
|
def parse_body(search_string)
|
375
|
-
|
430
|
+
if (@charset)
|
431
|
+
search_string = force_charset(search_string)
|
432
|
+
search_regexp = compile_search_regexp(search_string)
|
433
|
+
search_body = proc{|mail|
|
434
|
+
if (mail.text? || mail.messge?) then
|
435
|
+
search_regexp.match? encode_charset(mail.mime_charset_body_text)
|
436
|
+
elsif (mail.multipart?) then
|
437
|
+
mail.parts.any?{|next_mail|
|
438
|
+
search_body.call(next_mail)
|
439
|
+
}
|
440
|
+
else
|
441
|
+
false
|
442
|
+
end
|
443
|
+
}
|
444
|
+
else
|
445
|
+
search_string = search_string.b
|
446
|
+
search_regexp = compile_search_regexp(search_string)
|
447
|
+
search_body = proc{|mail|
|
448
|
+
if (mail.text? || mail.message?)then
|
449
|
+
search_regexp.match? mail.mime_binary_body_string
|
450
|
+
elsif (mail.multipart?) then
|
451
|
+
mail.parts.any?{|next_mail|
|
452
|
+
search_body.call(next_mail)
|
453
|
+
}
|
454
|
+
else
|
455
|
+
false
|
456
|
+
end
|
457
|
+
}
|
458
|
+
end
|
459
|
+
|
376
460
|
proc{|next_cond|
|
377
461
|
proc{|msg|
|
378
|
-
if (
|
379
|
-
|
462
|
+
if (mail = get_mail(msg)) then
|
463
|
+
search_body.call(mail) && next_cond.call(msg)
|
380
464
|
else
|
381
465
|
false
|
382
466
|
end
|
@@ -435,20 +519,44 @@ module RIMS
|
|
435
519
|
private :parse_or
|
436
520
|
|
437
521
|
def parse_text(search_string)
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
522
|
+
if (@charset) then
|
523
|
+
search_string = force_charset(search_string)
|
524
|
+
search_regexp = compile_search_regexp(search_string)
|
525
|
+
search_text = proc{|mail|
|
526
|
+
if (search_regexp.match? mail.mime_decoded_header_text(@charset, charset_convert_options: @charset_convert_options)) then
|
527
|
+
true
|
528
|
+
elsif (mail.text? || mail.message?) then
|
529
|
+
search_regexp.match? encode_charset(mail.mime_charset_body_text)
|
530
|
+
elsif (mail.multipart?) then
|
531
|
+
mail.parts.any?{|next_mail|
|
532
|
+
search_text.call(next_mail)
|
533
|
+
}
|
534
|
+
else
|
535
|
+
false
|
536
|
+
end
|
537
|
+
}
|
538
|
+
else
|
539
|
+
search_string = search_string.b
|
540
|
+
search_regexp = compile_search_regexp(search_string)
|
541
|
+
search_text = proc{|mail|
|
542
|
+
if (search_regexp.match? mail.header.raw_source) then
|
543
|
+
true
|
544
|
+
elsif (mail.text? || mail.message?) then
|
545
|
+
search_regexp.match? mail.mime_binary_body_string
|
546
|
+
elsif (mail.multipart?) then
|
547
|
+
mail.parts.any?{|next_mail|
|
548
|
+
search_text.call(next_mail)
|
549
|
+
}
|
550
|
+
else
|
551
|
+
false
|
552
|
+
end
|
553
|
+
}
|
554
|
+
end
|
555
|
+
|
448
556
|
proc{|next_cond|
|
449
557
|
proc{|msg|
|
450
558
|
mail = get_mail(msg)
|
451
|
-
|
559
|
+
search_text.call(mail) && next_cond.call(msg)
|
452
560
|
}
|
453
561
|
}
|
454
562
|
end
|
@@ -768,12 +876,12 @@ module RIMS
|
|
768
876
|
end
|
769
877
|
include Utils
|
770
878
|
|
771
|
-
def initialize(mail_store, folder)
|
879
|
+
def initialize(mail_store, folder, charset_aliases: RFC822::DEFAULT_CHARSET_ALIASES)
|
772
880
|
@mail_store = mail_store
|
773
881
|
@folder = folder
|
774
882
|
@mail_cache = Hash.new{|hash, uid|
|
775
883
|
if (msg_txt = @mail_store.msg_text(@folder.mbox_id, uid)) then
|
776
|
-
hash[uid] = RFC822::Message.new(msg_txt)
|
884
|
+
hash[uid] = RFC822::Message.new(msg_txt, charset_aliases: charset_aliases)
|
777
885
|
end
|
778
886
|
}
|
779
887
|
end
|
data/lib/rims/service.rb
CHANGED
@@ -118,6 +118,7 @@ module RIMS
|
|
118
118
|
# daemon:
|
119
119
|
# daemonize: true
|
120
120
|
# debug: false
|
121
|
+
# umask: 0037
|
121
122
|
# status_file: rims.pid
|
122
123
|
# server_polling_interval_seconds: 3
|
123
124
|
# server_privileged_user: nobody
|
@@ -157,10 +158,29 @@ module RIMS
|
|
157
158
|
# send_buffer_limit_size: 16384
|
158
159
|
# read_polling_interval_seconds: 1
|
159
160
|
# command_wait_timeout_seconds: 1800
|
161
|
+
# protocol:
|
162
|
+
# line_length_limit: 8192
|
163
|
+
# literal_size_limit: 10485760
|
164
|
+
# command_size_limit: 10485760
|
165
|
+
# charset:
|
166
|
+
# use_default_aliases: true
|
167
|
+
# aliases:
|
168
|
+
# - name: euc-jp
|
169
|
+
# encoding: eucJP-ms
|
170
|
+
# - name: ios-2022-jp
|
171
|
+
# encoding: CP50221
|
172
|
+
# - name: Shift_JIS
|
173
|
+
# encoding: Windows-31J
|
174
|
+
# convert_options:
|
175
|
+
# replace_invalid_byte_sequence: false
|
176
|
+
# replace_undefined_character: true
|
177
|
+
# replaced_mark: "\uFFFD"
|
160
178
|
# drb_services:
|
161
179
|
# process_num: 4
|
180
|
+
# load_limit: 134217728
|
162
181
|
# engine:
|
163
182
|
# bulk_response_count: 100
|
183
|
+
# bulk_response_size: 33554432
|
164
184
|
# read_lock_timeout_seconds: 30
|
165
185
|
# write_lock_timeout_seconds: 30
|
166
186
|
# cleanup_write_lock_timeout_seconds: 1
|
@@ -385,9 +405,8 @@ module RIMS
|
|
385
405
|
end
|
386
406
|
|
387
407
|
def daemonize?
|
388
|
-
|
389
|
-
|
390
|
-
daemon_config['daemonize']
|
408
|
+
if (@config.dig('daemon')&.key? 'daemonize') then
|
409
|
+
@config.dig('daemon', 'daemonize')
|
391
410
|
else
|
392
411
|
true
|
393
412
|
end
|
@@ -398,14 +417,17 @@ module RIMS
|
|
398
417
|
end
|
399
418
|
|
400
419
|
def daemon_debug?
|
401
|
-
|
402
|
-
|
403
|
-
daemon_config['debug']
|
420
|
+
if (@config.dig('daemon')&.key? 'debug') then
|
421
|
+
@config.dig('daemon', 'debug')
|
404
422
|
else
|
405
423
|
false
|
406
424
|
end
|
407
425
|
end
|
408
426
|
|
427
|
+
def daemon_umask
|
428
|
+
@config.dig('daemon', 'umask') || 0037
|
429
|
+
end
|
430
|
+
|
409
431
|
def status_file
|
410
432
|
file_path = @config.dig('daemon', 'status_file') || 'rims.pid'
|
411
433
|
file_path = Pathname(file_path)
|
@@ -521,22 +543,20 @@ module RIMS
|
|
521
543
|
end
|
522
544
|
|
523
545
|
def ssl_context
|
524
|
-
if (
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
end
|
530
|
-
|
531
|
-
if (use_ssl) then
|
532
|
-
ssl_context = OpenSSL::SSL::SSLContext.new
|
533
|
-
if (ssl_config_expr = openssl_config['ssl_context']) then
|
534
|
-
anon_mod = SSLContextConfigAttribute.new_module(ssl_context, base_dir)
|
535
|
-
SSLContextConfigAttribute.eval_config(anon_mod, ssl_config_expr, 'ssl_context')
|
536
|
-
end
|
546
|
+
if (@config.dig('openssl')&.key? 'use_ssl') then
|
547
|
+
use_ssl = @config.dig('openssl', 'use_ssl')
|
548
|
+
else
|
549
|
+
use_ssl = (@config.dig('openssl')&.key? 'ssl_context') || false
|
550
|
+
end
|
537
551
|
|
538
|
-
|
552
|
+
if (use_ssl) then
|
553
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
554
|
+
if (ssl_config_expr = @config.dig('openssl', 'ssl_context')) then
|
555
|
+
anon_mod = SSLContextConfigAttribute.new_module(ssl_context, base_dir)
|
556
|
+
SSLContextConfigAttribute.eval_config(anon_mod, ssl_config_expr, 'ssl_context')
|
539
557
|
end
|
558
|
+
|
559
|
+
ssl_context
|
540
560
|
end
|
541
561
|
end
|
542
562
|
|
@@ -551,14 +571,102 @@ module RIMS
|
|
551
571
|
@config.dig('connection', 'command_wait_timeout_seconds') || 60 * 30)
|
552
572
|
end
|
553
573
|
|
574
|
+
def protocol_line_length_limit
|
575
|
+
@config.dig('protocol', 'line_length_limit') || 1024 * 8
|
576
|
+
end
|
577
|
+
|
578
|
+
def protocol_literal_size_limit
|
579
|
+
@config.dig('protocol', 'literal_size_limit') || 1024**2 * 10
|
580
|
+
end
|
581
|
+
|
582
|
+
def protocol_command_size_limit
|
583
|
+
@config.dig('protocol', 'command_size_limit') || 1024**2 * 10
|
584
|
+
end
|
585
|
+
|
586
|
+
def charset_aliases
|
587
|
+
charset_aliases = RFC822::CharsetAliases.new
|
588
|
+
|
589
|
+
if (@config.dig('charset')&.key? 'use_default_aliases') then
|
590
|
+
use_default_aliases = @config.dig('charset', 'use_default_aliases')
|
591
|
+
else
|
592
|
+
use_default_aliases = true
|
593
|
+
end
|
594
|
+
|
595
|
+
if (use_default_aliases) then
|
596
|
+
for name, encoding in RFC822::DEFAULT_CHARSET_ALIASES
|
597
|
+
charset_aliases.add_alias(name, encoding)
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
if (alias_list = @config.dig('charset', 'aliases')) then
|
602
|
+
for an_alias in alias_list
|
603
|
+
charset_aliases.add_alias(an_alias['name'], Encoding.find(an_alias['encoding']))
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
charset_aliases
|
608
|
+
end
|
609
|
+
|
610
|
+
def charset_convert_options
|
611
|
+
options = {}
|
612
|
+
|
613
|
+
if (@config.dig('charset', 'convert_options')&.key? 'replace_invalid_byte_sequence') then
|
614
|
+
replace_invalid_byte_sequence = @config.dig('charset', 'convert_options', 'replace_invalid_byte_sequence')
|
615
|
+
else
|
616
|
+
replace_invalid_byte_sequence = false
|
617
|
+
end
|
618
|
+
|
619
|
+
if (replace_invalid_byte_sequence) then
|
620
|
+
options[:invalid] = :replace
|
621
|
+
end
|
622
|
+
|
623
|
+
if (@config.dig('charset', 'convert_options')&.key? 'replace_undefined_character') then
|
624
|
+
replace_undefined_character = @config.dig('charset', 'convert_options', 'replace_undefined_character')
|
625
|
+
else
|
626
|
+
replace_undefined_character = true
|
627
|
+
end
|
628
|
+
|
629
|
+
if (replace_undefined_character) then
|
630
|
+
options[:undef] = :replace
|
631
|
+
end
|
632
|
+
|
633
|
+
if (replaced_mark = @config.dig('charset', 'convert_options', 'replaced_mark')) then
|
634
|
+
options[:replace] = replaced_mark
|
635
|
+
end
|
636
|
+
|
637
|
+
options
|
638
|
+
end
|
639
|
+
|
554
640
|
def drb_process_num
|
555
641
|
@config.dig('drb_services', 'process_num') || 0
|
556
642
|
end
|
557
643
|
|
644
|
+
def drb_server_config
|
645
|
+
config = {}
|
646
|
+
if (load_limit = @config.dig('drb_services', 'load_limit')) then
|
647
|
+
config[:load_limit] = load_limit
|
648
|
+
end
|
649
|
+
|
650
|
+
config
|
651
|
+
end
|
652
|
+
|
653
|
+
def drb_client_config
|
654
|
+
config = {}
|
655
|
+
if (load_limit = @config.dig('drb_services', 'load_limit')) then
|
656
|
+
config[:load_limit] = load_limit
|
657
|
+
end
|
658
|
+
|
659
|
+
config
|
660
|
+
end
|
661
|
+
|
558
662
|
def bulk_response_count
|
559
663
|
@config.dig('drb_services', 'engine', 'bulk_response_count') || 100
|
560
664
|
end
|
561
665
|
|
666
|
+
def bulk_response_size
|
667
|
+
@config.dig('drb_services', 'engine', 'bulk_response_size') || 1024**2 * 10
|
668
|
+
end
|
669
|
+
|
562
670
|
def read_lock_timeout_seconds
|
563
671
|
@config.dig('drb_services', 'engine', 'read_lock_timeout_seconds') ||
|
564
672
|
@config.dig('read_lock_timeout_seconds') || # for backward compatibility
|
@@ -639,8 +747,8 @@ module RIMS
|
|
639
747
|
end
|
640
748
|
|
641
749
|
def make_authentication
|
642
|
-
if (
|
643
|
-
auth_conf = @config
|
750
|
+
if (@config.dig('authentication')&.is_a? Hash) then
|
751
|
+
auth_conf = @config.dig('authentication')
|
644
752
|
else
|
645
753
|
auth_conf = {}
|
646
754
|
end
|
@@ -679,8 +787,8 @@ module RIMS
|
|
679
787
|
end
|
680
788
|
|
681
789
|
# for backward compatibility
|
682
|
-
if (
|
683
|
-
plug_in_list = @config
|
790
|
+
if (@config.dig('authentication')&.is_a? Array) then
|
791
|
+
plug_in_list = @config.dig('authentication')
|
684
792
|
for plug_in_conf in plug_in_list
|
685
793
|
plug_in_name = plug_in_conf['plug_in'] or raise KeyError, 'not found an authentication plug_in.'
|
686
794
|
plug_in_config = get_configuration(plug_in_conf)
|
@@ -717,16 +825,16 @@ module RIMS
|
|
717
825
|
using Logger::JointPlus
|
718
826
|
|
719
827
|
def setup(server, daemon: false)
|
720
|
-
file_logger_params = @config.make_file_logger_params
|
721
|
-
logger = Logger.new(*file_logger_params)
|
828
|
+
*file_logger_params, file_logger_opts = @config.make_file_logger_params
|
829
|
+
logger = Logger.new(*file_logger_params, **file_logger_opts)
|
722
830
|
|
723
|
-
stdout_logger_params = @config.make_stdout_logger_params
|
831
|
+
*stdout_logger_params, stdout_logger_opts = @config.make_stdout_logger_params
|
724
832
|
unless (daemon && @config.daemonize?) then
|
725
|
-
logger += Logger.new(*stdout_logger_params)
|
833
|
+
logger += Logger.new(*stdout_logger_params, **stdout_logger_opts)
|
726
834
|
end
|
727
835
|
|
728
|
-
protocol_logger_params = @config.make_protocol_logger_params
|
729
|
-
protocol_logger = Logger.new(*protocol_logger_params)
|
836
|
+
*protocol_logger_params, protocol_logger_opts = @config.make_protocol_logger_params
|
837
|
+
protocol_logger = Logger.new(*protocol_logger_params, **protocol_logger_opts)
|
730
838
|
|
731
839
|
logger.info('preload libraries.')
|
732
840
|
Riser.preload
|
@@ -780,16 +888,21 @@ module RIMS
|
|
780
888
|
end
|
781
889
|
end
|
782
890
|
|
783
|
-
drb_services = Riser::DRbServices.new(drb_process_num
|
891
|
+
drb_services = Riser::DRbServices.new(drb_process_num,
|
892
|
+
server_config: @config.drb_server_config,
|
893
|
+
client_config: @config.drb_client_config)
|
784
894
|
drb_services.add_sticky_process_service(:engine,
|
785
895
|
Riser::ResourceSet.build{|builder|
|
786
896
|
builder.at_create{|unique_user_id|
|
787
897
|
mail_store = MailStore.build(unique_user_id, kvs_meta_open, kvs_text_open)
|
788
898
|
Protocol::Decoder::Engine.new(unique_user_id, mail_store, logger,
|
789
899
|
bulk_response_count: @config.bulk_response_count,
|
900
|
+
bulk_response_size: @config.bulk_response_size,
|
790
901
|
read_lock_timeout_seconds: @config.read_lock_timeout_seconds,
|
791
902
|
write_lock_timeout_seconds: @config.write_lock_timeout_seconds,
|
792
|
-
cleanup_write_lock_timeout_seconds: @config.cleanup_write_lock_timeout_seconds
|
903
|
+
cleanup_write_lock_timeout_seconds: @config.cleanup_write_lock_timeout_seconds,
|
904
|
+
charset_aliases: @config.charset_aliases,
|
905
|
+
charset_convert_options: @config.charset_convert_options)
|
793
906
|
}
|
794
907
|
builder.at_destroy{|engine|
|
795
908
|
engine.destroy
|
@@ -806,17 +919,17 @@ module RIMS
|
|
806
919
|
file_logger_params[1..-2].each_with_index do |value, i|
|
807
920
|
logger.info("file logging parameter: shift_args[#{i}]=#{value}")
|
808
921
|
end
|
809
|
-
for name, value in
|
922
|
+
for name, value in file_logger_opts
|
810
923
|
logger.info("file logging parameter: #{name}=#{value}")
|
811
924
|
end
|
812
|
-
for name, value in
|
925
|
+
for name, value in stdout_logger_opts
|
813
926
|
logger.info("stdout logging parameter: #{name}=#{value}")
|
814
927
|
end
|
815
928
|
logger.info("protocol logging parameter: path=#{protocol_logger_params[0]}")
|
816
929
|
protocol_logger_params[1..-2].each_with_index do |value, i|
|
817
930
|
logger.info("protocol logging parameter: shift_args[#{i}]=#{value}")
|
818
931
|
end
|
819
|
-
for name, value in
|
932
|
+
for name, value in protocol_logger_opts
|
820
933
|
logger.info("protocol logging parameter: #{name}=#{value}")
|
821
934
|
end
|
822
935
|
logger.info("listen address: #{server_socket.local_address.inspect_sockaddr}")
|
@@ -895,11 +1008,27 @@ module RIMS
|
|
895
1008
|
logger.info("connection parameter: send_buffer_limit_size=#{@config.send_buffer_limit_size}")
|
896
1009
|
logger.info("connection parameter: read_polling_interval_seconds=#{conn_limits.read_polling_interval_seconds}")
|
897
1010
|
logger.info("connection parameter: command_wait_timeout_seconds=#{conn_limits.command_wait_timeout_seconds}")
|
1011
|
+
logger.info("protocol parameter: line_length_limit=#{@config.protocol_line_length_limit}")
|
1012
|
+
logger.info("protocol parameter: literal_size_limit=#{@config.protocol_literal_size_limit}")
|
1013
|
+
logger.info("protocol parameter: command_size_limit=#{@config.protocol_command_size_limit}")
|
1014
|
+
@config.charset_aliases.each_with_index do |(name, enc), i|
|
1015
|
+
logger.info("charset aliases parameter: alias[#{i}]: #{name} -> #{enc.name}")
|
1016
|
+
end
|
1017
|
+
for name, value in @config.charset_convert_options
|
1018
|
+
logger.info("charset convert_options parameter: #{name}=#{value}")
|
1019
|
+
end
|
898
1020
|
logger.info("drb_services parameter: process_num=#{drb_process_num}")
|
1021
|
+
for name, value in @config.drb_server_config
|
1022
|
+
logger.info("drb_services server config parameter: #{name}=#{value}")
|
1023
|
+
end
|
1024
|
+
for name, value in @config.drb_client_config
|
1025
|
+
logger.info("drb_services client config parameter: #{name}=#{value}")
|
1026
|
+
end
|
899
1027
|
logger.info("drb_services engine parameter: bulk_response_count=#{@config.bulk_response_count}")
|
900
|
-
logger.info("
|
901
|
-
logger.info("
|
902
|
-
logger.info("
|
1028
|
+
logger.info("drb_services engine parameter: bulk_response_size=#{@config.bulk_response_size}")
|
1029
|
+
logger.info("drb_services engine parameter: read_lock_timeout_seconds=#{@config.read_lock_timeout_seconds}")
|
1030
|
+
logger.info("drb_services engine parameter: write_lock_timeout_seconds=#{@config.write_lock_timeout_seconds}")
|
1031
|
+
logger.info("drb_services engine parameter: cleanup_write_lock_timeout_seconds=#{@config.cleanup_write_lock_timeout_seconds}")
|
903
1032
|
kvs_meta_log.call
|
904
1033
|
kvs_text_log.call
|
905
1034
|
logger.info("authentication parameter: hostname=#{auth.hostname}")
|
@@ -947,7 +1076,11 @@ module RIMS
|
|
947
1076
|
stream = Riser::WriteBufferStream.new(socket, @config.send_buffer_limit_size)
|
948
1077
|
end
|
949
1078
|
stream = Riser::LoggingStream.new(stream, protocol_logger)
|
950
|
-
decoder = Protocol::Decoder.new_decoder(drb_services, auth, logger,
|
1079
|
+
decoder = Protocol::Decoder.new_decoder(drb_services, auth, logger,
|
1080
|
+
mail_delivery_user: @config.mail_delivery_user,
|
1081
|
+
line_length_limit: @config.protocol_line_length_limit,
|
1082
|
+
literal_size_limit: @config.protocol_literal_size_limit,
|
1083
|
+
command_size_limit: @config.protocol_command_size_limit)
|
951
1084
|
Protocol::Decoder.repl(decoder, conn_limits, stream, stream, logger)
|
952
1085
|
ensure
|
953
1086
|
if (stream) then
|