But there is a certain situation that needs a workaround to achieve
better cacheability. We need to deal with the "?"
in the relative path part of the requested URI. Section 13.9
specifies that:
... caches MUST NOT treat responses to such URIs as fresh unless the server provides
an explicit expiration time. This specifically means that responses from HTTP/1.0
servers for such URIs SHOULD NOT be taken from a cache.
Although it is tempting to imagine that if we are using HTTP/1.1 and
send an explicit expiration time we are safe, the reality is
unfortunately somewhat different. It has been common for quite a long
time to misconfigure cache servers so that they treat all
GET requests containing a question mark as
uncacheable. People even used to mark anything that contained the
string "cgi-bin" as uncacheable.
To work around this bug in HEAD requests, we have
stopped calling CGI directories cgi-bin and we
have written the following handler, which lets us work with CGI-like
query strings without rewriting the software (e.g.,
Apache::Request and CGI.pm)
that deals with them:
sub handler {
my $r = shift;
my $uri = $r->uri;
if ( my($u1,$u2) = $uri =~ / ^ ([^?]+?) ; ([^?]*) $ /x ) {
$r->uri($u1);
$r->args($u2);
}
elsif ( my ($u1,$u2) = $uri =~ m/^(.*?)%3[Bb](.*)$/ ) {
# protect against old proxies that escape volens nolens
# (see HTTP standard section 5.1.2)
$r->uri($u1);
$u2 =~ s/%3[Bb]/;/g;
$u2 =~ s/%26/;/g; # &
$u2 =~ s/%3[Dd]/=/g;
$r->args($u2);
}
DECLINED;
}
This handler must be installed as a
PerlPostReadRequestHandler.
The handler takes any request that contains one or more semicolons
but no question mark and changes it so that the
first semicolon is interpreted as a question mark and everything
after that as the query string. So now we can replace the request:
https://example.com/query?BGCOLOR=blue;FGCOLOR=red
with:
https://example.com/query;BGCOLOR=blue;FGCOLOR=red
This allows the coexistence of queries from ordinary forms that are
being processed by a browser alongside predefined requests for the
same resource. It has one minor bug: Apache doesn't
allow percent-escaped slashes in such a query string. So instead of:
https://example.com/query;BGCOLOR=blue;FGCOLOR=red;FONT=%2Ffont%2Fpath
we must use:
https://example.com/query;BGCOLOR=blue;FGCOLOR=red;FONT=/font/path
To unescape the escaped characters, use the following code:
s/%([0-9A-Fa-f]{2})/chr hex $1/ge;