ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/apache2-frontend/proxy_impl.pm
Revision: 1.2
Committed: Tue Jun 16 02:40:22 2015 UTC (11 years, 3 months ago) by root
Branch: MAIN
Changes since 1.1: +36 -18 lines
Log Message:
*** empty log message ***

File Contents

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