remove regexp for good
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Engine.pm
index ce40740..a5c177a 100644 (file)
@@ -13,6 +13,8 @@ use URI::QueryParam;
 use Plack::Loader;
 use Catalyst::EngineLoader;
 use Encode ();
+use Plack::Request::Upload;
+use Hash::MultiValue;
 use utf8;
 
 use namespace::clean -except => 'meta';
@@ -54,12 +56,21 @@ See L<Catalyst>.
 
 =head2 $self->finalize_body($c)
 
-Finalize body.  Prints the response output.
+Finalize body.  Prints the response output as blocking stream if it looks like
+a filehandle, otherwise write it out all in one go.  If there is no body in
+the response, we assume you are handling it 'manually', such as for nonblocking
+style or asynchronous streaming responses.  You do this by calling L</write>
+several times (which sends HTTP headers if needed) or you close over
+C<< $response->write_fh >>.
+
+See L<Catalyst::Response/write> and L<Catalyst::Response/write_fh> for more.
 
 =cut
 
 sub finalize_body {
     my ( $self, $c ) = @_;
+    return if $c->response->_has_write_fh;
+
     my $body = $c->response->body;
     no warnings 'uninitialized';
     if ( blessed($body) && $body->can('read') or ref($body) eq 'GLOB' ) {
@@ -181,7 +192,6 @@ sub finalize_error {
         $name  = "<h1>$name</h1>";
 
         # Don't show context in the dump
-        $c->req->_clear_context;
         $c->res->_clear_context;
 
         # Don't show body parser in the dump
@@ -325,29 +335,14 @@ sub finalize_error {
 
 =head2 $self->finalize_headers($c)
 
-Abstract method, allows engines to write headers to response
+Allows engines to write headers to response
 
 =cut
 
 sub finalize_headers {
     my ($self, $ctx) = @_;
 
-    # This is a less-than-pretty hack to avoid breaking the old
-    # Catalyst::Engine::PSGI. 5.9 Catalyst::Engine sets a response_cb and
-    # expects us to pass headers to it here, whereas Catalyst::Enngine::PSGI
-    # just pulls the headers out of $ctx->response in its run method and never
-    # sets response_cb. So take the lack of a response_cb as a sign that we
-    # don't need to set the headers.
-
-    return unless ($ctx->response->_has_response_cb);
-
-    my @headers;
-    $ctx->response->headers->scan(sub { push @headers, @_ });
-
-    my $writer = $ctx->response->_response_cb->([ $ctx->response->status, \@headers ]);
-    $ctx->response->_set_writer($writer);
-    $ctx->response->_clear_response_cb;
-
+    $ctx->finalize_headers unless $ctx->response->finalized_headers;
     return;
 }
 
@@ -410,14 +405,17 @@ sub prepare_body_parameters {
 
 =head2 $self->prepare_parameters($c)
 
-sets up parameters from query and post parameters.
+Sets up parameters from query and post parameters.
+If parameters have already been set up will clear
+existing parameters and set up again.
 
 =cut
 
 sub prepare_parameters {
     my ( $self, $c ) = @_;
 
-    $c->request->parameters;
+    $c->request->_clear_parameters;
+    return $c->request->parameters;
 }
 
 =head2 $self->prepare_path($c)
@@ -492,8 +490,16 @@ process the query string and extract query parameters.
 
 sub prepare_query_parameters {
     my ($self, $c) = @_;
-
     my $env = $c->request->env;
+
+    if(my $query_obj = $env->{'plack.request.query'}) {
+         $c->request->query_parameters(
+           $c->request->_use_hash_multivalue ?
+              $query_obj->clone :
+              $query_obj->as_hashref_mixed);
+         return;
+    }
+
     my $query_string = exists $env->{QUERY_STRING}
         ? $env->{QUERY_STRING}
         : '';
@@ -501,7 +507,7 @@ sub prepare_query_parameters {
     # Check for keywords (no = signs)
     # (yes, index() is faster than a regex :))
     if ( index( $query_string, '=' ) < 0 ) {
-        $c->request->query_keywords( $self->unescape_uri($query_string) );
+        $c->request->query_keywords($self->unescape_uri($query_string));
         return;
     }
 
@@ -532,12 +538,16 @@ sub prepare_query_parameters {
             $query{$param} = $value;
         }
     }
-    $c->request->query_parameters( \%query );
+
+    $c->request->query_parameters( 
+      $c->request->_use_hash_multivalue ?
+        Hash::MultiValue->from_mixed(\%query) :
+        \%query);
 }
 
 =head2 $self->prepare_read($c)
 
-prepare to read from the engine.
+Prepare to read by initializing the Content-Length from headers.
 
 =cut
 
@@ -556,6 +566,7 @@ Populate the context object from the request object.
 
 sub prepare_request {
     my ($self, $ctx, %args) = @_;
+    $ctx->log->psgienv($args{env}) if $ctx->log->can('psgienv');
     $ctx->request->_set_env($args{env});
     $self->_set_env($args{env}); # Nasty back compat!
     $ctx->response->_set_response_cb($args{response_cb});
@@ -607,6 +618,18 @@ sub prepare_uploads {
     }
 }
 
+=head2 $self->write($c, $buffer)
+
+Writes the buffer to the client.
+
+=cut
+
+sub write {
+    my ( $self, $c, $buffer ) = @_;
+
+    $c->response->write($buffer);
+}
+
 =head2 $self->read($c, [$maxlength])
 
 Reads from the input stream by calling C<< $self->read_chunk >>.
@@ -634,15 +657,6 @@ sub read_chunk {
     return $ctx->request->read_chunk(@_);
 }
 
-=head2 $self->read_length
-
-The length of input data to be read.  This is obtained from the Content-Length
-header.
-
-=head2 $self->read_position
-
-The amount of input data that has already been read.
-
 =head2 $self->run($app, $server)
 
 Start the engine. Builds a PSGI application and calls the
@@ -682,8 +696,7 @@ sub run {
 
 =head2 build_psgi_app ($app, @args)
 
-Builds and returns a PSGI application closure, wrapping it in the reverse proxy
-middleware if the using_frontend_proxy config setting is set.
+Builds and returns a PSGI application closure. (Raw, not wrapped in middleware)
 
 =cut
 
@@ -695,30 +708,12 @@ sub build_psgi_app {
 
         return sub {
             my ($respond) = @_;
+            confess("Did not get a response callback for writer, cannot continue") unless $respond;
             $app->handle_request(env => $env, response_cb => $respond);
         };
     };
 }
 
-=head2 $self->write($c, $buffer)
-
-Writes the buffer to the client.
-
-=cut
-
-sub write {
-    my ( $self, $c, $buffer ) = @_;
-
-    my $response = $c->response;
-
-    $buffer = q[] unless defined $buffer;
-
-    my $len = length($buffer);
-    $c->res->_writer->write($buffer);
-
-    return $len;
-}
-
 =head2 $self->unescape_uri($uri)
 
 Unescapes a given URI using the most efficient method available.  Engines such
@@ -761,4 +756,6 @@ the same terms as Perl itself.
 
 =cut
 
+__PACKAGE__->meta->make_immutable;
+
 1;