Subject: | HTTP::Negotiate checks prefixes the wrong way round |
Ticket http://rt.cpan.org/Public/Bug/Display.html?id=13275 (and its
patch) is the reverse of what the HTTP specification states.
Firstly, a quick script to show the issue (in the same style as ticket
13275):
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
use HTTP::Negotiate qw(choose);
use HTTP::Headers;
use Data::Dumper;
my @variants = (
[ 'English', undef, undef, undef, undef, 'en-gb', undef ],
[ 'Norwegian', undef, undef, undef, undef, 'nb', undef ],
);
local $HTTP::Negotiate::DEBUG = 1;
my @preferences = choose(\@variants,
HTTP::Headers->new('Accept-Language' => 'en,nb;q=0.1'));
print Dumper @preferences;
This should return the English variant first, but returns the Norwegian
variant.
The HTTP specification states: "A language-range [in an Accept-Language
request header] matches a language-tag [in a variant] if it exactly
equals the tag, or if it exactly equals a prefix of the tag such that
the first tag character following the prefix is "-"." - ie. the request
can be a prefix of the document language, not the other way round which
the index() line of Negotiate.pm is currently doing.
This is confirmed by the Apache documentation at
http://httpd.apache.org/docs/2.0/en/content-negotiation.html#exceptions
which says: "For example, if a client requests documents with the
language en-GB for British English, the server is not normally allowed
by the HTTP/1.1 standard to match that against a document that is marked
as simply en. (Note that it is almost surely a configuration error to
include en-GB and not en in the Accept-Language header, since it is very
unlikely that a reader understands British English, but doesn't
understand English in general. Unfortunately, many current clients have
default configurations that resemble this.)"
This is precisely the situation in ticket 13275, where actually
HTTP::Negotiate was doing the correct thing in returning the
Non-Specific option. The fix for this issue is simply to reverse the
patch supplied for ticket 13275.
I realise (if you read on in the Apache documentation) that Apache has
made the decision to implicitly add parent languages with low quality
levels, but I do not think a low-level module such as HTTP::Negotiate
should do this, it should be up to the caller.