Class: SPF::Request

Inherits:
Object
  • Object
show all
Defined in:
lib/spf/request.rb

Constant Summary collapse

VERSIONS_FOR_SCOPE =
{
  :helo  => [1   ],
  :mfrom => [1, 2],
  :pra   => [   2]
}
SCOPES_BY_VERSION =
{
  1      => [:helo, :mfrom      ],
  2      => [       :mfrom, :pra]
}
DEFAULT_LOCALPART =
'postmaster'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Request

Returns a new instance of Request.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/spf/request.rb', line 24

def initialize(options = {})
  @opt               = options
  @state             = {}
  @versions          = options[:versions]
  @scope             = options[:scope]             || :mfrom
  @scope             = @scope.to_sym if String === @scope
  @authority_domain  = options[:authority_domain]
  @identity          = options[:identity]
  @ip_address        = options[:ip_address]
  @helo_identity     = options[:helo_identity]
  @root_request      = self
  @super_request     = self
  @record            = nil
  @sub_requests      = []

  # Scope:
  versions_for_scope = VERSIONS_FOR_SCOPE[@scope] or
    raise SPF::InvalidScopeError.new("Invalid scope '#{@scope}'")

  # Versions:
  if @versions
    if Symbol === @versions
      # Single version specified as a symbol:
      @versions = [@versions]
    elsif not Array === @versions
      # Something other than symbol or array specified:
      raise SPF::InvalidOptionValueError.new("'versions' option must be symbol or array")
    end

    # All requested record versions must be supported:
    unsupported_versions = @versions.select { |x|
      not SCOPES_BY_VERSION[x]
    }
    if unsupported_versions.any?
      raise SPF::InvalidOptionValueError.new(
        "Unsupported record version(s): " +
        unsupported_versions.map { |x| "'#{x}'" }.join(', '))
    end
  else
    # No versions specified, use all versions relevant to scope:
    @versions = versions_for_scope
  end

  # Identity:
  raise SPF::OptionRequiredError.new(
    "Missing required 'identity' option") unless @identity
  raise SPF::InvalidOptionValueError.new(
    "'identity' option must not be empty") if @identity.empty?

  # Extract domain and localpart from identity:
  if ((@scope == :mfrom or @scope == :pra) and
      @identity =~ /^(.*)@(.*?)$/)
    @localpart = $1
    @domain    = $2
  else
    @domain    = @identity
  end
  # Lower-case domain and removee eventual trailing dot.
  @domain.downcase!
  @domain.chomp!('.')
  if (not self.instance_variable_defined?(:@localpart) or
      not @localpart or not @localpart.length > 0)
    @localpart = DEFAULT_LOCALPART
  end

  # HELO identity:
  if @scope == :helo
    @helo_identity ||= @identity
  end

  return unless @ip_address

  # Ensure ip_address is an IP object:
  unless IP === @ip_address
    @ip_address = IP.new(@ip_address)
  end

  # Convert IPv4 address to IPv4-mapped IPv6 address:

  if SPF::Util.ipv6_address_is_ipv4_mapped(@ip_address)
    @ip_address_v6 = @ip_address # Accept as IPv6 address as-is
    @ip_address = SPF::Util.ipv6_address_to_ipv4(@ip_address)
  elsif IP::V4 === @ip_address
    @ip_address_v6 = SPF::Util.ipv4_address_to_ipv6(@ip_address)
  elsif IP::V6 === @ip_address
    @ip_address_v6 = @ip_address
  else
    raise SPF::InvalidOptionValueError.new("Unexpected IP address version");
  end
end

Instance Attribute Details

#domainObject (readonly)

Returns the value of attribute domain.



8
9
10
# File 'lib/spf/request.rb', line 8

def domain
  @domain
end

#helo_identityObject (readonly)

Returns the value of attribute helo_identity.



8
9
10
# File 'lib/spf/request.rb', line 8

def helo_identity
  @helo_identity
end

#identityObject (readonly)

Returns the value of attribute identity.



8
9
10
# File 'lib/spf/request.rb', line 8

def identity
  @identity
end

#ip_addressObject (readonly)

Returns the value of attribute ip_address.



8
9
10
# File 'lib/spf/request.rb', line 8

def ip_address
  @ip_address
end

#ip_address_v6Object (readonly)

Returns the value of attribute ip_address_v6.



8
9
10
# File 'lib/spf/request.rb', line 8

def ip_address_v6
  @ip_address_v6
end

#localpartObject (readonly)

Returns the value of attribute localpart.



8
9
10
# File 'lib/spf/request.rb', line 8

def localpart
  @localpart
end

#optObject

Returns the value of attribute opt.



9
10
11
# File 'lib/spf/request.rb', line 9

def opt
  @opt
end

#recordObject

Returns the value of attribute record.



9
10
11
# File 'lib/spf/request.rb', line 9

def record
  @record
end

#root_requestObject

Returns the value of attribute root_request.



9
10
11
# File 'lib/spf/request.rb', line 9

def root_request
  @root_request
end

#scopeObject (readonly)

Returns the value of attribute scope.



8
9
10
# File 'lib/spf/request.rb', line 8

def scope
  @scope
end

#sub_requestsObject (readonly)

Returns the value of attribute sub_requests.



8
9
10
# File 'lib/spf/request.rb', line 8

def sub_requests
  @sub_requests
end

#super_requestObject

Returns the value of attribute super_request.



9
10
11
# File 'lib/spf/request.rb', line 9

def super_request
  @super_request
end

#versionsObject (readonly)

Returns the value of attribute versions.



8
9
10
# File 'lib/spf/request.rb', line 8

def versions
  @versions
end

Instance Method Details

#authority_domainObject



123
124
125
# File 'lib/spf/request.rb', line 123

def authority_domain
  return (@authority_domain or @domain)
end

#new_sub_request(options) ⇒ Object



115
116
117
118
119
120
121
# File 'lib/spf/request.rb', line 115

def new_sub_request(options)
  obj = self.class.new(@opt.merge(options))
  obj.super_request = self
  obj.root_request  = super_request.root_request
  @sub_requests << obj
  return obj
end

#state(field, value = nil) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
# File 'lib/spf/request.rb', line 127

def state(field, value = nil)
  unless field
    raise SPF::OptionRequiredError.new('Field name required')
  end
  if value and Fixnum === value
    @state[field] = 0 unless @state[field]
    @state[field] += value
  else
    @state[field] = value
  end
end