[Catalyst] Catalyst, REST and Firefox
Jonas Alves
jonas.alves at gmail.com
Thu Jan 17 17:58:59 GMT 2008
On Jan 17, 2008 2:32 PM, Christopher H. Laco <claco at chrislaco.com> wrote:
> I've touched on this before, and posted about it on UP:
> http://use.perl.org/~jk2addict/journal/35411
>
> In a nutshell, Firefox 2.x Accept header totaly screws with the REST
> controller when you use it as a base for View negotiations. If you have
> a default type of text/html pointed to a View::TT, REST will see
> text/xml from Firefox and try and send that instead, based on this header:
>
> text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
>
> What does everyone think about a config option/toggle to tell REST to
> ignore the Accept header, allowing it to fall back to the default
> content-type in config when no Cntent-Type header or content-type params
> are specified?
>
> -=Chris
>
I have a subclass of Action::Serialize that does this:
my $default = $controller->config->{serialize}{default};
my $pcontent_type = $c->req->preferred_content_type;
my $content_types = $c->req->accepted_content_types_qvalue;
my $ordered_content_types = $c->req->accepted_content_types;
my $max_qvalue = $content_types->{$pcontent_type};
my %max_qvalue_content_types = map {
$content_types->{$_} eq $max_qvalue ? ($_ => $default) : ()
} keys %$content_types;
my $content_type = $max_qvalue_content_types{$default}
|| $pcontent_type
|| $c->req->content_type;
And in a subclass of Request::REST mixed with Plugin::Flavour:
sub preferred_content_type {
my $self = shift;
if ($self->flavour) {
my $type = $self->{ext_map}{$self->flavour}
|| $self->_ext_to_type($self->flavour);
return $type;
}
$self->accepted_content_types->[0];
}
sub accepted_content_types_qvalue {
my $self = shift;
return $self->{content_types_qvalue} if $self->{content_types_qvalue};
my %types;
if ($self->method eq "GET" && $self->param('content-type')) {
$types{ $self->param('content-type') } = 2;
}
# This is taken from chansen's Apache2::UploadProgress.
if ( $self->header('Accept') ) {
$self->accept_only(1) unless keys %types;
my $accept_header = $self->header('Accept');
my $counter = 0;
foreach my $pair ( split_header_words($accept_header) ) {
my ( $type, $qvalue ) = @{$pair}[ 0, 3 ];
next if $types{$type};
$qvalue = 1 unless defined $qvalue;
$types{$type} = sprintf '%.3f', $qvalue;
}
}
return $self->{content_types_qvalue} = \%types;
}
That way all works fine. If you add an extension to the uri (like
.json or .xml), it serves that content-type. Else it tries to find the
greater qvalue on the Accept Header and tries to serve that. If it has
more than one content-type with the same max qvalue it tries to find
the default content-type in that list and serve it. If it isn't in the
max qvalue list than it serves the first content-type on that list.
I think that is a sane approach.
--
Jonas
More information about the Catalyst
mailing list