xenon 0.0.3 → 0.0.4
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
- metadata +13 -145
- data/.codeclimate.yml +0 -18
- data/.gitignore +0 -25
- data/.rspec +0 -3
- data/.travis.yml +0 -6
- data/Gemfile +0 -13
- data/Guardfile +0 -16
- data/LICENSE +0 -22
- data/README.md +0 -86
- data/Rakefile +0 -8
- data/examples/hello_world/config.ru +0 -3
- data/examples/hello_world/hello_world.rb +0 -17
- data/lib/xenon.rb +0 -253
- data/lib/xenon/auth.rb +0 -63
- data/lib/xenon/errors.rb +0 -5
- data/lib/xenon/etag.rb +0 -48
- data/lib/xenon/headers.rb +0 -112
- data/lib/xenon/headers/accept.rb +0 -34
- data/lib/xenon/headers/accept_charset.rb +0 -59
- data/lib/xenon/headers/accept_encoding.rb +0 -63
- data/lib/xenon/headers/accept_language.rb +0 -59
- data/lib/xenon/headers/authorization.rb +0 -50
- data/lib/xenon/headers/cache_control.rb +0 -56
- data/lib/xenon/headers/content_type.rb +0 -23
- data/lib/xenon/headers/if_match.rb +0 -53
- data/lib/xenon/headers/if_modified_since.rb +0 -22
- data/lib/xenon/headers/if_none_match.rb +0 -53
- data/lib/xenon/headers/if_range.rb +0 -45
- data/lib/xenon/headers/if_unmodified_since.rb +0 -22
- data/lib/xenon/headers/user_agent.rb +0 -65
- data/lib/xenon/headers/www_authenticate.rb +0 -70
- data/lib/xenon/media_type.rb +0 -162
- data/lib/xenon/parsers/basic_rules.rb +0 -86
- data/lib/xenon/parsers/header_rules.rb +0 -60
- data/lib/xenon/parsers/media_type.rb +0 -53
- data/lib/xenon/quoted_string.rb +0 -20
- data/lib/xenon/routing/directives.rb +0 -14
- data/lib/xenon/routing/header_directives.rb +0 -32
- data/lib/xenon/routing/method_directives.rb +0 -26
- data/lib/xenon/routing/param_directives.rb +0 -22
- data/lib/xenon/routing/path_directives.rb +0 -37
- data/lib/xenon/routing/route_directives.rb +0 -51
- data/lib/xenon/routing/security_directives.rb +0 -20
- data/lib/xenon/version.rb +0 -3
- data/spec/spec_helper.rb +0 -94
- data/spec/xenon/etag_spec.rb +0 -19
- data/spec/xenon/headers/accept_charset_spec.rb +0 -31
- data/spec/xenon/headers/accept_encoding_spec.rb +0 -40
- data/spec/xenon/headers/accept_language_spec.rb +0 -33
- data/spec/xenon/headers/accept_spec.rb +0 -54
- data/spec/xenon/headers/authorization_spec.rb +0 -47
- data/spec/xenon/headers/cache_control_spec.rb +0 -64
- data/spec/xenon/headers/if_match_spec.rb +0 -73
- data/spec/xenon/headers/if_modified_since_spec.rb +0 -19
- data/spec/xenon/headers/if_none_match_spec.rb +0 -79
- data/spec/xenon/headers/if_range_spec.rb +0 -45
- data/spec/xenon/headers/if_unmodified_since_spec.rb +0 -19
- data/spec/xenon/headers/user_agent_spec.rb +0 -67
- data/spec/xenon/headers/www_authenticate_spec.rb +0 -43
- data/spec/xenon/media_type_spec.rb +0 -267
- data/xenon.gemspec +0 -30
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'base64'
|
2
|
-
require 'xenon/auth'
|
3
|
-
require 'xenon/headers'
|
4
|
-
require 'xenon/parsers/header_rules'
|
5
|
-
|
6
|
-
module Xenon
|
7
|
-
class Headers
|
8
|
-
# http://tools.ietf.org/html/rfc7235#section-4.2
|
9
|
-
class Authorization < Header 'Authorization'
|
10
|
-
attr_reader :credentials
|
11
|
-
|
12
|
-
def initialize(credentials)
|
13
|
-
@credentials = credentials
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.parse(s)
|
17
|
-
tree = Parsers::AuthorizationHeader.new.parse(s)
|
18
|
-
Parsers::AuthorizationHeaderTransform.new.apply(tree)
|
19
|
-
rescue Parslet::ParseFailed
|
20
|
-
raise Xenon::ParseError.new("Invalid Authorization header (#{s}).")
|
21
|
-
end
|
22
|
-
|
23
|
-
def to_s
|
24
|
-
@credentials.to_s
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
module Parsers
|
30
|
-
class AuthorizationHeader < Parslet::Parser
|
31
|
-
include AuthHeaderRules
|
32
|
-
rule(:credentials) { auth_scheme >> sp >> (token68 | auth_params) }
|
33
|
-
rule(:authorization) { credentials.as(:authorization) }
|
34
|
-
root(:authorization)
|
35
|
-
end
|
36
|
-
|
37
|
-
class AuthorizationHeaderTransform < HeaderTransform
|
38
|
-
rule(auth_param: { name: simple(:n), value: simple(:v) }) { [n, v] }
|
39
|
-
rule(auth_params: subtree(:x)) { { foo: x } }
|
40
|
-
rule(auth_scheme: simple(:s), token: simple(:t)) {
|
41
|
-
case s
|
42
|
-
when 'Basic' then BasicCredentials.decode(t)
|
43
|
-
else GenericCredentials.new(s, token: t)
|
44
|
-
end
|
45
|
-
}
|
46
|
-
rule(auth_scheme: simple(:s), auth_params: subtree(:p)) { GenericCredentials.new(s, params: Hash[p]) }
|
47
|
-
rule(authorization: simple(:c)) { Headers::Authorization.new(c) }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
require 'xenon/headers'
|
2
|
-
require 'xenon/parsers/header_rules'
|
3
|
-
require 'xenon/quoted_string'
|
4
|
-
|
5
|
-
module Xenon
|
6
|
-
class CacheDirective
|
7
|
-
using QuotedString
|
8
|
-
|
9
|
-
attr_reader :name, :value
|
10
|
-
|
11
|
-
def initialize(name, value = nil)
|
12
|
-
@name = name
|
13
|
-
@value = value
|
14
|
-
end
|
15
|
-
|
16
|
-
def to_s
|
17
|
-
s = @name.dup
|
18
|
-
s << '=' << @value.quote if @value
|
19
|
-
s
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Headers
|
24
|
-
# http://tools.ietf.org/html/rfc7234#section-5.2
|
25
|
-
class CacheControl < ListHeader 'Cache-Control'
|
26
|
-
def initialize(*directives)
|
27
|
-
super(directives)
|
28
|
-
end
|
29
|
-
|
30
|
-
alias_method :directives, :values
|
31
|
-
|
32
|
-
def self.parse(s)
|
33
|
-
tree = Parsers::CacheControlHeader.new.parse(s)
|
34
|
-
Parsers::CacheControlHeaderTransform.new.apply(tree)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
module Parsers
|
40
|
-
class CacheControlHeader < Parslet::Parser
|
41
|
-
include HeaderRules
|
42
|
-
rule(:name) { token.as(:name) }
|
43
|
-
rule(:value) { str('=') >> (token | quoted_string).as(:value) }
|
44
|
-
rule(:directive) { (name >> value.maybe).as(:directive) >> sp? }
|
45
|
-
rule(:cache_control) { (directive >> (list_sep >> directive).repeat).as(:cache_control) }
|
46
|
-
root(:cache_control)
|
47
|
-
end
|
48
|
-
|
49
|
-
class CacheControlHeaderTransform < HeaderTransform
|
50
|
-
rule(directive: { name: simple(:n), value: simple(:v) }) { CacheDirective.new(n, v) }
|
51
|
-
rule(directive: { name: simple(:n) }) { CacheDirective.new(n) }
|
52
|
-
rule(cache_control: sequence(:d)) { Headers::CacheControl.new(*d) }
|
53
|
-
rule(cache_control: simple(:d)) { Headers::CacheControl.new(d) }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'xenon/headers'
|
2
|
-
require 'xenon/media_type'
|
3
|
-
|
4
|
-
module Xenon
|
5
|
-
class Headers
|
6
|
-
# http://tools.ietf.org/html/rfc7231#section-3.1.1.5
|
7
|
-
class ContentType < Header 'Content-Type'
|
8
|
-
attr_reader :content_type
|
9
|
-
|
10
|
-
def initialize(content_type)
|
11
|
-
@content_type = content_type
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.parse(s)
|
15
|
-
new(Xenon::ContentType.parse(s))
|
16
|
-
end
|
17
|
-
|
18
|
-
def to_s
|
19
|
-
@content_type.to_s
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'xenon/headers'
|
2
|
-
require 'xenon/parsers/header_rules'
|
3
|
-
require 'xenon/errors'
|
4
|
-
require 'xenon/etag'
|
5
|
-
|
6
|
-
module Xenon
|
7
|
-
class Headers
|
8
|
-
# http://tools.ietf.org/html/rfc7232#section-3.1
|
9
|
-
class IfMatch < ListHeader 'If-Match'
|
10
|
-
def initialize(*etags)
|
11
|
-
super(etags)
|
12
|
-
end
|
13
|
-
|
14
|
-
alias_method :etags, :values
|
15
|
-
|
16
|
-
def self.wildcard
|
17
|
-
new
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.parse(s)
|
21
|
-
tree = Parsers::IfMatchHeader.new.parse(s)
|
22
|
-
Parsers::IfMatchHeaderTransform.new.apply(tree)
|
23
|
-
end
|
24
|
-
|
25
|
-
def wildcard?
|
26
|
-
etags.empty?
|
27
|
-
end
|
28
|
-
|
29
|
-
def merge(other)
|
30
|
-
raise Xenon::ProtocolError.new('Cannot merge wildcard headers') if wildcard? || other.wildcard?
|
31
|
-
super
|
32
|
-
end
|
33
|
-
|
34
|
-
def to_s
|
35
|
-
wildcard? ? '*' : super
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
module Parsers
|
41
|
-
class IfMatchHeader < Parslet::Parser
|
42
|
-
include ETagHeaderRules
|
43
|
-
rule(:if_match) { (wildcard | (etag >> (list_sep >> etag).repeat)).as(:if_match) }
|
44
|
-
root(:if_match)
|
45
|
-
end
|
46
|
-
|
47
|
-
class IfMatchHeaderTransform < ETagHeaderTransform
|
48
|
-
rule(if_match: { wildcard: simple(:w) }) { Headers::IfMatch.new }
|
49
|
-
rule(if_match: sequence(:et)) { Headers::IfMatch.new(*et) }
|
50
|
-
rule(if_match: simple(:et)) { Headers::IfMatch.new(et) }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'xenon/headers'
|
2
|
-
|
3
|
-
module Xenon
|
4
|
-
class Headers
|
5
|
-
# http://tools.ietf.org/html/rfc7232#section-3.3
|
6
|
-
class IfModifiedSince < Header 'If-Modified-Since'
|
7
|
-
attr_reader :date
|
8
|
-
|
9
|
-
def initialize(date)
|
10
|
-
@date = date
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.parse(s)
|
14
|
-
new(Time.httpdate(s))
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_s
|
18
|
-
@date.httpdate
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'xenon/headers'
|
2
|
-
require 'xenon/parsers/header_rules'
|
3
|
-
require 'xenon/errors'
|
4
|
-
require 'xenon/etag'
|
5
|
-
|
6
|
-
module Xenon
|
7
|
-
class Headers
|
8
|
-
# http://tools.ietf.org/html/rfc7232#section-3.2
|
9
|
-
class IfNoneMatch < ListHeader 'If-None-Match'
|
10
|
-
def initialize(*etags)
|
11
|
-
super(etags)
|
12
|
-
end
|
13
|
-
|
14
|
-
alias_method :etags, :values
|
15
|
-
|
16
|
-
def self.wildcard
|
17
|
-
new
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.parse(s)
|
21
|
-
tree = Parsers::IfNoneMatchHeader.new.parse(s)
|
22
|
-
Parsers::IfNoneMatchHeaderTransform.new.apply(tree)
|
23
|
-
end
|
24
|
-
|
25
|
-
def wildcard?
|
26
|
-
etags.empty?
|
27
|
-
end
|
28
|
-
|
29
|
-
def merge(other)
|
30
|
-
raise Xenon::ProtocolError.new('Cannot merge wildcard headers') if wildcard? || other.wildcard?
|
31
|
-
super
|
32
|
-
end
|
33
|
-
|
34
|
-
def to_s
|
35
|
-
wildcard? ? '*' : super
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
module Parsers
|
41
|
-
class IfNoneMatchHeader < Parslet::Parser
|
42
|
-
include ETagHeaderRules
|
43
|
-
rule(:if_none_match) { (wildcard | (etag >> (list_sep >> etag).repeat)).as(:if_none_match) }
|
44
|
-
root(:if_none_match)
|
45
|
-
end
|
46
|
-
|
47
|
-
class IfNoneMatchHeaderTransform < ETagHeaderTransform
|
48
|
-
rule(if_none_match: { wildcard: simple(:w) }) { Headers::IfNoneMatch.new }
|
49
|
-
rule(if_none_match: sequence(:et)) { Headers::IfNoneMatch.new(*et) }
|
50
|
-
rule(if_none_match: simple(:et)) { Headers::IfNoneMatch.new(et) }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'xenon/headers'
|
2
|
-
require 'xenon/parsers/header_rules'
|
3
|
-
require 'xenon/errors'
|
4
|
-
require 'xenon/etag'
|
5
|
-
|
6
|
-
module Xenon
|
7
|
-
class Headers
|
8
|
-
# http://tools.ietf.org/html/rfc7233#section-3.2
|
9
|
-
class IfRange < Header 'If-Range'
|
10
|
-
attr_reader :date, :etag
|
11
|
-
|
12
|
-
def initialize(value)
|
13
|
-
case value
|
14
|
-
when Time, DateTime, Date then @date = value
|
15
|
-
when ETag then @etag = value
|
16
|
-
when String then @etag = ETag.parse(value)
|
17
|
-
else raise ArgumentError, 'Value must be a time or an etag.'
|
18
|
-
end
|
19
|
-
|
20
|
-
raise ProtocolError, 'If-Range headers must use strong ETags.' if @etag && @etag.weak?
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.parse(s)
|
24
|
-
tree = Parsers::IfRangeHeader.new.parse(s)
|
25
|
-
Parsers::IfRangeHeaderTransform.new.apply(tree)
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_s
|
29
|
-
@etag ? @etag.to_s : @date.httpdate
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
module Parsers
|
35
|
-
class IfRangeHeader < Parslet::Parser
|
36
|
-
include ETagHeaderRules
|
37
|
-
rule(:if_range) { (etag | http_date).as(:if_range) }
|
38
|
-
root(:if_range)
|
39
|
-
end
|
40
|
-
|
41
|
-
class IfRangeHeaderTransform < ETagHeaderTransform
|
42
|
-
rule(if_range: simple(:v)) { Headers::IfRange.new(v) }
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'xenon/headers'
|
2
|
-
|
3
|
-
module Xenon
|
4
|
-
class Headers
|
5
|
-
# http://tools.ietf.org/html/rfc7232#section-3.4
|
6
|
-
class IfUnmodifiedSince < Header 'If-Unmodified-Since'
|
7
|
-
attr_reader :date
|
8
|
-
|
9
|
-
def initialize(date)
|
10
|
-
@date = date
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.parse(s)
|
14
|
-
new(Time.httpdate(s))
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_s
|
18
|
-
@date.httpdate
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'xenon/headers'
|
2
|
-
require 'xenon/parsers/header_rules'
|
3
|
-
|
4
|
-
module Xenon
|
5
|
-
class Product
|
6
|
-
attr_reader :name, :version, :comment
|
7
|
-
|
8
|
-
def initialize(name, version = nil, comment = nil)
|
9
|
-
@name = name
|
10
|
-
@version = version
|
11
|
-
@comment = comment
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_s
|
15
|
-
s = ''
|
16
|
-
s << @name if @name
|
17
|
-
s << '/' << @version if @version
|
18
|
-
if @comment
|
19
|
-
s << ' ' unless s.empty?
|
20
|
-
s << '(' << @comment << ')'
|
21
|
-
end
|
22
|
-
s
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
class Headers
|
27
|
-
# http://tools.ietf.org/html/rfc7231#section-5.5.3
|
28
|
-
class UserAgent < Header 'User-Agent'
|
29
|
-
attr_reader :products
|
30
|
-
|
31
|
-
def initialize(*products)
|
32
|
-
@products = products
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.parse(s)
|
36
|
-
tree = Parsers::UserAgentHeader.new.parse(s)
|
37
|
-
Parsers::UserAgentHeaderTransform.new.apply(tree)
|
38
|
-
end
|
39
|
-
|
40
|
-
def to_s
|
41
|
-
@products.map(&:to_s).join(' ')
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
module Parsers
|
47
|
-
class UserAgentHeader < Parslet::Parser
|
48
|
-
include HeaderRules
|
49
|
-
rule(:product) { (token.as(:name) >> (str('/') >> token.as(:version)).maybe >> (rws >> comment.as(:comment)).maybe).as(:product) }
|
50
|
-
rule(:product_comment) { comment.as(:product_comment) }
|
51
|
-
rule(:user_agent) { (product >> (rws >> (product | product_comment)).repeat).as(:user_agent) }
|
52
|
-
root(:user_agent)
|
53
|
-
end
|
54
|
-
|
55
|
-
class UserAgentHeaderTransform < HeaderTransform
|
56
|
-
rule(product: { name: simple(:p), version: simple(:v), comment: simple(:c) }) { Product.new(p, v, c) }
|
57
|
-
rule(product: { name: simple(:p), version: simple(:v) }) { Product.new(p, v) }
|
58
|
-
rule(product: { name: simple(:p), comment: simple(:c) }) { Product.new(p, nil, c) }
|
59
|
-
rule(product: { name: simple(:p) }) { Product.new(p) }
|
60
|
-
rule(product_comment: simple(:c)) { Product.new(nil, nil, c) }
|
61
|
-
rule(user_agent: sequence(:p)) { Headers::UserAgent.new(*p) }
|
62
|
-
rule(user_agent: simple(:p)) { Headers::UserAgent.new(p) }
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
-
require 'xenon/headers'
|
3
|
-
require 'xenon/parsers/header_rules'
|
4
|
-
require 'xenon/quoted_string'
|
5
|
-
|
6
|
-
module Xenon
|
7
|
-
class Headers
|
8
|
-
class Challenge
|
9
|
-
extend Forwardable
|
10
|
-
using QuotedString
|
11
|
-
|
12
|
-
attr_reader :auth_scheme
|
13
|
-
def_delegators :@params, :key?, :include?, :[]
|
14
|
-
|
15
|
-
def initialize(auth_scheme, params = {})
|
16
|
-
@auth_scheme = auth_scheme
|
17
|
-
@params = params.with_indifferent_access
|
18
|
-
end
|
19
|
-
|
20
|
-
def method_missing(name, *args, &block)
|
21
|
-
name = name.to_sym
|
22
|
-
@params.key?(name) ? @params[name] : super
|
23
|
-
end
|
24
|
-
|
25
|
-
def respond_to_missing?(name, include_all)
|
26
|
-
@params.key?(name.to_sym) || super
|
27
|
-
end
|
28
|
-
|
29
|
-
def to_s
|
30
|
-
param_string = @params.map { |k, v| "#{k}=#{v.quote}"}.join(', ')
|
31
|
-
"#{@auth_scheme} #{param_string}"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# https://tools.ietf.org/html/rfc7235#section-4.1
|
36
|
-
class WWWAuthenticate < ListHeader 'WWW-Authenticate'
|
37
|
-
def initialize(*challenges)
|
38
|
-
super(challenges)
|
39
|
-
end
|
40
|
-
|
41
|
-
alias_method :challenges, :values
|
42
|
-
|
43
|
-
def self.parse(s)
|
44
|
-
tree = Parsers::WWWAuthenticateHeader.new.parse(s)
|
45
|
-
Parsers::WWWAuthenticateHeaderTransform.new.apply(tree)
|
46
|
-
end
|
47
|
-
|
48
|
-
def to_s
|
49
|
-
challenges.map(&:to_s).join(', ')
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
module Parsers
|
55
|
-
class WWWAuthenticateHeader < Parslet::Parser
|
56
|
-
include AuthHeaderRules
|
57
|
-
rule(:challenge) { (auth_scheme >> sp >> (auth_params | token68)).as(:challenge) }
|
58
|
-
rule(:www_authenticate) { (challenge >> (comma >> challenge).repeat).as(:www_authenticate) }
|
59
|
-
root(:www_authenticate)
|
60
|
-
end
|
61
|
-
|
62
|
-
class WWWAuthenticateHeaderTransform < HeaderTransform
|
63
|
-
rule(auth_param: { name: simple(:n), value: simple(:v) }) { Tuple.new(n, v) }
|
64
|
-
rule(challenge: { auth_scheme: simple(:s), auth_params: simple(:p) }) { Headers::Challenge.new(s, Hash[*p.to_a]) }
|
65
|
-
rule(challenge: { auth_scheme: simple(:s), auth_params: sequence(:p) }) { Headers::Challenge.new(s, Hash[p.map(&:to_a)]) }
|
66
|
-
rule(www_authenticate: simple(:c)) { Headers::WWWAuthenticate.new(c) }
|
67
|
-
rule(www_authenticate: sequence(:c)) { Headers::WWWAuthenticate.new(*c) }
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|