diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 832c7c40..33d1dbad 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -4088,7 +4088,10 @@ sub default_data_handlers { my $slurped; return eval { local $/; - $slurped = $fh->getline; + if ($fh) { + $fh->seek(0,0); # in case it's already been read + $slurped = $fh->getline; + } JSON::MaybeXS::decode_json($slurped); # decode_json does utf8 decoding for us } || Catalyst::Exception->throw(sprintf "Error Parsing POST '%s', Error: %s", (defined($slurped) ? $slurped : 'undef') ,$@); }, diff --git a/t/rewind_filehandle.t b/t/rewind_filehandle.t new file mode 100644 index 00000000..944f4fb7 --- /dev/null +++ b/t/rewind_filehandle.t @@ -0,0 +1,49 @@ +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 auto :Private { + my ($self, $c) = @_; + my $req_body = $c->req->body; + if ($req_body) { + $c->req->body->getline; + } + + return 1; # continue dispatch + } + + sub foo :Local Args(0) POST Consumes(JSON) { + my ($self, $c) =@_; + # try to access the deserialised JSON param via body_params + my $name = $c->req->body_data->{name}; + $c->res->body("Hi, $name!"); + } + + package MyApp; + use Catalyst; + MyApp->setup; +} + +use HTTP::Request::Common; +use Catalyst::Test 'MyApp'; + +{ + # Send POSTed JSON data to our handler that will read the body filehandle + # via $req->body filehandle then call body_params (see GH PR #186) + ok my $res = request POST 'root/foo', + 'Content-Type' => 'application/json', + 'Content' => '{"name": "Jack", "age": 42}'; + + is $res->content, 'Hi, Jack!'; # don't say that on an aeroplane +} + +done_testing();