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,64 +0,0 @@
|
|
1
|
-
require 'xenon/headers/cache_control'
|
2
|
-
|
3
|
-
describe Xenon::Headers::CacheControl do
|
4
|
-
|
5
|
-
context '::parse' do
|
6
|
-
['max-age', 'max-stale', 'min-fresh', 's-maxage'].each do |dir|
|
7
|
-
it "can parse the #{dir} directive" do
|
8
|
-
header = Xenon::Headers::CacheControl.parse("#{dir}=5")
|
9
|
-
expect(header.directives.size).to eq(1)
|
10
|
-
expect(header.directives[0].to_s).to eq("#{dir}=5")
|
11
|
-
end
|
12
|
-
|
13
|
-
it "can parse the #{dir} directive with a quoted value" do # should not be sent by clients but is permitted
|
14
|
-
header = Xenon::Headers::CacheControl.parse("#{dir}=\"5\"")
|
15
|
-
expect(header.directives.size).to eq(1)
|
16
|
-
expect(header.directives[0].to_s).to eq("#{dir}=5")
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
['no-cache', 'no-store', 'no-transform', 'only-if-cached', 'must-revalidate', 'public', 'proxy-revalidate'].each do |dir|
|
21
|
-
it "can parse the #{dir} directive" do
|
22
|
-
header = Xenon::Headers::CacheControl.parse("#{dir}")
|
23
|
-
expect(header.directives.size).to eq(1)
|
24
|
-
expect(header.directives[0].to_s).to eq("#{dir}")
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
it "can parse the private directive with no field names" do
|
29
|
-
header = Xenon::Headers::CacheControl.parse('private')
|
30
|
-
expect(header.directives.size).to eq(1)
|
31
|
-
expect(header.directives[0].to_s).to eq('private')
|
32
|
-
end
|
33
|
-
|
34
|
-
# TODO: private directive with field names
|
35
|
-
|
36
|
-
it 'can parse extension directives with quoted string values' do
|
37
|
-
header = Xenon::Headers::CacheControl.parse('ext="hello \"world\""')
|
38
|
-
expect(header.directives.size).to eq(1)
|
39
|
-
expect(header.directives[0].name).to eq('ext')
|
40
|
-
expect(header.directives[0].value).to eq("hello \"world\"")
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'can parse more complex directives' do
|
44
|
-
header = Xenon::Headers::CacheControl.parse('public, max-age=3600, must-revalidate')
|
45
|
-
expect(header.directives.size).to eq(3)
|
46
|
-
expect(header.directives[0].to_s).to eq('public')
|
47
|
-
expect(header.directives[1].to_s).to eq('max-age=3600')
|
48
|
-
expect(header.directives[2].to_s).to eq('must-revalidate')
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context '#merge' do
|
53
|
-
it 'can merge two headers and maintain directive order' do
|
54
|
-
h1 = Xenon::Headers::CacheControl.parse('public, max-age=3600')
|
55
|
-
h2 = Xenon::Headers::CacheControl.parse('must-revalidate')
|
56
|
-
header = h1.merge(h2)
|
57
|
-
expect(header.directives.size).to eq(3)
|
58
|
-
expect(header.directives[0].to_s).to eq('public')
|
59
|
-
expect(header.directives[1].to_s).to eq('max-age=3600')
|
60
|
-
expect(header.directives[2].to_s).to eq('must-revalidate')
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
require 'xenon/headers/if_match'
|
2
|
-
|
3
|
-
describe Xenon::Headers::IfMatch do
|
4
|
-
|
5
|
-
context '::parse' do
|
6
|
-
it 'can parse a single etag' do
|
7
|
-
header = Xenon::Headers::IfMatch.parse('"xyzzy"')
|
8
|
-
expect(header.etags.size).to eq(1)
|
9
|
-
expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'can parse multiple etags' do
|
13
|
-
header = Xenon::Headers::IfMatch.parse('"xyzzy", "r2d2xxxx", "c3piozzzz"')
|
14
|
-
expect(header.etags.size).to eq(3)
|
15
|
-
expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
|
16
|
-
expect(header.etags[1]).to eq(Xenon::ETag.new('r2d2xxxx'))
|
17
|
-
expect(header.etags[2]).to eq(Xenon::ETag.new('c3piozzzz'))
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'can parse a wildcard header' do
|
21
|
-
header = Xenon::Headers::IfMatch.parse('*')
|
22
|
-
expect(header.etags.size).to eq(0)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context '#merge' do
|
27
|
-
it 'can merge two headers and maintain etag order' do
|
28
|
-
h1 = Xenon::Headers::IfMatch.parse('"xyzzy", "r2d2xxxx"')
|
29
|
-
h2 = Xenon::Headers::IfMatch.parse('"c3piozzzz"')
|
30
|
-
header = h1.merge(h2)
|
31
|
-
expect(header.etags.size).to eq(3)
|
32
|
-
expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
|
33
|
-
expect(header.etags[1]).to eq(Xenon::ETag.new('r2d2xxxx'))
|
34
|
-
expect(header.etags[2]).to eq(Xenon::ETag.new('c3piozzzz'))
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'raises a protocol error when trying to merge into a wildcard header' do
|
38
|
-
h1 = Xenon::Headers::IfMatch.parse('*')
|
39
|
-
h2 = Xenon::Headers::IfMatch.parse('"c3piozzzz"')
|
40
|
-
expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'raises a protocol error when trying to merge a wildcard into a header' do
|
44
|
-
h1 = Xenon::Headers::IfMatch.parse('"xyzzy"')
|
45
|
-
h2 = Xenon::Headers::IfMatch.parse('*')
|
46
|
-
expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'raises a protocol error when trying to merge two wildcard headers' do
|
50
|
-
h1 = Xenon::Headers::IfMatch.parse('*')
|
51
|
-
h2 = Xenon::Headers::IfMatch.parse('*')
|
52
|
-
expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context '#to_s' do
|
57
|
-
it 'returns the string representation a single etag' do
|
58
|
-
header = Xenon::Headers::IfMatch.parse('"xyzzy"')
|
59
|
-
expect(header.to_s).to eq('"xyzzy"')
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'returns the string representation of multiple etags' do
|
63
|
-
header = Xenon::Headers::IfMatch.parse('"xyzzy", "r2d2xxxx", "c3piozzzz"')
|
64
|
-
expect(header.to_s).to eq('"xyzzy", "r2d2xxxx", "c3piozzzz"')
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'returns the string representation of a wildcard header' do
|
68
|
-
header = Xenon::Headers::IfMatch.wildcard
|
69
|
-
expect(header.to_s).to eq('*')
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'xenon/headers/if_modified_since'
|
2
|
-
|
3
|
-
describe Xenon::Headers::IfModifiedSince do
|
4
|
-
|
5
|
-
context '::parse' do
|
6
|
-
it 'can parse an http date' do
|
7
|
-
header = Xenon::Headers::IfModifiedSince.parse('Sat, 29 Oct 1994 19:43:31 GMT')
|
8
|
-
expect(header.date).to eq(Time.utc(1994, 10, 29, 19, 43, 31))
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
context '#to_s' do
|
13
|
-
it 'returns the http date format' do
|
14
|
-
header = Xenon::Headers::IfModifiedSince.new(Time.utc(1994, 10, 29, 19, 43, 31))
|
15
|
-
expect(header.to_s).to eq('Sat, 29 Oct 1994 19:43:31 GMT')
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'xenon/headers/if_none_match'
|
2
|
-
|
3
|
-
describe Xenon::Headers::IfNoneMatch do
|
4
|
-
|
5
|
-
context '::parse' do
|
6
|
-
it 'can parse a single strong etag' do
|
7
|
-
header = Xenon::Headers::IfNoneMatch.parse('"xyzzy"')
|
8
|
-
expect(header.etags.size).to eq(1)
|
9
|
-
expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'can parse a single weak etag' do
|
13
|
-
header = Xenon::Headers::IfNoneMatch.parse('W/"xyzzy"')
|
14
|
-
expect(header.etags.size).to eq(1)
|
15
|
-
expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy', weak: true))
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'can parse multiple etags' do
|
19
|
-
header = Xenon::Headers::IfNoneMatch.parse('"xyzzy", W/"r2d2xxxx", "c3piozzzz"')
|
20
|
-
expect(header.etags.size).to eq(3)
|
21
|
-
expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
|
22
|
-
expect(header.etags[1]).to eq(Xenon::ETag.new('r2d2xxxx', weak: true))
|
23
|
-
expect(header.etags[2]).to eq(Xenon::ETag.new('c3piozzzz'))
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'can parse a wildcard header' do
|
27
|
-
header = Xenon::Headers::IfNoneMatch.parse('*')
|
28
|
-
expect(header.etags.size).to eq(0)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context '#merge' do
|
33
|
-
it 'can merge two headers and maintain etag order' do
|
34
|
-
h1 = Xenon::Headers::IfNoneMatch.parse('"xyzzy", W/"r2d2xxxx"')
|
35
|
-
h2 = Xenon::Headers::IfNoneMatch.parse('"c3piozzzz"')
|
36
|
-
header = h1.merge(h2)
|
37
|
-
expect(header.etags.size).to eq(3)
|
38
|
-
expect(header.etags[0]).to eq(Xenon::ETag.new('xyzzy'))
|
39
|
-
expect(header.etags[1]).to eq(Xenon::ETag.new('r2d2xxxx', weak: true))
|
40
|
-
expect(header.etags[2]).to eq(Xenon::ETag.new('c3piozzzz'))
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'raises a protocol error when trying to merge into a wildcard header' do
|
44
|
-
h1 = Xenon::Headers::IfNoneMatch.parse('*')
|
45
|
-
h2 = Xenon::Headers::IfNoneMatch.parse('"c3piozzzz"')
|
46
|
-
expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'raises a protocol error when trying to merge a wildcard into a header' do
|
50
|
-
h1 = Xenon::Headers::IfNoneMatch.parse('"xyzzy"')
|
51
|
-
h2 = Xenon::Headers::IfNoneMatch.parse('*')
|
52
|
-
expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
|
53
|
-
end
|
54
|
-
|
55
|
-
it 'raises a protocol error when trying to merge two wildcard headers' do
|
56
|
-
h1 = Xenon::Headers::IfNoneMatch.parse('*')
|
57
|
-
h2 = Xenon::Headers::IfNoneMatch.parse('*')
|
58
|
-
expect { h1.merge(h2) }.to raise_error(Xenon::ProtocolError)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
context '#to_s' do
|
63
|
-
it 'returns the string representation a single etag' do
|
64
|
-
header = Xenon::Headers::IfNoneMatch.parse('"xyzzy"')
|
65
|
-
expect(header.to_s).to eq('"xyzzy"')
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'returns the string representation of multiple etags' do
|
69
|
-
header = Xenon::Headers::IfNoneMatch.parse('"xyzzy", W/"r2d2xxxx", "c3piozzzz"')
|
70
|
-
expect(header.to_s).to eq('"xyzzy", W/"r2d2xxxx", "c3piozzzz"')
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'returns the string representation of a wildcard header' do
|
74
|
-
header = Xenon::Headers::IfNoneMatch.wildcard
|
75
|
-
expect(header.to_s).to eq('*')
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'xenon/headers/if_range'
|
2
|
-
|
3
|
-
describe Xenon::Headers::IfRange do
|
4
|
-
|
5
|
-
context '::parse' do
|
6
|
-
it 'can parse an http date' do
|
7
|
-
header = Xenon::Headers::IfRange.parse('Sat, 29 Oct 1994 19:43:31 GMT')
|
8
|
-
expect(header.date).to eq(Time.utc(1994, 10, 29, 19, 43, 31))
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'can parse an obsolete RFC 850 date' do
|
12
|
-
header = Xenon::Headers::IfRange.parse('Sunday, 06-Nov-94 08:49:37 GMT')
|
13
|
-
expect(header.date).to eq(Time.utc(1994, 11, 6, 8, 49, 37))
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'can parse an obsolete asctime date' do
|
17
|
-
header = Xenon::Headers::IfRange.parse('Sun Nov 6 08:49:37 1994')
|
18
|
-
expect(header.date).to eq(Time.utc(1994, 11, 6, 8, 49, 37))
|
19
|
-
end
|
20
|
-
|
21
|
-
it 'can parse a strong etag' do
|
22
|
-
header = Xenon::Headers::IfRange.parse('"xyzzy"')
|
23
|
-
expect(header.etag).to_not be_nil
|
24
|
-
expect(header.etag.opaque_tag).to eq 'xyzzy'
|
25
|
-
expect(header.etag).to be_strong
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should raise a ProtocolError if the etag is weak' do
|
29
|
-
expect { Xenon::Headers::IfRange.parse('W/"xyzzy"') }.to raise_error Xenon::ProtocolError
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context '#to_s' do
|
34
|
-
it 'returns the http date format for dates' do
|
35
|
-
header = Xenon::Headers::IfRange.new(Time.utc(1994, 10, 29, 19, 43, 31))
|
36
|
-
expect(header.to_s).to eq('Sat, 29 Oct 1994 19:43:31 GMT')
|
37
|
-
end
|
38
|
-
|
39
|
-
it 'returns the etag format for etags' do
|
40
|
-
header = Xenon::Headers::IfRange.new(Xenon::ETag.new('xyzzy'))
|
41
|
-
expect(header.to_s).to eq('"xyzzy"')
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
require 'xenon/headers/if_unmodified_since'
|
2
|
-
|
3
|
-
describe Xenon::Headers::IfUnmodifiedSince do
|
4
|
-
|
5
|
-
context '::parse' do
|
6
|
-
it 'can parse an http date' do
|
7
|
-
header = Xenon::Headers::IfUnmodifiedSince.parse('Sat, 29 Oct 1994 19:43:31 GMT')
|
8
|
-
expect(header.date).to eq(Time.utc(1994, 10, 29, 19, 43, 31))
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
context '#to_s' do
|
13
|
-
it 'returns the http date format' do
|
14
|
-
header = Xenon::Headers::IfUnmodifiedSince.new(Time.utc(1994, 10, 29, 19, 43, 31))
|
15
|
-
expect(header.to_s).to eq('Sat, 29 Oct 1994 19:43:31 GMT')
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
require 'xenon/headers/user_agent'
|
2
|
-
|
3
|
-
describe Xenon::Headers::UserAgent do
|
4
|
-
|
5
|
-
context '::parse' do
|
6
|
-
it 'can parse a user agent with a product name' do
|
7
|
-
header = Xenon::Headers::UserAgent.parse('Mozilla')
|
8
|
-
expect(header.products.size).to eq(1)
|
9
|
-
expect(header.products[0].name).to eq('Mozilla')
|
10
|
-
expect(header.products[0].version).to be_nil
|
11
|
-
expect(header.products[0].comment).to be_nil
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'can parse a user agent with a product name and version' do
|
15
|
-
header = Xenon::Headers::UserAgent.parse('Mozilla/5.0')
|
16
|
-
expect(header.products.size).to eq(1)
|
17
|
-
expect(header.products[0].name).to eq('Mozilla')
|
18
|
-
expect(header.products[0].version).to eq('5.0')
|
19
|
-
expect(header.products[0].comment).to be_nil
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'can parse a user agent with a product name and comment' do
|
23
|
-
header = Xenon::Headers::UserAgent.parse('Mozilla (Macintosh; Intel Mac OS X 10_10_2)')
|
24
|
-
expect(header.products.size).to eq(1)
|
25
|
-
expect(header.products[0].name).to eq('Mozilla')
|
26
|
-
expect(header.products[0].version).to be_nil
|
27
|
-
expect(header.products[0].comment).to eq('Macintosh; Intel Mac OS X 10_10_2')
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'can parse a user agent with a product name, version and comment' do
|
31
|
-
header = Xenon::Headers::UserAgent.parse('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2)')
|
32
|
-
expect(header.products.size).to eq(1)
|
33
|
-
expect(header.products[0].name).to eq('Mozilla')
|
34
|
-
expect(header.products[0].version).to eq('5.0')
|
35
|
-
expect(header.products[0].comment).to eq('Macintosh; Intel Mac OS X 10_10_2')
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'can parse a user agent with multiple comments' do
|
39
|
-
header = Xenon::Headers::UserAgent.parse('Mozilla/5.0 (Macintosh) (Intel Mac OS X 10_10_2)')
|
40
|
-
expect(header.products.size).to eq(2)
|
41
|
-
expect(header.products[0].name).to eq('Mozilla')
|
42
|
-
expect(header.products[0].version).to eq('5.0')
|
43
|
-
expect(header.products[0].comment).to eq('Macintosh')
|
44
|
-
expect(header.products[1].name).to be_nil
|
45
|
-
expect(header.products[1].version).to be_nil
|
46
|
-
expect(header.products[1].comment).to eq('Intel Mac OS X 10_10_2')
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'can parse a typical Chrome user agent' do
|
50
|
-
header = Xenon::Headers::UserAgent.parse('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36')
|
51
|
-
expect(header.products.size).to eq(4)
|
52
|
-
expect(header.products[0].name).to eq('Mozilla')
|
53
|
-
expect(header.products[0].version).to eq('5.0')
|
54
|
-
expect(header.products[0].comment).to eq('Macintosh; Intel Mac OS X 10_10_2')
|
55
|
-
expect(header.products[1].name).to eq('AppleWebKit')
|
56
|
-
expect(header.products[1].version).to eq('537.36')
|
57
|
-
expect(header.products[1].comment).to eq('KHTML, like Gecko')
|
58
|
-
expect(header.products[2].name).to eq('Chrome')
|
59
|
-
expect(header.products[2].version).to eq('41.0.2272.89')
|
60
|
-
expect(header.products[2].comment).to be_nil
|
61
|
-
expect(header.products[3].name).to eq('Safari')
|
62
|
-
expect(header.products[3].version).to eq('537.36')
|
63
|
-
expect(header.products[3].comment).to be_nil
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'xenon/headers/www_authenticate'
|
2
|
-
|
3
|
-
describe Xenon::Headers::WWWAuthenticate do
|
4
|
-
|
5
|
-
context '::parse' do
|
6
|
-
|
7
|
-
it 'can parse a Basic challenge with a realm' do
|
8
|
-
header = Xenon::Headers::WWWAuthenticate.parse('Basic realm="simple"')
|
9
|
-
expect(header.challenges.size).to eq(1)
|
10
|
-
expect(header.challenges[0].auth_scheme).to eq('Basic')
|
11
|
-
expect(header.challenges[0].realm).to eq('simple')
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'can parse a Digest challenge with a realm' do
|
15
|
-
header = Xenon::Headers::WWWAuthenticate.parse('Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"')
|
16
|
-
expect(header.challenges.size).to eq(1)
|
17
|
-
expect(header.challenges[0].auth_scheme).to eq('Digest')
|
18
|
-
expect(header.challenges[0].realm).to eq('testrealm@host.com')
|
19
|
-
expect(header.challenges[0].qop).to eq('auth,auth-int')
|
20
|
-
expect(header.challenges[0].nonce).to eq('dcd98b7102dd2f0e8b11d0f600bfb0c093')
|
21
|
-
expect(header.challenges[0].opaque).to eq('5ccc069c403ebaf9f0171e9517f40e41')
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'can parse a custom challenge' do
|
25
|
-
header = Xenon::Headers::WWWAuthenticate.parse('Newauth realm="apps", type=1, title="Login to \"apps\""')
|
26
|
-
expect(header.challenges.size).to eq(1)
|
27
|
-
expect(header.challenges[0].auth_scheme).to eq('Newauth')
|
28
|
-
expect(header.challenges[0].realm).to eq('apps')
|
29
|
-
expect(header.challenges[0].type).to eq('1')
|
30
|
-
expect(header.challenges[0].title).to eq('Login to "apps"')
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'can parse multiple challenges' do
|
34
|
-
header = Xenon::Headers::WWWAuthenticate.parse('Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41", Basic realm="simple", Newauth realm="apps", type=1, title="Login to \"apps\""')
|
35
|
-
expect(header.challenges.size).to eq(3)
|
36
|
-
expect(header.challenges[0].auth_scheme).to eq('Digest')
|
37
|
-
expect(header.challenges[1].auth_scheme).to eq('Basic')
|
38
|
-
expect(header.challenges[2].auth_scheme).to eq('Newauth')
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
end
|
43
|
-
end
|
@@ -1,267 +0,0 @@
|
|
1
|
-
require 'xenon/media_type'
|
2
|
-
|
3
|
-
describe Xenon::MediaType do
|
4
|
-
|
5
|
-
context '::parse' do
|
6
|
-
it 'can parse basic media types' do
|
7
|
-
mt = Xenon::MediaType.parse('application/json')
|
8
|
-
expect(mt.type).to eq('application')
|
9
|
-
expect(mt.subtype).to eq('json')
|
10
|
-
end
|
11
|
-
it 'can parse media types with a subtype suffix' do
|
12
|
-
mt = Xenon::MediaType.parse('application/rss+xml')
|
13
|
-
expect(mt.type).to eq('application')
|
14
|
-
expect(mt.subtype).to eq('rss+xml')
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'can parse media types with parameters' do
|
18
|
-
mt = Xenon::MediaType.parse('text/plain; format=flowed; paged')
|
19
|
-
expect(mt.type).to eq('text')
|
20
|
-
expect(mt.subtype).to eq('plain')
|
21
|
-
expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'strips whitespace around separators' do
|
25
|
-
mt = Xenon::MediaType.parse('text/plain ; format = flowed ; paged')
|
26
|
-
expect(mt.type).to eq('text')
|
27
|
-
expect(mt.subtype).to eq('plain')
|
28
|
-
expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'raises an error when the media type contains wildcards' do
|
32
|
-
expect { Xenon::MediaType.parse('*/*') }.to raise_error(Xenon::ParseError)
|
33
|
-
expect { Xenon::MediaType.parse('application/*') }.to raise_error(Xenon::ParseError)
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'raises an error when the media type is invalid' do
|
37
|
-
expect { Xenon::MediaType.parse('application') }.to raise_error(Xenon::ParseError)
|
38
|
-
expect { Xenon::MediaType.parse('application; foo=bar') }.to raise_error(Xenon::ParseError)
|
39
|
-
expect { Xenon::MediaType.parse('/json') }.to raise_error(Xenon::ParseError)
|
40
|
-
expect { Xenon::MediaType.parse('/json; foo=bar') }.to raise_error(Xenon::ParseError)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
%w(application audio image message multipart text video).each do |type|
|
45
|
-
context "#{type}?" do
|
46
|
-
it "returns true when the root type is '#{type}'" do
|
47
|
-
mt = Xenon::MediaType.new(type, 'dummy')
|
48
|
-
expect(mt.send("#{type}?")).to eq(true)
|
49
|
-
end
|
50
|
-
|
51
|
-
it "returns false when the root type is not '#{type}'" do
|
52
|
-
mt = Xenon::MediaType.new('dummy', 'dummy')
|
53
|
-
expect(mt.send("#{type}?")).to eq(false)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
{ experimental?: 'x', personal?: 'prs', vendor?: 'vnd' }.each do |method, prefix|
|
59
|
-
context method do
|
60
|
-
it "returns true when the subtype starts with '#{prefix}.'" do
|
61
|
-
mt = Xenon::MediaType.new('application', "#{prefix}.dummy")
|
62
|
-
expect(mt.send(method)).to eq(true)
|
63
|
-
end
|
64
|
-
|
65
|
-
it "returns false when the subtype does not start with '#{prefix}.'" do
|
66
|
-
mt = Xenon::MediaType.new('application', "dummy.dummy")
|
67
|
-
expect(mt.send(method)).to eq(false)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
%w(ber der fastinfoset json wbxml xml zip).each do |format|
|
73
|
-
context "#{format}?" do
|
74
|
-
it "returns true when the subtype is '#{format}'" do
|
75
|
-
mt = Xenon::MediaType.new('application', format)
|
76
|
-
expect(mt.send("#{format}?")).to eq(true)
|
77
|
-
end
|
78
|
-
|
79
|
-
it "returns true when the subtype ends with '+#{format}'" do
|
80
|
-
mt = Xenon::MediaType.new('application', "dummy+#{format}")
|
81
|
-
expect(mt.send("#{format}?")).to eq(true)
|
82
|
-
end
|
83
|
-
|
84
|
-
it "returns false when the subtype is not '#{format}' and does not end with '+#{format}'" do
|
85
|
-
mt = Xenon::MediaType.new('dummy', 'dummy+dummy')
|
86
|
-
expect(mt.send("#{format}?")).to eq(false)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
context '#to_s' do
|
92
|
-
it 'returns the string representation of a media type' do
|
93
|
-
mt = Xenon::MediaType.new('text', 'plain', 'format' => 'flowed', 'paged' => nil)
|
94
|
-
expect(mt.to_s).to eq('text/plain; format=flowed; paged')
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|
99
|
-
|
100
|
-
describe Xenon::MediaRange do
|
101
|
-
|
102
|
-
context '::parse' do
|
103
|
-
it 'can parse basic media ranges' do
|
104
|
-
mt = Xenon::MediaRange.parse('application/json')
|
105
|
-
expect(mt.type).to eq('application')
|
106
|
-
expect(mt.subtype).to eq('json')
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'can parse media ranges with parameters' do
|
110
|
-
mt = Xenon::MediaRange.parse('text/plain; format=flowed; paged')
|
111
|
-
expect(mt.type).to eq('text')
|
112
|
-
expect(mt.subtype).to eq('plain')
|
113
|
-
expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'strips whitespace around separators' do
|
117
|
-
mt = Xenon::MediaRange.parse('text/plain ; format = flowed ; paged')
|
118
|
-
expect(mt.type).to eq('text')
|
119
|
-
expect(mt.subtype).to eq('plain')
|
120
|
-
expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'can parse media ranges with subtype wildcards' do
|
124
|
-
mt = Xenon::MediaRange.parse('application/*')
|
125
|
-
expect(mt.type).to eq('application')
|
126
|
-
expect(mt.subtype).to eq('*')
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'can parse media ranges with type and subtype wildcards' do
|
130
|
-
mt = Xenon::MediaRange.parse('*/*')
|
131
|
-
expect(mt.type).to eq('*')
|
132
|
-
expect(mt.subtype).to eq('*')
|
133
|
-
end
|
134
|
-
|
135
|
-
it 'extracts q from the parameters' do
|
136
|
-
mt = Xenon::MediaRange.parse('text/plain; q=0.8; format=flowed; paged')
|
137
|
-
expect(mt.type).to eq('text')
|
138
|
-
expect(mt.subtype).to eq('plain')
|
139
|
-
expect(mt.q).to eq(0.8)
|
140
|
-
expect(mt.params).to eq({ 'format' => 'flowed', 'paged' => nil })
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'uses the default value for q if the value is not numeric' do
|
144
|
-
mt = Xenon::MediaRange.parse('application/json; q=foo')
|
145
|
-
expect(mt.type).to eq('application')
|
146
|
-
expect(mt.subtype).to eq('json')
|
147
|
-
expect(mt.q).to eq(Xenon::MediaRange::DEFAULT_Q)
|
148
|
-
end
|
149
|
-
|
150
|
-
it 'raises an error when the media range is invalid' do
|
151
|
-
expect { Xenon::MediaRange.parse('application') }.to raise_error(Xenon::ParseError)
|
152
|
-
expect { Xenon::MediaRange.parse('application; foo=bar') }.to raise_error(Xenon::ParseError)
|
153
|
-
expect { Xenon::MediaRange.parse('*/json') }.to raise_error(Xenon::ParseError)
|
154
|
-
expect { Xenon::MediaRange.parse('/json') }.to raise_error(Xenon::ParseError)
|
155
|
-
expect { Xenon::MediaRange.parse('/json; foo=bar') }.to raise_error(Xenon::ParseError)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
context '#<=>' do
|
160
|
-
it 'considers a wildcard type less than a regular type' do
|
161
|
-
mr1 = Xenon::MediaRange.new('*', '*')
|
162
|
-
mr2 = Xenon::MediaRange.new('text', '*')
|
163
|
-
expect(mr1 <=> mr2).to eq(-1)
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'considers a wildcard subtype less than a regular subtype' do
|
167
|
-
mr1 = Xenon::MediaRange.new('application', '*')
|
168
|
-
mr2 = Xenon::MediaRange.new('text', 'plain')
|
169
|
-
expect(mr1 <=> mr2).to eq(-1)
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'considers media ranges with type and subtype equal' do
|
173
|
-
mr1 = Xenon::MediaRange.new('application', 'json')
|
174
|
-
mr2 = Xenon::MediaRange.new('text', 'plain')
|
175
|
-
expect(mr1 <=> mr2).to eq(0)
|
176
|
-
end
|
177
|
-
|
178
|
-
it 'considers a media range with parameters greater than one without' do
|
179
|
-
mr1 = Xenon::MediaRange.new('text', 'plain', 'format' => 'flowed')
|
180
|
-
mr2 = Xenon::MediaRange.new('text', 'plain')
|
181
|
-
expect(mr1 <=> mr2).to eq(1)
|
182
|
-
end
|
183
|
-
|
184
|
-
it 'does not consider the quality when one media range is more specific' do
|
185
|
-
mr1 = Xenon::MediaRange.new('application', '*', 'q' => '0.3')
|
186
|
-
mr2 = Xenon::MediaRange.new('*', '*', 'q' => '0.5')
|
187
|
-
expect(mr1 <=> mr2).to eq(1)
|
188
|
-
end
|
189
|
-
|
190
|
-
it 'considers the quality when media ranges are equally specific' do
|
191
|
-
mr1 = Xenon::MediaRange.new('application', 'json', 'q' => '0.8')
|
192
|
-
mr2 = Xenon::MediaRange.new('application', 'xml')
|
193
|
-
expect(mr1 <=> mr2).to eq(-1)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
%i(=~ ===).each do |name|
|
198
|
-
context "##{name}" do
|
199
|
-
it 'returns true when the type and subtype are wildcards' do
|
200
|
-
mr = Xenon::MediaRange.new('*', '*')
|
201
|
-
mt = Xenon::MediaType.new('application', 'json')
|
202
|
-
expect(mr.send(name, mt)).to eq(true)
|
203
|
-
end
|
204
|
-
|
205
|
-
it 'returns true when the type matches and subtype is a wildcard' do
|
206
|
-
mr = Xenon::MediaRange.new('application', '*')
|
207
|
-
mt = Xenon::MediaType.new('application', 'json')
|
208
|
-
expect(mr.send(name, mt)).to eq(true)
|
209
|
-
end
|
210
|
-
|
211
|
-
it 'returns true when the type and subtype match exactly' do
|
212
|
-
mr = Xenon::MediaRange.new('application', 'json')
|
213
|
-
mt = Xenon::MediaType.new('application', 'json')
|
214
|
-
expect(mr.send(name, mt)).to eq(true)
|
215
|
-
end
|
216
|
-
|
217
|
-
it 'returns true when the type, subtype and parameters match exactly' do
|
218
|
-
mr = Xenon::MediaRange.new('text', 'plain', 'format' => 'flowed')
|
219
|
-
mt = Xenon::MediaType.new('text', 'plain', 'format' => 'flowed', 'paged' => nil)
|
220
|
-
expect(mr.send(name, mt)).to eq(true)
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'returns true when the the media type has more specific parameters' do
|
224
|
-
mr = Xenon::MediaRange.new('text', 'plain')
|
225
|
-
mt = Xenon::MediaType.new('text', 'plain', 'format' => 'flowed', 'paged' => nil)
|
226
|
-
expect(mr.send(name, mt)).to eq(true)
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'returns false when the type is different' do
|
230
|
-
mr = Xenon::MediaRange.new('text', 'json')
|
231
|
-
mt = Xenon::MediaType.new('application', 'json')
|
232
|
-
expect(mr.send(name, mt)).to eq(false)
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'returns false when the type matches but subtype is different' do
|
236
|
-
mr = Xenon::MediaRange.new('application', 'xml')
|
237
|
-
mt = Xenon::MediaType.new('application', 'json')
|
238
|
-
expect(mr.send(name, mt)).to eq(false)
|
239
|
-
end
|
240
|
-
|
241
|
-
it 'returns false when the media range has more specific parameters' do
|
242
|
-
mr = Xenon::MediaRange.new('text', 'plain', 'format' => 'flowed', 'paged' => nil)
|
243
|
-
mt = Xenon::MediaType.new('text', 'plain')
|
244
|
-
expect(mr.send(name, mt)).to eq(false)
|
245
|
-
end
|
246
|
-
|
247
|
-
it 'returns false when the media range has a different parameter value' do
|
248
|
-
mr = Xenon::MediaRange.new('text', 'plain', 'format' => 'flowed')
|
249
|
-
mt = Xenon::MediaType.new('text', 'plain', 'format' => 'linear')
|
250
|
-
expect(mr.send(name, mt)).to eq(false)
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
context '#to_s' do
|
256
|
-
it 'returns the string representation of a media range' do
|
257
|
-
mt = Xenon::MediaRange.new('text', 'plain', 'q' => 0.8, 'format' => 'flowed', 'paged' => nil)
|
258
|
-
expect(mt.to_s).to eq('text/plain; format=flowed; paged; q=0.8')
|
259
|
-
end
|
260
|
-
|
261
|
-
it 'omits the q parameter when it is 1.0' do
|
262
|
-
mt = Xenon::MediaRange.new('application', 'json', 'q' => 1.0)
|
263
|
-
expect(mt.to_s).to eq('application/json')
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
end
|