File Coverage

blib/lib/Lemonldap/NG/Handler/Proxy.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             ## @file
2             # Perl based proxy used to replace mod_proxy
3              
4             ## @class
5             # Perl based proxy used to replace mod_proxy
6             package Lemonldap::NG::Handler::Proxy;
7              
8 1     1   7015 use strict;
  1         2  
  1         54  
9              
10 1     1   668 use Lemonldap::NG::Handler::Main qw(:apache :headers :tsv);
  0            
  0            
11             use LWP::UserAgent;
12             use Lemonldap::NG::Handler::Main::Headers;
13             use Lemonldap::NG::Handler::Main::Logger;
14              
15             our $VERSION = '1.2.0';
16              
17             ##########################################
18             # COMPATIBILITY WITH APACHE AND APACHE 2 #
19             ##########################################
20              
21             BEGIN {
22             if ( MP() == 2 ) {
23             Apache2::compat->import();
24             }
25             *handler = ( MP() == 2 ) ? \&handler_mp2 : \&handler_mp1;
26             }
27              
28             ## @cmethod int handler_mp1()
29             # Launch run() when used under mod_perl version 1
30             # @return Apache constant
31             sub handler_mp1 ($$) { shift->run(@_); }
32              
33             ## @cmethod int handler_mp2()
34             # Launch run() when used under mod_perl version 2
35             # @return Apache constant
36             sub handler_mp2 : method {
37             shift->run(@_);
38             }
39              
40             *lmLog = *Lemonldap::NG::Handler::Main::lmLog;
41              
42             ########
43             # MAIN #
44             ########
45              
46             # Shared variables
47             our $r;
48             our $base;
49             our $headers_set;
50             our $UA = new LWP::UserAgent;
51             our $class;
52              
53             # IMPORTANT: LWP does not have to execute any redirection itself. This has to
54             # be done by the client itself, else cookies and other information may
55             # disappear.
56             $UA->requests_redirectable( [] );
57              
58             ## @cmethod int run(Apache2::RequestRec r)
59             # Main proxy method.
60             # Called for Apache response (PerlResponseHandler).
61             # @return Apache constant
62             sub run($$) {
63             ( $class, $r ) = splice @_;
64             my $url = $r->uri;
65             $url .= "?" . $r->args if ( $r->args );
66              
67             # Uncomment this if you have lost of session problem with SAP.
68             # I don't know why cookie value and URL parameter differs but it causes
69             # this problem. By removing URL parameters, all works fine. SAP bug ?
70              
71             # $url =~ s/sap-wd-cltwndid=[^\&]+//g;
72             return DECLINED unless ( $base = $r->dir_config('LmProxyPass') );
73             my $request = new HTTP::Request( $r->method, $base . $url );
74              
75             # Scan Apache request headers to generate LWP request headers
76             $r->headers_in->do(
77             sub {
78             return 1 if ( $_[1] =~ /^$/ );
79             $request->header(@_) unless ( $_[0] =~ /^(Host|Referer)$/i );
80             Lemonldap::NG::Handler::Main::Logger->lmLog(
81             "$class: header pushed to the server: " . $_[0] . ": " . $_[1],
82             'debug'
83             );
84             1;
85             }
86             );
87             $base =~ s/https?:\/\/([^\/]+).*$/$1/;
88             $request->header( Host => $base );
89              
90             # copy POST data, if any
91             if ( $r->method eq "POST" ) {
92             my $len = $r->headers_in->{'Content-Length'};
93             my $buf;
94             if ($len) {
95             $r->read( $buf, $len );
96             $request->content($buf);
97             }
98             }
99             $headers_set = 0;
100              
101             # For performance, we use a callback. See LWP::UserAgent for more
102             my $response = $UA->request( $request, \&cb_content );
103             if ( $response->code != 200 ) {
104             $class->headers($response) unless ($headers_set);
105             $r->print( $response->content );
106             }
107             return OK;
108             }
109              
110             ## @fn void cb_content(string chunk)
111             # Send datas received from remote server to the client.
112             # @param $chunk part of datas returned by HTTP server
113             sub cb_content {
114             my $chunk = shift;
115             unless ($headers_set) {
116             $class->headers(shift);
117             $headers_set = 1;
118             }
119             $r->print($chunk);
120             }
121              
122             ## @cmethod void headers(HTTP::Request response)
123             # Send headers received from remote server to the client.
124             # Replace "Location" header.
125             # @param $response current HTTP response
126             sub headers {
127             $class = shift;
128             my $response = shift;
129             my $tmp = $response->header('Content-Type');
130             $r->content_type($tmp) if ($tmp);
131             $r->status( $response->code );
132             $r->status_line( join ' ', $response->code, $response->message );
133              
134             # Scan LWP response headers to generate Apache response headers
135             my ( $location_old, $location_new ) = split /[;,]+/,
136             $r->dir_config('LmLocationToReplace');
137             my ( $cookieDomain_old, $cookieDomain_new ) = split /[;,]+/,
138             $r->dir_config('LmCookieDomainToReplace');
139              
140             $response->scan(
141             sub {
142              
143             # Replace Location headers
144             $_[1] =~ s#$location_old#$location_new#o
145             if ( $location_old and $location_new and $_[0] =~ /Location/i );
146              
147             # Replace Set-Cookie headers
148             $_[1] =~ s#$cookieDomain_old#$cookieDomain_new#o
149             if ( $cookieDomain_old
150             and $cookieDomain_new
151             and $_[0] =~ /Set-Cookie/i );
152              
153             Lemonldap::NG::Handler::Main::Headers->lmSetErrHeaderOut( $r, @_ );
154              
155             Lemonldap::NG::Handler::Main::Logger->lmLog(
156             "$class: header pushed to the client: " . $_[0] . ": " . $_[1],
157             'debug'
158             );
159             1;
160             }
161             );
162             $headers_set = 1;
163             }
164              
165             1;
166              
167             __END__