1 |
3 |
ahitrov@rambler.ru |
package Contenido::Apache; |
2 |
|
|
|
3 |
|
|
# ---------------------------------------------------------------------------- |
4 |
|
|
# ����� ����� ��������� ��� �������� Apache... |
5 |
|
|
# ---------------------------------------------------------------------------- |
6 |
|
|
|
7 |
|
|
use strict; |
8 |
|
|
use warnings; |
9 |
|
|
use locale; |
10 |
|
|
|
11 |
|
|
use vars qw($VERSION); |
12 |
|
|
$VERSION = '7.0'; |
13 |
|
|
|
14 |
|
|
use Apache::Constants; |
15 |
|
|
use Apache::Request; |
16 |
|
|
|
17 |
|
|
use Contenido::Globals; |
18 |
|
|
use Contenido::Project; |
19 |
|
|
use Contenido::Request; |
20 |
|
|
use Contenido::State; |
21 |
|
|
|
22 |
|
|
use Contenido::Keeper; |
23 |
|
|
use Contenido::Object; |
24 |
|
|
use Contenido::User; |
25 |
|
|
use Contenido::Document; |
26 |
|
|
use Contenido::Section; |
27 |
|
|
use Contenido::Link; |
28 |
|
|
|
29 |
|
|
use Contenido::Init; |
30 |
|
|
use Contenido::Logger; |
31 |
|
|
|
32 |
|
|
# ---------------------------------------------------------------------------- |
33 |
|
|
# �������, ������� ����������� ��� ������ ������� ������ ��������� �������� |
34 |
|
|
# web-�������. |
35 |
|
|
# ---------------------------------------------------------------------------- |
36 |
|
|
sub child_init { |
37 |
|
|
my $r = shift; |
38 |
|
|
|
39 |
|
|
$log->info("������������ �������� ��������� �������� Apache") if $DEBUG; |
40 |
|
|
|
41 |
|
|
my $project_keeper_module; |
42 |
|
|
eval { |
43 |
|
|
$project_keeper_module=$state->project().'::Keeper'; |
44 |
|
|
$keeper = $project_keeper_module->new($state); |
45 |
|
|
}; |
46 |
|
|
if ($@) { |
47 |
|
|
$log->error("�� ���� ���������������� $project_keeper_module ��-��: $@"); |
48 |
|
|
die; |
49 |
|
|
} |
50 |
|
|
|
51 |
|
|
for my $plugin ($state->project, split(/\s+/, $state->plugins)) { |
52 |
|
|
my $class = $plugin.'::Apache'; |
53 |
|
|
eval { $class->child_init($r); }; |
54 |
|
|
if ( $@ ) { |
55 |
|
|
$log->error("�� ���� ��������� ����� child_init ������� $plugin ($class) �� ������� '$@'"); |
56 |
|
|
} |
57 |
|
|
} |
58 |
|
|
|
59 |
|
|
return OK; |
60 |
|
|
} |
61 |
|
|
|
62 |
|
|
# ---------------------------------------------------------------------------- |
63 |
|
|
# �������, ������� ����������� � ����� ������ ��������� ������� ������������. |
64 |
|
|
# ---------------------------------------------------------------------------- |
65 |
|
|
sub request_init { |
66 |
|
|
my $r = shift; |
67 |
|
|
|
68 |
|
|
$r = ref($r) eq 'Apache::Request' ? $r : Apache::Request->instance($r); |
69 |
|
|
|
70 |
|
|
my $URI = $r->uri; |
71 |
|
|
my $ARGS = $r->args; |
72 |
|
|
|
73 |
|
|
$log->info("������ ��������� ������� ".$URI.($ARGS ? "?$ARGS":'')) if $DEBUG; |
74 |
|
|
|
75 |
|
|
$state->_refresh_(); |
76 |
|
|
|
77 |
|
|
$request = Contenido::Request->new($state); |
78 |
|
|
|
79 |
|
|
if ($DEBUG) { |
80 |
|
|
$request->{_start} = Time::HiRes::time(); |
81 |
|
|
$Contenido::Globals::DB_TIME = 0; |
82 |
|
|
$Contenido::Globals::CORE_TIME = 0; |
83 |
|
|
$Contenido::Globals::DB_COUNT = 0; |
84 |
|
|
$Contenido::Globals::RPC_TIME = 0; |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
if (ref($r)) { |
88 |
|
|
|
89 |
|
|
my %headers = $r->headers_in(); |
90 |
|
|
my $ip = $headers{'X-Real-IP'} ? $headers{'X-Real-IP'} : $r->connection->remote_ip(); |
91 |
|
|
my @ips = split(/\s*,\s*/, $ip); |
92 |
|
|
$ip = $ips[ $#ips ]; |
93 |
|
|
|
94 |
|
|
$request->set_properties ( |
95 |
|
|
'uri' => $URI||'', |
96 |
|
|
'query' => $r->args()||'', |
97 |
|
|
'ip' => $ip||'', |
98 |
|
|
'user' => $r->connection->user()||'', |
99 |
|
|
'http_host' => $ENV{HTTP_HOST}, |
100 |
|
|
'r' => $r, |
101 |
|
|
) |
102 |
|
|
} |
103 |
|
|
$project->restore($keeper); |
104 |
|
|
|
105 |
|
|
for my $plugin ($state->project, split(/\s+/, $state->plugins)) { |
106 |
|
|
my $class = $plugin.'::Apache'; |
107 |
|
|
eval { $class->request_init($r); }; |
108 |
|
|
if ( $@ ) { |
109 |
|
|
$log->error("�� ���� ��������� ����� request_init ������� $plugin ($class) �� ������� '$@'"); |
110 |
|
|
} |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
return OK; |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
sub is_valid_request { |
117 |
|
|
my $r = shift; |
118 |
38 |
ahitrov@rambler.ru |
if ($r->uri =~ /^(?:\/i\/|\/images\/|\/binary\/)/ or ($r->content_type && !($r->content_type =~ m#(?:^text/|javascript|json|^httpd/unix-directory)#i || $r->content_type =~ /rss/i)) ) { |
119 |
3 |
ahitrov@rambler.ru |
return 0; |
120 |
|
|
} else { |
121 |
|
|
return 1; |
122 |
|
|
} |
123 |
|
|
} |
124 |
|
|
#���������� ������� (������������ ����� ������ ������... ��� ��� ����� ��� ������ ��������������� ��� ����� ���������� ���������� |
125 |
|
|
sub cleanup { |
126 |
|
|
my $r = shift; |
127 |
|
|
|
128 |
|
|
#����� ���������� ���������� ������� |
129 |
|
|
$user = undef; |
130 |
|
|
$session = undef; |
131 |
|
|
|
132 |
|
|
return Apache::Constants::DECLINED unless Contenido::Apache::is_valid_request($r); |
133 |
|
|
|
134 |
|
|
#��������� ���������� ������ � memcached |
135 |
|
|
if ($state->{memcached_enable} and $request->{_to_memcache}) { |
136 |
|
|
while ( my ($key, $values) = each(%{$request->{_to_memcache}}) ) { |
137 |
|
|
my ($value, $expire, $mode) = @$values; |
138 |
|
|
if (ref($key) or !$key) { |
139 |
|
|
$log->warning("bad key value in set ($key)"); |
140 |
|
|
next; |
141 |
|
|
} |
142 |
|
|
$mode ||= 'set'; |
143 |
|
|
if ($mode eq 'add') { |
144 |
|
|
$keeper->{MEMD}->add($key, $value, $expire); |
145 |
|
|
} elsif ($mode eq 'delete') { |
146 |
|
|
$keeper->{MEMD}->delete($key); |
147 |
|
|
#�� ��������� set |
148 |
|
|
} else { |
149 |
|
|
$keeper->{MEMD}->set($key, $value, $expire); |
150 |
|
|
} |
151 |
|
|
} |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
for my $plugin ($state->project, split(/\s+/, $state->plugins)) { |
155 |
|
|
my $class = $plugin.'::Apache'; |
156 |
|
|
next unless ($class->can('cleanup')); |
157 |
|
|
eval { $class->cleanup($r); }; |
158 |
|
|
if ( $@ ) { |
159 |
|
|
$log->error("�� ���� ��������� ����� request_init ������� $plugin ($class) �� ������� '$@'"); |
160 |
|
|
} |
161 |
|
|
} |
162 |
|
|
|
163 |
|
|
# ������������� �� ���� ������� � �������� |
164 |
|
|
# (���� �� ������������ ���������� �����������) |
165 |
|
|
# ����� ���������� ������������ �������� �������������� ���������� |
166 |
|
|
unless ($state->db_type eq 'none') { |
167 |
|
|
$keeper->shutdown unless $state->db_keepalive; |
168 |
|
|
$keeper->{_connect_ok} = 0; |
169 |
|
|
$keeper->t_shutdown(1); |
170 |
|
|
} |
171 |
|
|
for (split /\s+/, $state->plugins) { |
172 |
|
|
next unless $keeper->{$_}; |
173 |
|
|
next if $state->{$_}->db_type eq 'none'; |
174 |
|
|
$keeper->{$_}->shutdown unless $state->{$_}->db_keepalive; |
175 |
|
|
$keeper->{$_}->{_connect_ok} = 0; |
176 |
|
|
$keeper->{$_}->t_shutdown(1); |
177 |
|
|
} |
178 |
|
|
|
179 |
|
|
if ($DEBUG) { |
180 |
|
|
my $finish = Time::HiRes::time(); |
181 |
|
|
my $time = int(10000*($finish-$request->{_start}))/10; |
182 |
|
|
my $db_time = int(10000*($Contenido::Globals::DB_TIME)/10); |
183 |
|
|
my $core_time = int(10000*($Contenido::Globals::CORE_TIME)/10); |
184 |
|
|
my $rpc_time = int(10000*($Contenido::Globals::RPC_TIME)/10); |
185 |
|
|
$log->info("DEBUG: $$ ".__PACKAGE__." ".scalar(localtime())." ".($r->uri || '').($r->args ? '?'.$r->args : '')." worked $time ms, database time $db_time ms, rpc time $rpc_time ms, core time: $core_time ms, db requests count: $Contenido::Globals::DB_COUNT"); |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
$request = undef; |
189 |
|
|
|
190 |
|
|
return OK; |
191 |
|
|
} |
192 |
|
|
|
193 |
|
|
# ---------------------------------------------------------------------------- |
194 |
|
|
# �������, ������� ����������� ��� ��������� ������ ��������� �������� |
195 |
|
|
# web-�������... |
196 |
|
|
# ---------------------------------------------------------------------------- |
197 |
|
|
sub child_exit { |
198 |
|
|
my $r = shift; |
199 |
|
|
|
200 |
|
|
for my $plugin ($state->project, split(/\s+/, $state->plugins)) { |
201 |
|
|
my $class = $plugin.'::Apache'; |
202 |
|
|
eval { $class->child_exit($r); }; |
203 |
|
|
if ( $@ ) { |
204 |
|
|
$log->error("�� ���� ��������� ����� child_exit ������� $plugin ($class) �� ������� '$@'"); |
205 |
|
|
} |
206 |
|
|
} |
207 |
|
|
unless ($state->db_type eq 'none') { |
208 |
|
|
$keeper->shutdown; |
209 |
|
|
} |
210 |
|
|
|
211 |
|
|
$log->info("������������ ������ ��������� �������� Apache.") if ($DEBUG); |
212 |
|
|
|
213 |
|
|
return OK; |
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
|
217 |
|
|
# ---------------------------------------------------------------------------- |
218 |
|
|
# ������� ��� ��������������. |
219 |
|
|
# - ���� ��� �������� ��� ������������� ����������, �� ������ |
220 |
|
|
# ������������� ������ ���� ������� 1 (���������) |
221 |
|
|
# ---------------------------------------------------------------------------- |
222 |
|
|
sub authentication { |
223 |
|
|
my $r = shift; |
224 |
|
|
|
225 |
|
|
return Apache::Constants::DECLINED unless Contenido::Apache::is_valid_request($r); |
226 |
|
|
return FORBIDDEN if $state->db_type eq 'none'; |
227 |
|
|
|
228 |
|
|
my ($res, $sent_pw) = $r->get_basic_auth_pw(); |
229 |
|
|
return $res if $res != OK; |
230 |
|
|
|
231 |
|
|
my $username = $r->connection->user(); |
232 |
|
|
|
233 |
|
|
$keeper->db_connect unless $keeper->is_connected; |
234 |
|
|
$user = $keeper->get_user_by_login($username); |
235 |
|
|
$keeper->shutdown unless $state->db_keepalive; |
236 |
|
|
|
237 |
|
|
if (ref($user) && ($user->login() eq $username) && ($user->passwd() eq $sent_pw) && $user->passwd() && $user->status == 1) { |
238 |
|
|
return OK; |
239 |
|
|
} else { |
240 |
|
|
$log->warning("������� ����������� � �������� ����� �����/������ ($username, $sent_pw)"); |
241 |
|
|
$r->note_basic_auth_failure(); |
242 |
|
|
return AUTH_REQUIRED; |
243 |
|
|
} |
244 |
|
|
} |
245 |
|
|
|
246 |
|
|
1; |