mjackson / rack-accept

HTTP Accept* for Ruby/Rack
http://mjackson.github.com/rack-accept
47 stars 16 forks source link

negotiation algorythm should respect media-range precedence #2

Closed SSDany closed 14 years ago

SSDany commented 14 years ago

Your statement (issue1) means that you'll never respect precedence of the media range during negotiation.

But RFC says:

The media type quality factor associated with a given type is
determined by finding the media range with the *highest precedence*
which matches that type.

But, well, nobody cares ;)

mjackson commented 14 years ago

On the contrary, that's exactly what matches does. It finds all media ranges that match the given type and orders them by precedence. Precedence != quality factor.

SSDany commented 14 years ago

Yes, Precedence != quality factor. But precedence of media range inter alia determines the media type quality factor. Lets take a "text/*, text/html" header and "text/html" media type. Both media ranges applies to it, but the second one has precedence. Then, lets take "text/plain" media type. The first media range applies to it. So, who wins? since qvalues of both media ranges are equal (1.000), "text/html" (as a media type, corresponding to the media range with a higher precedence), wins.

"text/*;q=1, text/html;q=1"
"text/html;q=1, text/*;q=1" #sorted by qvalue and precedence

In this case, order of available media-types doesn't matter. Simply because "text/html" is the first one in the list of preferred media types.

mjackson commented 14 years ago

Media types do not have a quality factor (qvalue), just ranges. The text/html range only takes precedence over text/* in some context, like when you're trying to find the best matches for a particular media type.

So, to figure out the qvalue for a given media type, the algorithm first finds all matching ranges (regardless of that particular range's qvalue) and orders them by precedence. It then returns the qvalue from the range with the highest precedence.

If I am misunderstanding something, perhaps you could write a small test that demonstrates the error?

SSDany commented 14 years ago
m = Rack::Accept::MediaType.new('text/*, text/html')
m.best_of(['text/xml','text/html']) #=> "text/xml"

it's not wrong, of course (at least, "text/xml" is acceptable), but I prefer more perfectionistic algorithm. Anyway, thanks for discussion.

mjackson commented 14 years ago

In this example both "text/xml" and "text/html" have a qvalue of 1. Therefore, neither one is "more acceptable" according to the client and best_of should return the first value that was passed in (and it does).

SSDany commented 14 years ago

Already implemented, as an optional way to detect the best media-type. Thanx a lot.