# -*- encoding: utf-8 -*- module Stomp # Container class for frames, misnamed technically class Message attr_accessor :command, :headers, :body, :original @@allowed_commands = [ Stomp::CMD_CONNECTED, Stomp::CMD_MESSAGE, Stomp::CMD_RECEIPT, Stomp::CMD_ERROR ] def initialize(frame, protocol11p = false) # p [ "00", frame, frame.encoding ] # Set default empty values self.command = '' self.headers = {} self.body = '' self.original = frame return self if is_blank?(frame) # Figure out where individual parts of the frame begin and end. command_index = frame.index("\n") raise Stomp::Error::InvalidFormat, 'command index' unless command_index # headers_index = frame.index("\n\n", command_index+1) raise Stomp::Error::InvalidFormat, 'headers index' unless headers_index # lastnull_index = frame.rindex("\0") raise Stomp::Error::InvalidFormat, 'lastnull index' unless lastnull_index # Extract working copies of each frame part work_command = frame[0..command_index-1] raise Stomp::Error::InvalidServerCommand, "invalid command: #{work_command.inspect}" unless @@allowed_commands.include?(work_command) # work_headers = frame[command_index+1..headers_index-1] raise Stomp::Error::InvalidFormat, 'nil headers' unless work_headers # work_body = frame[headers_index+2..lastnull_index-1] raise Stomp::Error::InvalidFormat, 'nil body' unless work_body # Set the frame values if protocol11p work_command.force_encoding(Stomp::UTF8) if work_command.respond_to?(:force_encoding) end self.command = work_command work_headers.split("\n").map do |value| parsed_value = value.match /^([\w|-]*):(.*)$/ raise Stomp::Error::InvalidFormat, 'parsed header value' unless parsed_value # pk = parsed_value[1] pv = parsed_value[2] # if protocol11p pk.force_encoding(Stomp::UTF8) if pk.respond_to?(:force_encoding) pv.force_encoding(Stomp::UTF8) if pv.respond_to?(:force_encoding) # Stomp 1.1+ - Servers may put multiple values for a single key on the wire. # If so, we support reading those, and passing them to the user. if self.headers[pk] if self.headers[pk].is_a?(Array) # The 3rd and any subsequent ones for this key self.headers[pk] << pv else # The 2nd one for this key tv = self.headers[pk] + "" self.headers[pk] = [] self.headers[pk] << tv << pv end else self.headers[pk] = pv # The 1st one for this key end else # Stomp 1.0 self.headers[pk.strip] = pv.strip unless self.headers[pk.strip] # Only receive the 1st one end end body_length = -1 if self.headers['content-length'] body_length = self.headers['content-length'].to_i raise Stomp::Error::InvalidMessageLength if work_body.length != body_length end self.body = work_body[0..body_length] end def to_s "" end def empty? is_blank?(command) && is_blank?(headers) && is_blank?(body) end private def is_blank?(value) value.nil? || (value.respond_to?(:empty?) && value.empty?) end end end