File Coverage

blib/lib/Apache/MONITOR.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Apache::MONITOR;
2              
3             require 5.005_62;
4 1     1   553 use strict;
  1         1  
  1         27  
5 1     1   4 use vars qw($VERSION @EXPORTER @ISA);
  1         1  
  1         59  
6 1     1   4 use warnings;
  1         3  
  1         22  
7 1     1   1137 use String::CRC::Cksum qw(cksum);
  0            
  0            
8              
9             use DB_File;
10              
11             require Exporter;
12             use AutoLoader qw(AUTOLOAD);
13              
14             our @ISA = qw(Exporter);
15              
16             our @EXPORT = qw(SUBSCRIBE UNSUBSCRIBE NOTIFY SHOW);
17             our $VERSION = '0.02';
18              
19             use URI::Escape;
20             use Apache::Constants qw(:common :http :response :methods);
21             use constant SUBSCRIBE_OK => 1;
22             use constant SUBSCRIBE_ALREADY => 2;
23             use constant SUBSCRIBE_ERROR => 3;
24              
25             my $original_handler;
26              
27             sub is_proxy_request
28             {
29             my $r = shift;
30             my $host = $r->header_in('Host');
31             return 0 unless( $host );
32             return ($r->server->server_hostname ne $host);
33             }
34              
35             sub handler {
36             my $r = shift;
37             $r->warn( "prr_handler 1");
38             $r->warn( "------------------------------------------" );
39             $r->warn( $r->the_request() );
40             my $href = $r->headers_in();
41             foreach (keys %$href)
42             {
43             $r->warn( "$_ -> $href->{$_}\n");
44             }
45             $r->warn( "------------------------------------------" );
46             $r->warn( $r->server->server_hostname );
47             $r->warn( $r->get_server_name );
48             if( is_proxy_request($r) )
49             {
50             $r->warn( "IS PROXYREQ");
51             }
52             return DECLINED unless $r->method() eq 'MONITOR' ;
53             $r->warn( "Filename " , $r->filename, "\n" );
54             $r->warn( "Uri " , $r->uri, "\n" );
55             $r->warn( "pathinfop " , $r->path_info, "\n" );
56             $r->warn( "prr_handler 2");
57            
58             $r->method_number(M_GET);
59            
60             return OK;
61             }
62              
63             sub hp_handler {
64             my $r = shift;
65             $r->warn( "hp handler 1");
66            
67             $r->set_handlers(PerlFixupHandler => undef);
68             return DECLINED unless $r->method() eq 'MONITOR' ;
69             $r->warn( "hp handler 2");
70              
71             $original_handler = $r->handler();
72            
73             $r->handler("perl-script");
74             $r->set_handlers(PerlHandler => [ \&monitor_handler ] );
75             $r->warn( "Filename " , $r->filename, "\n" );
76             $r->warn( "Uri " , $r->uri, "\n" );
77             $r->warn( "pathinfop " , $r->path_info, "\n" );
78             $r->warn( "hp handler 3");
79              
80             if( $r->proxyreq() )
81             {
82             $r->warn( "IS PROXYREQ");
83             $r->filename('');
84             }
85              
86             $r->set_handlers(PerlAccessHandler => undef);
87             $r->set_handlers(PerlAuthenHandler => undef);
88             $r->set_handlers(PerlDispatchHandler => undef);
89             $r->set_handlers(PerlTypeHandler => undef);
90             $r->set_handlers(PerlFixupHandler => [ \&fixup ]);
91            
92             return OK;
93             }
94              
95             sub fixup
96             {
97             my $r = shift;
98             $r->warn( "FIXUP1: handler is now " . $r->handler());
99              
100             $r->handler("perl-script");
101             $r->set_handlers(PerlHandler => [ \&monitor_handler ] );
102             $r->warn( "FIXUP2: handler is now " . $r->handler());
103              
104             $r->set_handlers(PerlFixupHandler => undef);
105              
106             return OK;
107             }
108              
109            
110            
111            
112             sub monitor_handler
113             {
114             my $r = shift;
115              
116             my $state = 'NONE';
117              
118             my $host = $r->header_in( 'Host' );
119             if( !defined $host || !$host)
120             {
121             #FIXME allow HTTP 1.0!
122             return BAD_REQUEST;
123             }
124              
125             my $monitored_uri = $r->uri;
126             if($r->uri !~ /:\/\//)
127             {
128             $monitored_uri = "http://$host" . $r->uri;
129             }
130             $r->warn( "monitored URI: $monitored_uri");
131              
132             my $mon_string = "";
133             if( is_proxy_request($r) )
134             {
135             $mon_string = "proxy:" . $monitored_uri;
136             my($cs,$rv,$msg) = poll_to_checksum($monitored_uri);
137             $state = $cs;
138             if($rv)
139             {
140             $r->warn( "error when polling remote resource: $msg");
141             }
142             }
143             else
144             {
145             my $monitor_code = get_monitor_code($r,$monitored_uri);
146             $r->warn( "monitor_code: " . ( $monitor_code ? $monitor_code : "undef" ));
147              
148             if( (!$monitor_code) && ( ($r->filename =~ /cgi/) || (! -f $r->filename)) )
149             {
150             $r->warn( "monitor_handler HTTP_METHOD_NOT_ALLOWED");
151             return HTTP_METHOD_NOT_ALLOWED;
152             }
153             if( $monitor_code )
154             {
155             $mon_string = "apply:" . $monitor_code;
156             }
157             else
158             {
159             $mon_string = "mtime:" . $r->filename;
160             }
161              
162             }
163            
164             $r->warn( "monitor_handler 3 , monstring=$mon_string");
165             my $reply_uri = $r->header_in( 'Reply-To' );
166            
167             if( !defined $reply_uri || !$reply_uri)
168             {
169             $r->warn( "--------BAD REQUEST -------------" );
170             $r->warn( $r->method );
171             $r->warn( $r->method_number );
172             $r->warn( "--------BAD REQUEST -------------" );
173             return BAD_REQUEST;
174             }
175              
176            
177             my ($mon_url,$rv) = add_subscription($r,$monitored_uri,$mon_string,$state,$reply_uri);
178             if($rv == SUBSCRIBE_ERROR)
179             {
180             return SERVER_ERROR;
181             }
182            
183             if(
184             ($r->header_in('Accept') =~ /text\/html/)
185             || ($r->header_in('Accept') =~ /\*\/\*/)
186              
187             )
188             {
189             my $msg = ($rv == SUBSCRIBE_OK) ? "You have been subscribed to the URL"
190             : "You are already subscribed to the URL";
191             $r->status(200);
192             $r->send_http_header("text/html");
193            
194             $r->print(qq{
195            
196             Subscribed
197            
198             $msg
199             $monitored_uri
200            
201            
202             To edit or remove your subscription, visit the
203             monitor page
204            
205            
206             });
207             }
208             else
209             {
210             $r->header_out('Content-type' => undef);
211             $r->header_out('Content-Type' => undef);
212             $r->header_out("Location" => $mon_url );
213             $r->status(201);
214             $r->send_http_header();
215             }
216            
217             return OK;
218             }
219              
220             sub moo
221             {
222             my $r = shift;
223              
224            
225              
226             my $dir = $r->dir_config('MonitorDataDir');
227             my $host = $r->header_in( 'Host' );
228             my $mon_uri = 'http://' . $host . $r->uri();
229              
230             if($r->method eq "GET")
231             {
232             my %uris;
233             my %monitors;
234              
235             open(LOCK,">$dir/lock") || die("unable to open $dir/lock, $!");
236             flock(LOCK,1);
237              
238             dbmopen(%monitors , "$dir/monitors", 0666) || die("unable to open $dir/monitors, $!");
239             my $value = $monitors{$mon_uri};
240             dbmclose(%monitors);
241             close(LOCK);
242              
243             if(!defined $value)
244             {
245             return NOT_FOUND;
246             }
247              
248              
249             my ($u,$re) = split( / / , $value);
250              
251             $r->send_http_header("text/html" );
252             $r->print( qq{
253            
254            
255             Monitor $mon_uri
256            
257            
258            
259            

260             Monitor $mon_uri
261            

262              
263            

Monitors: $u

264             Reply-To: $re
265            

266            
275              
276            
277            
278            
279            
280            
281            
282             });
283             return OK;
284              
285             }
286             elsif($r->method eq "POST")
287             {
288             my %params = $r->content;
289             return HTTP_METHOD_NOT_ALLOWED;
290             }
291             elsif($r->method eq "DELETE")
292             {
293             my %uris;
294             my %monitors;
295             my $uri_still_monitored = 0;
296              
297             open(LOCK,">$dir/lock") || die("unable to open $dir/lock, $!");
298             flock(LOCK,2);
299              
300             dbmopen(%monitors , "$dir/monitors", 0666) || die("unable to open $dir/monitors, $!");
301             if(!exists($monitors{$mon_uri}))
302             {
303             dbmclose(%monitors);
304             close(LOCK);
305             return NOT_FOUND;
306             }
307             my ($monitored_uri,$re) = split(/ / , $monitors{$mon_uri});
308             delete $monitors{$mon_uri};
309             foreach my $muri (keys %monitors)
310             {
311             die("XXXXX") if($mon_uri eq $muri);
312             my $value = $monitors{$muri};
313             my ($u,$re) = split(/ / , $value);
314             if($u eq $monitored_uri)
315             {
316             $uri_still_monitored = 1;
317             last;
318             }
319             }
320             dbmclose(%monitors);
321             if(!$uri_still_monitored)
322             {
323             dbmopen(%uris , "$dir/uris", 0666) || die("unable to open $dir/uris, $!");
324             delete $uris{$monitored_uri};
325             dbmclose(%uris);
326             }
327             close(LOCK);
328            
329             $r->send_http_header("text/html" );
330             $r->print( qq{
331            
332            
333             Deleted Monitor $mon_uri
334            
335            
336            
337             Monitor $mon_uri has been deleted.
338            
339            
340             });
341              
342             }
343              
344             return OK;
345             }
346              
347             sub show_monitors
348             {
349             my $r = shift;
350             my %uris;
351             my %monitors;
352             my $dir = $r->dir_config('MonitorDataDir');
353             my $host = $r->header_in( 'Host' );
354             my $mon_uri = 'http://' . $host . $r->uri();
355              
356             $r->send_http_header("text/html" );
357             $r->print( qq{
358            
359            
360             Monitors
361            
362            
363             });
364            
365              
366              
367             open(LOCK,">$dir/lock") || die("unable to open $dir/lock, $!");
368             flock(LOCK,1);
369              
370             dbmopen( %uris , "$dir/uris" , 0040) || die("unable to open $dir/uris, $!");
371             dbmopen( %monitors , "$dir/monitors" , 0040) || die("unable to open $dir/monitors, $!");
372             foreach my $uri ( keys %uris)
373             {
374             my $value = $uris{$uri};
375             my ($u,$mon_string,$t,$state) = split(/ /,$value);
376             $r->print(qq{

$u
\n});

377             foreach my $muri (keys %monitors)
378             {
379             my $value = $monitors{$muri};
380             #print "-- $value --\n";
381             my ($u,$re) = split(/ / , $value);
382             if($u eq $uri)
383             {
384             $r->print(qq{
385                $muri 
386             ($re) [$mon_string]
\n});
387             }
388             }
389             $r->print("

\n");
390             }
391             dbmclose(%uris);
392             dbmclose(%monitors);
393              
394             close(LOCK);
395             }
396            
397              
398             sub add_subscription
399             {
400             my ($r,$uri,$mon_string,$state,$reply_to) = @_;
401              
402             my $dir = $r->dir_config('MonitorDataDir');
403             my $mon_prefix = $r->dir_config('MonitorUrlPrefix');
404              
405             my $monitor_url = $mon_prefix;
406             my %uris;
407             my %monitors;
408              
409              
410             open(LOCK,">$dir/lock") || die("unable to open $dir/lock, $!");
411             flock(LOCK,2);
412              
413             dbmopen( %uris , "$dir/uris", 0666) || die("unable to open $dir/uris, $!");
414             if(! exists $uris{$uri})
415             {
416             my $now = time();
417             my $value = join(' ', ($uri,$mon_string,$now,$state) );
418             $uris{$uri} = $value;
419             }
420             dbmclose(%uris);
421              
422             dbmopen( %monitors , "$dir/monitors", 0666) || die("unable to open $dir/monitors, $!");
423             foreach my $muri (keys %monitors)
424             {
425             my $value = $monitors{$muri};
426             my ($u,$re) = split (/ /,$value);
427             if( ($u eq $uri) && ($re eq $reply_to) )
428             {
429            
430             dbmclose(%monitors);
431             close(LOCK);
432             return ($muri,SUBSCRIBE_ALREADY);
433             }
434             }
435             my $id = time() . $$;
436             $monitor_url .= $id;
437             $monitors{$monitor_url} = "$uri $reply_to";
438             dbmclose(%monitors);
439             close(LOCK);
440              
441              
442             return ($monitor_url,SUBSCRIBE_OK);
443             }
444            
445              
446             sub get_monitor_code
447             {
448             my ($r,$monitored_uri) = @_;
449             return undef;
450             return "checker";
451             }
452              
453              
454              
455              
456              
457             sub SUBSCRIBE
458             {
459             require LWP::UserAgent;
460             @Apache::MONITOR::ISA = qw(LWP::UserAgent);
461              
462             my $ua = __PACKAGE__->new;
463            
464             my $args = @_ ? \@_ : \@ARGV;
465              
466             my ($url,$reply_to,$proxy) = @$args;
467             $ua->proxy(['http'], $proxy ) if(defined $proxy);
468             my $req = HTTP::Request->new('MONITOR' => $url );
469              
470             $req->header('Reply_To' => $reply_to );
471             #$req->header('Accept' => 'text/plain' );
472             my $res = $ua->request($req);
473              
474             if($res->is_success)
475             {
476             print $res->as_string();
477             print "Monitor created at: ",$res->header('Location') , "\n";
478             }
479             else
480             {
481             print $res->as_string();
482             }
483              
484             }
485             sub UNSUBSCRIBE
486             {
487             require LWP::UserAgent;
488             @Apache::MONITOR::ISA = qw(LWP::UserAgent);
489              
490             my $ua = __PACKAGE__->new;
491            
492             my $args = @_ ? \@_ : \@ARGV;
493              
494             my ($mon_url) = @$args;
495             my $req = HTTP::Request->new('DELETE' => $mon_url );
496              
497             my $res = $ua->request($req);
498              
499             if($res->is_success)
500             {
501             print $res->as_string();
502             #print $res->content;
503             print "Monitor deleted\n";
504             }
505             else
506             {
507             print $res->as_string();
508             }
509              
510             }
511              
512             sub NOTIFY
513             {
514             require LWP::UserAgent;
515             @Apache::MONITOR::ISA = qw(LWP::UserAgent);
516             my $ua = __PACKAGE__->new;
517             my $args = @_ ? \@_ : \@ARGV;
518              
519             my ($dir) = @$args;
520              
521             my %uris;
522             my %monitors;
523              
524             open(LOCK,">$dir/lock") || die("unable to open $dir/lock, $!");
525             flock(LOCK,2);
526              
527             dbmopen( %uris , "$dir/uris" , 0040) || die("unable to open $dir/uris, $!");
528             dbmopen( %monitors , "$dir/monitors" , 0040) || die("unable to open $dir/monitors, $!");
529             foreach my $monitored_uri ( keys %uris )
530             {
531             my $value = $uris{$monitored_uri};
532             my ($u,$mon_string,$lastmod,$state) = split(/ /,$value);
533             my $modified_time = $lastmod;
534             #print "--$u $mon_string $lastmod\n";
535             print "*--------------------------------------------------\n";
536              
537             if( $mon_string =~ /^apply:(.+)$/ )
538             {
539             # apply code
540             my $code = $1;
541             require "/tmp/" . $code;
542             $modified_time = $code->check($u);
543             }
544             elsif( $mon_string =~ /^mtime:(.+)$/ )
545             {
546             my $filename = $1;
547             print "$monitored_uri: checking file mtime of $filename\n";
548             my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
549             $atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
550             $modified_time = $mtime;
551             }
552             else
553             {
554             my $old_checksum = $state;
555             print "$monitored_uri: checking checksum via HTTP GET\n";
556             my ($checksum,$rv,$msg) = poll_to_checksum($monitored_uri);
557             if($rv)
558             {
559             print "$monitored_uri: ",$msg, "\n";
560             next;
561             }
562             print " ....old checksum $old_checksum\n";
563             print " ....new checksum $checksum\n";
564             if( $checksum != $old_checksum)
565             {
566             $modified_time = time();
567             $state = $checksum;
568             }
569             }
570            
571             next unless ($modified_time > $lastmod);
572              
573             print "...$monitored_uri has changed, getting monitors\n";
574              
575             # updating record with new lastmod
576              
577             $uris{$monitored_uri} = "$u $mon_string $modified_time $state";
578              
579             foreach my $muri (keys %monitors)
580             {
581             my $value = $monitors{$muri};
582             my ($u,$re) = split(/ / , $value);
583             next unless ($u eq $monitored_uri);
584              
585             #my $req = HTTP::Request->new('GET' => $monitored_uri);
586             #my $res = $ua->request($req);
587             #my $body;
588             #if($res->is_success)
589             #{
590             # $body = $res->content;
591             #}
592             #else
593             #{
594             # $body = $res->as_string();
595             #}
596             #$req->header('Reply_To' => $reply_to );
597              
598             if( $re =~ /^mailto:(.*)$/ )
599             {
600             my $to = $1;
601             open(MAIL,"|mail $to -s \"Resource $monitored_uri has changed\"");
602             print MAIL "Resource state has changed at ". localtime($modified_time) ."\n";
603             print MAIL "View the monitored resource: $monitored_uri\n";
604             print MAIL "Edit your monitor: $muri\n";
605             close(MAIL);
606             print " notified $re\n";
607             }
608             }
609            
610             }
611             dbmclose(%uris);
612             dbmclose(%monitors);
613              
614             close(LOCK);
615              
616             }
617             sub poll_to_checksum
618             {
619             require LWP::UserAgent;
620             @Apache::MONITOR::ISA = qw(LWP::UserAgent);
621             my $ua = __PACKAGE__->new;
622             my $args = @_ ? \@_ : \@ARGV;
623              
624             my ($uri) = @$args;
625              
626             my $req = HTTP::Request->new('GET' => $uri);
627             my $res = $ua->request($req);
628             if($res->is_success)
629             {
630             my $s = $res->content;
631             $s =~ s/]+>//gi;
632             my $cs = cksum($s);
633             return ($cs,0,'');
634             }
635             else
636             {
637             return (0,1,'GET error');
638             }
639             }
640              
641             1;
642             __END__