# This file documents the revision history for Perl extension Catalyst.
+5.90078 - 2014-12-30
+ - POD corrections (sergey++)
+ - New configuration option to disable the HTTP Exception passthru feature
+ introduced in 5.90060. You can use this if that feature is causing you
+ trouble. (davewood++);
+ - Some additional helper methods for dealing with errors.
+ - More clear exception when $request->body_data tries to parse malformed POSTed
+ data. Added documentation and tests around this.
+
5.90077 - 2014-11-18
- We store the PSGI $env in Catalyst::Engine for backcompat reasons. Changed
this so that the storage is a weak reference, so that it goes out of scope
$c->error('Something bad happened');
+Calling this will always return an arrayref (if there are no errors it
+will be an empty arrayref.
+
=cut
sub error {
sub has_errors { scalar(@{shift->error}) ? 1:0 }
+=head2 $c->last_error
+
+Returns the most recent error in the stack (the one most recently added...)
+or nothing if there are no errors.
+
+=cut
+
+sub last_error { my ($err, @errs) = @{shift->error}; return $err }
+
+=head2 shift_errors
+
+shifts the most recently added error off the error stack and returns if. Returns
+nothing if there are nomore errors.
+
+=cut
+
+sub shift_errors {
+ my ($self) = @_;
+ my ($err, @errors) = @{$self->error};
+ $self->{error} = \@errors;
+ return $err;
+}
+
sub _comp_search_prefixes {
my $c = shift;
return map $c->components->{ $_ }, $c->_comp_names_search_prefixes(@_);
->can('build_cgi_struct')->($params);
},
'application/json' => sub {
- Class::Load::load_first_existing_class('JSON::MaybeXS', 'JSON')
- ->can('decode_json')->(do { local $/; $_->getline });
- },
+ my ($fh, $req) = @_;
+ my $parser = Class::Load::load_first_existing_class('JSON::MaybeXS', 'JSON');
+ my $slurped;
+ return eval {
+ local $/;
+ $slurped = $fh->getline;
+ $parser->can("decode_json")->($slurped);
+ } || Catalyst::Exception->throw(sprintf "Error Parsing POST '%s', Error: %s", (defined($slurped) ? $slurped : 'undef') ,$@);
+ },
};
}
use Stream::Buffered;
use Hash::MultiValue;
use Scalar::Util;
-
+use Catalyst::Exception;
use Moose;
use namespace::clean -except => 'meta';
sub _build_body_data {
my ($self) = @_;
- my $content_type = $self->content_type;
+
+ # Not sure if these returns should not be exceptions...
+ my $content_type = $self->content_type || return;
+ return unless ($self->method eq 'POST' || $self->method eq 'PUT');
+
my ($match) = grep { $content_type =~/$_/i }
keys(%{$self->data_handlers});
local $_ = $fh;
return $self->data_handlers->{$match}->($fh, $self);
} else {
- return undef;
+ Catalyst::Exception->throw("$content_type is does not have an available data handler");
}
}
method. You may define addition data_handlers via a global configuration
setting. See L<Catalyst\DATA HANDLERS> for more information.
+If the POST is malformed in some way (such as undefined or not content that
+matches the content-type) we raise a L<Catalyst::Exception> with the error
+text as the message.
+
+If the POSTed content type does not match an availabled data handler, this
+will also raise an exception.
+
=head2 $req->body_parameters
Returns a reference to a hash containing body (POST) parameters. Values can
--- /dev/null
+use warnings;
+use strict;
+use Test::More;
+
+# Test case for reported issue when an action consumes JSON but a
+# POST sends nothing we get a hard error
+
+{
+ package MyApp::Controller::Root;
+ $INC{'MyApp/Controller/Root.pm'} = __FILE__;
+
+ use base 'Catalyst::Controller';
+
+ sub bar :Local Args(0) POST Consumes(JSON) {
+ my( $self, $c ) = @_;
+ my $foo = $c->req->body_data;
+ }
+
+ sub end :Private {
+ my( $self, $c ) = @_;
+ my $body = $c->shift_errors;
+ $c->res->body( $body || "No errors");
+ }
+
+ package MyApp;
+ use Catalyst;
+ MyApp->setup;
+}
+
+use HTTP::Request::Common;
+use Catalyst::Test 'MyApp';
+
+{
+ # Test to send no post
+ ok my $res = request POST 'root/bar',
+ 'Content-Type' => 'application/json';
+
+ like $res->content, qr"Error Parsing POST 'undef'";
+}
+
+{
+ # Test to send bad (malformed JSON) post
+ ok my $res = request POST 'root/bar',
+ 'Content-Type' => 'application/json',
+ 'Content' => 'i am not JSON';
+
+ like $res->content, qr/Error Parsing POST 'i am not JSON'/;
+}
+
+{
+ # Test to send bad (malformed JSON) post
+ ok my $res = request POST 'root/bar',
+ 'Content-Type' => 'application/json',
+ 'Content' => '{ "a":"b" }';
+
+ is $res->content, 'No errors';
+}
+
+done_testing();