"Fossies" - the Fresh Open Source Software Archive 
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/(\")($replacement|$pattern)(.*\")/$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