root/lang/perl/Catalyst-Plugin-XSendFile/trunk/lib/Catalyst/Plugin/XSendFile.pm @ 28476

Revision 28476, 4.8 kB (checked in by daisuke, 4 years ago)

import from unknownplace.org

  • Property svn:keywords set to Id
Line 
1package Catalyst::Plugin::XSendFile;
2use strict;
3use warnings;
4use base qw/Class::Data::Inheritable/;
5
6use Catalyst::Utils;
7use File::Temp qw/tempdir tempfile/;
8use File::stat;
9use NEXT;
10use Path::Class qw/file/;
11use Scalar::Util qw/blessed/;
12use bytes;
13
14our $VERSION = '0.03_001';
15
16=head1 NAME
17
18Catalyst::Plugin::XSendFile - Catalyst plugin for lighttpd's X-Sendfile.
19
20=head1 SYNOPSIS
21
22    use Catalyst qw/XSendFile/;
23   
24    # manual send file
25    sub show : Path('/files') {
26        my ( $self, $c, $filename ) = @_;
27   
28        # unless login, it shows 403 forbidden screen
29        $c->res->status(403);
30        $c->stash->{template} = 'error-403.tt';
31   
32        # serving a static file only when user logged in.
33        if ($c->user) {
34            $c->res->sendfile( "/path/to/$filename" );
35        }
36    }
37   
38   
39    # auto using x-send-tempfile on large content serving
40    MyApp->config->{sendfile}{tempdir} = '/dev/shm';
41
42=head1 NOTICE
43
44B<This developer version of module requires lighttpd 1.5.0 (r1477) or above.>
45
46=head1 DESCRIPTION
47
48lighty's X-Sendfile feature is great.
49
50If you use lighttpd + fastcgi, you can show files only set X-Sendfile header like below:
51
52    $c->res->header( 'X-LIGHTTPD-send-file' => $filename );
53
54This feature is especially great for serving static file on authentication area.
55
56And with this plugin, you can use:
57
58    $c->res->sendfile( $filename );
59
60instead of above.
61
62But off-course you know, this feature doesn't work on Catalyst Test Server (myapp_server.pl).
63So this module also provide its emulation when your app on test server.
64
65=head1 SERVE LARGE CONTENT BY X-LIGHTTPD-send-tempfile
66
67Latest version of lighttpd (1.5.0) also support X-LIGHTTPD-send-tempfile, that is almost same to X-LIGHTTPD-send-file except deleting sending file when server sent file.
68
69This module automatically use this feature when content length is above 16kbytes.
70
71And for more performance, you need to set tempdir ($c->config->{sendfile}{tempdir}) on tmpfs (/dev/shm).
72
73See below urls for detail.
74
75=head1 SEE ALSO
76
77lighty's life - X-Sendfile
78http://blog.lighttpd.net/articles/2006/07/02/x-sendfile
79
80Faster - FastCGI
81http://blog.lighttpd.net/articles/2006/11/29/faster-fastcgi
82
83=head1 NOTICE
84
85To use it you have to set "allow-x-sendfile" option enabled in your fastcgi configuration.
86
87    "allow-x-send-file" => "enable",
88
89or on 1.5.0:
90
91    proxy-core.allow-x-sendfile = "enable"
92
93=head1 EXTENDED_METHODS
94
95=head2 setup
96
97Setup tempdir for x-send-tempfile
98
99=cut
100
101sub setup {
102    my $c = shift;
103    $c->NEXT::setup(@_);
104
105    my $tempdir = $c->config->{sendfile}{tempdir}
106      || Catalyst::Utils::class2tempdir($c, 1);
107
108    __PACKAGE__->mk_classdata(
109        _sendfile_tempdir => tempdir( DIR => $tempdir, CLEANUP => 1 ) );
110
111    $c;
112}
113
114=head2 finalize_headers
115
116Serving large (16kbytes) content via X-LIGHTTPD-send-tempfile.
117
118=cut
119
120sub finalize_headers {
121    my $c = shift;
122
123    my $engine = $ENV{CATALYST_ENGINE} || '';
124
125    # X-Sendfile emulation for test server.
126    if ( $engine =~ /^HTTP/ ) {
127        if ( my $sendfile = file( $c->res->header('X-LIGHTTPD-send-file') ) ) {
128            $c->res->headers->remove_header('X-LIGHTTPD-send-file');
129            if ( $sendfile->stat && -f _ && -r _ ) {
130                $c->res->body( $sendfile->openr );
131            }
132        }
133    }
134    elsif ( $engine eq 'FastCGI' ) {
135
136        if ( my $body = $c->res->body ) {
137            my ( $fh, $tempfile ) = tempfile( DIR => $c->_sendfile_tempdir );
138
139            if ( blessed($body) && $body->can('read') or ref($body) eq 'GLOB' ) {
140                my $stat = stat $body;
141                if ( $stat and $stat->size >= 16*1024 ) {
142                    while ( !eof $body ) {
143                        read $body, my ($buffer), 4096;
144                        last unless $fh->write($buffer);
145                    }
146                    close $body;
147                    close $fh;
148
149                    $c->res->send_tempfile($tempfile);
150                }
151            }
152            elsif ( bytes::length($body) >= 16*1024 ) {
153                $fh->write($body);
154                $fh->close;
155
156                $c->res->send_tempfile($tempfile);
157            }
158        }
159    }
160
161    $c->NEXT::finalize_headers;
162}
163
164=head1 EXTENDED_RESPONSE_METHODS
165
166=head2 sendfile
167
168Set X-LIGHTTPD-send-file header easily.
169
170=cut
171
172{
173    package # avoid PAUSE Indexer
174        Catalyst::Response;
175
176    sub sendfile {
177        my ($self, $file) = @_;
178        $self->{body} = '';
179        $self->header( 'X-LIGHTTPD-send-file' => $file );
180    }
181
182    sub send_tempfile {
183        my ($self, $file) = @_;
184        $self->{body} = '';
185        $self->header( 'X-LIGHTTPD-send-tempfile' => $file );
186    }
187}
188
189=head1 AUTHOR
190
191Daisuke Murase <typester@cpan.org>
192
193=head1 COPYRIGHT
194
195This program is free software; you can redistribute
196it and/or modify it under the same terms as Perl itself.
197
198The full text of the license can be found in the
199LICENSE file included with this module.
200
201=cut
202
2031;
Note: See TracBrowser for help on using the browser.