| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
################################################################# |
|
2
|
|
|
|
|
|
|
# |
|
3
|
|
|
|
|
|
|
# Hook::Filter - A runtime filtering layer on top of subroutine calls |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# $Id: Filter.pm,v 1.12 2008/08/26 08:13:30 erwan_lemonnier Exp $ |
|
6
|
|
|
|
|
|
|
# |
|
7
|
|
|
|
|
|
|
# 051105 erwan Created |
|
8
|
|
|
|
|
|
|
# 060301 erwan Recreated |
|
9
|
|
|
|
|
|
|
# 070516 erwan Updated POD and license, added flush_rules and add_rule |
|
10
|
|
|
|
|
|
|
# 070522 erwan More POD + don't use rule file unless 'rules' specified in import |
|
11
|
|
|
|
|
|
|
# 070523 erwan Can use 'rules' multiple time if same rule file specified |
|
12
|
|
|
|
|
|
|
# 070523 erwan POD updates |
|
13
|
|
|
|
|
|
|
# 070524 erwan Import parameter 'hook' is now mandatory |
|
14
|
|
|
|
|
|
|
# |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
package Hook::Filter; |
|
17
|
|
|
|
|
|
|
|
|
18
|
6
|
|
|
6
|
|
306694
|
use 5.006; |
|
|
6
|
|
|
|
|
26
|
|
|
|
6
|
|
|
|
|
256
|
|
|
19
|
6
|
|
|
6
|
|
38
|
use strict; |
|
|
6
|
|
|
|
|
25
|
|
|
|
6
|
|
|
|
|
213
|
|
|
20
|
6
|
|
|
6
|
|
31
|
use warnings; |
|
|
6
|
|
|
|
|
15
|
|
|
|
6
|
|
|
|
|
276
|
|
|
21
|
6
|
|
|
6
|
|
171
|
use Carp qw(confess croak); |
|
|
6
|
|
|
|
|
17
|
|
|
|
6
|
|
|
|
|
501
|
|
|
22
|
6
|
|
|
6
|
|
41
|
use File::Spec; |
|
|
6
|
|
|
|
|
12
|
|
|
|
6
|
|
|
|
|
171
|
|
|
23
|
6
|
|
|
6
|
|
2774
|
use Hook::Filter::Rule; |
|
|
6
|
|
|
|
|
21
|
|
|
|
6
|
|
|
|
|
212
|
|
|
24
|
6
|
|
|
6
|
|
44
|
use Hook::Filter::RulePool qw(get_rule_pool); |
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
374
|
|
|
25
|
6
|
|
|
6
|
|
39
|
use Hook::Filter::Hooker qw(filter_sub); |
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
529
|
|
|
26
|
6
|
|
|
6
|
|
37
|
use base qw(Exporter); |
|
|
6
|
|
|
|
|
16
|
|
|
|
6
|
|
|
|
|
550
|
|
|
27
|
6
|
|
|
6
|
|
38
|
use Data::Dumper; |
|
|
6
|
|
|
|
|
14
|
|
|
|
6
|
|
|
|
|
8068
|
|
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
our @EXPORT = qw(); |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
our $VERSION = '0.10'; |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
#---------------------------------------------------------------- |
|
34
|
|
|
|
|
|
|
# |
|
35
|
|
|
|
|
|
|
# Global vars |
|
36
|
|
|
|
|
|
|
# |
|
37
|
|
|
|
|
|
|
#---------------------------------------------------------------- |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# the rule file actually used by Hook::Filter, and as declared with parameter 'rules' |
|
40
|
|
|
|
|
|
|
my $RULES_FILE; |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# list of subs to hijack |
|
43
|
|
|
|
|
|
|
my %HOOK_SUBS; |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub _queue_sub { |
|
46
|
19
|
|
|
19
|
|
29
|
my ($pkg,$name) = @_; |
|
47
|
19
|
100
|
|
|
|
100
|
($name =~ /::/) ? $HOOK_SUBS{$name}=1 : $HOOK_SUBS{$pkg."::".$name}=1; |
|
48
|
|
|
|
|
|
|
} |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
#---------------------------------------------------------------- |
|
51
|
|
|
|
|
|
|
# |
|
52
|
|
|
|
|
|
|
# import - verify import parameters, filter the subs and load the rule file |
|
53
|
|
|
|
|
|
|
# |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub import { |
|
56
|
17
|
|
|
17
|
|
18708
|
my($class,%args) = @_; |
|
57
|
17
|
|
|
|
|
43
|
my $pkg = caller(0); |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# |
|
60
|
|
|
|
|
|
|
# check parameter 'rules', indicating path to the rule file |
|
61
|
|
|
|
|
|
|
# |
|
62
|
|
|
|
|
|
|
|
|
63
|
17
|
100
|
|
|
|
72
|
if (exists $args{rules}) { |
|
64
|
|
|
|
|
|
|
|
|
65
|
7
|
100
|
|
|
|
279
|
croak "import parameter 'rules' for Hook::Filter should be a string, but was undef." |
|
66
|
|
|
|
|
|
|
if (!defined $args{rules}); |
|
67
|
|
|
|
|
|
|
|
|
68
|
6
|
100
|
|
|
|
27
|
croak "import parameter 'rules' for Hook::Filter should be a string, but was [".Dumper($args{rules})."]." |
|
69
|
|
|
|
|
|
|
if (ref \$args{rules} ne 'SCALAR'); |
|
70
|
|
|
|
|
|
|
|
|
71
|
5
|
100
|
100
|
|
|
261
|
croak "you tried to specify 2 different Hook::Filter rule file: [$RULES_FILE] and [".$args{rules}."]. you may have only 1 rule file." |
|
72
|
|
|
|
|
|
|
if (defined $RULES_FILE && $RULES_FILE ne $args{rules}); |
|
73
|
|
|
|
|
|
|
|
|
74
|
4
|
|
|
|
|
8
|
$RULES_FILE = $args{rules}; |
|
75
|
4
|
|
|
|
|
9
|
delete $args{rules}; |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# |
|
78
|
|
|
|
|
|
|
# load the rule file, if any |
|
79
|
|
|
|
|
|
|
# |
|
80
|
|
|
|
|
|
|
|
|
81
|
4
|
|
|
|
|
13
|
my $pool = get_rule_pool(); |
|
82
|
|
|
|
|
|
|
|
|
83
|
4
|
100
|
|
|
|
86
|
if (-f $RULES_FILE) { |
|
84
|
|
|
|
|
|
|
# TODO: support runtime monitoring of rules file and update of rules upon changes in file |
|
85
|
|
|
|
|
|
|
|
|
86
|
1
|
50
|
|
|
|
46
|
open(IN,"$RULES_FILE") |
|
87
|
|
|
|
|
|
|
or confess "failed to open Hook::Filter rules file [$RULES_FILE]: $!"; |
|
88
|
1
|
|
|
|
|
21
|
while (my $line = ) { |
|
89
|
9
|
|
|
|
|
16
|
chomp $line; |
|
90
|
9
|
100
|
|
|
|
39
|
next if ($line =~ /^\s*\#/); |
|
91
|
6
|
100
|
|
|
|
23
|
next if ($line =~ /^\s*$/); |
|
92
|
|
|
|
|
|
|
|
|
93
|
5
|
|
|
|
|
18
|
my $rule = new Hook::Filter::Rule($line); |
|
94
|
5
|
|
|
|
|
15
|
$rule->source($RULES_FILE); |
|
95
|
5
|
|
|
|
|
25
|
$pool->add_rule($rule); |
|
96
|
|
|
|
|
|
|
} |
|
97
|
1
|
|
|
|
|
11
|
close(IN); |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# |
|
102
|
|
|
|
|
|
|
# check parameter 'hook', indicating which subroutines to filter |
|
103
|
|
|
|
|
|
|
# |
|
104
|
|
|
|
|
|
|
|
|
105
|
14
|
100
|
|
|
|
354
|
croak "you must call Hook::Filter with the import parameter 'hook' set to something" |
|
106
|
|
|
|
|
|
|
if (!exists $args{hook}); |
|
107
|
|
|
|
|
|
|
|
|
108
|
12
|
100
|
|
|
|
203
|
croak "Invalid parameter: 'hook' should be a string or an array of strings, but was undef." |
|
109
|
|
|
|
|
|
|
if (!defined $args{hook}); |
|
110
|
|
|
|
|
|
|
|
|
111
|
11
|
100
|
|
|
|
160
|
if (ref $args{hook} eq 'ARRAY') { |
|
|
|
100
|
|
|
|
|
|
|
112
|
5
|
|
|
|
|
12
|
foreach my $name (@{$args{hook}}) { |
|
|
5
|
|
|
|
|
19
|
|
|
113
|
15
|
100
|
|
|
|
294
|
if (ref \$name ne 'SCALAR') { |
|
114
|
1
|
|
|
|
|
5
|
croak "Invalid parameter: 'hook' for Hook::Filter should be a string or an array of strings, but was [".Dumper($args{hook})."]."; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
14
|
|
|
|
|
27
|
_queue_sub($pkg,$name); |
|
117
|
|
|
|
|
|
|
} |
|
118
|
|
|
|
|
|
|
} elsif (ref \$args{hook} eq 'SCALAR') { |
|
119
|
5
|
|
|
|
|
17
|
_queue_sub($pkg,$args{hook}); |
|
120
|
|
|
|
|
|
|
} else { |
|
121
|
1
|
|
|
|
|
9
|
croak "Invalid parameter: 'hook' for Hook::Filter should be a string or an array of strings, but was [".Dumper($args{hook})."]."; |
|
122
|
|
|
|
|
|
|
} |
|
123
|
|
|
|
|
|
|
|
|
124
|
9
|
|
|
|
|
24
|
delete $args{hook}; |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# propagate super class's import |
|
127
|
9
|
|
|
|
|
915
|
$class->export_to_level(1,undef,()); |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# |
|
131
|
|
|
|
|
|
|
# when all is compiled, do filter all the subs |
|
132
|
|
|
|
|
|
|
# |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub _filter_subs { |
|
135
|
6
|
|
|
6
|
|
132
|
map { filter_sub($_) } keys %HOOK_SUBS; |
|
|
19
|
|
|
|
|
343
|
|
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# this init block won't be executed if Hook::Filter is used from an eval/require |
|
139
|
|
|
|
|
|
|
INIT { |
|
140
|
|
|
|
|
|
|
# add a filtering closure around each sub |
|
141
|
5
|
|
|
5
|
|
24
|
_filter_subs; |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
1; |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
__END__ |