From: John Napiorkowski Date: Mon, 18 Jul 2016 21:00:43 +0000 (-0500) Subject: Merge branch 'melmothx-invalid-get-param-unicode' into unicode-exception-issue X-Git-Tag: 5.90110~3 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=commitdiff_plain;h=33d3ae66457093bf400181b1a8145460257fc563;hp=9206d78d3c3c9439fcbc0b9dd79c552beebe5ff5 Merge branch 'melmothx-invalid-get-param-unicode' into unicode-exception-issue --- diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index ecaeb94..b085a6c 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -2466,9 +2466,6 @@ sub prepare { # VERY ugly and probably shouldn't rely on ->finalize actually working catch { # failed prepare is always due to an invalid request, right? - $c->response->status(400); - $c->response->content_type('text/plain'); - $c->response->body('Bad Request'); # Note we call finalize and then die here, which escapes # finalize being called in the enclosing block.. # It in fact couldn't be called, as we don't return $c.. @@ -2476,8 +2473,20 @@ sub prepare { # breaking compat for people doing crazy things (we should set # the 400 and just return the ctx here IMO, letting finalize get called # above... - $c->finalize; - die $_; + if ( $c->_handle_http_exception($_) ) { + foreach my $err (@{$c->error}) { + $c->log->error($err); + } + $c->clear_errors; + $c->log->_flush if $c->log->can('_flush'); + $_->can('rethrow') ? $_->rethrow : croak $_; + } else { + $c->response->status(400); + $c->response->content_type('text/plain'); + $c->response->body('Bad Request'); + $c->finalize; + die $_; + } }; $c->log_request; @@ -3564,14 +3573,31 @@ sub setup_encoding { Hook to let you customize how encoding errors are handled. By default we just throw an exception. Receives a hashref of debug information. -Example: +Example of call: $c->handle_unicode_encoding_exception({ param_value => $value, error_msg => $_, - encoding_step => 'params', + encoding_step => 'params', }); +You can override this for custom handling of unicode errors. If you want a +custom response here, one approach is to throw an HTTP style exception: + + sub handle_unicode_encoding_exception { + my ($c, $params) = @_; + HTTP::Exception::BAD_REQUEST->throw(status_message=>$params->{error_msg}); + } + +Alternatively you can 'catch' the error, stash it and write handling code later +in your application: + + sub handle_unicode_encoding_exception { + my ($c, $params) = @_; + $c->stash(BAD_UNICODE_DATA=>$params); + return 1; + } + =cut sub handle_unicode_encoding_exception { diff --git a/t/unicode-exception-bug.t b/t/unicode-exception-bug.t new file mode 100644 index 0000000..14031b0 --- /dev/null +++ b/t/unicode-exception-bug.t @@ -0,0 +1,76 @@ +use strict; +use warnings; +use Test::More; + +BEGIN { + package TestApp::Exception; + $INC{'TestApp/Exception.pm'} = __FILE__; + + sub new { + my ($class, $code, $headers, $body) = @_; + return bless +{res => [$code, $headers, $body]}, $class; + } + + sub throw { die shift->new(@_) } + + sub as_psgi { + my ($self, $env) = @_; + my ($code, $headers, $body) = @{$self->{res}}; + + return [$code, $headers, $body]; # for now + + return sub { + my $responder = shift; + $responder->([$code, $headers, $body]); + }; + } + + package TestApp::Controller::Root; + $INC{'TestApp/Controller/Root.pm'} = __FILE__; + + use Moose; + use MooseX::MethodAttributes; + extends 'Catalyst::Controller'; + + sub main :Path('') :Args(1) { + my ($self, $c, $arg) = @_; + $c->res->body('

OK

'); + $c->res->content_type('text/html'); + } + + TestApp::Controller::Root->config(namespace => ''); +} + +{ + package TestApp; + $INC{'TestApp.pm'} = __FILE__; + + use Catalyst; + use TestApp::Exception; + + sub handle_unicode_encoding_exception { + my ( $self, $param_value, $error_msg ) = @_; + TestApp::Exception->throw( + 200, ['content-type'=>'text/plain'], ['Bad unicode data']); + } + + __PACKAGE__->setup; +} + + +use Catalyst::Test 'TestApp'; + +{ + my $res = request('/ok'); + is ($res->status_line, "200 OK"); + is ($res->content, '

OK

'); +} + +{ + my $res = request('/%E2%C3%83%C6%92%C3%8'); + is ($res->content, 'Bad unicode data'); +} + +done_testing; + +#TestApp->to_app;