mirror of
https://gitea.invidious.io/iv-org/shard-athena-negotiation.git
synced 2024-08-15 00:53:23 +00:00
Add method to get ordered array of accept headers
Fix issue with header key including whitespace Add singleton negotiator to base namespace
This commit is contained in:
parent
180ba3fae4
commit
bf08531bca
3 changed files with 71 additions and 7 deletions
|
@ -7,7 +7,18 @@ struct NegotiatorTest < ASPEC::TestCase
|
|||
@negotiator = ANG::Negotiator.new
|
||||
end
|
||||
|
||||
def test_exception_handling : Nil
|
||||
def test_best_respects_quality : Nil
|
||||
accept = @negotiator.best "text/html,text/*;q=0.7", {"text/html;q=0.5", "text/plain;q=0.9"}
|
||||
accept = accept.should_not be_nil
|
||||
accept.should be_a ANG::Accept
|
||||
accept.type.should eq "text/plain"
|
||||
end
|
||||
|
||||
def test_best_invalid_unstrict
|
||||
@negotiator.best("/qwer", {"foo/bar"}, false).should be_nil
|
||||
end
|
||||
|
||||
def test_best_exception_handling : Nil
|
||||
ex = expect_raises ANG::Exceptions::InvalidMediaType, "Invalid media type: '/qwer'." do
|
||||
@negotiator.best "foo/bar", {"/qwer"}
|
||||
end
|
||||
|
@ -90,7 +101,7 @@ struct NegotiatorTest < ASPEC::TestCase
|
|||
# IE8
|
||||
{"image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, */*", {"text/html", "application/xhtml+xml"}, {"text/html", nil}},
|
||||
|
||||
# wildcards with '+'
|
||||
# wildcards with `+`
|
||||
{"application/vnd.api+json", {"application/json", "application/*+json"}, {"application/*+json", nil}},
|
||||
{"application/json;q=0.7, application/*+json;q=0.7", {"application/hal+json", "application/problem+json"}, {"application/hal+json", nil}},
|
||||
{"application/json;q=0.7, application/problem+*;q=0.7", {"application/hal+xml", "application/problem+xml"}, {"application/problem+xml", nil}},
|
||||
|
@ -98,4 +109,29 @@ struct NegotiatorTest < ASPEC::TestCase
|
|||
{"application/hal+json", {"application/ld+json", "application/hal+json", "application/xml", "text/xml", "application/json", "text/html"}, {"application/hal+json", nil}},
|
||||
}
|
||||
end
|
||||
|
||||
def test_ordered_elements_exception_handling : Nil
|
||||
expect_raises ArgumentError, "The header string should not be empty." do
|
||||
@negotiator.ordered_elements ""
|
||||
end
|
||||
end
|
||||
|
||||
@[DataProvider("test_ordered_elements_data_provider")]
|
||||
def test_ordered_elements(header : String, expected : Indexable(String)) : Nil
|
||||
elements = @negotiator.ordered_elements header
|
||||
|
||||
expected.each_with_index do |element, idx|
|
||||
elements[idx].should be_a ANG::Accept
|
||||
element.should eq elements[idx].value
|
||||
end
|
||||
end
|
||||
|
||||
def test_ordered_elements_data_provider : Tuple
|
||||
{
|
||||
{"/qwer", [] of String}, # Invalid
|
||||
{"text/html, text/xml", {"text/html", "text/xml"}}, # Ordered as given if no quality modifier
|
||||
{"text/html;q=0.3, text/html;q=0.7", {"text/html;q=0.7", "text/html;q=0.3"}}, # Ordered by quality modifier
|
||||
{"text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5", {"text/html;level=1", "text/html;q=0.7", "*/*;q=0.5", "text/html;level=2;q=0.4", "text/*;q=0.3"}}, # Ordered by quality modifier; one without wins
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,13 @@
|
|||
abstract class Athena::Negotiation::AbstractNegotiator
|
||||
private record OrderKey, quality : Float32, index : Int32, value : String do
|
||||
include Comparable(self)
|
||||
|
||||
def <=>(other : self) : Int32
|
||||
return @index <=> other.index if @quality == other.quality
|
||||
@quality > other.quality ? -1 : 1
|
||||
end
|
||||
end
|
||||
|
||||
private abstract def create_header(header : String) : ANG::BaseAccept
|
||||
|
||||
def best(header : String, priorities : Indexable(String), strict : Bool = false) : ANG::BaseAccept?
|
||||
|
@ -28,6 +37,28 @@ abstract class Athena::Negotiation::AbstractNegotiator
|
|||
match.nil? ? nil : accepted_priorties[match.index]
|
||||
end
|
||||
|
||||
def ordered_elements(header : String) : Array(ANG::BaseAccept)
|
||||
raise ArgumentError.new "The header string should not be empty." if header.blank?
|
||||
|
||||
elements = Array(ANG::BaseAccept).new
|
||||
order_keys = Array(OrderKey).new
|
||||
|
||||
idx = 0
|
||||
self.parse_header(header) do |h|
|
||||
element = self.create_header h
|
||||
elements << element
|
||||
order_keys << OrderKey.new element.quality, idx, element.value
|
||||
rescue ex
|
||||
# skip
|
||||
ensure
|
||||
idx += 1
|
||||
end
|
||||
|
||||
order_keys.sort!.map do |ok|
|
||||
elements[ok.index]
|
||||
end
|
||||
end
|
||||
|
||||
protected def match(header : ANG::BaseAccept, priority : ANG::BaseAccept, index : Int32) : ANG::AcceptMatch?
|
||||
accept_type = header.type
|
||||
priority_type = priority.type
|
||||
|
@ -43,7 +74,7 @@ abstract class Athena::Negotiation::AbstractNegotiator
|
|||
|
||||
private def parse_header(header : String, & : String ->) : Nil
|
||||
header.scan /(?:[^,\"]*+(?:"[^"]*+\")?)+[^,\"]*+/ do |match|
|
||||
yield match[0] unless match[0].blank?
|
||||
yield match[0].strip unless match[0].blank?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -11,8 +11,5 @@ require "./exceptions/*"
|
|||
alias ANG = Athena::Negotiation
|
||||
|
||||
module Athena::Negotiation
|
||||
class_getter(negotiator) { ANG::Negotiator.new }
|
||||
end
|
||||
|
||||
# n = ANG::Negotiator.new
|
||||
|
||||
# pp n.best "text/html; charset=UTF-8, application/pdf", ["text/html"]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue