[Catalyst-commits] r13834 - trunk/examples/CatalystAdvent/root/2010/pen

davewood at dev.catalyst.perl.org davewood at dev.catalyst.perl.org
Fri Dec 10 08:34:39 GMT 2010


Author: davewood
Date: 2010-12-10 08:34:38 +0000 (Fri, 10 Dec 2010)
New Revision: 13834

Added:
   trunk/examples/CatalystAdvent/root/2010/pen/xsendfile-inflatecolumn_fs.pod
Log:
added xsendfile+inflateclumn_fs article

Added: trunk/examples/CatalystAdvent/root/2010/pen/xsendfile-inflatecolumn_fs.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2010/pen/xsendfile-inflatecolumn_fs.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2010/pen/xsendfile-inflatecolumn_fs.pod	2010-12-10 08:34:38 UTC (rev 13834)
@@ -0,0 +1,144 @@
+=head1 DBIx::Class::InflateColumn::FS and X-Sendfile
+
+In this article I will explain how to elegantly store user submitted HTML code 
+in the filesystem for later delivery with X-Sendfile.
+
+=head1 Storing pages
+
+We are using L<DBIx::Class::InflateColumn::FS> to store content in the filesystem.
+
+=head2 Setting up your schema result class
+
+Code:
+
+MyApp/Schema/Result/Pages.pm
+
+    __PACKAGE__->load_components(qw/InflateColumn::FS Core/);
+    __PACKAGE__->add_columns(
+        id => {
+            data_type         => 'INT',
+            is_auto_increment => 1,
+        },
+        file => {
+            data_type      => 'TEXT',
+            is_fs_column   => 1,
+            fs_column_path => '/var/www/myapp/root/pages',
+        },
+    );
+
+=head2 Passing the content to the schema
+
+If you pass a filehandle to the C<file> column, filesystem management will be handled by 
+DBIx::Class::InflateColumn::FS. So somewhere in your Controller you probably want code like this:
+
+Code:
+
+MyApp/Controller/Pages.pm
+
+    use IO::File;
+    use Carp;
+
+    sub create :Path('create') Args(0) {
+        my ($self, $c) = @_;
+
+        # user submitted html code in a forms textarea
+        # validate form with module of your choice
+        ...
+
+        my $validated_page_code = ...
+
+        # create a temp file
+        $fh = IO::File->new_tmpfile;
+        print {$fh} $validated_page_code
+            or croak 'Couldn't write to temporary file';
+        close $fh
+            or croak 'Couldn't close temporary file';
+        
+        # store page
+        $c->model('DB::Pages')->create({ file => $fh });
+    }
+
+=head1 Delivering pages
+
+Now that the page is stored in our filesystem let's have a look how to 
+deliver the file using X-Sendfile.
+
+X-Sendfile lets the webserver deal with delivery of static files.
+
+The X-Sendfile features is supported by Apache, Lighttpd and nginx 
+(nginx is calling it X-Accel-Redirect though). Here is an Apache configuration.
+
+First, install mod_xsendfile. On Debian based systems use the package system.
+
+    aptitude install libapache2-mod-xsendfile
+
+then enable the module in your apache configuration
+
+    XSendfile On
+
+Now Apache looks for the presence of a X-Sendfile header and delivers the file 
+referenced in the header.
+
+=head2 Setting the X-Sendfile header. 
+
+You might want to put this code into a Role and let your Controller consume it.
+
+Code:
+
+    sub sendfile {
+        my ($self, $c, $file, $content_type) = @_;
+    
+        my $engine = $ENV{CATALYST_ENGINE} || '';
+    
+        # Catalyst development server
+        if ( $engine =~ /^HTTP/ ) {
+            if ( $file->stat && -f _ && -r _ ) {
+                $c->res->body( $file->openr );
+            }
+        }
+    
+        # Deployment with FastCGI
+        elsif ( $engine eq 'FastCGI' ) {
+            $c->res->header('X-Sendfile', $file);
+            $c->res->body("foo"); # MASSIVE HACK: bypass RenderView
+        }
+    
+        # unknown engine
+        else {
+            die "Unknown engine: " . $engine;
+        }
+    
+        $c->res->content_type($content_type);
+        $c->res->content_length( $file->stat->size );
+        $c->res->status(200);
+        $c->detach;
+    }
+
+=head2 the 'send' action
+
+Also in your controller add a send action that 
+sets the X-Sendfile header for the requested file.
+
+Code:
+
+    sub send : Path('send') Args(1) {
+        my ( $self, $c, $page_id ) = @_;
+        
+        # get the requested page from your model
+        my $page = $c->model('DB::Pages')->find($page_id);
+
+        # display error page if requested page doesn't exist
+        $c->detach('/error404') unless $page;
+        
+        # set X-Sendfile header
+        $self->sendfile($c, $page->file, 'text/html');
+    }
+
+=head1 Further Reading
+
+This article is based on the Catayst Cookbook entry 
+L<Controller With Fileupload|http://wiki.catalystframework.org/wiki/wikicookbook/controllerwithfileupload>.
+
+=head1 AUTHOR
+
+davewood: David Schmidt <davewood at gmx.at>




More information about the Catalyst-commits mailing list