class RIMS::Protocol::RequestReader
Attributes
command_tag[R]
Public Class Methods
new(input, output, logger, line_length_limit: 1024*8, literal_size_limit: (1024**2)*10, command_size_limit: (1024**2)*10)
click to toggle source
# File lib/rims/protocol/parser.rb, line 98 def initialize(input, output, logger, line_length_limit: 1024*8, literal_size_limit: (1024**2)*10, command_size_limit: (1024**2)*10) @input = input @output = output @logger = logger @line_length_limit = line_length_limit @literal_size_limit = literal_size_limit @command_size_limit = command_size_limit @command_tag = nil @read_size = 0 end
parse(atom_list, last_atom=nil)
click to toggle source
# File lib/rims/protocol/parser.rb, line 72 def self.parse(atom_list, last_atom=nil) syntax_list = [] while (atom = atom_list.shift) case (atom) when last_atom break when :'(' syntax_list.push([ :group ] + parse(atom_list, :')')) when :'[' syntax_list.push([ :block ] + parse(atom_list, :']')) else if ((atom.is_a? Array) && (atom[0] == :body)) then body = atom[1] body.section_list = parse(scan(body.section)) end syntax_list.push(atom) end end if (atom == nil && last_atom != nil) then raise SyntaxError, "not found a terminator: `#{last_atom}'" end syntax_list end
scan(line)
click to toggle source
# File lib/rims/protocol/parser.rb, line 35 def self.scan(line) atom_list = line.scan(/BODY(?:\.\S+)?\[.*?\](?:<\d+\.\d+>)?|[\[\]()]|".*?"|[^\[\]()\s]+/i).map{|s| case (s) when '(', ')', '[', ']', /\A NIL \z/ix s.upcase.intern when /\A "/x s.sub(/\A "/x, '').sub(/" \z/x, '') when / \A (?<body_symbol>BODY) (?:\. (?<body_option>\S+))? \[ (?<body_section>.*) \] (?:< (?<partial_origin>\d+) \. (?<partial_size>\d+) >)? \z /ix body_symbol = $~[:body_symbol] body_option = $~[:body_option] body_section = $~[:body_section] partial_origin = $~[:partial_origin] && $~[:partial_origin].to_i partial_size = $~[:partial_size] && $~[:partial_size].to_i [ :body, Protocol.body(symbol: body_symbol, option: body_option, section: body_section, partial_origin: partial_origin, partial_size: partial_size) ] else s end } if ((atom_list[-1].is_a? String) && (atom_list[-1] =~ /\A {\d+} \z/x)) then literal_size = $&[1..-2].to_i atom_list[-1] = [ :literal, literal_size ] end atom_list end
Public Instance Methods
gets()
click to toggle source
# File lib/rims/protocol/parser.rb, line 111 def gets if (line = @input.gets($/, @line_length_limit)) then # arguments compatible with OpenSSL::Buffering#gets if (line.bytesize < @line_length_limit) then line elsif (line.bytesize == @line_length_limit && (line.end_with? $/)) then line else raise LineTooLongError.new('line too long.', line_fragment: line) end end end
read_command()
click to toggle source
# File lib/rims/protocol/parser.rb, line 170 def read_command @command_tag = nil @read_size = 0 while (atom_list = read_line) if (atom_list.empty?) then @read_size = 0 next end if (atom_list.length < 2) then raise SyntaxError, 'need for tag and command.' end return self.class.parse(atom_list) end nil end
Private Instance Methods
read_line()
click to toggle source
# File lib/rims/protocol/parser.rb, line 142 def read_line line = gets or return @logger.debug("read line: #{Protocol.io_data_log(line)}") if @logger.debug? line.chomp!("\n") line.chomp!("\r") @read_size += line.bytesize if (@read_size > @command_size_limit) then raise CommandSizeTooLargeError.new('command size too large', @command_tag) end atom_list = self.class.scan(line) if (@command_tag.nil? && ! atom_list.empty?) then unless ((atom_list[0].is_a? String) && ! (atom_list[0].start_with? '*', '+')) then raise SyntaxError, "invalid command tag: #{atom_list[0]}" end @command_tag = atom_list[0] end if ((atom_list[-1].is_a? Array) && (atom_list[-1][0] == :literal)) then atom_list[-1] = read_literal(atom_list[-1][1]) next_atom_list = read_line or raise 'unexpected client close.' atom_list += next_atom_list end atom_list end
read_literal(size)
click to toggle source
# File lib/rims/protocol/parser.rb, line 123 def read_literal(size) @logger.debug("found literal: #{size} octets.") if @logger.debug? if (size > @literal_size_limit) then raise LiteralSizeTooLargeError.new('literal size too large', @command_tag) end if (@read_size + size > @command_size_limit) then raise CommandSizeTooLargeError.new('command size too large', @command_tag) end @output.write("+ continue\r\n") @output.flush @logger.debug('continue literal.') if @logger.debug? literal_string = @input.read(size) or raise 'unexpected client close.' @read_size += size @logger.debug("read literal: #{Protocol.io_data_log(literal_string)}") if @logger.debug? literal_string end