ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/apache2-frontend/proxy_impl.pm
Revision: 1.1
Committed: Mon Jun 15 18:16:47 2015 UTC (8 years, 11 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# Content
1 package proxy_impl;
2
3 use overload;
4
5 sub uriregex {
6 overload::constant qr => sub {
7 local $_ = shift;
8
9 s/\./\\./g;
10 s/ยท/./g;
11 s/\*\*/.*/g;
12
13 $_
14 };
15 }
16
17 BEGIN { uriregex }
18
19 use Apache2::Const -compile => qw(
20 OK DECLINED DONE NOT_FOUND SERVER_ERROR AUTH_REQUIRED FORBIDDEN
21 PROXYREQ_REVERSE
22 );
23 use Apache2::RequestUtil ();
24 use Apache2::RequestRec ();
25 use Apache2::Connection ();
26 use Apache2::Util ();
27 use Apache2::URI ();
28
29 use APR::Const -compile => qw(
30 FILETYPE_DIR FINFO_NORM
31 );
32 use APR::Error ();
33 use APR::Finfo ();
34
35 use common::sense;
36
37 # per-request values, cached here for performance, use them
38 our $req; # Apache2::RquestRec
39 our $host; # $req->hostname
40 our $uri; # $req->uri, already resolved .. and protects against %xx, hopefully
41 our $ip; # $req->connection->client_ip, alternative ->useragent_ip
42
43 # finish immediately with given status
44 sub status($) {
45 die \(my $status = shift);
46 }
47
48 #sub escape_path($) {
49 # Apache2::Util::escape_path shift, $req->pool
50 #}
51
52 # escapes everything not allowed in a url hpath
53 sub pesc($) {
54 local $_ = shift;
55
56 s/([^A-Za-z0-9\$\-_.+!*'(),;?&=]\/)/sprintf "%02x", ord $1/ge;
57
58 $_
59 }
60
61 # external redirect with status code
62 sub redirect($$) {
63 my ($status, $location) = @_;
64
65 # $location =~ s,^(http://[^/:]+)/,$1:34567/,;#d#
66
67 $req->headers_out->set (Location => $location);
68 status $status;
69 }
70
71 # permanent external redirect
72 sub rperm($) {
73 redirect 301, shift
74 }
75
76 # temporary redirect, could be internal, but never is
77 sub rtemp($) {
78 redirect 302, shift
79 }
80
81 # serve some path, do not call directly
82 sub _rpathname($) {
83 my $path = shift;
84
85 my $finfo = eval { APR::Finfo::stat $path, APR::Const::FINFO_NORM, $req->pool }
86 or status Apache2::Const::NOT_FOUND;
87
88 # let mod_dir, mod_autoindex and the default-handler handle this
89 $req->filename ($path);
90 $req->finfo ($finfo);
91 # warn "serve <$path,",$req->handler,">\n";#d#
92 status Apache2::Const::OK;
93 }
94
95 # serve a regular file from disk
96 sub rfile($) {
97 $req->handler ("default-handler");
98 &_rpathname
99 }
100
101 # serve a directory from disk
102 sub rdir($) {
103 my $path = shift;
104
105 if ($req->uri !~ m,/$,) {
106 # redirect dir to dir/
107 rperm $req->construct_url (pesc $req->uri . "/");
108
109 } elsif (-e "$path/index.html") {
110 # mod_dir emulation, display index.html if any
111 $req->content_type ("text/html");
112 rfile "$path/index.html";
113 } elsif (-e "$path/index.xhtml") {
114 $req->content_type ("text/html"); # we assume to follow the compatibility guidelines
115 rfile "$path/index.xhtml";
116
117 } else {
118 # let mod_autoindex handle it later
119 $req->handler ("httpd/unix-directory");
120 _rpathname $path;
121 }
122 }
123
124 # like rpath, but assumes caller already stat'ed
125 sub rpath_nostat {
126 -d _ ? &rdir : &rfile
127 }
128
129 # serve a generic path, can be dir or file
130 sub rpath($) {
131 stat $_[0];
132 &rpath_nostat
133 }
134
135 # run a cgi script, first argument is script uri
136 sub rcgi($$) {
137 my ($name, $path) = @_;
138
139 (substr $uri, 0, length $name) eq $name
140 or status 500;
141
142 $req->path_info (substr $uri, length $name);
143
144 $req->handler ("cgi-script");
145 $req->notes->set ("alias-forced-type" => "cgi-script"); # leave a note for mod_cgi, so it ignores missing ExecCGI
146 _rpathname $path;
147 }
148
149 # reverse proxy
150 # path is local root uri
151 # target is target root url
152 # suffix is appended to target url
153 sub rproxy($$$@) {
154 my ($path, $target, $suffix, @lines) = @_;
155
156 $req->proxyreq (Apache2::Const::PROXYREQ_REVERSE);
157 $req->uri ($path);
158 $req->filename ("proxy:$target$suffix");
159 $req->handler ("proxy-server");
160 $req->subprocess_env->set ("proxy-sendchunked", 1);
161 #$notes->set ("proxy-nocanon", 1);
162 #$env->set ("proxy-initial-not-pooled", 1);
163
164 # disable compression, see http://www.apachetutor.org/admin/reverseproxies
165 # $req->headers_in->unset ("accept-encoding");
166 # alternatively recompress, SetOutputFilter INFLATE;DEFLATE
167
168 (my $cpath = $path) =~ s/([^A-Za-z0-9\/.\-_])/sprintf "\\x%02x", ord $1/ge;
169
170 push @lines, (
171 "ProxyPassReverse /",
172 "ProxyHTMLEnable on",
173 "ProxyHTMLURLMap $target $cpath",
174 "ProxyHTMLURLMap / $cpath/",
175 );
176
177 # warn "PROXY<$path,$target,$suffix>\n";#d#
178 # warn map "$_\n",@lines;
179
180 $req->add_config (\@lines, ~0, $path);
181
182 status Apache2::Const::OK;
183 }
184
185 my $rules;
186
187 sub load_rules {
188 open my $fh, "<:raw", Apache2::ServerUtil::server_root . "/rules"
189 or die Apache2::ServerUtil::server_root . "/rules: $!";
190 local $/;
191
192 $rules = <$fh>;
193
194 $rules = eval "BEGIN { uriregex }\nsub {\n#line 0 'rules'\n$rules\n}"
195 or die $@;
196
197 warn "proxy rules successfully loaded.\n";
198
199 Apache2::Const::OK
200 }
201
202 sub map_to_storage {
203 local $req = shift;
204 local ($host, $uri, $ip) = ($req->hostname, $req->uri, $req->connection->client_ip);
205
206 eval {
207 # the uri is pre-parsed and "protected" by apache
208 # the hostname is lowercased but otherwise completely unchecked,
209 # so better be safe than sorry
210 $host =~ /^[A-Za-z0-9\-.]+$/
211 or status 404;
212
213 # must have at least one dot
214 $host =~ /./
215 or status 404;
216
217 local $_ = "$host$uri";
218 $rules->($req);
219 };
220
221 if ($@) {
222 if (SCALAR:: eq ref $@) {
223 return ${$@};
224 } else {
225 die;
226 }
227 }
228
229 Apache2::Const::NOT_FOUND
230 }
231
232 load_rules;
233
234 warn "proxy loaded and iniitalised.\n";
235
236 1
237