ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/apache2-frontend/proxy_impl.pm
Revision: 1.3
Committed: Tue Jun 16 12:52:13 2015 UTC (11 years, 3 months ago) by root
Branch: MAIN
Changes since 1.2: +11 -7 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,
140 # $1 and $2 MUST be SCRIPT_NAME and PATH_INFO, respectively
141 sub rcgi($) {
142 my ($path) = @_;
143
144 $req->uri ("$1$2");
145 $req->path_info ("$2");
146
147 $req->handler ("cgi-script");
148 $req->notes->set ("alias-forced-type" => "cgi-script"); # leave a note for mod_cgi, so it ignores missing ExecCGI
149 _rpathname $path;
150 }
151
152 # simplest reverse proxy, target is target url for this request
153 sub rproxy($) {
154 my ($target) = @_;
155
156 $req->proxyreq (Apache2::Const::PROXYREQ_REVERSE);
157 $req->filename ("proxy:$target");
158 $req->handler ("proxy-server");
159 $req->subprocess_env->set ("proxy-sendchunked", 1);
160 #$notes->set ("proxy-nocanon", 1);
161 #$env->set ("proxy-initial-not-pooled", 1);
162
163 # disable compression, see http://www.apachetutor.org/admin/reverseproxies
164 # $req->headers_in->unset ("accept-encoding");
165 # alternatively recompress, SetOutputFilter INFLATE;DEFLATE
166
167 status Apache2::Const::OK;
168 }
169
170 # host, port
171 # $1 and $2 MUST be SCRIPT_NAME and PATH_INFO, respectively
172 sub rscgi($;$) {
173 my ($target) = @_;
174
175 $req->uri ("$1$2");
176 $req->path_info ("$2");
177 rproxy $target;
178
179 # notes: uds_path
180 }
181
182 # reverse proxy
183 # path is local root uri
184 # target is target root url
185 # suffix is appended to target url
186 # @lines is extra config lines
187 sub rproxy_html($$$@) {
188 my ($path, $target, $suffix, @lines) = @_;
189
190 (my $cpath = $path) =~ s/([^A-Za-z0-9\/.\-_])/sprintf "\\x%02x", ord $1/ge;
191
192 push @lines, (
193 "ProxyPassReverse /",
194 "ProxyHTMLEnable on",
195 "ProxyHTMLURLMap $target $cpath",
196 "ProxyHTMLURLMap / $cpath/",
197 );
198
199 # warn "PROXY<$path,$target,$suffix>\n";#d#
200 # warn map "$_\n",@lines;
201
202 $req->add_config (\@lines, ~0, $path);
203
204 rproxy "$target$suffix";
205 }
206
207 my $rules;
208
209 sub load_rules {
210 open my $fh, "<:raw", Apache2::ServerUtil::server_root . "/rules"
211 or die Apache2::ServerUtil::server_root . "/rules: $!";
212 local $/;
213
214 $rules = <$fh>;
215
216 $rules = eval "use common::sense; BEGIN { uriregex }\nsub {\n#line 0 'rules'\n$rules\n}"
217 or die $@;
218
219 warn "proxy rules successfully loaded.\n";
220
221 Apache2::Const::OK
222 }
223
224 sub map_to_storage {
225 local $req = shift;
226 local ($host, $uri, $ip) = ($req->hostname, $req->uri, $req->connection->client_ip);
227
228 eval {
229 # the uri is pre-parsed and "protected" by apache
230 # the hostname is lowercased but otherwise completely unchecked,
231 # so better be safe than sorry
232 $host =~ /^[A-Za-z0-9\-.]+$/
233 or status 404;
234
235 # must have at least one dot
236 $host =~ /./
237 or status 404;
238
239 local $_ = "$host$uri";
240 $rules->($req);
241 };
242
243 if ($@) {
244 if (SCALAR:: eq ref $@) {
245 return ${$@};
246 } else {
247 die;
248 }
249 }
250
251 Apache2::Const::NOT_FOUND
252 }
253
254 load_rules;
255
256 warn "proxy loaded and iniitalised.\n";
257
258 1
259