Improve performance by skipping body processing if we don't have Content-Length
Andy Grundman [Fri, 23 Feb 2007 05:54:42 +0000 (05:54 +0000)]
Changes
lib/Catalyst.pm
lib/Catalyst/Engine.pm
lib/Catalyst/Request.pm

diff --git a/Changes b/Changes
index e79992e..e5754bd 100644 (file)
--- a/Changes
+++ b/Changes
@@ -5,7 +5,8 @@ This file documents the revision history for Perl extension Catalyst.
         - Don't ignore file uploads if form contains a text field with the same name.
           (Carl Franks)
         - Support restart_delay of 0 (for use in the POE engine).
-        - ...
+        - Skip body processing if we don't have a Content-Length header.
+          Results in about a 9% performance increase when handling GET/HEAD requests.
 
 5.7006   2006-11-03 14.18
         - Updated manifest
index 02af3c1..e73e2c6 100644 (file)
@@ -61,7 +61,7 @@ __PACKAGE__->response_class('Catalyst::Response');
 
 # Remember to update this in Catalyst::Runtime as well!
 
-our $VERSION = '5.7006';
+our $VERSION = '5.7007';
 
 sub import {
     my ( $class, @arguments ) = @_;
index d0c97b3..01b60c1 100644 (file)
@@ -312,29 +312,35 @@ sets up the L<Catalyst::Request> object body using L<HTTP::Body>
 
 sub prepare_body {
     my ( $self, $c ) = @_;
+    
+    my $length = $c->request->header('Content-Length') || 0;
 
-    $self->read_length( $c->request->header('Content-Length') || 0 );
-    my $type = $c->request->header('Content-Type');
+    $self->read_length( $length );
 
-    unless ( $c->request->{_body} ) {
-        $c->request->{_body} = HTTP::Body->new( $type, $self->read_length );
-        $c->request->{_body}->{tmpdir} = $c->config->{uploadtmp}
-          if exists $c->config->{uploadtmp};
-    }
-
-    if ( $self->read_length > 0 ) {
+    if ( $length > 0 ) {
+        unless ( $c->request->{_body} ) {
+            my $type = $c->request->header('Content-Type');
+            $c->request->{_body} = HTTP::Body->new( $type, $length );
+            $c->request->{_body}->{tmpdir} = $c->config->{uploadtmp}
+              if exists $c->config->{uploadtmp};
+        }
+        
         while ( my $buffer = $self->read($c) ) {
             $c->prepare_body_chunk($buffer);
         }
 
         # paranoia against wrong Content-Length header
-        my $remaining = $self->read_length - $self->read_position;
+        my $remaining = $length - $self->read_position;
         if ( $remaining > 0 ) {
             $self->finalize_read($c);
             Catalyst::Exception->throw(
-                "Wrong Content-Length value: " . $self->read_length );
+                "Wrong Content-Length value: $length" );
         }
     }
+    else {
+        # Defined but will cause all body code to be skipped
+        $c->request->{_body} = 0;
+    }
 }
 
 =head2 $self->prepare_body_chunk($c)
@@ -357,6 +363,9 @@ Sets up parameters from body.
 
 sub prepare_body_parameters {
     my ( $self, $c ) = @_;
+    
+    return unless $c->request->{_body};
+    
     $c->request->body_parameters( $c->request->{_body}->param );
 }
 
@@ -476,6 +485,9 @@ sub prepare_request { }
 
 sub prepare_uploads {
     my ( $self, $c ) = @_;
+    
+    return unless $c->request->{_body};
+    
     my $uploads = $c->request->{_body}->upload;
     for my $name ( keys %$uploads ) {
         my $files = $uploads->{$name};
index 7bebb4c..40825b7 100644 (file)
@@ -146,6 +146,9 @@ C<application/x-www-form-urlencoded> or C<multipart/form-data>.
 sub body {
     my ( $self, $body ) = @_;
     $self->{_context}->prepare_body;
+    
+    return unless $self->{_body};
+    
     $self->{_body}->body($body) if $body;
     return $self->{_body}->body;
 }