Forum Moderators: phranque
Basically, what I want to be able to do is to override content negotiation. So: a user would request "http://foo.com/bar/baz". Apache's content negotiator would resolve this, and return the contents of "http://foo.com/bar/baz.php" to the client. Normally, the client's URL would still show the former URL, but I need it to reflect the content negotiator's decision.
Can I setup a proxy server which will pass the client's request to the main server, then, based on the MIME type of the response, rewrite the client's URL to reflect the file that the main server's content negotiator resolved to?
The effect would be that the client receives a redirect to the URL that the content negotiator resolved the original request to.
Is there perhaps a simpler/other way of redirecting a browser to the specific file name the content negotiator would choose?
Thanks much, sorry if this is unclear--ask and I'll clarify. The details of why I'm on this crazy quest are in the linked thread.
Put the following text in ContributeFilter.pm
#file:MyApache2/ContributeFilter.pm
#--------------------------------
package MyApache2::ContributeFilter;use strict;
use warnings FATAL => 'all';use Apache2::Filter ();
use Apache2::RequestRec ();
use APR::Table ();
use APR::Bucket ();
use APR::Brigade ();use Apache2::Const -compile => qw(OK DECLINED M_PUT M_GET);
use APR::Const -compile => ':common';use constant BUFF_LEN => 1024;
my $INSTANCE_EXTEN = 'php';
my $VALID_URI = '(\.'.$INSTANCE_EXTEN.')$';
my $VALID_AGENT = 'Contribute';
my $begin = '<!-- BEGIN -->';
my $end = '<!-- END -->';
# the regex that match undesired content, ie. everything before and after these will be removed.
my $begin_regex = '(\s¦.)*'.$begin.'\s*';
my $end_regex = '\s*'.$end.'(\s¦.)*';
my $DOC_ROOT = '/var/www/website/trunk';sub output {
my $filter = shift;
my ($ctx, $r) = ($filter->ctx, $filter->r);# If a request is undealt with, must pass DECLINED to Apache
# So, the request must be a GET, and it must be for a file with a URI
# that matches $VALID_URI. We can't check User Agent, since Contribute
# won't identify itself properly on GET
if (($r->method_number == Apache2::Const::M_GET) && ($r->uri =~ /$VALID_URI/)) {
my $data = exists $ctx->{data}? $ctx->{data} : '';while($filter->read(my $buffer, BUFF_LEN)) {
$data .= $buffer;
}if ( $r->headers_out->{'Content-Length'} &&
(length($data)!= $r->headers_out->{'Content-Length'}) ){
# store context for all but the last invocation
$ctx->{data} = $data;
$filter->ctx($ctx);
} else {
# we'll search through for links and append .php so that Contribute doesn't
# get tripped up by content negotiation
my @links = ($data =~ /(?<=href=[\"\'])[^\"\']+(?=[\"\'])/ig);
foreach my $link (@links) {
# don't bother with links that are external or clearly to directories
unless (($link =~ /^http/)¦¦($link =~ /\/$/)) {
# aha! a relative link!
my $newlink = $link;
if ($link =~ /^(\w¦\.)/) {
$r->uri =~ m¦(.*/)¦; # get everything before the filename
$newlink = $1.$link.".php";
} else {
$newlink = $link.".php";
}
# see if the file exists at all, otherwise, don't bother
if (-f $DOC_ROOT.$newlink) {
$data =~ s/([\'\"])$link([\'\"])/$1$newlink$2/ig
}
}
}
$r->headers_out->set('Content-Length', length($data));
$filter->print($data) if $data;
}return Apache2::Const::OK;
} else {
$r->allowed($r->allowed ¦ (1<<Apache2::Const::M_GET));
return Apache2::Const::DECLINED;
}
}sub input {
my $filter = shift;
my ($ctx, $r) = ($filter->ctx, $filter->r);if ( ($r->method_number == Apache2::Const::M_PUT) &&
($r->uri =~ /$VALID_URI/) &&
($r->headers_in->{'User-Agent'} =~ /$VALID_AGENT/) ){my $data = exists $ctx->{data}? $ctx->{data} : '';
while ($filter->read(my $buffer, BUFF_LEN)) {
$data .= $buffer;
}if (length($data) == $r->headers_in->{'Content-Length'}) {
$data =~ s/$begin_regex//;
$data =~ s/$end_regex//;
$data =~ s/(a href=".+)\.php/$1/; # remove php file extensions for good links
$r->headers_in->set('Content-Length', length($data));
$filter->print($data) if $data;
} else {
$ctx->{data} = $data;
$filter->ctx($ctx);
}
return Apache2::Const::OK;
} else {
$r->allowed($r->allowed ¦ (1<<Apache2::Const::M_PUT));
return Apache2::Const::DECLINED;
}
}
1;
On output, this appends '.php' to links that Contribute would otherwise have problems editing, since they wouldn't have extensions. On input it strips all the display information, leaving only content, as well as editing links to remove the .php so that content negotiation can do its work.
Install it thusly:
~$ h2xs -X -n MyApache2::ContributeFilter
~$ mv ContributeFilter.pm MyApache2-ContributeFilter/lib/MyApache2/
~$ cd MyApache2-ContributeFilter/
~$ perl Makefile.PL
~$ make
~$ make test
~$ su
# make install