Use Ref::Util where appropriate
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine.pm
index e4deb9e..5c51dcb 100644 (file)
@@ -13,6 +13,7 @@ use Catalyst::EngineLoader;
 use Encode 2.21 'decode_utf8', 'encode', 'decode';
 use Plack::Request::Upload;
 use Hash::MultiValue;
+use Ref::Util qw(is_plain_arrayref is_plain_globref is_plain_hashref);
 use namespace::clean -except => 'meta';
 use utf8;
 
@@ -112,7 +113,7 @@ sub finalize_body {
                     $body = ["$body"]; 
                 }
             } elsif(ref $body) {
-                if( (ref($body) eq 'GLOB') or (ref($body) eq 'ARRAY')) {
+                if( (is_plain_globref($body)) or (is_plain_arrayref($body))) {
                   # Again, PSGI can just accept this, no transform needed.  We don't officially
                   # document the body as arrayref at this time (and there's not specific test
                   # cases.  we support it because it simplifies some plack compatibility logic
@@ -144,7 +145,7 @@ sub finalize_body {
 
         if(my $body = $res->body) {
 
-          if ( blessed($body) && $body->can('read') or ref($body) eq 'GLOB' ) {
+          if ( blessed($body) && $body->can('read') or is_plain_globref($body) ) {
 
               ## In this case we have no choice and will fall back on the old
               ## manual streaming stuff.  Not optimal.  This is deprecated as of 5.900560+
@@ -159,11 +160,11 @@ sub finalize_body {
           }
           else {
               
-              # Case where body was set afgter calling ->write.  We'd prefer not to
+              # Case where body was set after calling ->write.  We'd prefer not to
               # support this, but I can see some use cases with the way most of the
-              # views work.
-
-              $self->write($c, $body );
+              # views work. Since body has already been encoded, we need to do
+              # an 'unencoded_write' here.
+              $self->unencoded_write( $c, $body );
           }
         }
 
@@ -233,7 +234,7 @@ sub _dump_error_page_element {
     # This is fugly, but the metaclass is _HUGE_ and demands waaay too much
     # scrolling. Suggestions for more pleasant ways to do this welcome.
     local $val->{'__MOP__'} = "Stringified: "
-        . $val->{'__MOP__'} if ref $val eq 'HASH' && exists $val->{'__MOP__'};
+        . $val->{'__MOP__'} if is_plain_hashref($val) && exists $val->{'__MOP__'};
 
     my $text = encode_entities( dump( $val ));
     sprintf <<"EOF", $name, $text;
@@ -443,7 +444,7 @@ sub finalize_uploads {
     foreach my $key (keys %{ $request->uploads }) {
         my $upload = $request->uploads->{$key};
         unlink grep { -e $_ } map { $_->tempname }
-          (ref $upload eq 'ARRAY' ? @{$upload} : ($upload));
+          (is_plain_arrayref($upload) ? @{$upload} : ($upload));
     }
 
 }
@@ -574,15 +575,18 @@ sub prepare_query_parameters {
     my ($self, $c) = @_;
     my $env = $c->request->env;
     my $do_not_decode_query = $c->config->{do_not_decode_query};
-    my $default_query_encoding = $c->config->{default_query_encoding} || 
-      ($c->config->{decode_query_using_global_encoding} ?
-        $c->encoding : 'UTF-8');
 
+    my $old_encoding;
+    if(my $new = $c->config->{default_query_encoding}) {
+      $old_encoding = $c->encoding;
+      $c->encoding($new);
+    }
+
+    my $check = $c->config->{do_not_check_query_encoding} ? undef :$c->_encode_check;
     my $decoder = sub {
       my $str = shift;
       return $str if $do_not_decode_query;
-      return $str unless $default_query_encoding;
-      return decode( $default_query_encoding, $str);
+      return $c->_handle_param_unicode_decoding($str, $check);
     };
 
     my $query_string = exists $env->{QUERY_STRING}
@@ -606,6 +610,7 @@ sub prepare_query_parameters {
         split /[&;]+/, $query_string
     );
 
+    $c->encoding($old_encoding) if $old_encoding;
     $c->request->query_parameters( $c->request->_use_hash_multivalue ? $p : $p->mixed );
 }
 
@@ -650,10 +655,10 @@ sub prepare_uploads {
     my $uploads = $request->_body->upload;
     my $parameters = $request->parameters;
     foreach my $name (keys %$uploads) {
-        $name = $c->_handle_unicode_decoding($name) if $enc;
         my $files = $uploads->{$name};
+        $name = $c->_handle_unicode_decoding($name) if $enc;
         my @uploads;
-        for my $upload (ref $files eq 'ARRAY' ? @$files : ($files)) {
+        for my $upload (is_plain_arrayref($files) ? @$files : ($files)) {
             my $headers = HTTP::Headers->new( %{ $upload->{headers} } );
             my $filename = $upload->{filename};
             $filename = $c->_handle_unicode_decoding($filename) if $enc;
@@ -675,7 +680,7 @@ sub prepare_uploads {
         my @filenames = map { $_->{filename} } @uploads;
         # append, if there's already params with this name
         if (exists $parameters->{$name}) {
-            if (ref $parameters->{$name} eq 'ARRAY') {
+            if (is_plain_arrayref($parameters->{$name})) {
                 push @{ $parameters->{$name} }, @filenames;
             }
             else {
@@ -700,6 +705,20 @@ sub write {
     $c->response->write($buffer);
 }
 
+=head2 $self->unencoded_write($c, $buffer)
+
+Writes the buffer to the client without encoding. Necessary for
+already encoded buffers. Used when a $c->write has been done
+followed by $c->res->body.
+
+=cut
+
+sub unencoded_write {
+    my ( $self, $c, $buffer ) = @_;
+
+    $c->response->unencoded_write($buffer);
+}
+
 =head2 $self->read($c, [$maxlength])
 
 Reads from the input stream by calling C<< $self->read_chunk >>.
@@ -746,7 +765,7 @@ sub run {
     # FIXME - we should stash the options in an attribute so that custom args
     # like Gitalist's --git_dir are possible to get from the app without stupid tricks.
     my $server = pop @args if (scalar @args && blessed $args[-1]);
-    my $options = pop @args if (scalar @args && ref($args[-1]) eq 'HASH');
+    my $options = pop @args if (scalar @args && is_plain_hashref($args[-1]));
     # Back compat hack for applications with old (non Catalyst::Script) scripts to work in FCGI.
     if (scalar @args && !ref($args[0])) {
         if (my $listen = shift @args) {