coppertone 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|