File Coverage

blib/lib/Catalyst/Plugin/Compress.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::Compress;
2              
3 1     1   731 use strict;
  1         2  
  1         38  
4 1     1   230 use Catalyst::Utils;
  0            
  0            
5             use MRO::Compat;
6              
7             our $VERSION = '0.006';
8              
9             my $_method;
10             my %_compression_lib = (
11             gzip => 'Compress::Zlib',
12             deflate => 'Compress::Zlib',
13             bzip2 => 'Compress::Bzip2',
14             );
15              
16             sub _gzip_compress {
17             Compress::Zlib::memGzip(shift);
18             }
19              
20             sub _bzip2_compress {
21             Compress::Bzip2::memBzip(shift);
22             }
23              
24             sub _deflate_compress {
25             my $content = shift;
26             my $result;
27              
28             my ($d, $out, $status);
29             ($d, $status) = Compress::Zlib::deflateInit(
30             -WindowBits => -Compress::Zlib::MAX_WBITS(),
31             );
32             unless ($status == Compress::Zlib::Z_OK()) {
33             die("Cannot create a deflation stream. Error: $status");
34             }
35              
36             ($out, $status) = $d->deflate($content);
37             unless ($status == Compress::Zlib::Z_OK()) {
38             die("Deflation failed. Error: $status");
39             }
40             $result .= $out;
41              
42             ($out, $status) = $d->flush;
43             unless ($status == Compress::Zlib::Z_OK()) {
44             die("Deflation failed. Error: $status");
45             }
46              
47             return $result . $out;
48             }
49              
50             sub setup {
51             my $c = shift;
52             if ($_method = $c->config->{compression_format}) {
53             $_method = 'gzip'
54             if $_method eq 'zlib';
55              
56             my $lib_name = $_compression_lib{$_method};
57             die qq{No compression_format named "$_method"}
58             unless $lib_name;
59             Catalyst::Utils::ensure_class_loaded($lib_name);
60              
61             *_do_compress = \&{"_${_method}_compress"};
62             }
63             if ($c->debug) {
64             $_method
65             ? $c->log->debug(qq{Catalyst::Plugin::Compress sets compression_format to '$_method'})
66             : $c->log->debug(qq{Catalyst::Plugin::Compress has no compression_format config - disabled.});
67             }
68             $c->maybe::next::method(@_);
69             }
70              
71             use List::Util qw(first);
72             sub should_compress_response {
73             my ($self) = @_;
74             my ($ct) = split /;/, $self->res->content_type;
75             my @compress_types = qw(
76             application/javascript
77             application/json
78             application/x-javascript
79             application/xml
80             );
81             return 1
82             if ($ct =~ m{^text/})
83             or ($ct =~ m{\+xml$}
84             or (first { lc($ct) eq $_ } @compress_types));
85             }
86              
87             sub finalize {
88             my $c = shift;
89              
90             if ((not defined $_method)
91             or $c->res->content_encoding
92             or (not $c->res->body)
93             or ($c->res->status != 200)
94             or (not $c->should_compress_response)
95             ) {
96             return $c->maybe::next::method(@_);
97             }
98              
99             my $accept = $c->request->header('Accept-Encoding') || '';
100              
101             unless (index($accept, $_method) >= 0) {
102             return $c->maybe::next::method(@_);
103             }
104              
105             # Hack to support newer Catalyst. We need to invokce the encoding stuff
106             # Now since after the content encoding header is set, we can no longer
107             # call that method. (jnap, to support 590080+)
108             $c->finalize_encoding if($c->can('encoding') and $c->can('clear_encoding'));
109              
110             my $body = $c->res->body;
111             if (ref $body) {
112             eval { local $/; $body = <$body> };
113             die "Unknown type of ref in body."
114             if ref $body;
115             }
116              
117             my $compressed = _do_compress($body);
118             $c->response->body($compressed);
119             $c->response->content_length(length($compressed));
120             $c->response->content_encoding($_method);
121             $c->response->headers->push_header('Vary', 'Accept-Encoding');
122              
123             $c->maybe::next::method(@_);
124             }
125              
126             1;
127              
128             __END__
129              
130             =head1 NAME
131              
132             Catalyst::Plugin::Compress - Compress response
133              
134             =head1 SYNOPSIS
135              
136             use Catalyst qw/Compress/;
137              
138             or (Catalyst pre Unicode Merge, and If you want to use this plugin with
139             L<Catalyst::Plugin::Unicode>.)
140              
141             use Catalyst qw/
142             Unicode
143             Compress
144             /;
145              
146             or (Catalyst 5.90080 and later)
147              
148             use Catalyst qw/
149             Compress
150             /;
151              
152              
153             Remember to specify compression_format with:
154              
155             __PACKAGE__->config(
156             compression_format => $format,
157             );
158              
159             $format can be either gzip bzip2 zlib or deflate. bzip2 is B<*only*> supported
160             by lynx and some other console text-browsers.
161              
162             =head1 DESCRIPTION
163              
164             This module combines L<Catalyst::Plugin::Deflate> L<Catalyst::Plugin::Gzip>
165             L<Catalyst::Plugin::Zlib> into one.
166              
167             It compress response to [gzip bzip2 zlib deflate] if client supports it. In other
168             works the client should send the Accept-Encoding HTTP header with a supported
169             compression like 'gzip'.
170              
171             B<NOTE>: If you are using an older version of L<Catalyst> that requires the Unicode
172             plugin and if you want to use this module with L<Catalyst::Plugin::Unicode>, You
173             B<MUST> load this plugin B<AFTER> L<Catalyst::Plugin::Unicode>.
174              
175             use Catalyst qw/
176             Unicode
177             Compress
178             /;
179              
180             If you don't, You'll get error which is like:
181              
182             [error] Caught exception in engine "Wide character in subroutine entry at
183             /usr/lib/perl5/site_perl/5.8.8/Compress/Zlib.pm line xxx."
184              
185             If you upgrade to any version of L<Catalyst> 5.90080+ the unicode support has been
186             integrated into core code and this plugin is designed to work with that.
187              
188             =head1 INTERNAL METHODS
189              
190             =head2 should_compress_response
191              
192             This method determine wether compressing the reponse using this plugin.
193              
194             =head1 SEE ALSO
195              
196             L<Catalyst>.
197              
198             =head1 AUTHOR
199              
200             Yiyi Hu C<yiyihu@gmail.com>
201              
202             =head1 LICENSE
203              
204             This library is free software. You can redistribute it and/or modify it under
205             the same terms as perl itself.
206              
207             =cut
208