File Coverage

blib/lib/MasonX/Plugin/Compress.pm
Criterion Covered Total %
statement 56 56 100.0
branch 13 22 59.0
condition 2 6 33.3
subroutine 12 12 100.0
pod 1 1 100.0
total 84 97 86.6


line stmt bran cond sub pod time code
1             package MasonX::Plugin::Compress;
2              
3 6     6   157993 use warnings;
  6         19  
  6         182  
4 6     6   35 use strict;
  6         11  
  6         185  
5              
6 6     6   7520 use Compress::Zlib();
  6         666573  
  6         290  
7 6     6   8183 use Compress::Bzip2 2.0 ();
  6         81716  
  6         174  
8 6     6   59 use List::Util();
  6         14  
  6         108  
9              
10             #use Apache::Constants();
11              
12 6     6   34 use base 'HTML::Mason::Plugin';
  6         10  
  6         8001  
13              
14             our $VERSION = 0.1;
15              
16             =head1 NAME
17              
18             MasonX::Plugin::Compress - send compressed output if the client supports it
19              
20             =head1 SYNOPSIS
21              
22             PerlAddVar MasonPlugins MasonX::Plugin::Compress
23            
24             # or in a handler.pl script
25             my $ah = HTML::Mason::ApacheHandler->new( plugins => [ MasonX::Plugin::Compress-> new ],
26             # ...
27             );
28              
29             =head1 DESCRIPTION
30              
31             Negotiates a preferred compression method (currently, gzip, bzip2 or deflate) with the client,
32             compresses the response and sets appropriate headers.
33              
34             =head2 Methods
35              
36             =over 4
37              
38             =item end_request_hook
39              
40             =back
41              
42             =cut
43              
44             my %AcceptMap = ( gzip => '_gzip',
45             'x-gzip' => '_gzip',
46             deflate => '_deflate',
47             'x-deflate' => '_deflate', # does this exist?
48             bzip2 => '_bzip2',
49             'x-bzip2' => '_bzip2', # does this exist?
50             );
51            
52             sub end_request_hook
53             {
54 5     5 1 740 my ( $proto, $context ) = @_;
55            
56 5         33 my $o = $context->output;
57 5         66 my $m = $context->request;
58            
59 5   33     32 my $r = $m->apache_req || $m->cgi_request;
60            
61 5 50       97 return unless length $$o;
62            
63 5 50       24 return if $r->content_encoding;
64            
65             #return if $context->error; # there always seems to be one
66            
67             # not sure from the docs if results->[0] contains the request return code, but
68             # it seems to - does this break CGI? Anyway, seems to be undef.
69             #return unless $context->result->[0] == Apache::Constants::OK();
70            
71             # maybe worth accepting a few others, see e.g. http://www.pipeboost.com/contenttypes.asp
72 5 100       72 return unless $r->content_type =~ /^text/;
73            
74             # FireFox gives gzip, deflate
75 4 50       71 return unless my @accept = split /[\s,]/, $r->header_in( 'Accept-Encoding' );
76            
77 4 100   6   112 return unless my $encoding = List::Util::first { $AcceptMap{ $_ } } @accept;
  6         36  
78            
79             # Phew, we're really going to do this!
80            
81 3         15 my $compress = $AcceptMap{ $encoding };
82            
83 3         16 $proto->$compress( $context );
84             }
85              
86             sub _set_headers
87             {
88 3     3   8 my ( $class, $context, $enc ) = @_;
89            
90 3         20 my $m = $context->request;
91 3   33     23 my $r = $m->apache_req || $m->cgi_request;
92            
93 3         46 $r->content_encoding( $enc );
94            
95 3         45 $r->header_out( Vary => 'Accept-Encoding' );
96            
97             # I guess Mason sets this
98             #$r->content_length( length ${ $context->output } );
99             }
100              
101             sub _gzip
102             {
103 1     1   3 my ( $class, $context ) = @_;
104            
105 1         4 my $o = $context->output;
106            
107 1         9 $$o = Compress::Zlib::memGzip( $$o );
108            
109 1         932 $class->_set_headers( $context, 'gzip' );
110             }
111              
112             sub _bzip2
113             {
114 1     1   2 my ( $class, $context ) = @_;
115              
116 1         5 my $o = $context->output;
117            
118 1         924 $$o = Compress::Bzip2::memBzip( $$o );
119            
120 1         7 $class->_set_headers( $context, 'bzip2' );
121             }
122              
123             sub _deflate
124             {
125 1     1   3 my ( $class, $context ) = @_;
126            
127 1         6 my $d = Compress::Zlib::deflateInit;
128            
129 1 50       585 warn "Cannot create a deflation stream" unless $d;
130            
131 1 50       4 return unless $d;
132            
133 1         7 my $o = $context->output;
134            
135 1         21 my ( $out1, $status ) = $d->deflate( $o );
136            
137 1 50       150 warn "Deflation failed: $status" unless $status == Compress::Zlib::Z_OK();
138            
139 1 50       9 return unless $status == Compress::Zlib::Z_OK();
140            
141 1         9 ( my $out2, $status ) = $d->flush;
142              
143 1 50       123 warn "Deflation failed during flush: $status" unless $status == Compress::Zlib::Z_OK();
144            
145 1 50       9 return unless $status == Compress::Zlib::Z_OK();
146            
147 1         15 $$o = $out1 . $out2;
148            
149 1         6 $class->_set_headers( $context, 'deflate' );
150             }
151              
152             =head1 TODO
153              
154             Investigate what other types to compress (currently, only compresses text/*).
155              
156             =head1 SEE ALSO
157              
158             C.
159              
160             L.
161              
162             =head1 AUTHOR
163              
164             David Baird, C<< >>
165              
166             =head1 BUGS
167              
168             Please report any bugs or feature requests to
169             C, or through the web interface at
170             L.
171             I will be notified, and then you'll automatically be notified of progress on
172             your bug as I make changes.
173              
174             =head1 COPYRIGHT & LICENSE
175              
176             Copyright 2005 David Baird, All Rights Reserved.
177              
178             This program is free software; you can redistribute it and/or modify it
179             under the same terms as Perl itself.
180              
181             =cut
182              
183             1; # End of MasonX::Plugin::Compress