coppertone 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/LICENSE +1 -1
- data/Rakefile +2 -2
- data/coppertone.gemspec +1 -0
- data/lib/coppertone/directive.rb +14 -7
- data/lib/coppertone/error.rb +24 -5
- data/lib/coppertone/ip_address_wrapper.rb +9 -6
- data/lib/coppertone/macro_context.rb +7 -13
- data/lib/coppertone/macro_string/macro_expand.rb +3 -2
- data/lib/coppertone/macro_string.rb +12 -5
- data/lib/coppertone/mechanism/a.rb +5 -1
- data/lib/coppertone/mechanism/all.rb +11 -4
- data/lib/coppertone/mechanism/cidr_parser.rb +1 -1
- data/lib/coppertone/mechanism/domain_spec_mechanism.rb +9 -0
- data/lib/coppertone/mechanism/domain_spec_optional.rb +1 -0
- data/lib/coppertone/mechanism/domain_spec_required.rb +1 -0
- data/lib/coppertone/mechanism/domain_spec_with_dual_cidr.rb +1 -0
- data/lib/coppertone/mechanism/exists.rb +5 -1
- data/lib/coppertone/mechanism/include.rb +17 -5
- data/lib/coppertone/mechanism/ip4.rb +5 -1
- data/lib/coppertone/mechanism/ip6.rb +5 -1
- data/lib/coppertone/mechanism/ip_mechanism.rb +9 -1
- data/lib/coppertone/mechanism/mx.rb +5 -1
- data/lib/coppertone/mechanism/ptr.rb +5 -1
- data/lib/coppertone/mechanism.rb +25 -2
- data/lib/coppertone/modifier/base.rb +1 -0
- data/lib/coppertone/modifier/exp.rb +6 -2
- data/lib/coppertone/modifier/redirect.rb +5 -1
- data/lib/coppertone/modifier/unknown.rb +6 -1
- data/lib/coppertone/modifier.rb +11 -2
- data/lib/coppertone/null_macro_context.rb +23 -0
- data/lib/coppertone/qualifier.rb +8 -0
- data/lib/coppertone/record.rb +33 -41
- data/lib/coppertone/record_finder.rb +3 -1
- data/lib/coppertone/record_term_parser.rb +30 -0
- data/lib/coppertone/request.rb +3 -1
- data/lib/coppertone/request_context.rb +1 -2
- data/lib/coppertone/result.rb +6 -2
- data/lib/coppertone/utils/validated_domain_finder.rb +6 -4
- data/lib/coppertone/version.rb +1 -1
- data/lib/coppertone.rb +3 -1
- data/spec/directive_spec.rb +13 -0
- data/spec/ip_address_wrapper_spec.rb +3 -0
- data/spec/macro_string_spec.rb +20 -0
- data/spec/mechanism/a_spec.rb +22 -7
- data/spec/mechanism/all_spec.rb +8 -0
- data/spec/mechanism/exists_spec.rb +14 -6
- data/spec/mechanism/include_spec.rb +13 -1
- data/spec/mechanism/ip4_spec.rb +15 -5
- data/spec/mechanism/ip6_spec.rb +18 -11
- data/spec/mechanism/mx_spec.rb +56 -0
- data/spec/mechanism/ptr_spec.rb +7 -0
- data/spec/modifier/exp_spec.rb +10 -0
- data/spec/modifier/redirect_spec.rb +10 -0
- data/spec/open_spf/ALL_mechanism_syntax_spec.rb +6 -6
- data/spec/open_spf/A_mechanism_syntax_spec.rb +30 -30
- data/spec/open_spf/EXISTS_mechanism_syntax_spec.rb +8 -8
- data/spec/open_spf/IP4_mechanism_syntax_spec.rb +10 -10
- data/spec/open_spf/IP6_mechanism_syntax_spec.rb +10 -10
- data/spec/open_spf/Include_mechanism_semantics_and_syntax_spec.rb +10 -10
- data/spec/open_spf/Initial_processing_spec.rb +21 -14
- data/spec/open_spf/MX_mechanism_syntax_spec.rb +22 -22
- data/spec/open_spf/Macro_expansion_rules_spec.rb +26 -30
- data/spec/open_spf/PTR_mechanism_syntax_spec.rb +7 -7
- data/spec/open_spf/Processing_limits_spec.rb +12 -12
- data/spec/open_spf/Record_evaluation_spec.rb +13 -13
- data/spec/open_spf/Record_lookup_spec.rb +8 -8
- data/spec/open_spf/Selecting_records_spec.rb +11 -11
- data/spec/open_spf/Semantics_of_exp_and_other_modifiers_spec.rb +27 -25
- data/spec/open_spf/Test_cases_from_implementation_bugs_spec.rb +2 -2
- data/spec/record_spec.rb +34 -13
- data/spec/request_context_spec.rb +1 -1
- data/spec/rfc7208-tests.yml +10 -0
- metadata +59 -48
- data/lib/coppertone/dns/error.rb +0 -9
- data/lib/coppertone/dns/mock_client.rb +0 -106
- data/lib/coppertone/dns/resolv_client.rb +0 -110
- data/lib/coppertone/dns.rb +0 -3
- data/lib/resolv/dns/resource/in/spf.rb +0 -15
- data/spec/dns/resolv_client_spec.rb +0 -307
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70afc7cde39b4b1374dd4b0a580b9908a15b8745
|
4
|
+
data.tar.gz: ef5687a65195e0c2291f68bad0671b5448b35af6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f441c6616fe2346f55fa5251c74a15c5f77701684d612441a918572da57675a89b1cb956a4c7aee006e59f496dfd33b4378a133005eb703a66dbee9f7dde0ce4
|
7
|
+
data.tar.gz: c9b568748213933e23c29ca8028cf96b8b179357cd02c0c7915dd05bba7adf033a5005be97f2677de9f70e6fb8afa17192765b59bb4251de1fd9410662c0b4d1
|
data/.travis.yml
CHANGED
data/LICENSE
CHANGED
@@ -186,7 +186,7 @@ Apache License
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
187
187
|
identification within third-party archives.
|
188
188
|
|
189
|
-
Copyright
|
189
|
+
Copyright 2014 Peter M. Goldstein
|
190
190
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
192
192
|
you may not use this file except in compliance with the License.
|
data/Rakefile
CHANGED
@@ -48,7 +48,7 @@ def write_zonedata(f, zonedata, indent = 1)
|
|
48
48
|
puts_prefixed_string(f, zonedata, indent + 1)
|
49
49
|
puts_prefixed_string(f, 'end', indent)
|
50
50
|
empty_line(f)
|
51
|
-
dns_line = 'let(:dns_client) {
|
51
|
+
dns_line = 'let(:dns_client) { DNSAdapter::MockClient.new(zonefile) }'
|
52
52
|
puts_prefixed_string(f, dns_line, indent)
|
53
53
|
puts_prefixed_string(f, 'let(:options) { { dns_client: dns_client } }',
|
54
54
|
indent)
|
@@ -85,7 +85,7 @@ def write_result(f, host, mailfrom, helo, indent)
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def write_expects(f, results, explanation, indent)
|
88
|
-
results_array = "
|
88
|
+
results_array = "[#{results.map { |r| ':' + r } .join(',')}]"
|
89
89
|
code_expect = "expect(#{results_array}).to include(result.code)"
|
90
90
|
puts_prefixed_string(f, code_expect, indent)
|
91
91
|
return unless explanation
|
data/coppertone.gemspec
CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
18
18
|
spec.require_paths = ['lib']
|
19
19
|
|
20
|
+
spec.add_runtime_dependency 'dns_adapter'
|
20
21
|
spec.add_runtime_dependency 'i18n'
|
21
22
|
spec.add_runtime_dependency 'addressable'
|
22
23
|
spec.add_runtime_dependency 'activesupport', '>= 3.0'
|
data/lib/coppertone/directive.rb
CHANGED
@@ -12,13 +12,20 @@ module Coppertone
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def evaluate(context, options)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
if mechanism.match?(context, options)
|
16
|
+
Coppertone::Result.from_directive(self)
|
17
|
+
else
|
18
|
+
Result.none
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def all?
|
23
|
+
mechanism.is_a?(Coppertone::Mechanism::All)
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
mechanism_s = mechanism.to_s
|
28
|
+
qualifier.default? ? mechanism_s : "#{qualifier}#{mechanism_s}"
|
22
29
|
end
|
23
30
|
|
24
31
|
DIRECTIVE_REGEXP = /\A([\+\-\~\?]?)([a-zA-Z0-9]*)((:?)\S*)\z/
|
data/lib/coppertone/error.rb
CHANGED
@@ -2,26 +2,45 @@ module Coppertone
|
|
2
2
|
class Error < ::StandardError
|
3
3
|
end
|
4
4
|
|
5
|
+
# Error classes mapping to the SPF result codes
|
5
6
|
class TemperrorError < Coppertone::Error; end
|
6
7
|
class PermerrorError < Coppertone::Error; end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
class MissingQualifierError < Coppertone::PermerrorError; end
|
11
|
-
|
9
|
+
# Errors occurring when the string representation of a MacroString
|
10
|
+
# or DomainSpec does not obey the syntax requirements.
|
12
11
|
class MacroStringParsingError < Coppertone::PermerrorError; end
|
13
12
|
class DomainSpecParsingError < MacroStringParsingError; end
|
14
13
|
|
14
|
+
# Occurs when an SPF record cannot be parsed.
|
15
15
|
class RecordParsingError < Coppertone::PermerrorError; end
|
16
|
+
|
17
|
+
# Occurs when an individual mechanism cannot be parsed, usually
|
18
|
+
# because the arguments passed to the mechanism are not syntactically
|
19
|
+
# valid.
|
16
20
|
class InvalidMechanismError < Coppertone::RecordParsingError; end
|
21
|
+
|
22
|
+
# Occurs when an individual modifier cannot be parsed, usually
|
23
|
+
# because the arguments passed to the modifier are not syntactically
|
24
|
+
# valid.
|
17
25
|
class InvalidModifierError < Coppertone::RecordParsingError; end
|
18
26
|
|
19
|
-
|
27
|
+
# Occurs when an SPF record cannot be parsed because of a duplicate
|
28
|
+
# modifier.
|
29
|
+
class DuplicateModifierError < Coppertone::RecordParsingError; end
|
30
|
+
|
31
|
+
# Occurs when more than one potential SPF record is found for a
|
32
|
+
# domain.
|
20
33
|
class AmbiguousSpfRecordError < Coppertone::PermerrorError; end
|
21
34
|
|
35
|
+
# Occurs when the SPF record referenced by an include mechanism
|
36
|
+
# yields a 'none' result. This results in a permerror.
|
22
37
|
class NoneIncludeResultError < Coppertone::PermerrorError; end
|
38
|
+
|
39
|
+
# Occurs when an SPF record cannot be found for the domain
|
40
|
+
# referenced in a redirect macro.
|
23
41
|
class InvalidRedirectError < Coppertone::PermerrorError; end
|
24
42
|
|
43
|
+
# Errors generated when certain spec-defined limits are exceeded.
|
25
44
|
class LimitExceededError < Coppertone::PermerrorError; end
|
26
45
|
class TermLimitExceededError < PermerrorError; end
|
27
46
|
class VoidLimitExceededError < PermerrorError; end
|
@@ -7,7 +7,7 @@ module Coppertone
|
|
7
7
|
# of IPs in mechanism evaluation and macro string evaluation.
|
8
8
|
#
|
9
9
|
# Note: This class should only be used with a single IP address, and
|
10
|
-
# will fail if passed an address with a prefix
|
10
|
+
# will fail if passed an address with a non-trivial network prefix
|
11
11
|
class IPAddressWrapper
|
12
12
|
attr_reader :string_representation, :ip
|
13
13
|
def initialize(s)
|
@@ -16,12 +16,19 @@ module Coppertone
|
|
16
16
|
@string_representation = s
|
17
17
|
end
|
18
18
|
|
19
|
+
# Hack for JRuby - remove when JRuby moves to 2.0.x
|
20
|
+
if RUBY_VERSION < '2.0'
|
21
|
+
IP_PARSE_ERROR = ArgumentError
|
22
|
+
else
|
23
|
+
IP_PARSE_ERROR = IPAddr::InvalidAddressError
|
24
|
+
end
|
25
|
+
|
19
26
|
def self.parse(s)
|
20
27
|
return nil unless s
|
21
28
|
return nil if s.index('/')
|
22
29
|
ip_addr = IPAddr.new(s)
|
23
30
|
normalize_ip(ip_addr)
|
24
|
-
rescue
|
31
|
+
rescue IP_PARSE_ERROR
|
25
32
|
nil
|
26
33
|
end
|
27
34
|
|
@@ -48,10 +55,6 @@ module Coppertone
|
|
48
55
|
original_ipv4? ? 'in-addr' : 'ip6'
|
49
56
|
end
|
50
57
|
|
51
|
-
def p
|
52
|
-
fail NotImplementedError
|
53
|
-
end
|
54
|
-
|
55
58
|
def ip_v4
|
56
59
|
original_ipv4? ? @ip : nil
|
57
60
|
end
|
@@ -5,13 +5,13 @@ require 'uri'
|
|
5
5
|
|
6
6
|
module Coppertone
|
7
7
|
# A context used to evaluate MacroStrings. Responds to all of the
|
8
|
-
# macro letter directives.
|
8
|
+
# macro letter directives except 'p'.
|
9
9
|
class MacroContext
|
10
10
|
attr_reader :domain, :ip_address_wrapper, :sender_identity, :helo_domain
|
11
11
|
|
12
12
|
delegate :s, :l, :o, to: :sender_identity
|
13
13
|
alias_method :d, :domain
|
14
|
-
delegate :i, :
|
14
|
+
delegate :i, :v, :c, to: :ip_address_wrapper
|
15
15
|
delegate :ip_v4, :ip_v6, :original_ipv4?, :original_ipv6?,
|
16
16
|
to: :ip_address_wrapper
|
17
17
|
alias_method :h, :helo_domain
|
@@ -28,25 +28,19 @@ module Coppertone
|
|
28
28
|
|
29
29
|
UNKNOWN_HOSTNAME = 'unknown'
|
30
30
|
def r
|
31
|
-
|
32
|
-
|
33
|
-
else
|
34
|
-
UNKNOWN_HOSTNAME
|
35
|
-
end
|
31
|
+
valid = Coppertone::Utils::DomainUtils.valid?(raw_hostname)
|
32
|
+
valid ? raw_hostname : UNKNOWN_HOSTNAME
|
36
33
|
end
|
37
34
|
|
38
35
|
def t
|
39
36
|
Time.now.to_i
|
40
37
|
end
|
41
38
|
|
42
|
-
|
39
|
+
RESERVED_REGEXP = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
|
40
|
+
%w(s l o d i v h c r t).each do |m|
|
43
41
|
define_method(m.upcase) do
|
44
42
|
unencoded = send(m)
|
45
|
-
|
46
|
-
::URI.escape(unencoded, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
47
|
-
else
|
48
|
-
nil
|
49
|
-
end
|
43
|
+
unencoded ? ::URI.escape(unencoded, RESERVED_REGEXP) : nil
|
50
44
|
end
|
51
45
|
end
|
52
46
|
|
@@ -39,9 +39,10 @@ module Coppertone
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def expand_ptr(context, request)
|
42
|
+
context.send(@macro_letter) if context.respond_to?(@macro_letter)
|
42
43
|
ptr =
|
43
44
|
Coppertone::Utils::ValidatedDomainFinder
|
44
|
-
.new(context, request).find(context.d)
|
45
|
+
.new(context, request, false).find(context.d)
|
45
46
|
return 'unknown' unless ptr
|
46
47
|
@macro_letter == 'P' ? ::Addressable::URI.encode_component(ptr) : ptr
|
47
48
|
end
|
@@ -58,7 +59,7 @@ module Coppertone
|
|
58
59
|
end
|
59
60
|
|
60
61
|
def to_s
|
61
|
-
@body
|
62
|
+
"%{#{@body}}"
|
62
63
|
end
|
63
64
|
|
64
65
|
def ==(other)
|
@@ -11,16 +11,23 @@ module Coppertone
|
|
11
11
|
attr_reader :macro_text
|
12
12
|
def initialize(macro_text)
|
13
13
|
@macro_text = macro_text
|
14
|
-
|
14
|
+
macros
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
19
|
-
@macros = MacroParser.new(macro_text).macros
|
17
|
+
def macros
|
18
|
+
@macros ||= MacroParser.new(macro_text).macros
|
20
19
|
end
|
21
20
|
|
22
21
|
def expand(context, request = nil)
|
23
|
-
|
22
|
+
macros.map { |m| m.expand(context, request) }.join('')
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
macros.map(&:to_s).join('')
|
27
|
+
end
|
28
|
+
|
29
|
+
def context_dependent?
|
30
|
+
macros.any? { |m| m.is_a?(Coppertone::MacroString::MacroExpand) }
|
24
31
|
end
|
25
32
|
|
26
33
|
def ==(other)
|
@@ -10,7 +10,11 @@ module Coppertone
|
|
10
10
|
.new(macro_context, request_context)
|
11
11
|
.check(target_name, ip_v4_cidr_length, ip_v6_cidr_length)
|
12
12
|
end
|
13
|
+
|
14
|
+
def self.label
|
15
|
+
'a'
|
16
|
+
end
|
13
17
|
end
|
14
|
-
register(
|
18
|
+
register(Coppertone::Mechanism::A)
|
15
19
|
end
|
16
20
|
end
|
@@ -3,9 +3,6 @@ module Coppertone
|
|
3
3
|
# Implements the All mechanism. To reduce unnecessary object creation, this
|
4
4
|
# class is a singleton since all All mechanisms behave identically.
|
5
5
|
class All < Mechanism
|
6
|
-
SINGLETON = new
|
7
|
-
private_class_method :new
|
8
|
-
|
9
6
|
def self.create(attributes)
|
10
7
|
fail InvalidMechanismError unless attributes.blank?
|
11
8
|
SINGLETON
|
@@ -15,10 +12,20 @@ module Coppertone
|
|
15
12
|
SINGLETON
|
16
13
|
end
|
17
14
|
|
15
|
+
def self.label
|
16
|
+
'all'
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
super('')
|
21
|
+
end
|
22
|
+
SINGLETON = new
|
23
|
+
private_class_method :new
|
24
|
+
|
18
25
|
def match?(_macro_context, _request_context)
|
19
26
|
true
|
20
27
|
end
|
21
28
|
end
|
22
|
-
register(
|
29
|
+
register(Coppertone::Mechanism::All)
|
23
30
|
end
|
24
31
|
end
|
@@ -13,6 +13,15 @@ module Coppertone
|
|
13
13
|
return nil if raw_domain_spec.blank?
|
14
14
|
raw_domain_spec[1..-1]
|
15
15
|
end
|
16
|
+
|
17
|
+
def self.dns_lookup_term?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def context_dependent?
|
22
|
+
return true unless domain_spec
|
23
|
+
domain_spec.context_dependent?
|
24
|
+
end
|
16
25
|
end
|
17
26
|
end
|
18
27
|
end
|
@@ -8,7 +8,11 @@ module Coppertone
|
|
8
8
|
records = request_context.dns_client.fetch_a_records(target_name)
|
9
9
|
records.any?
|
10
10
|
end
|
11
|
+
|
12
|
+
def self.label
|
13
|
+
'exists'
|
14
|
+
end
|
11
15
|
end
|
12
|
-
register(
|
16
|
+
register(Coppertone::Mechanism::Exists)
|
13
17
|
end
|
14
18
|
end
|
@@ -7,12 +7,24 @@ module Coppertone
|
|
7
7
|
# Implements the include mechanism.
|
8
8
|
class Include < DomainSpecRequired
|
9
9
|
def match_target_name(macro_context, request_context, target_name)
|
10
|
-
|
11
|
-
record
|
12
|
-
|
13
|
-
|
10
|
+
record = included_record(request_context, target_name)
|
11
|
+
IncludeMatcher.new(record)
|
12
|
+
.match?(context_for_include(macro_context, target_name),
|
13
|
+
request_context)
|
14
|
+
end
|
15
|
+
|
16
|
+
def context_for_include(macro_context, target_name)
|
17
|
+
macro_context.with_domain(target_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def included_record(request_context, target_name)
|
21
|
+
RecordFinder.new(request_context.dns_client, target_name).record
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.label
|
25
|
+
'include'
|
14
26
|
end
|
15
27
|
end
|
16
|
-
register(
|
28
|
+
register(Coppertone::Mechanism::Include)
|
17
29
|
end
|
18
30
|
end
|
@@ -8,6 +8,7 @@ module Coppertone
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def initialize(attributes)
|
11
|
+
super(attributes)
|
11
12
|
unless attributes.blank?
|
12
13
|
attributes = attributes[1..-1] if attributes[0] == ':'
|
13
14
|
@ip_network = parse_ip_network(attributes)
|
@@ -21,6 +22,13 @@ module Coppertone
|
|
21
22
|
fail Coppertone::InvalidMechanismError
|
22
23
|
end
|
23
24
|
|
25
|
+
# Hack for JRuby - remove when JRuby moves to 2.0.x
|
26
|
+
if RUBY_VERSION < '2.0'
|
27
|
+
IP_PARSE_ERROR = ArgumentError
|
28
|
+
else
|
29
|
+
IP_PARSE_ERROR = IPAddr::Error
|
30
|
+
end
|
31
|
+
|
24
32
|
def parse_ip_network(ip_as_s)
|
25
33
|
validate_no_leading_zeroes_in_cidr(ip_as_s)
|
26
34
|
addr, cidr_length, dual = ip_as_s.split('/')
|
@@ -28,7 +36,7 @@ module Coppertone
|
|
28
36
|
network = IPAddr.new(addr)
|
29
37
|
network = network.mask(cidr_length.to_i) unless cidr_length.blank?
|
30
38
|
network
|
31
|
-
rescue
|
39
|
+
rescue IP_PARSE_ERROR
|
32
40
|
nil
|
33
41
|
end
|
34
42
|
|
data/lib/coppertone/mechanism.rb
CHANGED
@@ -16,8 +16,31 @@ module Coppertone
|
|
16
16
|
class_builder.build(type, attributes)
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.register(
|
20
|
-
|
19
|
+
def self.register(klass)
|
20
|
+
fail ArgumentError unless klass < self
|
21
|
+
class_builder.register(klass.label, klass)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.dns_lookup_term?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :arguments
|
29
|
+
def initialize(arguments)
|
30
|
+
@arguments = arguments
|
31
|
+
end
|
32
|
+
|
33
|
+
def dns_lookup_term?
|
34
|
+
self.class.dns_lookup_term?
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
mech_label = self.class.label
|
39
|
+
arguments.blank? ? mech_label : "#{mech_label}#{arguments}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def context_dependent?
|
43
|
+
false
|
21
44
|
end
|
22
45
|
end
|
23
46
|
end
|
@@ -17,7 +17,7 @@ module Coppertone
|
|
17
17
|
expanded = macro_string.expand(macro_context, request_context)
|
18
18
|
return nil unless ASCII_REGEXP.match(expanded)
|
19
19
|
expanded
|
20
|
-
rescue
|
20
|
+
rescue DNSAdapter::Error
|
21
21
|
nil
|
22
22
|
end
|
23
23
|
|
@@ -28,7 +28,11 @@ module Coppertone
|
|
28
28
|
return nil if records.size > 1
|
29
29
|
MacroString.new(records.first[:text])
|
30
30
|
end
|
31
|
+
|
32
|
+
def self.label
|
33
|
+
'exp'
|
34
|
+
end
|
31
35
|
end
|
32
|
-
register(
|
36
|
+
register(Coppertone::Modifier::Exp)
|
33
37
|
end
|
34
38
|
end
|
@@ -11,7 +11,11 @@ module Coppertone
|
|
11
11
|
request_context.register_dns_lookup_term
|
12
12
|
target_name_from_domain_spec(macro_context, request_context)
|
13
13
|
end
|
14
|
+
|
15
|
+
def self.label
|
16
|
+
'redirect'
|
17
|
+
end
|
14
18
|
end
|
15
|
-
register(
|
19
|
+
register(Coppertone::Modifier::Redirect)
|
16
20
|
end
|
17
21
|
end
|
@@ -6,11 +6,16 @@ module Coppertone
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def initialize(attributes)
|
9
|
+
super(attributes)
|
9
10
|
@macro_string = Coppertone::MacroString.new(attributes)
|
10
11
|
rescue Coppertone::MacroStringParsingError
|
11
12
|
raise Coppertone::InvalidModifierError
|
12
13
|
end
|
14
|
+
|
15
|
+
def self.label
|
16
|
+
'unknown'
|
17
|
+
end
|
13
18
|
end
|
14
|
-
register(
|
19
|
+
register(Coppertone::Modifier::Unknown)
|
15
20
|
end
|
16
21
|
end
|
data/lib/coppertone/modifier.rb
CHANGED
@@ -10,8 +10,8 @@ module Coppertone
|
|
10
10
|
class_builder.build(type, attributes)
|
11
11
|
end
|
12
12
|
|
13
|
-
def self.register(
|
14
|
-
class_builder.register(
|
13
|
+
def self.register(klass)
|
14
|
+
class_builder.register(klass.label, klass)
|
15
15
|
end
|
16
16
|
|
17
17
|
MODIFIER_REGEXP = /\A([a-zA-Z]+[a-zA-Z0-9\-\_\.]*)=(\S*)\z/
|
@@ -22,6 +22,15 @@ module Coppertone
|
|
22
22
|
attributes = matches[2]
|
23
23
|
build(type, attributes) || build('unknown', attributes)
|
24
24
|
end
|
25
|
+
|
26
|
+
attr_reader :arguments
|
27
|
+
def initialize(arguments)
|
28
|
+
@arguments = arguments
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
"#{self.class.label}=#{arguments}"
|
33
|
+
end
|
25
34
|
end
|
26
35
|
end
|
27
36
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Coppertone
|
2
|
+
# A context used to evaluate records, directives, and modifiers that do not have
|
3
|
+
# contextual dependence.
|
4
|
+
class NullMacroContext
|
5
|
+
|
6
|
+
RESERVED_REGEXP = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
|
7
|
+
%w(s l o d i p v h c r t).each do |m|
|
8
|
+
define_method(m.upcase) do
|
9
|
+
fail ArgumentError
|
10
|
+
end
|
11
|
+
|
12
|
+
define_method(m) do
|
13
|
+
fail ArgumentError
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def with_domain(new_domain)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
NULL_CONTEXT = new
|
22
|
+
end
|
23
|
+
end
|