mirror of
https://gitea.invidious.io/iv-org/shard-athena-negotiation.git
synced 2024-08-15 00:53:23 +00:00
Add more specialized negotiators
Fix issue with accept language setting
This commit is contained in:
parent
bf08531bca
commit
3850074f02
12 changed files with 211 additions and 14 deletions
67
spec/charset_negotiator_spec.cr
Normal file
67
spec/charset_negotiator_spec.cr
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
require "./spec_helper"
|
||||||
|
|
||||||
|
struct CharsetNegotiatorTest < NegotiatorTestCase
|
||||||
|
@negotiator : ANG::CharsetNegotiator
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@negotiator = ANG::CharsetNegotiator.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_best_unmatched_header : Nil
|
||||||
|
@negotiator.best("foo, bar, yo", {"baz"}).should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_best_ignores_missing_content : Nil
|
||||||
|
accept = @negotiator.best "en; q=0.1, fr; q=0.4, bu; q=1.0", {"en", "fr"}
|
||||||
|
|
||||||
|
accept = accept.should_not be_nil
|
||||||
|
accept.should be_a ANG::AcceptCharset
|
||||||
|
accept.value.should eq "fr"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_best_respects_priorities : Nil
|
||||||
|
accept = @negotiator.best "foo, bar, yo", {"yo"}
|
||||||
|
accept = accept.should_not be_nil
|
||||||
|
accept.should be_a ANG::AcceptCharset
|
||||||
|
accept.type.should eq "yo"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_best_respects_quality : Nil
|
||||||
|
accept = @negotiator.best "utf-8;q=0.5,iso-8859-1", {"iso-8859-1;q=0.3", "utf-8;q=0.9", "utf-16;q=1.0"}
|
||||||
|
accept = accept.should_not be_nil
|
||||||
|
accept.should be_a ANG::AcceptCharset
|
||||||
|
accept.type.should eq "utf-8"
|
||||||
|
end
|
||||||
|
|
||||||
|
@[DataProvider("best_data_provider")]
|
||||||
|
def test_best(header : String, priorities : Indexable(String), expected : String?) : Nil
|
||||||
|
accept = @negotiator.best header, priorities
|
||||||
|
|
||||||
|
if accept.nil?
|
||||||
|
expected.should be_nil
|
||||||
|
else
|
||||||
|
accept.should be_a ANG::AcceptCharset
|
||||||
|
accept.value.should eq expected
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def best_data_provider : Tuple
|
||||||
|
php_pear_charset = "ISO-8859-1, Big5;q=0.6,utf-8;q=0.7, *;q=0.5"
|
||||||
|
php_pear_charset2 = "ISO-8859-1, Big5;q=0.6,utf-8;q=0.7"
|
||||||
|
|
||||||
|
{
|
||||||
|
{php_pear_charset, {"utf-8", "big5", "iso-8859-1", "shift-jis"}, "iso-8859-1"},
|
||||||
|
{php_pear_charset, {"utf-8", "big5", "shift-jis"}, "utf-8"},
|
||||||
|
{php_pear_charset, {"Big5", "shift-jis"}, "Big5"},
|
||||||
|
{php_pear_charset, {"shift-jis"}, "shift-jis"},
|
||||||
|
{php_pear_charset2, {"utf-8", "big5", "iso-8859-1", "shift-jis"}, "iso-8859-1"},
|
||||||
|
{php_pear_charset2, {"utf-8", "big5", "shift-jis"}, "utf-8"},
|
||||||
|
{php_pear_charset2, {"Big5", "shift-jis"}, "Big5"},
|
||||||
|
{"utf-8;q=0.6,iso-8859-5;q=0.9", {"iso-8859-5", "utf-8"}, "iso-8859-5"},
|
||||||
|
{"en, *;q=0.9", {"fr"}, "fr"},
|
||||||
|
# Quality of source factors
|
||||||
|
{php_pear_charset, {"iso-8859-1;q=0.5", "utf-8", "utf-16;q=1.0"}, "utf-8"},
|
||||||
|
{php_pear_charset, {"iso-8859-1;q=0.8", "utf-8", "utf-16;q=1.0"}, "iso-8859-1;q=0.8"},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
42
spec/encoding_negotiator_spec.cr
Normal file
42
spec/encoding_negotiator_spec.cr
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
require "./spec_helper"
|
||||||
|
|
||||||
|
struct EncodingNegotiatorTest < NegotiatorTestCase
|
||||||
|
@negotiator : ANG::EncodingNegotiator
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@negotiator = ANG::EncodingNegotiator.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_best_unmatched_header : Nil
|
||||||
|
@negotiator.best("foo, bar, yo", {"baz"}).should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_best_respects_quality : Nil
|
||||||
|
accept = @negotiator.best "gzip;q=0.7,identity", {"identity;q=0.5", "gzip;q=0.9"}
|
||||||
|
accept = accept.should_not be_nil
|
||||||
|
accept.should be_a ANG::AcceptEncoding
|
||||||
|
accept.type.should eq "gzip"
|
||||||
|
end
|
||||||
|
|
||||||
|
@[DataProvider("best_data_provider")]
|
||||||
|
def test_best(header : String, priorities : Indexable(String), expected : String?) : Nil
|
||||||
|
accept = @negotiator.best header, priorities
|
||||||
|
|
||||||
|
if accept.nil?
|
||||||
|
expected.should be_nil
|
||||||
|
else
|
||||||
|
accept.should be_a ANG::AcceptEncoding
|
||||||
|
accept.value.should eq expected
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def best_data_provider : Tuple
|
||||||
|
{
|
||||||
|
{"gzip;q=1.0, identity; q=0.5, *;q=0", {"identity"}, "identity"},
|
||||||
|
{"gzip;q=0.5, identity; q=0.5, *;q=0.7", {"bzip", "foo"}, "bzip"},
|
||||||
|
{"gzip;q=0.7, identity; q=0.5, *;q=0.7", {"gzip", "foo"}, "gzip"},
|
||||||
|
# Quality of source factors
|
||||||
|
{"gzip;q=0.7,identity", {"identity;q=0.5", "gzip;q=0.9"}, "gzip;q=0.9"},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
43
spec/language_negotiator_spec.cr
Normal file
43
spec/language_negotiator_spec.cr
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
require "./spec_helper"
|
||||||
|
|
||||||
|
struct LanguageNegotiatorTest < NegotiatorTestCase
|
||||||
|
@negotiator : ANG::LanguageNegotiator
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@negotiator = ANG::LanguageNegotiator.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_best_respects_quality : Nil
|
||||||
|
accept = @negotiator.best "en;q=0.5,de", {"de;q=0.3", "en;q=0.9"}
|
||||||
|
accept = accept.should_not be_nil
|
||||||
|
accept.should be_a ANG::AcceptLanguage
|
||||||
|
accept.type.should eq "en"
|
||||||
|
end
|
||||||
|
|
||||||
|
@[DataProvider("best_data_provider")]
|
||||||
|
def test_best(header : String, priorities : Indexable(String), expected : String?) : Nil
|
||||||
|
accept = @negotiator.best header, priorities
|
||||||
|
|
||||||
|
if accept.nil?
|
||||||
|
expected.should be_nil
|
||||||
|
else
|
||||||
|
accept.should be_a ANG::AcceptLanguage
|
||||||
|
accept.value.should eq expected
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def best_data_provider : Tuple
|
||||||
|
{
|
||||||
|
{"en, de", {"fr"}, nil},
|
||||||
|
{"foo, bar, yo", {"baz", "biz"}, nil},
|
||||||
|
{"fr-FR, en;q=0.8", {"en-US", "de-DE"}, "en-US"},
|
||||||
|
{"en, *;q=0.9", {"fr"}, "fr"},
|
||||||
|
{"foo, bar, yo", {"yo"}, "yo"},
|
||||||
|
{"en; q=0.1, fr; q=0.4, bu; q=1.0", {"en", "fr"}, "fr"},
|
||||||
|
{"en; q=0.1, fr; q=0.4, fu; q=0.9, de; q=0.2", {"en", "fu"}, "fu"},
|
||||||
|
{"fr, zh-Hans-CN;q=0.3", {"fr"}, "fr"},
|
||||||
|
# Quality of source factors
|
||||||
|
{"en;q=0.5,de", {"de;q=0.3", "en;q=0.9"}, "en;q=0.9"},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,6 @@
|
||||||
require "./spec_helper"
|
require "./spec_helper"
|
||||||
|
|
||||||
struct NegotiatorTest < ASPEC::TestCase
|
struct NegotiatorTest < NegotiatorTestCase
|
||||||
@negotiator : ANG::Negotiator
|
@negotiator : ANG::Negotiator
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
|
@ -18,20 +18,12 @@ struct NegotiatorTest < ASPEC::TestCase
|
||||||
@negotiator.best("/qwer", {"foo/bar"}, false).should be_nil
|
@negotiator.best("/qwer", {"foo/bar"}, false).should be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_best_exception_handling : Nil
|
def test_invalid_media_type : Nil
|
||||||
ex = expect_raises ANG::Exceptions::InvalidMediaType, "Invalid media type: '/qwer'." do
|
ex = expect_raises ANG::Exceptions::InvalidMediaType, "Invalid media type: '/qwer'." do
|
||||||
@negotiator.best "foo/bar", {"/qwer"}
|
@negotiator.best "foo/bar", {"/qwer"}
|
||||||
end
|
end
|
||||||
|
|
||||||
ex.type.should eq "/qwer"
|
ex.type.should eq "/qwer"
|
||||||
|
|
||||||
expect_raises ArgumentError, "priorities should not be empty." do
|
|
||||||
@negotiator.best "foo/bar", [] of String
|
|
||||||
end
|
|
||||||
|
|
||||||
expect_raises ArgumentError, "The header string should not be empty." do
|
|
||||||
@negotiator.best "", {"text/html"}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@[DataProvider("best_data_provider")]
|
@[DataProvider("best_data_provider")]
|
||||||
|
|
11
spec/negotiator_test_case.cr
Normal file
11
spec/negotiator_test_case.cr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
abstract struct NegotiatorTestCase < ASPEC::TestCase
|
||||||
|
def test_best_exception_handling : Nil
|
||||||
|
expect_raises ArgumentError, "priorities should not be empty." do
|
||||||
|
@negotiator.best "foo/bar", [] of String
|
||||||
|
end
|
||||||
|
|
||||||
|
expect_raises ArgumentError, "The header string should not be empty." do
|
||||||
|
@negotiator.best "", {"text/html"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,7 @@
|
||||||
require "spec"
|
require "spec"
|
||||||
require "athena-spec"
|
require "athena-spec"
|
||||||
require "../src/athena-negotiation"
|
require "../src/athena-negotiation"
|
||||||
|
require "./negotiator_test_case"
|
||||||
|
|
||||||
include ASPEC::Methods
|
include ASPEC::Methods
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ struct Athena::Negotiation::AcceptLanguage < Athena::Negotiation::BaseAccept
|
||||||
def initialize(value : String)
|
def initialize(value : String)
|
||||||
super value
|
super value
|
||||||
|
|
||||||
parts = @value.split '-'
|
parts = @type.split '-'
|
||||||
|
|
||||||
case parts.size
|
case parts.size
|
||||||
when 2
|
when 2
|
||||||
|
|
|
@ -3,6 +3,9 @@ require "./accept_match"
|
||||||
require "./accept_charset"
|
require "./accept_charset"
|
||||||
require "./accept_encoding"
|
require "./accept_encoding"
|
||||||
require "./accept_language"
|
require "./accept_language"
|
||||||
|
require "./charset_negotiator"
|
||||||
|
require "./encoding_negotiator"
|
||||||
|
require "./language_negotiator"
|
||||||
require "./negotiator"
|
require "./negotiator"
|
||||||
|
|
||||||
require "./exceptions/*"
|
require "./exceptions/*"
|
||||||
|
|
7
src/charset_negotiator.cr
Normal file
7
src/charset_negotiator.cr
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
require "./abstract_negotiator"
|
||||||
|
|
||||||
|
class Athena::Negotiation::CharsetNegotiator < Athena::Negotiation::AbstractNegotiator
|
||||||
|
private def create_header(header : String) : ANG::BaseAccept
|
||||||
|
ANG::AcceptCharset.new header
|
||||||
|
end
|
||||||
|
end
|
7
src/encoding_negotiator.cr
Normal file
7
src/encoding_negotiator.cr
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
require "./abstract_negotiator"
|
||||||
|
|
||||||
|
class Athena::Negotiation::EncodingNegotiator < Athena::Negotiation::AbstractNegotiator
|
||||||
|
private def create_header(header : String) : ANG::BaseAccept
|
||||||
|
ANG::AcceptEncoding.new header
|
||||||
|
end
|
||||||
|
end
|
26
src/language_negotiator.cr
Normal file
26
src/language_negotiator.cr
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
require "./abstract_negotiator"
|
||||||
|
|
||||||
|
class Athena::Negotiation::LanguageNegotiator < Athena::Negotiation::AbstractNegotiator
|
||||||
|
protected def match(accept : ANG::AcceptLanguage, priority : ANG::AcceptLanguage, index : Int32) : ANG::AcceptMatch?
|
||||||
|
accept_base = accept.language
|
||||||
|
priority_base = priority.language
|
||||||
|
|
||||||
|
accept_sub = accept.region
|
||||||
|
priority_sub = priority.region
|
||||||
|
|
||||||
|
base_equal = accept_base.downcase == priority_base.downcase
|
||||||
|
sub_equal = accept_sub.try &.downcase == priority_sub.try &.downcase
|
||||||
|
|
||||||
|
if ((accept_base == "*" || base_equal) && (accept_sub.nil? || sub_equal))
|
||||||
|
score = 10 * (base_equal ? 1 : 0) + (sub_equal ? 1 : 0)
|
||||||
|
|
||||||
|
return ANG::AcceptMatch.new accept.quality * priority.quality, score, index
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
private def create_header(header : String) : ANG::BaseAccept
|
||||||
|
ANG::AcceptLanguage.new header
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,9 +1,7 @@
|
||||||
require "./abstract_negotiator"
|
require "./abstract_negotiator"
|
||||||
|
|
||||||
class Athena::Negotiation::Negotiator < Athena::Negotiation::AbstractNegotiator
|
class Athena::Negotiation::Negotiator < Athena::Negotiation::AbstractNegotiator
|
||||||
protected def match(accept : ANG::BaseAccept, priority : ANG::BaseAccept, index : Int32) : ANG::AcceptMatch?
|
protected def match(accept : ANG::Accept, priority : ANG::Accept, index : Int32) : ANG::AcceptMatch?
|
||||||
return nil if !accept.is_a?(ANG::Accept) || !priority.is_a?(ANG::Accept)
|
|
||||||
|
|
||||||
accept_base = accept.base_part
|
accept_base = accept.base_part
|
||||||
priority_base = priority.base_part
|
priority_base = priority.base_part
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue