accept_headers 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/CHANGELOG.md +5 -1
- data/Gemfile +2 -2
- data/README.md +86 -31
- data/accept_headers.gemspec +2 -2
- data/lib/accept_headers.rb +4 -0
- data/lib/accept_headers/acceptable.rb +4 -28
- data/lib/accept_headers/charset.rb +7 -15
- data/lib/accept_headers/charset/negotiator.rb +27 -0
- data/lib/accept_headers/encoding.rb +7 -15
- data/lib/accept_headers/encoding/negotiator.rb +27 -0
- data/lib/accept_headers/language.rb +9 -25
- data/lib/accept_headers/language/negotiator.rb +37 -0
- data/lib/accept_headers/media_type.rb +9 -38
- data/lib/accept_headers/media_type/negotiator.rb +50 -0
- data/lib/accept_headers/negotiatable.rb +54 -0
- data/lib/accept_headers/version.rb +1 -1
- data/spec/charset/negotiator_spec.rb +73 -0
- data/spec/charset_spec.rb +4 -58
- data/spec/encoding/negotiator_spec.rb +73 -0
- data/spec/encoding_spec.rb +4 -58
- data/spec/language/negotiator_spec.rb +78 -0
- data/spec/language_spec.rb +4 -63
- data/spec/media_type/negotiator_spec.rb +92 -0
- data/spec/media_type_spec.rb +4 -78
- data/spec/spec_helper.rb +10 -12
- metadata +19 -5
@@ -0,0 +1,37 @@
|
|
1
|
+
require "accept_headers/language"
|
2
|
+
require "accept_headers/negotiatable"
|
3
|
+
|
4
|
+
module AcceptHeaders
|
5
|
+
class Language
|
6
|
+
class Negotiator
|
7
|
+
include Negotiatable
|
8
|
+
|
9
|
+
LANGUAGE_PATTERN = /^\s*(?<primary_tag>[\w]{1,8}|\*)(?:\s*\-\s*(?<subtag>[\w]{1,8}|\*))?\s*$/
|
10
|
+
|
11
|
+
private
|
12
|
+
def parse(original_header)
|
13
|
+
header = original_header.dup
|
14
|
+
header.sub!(/\AAccept-Language:\s*/, '')
|
15
|
+
header.strip!
|
16
|
+
return [Language.new] if header.empty?
|
17
|
+
languages = []
|
18
|
+
header.split(',').each do |entry|
|
19
|
+
language_arr = entry.split(';', 2)
|
20
|
+
next if language_arr[0].nil?
|
21
|
+
language_range = LANGUAGE_PATTERN.match(language_arr[0])
|
22
|
+
next if language_range.nil?
|
23
|
+
begin
|
24
|
+
languages << Language.new(
|
25
|
+
language_range[:primary_tag],
|
26
|
+
language_range[:subtag],
|
27
|
+
q: parse_q(language_arr[1])
|
28
|
+
)
|
29
|
+
rescue Error
|
30
|
+
next
|
31
|
+
end
|
32
|
+
end
|
33
|
+
languages.sort! { |x,y| y <=> x }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -70,45 +70,16 @@ module AcceptHeaders
|
|
70
70
|
string
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
header.split(',').each do |entry|
|
83
|
-
accept_media_range, accept_params = entry.split(';', 2)
|
84
|
-
next if accept_media_range.nil?
|
85
|
-
media_range = MEDIA_TYPE_PATTERN.match(accept_media_range)
|
86
|
-
next if media_range.nil?
|
87
|
-
begin
|
88
|
-
media_types << MediaType.new(
|
89
|
-
media_range[:type],
|
90
|
-
media_range[:subtype],
|
91
|
-
q: parse_q(accept_params),
|
92
|
-
params: parse_params(accept_params)
|
93
|
-
)
|
94
|
-
rescue Error
|
95
|
-
next
|
96
|
-
end
|
97
|
-
end
|
98
|
-
media_types.sort! { |x,y| y <=> x }
|
99
|
-
end
|
100
|
-
|
101
|
-
private
|
102
|
-
|
103
|
-
def self.parse_params(params_string)
|
104
|
-
params = {}
|
105
|
-
return params if !params_string || params_string.empty?
|
106
|
-
params_string.split(';').each do |part|
|
107
|
-
param = PARAM_PATTERN.match(part)
|
108
|
-
params[param[:attribute]] = param[:value] if param
|
73
|
+
def match(other)
|
74
|
+
if type == other.type && subtype == other.subtype
|
75
|
+
true
|
76
|
+
elsif type == other.type && subtype == '*'
|
77
|
+
true
|
78
|
+
elsif other.type == '*' && other.subtype == '*'
|
79
|
+
true
|
80
|
+
else
|
81
|
+
false
|
109
82
|
end
|
110
|
-
params.delete('q')
|
111
|
-
params
|
112
83
|
end
|
113
84
|
end
|
114
85
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "accept_headers/media_type"
|
2
|
+
require "accept_headers/negotiatable"
|
3
|
+
|
4
|
+
module AcceptHeaders
|
5
|
+
class MediaType
|
6
|
+
class Negotiator
|
7
|
+
include Negotiatable
|
8
|
+
|
9
|
+
private
|
10
|
+
MEDIA_TYPE_PATTERN = /^\s*(?<type>[\w!#$%^&*\-\+{}\\|'.`~]+)(?:\s*\/\s*(?<subtype>[\w!#$%^&*\-\+{}\\|'.`~]+))?\s*$/
|
11
|
+
PARAM_PATTERN = /(?<attribute>[\w!#$%^&*\-\+{}\\|'.`~]+)\s*\=\s*(?:\"(?<value>[^"]*)\"|\'(?<value>[^']*)\'|(?<value>[\w!#$%^&*\-\+{}\\|\'.`~]*))/
|
12
|
+
|
13
|
+
def parse(original_header)
|
14
|
+
header = original_header.dup
|
15
|
+
header.sub!(/\AAccept:\s*/, '')
|
16
|
+
header.strip!
|
17
|
+
return [MediaType.new] if header.empty?
|
18
|
+
media_types = []
|
19
|
+
header.split(',').each do |entry|
|
20
|
+
accept_media_range, accept_params = entry.split(';', 2)
|
21
|
+
next if accept_media_range.nil?
|
22
|
+
media_range = MEDIA_TYPE_PATTERN.match(accept_media_range)
|
23
|
+
next if media_range.nil?
|
24
|
+
begin
|
25
|
+
media_types << MediaType.new(
|
26
|
+
media_range[:type],
|
27
|
+
media_range[:subtype],
|
28
|
+
q: parse_q(accept_params),
|
29
|
+
params: parse_params(accept_params)
|
30
|
+
)
|
31
|
+
rescue Error
|
32
|
+
next
|
33
|
+
end
|
34
|
+
end
|
35
|
+
media_types.sort! { |x,y| y <=> x }
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_params(params_string)
|
39
|
+
params = {}
|
40
|
+
return params if !params_string || params_string.empty?
|
41
|
+
params_string.split(';').each do |part|
|
42
|
+
param = PARAM_PATTERN.match(part)
|
43
|
+
params[param[:attribute]] = param[:value] if param
|
44
|
+
end
|
45
|
+
params.delete('q')
|
46
|
+
params
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module AcceptHeaders
|
2
|
+
module Negotiatable
|
3
|
+
class Error < StandardError; end
|
4
|
+
class ParseError < Error; end
|
5
|
+
|
6
|
+
TOKEN_PATTERN = /^\s*(?<token>[\w!#$%^&*\-\+{}\\|'.`~]+)\s*$/
|
7
|
+
Q_PATTERN = /(?:\A|;)\s*(?<exists>qs*\=)\s*(?:(?<q>0\.\d{1,3}|[01])|(?:[^;]*))\s*(?:\z|;)/
|
8
|
+
|
9
|
+
attr_reader :list
|
10
|
+
|
11
|
+
def initialize(header)
|
12
|
+
@list = parse(header)
|
13
|
+
end
|
14
|
+
|
15
|
+
def negotiate(supported_string)
|
16
|
+
supported = parse(supported_string)
|
17
|
+
return nil if @list.empty?
|
18
|
+
rejects, acceptable = @list.partition { |m| m.q == 0.0 }
|
19
|
+
rejects.each do |reject|
|
20
|
+
supported.each do |support|
|
21
|
+
if support.match(reject)
|
22
|
+
return nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
acceptable.sort { |x,y| y <=> x }.each do |accepted|
|
27
|
+
supported.each do |support|
|
28
|
+
if support.match(accepted)
|
29
|
+
return accepted
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def parse(header)
|
37
|
+
raise NotImplementedError.new("#parse(header) is not implemented")
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_q(header)
|
41
|
+
q = 1
|
42
|
+
return q unless header
|
43
|
+
q_match = Q_PATTERN.match(header)
|
44
|
+
if q_match && q_match[:exists]
|
45
|
+
if q_match[:q]
|
46
|
+
q = q_match[:q]
|
47
|
+
else
|
48
|
+
q = 0.001
|
49
|
+
end
|
50
|
+
end
|
51
|
+
q
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
module AcceptHeaders
|
4
|
+
class Charset
|
5
|
+
describe Negotiator do
|
6
|
+
subject do
|
7
|
+
AcceptHeaders::Charset::Negotiator
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "parsing an accept header" do
|
11
|
+
it "returns a sorted array of charsets" do
|
12
|
+
subject.new("*; q=0.2, unicode-1-1").list.must_equal [
|
13
|
+
Charset.new('unicode-1-1'),
|
14
|
+
Charset.new('*', q: 0.2)
|
15
|
+
]
|
16
|
+
|
17
|
+
subject.new("us-ascii; q=0.5, iso-8859-1, utf-8; q=0.8, macintosh").list.must_equal [
|
18
|
+
Charset.new('iso-8859-1'),
|
19
|
+
Charset.new('macintosh'),
|
20
|
+
Charset.new('utf-8', q: 0.8),
|
21
|
+
Charset.new('us-ascii', q: 0.5)
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "sets charset to * when the accept-charset header is empty" do
|
26
|
+
subject.new('').list.must_equal [
|
27
|
+
Charset.new('*')
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "defaults q to 1 if it's not explicitly specified" do
|
32
|
+
subject.new("iso-8859-1").list.must_equal [
|
33
|
+
Charset.new('iso-8859-1', q: 1.0)
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "strips whitespace from between charsets" do
|
38
|
+
subject.new("\tunicode-1-1\r,\niso-8859-1\s").list.must_equal [
|
39
|
+
Charset.new('unicode-1-1'),
|
40
|
+
Charset.new('iso-8859-1')
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "strips whitespace around q" do
|
45
|
+
subject.new("iso-8859-1;\tq\r=\n1, unicode-1-1;q=0.8\n").list.must_equal [
|
46
|
+
Charset.new('iso-8859-1'),
|
47
|
+
Charset.new('unicode-1-1', q: 0.8)
|
48
|
+
]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "has a q value of 0.001 when parsed q is invalid" do
|
52
|
+
subject.new("iso-8859-1;q=x").list.must_equal [
|
53
|
+
Charset.new('iso-8859-1', q: 0.001)
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "skips invalid character sets" do
|
58
|
+
subject.new("iso-8859-1, @unicode-1-1").list.must_equal [
|
59
|
+
Charset.new('iso-8859-1', q: 1)
|
60
|
+
]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "negotiate supported charsets" do
|
65
|
+
it "returns a best matching charset" do
|
66
|
+
match = Charset.new('iso-8859-1')
|
67
|
+
n = subject.new('us-ascii; q=0.5, iso-8859-1, utf-8; q=0.8, macintosh')
|
68
|
+
n.negotiate('iso-8859-1').must_equal match
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/spec/charset_spec.rb
CHANGED
@@ -34,11 +34,11 @@ module AcceptHeaders
|
|
34
34
|
subject.new('iso-8859-1', q: '1')
|
35
35
|
end
|
36
36
|
|
37
|
-
it "raises an
|
37
|
+
it "raises an InvalidQError unless q value is between 0 and 1" do
|
38
38
|
[-1.0, -0.1, 1.1].each do |q|
|
39
39
|
e = -> do
|
40
40
|
subject.new('iso-8859-1', q: q)
|
41
|
-
end.must_raise Charset::
|
41
|
+
end.must_raise Charset::InvalidQError
|
42
42
|
|
43
43
|
e.message.must_equal "q must be between 0 and 1"
|
44
44
|
end
|
@@ -47,10 +47,10 @@ module AcceptHeaders
|
|
47
47
|
subject.new('unicode-1-1', q: 0)
|
48
48
|
end
|
49
49
|
|
50
|
-
it "raises an
|
50
|
+
it "raises an InvalidQError if q has more than a precision of 3" do
|
51
51
|
e = -> do
|
52
52
|
subject.new('iso-8859-1', q: 0.1234)
|
53
|
-
end.must_raise Charset::
|
53
|
+
end.must_raise Charset::InvalidQError
|
54
54
|
|
55
55
|
e.message.must_equal "q must be at most 3 decimal places"
|
56
56
|
|
@@ -68,59 +68,5 @@ module AcceptHeaders
|
|
68
68
|
s = subject.new('iso-8859-1', q: 0.9).to_s
|
69
69
|
s.must_equal "iso-8859-1;q=0.9"
|
70
70
|
end
|
71
|
-
|
72
|
-
describe "parsing an accept header" do
|
73
|
-
it "returns a sorted array of charsets" do
|
74
|
-
subject.parse("*; q=0.2, unicode-1-1").must_equal [
|
75
|
-
Charset.new('unicode-1-1'),
|
76
|
-
Charset.new('*', q: 0.2)
|
77
|
-
]
|
78
|
-
|
79
|
-
subject.parse("us-ascii; q=0.5, iso-8859-1, utf-8; q=0.8, macintosh").must_equal [
|
80
|
-
Charset.new('iso-8859-1'),
|
81
|
-
Charset.new('macintosh'),
|
82
|
-
Charset.new('utf-8', q: 0.8),
|
83
|
-
Charset.new('us-ascii', q: 0.5)
|
84
|
-
]
|
85
|
-
end
|
86
|
-
|
87
|
-
it "sets charset to * when the accept-charset header is empty" do
|
88
|
-
subject.parse('').must_equal [
|
89
|
-
Charset.new('*')
|
90
|
-
]
|
91
|
-
end
|
92
|
-
|
93
|
-
it "defaults q to 1 if it's not explicitly specified" do
|
94
|
-
subject.parse("iso-8859-1").must_equal [
|
95
|
-
Charset.new('iso-8859-1', q: 1.0)
|
96
|
-
]
|
97
|
-
end
|
98
|
-
|
99
|
-
it "strips whitespace from between charsets" do
|
100
|
-
subject.parse("\tunicode-1-1\r,\niso-8859-1\s").must_equal [
|
101
|
-
Charset.new('unicode-1-1'),
|
102
|
-
Charset.new('iso-8859-1')
|
103
|
-
]
|
104
|
-
end
|
105
|
-
|
106
|
-
it "strips whitespace around q" do
|
107
|
-
subject.parse("iso-8859-1;\tq\r=\n1, unicode-1-1;q=0.8\n").must_equal [
|
108
|
-
Charset.new('iso-8859-1'),
|
109
|
-
Charset.new('unicode-1-1', q: 0.8)
|
110
|
-
]
|
111
|
-
end
|
112
|
-
|
113
|
-
it "has a q value of 0.001 when parsed q is invalid" do
|
114
|
-
subject.parse("iso-8859-1;q=x").must_equal [
|
115
|
-
Charset.new('iso-8859-1', q: 0.001)
|
116
|
-
]
|
117
|
-
end
|
118
|
-
|
119
|
-
it "skips invalid character sets" do
|
120
|
-
subject.parse("iso-8859-1, @unicode-1-1").must_equal [
|
121
|
-
Charset.new('iso-8859-1', q: 1)
|
122
|
-
]
|
123
|
-
end
|
124
|
-
end
|
125
71
|
end
|
126
72
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
module AcceptHeaders
|
4
|
+
class Encoding
|
5
|
+
describe Negotiator do
|
6
|
+
subject do
|
7
|
+
AcceptHeaders::Encoding::Negotiator
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "parsing an accept header" do
|
11
|
+
it "returns a sorted array of encodings" do
|
12
|
+
subject.new("*; q=0.2, compress").list.must_equal [
|
13
|
+
Encoding.new('compress'),
|
14
|
+
Encoding.new('*', q: 0.2)
|
15
|
+
]
|
16
|
+
|
17
|
+
subject.new("deflate; q=0.5, gzip, compress; q=0.8, identity").list.must_equal [
|
18
|
+
Encoding.new('gzip'),
|
19
|
+
Encoding.new('identity'),
|
20
|
+
Encoding.new('compress', q: 0.8),
|
21
|
+
Encoding.new('deflate', q: 0.5)
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "sets encoding to * when the accept-encoding header is empty" do
|
26
|
+
subject.new('').list.must_equal [
|
27
|
+
Encoding.new('*')
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "defaults q to 1 if it's not explicitly specified" do
|
32
|
+
subject.new("gzip").list.must_equal [
|
33
|
+
Encoding.new('gzip', q: 1.0)
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "strips whitespace from between encodings" do
|
38
|
+
subject.new("\tcompress\r,\ngzip\s").list.must_equal [
|
39
|
+
Encoding.new('compress'),
|
40
|
+
Encoding.new('gzip')
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "strips whitespace around q" do
|
45
|
+
subject.new("gzip;\tq\r=\n1, compress;q=0.8\n").list.must_equal [
|
46
|
+
Encoding.new('gzip'),
|
47
|
+
Encoding.new('compress', q: 0.8)
|
48
|
+
]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "has a q value of 0.001 when parsed q is invalid" do
|
52
|
+
subject.new("gzip;q=x").list.must_equal [
|
53
|
+
Encoding.new('gzip', q: 0.001)
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "skips invalid encodings" do
|
58
|
+
subject.new("gzip, @blah").list.must_equal [
|
59
|
+
Encoding.new('gzip', q: 1.0)
|
60
|
+
]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "negotiate supported encodings" do
|
65
|
+
it "returns a best matching encoding" do
|
66
|
+
match =
|
67
|
+
n = subject.new("deflate; q=0.5, gzip, compress; q=0.8, identity")
|
68
|
+
n.negotiate("identity").must_equal Encoding.new('identity')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/spec/encoding_spec.rb
CHANGED
@@ -34,11 +34,11 @@ module AcceptHeaders
|
|
34
34
|
subject.new('gzip', q: '1')
|
35
35
|
end
|
36
36
|
|
37
|
-
it "raises an
|
37
|
+
it "raises an InvalidQError unless q value is between 0 and 1" do
|
38
38
|
[-1.0, -0.1, 1.1].each do |q|
|
39
39
|
e = -> do
|
40
40
|
subject.new('gzip', q: q)
|
41
|
-
end.must_raise Encoding::
|
41
|
+
end.must_raise Encoding::InvalidQError
|
42
42
|
|
43
43
|
e.message.must_equal "q must be between 0 and 1"
|
44
44
|
end
|
@@ -47,10 +47,10 @@ module AcceptHeaders
|
|
47
47
|
subject.new('compress', q: 0)
|
48
48
|
end
|
49
49
|
|
50
|
-
it "raises an
|
50
|
+
it "raises an InvalidQError if q has more than a precision of 3" do
|
51
51
|
e = -> do
|
52
52
|
subject.new('gzip', q: 0.1234)
|
53
|
-
end.must_raise Encoding::
|
53
|
+
end.must_raise Encoding::InvalidQError
|
54
54
|
|
55
55
|
e.message.must_equal "q must be at most 3 decimal places"
|
56
56
|
|
@@ -68,59 +68,5 @@ module AcceptHeaders
|
|
68
68
|
s = subject.new('gzip', q: 0.9).to_s
|
69
69
|
s.must_equal "gzip;q=0.9"
|
70
70
|
end
|
71
|
-
|
72
|
-
describe "parsing an accept header" do
|
73
|
-
it "returns a sorted array of encodings" do
|
74
|
-
subject.parse("*; q=0.2, compress").must_equal [
|
75
|
-
Encoding.new('compress'),
|
76
|
-
Encoding.new('*', q: 0.2)
|
77
|
-
]
|
78
|
-
|
79
|
-
subject.parse("deflate; q=0.5, gzip, compress; q=0.8, identity").must_equal [
|
80
|
-
Encoding.new('gzip'),
|
81
|
-
Encoding.new('identity'),
|
82
|
-
Encoding.new('compress', q: 0.8),
|
83
|
-
Encoding.new('deflate', q: 0.5)
|
84
|
-
]
|
85
|
-
end
|
86
|
-
|
87
|
-
it "sets encoding to * when the accept-encoding header is empty" do
|
88
|
-
subject.parse('').must_equal [
|
89
|
-
Encoding.new('*')
|
90
|
-
]
|
91
|
-
end
|
92
|
-
|
93
|
-
it "defaults q to 1 if it's not explicitly specified" do
|
94
|
-
subject.parse("gzip").must_equal [
|
95
|
-
Encoding.new('gzip', q: 1.0)
|
96
|
-
]
|
97
|
-
end
|
98
|
-
|
99
|
-
it "strips whitespace from between encodings" do
|
100
|
-
subject.parse("\tcompress\r,\ngzip\s").must_equal [
|
101
|
-
Encoding.new('compress'),
|
102
|
-
Encoding.new('gzip')
|
103
|
-
]
|
104
|
-
end
|
105
|
-
|
106
|
-
it "strips whitespace around q" do
|
107
|
-
subject.parse("gzip;\tq\r=\n1, compress;q=0.8\n").must_equal [
|
108
|
-
Encoding.new('gzip'),
|
109
|
-
Encoding.new('compress', q: 0.8)
|
110
|
-
]
|
111
|
-
end
|
112
|
-
|
113
|
-
it "has a q value of 0.001 when parsed q is invalid" do
|
114
|
-
subject.parse("gzip;q=x").must_equal [
|
115
|
-
Encoding.new('gzip', q: 0.001)
|
116
|
-
]
|
117
|
-
end
|
118
|
-
|
119
|
-
it "skips invalid encodings" do
|
120
|
-
subject.parse("gzip, @blah").must_equal [
|
121
|
-
Encoding.new('gzip', q: 1.0)
|
122
|
-
]
|
123
|
-
end
|
124
|
-
end
|
125
71
|
end
|
126
72
|
end
|