Filename | /usr/local/lib/perl5/site_perl/Mail/SpamAssassin/HTML.pm |
Statements | Executed 3803434 statements in 23.0s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
46468 | 5 | 1 | 4.54s | 4.91s | display_text | Mail::SpamAssassin::HTML::
46892 | 1 | 1 | 3.39s | 14.1s | html_tag | Mail::SpamAssassin::HTML::
29709 | 2 | 1 | 2.28s | 6.56s | html_text | Mail::SpamAssassin::HTML::
32908 | 1 | 1 | 2.26s | 5.65s | text_style | Mail::SpamAssassin::HTML::
16266 | 1 | 1 | 1.93s | 1.93s | close_tag | Mail::SpamAssassin::HTML::
231886 | 25 | 1 | 1.34s | 1.34s | CORE:match (opcode) | Mail::SpamAssassin::HTML::
7824 | 1 | 1 | 993ms | 1.01s | close_table_tag | Mail::SpamAssassin::HTML::
24570 | 1 | 1 | 661ms | 734ms | html_tests | Mail::SpamAssassin::HTML::
16860 | 1 | 1 | 616ms | 2.53s | html_whitespace | Mail::SpamAssassin::HTML::
101699 | 12 | 1 | 576ms | 576ms | CORE:subst (opcode) | Mail::SpamAssassin::HTML::
2703 | 2 | 1 | 400ms | 490ms | _remove_dot_segments | Mail::SpamAssassin::HTML::
4787 | 1 | 1 | 396ms | 444ms | html_font_invisible | Mail::SpamAssassin::HTML::
567 | 3 | 1 | 383ms | 383ms | get_rendered_text | Mail::SpamAssassin::HTML::
12673 | 1 | 1 | 348ms | 1.73s | html_uri | Mail::SpamAssassin::HTML::
2705 | 1 | 1 | 315ms | 1.05s | target_uri | Mail::SpamAssassin::HTML::
2325 | 3 | 1 | 204ms | 266ms | name_to_rgb | Mail::SpamAssassin::HTML::
5410 | 2 | 1 | 191ms | 246ms | _parse_uri | Mail::SpamAssassin::HTML::
4261 | 2 | 1 | 144ms | 192ms | canon_uri | Mail::SpamAssassin::HTML::
2705 | 3 | 1 | 126ms | 1.31s | push_uri | Mail::SpamAssassin::HTML::
3096 | 20 | 1 | 88.0ms | 88.0ms | put_results | Mail::SpamAssassin::HTML::
189 | 1 | 1 | 64.3ms | 146ms | html_end | Mail::SpamAssassin::HTML::
189 | 1 | 1 | 34.9ms | 22.6s | parse | Mail::SpamAssassin::HTML::
1404 | 1 | 1 | 28.3ms | 28.3ms | CORE:substcont (opcode) | Mail::SpamAssassin::HTML::
1 | 1 | 1 | 18.9ms | 20.7ms | BEGIN@30 | Mail::SpamAssassin::HTML::
189 | 1 | 1 | 15.7ms | 80.2ms | new | Mail::SpamAssassin::HTML::
189 | 1 | 1 | 7.40ms | 12.4ms | html_start | Mail::SpamAssassin::HTML::
411 | 1 | 1 | 7.24ms | 7.24ms | html_comment | Mail::SpamAssassin::HTML::
67 | 1 | 1 | 2.64ms | 3.04ms | html_declaration | Mail::SpamAssassin::HTML::
189 | 1 | 1 | 1.56ms | 1.56ms | get_results | Mail::SpamAssassin::HTML::
1 | 1 | 1 | 46µs | 289µs | BEGIN@1080 | Mail::SpamAssassin::HTML::
1 | 1 | 1 | 38µs | 46µs | BEGIN@23 | Mail::SpamAssassin::HTML::
1 | 1 | 1 | 35µs | 204µs | BEGIN@31 | Mail::SpamAssassin::HTML::
1 | 1 | 1 | 30µs | 605µs | BEGIN@32 | Mail::SpamAssassin::HTML::
1 | 1 | 1 | 23µs | 113µs | BEGIN@33 | Mail::SpamAssassin::HTML::
1 | 1 | 1 | 20µs | 42µs | BEGIN@24 | Mail::SpamAssassin::HTML::
1 | 1 | 1 | 18µs | 64µs | BEGIN@25 | Mail::SpamAssassin::HTML::
0 | 0 | 0 | 0s | 0s | _merge_uri | Mail::SpamAssassin::HTML::
0 | 0 | 0 | 0s | 0s | dec2hex | Mail::SpamAssassin::HTML::
0 | 0 | 0 | 0s | 0s | name_to_rgb_old | Mail::SpamAssassin::HTML::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # <@LICENSE> | ||||
2 | # Licensed to the Apache Software Foundation (ASF) under one or more | ||||
3 | # contributor license agreements. See the NOTICE file distributed with | ||||
4 | # this work for additional information regarding copyright ownership. | ||||
5 | # The ASF licenses this file to you under the Apache License, Version 2.0 | ||||
6 | # (the "License"); you may not use this file except in compliance with | ||||
7 | # the License. You may obtain a copy of the License at: | ||||
8 | # | ||||
9 | # http://www.apache.org/licenses/LICENSE-2.0 | ||||
10 | # | ||||
11 | # Unless required by applicable law or agreed to in writing, software | ||||
12 | # distributed under the License is distributed on an "AS IS" BASIS, | ||||
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
14 | # See the License for the specific language governing permissions and | ||||
15 | # limitations under the License. | ||||
16 | # </@LICENSE> | ||||
17 | |||||
18 | # HTML decoding TODOs | ||||
19 | # - add URIs to list for faster URI testing | ||||
20 | |||||
21 | package Mail::SpamAssassin::HTML; | ||||
22 | |||||
23 | 2 | 60µs | 2 | 53µs | # spent 46µs (38+7) within Mail::SpamAssassin::HTML::BEGIN@23 which was called:
# once (38µs+7µs) by Mail::SpamAssassin::Message::Node::BEGIN@45 at line 23 # spent 46µs making 1 call to Mail::SpamAssassin::HTML::BEGIN@23
# spent 7µs making 1 call to strict::import |
24 | 2 | 52µs | 2 | 65µs | # spent 42µs (20+23) within Mail::SpamAssassin::HTML::BEGIN@24 which was called:
# once (20µs+23µs) by Mail::SpamAssassin::Message::Node::BEGIN@45 at line 24 # spent 42µs making 1 call to Mail::SpamAssassin::HTML::BEGIN@24
# spent 23µs making 1 call to warnings::import |
25 | 2 | 73µs | 2 | 110µs | # spent 64µs (18+46) within Mail::SpamAssassin::HTML::BEGIN@25 which was called:
# once (18µs+46µs) by Mail::SpamAssassin::Message::Node::BEGIN@45 at line 25 # spent 64µs making 1 call to Mail::SpamAssassin::HTML::BEGIN@25
# spent 46µs making 1 call to re::import |
26 | |||||
27 | 1 | 32µs | require 5.008; # need basic Unicode support for HTML::Parser::utf8_mode | ||
28 | # require 5.008008; # Bug 3787; [perl #37950]: Malformed UTF-8 character ... | ||||
29 | |||||
30 | 3 | 436µs | 2 | 20.8ms | # spent 20.7ms (18.9+1.87) within Mail::SpamAssassin::HTML::BEGIN@30 which was called:
# once (18.9ms+1.87ms) by Mail::SpamAssassin::Message::Node::BEGIN@45 at line 30 # spent 20.7ms making 1 call to Mail::SpamAssassin::HTML::BEGIN@30
# spent 25µs making 1 call to version::_VERSION |
31 | 2 | 78µs | 2 | 373µs | # spent 204µs (35+169) within Mail::SpamAssassin::HTML::BEGIN@31 which was called:
# once (35µs+169µs) by Mail::SpamAssassin::Message::Node::BEGIN@45 at line 31 # spent 204µs making 1 call to Mail::SpamAssassin::HTML::BEGIN@31
# spent 169µs making 1 call to Exporter::import |
32 | 2 | 71µs | 2 | 1.18ms | # spent 605µs (30+576) within Mail::SpamAssassin::HTML::BEGIN@32 which was called:
# once (30µs+576µs) by Mail::SpamAssassin::Message::Node::BEGIN@45 at line 32 # spent 605µs making 1 call to Mail::SpamAssassin::HTML::BEGIN@32
# spent 576µs making 1 call to Exporter::import |
33 | 2 | 11.7ms | 2 | 203µs | # spent 113µs (23+90) within Mail::SpamAssassin::HTML::BEGIN@33 which was called:
# once (23µs+90µs) by Mail::SpamAssassin::Message::Node::BEGIN@45 at line 33 # spent 113µs making 1 call to Mail::SpamAssassin::HTML::BEGIN@33
# spent 90µs making 1 call to Exporter::import |
34 | |||||
35 | 1 | 25µs | our @ISA = qw(HTML::Parser); | ||
36 | |||||
37 | # elements defined by the HTML 4.01 and XHTML 1.0 DTDs (do not change them!) | ||||
38 | # does not include XML | ||||
39 | 95 | 410µs | my %elements = map {; $_ => 1 } | ||
40 | # strict | ||||
41 | qw( a abbr acronym address area b base bdo big blockquote body br button caption cite code col colgroup dd del dfn div dl dt em fieldset form h1 h2 h3 h4 h5 h6 head hr html i img input ins kbd label legend li link map meta noscript object ol optgroup option p param pre q samp script select small span strong style sub sup table tbody td textarea tfoot th thead title tr tt ul var ), | ||||
42 | # loose | ||||
43 | qw( applet basefont center dir font frame frameset iframe isindex menu noframes s strike u ), | ||||
44 | # non-standard tags | ||||
45 | qw( nobr x-sigsep x-tab ), | ||||
46 | ; | ||||
47 | |||||
48 | # elements that we want to render, but not count as valid | ||||
49 | 6 | 24µs | my %tricks = map {; $_ => 1 } | ||
50 | # non-standard and non-valid tags | ||||
51 | qw( bgsound embed listing plaintext xmp ), | ||||
52 | # other non-standard tags handled in popfile | ||||
53 | # blink ilayer multicol noembed nolayer spacer wbr | ||||
54 | ; | ||||
55 | |||||
56 | # elements that change text style | ||||
57 | 14 | 50µs | my %elements_text_style = map {; $_ => 1 } | ||
58 | qw( body font table tr th td big small basefont marquee span p div ), | ||||
59 | ; | ||||
60 | |||||
61 | # elements that insert whitespace | ||||
62 | 23 | 84µs | my %elements_whitespace = map {; $_ => 1 } | ||
63 | qw( br div li th td dt dd p hr blockquote pre embed listing plaintext xmp title | ||||
64 | h1 h2 h3 h4 h5 h6 ), | ||||
65 | ; | ||||
66 | |||||
67 | # elements that push URIs | ||||
68 | 16 | 57µs | my %elements_uri = map {; $_ => 1 } | ||
69 | qw( body table tr td a area link img frame iframe embed script form base bgsound ), | ||||
70 | ; | ||||
71 | |||||
72 | # style attribute not accepted | ||||
73 | #my %elements_no_style = map {; $_ => 1 } | ||||
74 | # qw( base basefont head html meta param script style title ), | ||||
75 | #; | ||||
76 | |||||
77 | # permitted element attributes | ||||
78 | 1 | 2µs | my %ok_attributes; | ||
79 | 1 | 14µs | $ok_attributes{basefont}{$_} = 1 for qw( color face size ); | ||
80 | 1 | 18µs | $ok_attributes{body}{$_} = 1 for qw( text bgcolor link alink vlink background ); | ||
81 | 1 | 10µs | $ok_attributes{font}{$_} = 1 for qw( color face size ); | ||
82 | 1 | 8µs | $ok_attributes{marquee}{$_} = 1 for qw( bgcolor background ); | ||
83 | 1 | 6µs | $ok_attributes{table}{$_} = 1 for qw( bgcolor ); | ||
84 | 1 | 5µs | $ok_attributes{td}{$_} = 1 for qw( bgcolor ); | ||
85 | 1 | 10µs | $ok_attributes{th}{$_} = 1 for qw( bgcolor ); | ||
86 | 1 | 6µs | $ok_attributes{tr}{$_} = 1 for qw( bgcolor ); | ||
87 | 1 | 6µs | $ok_attributes{span}{$_} = 1 for qw( style ); | ||
88 | 1 | 5µs | $ok_attributes{p}{$_} = 1 for qw( style ); | ||
89 | 1 | 5µs | $ok_attributes{div}{$_} = 1 for qw( style ); | ||
90 | |||||
91 | # spent 80.2ms (15.7+64.6) within Mail::SpamAssassin::HTML::new which was called 189 times, avg 425µs/call:
# 189 times (15.7ms+64.6ms) by Mail::SpamAssassin::Message::Node::rendered at line 635 of Mail/SpamAssassin/Message/Node.pm, avg 425µs/call | ||||
92 | 189 | 548µs | my ($class, $character_semantics_input, $character_semantics_output) = @_; | ||
93 | 189 | 6.02ms | 189 | 64.6ms | my $self = $class->SUPER::new( # spent 64.6ms making 189 calls to HTML::Parser::new, avg 342µs/call |
94 | api_version => 3, | ||||
95 | handlers => [ | ||||
96 | start_document => ["html_start", "self"], | ||||
97 | start => ["html_tag", "self,tagname,attr,'+1'"], | ||||
98 | end_document => ["html_end", "self"], | ||||
99 | end => ["html_tag", "self,tagname,attr,'-1'"], | ||||
100 | text => ["html_text", "self,dtext"], | ||||
101 | comment => ["html_comment", "self,text"], | ||||
102 | declaration => ["html_declaration", "self,text"], | ||||
103 | ], | ||||
104 | marked_sections => 1); | ||||
105 | 189 | 666µs | $self->{SA_character_semantics_input} = $character_semantics_input; | ||
106 | $self->{SA_encode_results} = | ||||
107 | 189 | 654µs | $character_semantics_input && !$character_semantics_output; | ||
108 | 189 | 1.58ms | $self; | ||
109 | } | ||||
110 | |||||
111 | # spent 12.4ms (7.40+4.95) within Mail::SpamAssassin::HTML::html_start which was called 189 times, avg 65µs/call:
# 189 times (7.40ms+4.95ms) by HTML::Parser::parse at line 260, avg 65µs/call | ||||
112 | 189 | 459µs | my ($self) = @_; | ||
113 | |||||
114 | # trigger HTML_MESSAGE | ||||
115 | 189 | 1.64ms | 189 | 4.95ms | $self->put_results(html => 1); # spent 4.95ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 26µs/call |
116 | |||||
117 | # initial display attributes | ||||
118 | 189 | 640µs | $self->{basefont} = 3; | ||
119 | my %default = (tag => "default", | ||||
120 | fgcolor => "#000000", | ||||
121 | bgcolor => "#ffffff", | ||||
122 | 189 | 1.77ms | size => $self->{basefont}); | ||
123 | 378 | 2.92ms | push @{ $self->{text_style} }, \%default; | ||
124 | } | ||||
125 | |||||
126 | # spent 146ms (64.3+81.7) within Mail::SpamAssassin::HTML::html_end which was called 189 times, avg 773µs/call:
# 189 times (64.3ms+81.7ms) by HTML::Parser::eof at line 261, avg 773µs/call | ||||
127 | 189 | 442µs | my ($self) = @_; | ||
128 | |||||
129 | 189 | 1.31ms | delete $self->{text_style}; | ||
130 | |||||
131 | 189 | 368µs | my @uri; | ||
132 | |||||
133 | # add the canonicalized version of each uri to the detail list | ||||
134 | 189 | 881µs | if (defined $self->{uri}) { | ||
135 | 236 | 1.97ms | @uri = keys %{$self->{uri}}; | ||
136 | } | ||||
137 | |||||
138 | # these keep backward compatibility, albeit a little wasteful | ||||
139 | 189 | 1.64ms | 189 | 4.71ms | $self->put_results(uri => \@uri); # spent 4.71ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 25µs/call |
140 | 189 | 1.64ms | 189 | 5.43ms | $self->put_results(anchor => $self->{anchor}); # spent 5.43ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 29µs/call |
141 | |||||
142 | 189 | 1.45ms | 189 | 5.96ms | $self->put_results(uri_detail => $self->{uri}); # spent 5.96ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 32µs/call |
143 | 189 | 1.80ms | 189 | 5.82ms | $self->put_results(uri_truncated => $self->{uri_truncated}); # spent 5.82ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 31µs/call |
144 | |||||
145 | # final results scalars | ||||
146 | 189 | 1.37ms | 189 | 4.78ms | $self->put_results(image_area => $self->{image_area}); # spent 4.78ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 25µs/call |
147 | 189 | 1.40ms | 189 | 4.93ms | $self->put_results(length => $self->{length}); # spent 4.93ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 26µs/call |
148 | 189 | 1.35ms | 189 | 5.11ms | $self->put_results(min_size => $self->{min_size}); # spent 5.11ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 27µs/call |
149 | 189 | 1.41ms | 189 | 5.16ms | $self->put_results(max_size => $self->{max_size}); # spent 5.16ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 27µs/call |
150 | 189 | 968µs | if (exists $self->{tags}) { | ||
151 | $self->put_results(closed_extra_ratio => | ||||
152 | 187 | 1.80ms | 187 | 5.48ms | ($self->{closed_extra} / $self->{tags})); # spent 5.48ms making 187 calls to Mail::SpamAssassin::HTML::put_results, avg 29µs/call |
153 | } | ||||
154 | |||||
155 | # final result arrays | ||||
156 | 189 | 1.69ms | 189 | 5.68ms | $self->put_results(comment => $self->{comment}); # spent 5.68ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 30µs/call |
157 | 189 | 1.67ms | 189 | 5.74ms | $self->put_results(script => $self->{script}); # spent 5.74ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 30µs/call |
158 | 189 | 1.55ms | 189 | 5.58ms | $self->put_results(title => $self->{title}); # spent 5.58ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 29µs/call |
159 | |||||
160 | # final result hashes | ||||
161 | 189 | 1.32ms | 189 | 5.64ms | $self->put_results(inside => $self->{inside}); # spent 5.64ms making 189 calls to Mail::SpamAssassin::HTML::put_results, avg 30µs/call |
162 | |||||
163 | # end-of-document result values that don't require looking at the text | ||||
164 | 189 | 519µs | if (exists $self->{backhair}) { | ||
165 | 22 | 137µs | 11 | 382µs | $self->put_results(backhair_count => scalar keys %{ $self->{backhair} }); # spent 382µs making 11 calls to Mail::SpamAssassin::HTML::put_results, avg 35µs/call |
166 | } | ||||
167 | 189 | 915µs | if (exists $self->{elements} && exists $self->{tags}) { | ||
168 | $self->put_results(bad_tag_ratio => | ||||
169 | 187 | 1.78ms | 187 | 5.40ms | ($self->{tags} - $self->{elements}) / $self->{tags}); # spent 5.40ms making 187 calls to Mail::SpamAssassin::HTML::put_results, avg 29µs/call |
170 | } | ||||
171 | 189 | 983µs | if (exists $self->{elements_seen} && exists $self->{tags_seen}) { | ||
172 | $self->put_results(non_element_ratio => | ||||
173 | ($self->{tags_seen} - $self->{elements_seen}) / | ||||
174 | 187 | 1.68ms | 187 | 5.42ms | $self->{tags_seen}); # spent 5.42ms making 187 calls to Mail::SpamAssassin::HTML::put_results, avg 29µs/call |
175 | } | ||||
176 | 189 | 1.80ms | if (exists $self->{tags} && exists $self->{obfuscation}) { | ||
177 | $self->put_results(obfuscation_ratio => | ||||
178 | 19 | 146µs | 19 | 491µs | $self->{obfuscation} / $self->{tags}); # spent 491µs making 19 calls to Mail::SpamAssassin::HTML::put_results, avg 26µs/call |
179 | } | ||||
180 | } | ||||
181 | |||||
182 | # spent 88.0ms within Mail::SpamAssassin::HTML::put_results which was called 3096 times, avg 28µs/call:
# 189 times (5.96ms+0s) by Mail::SpamAssassin::HTML::html_end at line 142, avg 32µs/call
# 189 times (5.82ms+0s) by Mail::SpamAssassin::HTML::html_end at line 143, avg 31µs/call
# 189 times (5.74ms+0s) by Mail::SpamAssassin::HTML::html_end at line 157, avg 30µs/call
# 189 times (5.68ms+0s) by Mail::SpamAssassin::HTML::html_end at line 156, avg 30µs/call
# 189 times (5.64ms+0s) by Mail::SpamAssassin::HTML::html_end at line 161, avg 30µs/call
# 189 times (5.58ms+0s) by Mail::SpamAssassin::HTML::html_end at line 158, avg 29µs/call
# 189 times (5.43ms+0s) by Mail::SpamAssassin::HTML::html_end at line 140, avg 29µs/call
# 189 times (5.16ms+0s) by Mail::SpamAssassin::HTML::html_end at line 149, avg 27µs/call
# 189 times (5.11ms+0s) by Mail::SpamAssassin::HTML::html_end at line 148, avg 27µs/call
# 189 times (4.95ms+0s) by Mail::SpamAssassin::HTML::html_start at line 115, avg 26µs/call
# 189 times (4.93ms+0s) by Mail::SpamAssassin::HTML::html_end at line 147, avg 26µs/call
# 189 times (4.78ms+0s) by Mail::SpamAssassin::HTML::html_end at line 146, avg 25µs/call
# 189 times (4.71ms+0s) by Mail::SpamAssassin::HTML::html_end at line 139, avg 25µs/call
# 187 times (5.48ms+0s) by Mail::SpamAssassin::HTML::html_end at line 152, avg 29µs/call
# 187 times (5.42ms+0s) by Mail::SpamAssassin::HTML::html_end at line 174, avg 29µs/call
# 187 times (5.40ms+0s) by Mail::SpamAssassin::HTML::html_end at line 169, avg 29µs/call
# 47 times (1.33ms+0s) by Mail::SpamAssassin::HTML::html_font_invisible at line 555, avg 28µs/call
# 19 times (491µs+0s) by Mail::SpamAssassin::HTML::html_end at line 178, avg 26µs/call
# 11 times (382µs+0s) by Mail::SpamAssassin::HTML::html_end at line 165, avg 35µs/call
# once (32µs+0s) by Mail::SpamAssassin::HTML::html_font_invisible at line 586 | ||||
183 | 3096 | 5.37ms | my $self = shift; | ||
184 | 3096 | 20.7ms | my %results = @_; | ||
185 | |||||
186 | 3096 | 81.0ms | while (my ($k, $v) = each %results) { | ||
187 | 3096 | 12.2ms | $self->{results}{$k} = $v; | ||
188 | } | ||||
189 | } | ||||
190 | |||||
191 | # spent 1.56ms within Mail::SpamAssassin::HTML::get_results which was called 189 times, avg 8µs/call:
# 189 times (1.56ms+0s) by Mail::SpamAssassin::Message::Node::rendered at line 643 of Mail/SpamAssassin/Message/Node.pm, avg 8µs/call | ||||
192 | 189 | 442µs | my ($self) = @_; | ||
193 | |||||
194 | 189 | 1.42ms | return $self->{results}; | ||
195 | } | ||||
196 | |||||
197 | # spent 383ms within Mail::SpamAssassin::HTML::get_rendered_text which was called 567 times, avg 675µs/call:
# 189 times (193ms+0s) by Mail::SpamAssassin::Message::Node::rendered at line 641 of Mail/SpamAssassin/Message/Node.pm, avg 1.02ms/call
# 189 times (179ms+0s) by Mail::SpamAssassin::Message::Node::rendered at line 642 of Mail/SpamAssassin/Message/Node.pm, avg 947µs/call
# 189 times (10.7ms+0s) by Mail::SpamAssassin::Message::Node::rendered at line 640 of Mail/SpamAssassin/Message/Node.pm, avg 57µs/call | ||||
198 | 567 | 1.03ms | my $self = shift; | ||
199 | 567 | 2.68ms | my %options = @_; | ||
200 | |||||
201 | 756 | 11.0ms | return join('', @{ $self->{text} }) unless %options; | ||
202 | |||||
203 | 378 | 725µs | my $mask; | ||
204 | 378 | 4.30ms | while (my ($k, $v) = each %options) { | ||
205 | 378 | 1.20ms | next if !defined $self->{"text_$k"}; | ||
206 | 378 | 1.42ms | if (!defined $mask) { | ||
207 | 378 | 3.62ms | $mask |= $v ? $self->{"text_$k"} : ~ $self->{"text_$k"}; | ||
208 | } | ||||
209 | else { | ||||
210 | $mask &= $v ? $self->{"text_$k"} : ~ $self->{"text_$k"}; | ||||
211 | } | ||||
212 | } | ||||
213 | |||||
214 | 378 | 960µs | my $text = ''; | ||
215 | 378 | 708µs | my $i = 0; | ||
216 | 93692 | 352ms | for (@{ $self->{text} }) { $text .= $_ if vec($mask, $i++, 1); } | ||
217 | 378 | 5.07ms | return $text; | ||
218 | } | ||||
219 | |||||
220 | # spent 22.6s (34.9ms+22.5) within Mail::SpamAssassin::HTML::parse which was called 189 times, avg 119ms/call:
# 189 times (34.9ms+22.5s) by Mail::SpamAssassin::Message::Node::rendered at line 637 of Mail/SpamAssassin/Message/Node.pm, avg 119ms/call | ||||
221 | 189 | 1.04ms | my ($self, $text) = @_; | ||
222 | |||||
223 | 189 | 695µs | $self->{image_area} = 0; | ||
224 | 189 | 578µs | $self->{title_index} = -1; | ||
225 | 189 | 601µs | $self->{max_size} = 3; # start at default size | ||
226 | 189 | 548µs | $self->{min_size} = 3; # start at default size | ||
227 | 189 | 762µs | $self->{closed_html} = 0; | ||
228 | 189 | 608µs | $self->{closed_body} = 0; | ||
229 | 189 | 550µs | $self->{closed_extra} = 0; | ||
230 | 189 | 606µs | $self->{text} = []; # rendered text | ||
231 | 189 | 3.35ms | 189 | 6.75ms | $self->{length} += untaint_var(length($text)); # spent 6.75ms making 189 calls to Mail::SpamAssassin::Util::untaint_var, avg 36µs/call |
232 | |||||
233 | # NOTE: We *only* need to fix the rendering when we verify that it | ||||
234 | # differs from what people see in their MUA. Testing is best done with | ||||
235 | # the most common MUAs and browsers, if you catch my drift. | ||||
236 | |||||
237 | # NOTE: HTML::Parser can cope with: <?xml pis>, <? with space>, so we | ||||
238 | # don't need to fix them here. | ||||
239 | |||||
240 | # # (outdated claim) HTML::Parser converts into a question mark ("?") | ||||
241 | # # for some reason, so convert them to spaces. Confirmed in 3.31, at least. | ||||
242 | # ... Actually it doesn't, it is correctly coverted into Unicode NBSP, | ||||
243 | # nevertheless it does not hurt to treat it as a space. | ||||
244 | 189 | 16.8ms | 189 | 15.0ms | $text =~ s/ / /g; # spent 15.0ms making 189 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 79µs/call |
245 | |||||
246 | # bug 4695: we want "<br/>" to be treated the same as "<br>", and | ||||
247 | # the HTML::Parser API won't do it for us | ||||
248 | 189 | 48.5ms | 1593 | 37.6ms | $text =~ s/<(\w+)\s*\/>/<$1>/gi; # spent 28.3ms making 1404 calls to Mail::SpamAssassin::HTML::CORE:substcont, avg 20µs/call
# spent 9.24ms making 189 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 49µs/call |
249 | |||||
250 | 189 | 3.55ms | 189 | 1.03ms | if (!$self->UNIVERSAL::can('utf8_mode')) { # spent 1.03ms making 189 calls to UNIVERSAL::can, avg 5µs/call |
251 | # utf8_mode is cleared by default, only warn if it would need to be set | ||||
252 | warn "message: cannot set utf8_mode, module HTML::Parser is too old\n" | ||||
253 | if !$self->{SA_character_semantics_input}; | ||||
254 | } else { | ||||
255 | 189 | 2.48ms | 189 | 682µs | $self->SUPER::utf8_mode($self->{SA_character_semantics_input} ? 0 : 1); # spent 682µs making 189 calls to HTML::Parser::utf8_mode, avg 4µs/call |
256 | 189 | 3.10ms | 378 | 1.95ms | dbg("message: HTML::Parser utf8_mode %s", # spent 1.41ms making 189 calls to Mail::SpamAssassin::Logger::dbg, avg 7µs/call
# spent 536µs making 189 calls to HTML::Parser::utf8_mode, avg 3µs/call |
257 | $self->SUPER::utf8_mode ? "on (assumed UTF-8 octets)" | ||||
258 | : "off (default, assumed Unicode characters)"); | ||||
259 | } | ||||
260 | 189 | 1.10s | 77311 | 43.0s | $self->SUPER::parse($text); # spent 22.3s making 189 calls to HTML::Parser::parse, avg 118ms/call
# spent 14.1s making 46892 calls to Mail::SpamAssassin::HTML::html_tag, avg 301µs/call
# spent 6.52s making 29563 calls to Mail::SpamAssassin::HTML::html_text, avg 221µs/call
# spent 12.4ms making 189 calls to Mail::SpamAssassin::HTML::html_start, avg 65µs/call
# spent 7.24ms making 411 calls to Mail::SpamAssassin::HTML::html_comment, avg 18µs/call
# spent 3.04ms making 67 calls to Mail::SpamAssassin::HTML::html_declaration, avg 45µs/call |
261 | 189 | 5.63ms | 524 | 369ms | $self->SUPER::eof; # spent 187ms making 189 calls to HTML::Parser::eof, avg 991µs/call
# spent 146ms making 189 calls to Mail::SpamAssassin::HTML::html_end, avg 773µs/call
# spent 35.8ms making 146 calls to Mail::SpamAssassin::HTML::html_text, avg 245µs/call |
262 | |||||
263 | 189 | 2.02ms | return $self->{text}; | ||
264 | } | ||||
265 | |||||
266 | # spent 14.1s (3.39+10.7) within Mail::SpamAssassin::HTML::html_tag which was called 46892 times, avg 301µs/call:
# 46892 times (3.39s+10.7s) by HTML::Parser::parse at line 260, avg 301µs/call | ||||
267 | 46892 | 102ms | my ($self, $tag, $attr, $num) = @_; | ||
268 | 46892 | 90.4ms | utf8::encode($tag) if $self->{SA_encode_results}; | ||
269 | |||||
270 | 46892 | 562ms | 46892 | 97.9ms | my $maybe_namespace = ($tag =~ m@^(?:o|st\d):[\w-]+/?$@); # spent 97.9ms making 46892 calls to Mail::SpamAssassin::HTML::CORE:match, avg 2µs/call |
271 | |||||
272 | 46892 | 177ms | if (exists $elements{$tag} || $maybe_namespace) { | ||
273 | 46877 | 82.9ms | $self->{elements}++; | ||
274 | 46877 | 95.7ms | $self->{elements_seen}++ if !exists $self->{inside}{$tag}; | ||
275 | } | ||||
276 | 46892 | 79.9ms | $self->{tags}++; | ||
277 | 46892 | 86.1ms | $self->{tags_seen}++ if !exists $self->{inside}{$tag}; | ||
278 | 46892 | 126ms | $self->{inside}{$tag} += $num; | ||
279 | 46892 | 90.6ms | if ($self->{inside}{$tag} < 0) { | ||
280 | 34 | 82µs | $self->{inside}{$tag} = 0; | ||
281 | 34 | 72µs | $self->{closed_extra}++; | ||
282 | } | ||||
283 | |||||
284 | 46892 | 89.5ms | return if $maybe_namespace; | ||
285 | |||||
286 | # ignore non-elements | ||||
287 | 45476 | 598ms | if (exists $elements{$tag} || exists $tricks{$tag}) { | ||
288 | 45461 | 320ms | 32908 | 5.65s | $self->text_style($tag, $attr, $num) if exists $elements_text_style{$tag}; # spent 5.65s making 32908 calls to Mail::SpamAssassin::HTML::text_style, avg 172µs/call |
289 | |||||
290 | # bug 5009: things like <p> and </p> both need dealing with | ||||
291 | 45461 | 169ms | 16860 | 2.53s | $self->html_whitespace($tag) if exists $elements_whitespace{$tag}; # spent 2.53s making 16860 calls to Mail::SpamAssassin::HTML::html_whitespace, avg 150µs/call |
292 | |||||
293 | # start tags | ||||
294 | 45461 | 194ms | if ($num == 1) { | ||
295 | 24570 | 110ms | 12673 | 1.73s | $self->html_uri($tag, $attr) if exists $elements_uri{$tag}; # spent 1.73s making 12673 calls to Mail::SpamAssassin::HTML::html_uri, avg 136µs/call |
296 | 24570 | 190ms | 24570 | 734ms | $self->html_tests($tag, $attr, $num); # spent 734ms making 24570 calls to Mail::SpamAssassin::HTML::html_tests, avg 30µs/call |
297 | } | ||||
298 | # end tags | ||||
299 | else { | ||||
300 | 20891 | 36.7ms | $self->{closed_html} = 1 if $tag eq "html"; | ||
301 | 20891 | 36.1ms | $self->{closed_body} = 1 if $tag eq "body"; | ||
302 | } | ||||
303 | } | ||||
304 | } | ||||
305 | |||||
306 | # spent 2.53s (616ms+1.91) within Mail::SpamAssassin::HTML::html_whitespace which was called 16860 times, avg 150µs/call:
# 16860 times (616ms+1.91s) by Mail::SpamAssassin::HTML::html_tag at line 291, avg 150µs/call | ||||
307 | 16860 | 37.3ms | my ($self, $tag) = @_; | ||
308 | |||||
309 | # ordered by frequency of tag groups, note: whitespace is always "visible" | ||||
310 | 16860 | 459ms | 16907 | 78.4ms | if ($tag eq "br" || $tag eq "div") { # spent 78.4ms making 16907 calls to Mail::SpamAssassin::HTML::CORE:match, avg 5µs/call |
311 | 3949 | 25.6ms | 3949 | 403ms | $self->display_text("\n", whitespace => 1); # spent 403ms making 3949 calls to Mail::SpamAssassin::HTML::display_text, avg 102µs/call |
312 | } | ||||
313 | elsif ($tag =~ /^(?:li|t[hd]|d[td]|embed|h\d)$/) { | ||||
314 | 8915 | 67.4ms | 8915 | 1.02s | $self->display_text(" ", whitespace => 1); # spent 1.02s making 8915 calls to Mail::SpamAssassin::HTML::display_text, avg 114µs/call |
315 | } | ||||
316 | elsif ($tag =~ /^(?:p|hr|blockquote|pre|listing|plaintext|xmp|title)$/) { | ||||
317 | 3996 | 25.7ms | 3996 | 413ms | $self->display_text("\n\n", whitespace => 1); # spent 413ms making 3996 calls to Mail::SpamAssassin::HTML::display_text, avg 103µs/call |
318 | } | ||||
319 | } | ||||
320 | |||||
321 | # puts the uri onto the internal array | ||||
322 | # note: uri may be blank (<a href=""></a> obfuscation, etc.) | ||||
323 | # spent 1.31s (126ms+1.18) within Mail::SpamAssassin::HTML::push_uri which was called 2705 times, avg 484µs/call:
# 1560 times (76.6ms+702ms) by Mail::SpamAssassin::HTML::html_uri at line 362, avg 499µs/call
# 1132 times (48.9ms+464ms) by Mail::SpamAssassin::HTML::html_uri at line 367, avg 453µs/call
# 13 times (496µs+17.9ms) by Mail::SpamAssassin::HTML::html_uri at line 357, avg 1.41ms/call | ||||
324 | 2705 | 5.87ms | my ($self, $type, $uri) = @_; | ||
325 | |||||
326 | 2705 | 19.1ms | 2705 | 133ms | $uri = $self->canon_uri($uri); # spent 133ms making 2705 calls to Mail::SpamAssassin::HTML::canon_uri, avg 49µs/call |
327 | 2705 | 5.50ms | utf8::encode($uri) if $self->{SA_encode_results}; | ||
328 | |||||
329 | 2705 | 25.6ms | 2705 | 1.05s | my $target = target_uri($self->{base_href} || "", $uri); # spent 1.05s making 2705 calls to Mail::SpamAssassin::HTML::target_uri, avg 389µs/call |
330 | |||||
331 | # skip things like <iframe src="" ...> | ||||
332 | 2705 | 30.3ms | $self->{uri}->{$uri}->{types}->{$type} = 1 if $uri ne ''; | ||
333 | } | ||||
334 | |||||
335 | # spent 192ms (144+47.3) within Mail::SpamAssassin::HTML::canon_uri which was called 4261 times, avg 45µs/call:
# 2705 times (101ms+31.1ms) by Mail::SpamAssassin::HTML::push_uri at line 326, avg 49µs/call
# 1556 times (43.0ms+16.1ms) by Mail::SpamAssassin::HTML::html_tests at line 654, avg 38µs/call | ||||
336 | 4261 | 8.27ms | my ($self, $uri) = @_; | ||
337 | |||||
338 | # URIs don't have leading/trailing whitespace ... | ||||
339 | 4261 | 72.3ms | 4261 | 24.9ms | $uri =~ s/^\s+//; # spent 24.9ms making 4261 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 6µs/call |
340 | 4261 | 68.0ms | 4261 | 22.3ms | $uri =~ s/\s+$//; # spent 22.3ms making 4261 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 5µs/call |
341 | |||||
342 | # Make sure all the URIs are nice and short | ||||
343 | 4261 | 8.38ms | if (length $uri > MAX_URI_LENGTH) { | ||
344 | $self->{'uri_truncated'} = 1; | ||||
345 | $uri = substr $uri, 0, MAX_URI_LENGTH; | ||||
346 | } | ||||
347 | |||||
348 | 4261 | 75.4ms | return $uri; | ||
349 | } | ||||
350 | |||||
351 | # spent 1.73s (348ms+1.38) within Mail::SpamAssassin::HTML::html_uri which was called 12673 times, avg 136µs/call:
# 12673 times (348ms+1.38s) by Mail::SpamAssassin::HTML::html_tag at line 295, avg 136µs/call | ||||
352 | 12673 | 32.8ms | my ($self, $tag, $attr) = @_; | ||
353 | |||||
354 | # ordered by frequency of tag groups | ||||
355 | 12673 | 358ms | 16542 | 70.8ms | if ($tag =~ /^(?:body|table|tr|td)$/) { # spent 70.8ms making 16542 calls to Mail::SpamAssassin::HTML::CORE:match, avg 4µs/call |
356 | 9938 | 20.5ms | if (defined $attr->{background}) { | ||
357 | 13 | 113µs | 13 | 18.3ms | $self->push_uri($tag, $attr->{background}); # spent 18.3ms making 13 calls to Mail::SpamAssassin::HTML::push_uri, avg 1.41ms/call |
358 | } | ||||
359 | } | ||||
360 | elsif ($tag =~ /^(?:a|area|link)$/) { | ||||
361 | 1601 | 6.10ms | if (defined $attr->{href}) { | ||
362 | 1560 | 15.4ms | 1560 | 779ms | $self->push_uri($tag, $attr->{href}); # spent 779ms making 1560 calls to Mail::SpamAssassin::HTML::push_uri, avg 499µs/call |
363 | } | ||||
364 | } | ||||
365 | elsif ($tag =~ /^(?:img|frame|iframe|embed|script|bgsound)$/) { | ||||
366 | 1134 | 4.39ms | if (defined $attr->{src}) { | ||
367 | 1132 | 10.7ms | 1132 | 513ms | $self->push_uri($tag, $attr->{src}); # spent 513ms making 1132 calls to Mail::SpamAssassin::HTML::push_uri, avg 453µs/call |
368 | } | ||||
369 | } | ||||
370 | elsif ($tag eq "form") { | ||||
371 | if (defined $attr->{action}) { | ||||
372 | $self->push_uri($tag, $attr->{action}); | ||||
373 | } | ||||
374 | } | ||||
375 | elsif ($tag eq "base") { | ||||
376 | if (my $uri = $attr->{href}) { | ||||
377 | $uri = $self->canon_uri($uri); | ||||
378 | |||||
379 | # use <BASE HREF="URI"> to turn relative links into absolute links | ||||
380 | |||||
381 | # even if it is a base URI, handle like a normal URI as well | ||||
382 | $self->push_uri($tag, $uri); | ||||
383 | |||||
384 | # a base URI will be ignored by browsers unless it is an absolute | ||||
385 | # URI of a standard protocol | ||||
386 | if ($uri =~ m@^(?:https?|ftp):/{0,2}@i) { | ||||
387 | # remove trailing filename, if any; base URIs can have the | ||||
388 | # form of "http://foo.com/index.html" | ||||
389 | $uri =~ s@^([a-z]+:/{0,2}[^/]+/.*?)[^/\.]+\.[^/\.]{2,4}$@$1@i; | ||||
390 | |||||
391 | # Make sure it ends in a slash | ||||
392 | $uri .= "/" unless $uri =~ m@/$@; | ||||
393 | utf8::encode($uri) if $self->{SA_encode_results}; | ||||
394 | $self->{base_href} = $uri; | ||||
395 | } | ||||
396 | } | ||||
397 | } | ||||
398 | } | ||||
399 | |||||
400 | # this might not be quite right, may need to pay attention to table nesting | ||||
401 | # spent 1.01s (993ms+12.8ms) within Mail::SpamAssassin::HTML::close_table_tag which was called 7824 times, avg 129µs/call:
# 7824 times (993ms+12.8ms) by Mail::SpamAssassin::HTML::text_style at line 455, avg 129µs/call | ||||
402 | 7824 | 15.3ms | my ($self, $tag) = @_; | ||
403 | |||||
404 | # don't close if never opened | ||||
405 | 176215 | 837ms | return unless grep { $_->{tag} eq $tag } @{ $self->{text_style} }; | ||
406 | |||||
407 | 7281 | 11.4ms | my $top; | ||
408 | 14594 | 43.2ms | while (@{ $self->{text_style} } && ($top = $self->{text_style}[-1]->{tag})) { | ||
409 | 7313 | 45.7ms | 3213 | 12.8ms | if (($tag eq "td" && ($top eq "font" || $top eq "td")) || # spent 12.8ms making 3213 calls to Mail::SpamAssassin::HTML::CORE:match, avg 4µs/call |
410 | ($tag eq "tr" && $top =~ /^(?:font|td|tr)$/)) | ||||
411 | { | ||||
412 | 64 | 211µs | pop @{ $self->{text_style} }; | ||
413 | } | ||||
414 | else { | ||||
415 | 7281 | 69.7ms | last; | ||
416 | } | ||||
417 | } | ||||
418 | } | ||||
419 | |||||
420 | # spent 1.93s within Mail::SpamAssassin::HTML::close_tag which was called 16266 times, avg 118µs/call:
# 16266 times (1.93s+0s) by Mail::SpamAssassin::HTML::text_style at line 539, avg 118µs/call | ||||
421 | 16266 | 31.4ms | my ($self, $tag) = @_; | ||
422 | |||||
423 | # don't close if never opened | ||||
424 | 298665 | 1.41s | return if !grep { $_->{tag} eq $tag } @{ $self->{text_style} }; | ||
425 | |||||
426 | # close everything up to and including tag | ||||
427 | 48780 | 308ms | while (my %current = %{ pop @{ $self->{text_style} } }) { | ||
428 | 16279 | 293ms | last if $current{tag} eq $tag; | ||
429 | } | ||||
430 | } | ||||
431 | |||||
432 | # spent 5.65s (2.26+3.39) within Mail::SpamAssassin::HTML::text_style which was called 32908 times, avg 172µs/call:
# 32908 times (2.26s+3.39s) by Mail::SpamAssassin::HTML::html_tag at line 288, avg 172µs/call | ||||
433 | 32908 | 70.6ms | my ($self, $tag, $attr, $num) = @_; | ||
434 | |||||
435 | # treat <th> as <td> | ||||
436 | 32908 | 58.7ms | $tag = "td" if $tag eq "th"; | ||
437 | |||||
438 | # open | ||||
439 | 32908 | 453ms | if ($num == 1) { | ||
440 | # HTML browsers generally only use first <body> for colors, | ||||
441 | # so only push if we haven't seen a body tag yet | ||||
442 | 16485 | 27.4ms | if ($tag eq "body") { | ||
443 | # TODO: skip if we've already seen body | ||||
444 | } | ||||
445 | |||||
446 | # change basefont (only change size) | ||||
447 | 16485 | 26.5ms | if ($tag eq "basefont" && | ||
448 | exists $attr->{size} && $attr->{size} =~ /^\s*(\d+)/) | ||||
449 | { | ||||
450 | $self->{basefont} = $1; | ||||
451 | return; | ||||
452 | } | ||||
453 | |||||
454 | # close elements with optional end tags | ||||
455 | 16485 | 65.2ms | 7824 | 1.01s | $self->close_table_tag($tag) if ($tag eq "td" || $tag eq "tr"); # spent 1.01s making 7824 calls to Mail::SpamAssassin::HTML::close_table_tag, avg 129µs/call |
456 | |||||
457 | # copy current text state | ||||
458 | 32970 | 333ms | my %new = %{ $self->{text_style}[-1] }; | ||
459 | |||||
460 | # change tag name! | ||||
461 | 16485 | 32.3ms | $new{tag} = $tag; | ||
462 | |||||
463 | # big and small tags | ||||
464 | 16485 | 27.7ms | if ($tag eq "big") { | ||
465 | 13 | 32µs | $new{size} += 1; | ||
466 | 26 | 86µs | push @{ $self->{text_style} }, \%new; | ||
467 | 13 | 98µs | return; | ||
468 | } | ||||
469 | 16472 | 26.7ms | if ($tag eq "small") { | ||
470 | 16 | 37µs | $new{size} -= 1; | ||
471 | 32 | 108µs | push @{ $self->{text_style} }, \%new; | ||
472 | 16 | 141µs | return; | ||
473 | } | ||||
474 | |||||
475 | # tag attributes | ||||
476 | 16456 | 127ms | for my $name (keys %$attr) { | ||
477 | 26286 | 56.4ms | next unless exists $ok_attributes{$tag}{$name}; | ||
478 | 5448 | 23.3ms | if ($name eq "text" || $name eq "color") { | ||
479 | # two different names for text color | ||||
480 | 85 | 882µs | 85 | 20.1ms | $new{fgcolor} = name_to_rgb($attr->{$name}); # spent 20.1ms making 85 calls to Mail::SpamAssassin::HTML::name_to_rgb, avg 237µs/call |
481 | } | ||||
482 | elsif ($name eq "size") { | ||||
483 | 117 | 2.63ms | 198 | 800µs | if ($attr->{size} =~ /^\s*([+-]\d+)/) { # spent 800µs making 198 calls to Mail::SpamAssassin::HTML::CORE:match, avg 4µs/call |
484 | # relative font size | ||||
485 | 36 | 132µs | $new{size} = $self->{basefont} + $1; | ||
486 | } | ||||
487 | elsif ($attr->{size} =~ /^\s*(\d+)/) { | ||||
488 | # absolute font size | ||||
489 | 77 | 322µs | $new{size} = $1; | ||
490 | } | ||||
491 | } | ||||
492 | elsif ($name eq 'style') { | ||||
493 | 4426 | 9.71ms | $new{style} = $attr->{style}; | ||
494 | 4426 | 27.3ms | my @parts = split(/;/, $new{style}); | ||
495 | 4426 | 26.2ms | foreach (@parts) { | ||
496 | 15262 | 595ms | 28303 | 182ms | if (/^\s*(background-)?color:\s*(.+)\s*$/i) { # spent 182ms making 28303 calls to Mail::SpamAssassin::HTML::CORE:match, avg 6µs/call |
497 | 2221 | 5.89ms | my $whcolor = $1 ? 'bgcolor' : 'fgcolor'; | ||
498 | 2221 | 6.42ms | my $value = lc $2; | ||
499 | |||||
500 | 2221 | 34.5ms | 2221 | 6.05ms | if ($value =~ /rgb/) { # spent 6.05ms making 2221 calls to Mail::SpamAssassin::HTML::CORE:match, avg 3µs/call |
501 | 611 | 1.87ms | $value =~ tr/0-9,//cd; | ||
502 | 611 | 2.56ms | my @rgb = split(/,/, $value); | ||
503 | $new{$whcolor} = sprintf("#%02x%02x%02x", | ||||
504 | 2444 | 16.8ms | map { !$_ ? 0 : $_ > 255 ? 255 : $_ } | ||
505 | @rgb[0..2]); | ||||
506 | } | ||||
507 | else { | ||||
508 | 1610 | 15.0ms | 1610 | 170ms | $new{$whcolor} = name_to_rgb($value); # spent 170ms making 1610 calls to Mail::SpamAssassin::HTML::name_to_rgb, avg 105µs/call |
509 | } | ||||
510 | } | ||||
511 | elsif (/^\s*([a-z_-]+)\s*:\s*(\S.*?)\s*$/i) { | ||||
512 | # "display: none", "visibility: hidden", etc. | ||||
513 | 12646 | 113ms | $new{'style_'.$1} = $2; | ||
514 | } | ||||
515 | } | ||||
516 | } | ||||
517 | elsif ($name eq "bgcolor") { | ||||
518 | # overwrite with hex value, $new{bgcolor} is set below | ||||
519 | 630 | 7.32ms | 630 | 75.9ms | $attr->{bgcolor} = name_to_rgb($attr->{bgcolor}); # spent 75.9ms making 630 calls to Mail::SpamAssassin::HTML::name_to_rgb, avg 120µs/call |
520 | } | ||||
521 | else { | ||||
522 | # attribute is probably okay | ||||
523 | 190 | 483µs | $new{$name} = $attr->{$name}; | ||
524 | } | ||||
525 | |||||
526 | 5448 | 34.7ms | if ($new{size} > $self->{max_size}) { | ||
527 | 2 | 6µs | $self->{max_size} = $new{size}; | ||
528 | } | ||||
529 | elsif ($new{size} < $self->{min_size}) { | ||||
530 | 33 | 94µs | $self->{min_size} = $new{size}; | ||
531 | } | ||||
532 | } | ||||
533 | 32912 | 144ms | push @{ $self->{text_style} }, \%new; | ||
534 | } | ||||
535 | # explicitly close a tag | ||||
536 | else { | ||||
537 | 16423 | 55.3ms | if ($tag ne "body") { | ||
538 | # don't close body since browsers seem to render text after </body> | ||||
539 | 16266 | 101ms | 16266 | 1.93s | $self->close_tag($tag); # spent 1.93s making 16266 calls to Mail::SpamAssassin::HTML::close_tag, avg 118µs/call |
540 | } | ||||
541 | } | ||||
542 | } | ||||
543 | |||||
544 | # spent 444ms (396+47.8) within Mail::SpamAssassin::HTML::html_font_invisible which was called 4787 times, avg 93µs/call:
# 4787 times (396ms+47.8ms) by Mail::SpamAssassin::HTML::html_text at line 746, avg 93µs/call | ||||
545 | 4787 | 10.3ms | my ($self, $text) = @_; | ||
546 | |||||
547 | 4787 | 12.3ms | my $fg = $self->{text_style}[-1]->{fgcolor}; | ||
548 | 4787 | 10.3ms | my $bg = $self->{text_style}[-1]->{bgcolor}; | ||
549 | 4787 | 9.92ms | my $size = $self->{text_style}[-1]->{size}; | ||
550 | 4787 | 9.80ms | my $display = $self->{text_style}[-1]->{style_display}; | ||
551 | 4787 | 9.51ms | my $visibility = $self->{text_style}[-1]->{style_visibility}; | ||
552 | |||||
553 | # invisibility | ||||
554 | 4787 | 103ms | 4740 | 29.8ms | if (substr($fg,-6) eq substr($bg,-6)) { # spent 29.8ms making 4740 calls to Mail::SpamAssassin::HTML::CORE:match, avg 6µs/call |
555 | 47 | 332µs | 47 | 1.33ms | $self->put_results(font_low_contrast => 1); # spent 1.33ms making 47 calls to Mail::SpamAssassin::HTML::put_results, avg 28µs/call |
556 | 47 | 485µs | return 1; | ||
557 | # near-invisibility | ||||
558 | } elsif ($fg =~ /^\#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/) { | ||||
559 | 4739 | 18.9ms | my ($r1, $g1, $b1) = (hex($1), hex($2), hex($3)); | ||
560 | |||||
561 | 4739 | 97.3ms | 4739 | 16.6ms | if ($bg =~ /^\#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/) { # spent 16.6ms making 4739 calls to Mail::SpamAssassin::HTML::CORE:match, avg 4µs/call |
562 | 4739 | 14.7ms | my ($r2, $g2, $b2) = (hex($1), hex($2), hex($3)); | ||
563 | |||||
564 | 4739 | 9.86ms | my $r = ($r1 - $r2); | ||
565 | 4739 | 8.18ms | my $g = ($g1 - $g2); | ||
566 | 4739 | 8.04ms | my $b = ($b1 - $b2); | ||
567 | |||||
568 | # geometric distance weighted by brightness | ||||
569 | # maximum distance is 191.151823601032 | ||||
570 | 4739 | 19.9ms | my $distance = ((0.2126*$r)**2 + (0.7152*$g)**2 + (0.0722*$b)**2)**0.5; | ||
571 | |||||
572 | # the text is very difficult to read if the distance is under 12, | ||||
573 | # a limit of 14 to 16 might be okay if the usage significantly | ||||
574 | # increases (near-invisible text is at about 0.95% of spam and | ||||
575 | # 1.25% of HTML spam right now), but please test any changes first | ||||
576 | 4739 | 31.9ms | if ($distance < 12) { | ||
577 | $self->put_results(font_low_contrast => 1); | ||||
578 | return 1; | ||||
579 | } | ||||
580 | } | ||||
581 | } | ||||
582 | |||||
583 | |||||
584 | # invalid color | ||||
585 | 4740 | 9.65ms | if ($fg eq 'invalid' or $bg eq 'invalid') { | ||
586 | 1 | 7µs | 1 | 32µs | $self->put_results(font_invalid_color => 1); # spent 32µs making 1 call to Mail::SpamAssassin::HTML::put_results |
587 | 1 | 7µs | return 1; | ||
588 | } | ||||
589 | |||||
590 | # size too small | ||||
591 | 4739 | 8.83ms | if ($size <= 1) { | ||
592 | 40 | 452µs | return 1; | ||
593 | } | ||||
594 | |||||
595 | # <span style="display: none"> | ||||
596 | 4699 | 8.16ms | if ($display && lc $display eq 'none') { | ||
597 | 4 | 38µs | return 1; | ||
598 | } | ||||
599 | |||||
600 | 4695 | 7.87ms | if ($visibility && lc $visibility eq 'hidden') { | ||
601 | 8 | 87µs | return 1; | ||
602 | } | ||||
603 | |||||
604 | 4687 | 73.3ms | return 0; | ||
605 | } | ||||
606 | |||||
607 | # spent 734ms (661+73.3) within Mail::SpamAssassin::HTML::html_tests which was called 24570 times, avg 30µs/call:
# 24570 times (661ms+73.3ms) by Mail::SpamAssassin::HTML::html_tag at line 296, avg 30µs/call | ||||
608 | 24570 | 54.2ms | my ($self, $tag, $attr, $num) = @_; | ||
609 | |||||
610 | 24570 | 43.9ms | if ($tag eq "font" && exists $attr->{face}) { | ||
611 | 175 | 3.38ms | 175 | 1.97ms | if ($attr->{face} !~ /^[a-z ][a-z -]*[a-z](?:,\s*[a-z][a-z -]*[a-z])*$/i) { # spent 1.97ms making 175 calls to Mail::SpamAssassin::HTML::CORE:match, avg 11µs/call |
612 | $self->put_results(font_face_bad => 1); | ||||
613 | } | ||||
614 | } | ||||
615 | 24570 | 45.9ms | if ($tag eq "img" && exists $self->{inside}{a} && $self->{inside}{a} > 0) { | ||
616 | 504 | 1.37ms | my $uri = $self->{anchor_last}; | ||
617 | 504 | 1.00ms | utf8::encode($uri) if $self->{SA_encode_results}; | ||
618 | 504 | 2.02ms | $self->{uri}->{$uri}->{anchor_text}->[-1] .= "<img>\n"; | ||
619 | 504 | 3.22ms | $self->{anchor}->[-1] .= "<img>\n"; | ||
620 | } | ||||
621 | |||||
622 | 24570 | 42.8ms | if ($tag eq "img" && exists $attr->{width} && exists $attr->{height}) { | ||
623 | 776 | 1.65ms | my $width = 0; | ||
624 | 776 | 1.55ms | my $height = 0; | ||
625 | 776 | 1.58ms | my $area = 0; | ||
626 | |||||
627 | # assume 800x600 screen for percentage values | ||||
628 | 776 | 13.7ms | 776 | 7.29ms | if ($attr->{width} =~ /^(\d+)(\%)?$/) { # spent 7.29ms making 776 calls to Mail::SpamAssassin::HTML::CORE:match, avg 9µs/call |
629 | 776 | 2.03ms | $width = $1; | ||
630 | 776 | 1.90ms | $width *= 8 if (defined $2 && $2 eq "%"); | ||
631 | } | ||||
632 | 776 | 9.88ms | 776 | 3.15ms | if ($attr->{height} =~ /^(\d+)(\%)?$/) { # spent 3.15ms making 776 calls to Mail::SpamAssassin::HTML::CORE:match, avg 4µs/call |
633 | 775 | 1.89ms | $height = $1; | ||
634 | 775 | 1.71ms | $height *= 6 if (defined $2 && $2 eq "%"); | ||
635 | } | ||||
636 | # guess size | ||||
637 | 776 | 2.04ms | $width = 200 if $width <= 0; | ||
638 | 776 | 1.44ms | $height = 200 if $height <= 0; | ||
639 | 776 | 6.63ms | if ($width > 0 && $height > 0) { | ||
640 | 776 | 1.42ms | $area = $width * $height; | ||
641 | 776 | 2.21ms | $self->{image_area} += $area; | ||
642 | } | ||||
643 | } | ||||
644 | 24570 | 39.8ms | if ($tag eq "form" && exists $attr->{action}) { | ||
645 | $self->put_results(form_action_mailto => 1) if $attr->{action} =~ /mailto:/i | ||||
646 | } | ||||
647 | 24570 | 45.3ms | if ($tag eq "object" || $tag eq "embed") { | ||
648 | $self->put_results(embeds => 1); | ||||
649 | } | ||||
650 | |||||
651 | # special text delimiters - <a> and <title> | ||||
652 | 24570 | 44.7ms | if ($tag eq "a") { | ||
653 | my $uri = $self->{anchor_last} = | ||||
654 | 1597 | 13.8ms | 1556 | 59.1ms | (exists $attr->{href} ? $self->canon_uri($attr->{href}) : ""); # spent 59.1ms making 1556 calls to Mail::SpamAssassin::HTML::canon_uri, avg 38µs/call |
655 | 1597 | 3.00ms | utf8::encode($uri) if $self->{SA_encode_results}; | ||
656 | 3194 | 18.7ms | push(@{$self->{uri}->{$uri}->{anchor_text}}, ''); | ||
657 | 3194 | 18.3ms | push(@{$self->{anchor}}, ''); | ||
658 | } | ||||
659 | 24570 | 40.8ms | if ($tag eq "title") { | ||
660 | 67 | 163µs | $self->{title_index}++; | ||
661 | 67 | 334µs | $self->{title}->[$self->{title_index}] = ""; | ||
662 | } | ||||
663 | |||||
664 | 24570 | 332ms | 272 | 1.79ms | if ($tag eq "meta" && # spent 1.79ms making 272 calls to Mail::SpamAssassin::HTML::CORE:match, avg 7µs/call |
665 | exists $attr->{'http-equiv'} && | ||||
666 | exists $attr->{content} && | ||||
667 | $attr->{'http-equiv'} =~ /Content-Type/i && | ||||
668 | $attr->{content} =~ /\bcharset\s*=\s*["']?([^"']+)/i) | ||||
669 | { | ||||
670 | 123 | 750µs | $self->{charsets} .= exists $self->{charsets} ? " $1" : $1; | ||
671 | } | ||||
672 | } | ||||
673 | |||||
674 | # spent 4.91s (4.54+373ms) within Mail::SpamAssassin::HTML::display_text which was called 46468 times, avg 106µs/call:
# 29508 times (2.76s+304ms) by Mail::SpamAssassin::HTML::html_text at line 773, avg 104µs/call
# 8915 times (980ms+36.9ms) by Mail::SpamAssassin::HTML::html_whitespace at line 314, avg 114µs/call
# 3996 times (404ms+9.16ms) by Mail::SpamAssassin::HTML::html_whitespace at line 317, avg 103µs/call
# 3949 times (394ms+9.14ms) by Mail::SpamAssassin::HTML::html_whitespace at line 311, avg 102µs/call
# 100 times (8.15ms+13.9ms) by Mail::SpamAssassin::HTML::html_text at line 770, avg 221µs/call | ||||
675 | 46468 | 83.8ms | my $self = shift; | ||
676 | 46468 | 90.4ms | my $text = shift; | ||
677 | 46468 | 156ms | my %display = @_; | ||
678 | |||||
679 | # Unless it's specified to be invisible, then it's not invisible. ;) | ||||
680 | 46468 | 159ms | if (!exists $display{invisible}) { | ||
681 | 46368 | 94.9ms | $display{invisible} = 0; | ||
682 | } | ||||
683 | |||||
684 | 46468 | 199ms | if ($display{whitespace}) { | ||
685 | # trim trailing whitespace from previous element if it was not whitespace | ||||
686 | # and it was not invisible | ||||
687 | 33720 | 194ms | if (@{ $self->{text} } && | ||
688 | (!defined $self->{text_whitespace} || | ||||
689 | 16673 | 31.9ms | !vec($self->{text_whitespace}, $#{$self->{text}}, 1)) && | ||
690 | (!defined $self->{text_invisible} || | ||||
691 | 14264 | 26.7ms | !vec($self->{text_invisible}, $#{$self->{text}}, 1))) | ||
692 | { | ||||
693 | 14202 | 308ms | 14202 | 55.2ms | $self->{text}->[-1] =~ s/ $//; # spent 55.2ms making 14202 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 4µs/call |
694 | } | ||||
695 | } | ||||
696 | else { | ||||
697 | # NBSP: UTF-8: C2 A0, ISO-8859-*: A0 | ||||
698 | 29608 | 714ms | 29608 | 261ms | $text =~ s/[ \t\n\r\f\x0b]+|\xc2\xa0/ /gs; # spent 261ms making 29608 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 9µs/call |
699 | # trim leading whitespace if previous element was whitespace | ||||
700 | # and current element is not invisible | ||||
701 | 59216 | 346ms | if (@{ $self->{text} } && !$display{invisible} && | ||
702 | defined $self->{text_whitespace} && | ||||
703 | 28761 | 52.5ms | vec($self->{text_whitespace}, $#{$self->{text}}, 1)) | ||
704 | { | ||||
705 | 14215 | 275ms | 14215 | 56.8ms | $text =~ s/^ //; # spent 56.8ms making 14215 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 4µs/call |
706 | } | ||||
707 | } | ||||
708 | 92936 | 479ms | push @{ $self->{text} }, $text; | ||
709 | 46468 | 1.38s | while (my ($k, $v) = each %display) { | ||
710 | 63328 | 127ms | my $textvar = "text_".$k; | ||
711 | 63704 | 125ms | if (!exists $self->{$textvar}) { $self->{$textvar} = ''; } | ||
712 | 126656 | 588ms | vec($self->{$textvar}, $#{$self->{text}}, 1) = $v; | ||
713 | } | ||||
714 | } | ||||
715 | |||||
716 | sub html_text { | ||||
717 | 29709 | 62.5ms | my ($self, $text) = @_; | ||
718 | 29709 | 57.7ms | utf8::encode($text) if $self->{SA_encode_results}; | ||
719 | |||||
720 | # text that is not part of body | ||||
721 | 29709 | 54.9ms | if (exists $self->{inside}{script} && $self->{inside}{script} > 0) | ||
722 | { | ||||
723 | 2 | 8µs | push @{ $self->{script} }, $text; | ||
724 | 1 | 7µs | return; | ||
725 | } | ||||
726 | 29708 | 59.3ms | if (exists $self->{inside}{style} && $self->{inside}{style} > 0) { | ||
727 | 100 | 785µs | return; | ||
728 | } | ||||
729 | |||||
730 | # text that is part of body and also stored separately | ||||
731 | 29608 | 63.6ms | if (exists $self->{inside}{a} && $self->{inside}{a} > 0) { | ||
732 | # this doesn't worry about nested anchors | ||||
733 | 1631 | 3.92ms | my $uri = $self->{anchor_last}; | ||
734 | 1631 | 2.92ms | utf8::encode($uri) if $self->{SA_encode_results}; | ||
735 | 1631 | 6.32ms | $self->{uri}->{$uri}->{anchor_text}->[-1] .= $text; | ||
736 | 1631 | 11.9ms | $self->{anchor}->[-1] .= $text; | ||
737 | } | ||||
738 | 29608 | 56.2ms | if (exists $self->{inside}{title} && $self->{inside}{title} > 0) { | ||
739 | 27 | 100µs | $self->{title}->[$self->{title_index}] .= $text; | ||
740 | } | ||||
741 | |||||
742 | 29608 | 51.2ms | my $invisible_for_bayes = 0; | ||
743 | |||||
744 | # NBSP: UTF-8: C2 A0, ISO-8859-*: A0 | ||||
745 | 29608 | 759ms | 29608 | 405ms | if ($text !~ /^(?:[ \t\n\r\f\x0b]|\xc2\xa0)*\z/s) { # spent 405ms making 29608 calls to Mail::SpamAssassin::HTML::CORE:match, avg 14µs/call |
746 | 4787 | 34.8ms | 4787 | 444ms | $invisible_for_bayes = $self->html_font_invisible($text); # spent 444ms making 4787 calls to Mail::SpamAssassin::HTML::html_font_invisible, avg 93µs/call |
747 | } | ||||
748 | |||||
749 | 29608 | 116ms | if (exists $self->{text}->[-1]) { | ||
750 | # ideas discarded since they would be easy to evade: | ||||
751 | # 1. using \w or [A-Za-z] instead of \S or non-punctuation | ||||
752 | # 2. exempting certain tags | ||||
753 | # no re "strict"; # since perl 5.21.8: Ranges of ASCII printables... | ||||
754 | 29444 | 441ms | 33070 | 148ms | if ($text =~ /^[^\s\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]/s && # spent 148ms making 33070 calls to Mail::SpamAssassin::HTML::CORE:match, avg 4µs/call |
755 | $self->{text}->[-1] =~ /[^\s\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]\z/s) | ||||
756 | { | ||||
757 | 38 | 97µs | $self->{obfuscation}++; | ||
758 | } | ||||
759 | 29444 | 511ms | 29444 | 199ms | if ($self->{text}->[-1] =~ # spent 199ms making 29444 calls to Mail::SpamAssassin::HTML::CORE:match, avg 7µs/call |
760 | /\b([^\s\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]{1,7})\z/s) | ||||
761 | { | ||||
762 | 391 | 1.27ms | my $start = length($1); | ||
763 | 391 | 5.00ms | 391 | 1.29ms | if ($text =~ /^([^\s\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]{1,7})\b/s) { # spent 1.29ms making 391 calls to Mail::SpamAssassin::HTML::CORE:match, avg 3µs/call |
764 | 13 | 109µs | $self->{backhair}->{$start . "_" . length($1)}++; | ||
765 | } | ||||
766 | } | ||||
767 | } | ||||
768 | |||||
769 | 29608 | 424ms | if ($invisible_for_bayes) { | ||
770 | 100 | 802µs | 100 | 22.1ms | $self->display_text($text, invisible => 1); # spent 22.1ms making 100 calls to Mail::SpamAssassin::HTML::display_text, avg 221µs/call |
771 | } | ||||
772 | else { | ||||
773 | 29508 | 191ms | 29508 | 3.06s | $self->display_text($text); # spent 3.06s making 29508 calls to Mail::SpamAssassin::HTML::display_text, avg 104µs/call |
774 | } | ||||
775 | } | ||||
776 | |||||
777 | # note: $text includes <!-- and --> | ||||
778 | # spent 7.24ms within Mail::SpamAssassin::HTML::html_comment which was called 411 times, avg 18µs/call:
# 411 times (7.24ms+0s) by HTML::Parser::parse at line 260, avg 18µs/call | ||||
779 | 411 | 869µs | my ($self, $text) = @_; | ||
780 | 411 | 847µs | utf8::encode($text) if $self->{SA_encode_results}; | ||
781 | |||||
782 | 822 | 6.39ms | push @{ $self->{comment} }, $text; | ||
783 | } | ||||
784 | |||||
785 | # spent 3.04ms (2.64+396µs) within Mail::SpamAssassin::HTML::html_declaration which was called 67 times, avg 45µs/call:
# 67 times (2.64ms+396µs) by HTML::Parser::parse at line 260, avg 45µs/call | ||||
786 | 67 | 328µs | my ($self, $text) = @_; | ||
787 | 67 | 191µs | utf8::encode($text) if $self->{SA_encode_results}; | ||
788 | |||||
789 | 67 | 1.77ms | 67 | 396µs | if ($text =~ /^<!doctype/i) { # spent 396µs making 67 calls to Mail::SpamAssassin::HTML::CORE:match, avg 6µs/call |
790 | 67 | 178µs | my $tag = "!doctype"; | ||
791 | 67 | 329µs | $self->{elements}++; | ||
792 | 67 | 179µs | $self->{tags}++; | ||
793 | 67 | 320µs | $self->{inside}{$tag} = 0; | ||
794 | } | ||||
795 | } | ||||
796 | |||||
797 | ########################################################################### | ||||
798 | |||||
799 | 1 | 127µs | my %html_color = ( | ||
800 | # HTML 4 defined 16 colors | ||||
801 | aqua => 0x00ffff, | ||||
802 | black => 0x000000, | ||||
803 | blue => 0x0000ff, | ||||
804 | fuchsia => 0xff00ff, | ||||
805 | gray => 0x808080, | ||||
806 | green => 0x008000, | ||||
807 | lime => 0x00ff00, | ||||
808 | maroon => 0x800000, | ||||
809 | navy => 0x000080, | ||||
810 | olive => 0x808000, | ||||
811 | purple => 0x800080, | ||||
812 | red => 0xff0000, | ||||
813 | silver => 0xc0c0c0, | ||||
814 | teal => 0x008080, | ||||
815 | white => 0xffffff, | ||||
816 | yellow => 0xffff00, | ||||
817 | # colors specified in CSS3 color module | ||||
818 | aliceblue => 0xf0f8ff, | ||||
819 | antiquewhite => 0xfaebd7, | ||||
820 | aqua => 0x00ffff, | ||||
821 | aquamarine => 0x7fffd4, | ||||
822 | azure => 0xf0ffff, | ||||
823 | beige => 0xf5f5dc, | ||||
824 | bisque => 0xffe4c4, | ||||
825 | black => 0x000000, | ||||
826 | blanchedalmond => 0xffebcd, | ||||
827 | blue => 0x0000ff, | ||||
828 | blueviolet => 0x8a2be2, | ||||
829 | brown => 0xa52a2a, | ||||
830 | burlywood => 0xdeb887, | ||||
831 | cadetblue => 0x5f9ea0, | ||||
832 | chartreuse => 0x7fff00, | ||||
833 | chocolate => 0xd2691e, | ||||
834 | coral => 0xff7f50, | ||||
835 | cornflowerblue => 0x6495ed, | ||||
836 | cornsilk => 0xfff8dc, | ||||
837 | crimson => 0xdc143c, | ||||
838 | cyan => 0x00ffff, | ||||
839 | darkblue => 0x00008b, | ||||
840 | darkcyan => 0x008b8b, | ||||
841 | darkgoldenrod => 0xb8860b, | ||||
842 | darkgray => 0xa9a9a9, | ||||
843 | darkgreen => 0x006400, | ||||
844 | darkgrey => 0xa9a9a9, | ||||
845 | darkkhaki => 0xbdb76b, | ||||
846 | darkmagenta => 0x8b008b, | ||||
847 | darkolivegreen => 0x556b2f, | ||||
848 | darkorange => 0xff8c00, | ||||
849 | darkorchid => 0x9932cc, | ||||
850 | darkred => 0x8b0000, | ||||
851 | darksalmon => 0xe9967a, | ||||
852 | darkseagreen => 0x8fbc8f, | ||||
853 | darkslateblue => 0x483d8b, | ||||
854 | darkslategray => 0x2f4f4f, | ||||
855 | darkslategrey => 0x2f4f4f, | ||||
856 | darkturquoise => 0x00ced1, | ||||
857 | darkviolet => 0x9400d3, | ||||
858 | deeppink => 0xff1493, | ||||
859 | deepskyblue => 0x00bfff, | ||||
860 | dimgray => 0x696969, | ||||
861 | dimgrey => 0x696969, | ||||
862 | dodgerblue => 0x1e90ff, | ||||
863 | firebrick => 0xb22222, | ||||
864 | floralwhite => 0xfffaf0, | ||||
865 | forestgreen => 0x228b22, | ||||
866 | fuchsia => 0xff00ff, | ||||
867 | gainsboro => 0xdcdcdc, | ||||
868 | ghostwhite => 0xf8f8ff, | ||||
869 | gold => 0xffd700, | ||||
870 | goldenrod => 0xdaa520, | ||||
871 | gray => 0x808080, | ||||
872 | green => 0x008000, | ||||
873 | greenyellow => 0xadff2f, | ||||
874 | grey => 0x808080, | ||||
875 | honeydew => 0xf0fff0, | ||||
876 | hotpink => 0xff69b4, | ||||
877 | indianred => 0xcd5c5c, | ||||
878 | indigo => 0x4b0082, | ||||
879 | ivory => 0xfffff0, | ||||
880 | khaki => 0xf0e68c, | ||||
881 | lavender => 0xe6e6fa, | ||||
882 | lavenderblush => 0xfff0f5, | ||||
883 | lawngreen => 0x7cfc00, | ||||
884 | lemonchiffon => 0xfffacd, | ||||
885 | lightblue => 0xadd8e6, | ||||
886 | lightcoral => 0xf08080, | ||||
887 | lightcyan => 0xe0ffff, | ||||
888 | lightgoldenrodyellow => 0xfafad2, | ||||
889 | lightgray => 0xd3d3d3, | ||||
890 | lightgreen => 0x90ee90, | ||||
891 | lightgrey => 0xd3d3d3, | ||||
892 | lightpink => 0xffb6c1, | ||||
893 | lightsalmon => 0xffa07a, | ||||
894 | lightseagreen => 0x20b2aa, | ||||
895 | lightskyblue => 0x87cefa, | ||||
896 | lightslategray => 0x778899, | ||||
897 | lightslategrey => 0x778899, | ||||
898 | lightsteelblue => 0xb0c4de, | ||||
899 | lightyellow => 0xffffe0, | ||||
900 | lime => 0x00ff00, | ||||
901 | limegreen => 0x32cd32, | ||||
902 | linen => 0xfaf0e6, | ||||
903 | magenta => 0xff00ff, | ||||
904 | maroon => 0x800000, | ||||
905 | mediumaquamarine => 0x66cdaa, | ||||
906 | mediumblue => 0x0000cd, | ||||
907 | mediumorchid => 0xba55d3, | ||||
908 | mediumpurple => 0x9370db, | ||||
909 | mediumseagreen => 0x3cb371, | ||||
910 | mediumslateblue => 0x7b68ee, | ||||
911 | mediumspringgreen => 0x00fa9a, | ||||
912 | mediumturquoise => 0x48d1cc, | ||||
913 | mediumvioletred => 0xc71585, | ||||
914 | midnightblue => 0x191970, | ||||
915 | mintcream => 0xf5fffa, | ||||
916 | mistyrose => 0xffe4e1, | ||||
917 | moccasin => 0xffe4b5, | ||||
918 | navajowhite => 0xffdead, | ||||
919 | navy => 0x000080, | ||||
920 | oldlace => 0xfdf5e6, | ||||
921 | olive => 0x808000, | ||||
922 | olivedrab => 0x6b8e23, | ||||
923 | orange => 0xffa500, | ||||
924 | orangered => 0xff4500, | ||||
925 | orchid => 0xda70d6, | ||||
926 | palegoldenrod => 0xeee8aa, | ||||
927 | palegreen => 0x98fb98, | ||||
928 | paleturquoise => 0xafeeee, | ||||
929 | palevioletred => 0xdb7093, | ||||
930 | papayawhip => 0xffefd5, | ||||
931 | peachpuff => 0xffdab9, | ||||
932 | peru => 0xcd853f, | ||||
933 | pink => 0xffc0cb, | ||||
934 | plum => 0xdda0dd, | ||||
935 | powderblue => 0xb0e0e6, | ||||
936 | purple => 0x800080, | ||||
937 | red => 0xff0000, | ||||
938 | rosybrown => 0xbc8f8f, | ||||
939 | royalblue => 0x4169e1, | ||||
940 | saddlebrown => 0x8b4513, | ||||
941 | salmon => 0xfa8072, | ||||
942 | sandybrown => 0xf4a460, | ||||
943 | seagreen => 0x2e8b57, | ||||
944 | seashell => 0xfff5ee, | ||||
945 | sienna => 0xa0522d, | ||||
946 | silver => 0xc0c0c0, | ||||
947 | skyblue => 0x87ceeb, | ||||
948 | slateblue => 0x6a5acd, | ||||
949 | slategray => 0x708090, | ||||
950 | slategrey => 0x708090, | ||||
951 | snow => 0xfffafa, | ||||
952 | springgreen => 0x00ff7f, | ||||
953 | steelblue => 0x4682b4, | ||||
954 | tan => 0xd2b48c, | ||||
955 | teal => 0x008080, | ||||
956 | thistle => 0xd8bfd8, | ||||
957 | tomato => 0xff6347, | ||||
958 | turquoise => 0x40e0d0, | ||||
959 | violet => 0xee82ee, | ||||
960 | wheat => 0xf5deb3, | ||||
961 | white => 0xffffff, | ||||
962 | whitesmoke => 0xf5f5f5, | ||||
963 | yellow => 0xffff00, | ||||
964 | yellowgreen => 0x9acd32, | ||||
965 | ); | ||||
966 | |||||
967 | sub name_to_rgb_old { | ||||
968 | my $color = lc $_[0]; | ||||
969 | |||||
970 | # note: Mozilla strips leading and trailing whitespace at this point, | ||||
971 | # but IE does not | ||||
972 | |||||
973 | # named colors | ||||
974 | my $hex = $html_color{$color}; | ||||
975 | if (defined $hex) { | ||||
976 | return sprintf("#%06x", $hex); | ||||
977 | } | ||||
978 | |||||
979 | # Flex Hex: John Graham-Cumming, http://www.jgc.org/pdf/lisa2004.pdf | ||||
980 | # strip optional # character | ||||
981 | $color =~ s/^#//; | ||||
982 | # pad right-hand-side to a multiple of three | ||||
983 | $color .= "0" x (3 - (length($color) % 3)) if (length($color) % 3); | ||||
984 | # split into triplets | ||||
985 | my $length = length($color) / 3; | ||||
986 | my @colors = ($color =~ /(.{$length})(.{$length})(.{$length})/); | ||||
987 | # truncate each color to a DWORD, take MSB, left pad nibbles | ||||
988 | foreach (@colors) { s/.*(.{8})$/$1/; s/(..).*/$1/; s/^(.)$/0$1/ }; | ||||
989 | # the color | ||||
990 | $color = join("", @colors); | ||||
991 | # replace non-hex characters with 0 | ||||
992 | $color =~ tr/0-9a-f/0/c; | ||||
993 | |||||
994 | return "#" . $color; | ||||
995 | } | ||||
996 | |||||
997 | # spent 266ms (204+61.4) within Mail::SpamAssassin::HTML::name_to_rgb which was called 2325 times, avg 114µs/call:
# 1610 times (132ms+37.6ms) by Mail::SpamAssassin::HTML::text_style at line 508, avg 105µs/call
# 630 times (54.4ms+21.5ms) by Mail::SpamAssassin::HTML::text_style at line 519, avg 120µs/call
# 85 times (17.9ms+2.27ms) by Mail::SpamAssassin::HTML::text_style at line 480, avg 237µs/call | ||||
998 | 2325 | 6.52ms | my $color = lc $_[0]; | ||
999 | 2325 | 4.73ms | my $before = $color; | ||
1000 | |||||
1001 | # strip leading and ending whitespace | ||||
1002 | 2325 | 30.8ms | 2325 | 12.8ms | $color =~ s/^\s*//; # spent 12.8ms making 2325 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 6µs/call |
1003 | 2325 | 40.1ms | 2325 | 13.6ms | $color =~ s/\s*$//; # spent 13.6ms making 2325 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 6µs/call |
1004 | |||||
1005 | # named colors | ||||
1006 | 2325 | 7.73ms | my $hex = $html_color{$color}; | ||
1007 | 2325 | 4.37ms | if (defined $hex) { | ||
1008 | 302 | 4.92ms | return sprintf("#%06x", $hex); | ||
1009 | } | ||||
1010 | |||||
1011 | # IF NOT A NAME, IT SHOULD BE A HEX COLOR, HEX SHORTHAND or rgb values | ||||
1012 | 2023 | 24.2ms | 2023 | 6.92ms | if ($color =~ m/^[#a-f0-9]*$|rgb\([\d%, ]*\)/i) { # spent 6.92ms making 2023 calls to Mail::SpamAssassin::HTML::CORE:match, avg 3µs/call |
1013 | |||||
1014 | #Convert the RGB values to hex values so we can fall through on the programming | ||||
1015 | |||||
1016 | #RGB PERCENTS TO HEX | ||||
1017 | 2017 | 15.5ms | 2017 | 3.52ms | if ($color =~ m/rgb\((\d+)%,\s*(\d+)%,\s*(\d+)%\s*\)/i) { # spent 3.52ms making 2017 calls to Mail::SpamAssassin::HTML::CORE:match, avg 2µs/call |
1018 | $color = "#".dec2hex(int($1/100*255)).dec2hex(int($2/100*255)).dec2hex(int($3/100*255)); | ||||
1019 | } | ||||
1020 | |||||
1021 | #RGB DEC TO HEX | ||||
1022 | 2017 | 15.7ms | 2017 | 3.27ms | if ($color =~ m/rgb\((\d+),\s*(\d+),\s*(\d+)\s*\)/i) { # spent 3.27ms making 2017 calls to Mail::SpamAssassin::HTML::CORE:match, avg 2µs/call |
1023 | $color = "#".dec2hex($1).dec2hex($2).dec2hex($3); | ||||
1024 | } | ||||
1025 | |||||
1026 | #PARSE THE HEX | ||||
1027 | 2017 | 22.9ms | 2017 | 6.01ms | if ($color =~ m/^#/) { # spent 6.01ms making 2017 calls to Mail::SpamAssassin::HTML::CORE:match, avg 3µs/call |
1028 | # strip to hex only | ||||
1029 | 2017 | 38.2ms | 2017 | 15.1ms | $color =~ s/[^a-f0-9]//ig; # spent 15.1ms making 2017 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 7µs/call |
1030 | |||||
1031 | # strip to 6 if greater than 6 | ||||
1032 | 2017 | 4.72ms | if (length($color) > 6) { | ||
1033 | $color=substr($color,0,6); | ||||
1034 | } | ||||
1035 | |||||
1036 | # strip to 3 if length < 6) | ||||
1037 | 2017 | 4.99ms | if (length($color) > 3 && length($color) < 6) { | ||
1038 | $color=substr($color,0,3); | ||||
1039 | } | ||||
1040 | |||||
1041 | # pad right-hand-side to a multiple of three | ||||
1042 | 2017 | 4.97ms | $color .= "0" x (3 - (length($color) % 3)) if (length($color) % 3); | ||
1043 | |||||
1044 | #DUPLICATE SHORTHAND HEX | ||||
1045 | 2017 | 13.3ms | if (length($color) == 3) { | ||
1046 | 66 | 804µs | 66 | 295µs | $color =~ m/(.)(.)(.)/; # spent 295µs making 66 calls to Mail::SpamAssassin::HTML::CORE:match, avg 4µs/call |
1047 | 66 | 687µs | $color = "$1$1$2$2$3$3"; | ||
1048 | } | ||||
1049 | |||||
1050 | } else { | ||||
1051 | return "invalid"; | ||||
1052 | } | ||||
1053 | |||||
1054 | } else { | ||||
1055 | #INVALID | ||||
1056 | |||||
1057 | #??RETURN BLACK SINCE WE DO NOT KNOW HOW THE MUA / BROWSER WILL PARSE | ||||
1058 | #$color = "000000"; | ||||
1059 | |||||
1060 | 6 | 53µs | return "invalid"; | ||
1061 | } | ||||
1062 | |||||
1063 | #print "DEBUG: before/after name_to_rgb new version: $before/$color\n"; | ||||
1064 | |||||
1065 | 2017 | 44.5ms | return "#" . $color; | ||
1066 | } | ||||
1067 | |||||
1068 | sub dec2hex { | ||||
1069 | my ($dec) = @_; | ||||
1070 | my ($pre) = ''; | ||||
1071 | |||||
1072 | if ($dec < 16) { | ||||
1073 | $pre = '0'; | ||||
1074 | } | ||||
1075 | |||||
1076 | return sprintf("$pre%lx", $dec); | ||||
1077 | } | ||||
1078 | |||||
1079 | |||||
1080 | 2 | 1.80ms | 2 | 533µs | # spent 289µs (46+244) within Mail::SpamAssassin::HTML::BEGIN@1080 which was called:
# once (46µs+244µs) by Mail::SpamAssassin::Message::Node::BEGIN@45 at line 1080 # spent 289µs making 1 call to Mail::SpamAssassin::HTML::BEGIN@1080
# spent 244µs making 1 call to constant::import |
1081 | |||||
1082 | # resolving relative URIs as defined in RFC 2396 (steps from section 5.2) | ||||
1083 | # using draft http://www.gbiv.com/protocols/uri/rev-2002/rfc2396bis.html | ||||
1084 | # spent 246ms (191+54.9) within Mail::SpamAssassin::HTML::_parse_uri which was called 5410 times, avg 45µs/call:
# 2705 times (111ms+39.1ms) by Mail::SpamAssassin::HTML::target_uri at line 1131, avg 56µs/call
# 2705 times (79.7ms+15.8ms) by Mail::SpamAssassin::HTML::target_uri at line 1132, avg 35µs/call | ||||
1085 | 5410 | 10.1ms | my ($u) = @_; | ||
1086 | 5410 | 9.23ms | my %u; | ||
1087 | 5410 | 156ms | 5410 | 54.9ms | ($u{scheme}, $u{authority}, $u{path}, $u{query}, $u{fragment}) = # spent 54.9ms making 5410 calls to Mail::SpamAssassin::HTML::CORE:match, avg 10µs/call |
1088 | $u =~ m|^(?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?|; | ||||
1089 | 5410 | 109ms | return %u; | ||
1090 | } | ||||
1091 | |||||
1092 | sub _remove_dot_segments { | ||||
1093 | 2703 | 5.81ms | my ($input) = @_; | ||
1094 | 2703 | 5.32ms | my $output = ""; | ||
1095 | |||||
1096 | 2703 | 54.3ms | 2703 | 6.42ms | $input =~ s@^(?:\.\.?/)@/@; # spent 6.42ms making 2703 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 2µs/call |
1097 | |||||
1098 | 2703 | 9.65ms | while ($input) { | ||
1099 | 8468 | 369ms | 25404 | 83.4ms | if ($input =~ s@^/\.(?:$|/)@/@) { # spent 83.4ms making 25404 calls to Mail::SpamAssassin::HTML::CORE:subst, avg 3µs/call |
1100 | } | ||||
1101 | elsif ($input =~ s@^/\.\.(?:$|/)@/@) { | ||||
1102 | $output =~ s@/?[^/]*$@@; | ||||
1103 | } | ||||
1104 | elsif ($input =~ s@(/?[^/]*)@@) { | ||||
1105 | 8468 | 29.4ms | $output .= $1; | ||
1106 | } | ||||
1107 | } | ||||
1108 | 2703 | 42.7ms | return $output; | ||
1109 | } | ||||
1110 | |||||
1111 | sub _merge_uri { | ||||
1112 | my ($base_authority, $base_path, $r_path) = @_; | ||||
1113 | |||||
1114 | if (defined $base_authority && !$base_path) { | ||||
1115 | return "/" . $r_path; | ||||
1116 | } | ||||
1117 | else { | ||||
1118 | if ($base_path =~ m|/|) { | ||||
1119 | $base_path =~ s|(?<=/)[^/]*$||; | ||||
1120 | } | ||||
1121 | else { | ||||
1122 | $base_path = ""; | ||||
1123 | } | ||||
1124 | return $base_path . $r_path; | ||||
1125 | } | ||||
1126 | } | ||||
1127 | |||||
1128 | # spent 1.05s (315ms+736ms) within Mail::SpamAssassin::HTML::target_uri which was called 2705 times, avg 389µs/call:
# 2705 times (315ms+736ms) by Mail::SpamAssassin::HTML::push_uri at line 329, avg 389µs/call | ||||
1129 | 2705 | 5.69ms | my ($base, $r) = @_; | ||
1130 | |||||
1131 | 2705 | 33.3ms | 2705 | 150ms | my %r = _parse_uri($r); # parsed relative URI # spent 150ms making 2705 calls to Mail::SpamAssassin::HTML::_parse_uri, avg 56µs/call |
1132 | 2705 | 27.9ms | 2705 | 95.5ms | my %base = _parse_uri($base); # parsed base URI # spent 95.5ms making 2705 calls to Mail::SpamAssassin::HTML::_parse_uri, avg 35µs/call |
1133 | 2705 | 4.41ms | my %t; # generated temporary URI | ||
1134 | |||||
1135 | 2705 | 6.73ms | if ((not URI_STRICT) and | ||
1136 | (defined $r{scheme} && defined $base{scheme}) and | ||||
1137 | ($r{scheme} eq $base{scheme})) | ||||
1138 | { | ||||
1139 | undef $r{scheme}; | ||||
1140 | } | ||||
1141 | |||||
1142 | 2705 | 9.57ms | if (defined $r{scheme}) { | ||
1143 | 2702 | 8.01ms | $t{scheme} = $r{scheme}; | ||
1144 | 2702 | 7.44ms | $t{authority} = $r{authority}; | ||
1145 | 2702 | 21.9ms | 2702 | 490ms | $t{path} = _remove_dot_segments($r{path}); # spent 490ms making 2702 calls to Mail::SpamAssassin::HTML::_remove_dot_segments, avg 181µs/call |
1146 | 2702 | 18.7ms | $t{query} = $r{query}; | ||
1147 | } | ||||
1148 | else { | ||||
1149 | 3 | 13µs | if (defined $r{authority}) { | ||
1150 | 1 | 3µs | $t{authority} = $r{authority}; | ||
1151 | 1 | 7µs | 1 | 56µs | $t{path} = _remove_dot_segments($r{path}); # spent 56µs making 1 call to Mail::SpamAssassin::HTML::_remove_dot_segments |
1152 | 1 | 3µs | $t{query} = $r{query}; | ||
1153 | } | ||||
1154 | else { | ||||
1155 | 2 | 17µs | if ($r{path} eq "") { | ||
1156 | 2 | 7µs | $t{path} = $base{path}; | ||
1157 | 2 | 8µs | if (defined $r{query}) { | ||
1158 | $t{query} = $r{query}; | ||||
1159 | } | ||||
1160 | else { | ||||
1161 | 2 | 5µs | $t{query} = $base{query}; | ||
1162 | } | ||||
1163 | } | ||||
1164 | else { | ||||
1165 | if ($r{path} =~ m|^/|) { | ||||
1166 | $t{path} = _remove_dot_segments($r{path}); | ||||
1167 | } | ||||
1168 | else { | ||||
1169 | $t{path} = _merge_uri($base{authority}, $base{path}, $r{path}); | ||||
1170 | $t{path} = _remove_dot_segments($t{path}); | ||||
1171 | } | ||||
1172 | $t{query} = $r{query}; | ||||
1173 | } | ||||
1174 | 2 | 6µs | $t{authority} = $base{authority}; | ||
1175 | } | ||||
1176 | 3 | 8µs | $t{scheme} = $base{scheme}; | ||
1177 | } | ||||
1178 | 2705 | 7.16ms | $t{fragment} = $r{fragment}; | ||
1179 | |||||
1180 | # recompose URI | ||||
1181 | 2705 | 5.06ms | my $result = ""; | ||
1182 | 2705 | 9.24ms | if ($t{scheme}) { | ||
1183 | 2702 | 8.38ms | $result .= $t{scheme} . ":"; | ||
1184 | } | ||||
1185 | elsif (defined $t{authority}) { | ||||
1186 | # this block is not part of the RFC | ||||
1187 | # TODO: figure out what MUAs actually do with unschemed URIs | ||||
1188 | # maybe look at URI::Heuristic | ||||
1189 | 1 | 20µs | 2 | 6µs | if ($t{authority} =~ /^www\d*\./i) { # spent 6µs making 2 calls to Mail::SpamAssassin::HTML::CORE:match, avg 3µs/call |
1190 | # some spammers are using unschemed URIs to escape filters | ||||
1191 | $result .= "http:"; | ||||
1192 | } | ||||
1193 | elsif ($t{authority} =~ /^ftp\d*\./i) { | ||||
1194 | $result .= "ftp:"; | ||||
1195 | } | ||||
1196 | } | ||||
1197 | 2705 | 9.39ms | if ($t{authority}) { | ||
1198 | 2654 | 7.28ms | $result .= "//" . $t{authority}; | ||
1199 | } | ||||
1200 | 2705 | 8.72ms | $result .= $t{path}; | ||
1201 | 2705 | 5.81ms | if (defined $t{query}) { | ||
1202 | 328 | 1.53ms | $result .= "?" . $t{query}; | ||
1203 | } | ||||
1204 | 2705 | 5.11ms | if (defined $t{fragment}) { | ||
1205 | 8 | 41µs | $result .= "#" . $t{fragment}; | ||
1206 | } | ||||
1207 | 2705 | 52.3ms | return $result; | ||
1208 | } | ||||
1209 | |||||
1210 | 1 | 119µs | 1; | ||
1211 | __END__ | ||||
# spent 1.34s within Mail::SpamAssassin::HTML::CORE:match which was called 231886 times, avg 6µs/call:
# 46892 times (97.9ms+0s) by Mail::SpamAssassin::HTML::html_tag at line 270, avg 2µs/call
# 33070 times (148ms+0s) by Mail::SpamAssassin::HTML::html_text at line 754, avg 4µs/call
# 29608 times (405ms+0s) by Mail::SpamAssassin::HTML::html_text at line 745, avg 14µs/call
# 29444 times (199ms+0s) by Mail::SpamAssassin::HTML::html_text at line 759, avg 7µs/call
# 28303 times (182ms+0s) by Mail::SpamAssassin::HTML::text_style at line 496, avg 6µs/call
# 16907 times (78.4ms+0s) by Mail::SpamAssassin::HTML::html_whitespace at line 310, avg 5µs/call
# 16542 times (70.8ms+0s) by Mail::SpamAssassin::HTML::html_uri at line 355, avg 4µs/call
# 5410 times (54.9ms+0s) by Mail::SpamAssassin::HTML::_parse_uri at line 1087, avg 10µs/call
# 4740 times (29.8ms+0s) by Mail::SpamAssassin::HTML::html_font_invisible at line 554, avg 6µs/call
# 4739 times (16.6ms+0s) by Mail::SpamAssassin::HTML::html_font_invisible at line 561, avg 4µs/call
# 3213 times (12.8ms+0s) by Mail::SpamAssassin::HTML::close_table_tag at line 409, avg 4µs/call
# 2221 times (6.05ms+0s) by Mail::SpamAssassin::HTML::text_style at line 500, avg 3µs/call
# 2023 times (6.92ms+0s) by Mail::SpamAssassin::HTML::name_to_rgb at line 1012, avg 3µs/call
# 2017 times (6.01ms+0s) by Mail::SpamAssassin::HTML::name_to_rgb at line 1027, avg 3µs/call
# 2017 times (3.52ms+0s) by Mail::SpamAssassin::HTML::name_to_rgb at line 1017, avg 2µs/call
# 2017 times (3.27ms+0s) by Mail::SpamAssassin::HTML::name_to_rgb at line 1022, avg 2µs/call
# 776 times (7.29ms+0s) by Mail::SpamAssassin::HTML::html_tests at line 628, avg 9µs/call
# 776 times (3.15ms+0s) by Mail::SpamAssassin::HTML::html_tests at line 632, avg 4µs/call
# 391 times (1.29ms+0s) by Mail::SpamAssassin::HTML::html_text at line 763, avg 3µs/call
# 272 times (1.79ms+0s) by Mail::SpamAssassin::HTML::html_tests at line 664, avg 7µs/call
# 198 times (800µs+0s) by Mail::SpamAssassin::HTML::text_style at line 483, avg 4µs/call
# 175 times (1.97ms+0s) by Mail::SpamAssassin::HTML::html_tests at line 611, avg 11µs/call
# 67 times (396µs+0s) by Mail::SpamAssassin::HTML::html_declaration at line 789, avg 6µs/call
# 66 times (295µs+0s) by Mail::SpamAssassin::HTML::name_to_rgb at line 1046, avg 4µs/call
# 2 times (6µs+0s) by Mail::SpamAssassin::HTML::target_uri at line 1189, avg 3µs/call | |||||
# spent 576ms within Mail::SpamAssassin::HTML::CORE:subst which was called 101699 times, avg 6µs/call:
# 29608 times (261ms+0s) by Mail::SpamAssassin::HTML::display_text at line 698, avg 9µs/call
# 25404 times (83.4ms+0s) by Mail::SpamAssassin::HTML::_remove_dot_segments at line 1099, avg 3µs/call
# 14215 times (56.8ms+0s) by Mail::SpamAssassin::HTML::display_text at line 705, avg 4µs/call
# 14202 times (55.2ms+0s) by Mail::SpamAssassin::HTML::display_text at line 693, avg 4µs/call
# 4261 times (24.9ms+0s) by Mail::SpamAssassin::HTML::canon_uri at line 339, avg 6µs/call
# 4261 times (22.3ms+0s) by Mail::SpamAssassin::HTML::canon_uri at line 340, avg 5µs/call
# 2703 times (6.42ms+0s) by Mail::SpamAssassin::HTML::_remove_dot_segments at line 1096, avg 2µs/call
# 2325 times (13.6ms+0s) by Mail::SpamAssassin::HTML::name_to_rgb at line 1003, avg 6µs/call
# 2325 times (12.8ms+0s) by Mail::SpamAssassin::HTML::name_to_rgb at line 1002, avg 6µs/call
# 2017 times (15.1ms+0s) by Mail::SpamAssassin::HTML::name_to_rgb at line 1029, avg 7µs/call
# 189 times (15.0ms+0s) by Mail::SpamAssassin::HTML::parse at line 244, avg 79µs/call
# 189 times (9.24ms+0s) by Mail::SpamAssassin::HTML::parse at line 248, avg 49µs/call | |||||
# spent 28.3ms within Mail::SpamAssassin::HTML::CORE:substcont which was called 1404 times, avg 20µs/call:
# 1404 times (28.3ms+0s) by Mail::SpamAssassin::HTML::parse at line 248, avg 20µs/call |