Apache-Dynagzip
view release on metacpan or search on metacpan
Dynagzip.pm view on Meta::CPAN
}
unless ($fh = FileHandle->new("$filename |")) {
$r->log->error($qualifiedName.' aborts: Fails to obtain incoming data handle for '.$r->filename);
return NOT_FOUND;
}
# lucky to proceed:
my $headers = retrieve_all_cgi_headers_via ($fh);
$r->send_cgi_header($headers);
if ($r->header_only){
$fh->close;
$r->log->warn($qualifiedName.' request for HTTP header only is done OK for '.$r->the_request);
return OK;
}
if ($light_compression) {
local $\;
send_lightly_compressed_stream($r, $fh);
} else { # no any compression:
local $\;
while (<$fh>) {
print ($_);
}
}
$fh->close;
$r->log->warn($qualifiedName.' is done OK for '.$r->the_request
.' '.$r->bytes_sent.' bytes sent');
return OK;
} # unless ($r->is_main)
# This is the main request,
# =========================
# check if it worths to gzip for the client:
my $can_gzip = can_gzip_for_this_client($r);
my $message = ' Light Compression is ';
if ($light_compression) {
$message .= 'On.';
} else {
$message .= 'Off.';
}
$message .= ' Source comes from ';
if ($filter) {
$message .= 'Filter Chain.';
} elsif ($binaryCGI) {
$message .= 'Binary CGI.';
} else {
$message .= 'Plain File.';
}
$message .= ' The client '.($r->header_in("User-agent") || '');
if ($can_gzip){
$message .= ' accepts GZIP.';
} else {
$message .= ' does not accept GZIP.';
}
$r->log->info($qualifiedName.' is serving the main request for '.$r->the_request
.' targeting '.$r->filename.' via '.$r->uri.$message);
$r->header_out("X-Module-Sender" => __PACKAGE__);
# Client Local Cache Control (see rfc2068):
# The Expires entity-header field gives the date/time after which the response should be
# considered stale. A stale cache entry may not normally be returned by a cache
# (either a proxy cache or an user agent cache) unless it is first validated with the origin server
# (or with an intermediate cache that has a fresh copy of the entity).
# The format is an absolute date and time as defined by HTTP-date in section 3.3;
# it MUST be in RFC1123-date format: Expires = "Expires" ":" HTTP-date
my $life_length = $r->dir_config('pageLifeTime') || PAGE_LIFE_TIME_DEFAULT;
my $now = time() + $life_length;
my $time_format_gmt = '%A, %d-%B-%Y %H:%M:%S %Z';
my $date_gmt = Apache::Util::ht_time($now, $time_format_gmt);
$r->header_out("Expires" => $date_gmt) unless $r->header_out("Expires");
# Advanced control over the client/proxy Cache:
#
{
local $^W = 0;
my $extra_vary = $r->dir_config('Vary');
my $current_vary = $r->header_out("Vary");
my $new_vary = join (',',$current_vary,$extra_vary);
$r->header_out("Vary" => $new_vary) if $extra_vary;
}
my $can_chunk = chunkable($r); # check if it is HTTP/1.1 or higher
unless ($can_chunk) {
# No chunks for HTTP/1.0. Close connection instead...
$r->header_out('Connection','close'); # for HTTP/1.0
$r->log->debug($qualifiedName.' is serving the main request in no-chunk mode for '.$r->the_request);
unless ($can_gzip) { # send plain content
# server-side cache control might be in effect, if ordered...
$r->log->info($qualifiedName.' no gzip for '.$r->the_request);
if ($filter) {
# create the filter-chain with no chunks...
$r = $r->filter_register;
$fh = $r->filter_input();
unless ($fh){
my $message = ' Fails to obtain the Filter data handle for ';
$r->log->error($qualifiedName.' aborts:'.$message.$r->filename);
return SERVER_ERROR;
}
# Inside the filter chain there are no need to prpogate CGI headers.
# All headers are already generated (presumably) by the previous filter(s).
if ($r->header_out('Content-Type')) {
$r->log->debug($qualifiedName
.' has Content-Type='.$r->header_out('Content-Type')
.' for '.$r->the_request);
} else {
# create default Content-Type HTTP header:
$r->log->debug($qualifiedName
.' creates default Content-Type for '.$r->the_request);
$r->content_type("text/html");
}
$r->send_http_header;
if ($r->header_only){
my $message = ' request for HTTP header only is done OK for ';
$r->log->info($qualifiedName.$message.$r->the_request);
return OK;
}
my $body = ''; # incoming content
if ($light_compression) {
$body = send_lightly_compressed_stream($r, $fh);
} else { # no light compression
while (<$fh>) {
Dynagzip.pm view on Meta::CPAN
minChunkSize
In case of uncompressed output, or the C<extra light> compression only,
the minimum size of the chunk is under the control of internal variable
minChunkSizePP
In this version handler provides defaults:
minChunkSize = 8
minChunkSizePP = 8192
You may overwrite the default values of these variables in your C<httpd.conf> if necessary.
=over 4
=item Note:
The internal variable C<minChunkSize> should be treated carefully
together with the C<minChunkSizeSource> (see Compression Features).
In this version handler does not keep control over the chunk-size
when it serves the internally redirected request.
An appropriate warning is placed to C<error_log> in this case.
=back
=head2 Filter Chain Features
As a member of C<Apache::Filter> chain, C<Apache::Dynagzip> handler is
supposed to be the last executable filter in the chain due to the features of it's
functions.
=head2 CGI Compatibility
When serving CGI binary this version of the handler is CGI/1.1 compatible.
It accepts CGI headers from the binary and produces a set of required HTTP headers
followed by gzipped content.
=head2 POST Request Features
I have to serve the POST requests for CGI binary with special care,
because in this case the handler
is standing along and have to serve all data flow in both directions
at the time when C<stdin> is tied into
Apache, and could not be exposed to CGI binary transparently.
To solve the problem I alter POST with GET request internally
doing the required incoming data transformations on the fly.
This could cause a problem, when you have a huge incoming stream from your client (more than 4K bytes).
Another problem could appear if your CGI binary is capable to distinguish POST and GET requests internally.
=head2 Control over the Client Cache
The control over the lifetime of the response in client's cache is provided
through implementation of C<Expires> HTTP header:
The Expires entity-header field gives the date/time after which the response should be considered stale.
A stale cache entry may not normally be returned by a cache (either a proxy cache or an user agent cache)
unless it is first validated with the origin server (or with an intermediate cache that has a fresh copy
of the entity). The format is an absolute date and time as defined by HTTP-date in section 3.3;
it MUST be in rfc1123-date format:
C<Expires = "Expires" ":" HTTP-date>
This handler creates the C<Expires> HTTP header, adding the C<pageLifeTime> to the date-time
of the request. The internal variable C<pageLifeTime> has default value
pageLifeTime = 300 # sec.
that could be overwriten in C<httpd.conf> for example as:
PerlSetVar pageLifeTime 1800
to make the C<pageLifeTime = 30 minutes>.
During the lifetime the client (browser) will
not even try to access the server when user requests the same URL again.
Instead, it restarts the page from the local cache.
It's important to point out here, that all initial JavaScripts will be restarted indeed,
so you can rotate your advertisements and dynamic content when needed.
The second important point should be mentioned here: when user clicks the "Refresh" button, the
browser will reload the page from the server unconditionally. This is right behavior,
because it is exactly what the human user expects from "Refresh" button.
=over 4
=item Notes:
The lifetime defined by C<Expires> depends on accuracy of time settings on client machine.
If the client's local clock is running 1 hour back, the cached copy of
the page will be alive 60 minutes longer on that machine.
C<Apache::Dynagzip> never overwrites C<Expires> header set by earlier handler inside the filter-chain.
=back
=head2 Support for the Server-Side Cache
In order to support the Server-Side Cache
I place a reference to the dynamically generated document to the C<notes()>
when the Server-Side Cache Support is ordered.
The referenced document could be already compressed with
an C<extra light> compression (if an C<extra light> compression is in effect for the current request).
In this case the regular dynamic C<gzip> compression takes place as usual
and the effective C<gzip> compression is supposed to take place within the C<log> stage
of the request processing flow.
You usually should not care about this feature of C<Apache::Dynagzip>
unless you use it in your own chain of handlers for the various phases of the request processing.
=head2 Control over the Proxy Cache.
Control over the (possible) proxy cache is provided through the implementation of C<Vary>
HTTP header.
Within C<Apache::Dynagzip> this header is under the control of few simple rules:
( run in 0.577 second using v1.01-cache-2.11-cpan-39bf76dae61 )