Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
added support for MIME type prioritization to Mojolicious::Types
  • Loading branch information
kraih committed Dec 14, 2012
1 parent e2ae7d4 commit eaf1402
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 15 deletions.
5 changes: 5 additions & 0 deletions Changes
@@ -1,4 +1,9 @@

3.67 2012-12-15
- Added support for MIME type prioritization to Mojolicious::Types.
- Improved respond_to to prioritize multiple MIME types if the
X-Requested-With header is set to the value "XMLHttpRequest".

3.66 2012-12-14
- Added request_ok method to Test::Mojo.
- Improved documentation.
Expand Down
2 changes: 1 addition & 1 deletion lib/Mojolicious.pm
Expand Up @@ -38,7 +38,7 @@ has static => sub { Mojolicious::Static->new };
has types => sub { Mojolicious::Types->new };

our $CODENAME = 'Rainbow';
our $VERSION = '3.66';
our $VERSION = '3.67';

sub AUTOLOAD {
my $self = shift;
Expand Down
8 changes: 5 additions & 3 deletions lib/Mojolicious/Controller.pm
Expand Up @@ -281,10 +281,11 @@ sub respond_to {

# Detect formats
my $app = $self->app;
my @formats = @{$app->types->detect($self->req->headers->accept)};
my $req = $self->req;
my @formats = @{$app->types->detect($req->headers->accept, $req->is_xhr)};
my $stash = $self->stash;
unless (@formats) {
my $format = $stash->{format} || $self->req->param('format');
my $format = $stash->{format} || $req->param('format');
push @formats, $format ? $format : $app->renderer->default_format;
}

Expand Down Expand Up @@ -788,7 +789,8 @@ Get L<Mojo::Message::Response> object from L<Mojo::Transaction/"res">.
Automatically select best possible representation for resource from C<Accept>
request header, C<format> stash value or C<format> GET/POST parameter,
defaults to rendering an empty C<204> response. Unspecific C<Accept> request
headers that contain more than one MIME type are currently ignored, since
headers that contain more than one MIME type are currently ignored, unless the
C<X-Requested-With> header is set to the value C<XMLHttpRequest>, since
browsers often don't really know what they actually want.
$c->respond_to(
Expand Down
31 changes: 20 additions & 11 deletions lib/Mojolicious/Types.pm
Expand Up @@ -33,16 +33,25 @@ has types => sub {
};

sub detect {
my ($self, $accept) = @_;
my ($self, $accept, $prioritize) = @_;

# Detect extensions from MIME type
return [] unless (($accept || '') =~ /^([^,]+?)(?:\;[^,]*)*$/);
my $type = lc $1;
# Extract and prioritize MIME types
my %types;
for my $type (split /,/, $accept // '') {
next unless $type =~ /^\s*([^,; ]+)(?:.*\;\s*q=([\d.]+))?.*$/i;
$types{lc $1} = $2 // 1;
}
my @types = sort { $types{$b} <=> $types{$a} } keys %types;
return [] if !$prioritize && @types > 1;

# Detect extensions from MIME types
my @exts;
my $types = $self->types;
for my $ext (sort keys %$types) {
my @types = ref $types->{$ext} ? @{$types->{$ext}} : ($types->{$ext});
$type eq $_ and push @exts, $ext for map { s/\;.*$//; lc $_ } @types;
for my $type (@types) {
my $types = $self->types;
for my $ext (sort keys %$types) {
my @types = ref $types->{$ext} ? @{$types->{$ext}} : ($types->{$ext});
$type eq $_ and push @exts, $ext for map { s/\;.*$//; lc $_ } @types;
}
}

return \@exts;
Expand Down Expand Up @@ -122,10 +131,10 @@ the following ones.
=head2 C<detect>
my $exts = $types->detect('application/json;q=9');
my $exts = $types->detect('text/html, application/json;q=9', 1);
Detect file extensions from C<Accept> header value. Unspecific values that
contain more than one MIME type are currently ignored, since browsers often
don't really know what they actually want.
Detect file extensions from C<Accept> header value, prioritization of
unspecific values that contain more than one MIME type is disabled by default.
# List detected extensions
say for @{$types->detect('application/json')};
Expand Down
7 changes: 7 additions & 0 deletions t/mojolicious/restful_lite_app.t
Expand Up @@ -460,4 +460,11 @@ $t->get_ok('/rest?format=html' => {Accept => $chrome})->status_is(200)
->content_type_is('text/html;charset=UTF-8')
->text_is('html > body', 'works');

# GET /rest (jQuery Ajax)
my $jquery = 'application/json, text/javascript, */*; q=0.01';
$t->get_ok(
'/rest' => {Accept => $jquery, 'X-Requested-With' => 'XMLHttpRequest'})
->status_is(200)->content_type_is('application/json')
->json_content_is({just => 'works'});

done_testing();
9 changes: 9 additions & 0 deletions t/mojolicious/types.t
Expand Up @@ -66,4 +66,13 @@ is $t->type('json'), 'application/json', 'right type';
is $t->type('htm'), 'text/html', 'right type';
is $t->type('html'), 'text/html;charset=UTF-8', 'right type';

# Prioritize
is_deeply $t->detect('text/plain', 1), ['txt'], 'right formats';
is_deeply $t->detect('TEXT/HTML;V=1.0; q=0.8 ; foo=bar', 1), ['htm', 'html'],
'right formats';
is_deeply $t->detect('TEXT/HTML;Q=0.8,text/plain;Q=0.9', 1),
['txt', 'htm', 'html'], 'right formats';
is_deeply $t->detect(' TEXT/HTML , text/plain;Q=0.9', 1),
['htm', 'html', 'txt'], 'right formats';

done_testing();

0 comments on commit eaf1402

Please sign in to comment.