rack-accept_headers 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +15 -0
- data/CHANGELOG.md +35 -0
- data/Gemfile +4 -0
- data/Guardfile +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +198 -0
- data/Rakefile +10 -0
- data/lib/rack/accept_headers/charset.rb +36 -0
- data/lib/rack/accept_headers/context.rb +67 -0
- data/lib/rack/accept_headers/encoding.rb +36 -0
- data/lib/rack/accept_headers/header.rb +149 -0
- data/lib/rack/accept_headers/language.rb +36 -0
- data/lib/rack/accept_headers/media_type.rb +73 -0
- data/lib/rack/accept_headers/request.rb +90 -0
- data/lib/rack/accept_headers/response.rb +18 -0
- data/lib/rack/accept_headers/version.rb +5 -0
- data/lib/rack/accept_headers.rb +16 -0
- data/rack-accept_headers.gemspec +27 -0
- data/test/charset_test.rb +43 -0
- data/test/context_test.rb +57 -0
- data/test/encoding_test.rb +29 -0
- data/test/header_test.rb +69 -0
- data/test/language_test.rb +47 -0
- data/test/media_type_test.rb +80 -0
- data/test/request_test.rb +60 -0
- data/test/test_helper.rb +26 -0
- metadata +166 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
module Rack::AcceptHeaders
|
2
|
+
# Represents an HTTP Accept header according to the HTTP 1.1 specification,
|
3
|
+
# and provides several convenience methods for determining acceptable media
|
4
|
+
# types.
|
5
|
+
#
|
6
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
|
7
|
+
class MediaType
|
8
|
+
include Header
|
9
|
+
|
10
|
+
attr_accessor :extensions
|
11
|
+
|
12
|
+
# The name of this header.
|
13
|
+
def name
|
14
|
+
'Accept'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Determines the quality factor (qvalue) of the given +media_type+.
|
18
|
+
def qvalue(media_type)
|
19
|
+
return 1 if @qvalues.empty?
|
20
|
+
m = matches(media_type)
|
21
|
+
return 0 if m.empty?
|
22
|
+
normalize_qvalue(@qvalues[m.first])
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns an array of media types from this header that match the given
|
26
|
+
# +media_type+, ordered by precedence.
|
27
|
+
def matches(media_type)
|
28
|
+
type, subtype, params = parse_media_type(media_type)
|
29
|
+
values.select {|v|
|
30
|
+
if v == media_type || v == '*/*'
|
31
|
+
true
|
32
|
+
else
|
33
|
+
t, s, p = parse_media_type(v)
|
34
|
+
t == type && (s == '*' || s == subtype) && (p == '' || params_match?(params, p))
|
35
|
+
end
|
36
|
+
}.sort_by {|v|
|
37
|
+
# Most specific gets precedence.
|
38
|
+
v.length
|
39
|
+
}.reverse
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns a params hash for the media type that matches
|
43
|
+
def params(media_type)
|
44
|
+
return {} unless media_type
|
45
|
+
key = matches(media_type).first
|
46
|
+
@extensions[key] || {}
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def initialize(header)
|
52
|
+
@extensions = {}
|
53
|
+
@qvalues = {}
|
54
|
+
|
55
|
+
header.to_s.split(',').each do |part|
|
56
|
+
type, subtype, raw_params = parse_media_type(part)
|
57
|
+
raise InvalidHeader, "Invalid header value: #{part.inspect}" if !type || !subtype
|
58
|
+
media_type = "#{type}/#{subtype}"
|
59
|
+
params = parse_range_params(raw_params)
|
60
|
+
@extensions[media_type] = params
|
61
|
+
@qvalues[media_type] = normalize_qvalue(params['q']).to_f
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns true if all parameters and values in +match+ are also present in
|
66
|
+
# +params+.
|
67
|
+
def params_match?(params, match)
|
68
|
+
return true if params == match
|
69
|
+
parsed = parse_range_params(params)
|
70
|
+
parsed == parsed.merge(parse_range_params(match))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
|
3
|
+
module Rack::AcceptHeaders
|
4
|
+
# A container class for convenience methods when Rack::AcceptHeaders is used on the
|
5
|
+
# request level as Rack middleware. Instances of this class also manage a
|
6
|
+
# lightweight cache of various header instances to speed up execution.
|
7
|
+
class Request < Rack::Request
|
8
|
+
attr_reader :env
|
9
|
+
|
10
|
+
def initialize(env)
|
11
|
+
@env = env
|
12
|
+
end
|
13
|
+
|
14
|
+
# Provides access to the Rack::AcceptHeaders::MediaType instance for this request.
|
15
|
+
def media_type
|
16
|
+
@media_type ||= MediaType.new(env['HTTP_ACCEPT'])
|
17
|
+
end
|
18
|
+
|
19
|
+
# Provides access to the Rack::AcceptHeaders::Charset instance for this request.
|
20
|
+
def charset
|
21
|
+
@charset ||= Charset.new(env['HTTP_ACCEPT_CHARSET'])
|
22
|
+
end
|
23
|
+
|
24
|
+
# Provides access to the Rack::AcceptHeaders::Encoding instance for this request.
|
25
|
+
def encoding
|
26
|
+
@encoding ||= Encoding.new(env['HTTP_ACCEPT_ENCODING'])
|
27
|
+
end
|
28
|
+
|
29
|
+
# Provides access to the Rack::AcceptHeaders::Language instance for this request.
|
30
|
+
def language
|
31
|
+
@language ||= Language.new(env['HTTP_ACCEPT_LANGUAGE'])
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns true if the +Accept+ request header indicates the given media
|
35
|
+
# type is acceptable, false otherwise.
|
36
|
+
def media_type?(value)
|
37
|
+
media_type.accept?(value)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns true if the +Accept-Charset+ request header indicates the given
|
41
|
+
# character set is acceptable, false otherwise.
|
42
|
+
def charset?(value)
|
43
|
+
charset.accept?(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns true if the +Accept-Encoding+ request header indicates the given
|
47
|
+
# encoding is acceptable, false otherwise.
|
48
|
+
def encoding?(value)
|
49
|
+
encoding.accept?(value)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns true if the +Accept-Language+ request header indicates the given
|
53
|
+
# language is acceptable, false otherwise.
|
54
|
+
def language?(value)
|
55
|
+
language.accept?(value)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Determines the best media type to use in a response from the given media
|
59
|
+
# types, if any is acceptable. For more information on how this value is
|
60
|
+
# determined, see the documentation for
|
61
|
+
# Rack::AcceptHeaders::Header::PublicInstanceMethods#sort.
|
62
|
+
def best_media_type(values)
|
63
|
+
media_type.best_of(values)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Determines the best character set to use in a response from the given
|
67
|
+
# character sets, if any is acceptable. For more information on how this
|
68
|
+
# value is determined, see the documentation for
|
69
|
+
# Rack::AcceptHeaders::Header::PublicInstanceMethods#sort.
|
70
|
+
def best_charset(values)
|
71
|
+
charset.best_of(values)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Determines the best encoding to use in a response from the given
|
75
|
+
# encodings, if any is acceptable. For more information on how this value
|
76
|
+
# is determined, see the documentation for
|
77
|
+
# Rack::AcceptHeaders::Header::PublicInstanceMethods#sort.
|
78
|
+
def best_encoding(values)
|
79
|
+
encoding.best_of(values)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Determines the best language to use in a response from the given
|
83
|
+
# languages, if any is acceptable. For more information on how this value
|
84
|
+
# is determined, see the documentation for
|
85
|
+
# Rack::AcceptHeaders::Header::PublicInstanceMethods#sort.
|
86
|
+
def best_language(values)
|
87
|
+
language.best_of(values)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rack/response'
|
2
|
+
|
3
|
+
module Rack::AcceptHeaders
|
4
|
+
# The base class for responses issued by Rack::AcceptHeaders.
|
5
|
+
class Response < Rack::Response
|
6
|
+
# Marks this response as being unacceptable and clears the response body.
|
7
|
+
#
|
8
|
+
# Note: The HTTP spec advises servers to respond with an "entity" that
|
9
|
+
# describes acceptable parameters, but it fails to go into detail about its
|
10
|
+
# implementation. Thus, it is up to the user of this library to create such
|
11
|
+
# an entity if one is desired.
|
12
|
+
def not_acceptable!
|
13
|
+
self.status = 406
|
14
|
+
self.body = []
|
15
|
+
header['Content-Length'] = '0'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/accept_headers/header'
|
3
|
+
require 'rack/accept_headers/charset'
|
4
|
+
require 'rack/accept_headers/context'
|
5
|
+
require 'rack/accept_headers/encoding'
|
6
|
+
require 'rack/accept_headers/language'
|
7
|
+
require 'rack/accept_headers/media_type'
|
8
|
+
require 'rack/accept_headers/request'
|
9
|
+
require 'rack/accept_headers/response'
|
10
|
+
|
11
|
+
module Rack::AcceptHeaders
|
12
|
+
# Enables Rack::AcceptHeaders to be used as a Rack middleware.
|
13
|
+
def self.new(app, &block)
|
14
|
+
Context.new(app, &block)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'rack/accept_headers/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "rack-accept_headers"
|
7
|
+
spec.version = Rack::AcceptHeaders::VERSION
|
8
|
+
spec.authors = ["Jack Chu", "Michael Jackson"]
|
9
|
+
spec.email = ["kamuigt@gmail.com", "mjijackson@gmail.com"]
|
10
|
+
spec.summary = %q{HTTP Accept* for Ruby/Rack}
|
11
|
+
spec.description = %q{HTTP Accept, Accept-Charset, Accept-Encoding, and Accept-Language for Ruby/Rack}
|
12
|
+
spec.homepage = "https://github.com/kamui/rack-accept_headers"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency 'rack'
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler'
|
23
|
+
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'minitest'
|
25
|
+
spec.add_development_dependency 'guard'
|
26
|
+
spec.add_development_dependency 'guard-minitest'
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class CharsetTest < Minitest::Test
|
4
|
+
C = Rack::AcceptHeaders::Charset
|
5
|
+
|
6
|
+
def test_qvalue
|
7
|
+
c = C.new('')
|
8
|
+
assert_equal(0, c.qvalue('unicode-1-1'))
|
9
|
+
assert_equal(1, c.qvalue('iso-8859-1'))
|
10
|
+
|
11
|
+
c = C.new('unicode-1-1')
|
12
|
+
assert_equal(1, c.qvalue('unicode-1-1'))
|
13
|
+
assert_equal(0, c.qvalue('iso-8859-5'))
|
14
|
+
assert_equal(1, c.qvalue('iso-8859-1'))
|
15
|
+
|
16
|
+
c = C.new('unicode-1-1, *;q=0.5')
|
17
|
+
assert_equal(1, c.qvalue('unicode-1-1'))
|
18
|
+
assert_equal(0.5, c.qvalue('iso-8859-5'))
|
19
|
+
assert_equal(0.5, c.qvalue('iso-8859-1'))
|
20
|
+
|
21
|
+
c = C.new('iso-8859-1;q=0, *;q=0.5')
|
22
|
+
assert_equal(0.5, c.qvalue('iso-8859-5'))
|
23
|
+
assert_equal(0, c.qvalue('iso-8859-1'))
|
24
|
+
|
25
|
+
c = C.new('*;q=0')
|
26
|
+
assert_equal(0, c.qvalue('iso-8859-1'))
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_matches
|
30
|
+
c = C.new('iso-8859-1, iso-8859-5, *')
|
31
|
+
assert_equal(%w{*}, c.matches(''))
|
32
|
+
assert_equal(%w{iso-8859-1 *}, c.matches('iso-8859-1'))
|
33
|
+
assert_equal(%w{*}, c.matches('unicode-1-1'))
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_best_of
|
37
|
+
c = C.new('iso-8859-5, unicode-1-1;q=0.8')
|
38
|
+
assert_equal('iso-8859-5', c.best_of(%w< iso-8859-5 unicode-1-1 >))
|
39
|
+
assert_equal('iso-8859-5', c.best_of(%w< iso-8859-5 utf-8 >))
|
40
|
+
assert_equal('iso-8859-1', c.best_of(%w< iso-8859-1 utf-8 >))
|
41
|
+
assert_equal(nil, c.best_of(%w< utf-8 >))
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class ContextTest < Minitest::Test
|
4
|
+
def media_types; Proc.new {|c| c.media_types = %w< text/html > } end
|
5
|
+
def charsets; Proc.new {|c| c.charsets = %w< iso-8859-5 > } end
|
6
|
+
def encodings; Proc.new {|c| c.encodings = %w< gzip > } end
|
7
|
+
def languages; Proc.new {|c| c.languages = %w< en > } end
|
8
|
+
|
9
|
+
def test_empty
|
10
|
+
request
|
11
|
+
assert_equal(200, status)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_media_types
|
15
|
+
request('HTTP_ACCEPT' => 'text/html')
|
16
|
+
assert_equal(200, status)
|
17
|
+
|
18
|
+
request('HTTP_ACCEPT' => 'text/html', &media_types)
|
19
|
+
assert_equal(200, status)
|
20
|
+
|
21
|
+
request('HTTP_ACCEPT' => 'text/plain', &media_types)
|
22
|
+
assert_equal(406, status)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_charsets
|
26
|
+
request('HTTP_ACCEPT_CHARSET' => 'iso-8859-5')
|
27
|
+
assert_equal(200, status)
|
28
|
+
|
29
|
+
request('HTTP_ACCEPT_CHARSET' => 'iso-8859-5', &charsets)
|
30
|
+
assert_equal(200, status)
|
31
|
+
|
32
|
+
request('HTTP_ACCEPT_CHARSET' => 'unicode-1-1', &charsets)
|
33
|
+
assert_equal(406, status)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_encodings
|
37
|
+
request('HTTP_ACCEPT_ENCODING' => 'gzip')
|
38
|
+
assert_equal(200, status)
|
39
|
+
|
40
|
+
request('HTTP_ACCEPT_ENCODING' => 'gzip', &encodings)
|
41
|
+
assert_equal(200, status)
|
42
|
+
|
43
|
+
request('HTTP_ACCEPT_ENCODING' => 'compress', &encodings)
|
44
|
+
assert_equal(406, status)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_languages
|
48
|
+
request('HTTP_ACCEPT_LANGUAGE' => 'en')
|
49
|
+
assert_equal(200, status)
|
50
|
+
|
51
|
+
request('HTTP_ACCEPT_LANGUAGE' => 'en', &languages)
|
52
|
+
assert_equal(200, status)
|
53
|
+
|
54
|
+
request('HTTP_ACCEPT_LANGUAGE' => 'jp', &languages)
|
55
|
+
assert_equal(406, status)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class EncodingTest < Minitest::Test
|
4
|
+
E = Rack::AcceptHeaders::Encoding
|
5
|
+
|
6
|
+
def test_qvalue
|
7
|
+
e = E.new('')
|
8
|
+
assert_equal(0, e.qvalue('gzip'))
|
9
|
+
assert_equal(1, e.qvalue('identity'))
|
10
|
+
|
11
|
+
e = E.new('gzip, *;q=0.5')
|
12
|
+
assert_equal(1, e.qvalue('gzip'))
|
13
|
+
assert_equal(0.5, e.qvalue('identity'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_matches
|
17
|
+
e = E.new('gzip, identity, *')
|
18
|
+
assert_equal(%w{*}, e.matches(''))
|
19
|
+
assert_equal(%w{gzip *}, e.matches('gzip'))
|
20
|
+
assert_equal(%w{*}, e.matches('compress'))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_best_of
|
24
|
+
e = E.new('gzip, compress')
|
25
|
+
assert_equal('gzip', e.best_of(%w< gzip compress >))
|
26
|
+
assert_equal('identity', e.best_of(%w< identity compress >))
|
27
|
+
assert_equal(nil, e.best_of(%w< zip >))
|
28
|
+
end
|
29
|
+
end
|
data/test/header_test.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class HeaderTest < Minitest::Test
|
4
|
+
H = Rack::AcceptHeaders::Header
|
5
|
+
|
6
|
+
def test_parse_and_join
|
7
|
+
# Accept
|
8
|
+
header = 'text/plain; q=0.5, text/html, text/html;level=2, text/html;level=1;q=0.3, text/x-c, image/*; q=0.2'
|
9
|
+
expect = {
|
10
|
+
'text/plain' => 0.5,
|
11
|
+
'text/html' => 1,
|
12
|
+
'text/html;level=2' => 1,
|
13
|
+
'text/html;level=1' => 0.3,
|
14
|
+
'text/x-c' => 1,
|
15
|
+
'image/*' => 0.2
|
16
|
+
}
|
17
|
+
assert_equal(expect, H.parse(header))
|
18
|
+
assert_equal(expect, H.parse(H.join(expect)))
|
19
|
+
|
20
|
+
# Accept-Charset
|
21
|
+
header = 'iso-8859-5, unicode-1-1;q=0.8'
|
22
|
+
expect = { 'iso-8859-5' => 1, 'unicode-1-1' => 0.8 }
|
23
|
+
assert_equal(expect, H.parse(header))
|
24
|
+
assert_equal(expect, H.parse(H.join(expect)))
|
25
|
+
|
26
|
+
# Accept-Encoding
|
27
|
+
header = 'gzip;q=1.0, identity; q=0.5, *;q=0'
|
28
|
+
expect = { 'gzip' => 1, 'identity' => 0.5, '*' => 0 }
|
29
|
+
assert_equal(expect, H.parse(header))
|
30
|
+
assert_equal(expect, H.parse(H.join(expect)))
|
31
|
+
|
32
|
+
# Accept-Language
|
33
|
+
header = 'da, en-gb;q=0.8, en;q=0.7'
|
34
|
+
expect = { 'da' => 1, 'en-gb' => 0.8, 'en' => 0.7 }
|
35
|
+
assert_equal(expect, H.parse(header))
|
36
|
+
assert_equal(expect, H.parse(H.join(expect)))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_parse_media_type
|
40
|
+
assert_equal([], H.parse_media_type(''))
|
41
|
+
assert_equal(['*', '*', ''], H.parse_media_type('*/*'))
|
42
|
+
assert_equal(['text', '*', ''], H.parse_media_type('text/*'))
|
43
|
+
assert_equal(['text', 'html', ''], H.parse_media_type('text/html'))
|
44
|
+
assert_equal(['text', 'html', 'level=1'], H.parse_media_type('text/html;level=1'))
|
45
|
+
assert_equal(['text', 'html', 'level=1;answer=42'], H.parse_media_type('text/html;level=1;answer=42'))
|
46
|
+
assert_equal(['text', 'x-dvi', ''], H.parse_media_type('text/x-dvi'))
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_parse_range_params
|
50
|
+
assert_equal({'q' => '1'}, H.parse_range_params(''))
|
51
|
+
assert_equal({'q' => '1'}, H.parse_range_params('a'))
|
52
|
+
assert_equal({'q' => '1', 'a' => 'a'}, H.parse_range_params('a=a'))
|
53
|
+
assert_equal({'q' => '1', 'a' => 'a', 'b' => 'b'}, H.parse_range_params('a=a;b=b'))
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_normalize_qvalue
|
57
|
+
assert_equal(1, H.normalize_qvalue(1.0))
|
58
|
+
assert_equal(0, H.normalize_qvalue(0.0))
|
59
|
+
assert_equal(1, H.normalize_qvalue(1))
|
60
|
+
assert_equal(0, H.normalize_qvalue(0))
|
61
|
+
assert_equal(0.5, H.normalize_qvalue(0.5))
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_invalid_header
|
65
|
+
assert_raises Rack::AcceptHeaders::Header::InvalidHeader do
|
66
|
+
h = H.parse(' / ')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class LanguageTest < Minitest::Test
|
4
|
+
L = Rack::AcceptHeaders::Language
|
5
|
+
|
6
|
+
def test_qvalue
|
7
|
+
l = L.new('')
|
8
|
+
assert_equal(1, l.qvalue('en'))
|
9
|
+
|
10
|
+
l = L.new('en;q=0.5, en-gb')
|
11
|
+
assert_equal(0.5, l.qvalue('en'))
|
12
|
+
assert_equal(1, l.qvalue('en-gb'))
|
13
|
+
assert_equal(0, l.qvalue('da'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_matches
|
17
|
+
l = L.new('da, *, en')
|
18
|
+
assert_equal(%w{*}, l.matches(''))
|
19
|
+
assert_equal(%w{da *}, l.matches('da'))
|
20
|
+
assert_equal(%w{en *}, l.matches('en'))
|
21
|
+
assert_equal(%w{en *}, l.matches('en-gb'))
|
22
|
+
assert_equal(%w{*}, l.matches('eng'))
|
23
|
+
|
24
|
+
l = L.new('en, en-gb')
|
25
|
+
assert_equal(%w{en-gb en}, l.matches('en-gb'))
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_best_of
|
29
|
+
l = L.new('en;q=0.5, en-gb')
|
30
|
+
assert_equal('en-gb', l.best_of(%w< en en-gb >))
|
31
|
+
assert_equal('en', l.best_of(%w< en da >))
|
32
|
+
assert_equal('en-us', l.best_of(%w< en-us en-au >))
|
33
|
+
assert_equal(nil, l.best_of(%w< da >))
|
34
|
+
|
35
|
+
l = L.new('en;q=0.5, en-GB, fr-CA')
|
36
|
+
assert_equal('en-gb', l.best_of(%w< en en-gb >))
|
37
|
+
|
38
|
+
l = L.new('en-gb;q=0.5, EN, fr-CA')
|
39
|
+
assert_equal('en', l.best_of(%w< en en-gb >))
|
40
|
+
|
41
|
+
l = L.new('en;q=0.5, fr-ca')
|
42
|
+
assert_equal('en', l.best_of(%w< en fr >))
|
43
|
+
|
44
|
+
l.first_level_match = true
|
45
|
+
assert_equal('fr', l.best_of(%w< en fr >))
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MediaTypeTest < Minitest::Test
|
4
|
+
M = Rack::AcceptHeaders::MediaType
|
5
|
+
|
6
|
+
def test_qvalue
|
7
|
+
m = M.new('text/html, text/*;q=0.3, */*;q=0.5')
|
8
|
+
assert_equal(0.5, m.qvalue('image/png'))
|
9
|
+
assert_equal(0.3, m.qvalue('text/plain'))
|
10
|
+
assert_equal(1, m.qvalue('text/html'))
|
11
|
+
|
12
|
+
m = M.new('text/html')
|
13
|
+
assert_equal(0, m.qvalue('image/png'))
|
14
|
+
|
15
|
+
m = M.new('')
|
16
|
+
assert_equal(1, m.qvalue('text/html'))
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_invalid_media_type
|
20
|
+
assert_raises Rack::AcceptHeaders::Header::InvalidHeader do
|
21
|
+
m = M.new('')
|
22
|
+
m = M.new('text')
|
23
|
+
m = M.new('text;q=1')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_matches
|
28
|
+
m = M.new('text/*, text/html, text/html;level=1, */*')
|
29
|
+
assert_equal(%w{*/*}, m.matches(''))
|
30
|
+
assert_equal(%w{*/*}, m.matches('image/jpeg'))
|
31
|
+
assert_equal(%w{text/* */*}, m.matches('text/plain'))
|
32
|
+
assert_equal(%w{text/html text/* */*}, m.matches('text/html'))
|
33
|
+
assert_equal(%w{text/html text/* */*}, m.matches('text/html;level=1'))
|
34
|
+
assert_equal(%w{text/html text/* */*}, m.matches('text/html;level=1;answer=42'))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_best_of
|
38
|
+
m = M.new('text/*;q=0.5, text/html')
|
39
|
+
assert_equal('text/html', m.best_of(%w< text/plain text/html >))
|
40
|
+
assert_equal('text/plain', m.best_of(%w< text/plain image/png >))
|
41
|
+
assert_equal('text/plain', m.best_of(%w< text/plain text/javascript >))
|
42
|
+
assert_equal(nil, m.best_of(%w< image/png >))
|
43
|
+
|
44
|
+
m = M.new('text/*')
|
45
|
+
assert_equal('text/html', m.best_of(%w< text/html text/xml >))
|
46
|
+
assert_equal('text/xml', m.best_of(%w< text/xml text/html >))
|
47
|
+
|
48
|
+
m = M.new('TEXT/*')
|
49
|
+
assert_equal('text/html', m.best_of(%w< text/html text/xml >))
|
50
|
+
assert_equal('text/xml', m.best_of(%w< text/xml text/html >))
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_extensions
|
54
|
+
m = M.new('text/plain')
|
55
|
+
assert_equal({'text/plain' => {'q' => '1'}}, m.extensions)
|
56
|
+
m = M.new('text/*;q=0.5;a=42')
|
57
|
+
assert_equal({'text/*' => {'q' => '0.5', 'a' => '42'}}, m.extensions)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_params
|
61
|
+
m = M.new('text/plain;q=0.7;version=1.0')
|
62
|
+
assert_equal({'q' => '0.7', 'version' => '1.0'}, m.params('text/plain'))
|
63
|
+
m = M.new('text/*;q=0.5;a=42, application/json;b=12')
|
64
|
+
assert_equal({'q' => '0.5', 'a' => '42'}, m.params('text/plain'))
|
65
|
+
assert_equal({'q' => '1', 'b' => '12'}, m.params('application/json'))
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_vendored_types
|
69
|
+
m = M.new("application/vnd.ms-excel")
|
70
|
+
assert_equal(nil, m.best_of(%w< application/vnd.ms-powerpoint >))
|
71
|
+
|
72
|
+
m = M.new("application/vnd.api-v1+json")
|
73
|
+
assert_equal(false, m.accept?("application/vnd.api-v2+json"))
|
74
|
+
|
75
|
+
v1, v2 = "application/vnd.api-v1+json", "application/vnd.api-v2+json"
|
76
|
+
m = M.new("#{v1},#{v2}")
|
77
|
+
assert_equal(v1, m.best_of([v1, v2]))
|
78
|
+
assert_equal(v2, m.best_of([v2, v1]))
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class RequestTest < Minitest::Test
|
4
|
+
R = Rack::AcceptHeaders::Request
|
5
|
+
|
6
|
+
def test_media_type
|
7
|
+
r = R.new('HTTP_ACCEPT' => 'text/*;q=0, text/html')
|
8
|
+
assert(r.media_type?('text/html'))
|
9
|
+
assert(r.media_type?('text/html;level=1'))
|
10
|
+
assert(!r.media_type?('text/plain'))
|
11
|
+
assert(!r.media_type?('image/png'))
|
12
|
+
|
13
|
+
request = R.new('HTTP_ACCEPT' => '*/*')
|
14
|
+
assert(request.media_type?('image/png'))
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_charset
|
18
|
+
r = R.new('HTTP_ACCEPT_CHARSET' => 'iso-8859-5, unicode-1-1;q=0.8')
|
19
|
+
assert(r.charset?('iso-8859-5'))
|
20
|
+
assert(r.charset?('unicode-1-1'))
|
21
|
+
assert(r.charset?('iso-8859-1'))
|
22
|
+
assert(!r.charset?('utf-8'))
|
23
|
+
|
24
|
+
r = R.new('HTTP_ACCEPT_CHARSET' => 'iso-8859-1;q=0')
|
25
|
+
assert(!r.charset?('iso-8859-1'))
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_encoding
|
29
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => '')
|
30
|
+
assert(r.encoding?('identity'))
|
31
|
+
assert(!r.encoding?('gzip'))
|
32
|
+
|
33
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => 'gzip')
|
34
|
+
assert(r.encoding?('identity'))
|
35
|
+
assert(r.encoding?('gzip'))
|
36
|
+
assert(!r.encoding?('compress'))
|
37
|
+
|
38
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => 'gzip;q=0, *')
|
39
|
+
assert(r.encoding?('compress'))
|
40
|
+
assert(r.encoding?('identity'))
|
41
|
+
assert(!r.encoding?('gzip'))
|
42
|
+
|
43
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => 'identity;q=0')
|
44
|
+
assert(!r.encoding?('identity'))
|
45
|
+
|
46
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => '*;q=0')
|
47
|
+
assert(!r.encoding?('identity'))
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_language
|
51
|
+
request = R.new({})
|
52
|
+
assert(request.language?('en'))
|
53
|
+
assert(request.language?('da'))
|
54
|
+
|
55
|
+
request = R.new('HTTP_ACCEPT_LANGUAGE' => 'en;q=0.5, en-gb')
|
56
|
+
assert(request.language?('en'))
|
57
|
+
assert(request.language?('en-gb'))
|
58
|
+
assert(!request.language?('da'))
|
59
|
+
end
|
60
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'rack/accept_headers'
|
6
|
+
|
7
|
+
class Minitest::Test
|
8
|
+
attr_reader :context
|
9
|
+
attr_reader :response
|
10
|
+
|
11
|
+
def status
|
12
|
+
@response && @response.status
|
13
|
+
end
|
14
|
+
|
15
|
+
def request(env={}, method='GET', uri='/')
|
16
|
+
@context = Rack::AcceptHeaders.new(fake_app)
|
17
|
+
yield @context if block_given?
|
18
|
+
mock_request = Rack::MockRequest.new(@context)
|
19
|
+
@response = mock_request.request(method.to_s.upcase, uri, env)
|
20
|
+
@response
|
21
|
+
end
|
22
|
+
|
23
|
+
def fake_app(status=200, headers={}, body=[])
|
24
|
+
lambda {|env| Rack::Response.new(body, status, headers).finish }
|
25
|
+
end
|
26
|
+
end
|