"Fossies" - the Fresh Open Source Software Archive

Member "Apache2-ModProxyPerlHtml-4.0/ModProxyPerlHtml.pm" (11 May 2020, 22621 Bytes) of package /linux/www/apache_httpd_modules/Apache2-ModProxyPerlHtml-4.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ModProxyPerlHtml.pm" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.6_vs_4.0.

    1 #------------------------------------------------------------------------------
    2 # Project  : Reverse Proxy HTML link rewriter
    3 # Name     : ModProxyPerlHtml.pm
    4 # Language : perl 5
    5 # Authors  : Gilles Darold, gilles at darold dot net
    6 # Copyright: Copyright (c) 2005-2020: Gilles Darold - All rights reserved -
    7 # Description : This mod_perl module is a replacement for mod_proxy_html.c
    8 #       with far better URL HTML rewriting.
    9 # Usage    : See documentation in this file with perldoc.
   10 #------------------------------------------------------------------------------
   11 # This program is free software; you can redistribute it and/or modify it under
   12 # the same terms as Perl itself.
   13 #------------------------------------------------------------------------------
   14 package Apache2::ModProxyPerlHtml;
   15 use strict qw(vars);
   16 use warnings;
   17 
   18 require mod_perl2;
   19 
   20 use Apache2::Connection ();
   21 use Apache2::RequestRec;
   22 use Apache2::RequestUtil;
   23 use APR::Table;
   24 use APR::URI;
   25 use base qw(Apache2::Filter);
   26 use Apache2::Const -compile => qw(OK DECLINED :conn_keepalive);
   27 use constant BUFF_LEN => 8000;
   28 use Apache2::ServerRec;
   29 use Apache2::URI;
   30 
   31 
   32 $Apache2::ModProxyPerlHtml::VERSION = '4.0';
   33 
   34 
   35 %Apache2::ModProxyPerlHtml::linkElements = (
   36     'a'       => ['href'],
   37     'applet'  => ['archive', 'codebase', 'code'],
   38     'area'    => ['href'],
   39     'bgsound' => ['src'],
   40     'blockquote' => ['cite'],
   41     'body'    => ['background'],
   42     'del'     => ['cite'],
   43     'embed'   => ['pluginspage', 'src'],
   44     'form'    => ['action'],
   45     'frame'   => ['src', 'longdesc'],
   46     'iframe'  => ['src', 'longdesc'],
   47     'ilayer'  => ['background'],
   48     'img'     => ['src', 'lowsrc', 'longdesc', 'usemap'],
   49     'input'   => ['src', 'usemap','formaction'],
   50     'ins'     => ['cite'],
   51     'isindex' => ['action'],
   52     'head'    => ['profile'],
   53     'layer'   => ['background', 'src'],
   54     'link'    => ['href'],
   55     'object'  => ['classid', 'codebase', 'data', 'archive', 'usemap'],
   56     'q'       => ['cite'],
   57     'script'  => ['src', 'for'],
   58     'table'   => ['background'],
   59     'td'      => ['background'],
   60     'th'      => ['background'],
   61     'tr'      => ['background'],
   62     'xmp'     => ['href'],
   63     'button'  => ['formaction'],
   64 );
   65 
   66 sub handler
   67 {
   68     my $f = shift;
   69 
   70     my $debug = $f->r->dir_config->get('ProxyHTMLVerbose');
   71     if ($debug && $debug =~ /(on|1)/i) {
   72         $debug = 1;
   73     } else {
   74         $debug = 0;
   75     }
   76 
   77     # Thing we do at the first chunk
   78     my $content_type = $f->r->content_type() || '';
   79     unless ($f->ctx) {
   80         $f->r->headers_out->unset('Content-Length');
   81         my @pattern = $f->r->dir_config->get('ProxyHTMLURLMap');
   82         my @rewrite = $f->r->dir_config->get('ProxyHTMLRewrite');
   83         my $contenttype = $f->r->dir_config->get('ProxyHTMLContentType');
   84         $contenttype ||= '(text\/javascript|text\/html|text\/css|text\/xml|application\/.*javascript|application\/.*xml)';
   85         my $badcontenttype = $f->r->dir_config->get('ProxyHTMLExcludeContentType');
   86         $badcontenttype ||= '(application\/vnd\.openxml)';
   87         my @exclude = $f->r->dir_config->get('ProxyHTMLExcludeUri');
   88         my @obfuscation = $f->r->dir_config->get('ProxyHTMLRot13Links');
   89 
   90         my $ct = $f->ctx;
   91         $ct->{data} = '';
   92         foreach my $p (@pattern) {
   93             push(@{$ct->{pattern}}, $p);
   94         }
   95         foreach my $p (@rewrite) {
   96             push(@{$ct->{rewrite}}, $p);
   97         }
   98         $ct->{contenttype} = $contenttype;
   99         $ct->{badcontenttype} = $badcontenttype;
  100         foreach my $u (@exclude) {
  101             push(@{$ct->{excluded}}, $u);
  102         }
  103         foreach my $o (@obfuscation) {
  104             my ($elt, $attr) = split(/:/, $o);
  105             if (uc($elt) eq 'ALL') {
  106                 $ct->{rot13elements} = 'All';
  107                 last;
  108             } else {
  109                 $ct->{rot13elements}->{$elt} = $attr;
  110             }
  111         }
  112         $f->ctx($ct);
  113     }
  114     # Thing we do on all invocations
  115     my $ctx = $f->ctx;
  116     while ($f->read(my $buffer, BUFF_LEN)) {
  117         $ctx->{data} .= $buffer;
  118         $ctx->{keepalives} = $f->c->keepalives;
  119         $f->ctx($ctx);
  120     }
  121     # Thing we do at end
  122     if ($f->seen_eos) { 
  123         my $parsed_uri = $f->r->construct_url();
  124         my $a_encoding = $f->r->headers_in->{'Accept-Encoding'} || '';
  125         my $c_encoding = $f->r->headers_out->{'Content-Encoding'} || '';
  126         my $ct = $f->r->headers_out->{'Content-type'} || '';
  127 
  128         # Only proceed URLs that are not excluded from rewritter
  129         if ( ($#{$ctx->{excluded}} == -1) || !grep($parsed_uri =~ /$_/i, @{$ctx->{excluded}}) ) {
  130 
  131             # if Accept-Encoding: gzip,deflate try to uncompress
  132             if ( ($c_encoding =~ /gzip|deflate/) && ($ct =~ /$ctx->{contenttype}/is) && ($ct !~ /$ctx->{badcontenttype}/is) ) {
  133                 if ($debug) {
  134                     Apache2::ServerRec::warn("[ModProxyPerlHtml] Uncompressing $ct, Content-Encoding: $c_encoding");
  135                 }
  136                 use IO::Uncompress::AnyInflate qw(anyinflate $AnyInflateError) ;
  137                 my $output = '';
  138                 anyinflate  \$ctx->{data} => \$output or print STDERR "anyinflate failed: $AnyInflateError\n";
  139                 if ($ctx->{data} ne $output) {
  140                     $ctx->{data} = $output;
  141                 } else {
  142                     $c_encoding = '';
  143                 }
  144             } else {
  145                 $c_encoding = '';
  146             }
  147 
  148             # Rewrite refresh command in header
  149             my $refresh = $f->r->headers_out->{'Refresh'};
  150             if ($refresh) {
  151                 foreach my $p (@{$ctx->{pattern}}) {
  152                     my ($match, $substitute) = split(/[\s\t]+/, $p, 2);
  153                     if ($refresh =~ s#([^\/:])$match#$1$substitute#) {
  154                         if ($debug) {
  155                             Apache2::ServerRec::warn("[ModProxyPerlHtml] Refresh header match '$match', substituted by: /$substitute/");
  156                         }
  157                     }
  158                 }
  159                 $f->r->headers_out->set('Refresh' => $refresh);
  160             }
  161 
  162             # Rewrite referer in header
  163             my $referer = $f->r->headers_out->{'Referer'};
  164             if ($referer) {
  165                 foreach my $p (@{$ctx->{pattern}}) {
  166                     my ($match, $substitute) = split(/[\s\t]+/, $p, 2);
  167                     if ($referer =~ s#([^\/:])$match#$1$substitute#) {
  168                         if ($debug) {
  169                             Apache2::ServerRec::warn("[ModProxyPerlHtml] Referer header match '$match', substituted by: /$substitute/");
  170                         }
  171                     }
  172                 }
  173                 $f->r->headers_out->set('Referer' => $referer);
  174             }
  175             
  176             # Only parse content that should have hyperlinks to rewrite
  177             if ( ($content_type =~ /$ctx->{contenttype}/is) && ($content_type !~ /$ctx->{badcontenttype}/is) ) {
  178                 if ($debug) {
  179                     Apache2::ServerRec::warn("[ModProxyPerlHtml] Content-type '$content_type' match: /$ctx->{contenttype}/is");
  180                 }
  181                 # Replace links if pattern match
  182                 foreach my $p (@{$ctx->{pattern}}) {
  183                     my ($match, $substitute) = split(/[\s\t]+/, $p, 2);
  184                     &link_replacement(\$ctx->{data}, $match, $substitute, $parsed_uri, $ctx->{rot13elements});
  185                 }
  186                 # Rewrite code if rewrite pattern match
  187                 foreach my $p (@{$ctx->{rewrite}}) {
  188                     my ($match, $substitute) = split(/[\s\t]+/, $p, 2);
  189                     &rewrite_content(\$ctx->{data}, $match, $substitute, $parsed_uri);
  190                 }
  191             }
  192 
  193             # Compress again data if require
  194             if (($a_encoding =~ /gzip|deflate/) && ($c_encoding =~ /gzip|deflate/)) {
  195                 if ($debug) {
  196                     Apache2::ServerRec::warn("[ModProxyPerlHtml] Compressing output as Content-Encoding: $c_encoding");
  197                 }
  198                 if ($c_encoding =~ /gzip/) {
  199                     use IO::Compress::Gzip qw(gzip $GzipError) ;
  200                     my $output = '';
  201                     my $status = gzip \$ctx->{data} => \$output or die "gzip failed: $GzipError\n";
  202                     $ctx->{data} = $output;
  203                 } elsif ($c_encoding =~ /deflate/) {
  204                     use IO::Compress::Deflate qw(deflate $DeflateError) ;
  205                     my $output = '';
  206                     my $status = deflate \$ctx->{data} => \$output or die "deflate failed: $DeflateError\n";
  207                     $ctx->{data} = $output;
  208                 }
  209             }
  210         }
  211 
  212         # Apply any change
  213         $f->ctx($ctx);
  214 
  215         # Dump datas out
  216         $f->print($f->ctx->{data});
  217         my $c = $f->c;
  218         if ($c->keepalive == Apache2::Const::CONN_KEEPALIVE && $ctx->{data} && $c->keepalives > $ctx->{keepalives}) {
  219             if ($debug) {
  220                 Apache2::ServerRec::warn("[ModProxyPerlHtml] Cleaning context for keep alive request");
  221             }
  222             $ctx->{data} = '';
  223             $ctx->{pattern} = ();
  224             $ctx->{rewrite} = ();
  225             $ctx->{excluded} = ();
  226             $ctx->{rot13elements} = ();
  227             $ctx->{contenttype} = '';
  228             $ctx->{badcontenttype} = '';
  229             $ctx->{keepalives} = $c->keepalives;
  230         }
  231             
  232     }
  233 
  234     return Apache2::Const::OK;
  235 }
  236 
  237 sub link_replacement
  238 {
  239     my ($data, $pattern, $replacement, $uri, $rot13elements) = @_;
  240 
  241     return if (!$$data);
  242 
  243     my $old_terminator = $/;
  244     $/ = '';
  245     my %TODOS = ();
  246     my %ROT13TODOS = ();
  247     my $i = 0;
  248 
  249     # Detect parts that need to be deobfuscated before replacement
  250     if ($rot13elements ne 'All') {
  251         foreach my $tag (keys %{$rot13elements}) {
  252             while ($$data =~ s/(<$tag\s+[^>]*\b$rot13elements->{$tag}=['"\s]*)([^'"\s>]+)([^>]*>)/ROT13REPLACE_$i\$\$/i) {
  253                 $ROT13TODOS{$i} = "$1ROT13$2ROT13$3";
  254                 $i++;
  255             }
  256         }
  257     } elsif ($rot13elements eq 'All') {
  258         foreach my $tag (keys %Apache2::ModProxyPerlHtml::linkElements) {
  259             next if ($$data !~ /<$tag/i);
  260             foreach my $attr (@{$Apache2::ModProxyPerlHtml::linkElements{$tag}}) {
  261                 while ($$data =~ s/(<$tag\s+[^>]*\b$attr=['"\s]*)([^'"\s>]+)([^>]*>)/ROT13REPLACE_$i\$\$/i) {
  262                     $ROT13TODOS{$i} = "$1ROT13$2ROT13$3";
  263                     $i++;
  264                 }
  265             }
  266         }
  267     }
  268     # Decode ROT13 links now
  269     foreach my $k (keys %ROT13TODOS) {
  270         my $repl = rot13_decode($ROT13TODOS{$k});
  271         $$data =~ s/ROT13REPLACE_$k\$\$/$repl/;
  272     }
  273 
  274     # Replace standard link into attributes of any element
  275     foreach my $tag (keys %Apache2::ModProxyPerlHtml::linkElements) {
  276         next if ($$data !~ /<$tag/i);
  277         foreach my $attr (@{$Apache2::ModProxyPerlHtml::linkElements{$tag}}) {
  278             while ($$data =~ s/(<$tag[\t\s]+[^>]*\b$attr=['"]*)($replacement|$pattern)([^'"\s>]+)/\$\$NEEDREPLACE$i\$\$/i) {
  279                 $TODOS{$i} = "$1$replacement$3";
  280                 $i++;
  281             }
  282         }
  283     }
  284     # Replace all links in javascript code after hiding javascript replacement pattern
  285     my %replace_fct = ();
  286     while ($$data =~ s/(\.replace\([^,]+,[^\)]+\))/\%\%REPLACE$i\%\%/) {
  287         $replace_fct{$i} = $1;
  288         $i++;
  289     }
  290 
  291     $$data =~ s/([^\\\/]['"])($replacement|$pattern)([^'"]*['"])/$1$replacement$3/ig;
  292 
  293     $$data =~ s/\%\%REPLACE(\d+)\%\%/$replace_fct{$1}/g;
  294 
  295     # Some use escaped quote - Do you have better regexp ?
  296     $$data =~ s/(\&quot;)($replacement|$pattern)(.*\&quot;)/$1$replacement$3/ig;
  297 
  298     # Try to set a fully qualified URI
  299     $uri =~ s/$replacement.*//;
  300         # Replace meta refresh URLs
  301     $$data =~ s/(<meta\b[^>]+content=['"]*.*url=)($replacement|$pattern)([^>]+)/$1$uri$replacement$3/i;
  302     # Replace base URI
  303     $$data =~ s/(<base\b[^>]+href=['"]*)($replacement|$pattern)([^>]+)/$1$uri$replacement$3/i;
  304 
  305     # CSS have url import call, most of the time not quoted
  306     $$data =~ s/(url\(['"]*)($replacement|$pattern)(.*['"]*\))/$1$replacement$3/ig;
  307 
  308     # Javascript have image object or other with a src method.
  309     $$data =~ s/(\.src[\s\t]*=[\s\t]*['"]*)($replacement|$pattern)(.*['"]*)/$1$replacement$3/ig;
  310     
  311     # The single ended tag broke mod_proxy parsing
  312     $$data =~ s/($replacement|$pattern)>/\/>/ig;
  313     
  314     # Replace todos now
  315     $$data =~ s/\$\$NEEDREPLACE(\d+)\$\$/$TODOS{$1}/g;
  316 
  317     # Detect parts that need to be obfuscated after replacement
  318     if ($rot13elements ne 'All') {
  319         foreach my $tag (keys %{$rot13elements}) {
  320             while ($$data =~ s/(<$tag\s+[^>]*\b$rot13elements->{$tag}=['"\s]*)([^'"\s>]+)([^>]*>)/ROT13REPLACE_$i\$\$/i) {
  321                 $ROT13TODOS{$i} = "$1ROT13$2ROT13$3";
  322                 $i++;
  323             }
  324         }
  325     } elsif ($rot13elements eq 'All') {
  326         foreach my $tag (keys %Apache2::ModProxyPerlHtml::linkElements) {
  327             next if ($$data !~ /<$tag/i);
  328             foreach my $attr (@{$Apache2::ModProxyPerlHtml::linkElements{$tag}}) {
  329                 while ($$data =~ s/(<$tag\s+[^>]*\b$attr=['"\s]*)([^'"\s>]+)([^>]*>)/ROT13REPLACE_$i\$\$/i) {
  330                     $ROT13TODOS{$i} = "$1ROT13$2ROT13$3";
  331                     $i++;
  332                 }
  333             }
  334         }
  335     }
  336 
  337     # Encode ROT13 links now
  338     foreach my $k (keys %ROT13TODOS) {
  339         my $repl = rot13_encode($ROT13TODOS{$k});
  340         $$data =~ s/ROT13REPLACE_$k\$\$/$repl/;
  341     }
  342 
  343     $/ = $old_terminator;
  344 }
  345 
  346 sub rewrite_content
  347 {
  348     my ($data, $pattern, $replacement, $uri) = @_;
  349 
  350     return if (!$$data);
  351 
  352     my $old_terminator = $/;
  353     $/ = '';
  354 
  355     # Rewrite things in code (case sensitive)
  356     $replacement = '"' . $replacement . '"';
  357     $$data =~ s/$pattern/$replacement/eeg;
  358 
  359     $/ = $old_terminator;
  360 
  361 }
  362 
  363 sub rot13_decode
  364 {
  365     my $str = shift;
  366 
  367     my @parts = split(/ROT13/, $str);
  368         $parts[1] =~ tr/nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/;
  369 
  370     return join('', @parts);
  371 }
  372 
  373 sub rot13_encode
  374 {
  375     my $str = shift;
  376 
  377     my @parts = split(/ROT13/, $str);
  378         $parts[1] =~ tr/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM/;
  379 
  380     return join('', @parts);
  381 }
  382 
  383 
  384 1;
  385 
  386 __END__
  387 
  388 =head1 NAME
  389 
  390 Apache2::ModProxyPerlHtml - rewrite HTTP headers and HTML links for reverse proxy usage
  391 
  392 =head1 DESCRIPTION
  393 
  394 Apache2::ModProxyPerlHtml is the most advanced Apache output filter to rewrite
  395 HTTP headers and HTML links for reverse proxy usage. It is written in Perl and
  396 exceeds all mod_proxy_html.c limitations without performance lost.
  397 
  398 Apache2::ModProxyPerlHtml is very simple and has far better parsing/replacement
  399 of URL than the original C code. It also supports meta tag, CSS, and javascript
  400 URL rewriting and can be used with compressed HTTP. You can now replace any code
  401 by other, like changing image names or anything else. mod_proxy_html can't do
  402 all of that. Since release 3.x ModProxyPerlHtml is also able to rewrite HTTP
  403 headers with Refresh url redirection and Referer. 
  404 
  405 The replacement capability concern only the following HTTP content type:
  406 
  407     text/javascript
  408     text/html
  409     text/css
  410     text/xml
  411     application/.*javascript
  412     application/.*xml
  413 
  414 other kind of file, will be left untouched (or see ProxyHTMLContentType and ProxyHTMLExcludeContentType).
  415 
  416 =head1 AVAILIBILITY
  417 
  418 You can get the latest version of Apache2::ModProxyPerlHtml from CPAN
  419 (http://search.cpan.org/).
  420 
  421 =head1 PREREQUISITES
  422 
  423 You must have Apache2, mod_proxy, mod_perl and IO::Compress::Zlib perl modules
  424 installed on your system.
  425 
  426 =head2 Installation on RH/CentOs
  427 
  428 Install Apache2, apxs, the Epel repository (for mod_perl install) and the
  429 Perl Module IO::Compress:
  430  
  431     yum install httpd httpd-devel
  432     yum install epel-release
  433     yum install perl-IO-Compress
  434 
  435 Install ModPerl, minimal version to work with Apache 2.4 is 2.0.10:
  436 
  437     yum list | grep mod_perl
  438     yum --enablerepo=epel -y install mod_perl mod_perl-devel
  439 
  440 Enable mod_perl:
  441 
  442     a2enconf mod_perl
  443     systemctl reload apache2
  444 
  445 The Apache module mod_ssl is not available by default, install it:
  446 
  447         yum install mod_ssl
  448 
  449 If the firewall is enabled you might want to allow access to the Apache services
  450 
  451     firewall-cmd --permanent --add-service=http
  452     firewall-cmd --permanent --add-service=https
  453     firewall-cmd --reload
  454 
  455 
  456 =head2 Installation on Debian/Ubuntu
  457 
  458 To have Apache2 server and apxs command:
  459 
  460     apt install apache2 apache2-dev
  461 
  462 ModPerl can be installed using:
  463 
  464     apt install libapache2-mod-perl2 libapache2-mod-perl2-dev
  465 
  466 ModProxyPerlHtml need additional Perl module IO::Compress:
  467 
  468     apt install libio-compress-perl
  469 
  470 Enable mod_proxy:
  471 
  472     a2enmod proxy
  473     a2enmod proxy_http
  474     a2enmod proxy_ftp
  475     a2enmod proxy_connect
  476 
  477 Enable the configuration and mod_perl:
  478 
  479     a2enmod perl
  480 
  481 
  482 =head1 INSTALLATION
  483 
  484     % perl Makefile.PL
  485     % make && make install
  486 
  487 =head1 APACHE CONFIGURATION
  488 
  489 On Debian/Ubuntu set the following configuration into the VirtualHost section
  490 of files /etc/apache2/sites-available/default-ssl.conf and /etc/apache2/sites-available/000-default.conf.
  491 On CentOS/RedHat add it to /etc/httpd/conf.d/vhost.conf.
  492 
  493     ProxyRequests Off
  494     ProxyPreserveHost Off
  495     ProxyPass       /webcal/  http://webcal.domain.com/
  496 
  497     PerlInputFilterHandler Apache2::ModProxyPerlHtml
  498     PerlOutputFilterHandler Apache2::ModProxyPerlHtml
  499     SetHandler perl-script
  500     # Use line below and comment line above if you experience error:
  501     # "Attempt to serve directory". The reason is that with SetHandler
  502     # DirectoryIndex is not working 
  503     # AddHandler perl-script *
  504     PerlSetVar ProxyHTMLVerbose "On"
  505     LogLevel Info
  506 
  507 
  508     <Location /webcal/>
  509         ProxyPassReverse /
  510         PerlAddVar ProxyHTMLURLMap "/ /webcal/"
  511         PerlAddVar ProxyHTMLURLMap "http://webcal.domain.com /webcal"
  512     </Location>
  513 
  514 Note that here FilterHandlers are set globally, you can also set them in any
  515 <Location> part to set it locally and avoid calling this Apache module globally.
  516 
  517 If you want to rewrite some code on the fly, like changing images filename you
  518 can use the perl variable ProxyHTMLRewrite under the location directive as
  519 follow:
  520 
  521     <Location /webcal/>
  522         ...
  523         PerlAddVar ProxyHTMLRewrite "/logo/image1.png /images/logo1.png"
  524     # Or more complicated to handle space in the code as space is the
  525     # pattern / substitution separator character internally in ModProxyPerlHtml
  526     PerlAddVar ProxyHTMLRewrite "ajaxurl[\s\t]*=[\s\t]*'/blog' ajaxurl = '/www2.mydom.org/blog'"
  527         ...
  528     </Location>
  529 
  530 this will replace each occurence of '/logo/image1.png' by '/images/logo1.png' in
  531 the entire stream (html, javascript or css). Note that this kind of substitution
  532 is done after all other proxy related replacements.
  533 
  534 In some conditions javascript code can be replaced by error, for example:
  535 
  536         imgUp.src = '/images/' + varPath + '/' + 'up.png';
  537 
  538 will be rewritten like this:
  539 
  540         imgUp.src = '/URL/images/' + varPath + '/URL/' + 'up.png';
  541 
  542 To avoid the second replacement, write your JS code like that:
  543 
  544         imgUp.src = '/images/' + varPath + unescape('%2F') + 'up.png';
  545 
  546 ModProxyPerlHTML replacement is activated on certain HTTP Content Type. If you
  547 experienced that replacement is not activated for your file type, you can use the
  548 ProxyHTMLContentType configuration directive to redefined the HTTP Content Type
  549 that should be parsed by ModProxyPerlHTML. The default value is the following
  550 Perl regular expresssion:
  551 
  552     PerlAddVar ProxyHTMLContentType    (text\/javascript|text\/html|text\/css|text\/xml|application\/.*javascript|application\/.*xml)
  553 
  554 If you know exactly what you are doing by editing this regexp fill free to add
  555 the missing Content-Type that must be parsed by ModProxyPerlHTML. Otherwise drop
  556 me a line with the content type, I will give you the rigth expression. If you don't
  557 know about the content type, with FireFox simply type Ctrl+i on the web page.
  558 
  559 Some MS Office files may conflict with the above ProxyHTMLContentType regex like .docx or .xlsx
  560 files. The result is that there could suffer of replacement inside and the file will be corrupted.
  561 to prevent this you have the ProxyHTMLExcludeContentType configuration directive to exclude certain
  562 content-type. Here is the default value:
  563  
  564     PerlAddVar ProxyHTMLExcludeContentType  (application\/vnd\.openxml)
  565 
  566 If you have problem with other content-type, use this directive. For example, as follow:
  567 
  568     PerlAddVar ProxyHTMLExcludeContentType  (application\/vnd\.openxml|application\/vnd\..*text)
  569 
  570 this regex will prevent any MS Office XML or text document to be parsed.
  571 
  572 Some javascript libraries like JQuery are wrongly rewritten by ModProxyPerlHtml.
  573 The problem is that those javascript code include some code and regex that are
  574 detected as links and rewritten. The only way to fix that is to exclude those
  575 files from the URL rewritter by using the "ProxyHTMLExcludeUri" configuration
  576 directive. For example:
  577 
  578     PerlAddVar ProxyHTMLExcludeUri  jquery.min.js$
  579     PerlAddVar ProxyHTMLExcludeUri  ^.*\/jquery-lib\/.*$
  580 
  581 Any downloaded URI that contains the given regex will be returned asis without
  582 rewritting. You can use this directive multiple time like above to match different
  583 cases.
  584 
  585 =head1 LIVE EXAMPLE
  586 
  587 Here is the reverse proxy configuration I use to give access to Internet users
  588 to internal applications:
  589 
  590     ProxyRequests Off
  591     ProxyPreserveHost Off
  592     ProxyPass       /webmail/  http://webmail.domain.com/
  593     ProxyPass       /webcal/  http://webcal.domain.com/
  594     ProxyPass       /intranet/  http://intranet.domain.com/
  595 
  596 
  597     PerlInputFilterHandler Apache2::ModProxyPerlHtml
  598     PerlOutputFilterHandler Apache2::ModProxyPerlHtml
  599     SetHandler perl-script
  600     # Use line below iand comment line above if you experience error:
  601     # "Attempt to serve directory". The reason is that with SetHandler
  602     # DirectoryIndex is not working 
  603     # AddHandler perl-script *
  604     PerlSetVar ProxyHTMLVerbose "On"
  605     LogLevel Info
  606 
  607 
  608     # URL rewriting
  609     RewriteEngine   On
  610     #RewriteLog      "/var/log/apache/rewrite.log"
  611     #RewriteLogLevel 9
  612     # Add ending '/' if not provided
  613     RewriteCond     %{REQUEST_URI}  ^/mail$
  614     RewriteRule     ^/(.*)$ /$1/    [R]
  615     RewriteCond     %{REQUEST_URI}  ^/planet$
  616     RewriteRule     ^/(.*)$ /$1/    [R]
  617     # Add full path to the CGI to bypass the index.html redirect that may fail
  618     RewriteCond     %{REQUEST_URI}  ^/calendar/$
  619     RewriteRule     ^/(.*)/$ /$1/cgi-bin/wcal.pl    [R]
  620     RewriteCond     %{REQUEST_URI}  ^/calendar$
  621     RewriteRule     ^/(.*)$ /$1/cgi-bin/wcal.pl     [R]
  622 
  623 
  624     <Location /webmail/>
  625         ProxyPassReverse /
  626         PerlAddVar ProxyHTMLURLMap "/ /webmail/"
  627         PerlAddVar ProxyHTMLURLMap "http://webmail.domain.com /webmail"
  628         # Use this to disable compressed HTTP
  629         #RequestHeader   unset   Accept-Encoding
  630     </Location>
  631 
  632 
  633     <Location /webcal/>
  634         ProxyPassReverse /
  635         PerlAddVar ProxyHTMLURLMap "/ /webcal/"
  636         PerlAddVar ProxyHTMLURLMap "http://webcal.domain.com /webcal"
  637     </Location>
  638 
  639 
  640     <Location /intranet/>
  641         ProxyPassReverse /
  642         PerlAddVar ProxyHTMLURLMap "/ /intranet/"
  643         PerlAddVar ProxyHTMLURLMap "http://intranet.domain.com /intranet"
  644     # Rewrite links that give access to the two previous location 
  645         PerlAddVar ProxyHTMLURLMap "/intranet/webmail /webmail"
  646         PerlAddVar ProxyHTMLURLMap "/intranet/webcal /webcal"
  647     </Location>
  648 
  649 This gives access two a webmail and webcal application hosted internally to all
  650 authentified users through their own Internet acces. There's also one acces to
  651 an Intranet portal that have links to the webcal and webmail application. Those
  652 links must be rewritten twice to works.
  653 
  654 =head1 ROT13 obfuscation
  655 
  656 Some links can be obfucated to be hidden from google or other robots. To enable
  657 encode/decode of those links you can use the ProxyHTMLRot13Links directive as
  658 follow:
  659 
  660     PerlAddVar ProxyHTMLRot13Links All
  661 
  662 All links in the page will be decoded before being rewritten and re-encoded.
  663 
  664 If obfuscation occurs on some attributs only you can set the value as a pair
  665 of element:attribut where the decoding/encoding must be applied. For example:
  666 
  667     PerlAddVar ProxyHTMLRot13Links a:data-href
  668     PerlAddVar ProxyHTMLRot13Links a:href
  669 
  670 =head1 BUGS 
  671 
  672 Apache2::ModProxyPerlHtml is still under development and is pretty
  673 stable. Please send me email to submit bug reports or feature
  674 requests.
  675 
  676 =head1 COPYRIGHT
  677 
  678 Copyright (c) 2005-2020 - Gilles Darold
  679 
  680 All rights reserved.  This program is free software; you may redistribute
  681 it and/or modify it under the same terms as Perl itself.
  682 
  683 =head1 AUTHOR
  684 
  685 Apache2::ModProxyPerlHtml was created by :
  686 
  687     Gilles Darold
  688     <gilles at darold dot net>
  689 
  690 and is currently maintain by me.
  691