class SPF::Record
Constants
- DEFAULT_QUALIFIER
- RESULTS_BY_QUALIFIER
Attributes
errors[R]
terms[R]
text[R]
Public Class Methods
new(options)
click to toggle source
Calls superclass method
# File lib/spf/model.rb, line 843 def initialize(options) super() @parse_text = (@text = options[:text] if not self.instance_variable_defined?(:@parse_text)).dup @terms ||= [] @global_mods ||= {} @errors = [] @ip_netblocks = [] @record_domain = options[:record_domain] @raise_exceptions = options.has_key?(:raise_exceptions) ? options[:raise_exceptions] : true end
new_from_string(text, options = {})
click to toggle source
# File lib/spf/model.rb, line 854 def self.new_from_string(text, options = {}) options[:text] = text record = new(options) record.parse return record end
Public Instance Methods
error(exception)
click to toggle source
# File lib/spf/model.rb, line 861 def error(exception) raise exception if @raise_exceptions @errors << exception end
eval(server, request, want_result = true)
click to toggle source
# File lib/spf/model.rb, line 987 def eval(server, request, want_result = true) raise SPF::OptionRequiredError.new('SPF server object required for record evaluation') unless server raise SPF::OptionRequiredError.new('Request object required for record evaluation') unless request begin @terms.each do |term| if SPF::Mech === term # Term is a mechanism. mech = term if mech.match(server, request, request.ip_address != nil) result_name = RESULTS_BY_QUALIFIER[mech.qualifier] result_class = server.result_class(result_name) result = result_class.new([server, request, "Mechanism '#{term.text}' matched"]) mech.explain(server, request, result) raise result if want_result end elsif SPF::PositionalMod === term # Term is a positional modifier. mod = term mod.process(server, request) elsif SPF::UnknownMod === term # Term is an unknown modifier. Ignore it (RFC 4408, 6/3). else # Invalid term object encountered: error(SPF::UnexpectedTermObjectError.new("Unexpected term object '#{term}' encountered.")) end end server.throw_result(:neutral_by_default, request, 'Default neutral result due to no mechanism matches') rescue SPF::Result => result # Process global modifiers in ascending order of precedence: global_mods.each do |global_mod| global_mod.process(server, request, result) end raise result if want_result end end
global_mod(mod_name)
click to toggle source
# File lib/spf/model.rb, line 979 def global_mod(mod_name) return @global_mods[mod_name] end
global_mods()
click to toggle source
# File lib/spf/model.rb, line 975 def global_mods return @global_mods.values.sort {|a,b| a.precedence <=> b.precedence } end
ip_netblocks()
click to toggle source
# File lib/spf/model.rb, line 866 def ip_netblocks @ip_netblocks.flatten! return @ip_netblocks end
parse()
click to toggle source
# File lib/spf/model.rb, line 871 def parse unless self.instance_variable_defined?(:@parse_text) and @parse_text error(SPF::NothingToParseError.new('Nothing to parse for record')) return end self.parse_version_tag while @parse_text.length > 0 term = nil begin term = self.parse_term rescue SPF::Error => e term.errors << e if term @errors << e raise if @raise_exceptions return if SPF::JunkInRecordError === e or SPF::JunkInTermError === e end end end
parse_term()
click to toggle source
# File lib/spf/model.rb, line 898 def parse_term regex = / ^ ( #{SPF::Mech::QUALIFIER_PATTERN}? (#{SPF::Mech::NAME_PATTERN}) [^\x20]* ) (?: \x20+ | $ ) /x term = nil if @parse_text.sub!(regex, '') and $& # Looks like a mechanism: mech_text = $1 mech_name = $2.downcase mech_class = self.mech_classes[mech_name.to_sym] exception = nil unless mech_class exception = SPF::InvalidMechError.new("Unknown mechanism type '#{mech_name}' in '#{self.version_tag}' record") error(exception) mech_class = SPF::Mech end options = {:raise_exceptions => @raise_exceptions} if instance_variable_defined?("@record_domain") options[:record_domain] = @record_domain end term = mech = mech_class.new_from_string(mech_text, options) term.errors << exception if exception @ip_netblocks << mech.ip_netblocks if mech.ip_netblocks @terms << mech if mech_class == SPF::Mech raise SPF::InvalidMechError.new("Unknown mechanism type '#{mech_name}' in '#{self.version_tag}' record") end elsif ( @parse_text.sub!(/ ^ ( (#{SPF::Mod::NAME_PATTERN}) = [^\x20]* ) (?: \x20+ | $ ) /x, '') and $& ) # Looks like a modifier: mod_text = $1 mod_name = $2.downcase mod_class = self.class::MOD_CLASSES[mod_name.to_sym] || SPF::UnknownMod if mod_class # Known modifier. term = mod = mod_class.new_from_string(mod_text, {:raise_exceptions => @raise_exceptions}) if SPF::GlobalMod === mod # Global modifier. if @global_mods[mod_name] raise SPF::DuplicateGlobalModError.new("Duplicate global modifier '#{mod_name}' encountered") end @global_mods[mod_name] = mod elsif SPF::PositionalMod === mod # Positional modifier, queue normally: @terms << mod end end else token_text = @parse_text.sub(/\s.*/, '') hint = nil if token_text =~ /#{SPF::Term::IPV4_ADDRESS_PATTERN}/x hint = 'missing ip4: before IPv4 address?' elsif token_text =~ /#{SPF::Term::IPV6_ADDRESS_PATTERN}/x hint = 'missing ip6: before IPv6 address?' end raise SPF::JunkInRecordError.new("Junk encountered in record '#{@text}'", @text, @parse_text, hint) end @errors.concat(term.errors) return term end
parse_version_tag()
click to toggle source
# File lib/spf/model.rb, line 890 def parse_version_tag @parse_text.sub!(/^#{self.version_tag_pattern}\s*/ix, '') unless $1 raise SPF::InvalidRecordVersionError.new( "Not a '#{self.version_tag}' record: '#{@text}'") end end
to_s()
click to toggle source
# File lib/spf/model.rb, line 983 def to_s return [version_tag, @terms, @global_mods].join(' ') end