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   780 use strict;
  1         3  
  1         37  
4 1     1   492 use Catalyst::Utils;
  0            
  0            
5             use MRO::Compat;
6              
7             our $VERSION = '0.005';
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             my $body = $c->res->body;
106             if (ref $body) {
107             eval { local $/; $body = <$body> };
108             die "Unknown type of ref in body."
109             if ref $body;
110             }
111              
112             my $compressed = _do_compress($body);
113             $c->response->body($compressed);
114             $c->response->content_length(length($compressed));
115             $c->response->content_encoding($_method);
116             $c->response->headers->push_header('Vary', 'Accept-Encoding');
117              
118             $c->maybe::next::method(@_);
119             }
120              
121             1;
122              
123             __END__
124              
125             =head1 NAME
126              
127             Catalyst::Plugin::Compress - Compress response
128              
129             =head1 SYNOPSIS
130              
131             use Catalyst qw/Compress/;
132              
133             or
134              
135             use Catalyst qw/
136             Unicode
137             Compress
138             /;
139              
140             If you want to use this plugin with L<Catalyst::Plugin::Unicode>.
141              
142             Remember to specify compression_format with:
143              
144             __PACKAGE__->config(
145             compression_format => $format,
146             );
147              
148             $format can be either gzip bzip2 zlib or deflate. bzip2 is B<*only*> supported
149             by lynx and some other console text-browsers.
150              
151             =head1 DESCRIPTION
152              
153             This module combines L<Catalyst::Plugin::Deflate> L<Catalyst::Plugin::Gzip>
154             L<Catalyst::Plugin::Zlib> into one.
155              
156             It compress response to [gzip bzip2 zlib deflate] if client supports it.
157              
158             B<NOTE>: If you want to use this module with L<Catalyst::Plugin::Unicode>, You
159             B<MUST> load this plugin B<AFTER> L<Catalyst::Plugin::Unicode>.
160              
161             use Catalyst qw/
162             Unicode
163             Compress
164             /;
165              
166             If you don't, You'll get error which is like:
167              
168             [error] Caught exception in engine "Wide character in subroutine entry at
169             /usr/lib/perl5/site_perl/5.8.8/Compress/Zlib.pm line xxx."
170              
171             =head1 INTERNAL METHODS
172              
173             =head2 should_compress_response
174              
175             This method determine wether compressing the reponse using this plugin.
176              
177             =head1 SEE ALSO
178              
179             L<Catalyst>.
180              
181             =head1 AUTHOR
182              
183             Yiyi Hu C<yiyihu@gmail.com>
184              
185             =head1 LICENSE
186              
187             This library is free software. You can redistribute it and/or modify it under
188             the same terms as perl itself.
189              
190             =cut
191