Filename | /var/www/foswiki11/lib/Foswiki.pm |
Statements | Executed 979141 statements in 1.48s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
81918 | 13 | 11 | 924ms | 993ms | normalizeWebTopicName | Foswiki::
46261 | 10 | 9 | 598ms | 3.15s | topicExists | Foswiki::
17563 | 6 | 4 | 44.0ms | 49.6ms | search | Foswiki::
454 | 2 | 1 | 20.7ms | 59.1s | _expandMacroOnTopicRendering (recurses: max depth 3, inclusive time 17.4s) | Foswiki::
86 | 2 | 1 | 15.2ms | 59.1s | _processMacros (recurses: max depth 5, inclusive time 26.7s) | Foswiki::
1 | 1 | 1 | 13.2ms | 14.7ms | BEGIN@630 | Foswiki::
14 | 4 | 4 | 11.5ms | 12.9ms | renderer | Foswiki::
1 | 1 | 1 | 10.0ms | 16.9ms | BEGIN@49 | Foswiki::
1515 | 41 | 9 | 7.13ms | 7.13ms | isTrue | Foswiki::
1 | 1 | 1 | 6.47ms | 27.8ms | writeCompletePage | Foswiki::
1 | 1 | 1 | 4.53ms | 35.5ms | BEGIN@137 | Foswiki::
1 | 1 | 1 | 4.45ms | 8.93ms | BEGIN@47 | Foswiki::
48 | 3 | 3 | 3.51ms | 4.67ms | i18n | Foswiki::
168 | 7 | 4 | 2.83ms | 3.14ms | templates | Foswiki::
1 | 1 | 1 | 2.68ms | 8.05ms | BEGIN@636 | Foswiki::
3 | 3 | 2 | 2.55ms | 2.96ms | logger | Foswiki::
1 | 1 | 1 | 2.45ms | 14.6ms | BEGIN@631 | Foswiki::
1 | 1 | 1 | 2.32ms | 12.5ms | finish | Foswiki::
1 | 1 | 1 | 2.25ms | 2.33ms | BEGIN@632 | Foswiki::
1 | 1 | 1 | 2.25ms | 2.36ms | attach | Foswiki::
1 | 1 | 1 | 2.02ms | 2.21ms | BEGIN@48 | Foswiki::
49 | 6 | 3 | 2.01ms | 59.1s | innerExpandMacros (recurses: max depth 3, inclusive time 17.4s) | Foswiki::
106 | 7 | 3 | 2.00ms | 2.00ms | takeOutBlocks | Foswiki::
1 | 1 | 1 | 1.97ms | 3.16ms | BEGIN@171 | Foswiki::
2 | 1 | 1 | 1.90ms | 8.35s | deepWebList | Foswiki::
1 | 1 | 1 | 1.81ms | 4.42ms | BEGIN@633 | Foswiki::
1 | 1 | 1 | 1.77ms | 5.61ms | BEGIN@634 | Foswiki::
177 | 4 | 4 | 1.68ms | 14.4ms | webExists | Foswiki::
1 | 1 | 1 | 1.67ms | 1.74ms | BEGIN@51 | Foswiki::
45 | 3 | 2 | 1.65ms | 6.67ms | getSkin | Foswiki::
182 | 1 | 1 | 1.16ms | 1.16ms | isValidWebName | Foswiki::
1 | 1 | 1 | 1.15ms | 4.33ms | BEGIN@46 | Foswiki::
96 | 7 | 6 | 1.06ms | 1.06ms | expandStandardEscapes | Foswiki::
48 | 6 | 4 | 995µs | 1.75ms | getScriptUrl | Foswiki::
1 | 1 | 1 | 989µs | 1.34ms | BEGIN@50 | Foswiki::
99 | 6 | 3 | 795µs | 830µs | putBackBlocks | Foswiki::
7 | 1 | 1 | 638µs | 59.1s | expandMacros | Foswiki::
2 | 2 | 1 | 556µs | 20.8ms | _renderZone | Foswiki::
1 | 1 | 1 | 531µs | 1.72s | new | Foswiki::
1 | 1 | 1 | 442µs | 634µs | BEGIN@635 | Foswiki::
36 | 3 | 2 | 386µs | 518µs | getPubUrl | Foswiki::
16 | 2 | 2 | 358µs | 358µs | addToZone | Foswiki::
43 | 2 | 1 | 302µs | 302µs | _visitZoneID (recurses: max depth 3, inclusive time 163µs) | Foswiki::
97 | 12 | 4 | 264µs | 264µs | inContext | Foswiki::
1 | 1 | 1 | 236µs | 308µs | BEGIN@629 | Foswiki::
23 | 1 | 1 | 206µs | 241µs | _make_params | Foswiki::
55 | 12 | 4 | 185µs | 185µs | registerTagHandler | Foswiki::
42 | 7 | 4 | 182µs | 182µs | enterContext | Foswiki::
33 | 1 | 1 | 182µs | 590µs | __ANON__[:241] | Foswiki::
1 | 1 | 1 | 177µs | 21.0ms | _renderZones | Foswiki::
56 | 5 | 2 | 175µs | 175µs | urlEncode | Foswiki::
6 | 1 | 1 | 158µs | 158µs | parseSections | Foswiki::
41 | 1 | 1 | 113µs | 113µs | __ANON__[:368] | Foswiki::
51 | 3 | 1 | 111µs | 111µs | SINGLE_SINGLETONS | Foswiki::
16 | 1 | 1 | 105µs | 342µs | __ANON__[:270] | Foswiki::
9 | 2 | 2 | 104µs | 104µs | isValidTopicName | Foswiki::
2 | 1 | 1 | 88µs | 88µs | spaceOutWikiWord | Foswiki::
1 | 1 | 1 | 77µs | 225µs | generateHTTPHeaders | Foswiki::
9 | 1 | 1 | 74µs | 161µs | __ANON__[:268] | Foswiki::
10 | 5 | 4 | 73µs | 108µs | getLoginManager | Foswiki::
5 | 1 | 1 | 55µs | 296µs | __ANON__[:211] | Foswiki::
1 | 1 | 1 | 48µs | 450µs | logEvent | Foswiki::
14 | 1 | 1 | 45µs | 45µs | __ANON__[:372] | Foswiki::
2 | 1 | 1 | 37µs | 37µs | __ANON__[:417] | Foswiki::
4 | 4 | 2 | 32µs | 32µs | leaveContext | Foswiki::
4 | 1 | 1 | 26µs | 26µs | __ANON__[:361] | Foswiki::
1 | 1 | 1 | 25µs | 111µs | getWorkArea | Foswiki::
1 | 1 | 1 | 24µs | 48µs | BEGIN@44 | Foswiki::
1 | 1 | 1 | 21µs | 28µs | urlEncodeAttachment | Foswiki::
1 | 1 | 1 | 16µs | 77µs | __ANON__[:283] | Foswiki::
1 | 1 | 1 | 15µs | 15µs | _getLibDir | Foswiki::
1 | 1 | 1 | 15µs | 25µs | BEGIN@45 | Foswiki::
1 | 1 | 1 | 14µs | 79µs | __ANON__[:279] | Foswiki::
2 | 1 | 1 | 13µs | 25µs | __ANON__[:240] | Foswiki::
1 | 1 | 1 | 13µs | 22µs | __ANON__[:267] | Foswiki::
2 | 2 | 1 | 12µs | 12µs | UTF82SiteCharSet | Foswiki::
1 | 1 | 1 | 12µs | 42µs | getCGISession | Foswiki::
1 | 1 | 1 | 9µs | 93µs | __ANON__[:244] | Foswiki::
1 | 1 | 1 | 8µs | 8µs | __ANON__[:404] | Foswiki::
2 | 2 | 1 | 6µs | 6µs | SINGLE_SINGLETONS_TRACE | Foswiki::
1 | 1 | 1 | 5µs | 5µs | BEGIN@627 | Foswiki::
1 | 1 | 1 | 3µs | 3µs | BEGIN@628 | Foswiki::
1 | 1 | 1 | 3µs | 3µs | __ANON__[:366] | Foswiki::
2 | 2 | 1 | 2µs | 2µs | __ANON__ (xsub) | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:152] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:184] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:186] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:188] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:195] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:202] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:217] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:226] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:236] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:239] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:250] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:258] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:262] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:275] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:297] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:298] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:299] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:300] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:301] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:302] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:3141] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:341] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:358] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:359] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:360] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:362] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:364] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:365] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:367] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:369] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:370] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:371] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:373] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:374] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:375] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:376] | Foswiki::
0 | 0 | 0 | 0s | 0s | __ANON__[:377] | Foswiki::
0 | 0 | 0 | 0s | 0s | _expandMacroOnTopicCreation | Foswiki::
0 | 0 | 0 | 0s | 0s | _isRedirectSafe | Foswiki::
0 | 0 | 0 | 0s | 0s | _renderZoneById | Foswiki::
0 | 0 | 0 | 0s | 0s | cacheQuery | Foswiki::
0 | 0 | 0 | 0s | 0s | entityDecode | Foswiki::
0 | 0 | 0 | 0s | 0s | entityEncode | Foswiki::
0 | 0 | 0 | 0s | 0s | expandMacrosOnTopicCreation | Foswiki::
0 | 0 | 0 | 0s | 0s | getApproxRevTime | Foswiki::
0 | 0 | 0 | 0s | 0s | inlineAlert | Foswiki::
0 | 0 | 0 | 0s | 0s | isValidEmailAddress | Foswiki::
0 | 0 | 0 | 0s | 0s | isValidWikiWord | Foswiki::
0 | 0 | 0 | 0s | 0s | net | Foswiki::
0 | 0 | 0 | 0s | 0s | readFile | Foswiki::
0 | 0 | 0 | 0s | 0s | redirect | Foswiki::
0 | 0 | 0 | 0s | 0s | redirectto | Foswiki::
0 | 0 | 0 | 0s | 0s | splitAnchorFromUrl | Foswiki::
0 | 0 | 0 | 0s | 0s | urlDecode | Foswiki::
0 | 0 | 0 | 0s | 0s | validatePattern | Foswiki::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | package Foswiki; | ||||
3 | |||||
4 | =begin TML | ||||
5 | |||||
6 | ---+ package Foswiki | ||||
7 | |||||
8 | Foswiki operates by creating a singleton object (known as the Session | ||||
9 | object) that acts as a point of reference for all the different | ||||
10 | modules in the system. This package is the class for this singleton, | ||||
11 | and also contains the vast bulk of the basic constants and the per- | ||||
12 | site configuration mechanisms. | ||||
13 | |||||
14 | Global variables are avoided wherever possible to avoid problems | ||||
15 | with CGI accelerators such as mod_perl. | ||||
16 | |||||
17 | ---++ Public Data members | ||||
18 | * =request= Pointer to the Foswiki::Request | ||||
19 | * =response= Pointer to the Foswiki::Response | ||||
20 | * =context= Hash of context ids | ||||
21 | * =plugins= Foswiki::Plugins singleton | ||||
22 | * =prefs= Foswiki::Prefs singleton | ||||
23 | * =remoteUser= Login ID when using ApacheLogin. Maintained for | ||||
24 | compatibility only, do not use. | ||||
25 | * =requestedWebName= Name of web found in URL path or =web= URL parameter | ||||
26 | * =scriptUrlPath= URL path to the current script. May be dynamically | ||||
27 | extracted from the URL path if {GetScriptUrlFromCgi}. | ||||
28 | Only required to support {GetScriptUrlFromCgi} and | ||||
29 | not consistently used. Avoid. | ||||
30 | * =security= Foswiki::Access singleton | ||||
31 | * =store= Foswiki::Store singleton | ||||
32 | * =topicName= Name of topic found in URL path or =topic= URL | ||||
33 | parameter | ||||
34 | * =urlHost= Host part of the URL (including the protocol) | ||||
35 | determined during intialisation and defaulting to | ||||
36 | {DefaultUrlHost} | ||||
37 | * =user= Unique user ID of logged-in user | ||||
38 | * =users= Foswiki::Users singleton | ||||
39 | * =webName= Name of web found in URL path, or =web= URL parameter, | ||||
40 | or {UsersWebName} | ||||
41 | |||||
42 | =cut | ||||
43 | |||||
44 | 2 | 47µs | 2 | 72µs | # spent 48µs (24+24) within Foswiki::BEGIN@44 which was called:
# once (24µs+24µs) by main::BEGIN@22 at line 44 # spent 48µs making 1 call to Foswiki::BEGIN@44
# spent 24µs making 1 call to strict::import |
45 | 2 | 40µs | 2 | 35µs | # spent 25µs (15+10) within Foswiki::BEGIN@45 which was called:
# once (15µs+10µs) by main::BEGIN@22 at line 45 # spent 25µs making 1 call to Foswiki::BEGIN@45
# spent 10µs making 1 call to warnings::import |
46 | 2 | 172µs | 2 | 4.35ms | # spent 4.33ms (1.15+3.18) within Foswiki::BEGIN@46 which was called:
# once (1.15ms+3.18ms) by main::BEGIN@22 at line 46 # spent 4.33ms making 1 call to Foswiki::BEGIN@46
# spent 20µs making 1 call to Assert::import |
47 | 2 | 193µs | 2 | 9.13ms | # spent 8.93ms (4.45+4.48) within Foswiki::BEGIN@47 which was called:
# once (4.45ms+4.48ms) by main::BEGIN@22 at line 47 # spent 8.93ms making 1 call to Foswiki::BEGIN@47
# spent 198µs making 1 call to Error::import |
48 | 2 | 176µs | 1 | 2.21ms | # spent 2.21ms (2.02+188µs) within Foswiki::BEGIN@48 which was called:
# once (2.02ms+188µs) by main::BEGIN@22 at line 48 # spent 2.21ms making 1 call to Foswiki::BEGIN@48 |
49 | 2 | 164µs | 1 | 16.9ms | # spent 16.9ms (10.0+6.85) within Foswiki::BEGIN@49 which was called:
# once (10.0ms+6.85ms) by main::BEGIN@22 at line 49 # spent 16.9ms making 1 call to Foswiki::BEGIN@49 |
50 | 2 | 148µs | 1 | 1.34ms | # spent 1.34ms (989µs+347µs) within Foswiki::BEGIN@50 which was called:
# once (989µs+347µs) by main::BEGIN@22 at line 50 # spent 1.34ms making 1 call to Foswiki::BEGIN@50 |
51 | 2 | 765µs | 1 | 1.74ms | # spent 1.74ms (1.67+67µs) within Foswiki::BEGIN@51 which was called:
# once (1.67ms+67µs) by main::BEGIN@22 at line 51 # spent 1.74ms making 1 call to Foswiki::BEGIN@51 |
52 | |||||
53 | 1 | 12µs | require 5.005; # For regex objects and internationalisation | ||
54 | |||||
55 | # Site configuration constants | ||||
56 | 1 | 400ns | our %cfg; | ||
57 | |||||
58 | # Other computed constants | ||||
59 | 1 | 200ns | our $foswikiLibDir; | ||
60 | 1 | 200ns | our %regex; | ||
61 | 1 | 100ns | our %macros; | ||
62 | 1 | 100ns | our %contextFreeSyntax; | ||
63 | 1 | 300ns | our $VERSION; | ||
64 | 1 | 200ns | our $RELEASE; | ||
65 | 1 | 300ns | our $TRUE = 1; | ||
66 | 1 | 100ns | our $FALSE = 0; | ||
67 | 1 | 100ns | our $engine; | ||
68 | 1 | 700ns | our $TranslationToken = "\0"; # Do not deprecate - used in many plugins | ||
69 | |||||
70 | # Note: the following marker is used in text to mark RENDERZONE | ||||
71 | # macros that have been hoisted from the source text of a page. It is | ||||
72 | # carefully chosen so that it is (1) not normally present in written | ||||
73 | # text (2) does not combine with other characters to form valid | ||||
74 | # wide-byte characters and (3) does not conflict with other markers used | ||||
75 | # by Foswiki/Render.pm | ||||
76 | 1 | 200ns | our $RENDERZONE_MARKER = "\3"; | ||
77 | |||||
78 | # Used by takeOut/putBack blocks | ||||
79 | 1 | 100ns | our $BLOCKID = 0; | ||
80 | 1 | 200ns | our $OC = "<!--\0"; | ||
81 | 1 | 300ns | our $CC = "\0-->"; | ||
82 | |||||
83 | # This variable is set if Foswiki is running in unit test mode. | ||||
84 | # It is provided so that modules can detect unit test mode to avoid | ||||
85 | # corrupting data spaces. | ||||
86 | 1 | 200ns | our $inUnitTestMode = 0; | ||
87 | |||||
88 | 51 | 153µs | sub SINGLE_SINGLETONS { 0 } | ||
89 | 2 | 8µs | sub SINGLE_SINGLETONS_TRACE { 0 } | ||
90 | |||||
91 | # Returns the full path of the directory containing Foswiki.pm | ||||
92 | # spent 15µs within Foswiki::_getLibDir which was called:
# once (15µs+0s) by Foswiki::BEGIN@137 at line 611 | ||||
93 | 1 | 300ns | return $foswikiLibDir if $foswikiLibDir; | ||
94 | |||||
95 | 1 | 800ns | $foswikiLibDir = $INC{'Foswiki.pm'}; | ||
96 | |||||
97 | # fix path relative to location of called script | ||||
98 | 1 | 700ns | if ( $foswikiLibDir =~ /^\./ ) { | ||
99 | print STDERR | ||||
100 | "WARNING: Foswiki lib path $foswikiLibDir is relative; you should make it absolute, otherwise some scripts may not run from the command line."; | ||||
101 | my $bin; | ||||
102 | |||||
103 | # SMELL : Should not assume environment variables; get data from request | ||||
104 | if ( $ENV{SCRIPT_FILENAME} | ||||
105 | && $ENV{SCRIPT_FILENAME} =~ m#^(.+)/.+?$# ) | ||||
106 | { | ||||
107 | |||||
108 | # CGI script name | ||||
109 | # implicit untaint OK, because of use of $SCRIPT_FILENAME | ||||
110 | $bin = $1; | ||||
111 | } | ||||
112 | elsif ( $0 =~ m#^(.*)/.*?$# ) { | ||||
113 | |||||
114 | # program name | ||||
115 | # implicit untaint OK, because of use of $PROGRAM_NAME ($0) | ||||
116 | $bin = $1; | ||||
117 | } | ||||
118 | else { | ||||
119 | |||||
120 | # last ditch; relative to current directory. | ||||
121 | require Cwd; | ||||
122 | $bin = Cwd::cwd(); | ||||
123 | } | ||||
124 | $foswikiLibDir = "$bin/$foswikiLibDir/"; | ||||
125 | |||||
126 | # normalize "/../" and "/./" | ||||
127 | while ( $foswikiLibDir =~ s|([\\/])[^\\/]+[\\/]\.\.[\\/]|$1| ) { | ||||
128 | } | ||||
129 | $foswikiLibDir =~ s|([\\/])\.[\\/]|$1|g; | ||||
130 | } | ||||
131 | 1 | 10µs | $foswikiLibDir =~ s|([\\/])[\\/]*|$1|g; # reduce "//" to "/" | ||
132 | 1 | 1µs | $foswikiLibDir =~ s|[\\/]$||; # cut trailing "/" | ||
133 | |||||
134 | 1 | 6µs | return $foswikiLibDir; | ||
135 | } | ||||
136 | |||||
137 | # spent 35.5ms (4.53+31.0) within Foswiki::BEGIN@137 which was called:
# once (4.53ms+31.0ms) by main::BEGIN@22 at line 624 | ||||
138 | |||||
139 | #Monitor::MARK("Start of BEGIN block in Foswiki.pm"); | ||||
140 | 1 | 2µs | 1 | 2µs | if (DEBUG) { # spent 2µs making 1 call to Assert::ASSERTS_OFF |
141 | if ( not $Assert::soft ) { | ||||
142 | |||||
143 | # If ASSERTs are on (and not soft), then warnings are errors. | ||||
144 | # Paranoid, but the only way to be sure we eliminate them all. | ||||
145 | # Look out also for $cfg{WarningsAreErrors}, below, which | ||||
146 | # is another way to install this handler without enabling | ||||
147 | # ASSERTs | ||||
148 | # ASSERTS are turned on by defining the environment variable | ||||
149 | # FOSWIKI_ASSERTS. If ASSERTs are off, this is assumed to be a | ||||
150 | # production environment, and no stack traces or paths are | ||||
151 | # output to the browser. | ||||
152 | $SIG{'__WARN__'} = sub { die @_ }; | ||||
153 | $Error::Debug = 1; # verbose stack traces, please | ||||
154 | } | ||||
155 | else { | ||||
156 | |||||
157 | # ASSERTs are soft, so warnings are not errors | ||||
158 | # but ASSERTs are enabled. This is useful for tracking down | ||||
159 | # problems that only manifest on production servers. | ||||
160 | # Consequently, this is only useful when | ||||
161 | # $cfg{WarningsAreErrors} is NOT enabled | ||||
162 | $Error::Debug = 0; # no verbose stack traces | ||||
163 | } | ||||
164 | } | ||||
165 | else { | ||||
166 | 1 | 500ns | $Error::Debug = 0; # no verbose stack traces | ||
167 | } | ||||
168 | |||||
169 | # DO NOT CHANGE THE FORMAT OF $VERSION. | ||||
170 | # Use $RELEASE for a descriptive version. | ||||
171 | 4 | 3.40ms | 4 | 3.32ms | # spent 3.16ms (1.97+1.19) within Foswiki::BEGIN@171 which was called:
# once (1.97ms+1.19ms) by main::BEGIN@22 at line 171 # spent 3.16ms making 1 call to Foswiki::BEGIN@171
# spent 66µs making 1 call to version::vxs::declare
# spent 65µs making 1 call to UNIVERSAL::VERSION
# spent 27µs making 1 call to version::import |
172 | 1 | 500ns | $RELEASE = 'Foswiki-1.1.9'; | ||
173 | |||||
174 | # Default handlers for different %TAGS% | ||||
175 | # Where an entry is set as 'undef', the tag will be demand-loaded | ||||
176 | # from Foswiki::Macros, if it is used. This tactic is used to reduce | ||||
177 | # the load time of this module, especially when it is used from | ||||
178 | # REST handlers. | ||||
179 | %macros = ( | ||||
180 | ADDTOHEAD => undef, | ||||
181 | |||||
182 | # deprecated, use ADDTOZONE instead | ||||
183 | ADDTOZONE => undef, | ||||
184 | ALLVARIABLES => sub { $_[0]->{prefs}->stringify() }, | ||||
185 | ATTACHURL => | ||||
186 | sub { return $_[0]->getPubUrl( 1, $_[2]->web, $_[2]->topic ); }, | ||||
187 | ATTACHURLPATH => | ||||
188 | sub { return $_[0]->getPubUrl( 0, $_[2]->web, $_[2]->topic ); }, | ||||
189 | DATE => sub { | ||||
190 | Foswiki::Time::formatTime( | ||||
191 | time(), | ||||
192 | $Foswiki::cfg{DefaultDateFormat}, | ||||
193 | $Foswiki::cfg{DisplayTimeValues} | ||||
194 | ); | ||||
195 | }, | ||||
196 | DISPLAYTIME => sub { | ||||
197 | Foswiki::Time::formatTime( | ||||
198 | time(), | ||||
199 | $_[1]->{_DEFAULT} || '', | ||||
200 | $Foswiki::cfg{DisplayTimeValues} | ||||
201 | ); | ||||
202 | }, | ||||
203 | ENCODE => undef, | ||||
204 | ENV => undef, | ||||
205 | EXPAND => undef, | ||||
206 | FORMAT => undef, | ||||
207 | FORMFIELD => undef, | ||||
208 | # spent 296µs (55+241) within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:211] which was called 5 times, avg 59µs/call:
# 5 times (55µs+241µs) by Foswiki::_expandMacroOnTopicRendering at line 3160, avg 59µs/call | ||||
209 | 5 | 47µs | 5 | 241µs | Foswiki::Time::formatTime( time(), $_[1]->{_DEFAULT} || '', # spent 241µs making 5 calls to Foswiki::Time::formatTime, avg 48µs/call |
210 | 'gmtime' ); | ||||
211 | }, | ||||
212 | GROUPINFO => undef, | ||||
213 | GROUPS => undef, | ||||
214 | HTTP_HOST => | ||||
215 | |||||
216 | #deprecated functionality, now implemented using %ENV% | ||||
217 | sub { $_[0]->{request}->header('Host') || '' }, | ||||
218 | HTTP => undef, | ||||
219 | HTTPS => undef, | ||||
220 | ICON => undef, | ||||
221 | ICONURL => undef, | ||||
222 | ICONURLPATH => undef, | ||||
223 | IF => undef, | ||||
224 | INCLUDE => undef, | ||||
225 | INTURLENCODE => undef, | ||||
226 | LANGUAGE => sub { $_[0]->i18n->language(); }, | ||||
227 | LANGUAGES => undef, | ||||
228 | MAKETEXT => undef, | ||||
229 | META => undef, # deprecated | ||||
230 | METASEARCH => undef, # deprecated | ||||
231 | NOP => | ||||
232 | |||||
233 | # Remove NOP tag in template topics but show content. | ||||
234 | # Used in template _topics_ (not templates, per se, but | ||||
235 | # topics used as templates for new topics) | ||||
236 | sub { $_[1]->{_RAW} ? $_[1]->{_RAW} : '<nop>' }, | ||||
237 | PLUGINVERSION => sub { | ||||
238 | $_[0]->{plugins}->getPluginVersion( $_[1]->{_DEFAULT} ); | ||||
239 | }, | ||||
240 | 2 | 10µs | 2 | 11µs | # spent 25µs (13+11) within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:240] which was called 2 times, avg 12µs/call:
# 2 times (13µs+11µs) by Foswiki::_expandMacroOnTopicRendering at line 3160, avg 12µs/call # spent 11µs making 2 calls to Foswiki::getPubUrl, avg 6µs/call |
241 | 33 | 145µs | 33 | 408µs | # spent 590µs (182+408) within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:241] which was called 33 times, avg 18µs/call:
# 33 times (182µs+408µs) by Foswiki::_expandMacroOnTopicRendering at line 3160, avg 18µs/call # spent 408µs making 33 calls to Foswiki::getPubUrl, avg 12µs/call |
242 | QUERY => undef, | ||||
243 | QUERYPARAMS => undef, | ||||
244 | 1 | 10µs | 1 | 84µs | # spent 93µs (9+84) within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:244] which was called:
# once (9µs+84µs) by Foswiki::_expandMacroOnTopicRendering at line 3160 # spent 84µs making 1 call to Foswiki::Request::queryString |
245 | RELATIVETOPICPATH => undef, | ||||
246 | REMOTE_ADDR => | ||||
247 | |||||
248 | # DEPRECATED, now implemented using %ENV% | ||||
249 | #move to compatibility plugin in Foswiki 2.0 | ||||
250 | sub { $_[0]->{request}->remoteAddress() || ''; }, | ||||
251 | REMOTE_PORT => | ||||
252 | |||||
253 | # DEPRECATED | ||||
254 | # CGI/1.1 (RFC 3875) doesn't specify REMOTE_PORT, | ||||
255 | # but some webservers implement it. However, since | ||||
256 | # it's not RFC compliant, Foswiki should not rely on | ||||
257 | # it. So we get more portability. | ||||
258 | sub { '' }, | ||||
259 | REMOTE_USER => | ||||
260 | |||||
261 | # DEPRECATED | ||||
262 | sub { $_[0]->{request}->remoteUser() || '' }, | ||||
263 | RENDERZONE => undef, | ||||
264 | REVINFO => undef, | ||||
265 | REVTITLE => undef, | ||||
266 | REVARG => undef, | ||||
267 | 1 | 15µs | 1 | 9µs | # spent 22µs (13+9) within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:267] which was called:
# once (13µs+9µs) by Foswiki::_expandMacroOnTopicRendering at line 3160 # spent 9µs making 1 call to Foswiki::Request::action |
268 | 9 | 61µs | 9 | 87µs | # spent 161µs (74+87) within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:268] which was called 9 times, avg 18µs/call:
# 9 times (74µs+87µs) by Foswiki::_expandMacroOnTopicRendering at line 3160, avg 18µs/call # spent 87µs making 9 calls to Foswiki::getScriptUrl, avg 10µs/call |
269 | SCRIPTURLPATH => | ||||
270 | 16 | 83µs | 16 | 238µs | # spent 342µs (105+238) within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:270] which was called 16 times, avg 21µs/call:
# 16 times (105µs+238µs) by Foswiki::_expandMacroOnTopicRendering at line 3160, avg 21µs/call # spent 238µs making 16 calls to Foswiki::getScriptUrl, avg 15µs/call |
271 | SEARCH => undef, | ||||
272 | SEP => | ||||
273 | |||||
274 | # Shortcut to %TMPL:P{"sep"}% | ||||
275 | sub { $_[0]->templates->expandTemplate('sep') }, | ||||
276 | # spent 79µs (14+65) within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:279] which was called:
# once (14µs+65µs) by Foswiki::_expandMacroOnTopicRendering at line 3160 | ||||
277 | 1 | 9µs | 1 | 65µs | Foswiki::Time::formatTime( time(), $_[1]->{_DEFAULT} || '', # spent 65µs making 1 call to Foswiki::Time::formatTime |
278 | 'servertime' ); | ||||
279 | }, | ||||
280 | SHOWPREFERENCE => undef, | ||||
281 | SPACEDTOPIC => undef, | ||||
282 | SPACEOUT => undef, | ||||
283 | 1 | 15µs | 2 | 61µs | # spent 77µs (16+61) within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:283] which was called:
# once (16µs+61µs) by Foswiki::_expandMacroOnTopicRendering at line 3160 # spent 55µs making 1 call to Foswiki::Templates::tmplP
# spent 6µs making 1 call to Foswiki::templates |
284 | TOPICLIST => undef, | ||||
285 | URLENCODE => undef, | ||||
286 | URLPARAM => undef, | ||||
287 | USERINFO => undef, | ||||
288 | USERNAME => undef, | ||||
289 | VAR => undef, | ||||
290 | WEBLIST => undef, | ||||
291 | WIKINAME => undef, | ||||
292 | WIKIUSERNAME => undef, | ||||
293 | DISPLAYDEPENDENCIES => undef, | ||||
294 | |||||
295 | # Constant tag strings _not_ dependent on config. These get nicely | ||||
296 | # optimised by the compiler. | ||||
297 | ENDSECTION => sub { '' }, | ||||
298 | WIKIVERSION => sub { $VERSION }, | ||||
299 | WIKIRELEASE => sub { $RELEASE }, | ||||
300 | STARTSECTION => sub { '' }, | ||||
301 | STARTINCLUDE => sub { '' }, | ||||
302 | STOPINCLUDE => sub { '' }, | ||||
303 | 1 | 75µs | ); | ||
304 | 1 | 1µs | $contextFreeSyntax{IF} = 1; | ||
305 | |||||
306 | 1 | 2µs | unless ( ( $Foswiki::cfg{DetailedOS} = $^O ) ) { | ||
307 | require Config; | ||||
308 | $Foswiki::cfg{DetailedOS} = $Config::Config{'osname'}; | ||||
309 | } | ||||
310 | 1 | 600ns | $Foswiki::cfg{OS} = 'UNIX'; | ||
311 | 1 | 5µs | if ( $Foswiki::cfg{DetailedOS} =~ /darwin/i ) { # MacOS X | ||
312 | $Foswiki::cfg{OS} = 'UNIX'; | ||||
313 | } | ||||
314 | elsif ( $Foswiki::cfg{DetailedOS} =~ /Win/i ) { | ||||
315 | $Foswiki::cfg{OS} = 'WINDOWS'; | ||||
316 | } | ||||
317 | elsif ( $Foswiki::cfg{DetailedOS} =~ /vms/i ) { | ||||
318 | $Foswiki::cfg{OS} = 'VMS'; | ||||
319 | } | ||||
320 | elsif ( $Foswiki::cfg{DetailedOS} =~ /bsdos/i ) { | ||||
321 | $Foswiki::cfg{OS} = 'UNIX'; | ||||
322 | } | ||||
323 | elsif ( $Foswiki::cfg{DetailedOS} =~ /dos/i ) { | ||||
324 | $Foswiki::cfg{OS} = 'DOS'; | ||||
325 | } | ||||
326 | elsif ( $Foswiki::cfg{DetailedOS} =~ /^MacOS$/i ) { # MacOS 9 or earlier | ||||
327 | $Foswiki::cfg{OS} = 'MACINTOSH'; | ||||
328 | } | ||||
329 | elsif ( $Foswiki::cfg{DetailedOS} =~ /os2/i ) { | ||||
330 | $Foswiki::cfg{OS} = 'OS2'; | ||||
331 | } | ||||
332 | |||||
333 | # readConfig is defined in Foswiki::Configure::Load to allow overriding it | ||||
334 | 1 | 3µs | 1 | 13.2ms | if ( Foswiki::Configure::Load::readConfig() ) { # spent 13.2ms making 1 call to Foswiki::Configure::Load::readConfig |
335 | $Foswiki::cfg{isVALID} = 1; | ||||
336 | } | ||||
337 | |||||
338 | 1 | 400ns | if ( $Foswiki::cfg{WarningsAreErrors} ) { | ||
339 | |||||
340 | # Note: Warnings are always errors if ASSERTs are enabled | ||||
341 | $SIG{'__WARN__'} = sub { die @_ }; | ||||
342 | } | ||||
343 | |||||
344 | 1 | 600ns | if ( $Foswiki::cfg{UseLocale} ) { | ||
345 | 1 | 600ns | require locale; | ||
346 | 1 | 5µs | 1 | 6µs | import locale(); # spent 6µs making 1 call to locale::import |
347 | } | ||||
348 | |||||
349 | # If not set, default to strikeone validation | ||||
350 | 1 | 800ns | $Foswiki::cfg{Validation}{Method} ||= 'strikeone'; | ||
351 | 1 | 500ns | $Foswiki::cfg{Validation}{ValidForTime} = $Foswiki::cfg{LeaseLength} | ||
352 | unless defined $Foswiki::cfg{Validation}{ValidForTime}; | ||||
353 | 1 | 900ns | $Foswiki::cfg{Validation}{MaxKeys} = 1000 | ||
354 | unless defined $Foswiki::cfg{Validation}{MaxKeys}; | ||||
355 | |||||
356 | # Constant tags dependent on the config | ||||
357 | $macros{ALLOWLOGINNAME} = | ||||
358 | 1 | 3µs | sub { $Foswiki::cfg{Register}{AllowLoginName} || 0 }; | ||
359 | 1 | 2µs | $macros{AUTHREALM} = sub { $Foswiki::cfg{AuthRealm} }; | ||
360 | 1 | 1µs | $macros{DEFAULTURLHOST} = sub { $Foswiki::cfg{DefaultUrlHost} }; | ||
361 | 5 | 27µs | # spent 26µs within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:361] which was called 4 times, avg 6µs/call:
# 4 times (26µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3160, avg 6µs/call | ||
362 | 1 | 1µs | $macros{LOCALSITEPREFS} = sub { $Foswiki::cfg{LocalSitePreferences} }; | ||
363 | $macros{NOFOLLOW} = | ||||
364 | 1 | 2µs | sub { $Foswiki::cfg{NoFollow} ? 'rel=' . $Foswiki::cfg{NoFollow} : '' }; | ||
365 | 1 | 1µs | $macros{NOTIFYTOPIC} = sub { $Foswiki::cfg{NotifyTopicName} }; | ||
366 | 2 | 17µs | # spent 3µs within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:366] which was called:
# once (3µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3160 | ||
367 | 1 | 2µs | $macros{STATISTICSTOPIC} = sub { $Foswiki::cfg{Stats}{TopicName} }; | ||
368 | 42 | 157µs | # spent 113µs within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:368] which was called 41 times, avg 3µs/call:
# 41 times (113µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3160, avg 3µs/call | ||
369 | 1 | 1µs | $macros{TRASHWEB} = sub { $Foswiki::cfg{TrashWebName} }; | ||
370 | 1 | 1µs | $macros{SANDBOXWEB} = sub { $Foswiki::cfg{SandboxWebName} }; | ||
371 | 1 | 1µs | $macros{WIKIADMINLOGIN} = sub { $Foswiki::cfg{AdminUserLogin} }; | ||
372 | 15 | 48µs | # spent 45µs within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:372] which was called 14 times, avg 3µs/call:
# 14 times (45µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3160, avg 3µs/call | ||
373 | 1 | 1µs | $macros{WEBPREFSTOPIC} = sub { $Foswiki::cfg{WebPrefsTopicName} }; | ||
374 | 1 | 2µs | $macros{WIKIPREFSTOPIC} = sub { $Foswiki::cfg{SitePrefsTopicName} }; | ||
375 | 1 | 1µs | $macros{WIKIUSERSTOPIC} = sub { $Foswiki::cfg{UsersTopicName} }; | ||
376 | 1 | 1µs | $macros{WIKIWEBMASTER} = sub { $Foswiki::cfg{WebMasterEmail} }; | ||
377 | 1 | 1µs | $macros{WIKIWEBMASTERNAME} = sub { $Foswiki::cfg{WebMasterName} }; | ||
378 | |||||
379 | # locale setup | ||||
380 | # | ||||
381 | # | ||||
382 | # Note that 'use locale' must be done in BEGIN block for regexes and | ||||
383 | # sorting to work properly, although regexes can still work without | ||||
384 | # this in 'non-locale regexes' mode. | ||||
385 | |||||
386 | 1 | 700ns | if ( $Foswiki::cfg{UseLocale} ) { | ||
387 | |||||
388 | # Set environment variables for grep | ||||
389 | 1 | 5µs | $ENV{LC_CTYPE} = $Foswiki::cfg{Site}{Locale}; | ||
390 | |||||
391 | # Load POSIX for I18N support. | ||||
392 | 1 | 109µs | require POSIX; | ||
393 | 1 | 4µs | 1 | 1.14ms | import POSIX qw( locale_h LC_CTYPE LC_COLLATE ); # spent 1.14ms making 1 call to POSIX::import |
394 | |||||
395 | # SMELL: mod_perl compatibility note: If Foswiki is running under Apache, | ||||
396 | # won't this play with the Apache process's locale settings too? | ||||
397 | # What effects would this have? | ||||
398 | 1 | 48µs | 2 | 35µs | setlocale( &LC_CTYPE, $Foswiki::cfg{Site}{Locale} ); # spent 33µs making 1 call to POSIX::setlocale
# spent 1µs making 1 call to Foswiki::__ANON__ |
399 | 1 | 16µs | 2 | 9µs | setlocale( &LC_COLLATE, $Foswiki::cfg{Site}{Locale} ); # spent 8µs making 1 call to POSIX::setlocale
# spent 900ns making 1 call to Foswiki::__ANON__ |
400 | } | ||||
401 | |||||
402 | # spent 8µs within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:404] which was called:
# once (8µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3160 | ||||
403 | 1 | 11µs | $Foswiki::cfg{Site}{CharSet} || CGI::charset(); | ||
404 | 1 | 4µs | }; | ||
405 | |||||
406 | # spent 37µs within Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:417] which was called 2 times, avg 19µs/call:
# 2 times (37µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3160, avg 19µs/call | ||||
407 | 2 | 2µs | my $lang = 'en'; # the default | ||
408 | 2 | 24µs | if ( $Foswiki::cfg{UseLocale} | ||
409 | && $Foswiki::cfg{Site}{Locale} =~ m/^([a-z]+)(?:_([a-z]+))?/i ) | ||||
410 | { | ||||
411 | |||||
412 | # Locale identifiers use _ as the separator in the language, but a minus sign is required | ||||
413 | # for HTML (see http://www.ietf.org/rfc/rfc1766.txt) | ||||
414 | $lang = $1 . ( $2 ? "-$2" : '' ); | ||||
415 | } | ||||
416 | 2 | 16µs | return $lang; | ||
417 | 1 | 6µs | }; | ||
418 | |||||
419 | # Set up pre-compiled regexes for use in rendering. All regexes with | ||||
420 | # unchanging variables in match should use the '/o' option. | ||||
421 | # In the regex hash, all precompiled REs have "Regex" at the | ||||
422 | # end of the name. Anything else is a string, either intended | ||||
423 | # for use as a character class, or as a sub-expression in | ||||
424 | # another compiled RE. | ||||
425 | |||||
426 | # Build up character class components for use in regexes. | ||||
427 | # Depends on locale mode and Perl version, and finally on | ||||
428 | # whether locale-based regexes are turned off. | ||||
429 | 1 | 3µs | if ( not $Foswiki::cfg{UseLocale} | ||
430 | or $] < 5.006 | ||||
431 | or not $Foswiki::cfg{Site}{LocaleRegexes} ) | ||||
432 | { | ||||
433 | |||||
434 | # No locales needed/working, or Perl 5.005, so just use | ||||
435 | # any additional national characters defined in LocalSite.cfg | ||||
436 | $regex{upperAlpha} = 'A-Z' . $Foswiki::cfg{UpperNational}; | ||||
437 | $regex{lowerAlpha} = 'a-z' . $Foswiki::cfg{LowerNational}; | ||||
438 | $regex{numeric} = '\d'; | ||||
439 | $regex{mixedAlpha} = $regex{upperAlpha} . $regex{lowerAlpha}; | ||||
440 | } | ||||
441 | else { | ||||
442 | |||||
443 | # Perl 5.006 or higher with working locales | ||||
444 | 1 | 1µs | $regex{upperAlpha} = '[:upper:]'; | ||
445 | 1 | 500ns | $regex{lowerAlpha} = '[:lower:]'; | ||
446 | 1 | 500ns | $regex{numeric} = '[:digit:]'; | ||
447 | 1 | 600ns | $regex{mixedAlpha} = '[:alpha:]'; | ||
448 | } | ||||
449 | 1 | 2µs | $regex{mixedAlphaNum} = $regex{mixedAlpha} . $regex{numeric}; | ||
450 | 1 | 900ns | $regex{lowerAlphaNum} = $regex{lowerAlpha} . $regex{numeric}; | ||
451 | 1 | 900ns | $regex{upperAlphaNum} = $regex{upperAlpha} . $regex{numeric}; | ||
452 | |||||
453 | # Compile regexes for efficiency and ease of use | ||||
454 | # Note: qr// locks in regex modes (i.e. '-xism' here) - see Friedl | ||||
455 | # book at http://regex.info/. | ||||
456 | |||||
457 | 1 | 1µs | $regex{linkProtocolPattern} = $Foswiki::cfg{LinkProtocolPattern}; | ||
458 | |||||
459 | # Header patterns based on '+++'. The '###' are reserved for numbered | ||||
460 | # headers | ||||
461 | # '---++ Header', '---## Header' | ||||
462 | 1 | 3µs | $regex{headerPatternDa} = qr/^---+(\++|\#+)(.*)$/m; | ||
463 | |||||
464 | # '<h6>Header</h6> | ||||
465 | 1 | 1µs | $regex{headerPatternHt} = qr/^<h([1-6])>(.+?)<\/h\1>/mi; | ||
466 | |||||
467 | # '---++!! Header' or '---++ Header %NOTOC% ^top' | ||||
468 | 1 | 500ns | $regex{headerPatternNoTOC} = '(\!\!+|%NOTOC%)'; | ||
469 | |||||
470 | # Foswiki concept regexes | ||||
471 | 1 | 30µs | $regex{wikiWordRegex} = qr( | ||
472 | [$regex{upperAlpha}]+ | ||||
473 | [$regex{lowerAlphaNum}]+ | ||||
474 | [$regex{upperAlpha}]+ | ||||
475 | [$regex{mixedAlphaNum}]* | ||||
476 | )xo; | ||||
477 | 1 | 12µs | $regex{webNameBaseRegex} = | ||
478 | qr/[$regex{upperAlpha}]+[$regex{mixedAlphaNum}_]*/o; | ||||
479 | 1 | 600ns | if ( $Foswiki::cfg{EnableHierarchicalWebs} ) { | ||
480 | 1 | 28µs | $regex{webNameRegex} = qr( | ||
481 | $regex{webNameBaseRegex} | ||||
482 | (?:(?:[\.\/]$regex{webNameBaseRegex})+)* | ||||
483 | )xo; | ||||
484 | } | ||||
485 | else { | ||||
486 | $regex{webNameRegex} = $regex{webNameBaseRegex}; | ||||
487 | } | ||||
488 | 1 | 11µs | $regex{defaultWebNameRegex} = qr/_[$regex{mixedAlphaNum}_]+/o; | ||
489 | 1 | 10µs | $regex{anchorRegex} = qr/\#[$regex{mixedAlphaNum}:._]+/o; | ||
490 | 1 | 10µs | $regex{abbrevRegex} = qr/[$regex{upperAlpha}]{3,}s?\b/o; | ||
491 | |||||
492 | 1 | 29µs | $regex{topicNameRegex} = | ||
493 | qr/(?:(?:$regex{wikiWordRegex})|(?:$regex{abbrevRegex}))/o; | ||||
494 | |||||
495 | # Email regex, e.g. for WebNotify processing and email matching | ||||
496 | # during rendering. | ||||
497 | |||||
498 | 1 | 9µs | my $emailAtom = qr([A-Z0-9\Q!#\$%&'*+-/=?^_`{|}~\E])i; # Per RFC 5322 ] | ||
499 | |||||
500 | # Valid TLD's at http://data.iana.org/TLD/tlds-alpha-by-domain.txt | ||||
501 | # Version 2012022300, Last Updated Thu Feb 23 15:07:02 2012 UTC | ||||
502 | 1 | 1µs | my $validTLD = $Foswiki::cfg{Email}{ValidTLD}; | ||
503 | |||||
504 | 2 | 18µs | unless ( eval { qr/$validTLD/ } ) { | ||
505 | $validTLD = | ||||
506 | qr(AERO|ARPA|ASIA|BIZ|CAT|COM|COOP|EDU|GOV|INFO|INT|JOBS|MIL|MOBI|MUSEUM|NAME|NET|ORG|PRO|TEL|TRAVEL|XXX)i; | ||||
507 | |||||
508 | # Too early to log, should do something here other than die (which prevents fixing) | ||||
509 | # warn is trapped and turned into a die... | ||||
510 | #warn( "{Email}{ValidTLD} does not compile, using default" ); | ||||
511 | } | ||||
512 | |||||
513 | 1 | 59µs | $regex{emailAddrRegex} = qr( | ||
514 | (?: # LEFT Side of Email address | ||||
515 | (?:$emailAtom+ # Valid characters left side of email address | ||||
516 | (?:\.$emailAtom+)* # And 0 or more dotted atoms | ||||
517 | ) | ||||
518 | | | ||||
519 | (?:"[\x21\x23-\x5B\x5D-\x7E\s]+?") # or a quoted string per RFC 5322 | ||||
520 | ) | ||||
521 | @ | ||||
522 | (?: # RIGHT side of Email address | ||||
523 | (?: # FQDN | ||||
524 | [a-z0-9-]+ # hostname part | ||||
525 | (?:\.[a-z0-9-]+)* # 0 or more alphanumeric domains following a dot. | ||||
526 | \.(?: # TLD | ||||
527 | (?:[a-z]{2,2}) # 2 character TLD | ||||
528 | | | ||||
529 | $validTLD # TLD's longer than 2 characters | ||||
530 | ) | ||||
531 | ) | ||||
532 | | | ||||
533 | (?:\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\]) # dotted triplets IP Address | ||||
534 | ) | ||||
535 | )oxi; | ||||
536 | |||||
537 | # Item11185: This is how things were before we began Operation Unicode: | ||||
538 | # | ||||
539 | # $regex{filenameInvalidCharRegex} = qr/[^$regex{mixedAlphaNum}\. _-]/o; | ||||
540 | # | ||||
541 | # It was only used in Foswiki::Sandbox::sanitizeAttachmentName(), which now | ||||
542 | # uses $Foswiki::cfg{NameFilter} instead. | ||||
543 | # See RobustnessTests::test_sanitizeAttachmentName | ||||
544 | # | ||||
545 | # Actually, this is used in GenPDFPrincePlugin; let's copy NameFilter | ||||
546 | 1 | 800ns | $regex{filenameInvalidCharRegex} = $Foswiki::cfg{NameFilter}; | ||
547 | |||||
548 | # Multi-character alpha-based regexes | ||||
549 | 1 | 12µs | $regex{mixedAlphaNumRegex} = qr/[$regex{mixedAlphaNum}]*/o; | ||
550 | |||||
551 | # %TAG% name | ||||
552 | 1 | 2µs | $regex{tagNameRegex} = | ||
553 | '[' . $regex{mixedAlpha} . '][' . $regex{mixedAlphaNum} . '_:]*'; | ||||
554 | |||||
555 | # Set statement in a topic | ||||
556 | 1 | 500ns | $regex{bulletRegex} = '^(?:\t| )+\*'; | ||
557 | 1 | 1µs | $regex{setRegex} = $regex{bulletRegex} . '\s+(Set|Local)\s+'; | ||
558 | 1 | 1µs | $regex{setVarRegex} = | ||
559 | $regex{setRegex} . '(' . $regex{tagNameRegex} . ')\s*=\s*(.*)$'; | ||||
560 | |||||
561 | # Character encoding regexes | ||||
562 | |||||
563 | # 7-bit ASCII only | ||||
564 | 1 | 1µs | $regex{validAsciiStringRegex} = qr/^[\x00-\x7F]+$/o; | ||
565 | |||||
566 | # Regex to match only a valid UTF-8 character, taking care to avoid | ||||
567 | # security holes due to overlong encodings by excluding the relevant | ||||
568 | # gaps in UTF-8 encoding space - see 'perldoc perlunicode', Unicode | ||||
569 | # Encodings section. Tested against Markus Kuhn's UTF-8 test file | ||||
570 | # at http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt. | ||||
571 | 1 | 1µs | $regex{validUtf8CharRegex} = qr{ | ||
572 | # Single byte - ASCII | ||||
573 | [\x00-\x7F] | ||||
574 | | | ||||
575 | |||||
576 | # 2 bytes | ||||
577 | [\xC2-\xDF][\x80-\xBF] | ||||
578 | | | ||||
579 | |||||
580 | # 3 bytes | ||||
581 | |||||
582 | # Avoid illegal codepoints - negative lookahead | ||||
583 | (?!\xEF\xBF[\xBE\xBF]) | ||||
584 | |||||
585 | # Match valid codepoints | ||||
586 | (?: | ||||
587 | ([\xE0][\xA0-\xBF])| | ||||
588 | ([\xE1-\xEC\xEE-\xEF][\x80-\xBF])| | ||||
589 | ([\xED][\x80-\x9F]) | ||||
590 | ) | ||||
591 | [\x80-\xBF] | ||||
592 | | | ||||
593 | |||||
594 | # 4 bytes | ||||
595 | (?: | ||||
596 | ([\xF0][\x90-\xBF])| | ||||
597 | ([\xF1-\xF3][\x80-\xBF])| | ||||
598 | ([\xF4][\x80-\x8F]) | ||||
599 | ) | ||||
600 | [\x80-\xBF][\x80-\xBF] | ||||
601 | }xo; | ||||
602 | |||||
603 | 1 | 38µs | $regex{validUtf8StringRegex} = qr/^(?:$regex{validUtf8CharRegex})+$/o; | ||
604 | |||||
605 | # Check for unsafe search regex mode (affects filtering in) - default | ||||
606 | # to safe mode | ||||
607 | 1 | 500ns | $Foswiki::cfg{ForceUnsafeRegexes} = 0 | ||
608 | unless defined $Foswiki::cfg{ForceUnsafeRegexes}; | ||||
609 | |||||
610 | # initialize lib directory early because of later 'cd's | ||||
611 | 1 | 2µs | 1 | 15µs | _getLibDir(); # spent 15µs making 1 call to Foswiki::_getLibDir |
612 | |||||
613 | # initialize the runtime engine | ||||
614 | 1 | 500ns | if ( !defined $Foswiki::cfg{Engine} ) { | ||
615 | |||||
616 | # Caller did not define an engine; try and work it out (mainly for | ||||
617 | # the benefit of pre-1.0 CGI scripts) | ||||
618 | $Foswiki::cfg{Engine} = 'Foswiki::Engine::Legacy'; | ||||
619 | } | ||||
620 | 1 | 46µs | $engine = eval qq(use $Foswiki::cfg{Engine}; $Foswiki::cfg{Engine}->new); # spent 406µs executing statements in string eval # includes 1.10ms spent executing 1 call to 1 sub defined therein. | ||
621 | 1 | 5µs | die $@ if $@; | ||
622 | |||||
623 | #Monitor::MARK('End of BEGIN block in Foswiki.pm'); | ||||
624 | 1 | 25µs | 1 | 35.5ms | } # spent 35.5ms making 1 call to Foswiki::BEGIN@137 |
625 | |||||
626 | # Components that all requests need | ||||
627 | 2 | 23µs | 1 | 5µs | # spent 5µs within Foswiki::BEGIN@627 which was called:
# once (5µs+0s) by main::BEGIN@22 at line 627 # spent 5µs making 1 call to Foswiki::BEGIN@627 |
628 | 2 | 183µs | 1 | 3µs | # spent 3µs within Foswiki::BEGIN@628 which was called:
# once (3µs+0s) by main::BEGIN@22 at line 628 # spent 3µs making 1 call to Foswiki::BEGIN@628 |
629 | 2 | 98µs | 1 | 308µs | # spent 308µs (236+73) within Foswiki::BEGIN@629 which was called:
# once (236µs+73µs) by main::BEGIN@22 at line 629 # spent 308µs making 1 call to Foswiki::BEGIN@629 |
630 | 2 | 154µs | 1 | 14.7ms | # spent 14.7ms (13.2+1.44) within Foswiki::BEGIN@630 which was called:
# once (13.2ms+1.44ms) by main::BEGIN@22 at line 630 # spent 14.7ms making 1 call to Foswiki::BEGIN@630 |
631 | 2 | 129µs | 1 | 14.6ms | # spent 14.6ms (2.45+12.2) within Foswiki::BEGIN@631 which was called:
# once (2.45ms+12.2ms) by main::BEGIN@22 at line 631 # spent 14.6ms making 1 call to Foswiki::BEGIN@631 |
632 | 2 | 113µs | 1 | 2.33ms | # spent 2.33ms (2.25+73µs) within Foswiki::BEGIN@632 which was called:
# once (2.25ms+73µs) by main::BEGIN@22 at line 632 # spent 2.33ms making 1 call to Foswiki::BEGIN@632 |
633 | 2 | 96µs | 1 | 4.42ms | # spent 4.42ms (1.81+2.61) within Foswiki::BEGIN@633 which was called:
# once (1.81ms+2.61ms) by main::BEGIN@22 at line 633 # spent 4.42ms making 1 call to Foswiki::BEGIN@633 |
634 | 2 | 105µs | 1 | 5.61ms | # spent 5.61ms (1.77+3.84) within Foswiki::BEGIN@634 which was called:
# once (1.77ms+3.84ms) by main::BEGIN@22 at line 634 # spent 5.61ms making 1 call to Foswiki::BEGIN@634 |
635 | 2 | 112µs | 1 | 634µs | # spent 634µs (442+192) within Foswiki::BEGIN@635 which was called:
# once (442µs+192µs) by main::BEGIN@22 at line 635 # spent 634µs making 1 call to Foswiki::BEGIN@635 |
636 | 2 | 9.72ms | 1 | 8.05ms | # spent 8.05ms (2.68+5.37) within Foswiki::BEGIN@636 which was called:
# once (2.68ms+5.37ms) by main::BEGIN@22 at line 636 # spent 8.05ms making 1 call to Foswiki::BEGIN@636 |
637 | |||||
638 | sub UTF82SiteCharSet { | ||||
639 | 2 | 2µs | my ( $this, $text ) = @_; | ||
640 | |||||
641 | 2 | 2µs | return $text unless ( defined $Foswiki::cfg{Site}{CharSet} ); | ||
642 | |||||
643 | # Detect character encoding of the full topic name from URL | ||||
644 | 2 | 13µs | return if ( $text =~ $regex{validAsciiStringRegex} ); | ||
645 | |||||
646 | # SMELL: all this regex stuff should go away. | ||||
647 | # If not UTF-8 - assume in site character set, no conversion required | ||||
648 | if ( $^O eq 'darwin' ) { | ||||
649 | |||||
650 | #this is a gross over-generalisation - as not all darwins are apple's | ||||
651 | # and not all darwins use apple's perl | ||||
652 | my $trial = $text; | ||||
653 | $trial =~ s/$regex{validUtf8CharRegex}//g; | ||||
654 | return unless ( length($trial) == 0 ); | ||||
655 | } | ||||
656 | else { | ||||
657 | |||||
658 | #SMELL: this seg faults on OSX leopard. (and possibly others) | ||||
659 | return unless ( $text =~ $regex{validUtf8StringRegex} ); | ||||
660 | } | ||||
661 | |||||
662 | # If site charset is already UTF-8, there is no need to convert anything: | ||||
663 | if ( $Foswiki::cfg{Site}{CharSet} =~ /^utf-?8$/i ) { | ||||
664 | |||||
665 | # warn if using Perl older than 5.8 | ||||
666 | if ( $] < 5.008 ) { | ||||
667 | $this->logger->log( 'warning', | ||||
668 | 'UTF-8 not remotely supported on Perl ' | ||||
669 | . $] | ||||
670 | . ' - use Perl 5.8 or higher..' ); | ||||
671 | } | ||||
672 | |||||
673 | # We still don't have Codev.UnicodeSupport | ||||
674 | $this->logger->log( 'warning', | ||||
675 | 'UTF-8 not yet supported as site charset -' | ||||
676 | . 'Foswiki is likely to have problems' ); | ||||
677 | return $text; | ||||
678 | } | ||||
679 | |||||
680 | # Convert into ISO-8859-1 if it is the site charset. This conversion | ||||
681 | # is *not valid for ISO-8859-15*. | ||||
682 | if ( $Foswiki::cfg{Site}{CharSet} =~ /^iso-?8859-?1$/i ) { | ||||
683 | |||||
684 | # ISO-8859-1 maps onto first 256 codepoints of Unicode | ||||
685 | # (conversion from 'perldoc perluniintro') | ||||
686 | $text =~ s/ ([\xC2\xC3]) ([\x80-\xBF]) / | ||||
687 | chr( ord($1) << 6 & 0xC0 | ord($2) & 0x3F ) | ||||
688 | /egx; | ||||
689 | } | ||||
690 | else { | ||||
691 | |||||
692 | # Convert from UTF-8 into some other site charset | ||||
693 | if ( $] >= 5.008 ) { | ||||
694 | require Encode; | ||||
695 | import Encode qw(:fallbacks); | ||||
696 | |||||
697 | # Map $Foswiki::cfg{Site}{CharSet} into real encoding name | ||||
698 | my $charEncoding = | ||||
699 | Encode::resolve_alias( $Foswiki::cfg{Site}{CharSet} ); | ||||
700 | if ( not $charEncoding ) { | ||||
701 | $this->logger->log( 'warning', | ||||
702 | 'Conversion to "' | ||||
703 | . $Foswiki::cfg{Site}{CharSet} | ||||
704 | . '" not supported, or name not recognised - check ' | ||||
705 | . '"perldoc Encode::Supported"' ); | ||||
706 | } | ||||
707 | else { | ||||
708 | |||||
709 | # Convert text using Encode: | ||||
710 | # - first, convert from UTF8 bytes into internal | ||||
711 | # (UTF-8) characters | ||||
712 | $text = Encode::decode( 'utf8', $text ); | ||||
713 | |||||
714 | # - then convert into site charset from internal UTF-8, | ||||
715 | # inserting \x{NNNN} for characters that can't be converted | ||||
716 | $text = Encode::encode( $charEncoding, $text, &FB_PERLQQ() ); | ||||
717 | } | ||||
718 | } | ||||
719 | else { | ||||
720 | require Unicode::MapUTF8; # Pre-5.8 Perl versions | ||||
721 | my $charEncoding = $Foswiki::cfg{Site}{CharSet}; | ||||
722 | if ( not Unicode::MapUTF8::utf8_supported_charset($charEncoding) ) { | ||||
723 | $this->logger->log( 'warning', | ||||
724 | 'Conversion to "' | ||||
725 | . $Foswiki::cfg{Site}{CharSet} | ||||
726 | . '" not supported, or name not recognised - check ' | ||||
727 | . '"perldoc Unicode::MapUTF8"' ); | ||||
728 | } | ||||
729 | else { | ||||
730 | |||||
731 | # Convert text | ||||
732 | $text = Unicode::MapUTF8::from_utf8( | ||||
733 | { | ||||
734 | -string => $text, | ||||
735 | -charset => $charEncoding | ||||
736 | } | ||||
737 | ); | ||||
738 | |||||
739 | # FIXME: Check for failed conversion? | ||||
740 | } | ||||
741 | } | ||||
742 | } | ||||
743 | return $text; | ||||
744 | } | ||||
745 | |||||
746 | =begin TML | ||||
747 | |||||
748 | ---++ ObjectMethod writeCompletePage( $text, $pageType, $contentType ) | ||||
749 | |||||
750 | Write a complete HTML page with basic header to the browser. | ||||
751 | * =$text= is the text of the page script (<html> to </html> if it's HTML) | ||||
752 | * =$pageType= - May be "edit", which will cause headers to be generated that force | ||||
753 | caching for 24 hours, to prevent Codev.BackFromPreviewLosesText bug, which caused | ||||
754 | data loss with IE5 and IE6. | ||||
755 | * =$contentType= - page content type | text/html | ||||
756 | |||||
757 | This method removes noautolink and nop tags before outputting the page unless | ||||
758 | $contentType is text/plain. | ||||
759 | |||||
760 | =cut | ||||
761 | |||||
762 | # spent 27.8ms (6.47+21.4) within Foswiki::writeCompletePage which was called:
# once (6.47ms+21.4ms) by Foswiki::UI::View::view at line 405 of /var/www/foswiki11/lib/Foswiki/UI/View.pm | ||||
763 | 1 | 18µs | my ( $this, $text, $pageType, $contentType ) = @_; | ||
764 | 1 | 500ns | $contentType ||= 'text/html'; | ||
765 | |||||
766 | 1 | 3µs | 1 | 42µs | my $cgis = $this->getCGISession(); # spent 42µs making 1 call to Foswiki::getCGISession |
767 | 1 | 400ns | if ( $cgis | ||
768 | && $contentType eq 'text/html' | ||||
769 | && $Foswiki::cfg{Validation}{Method} ne 'none' ) | ||||
770 | { | ||||
771 | |||||
772 | # Don't expire the validation key through login, or when | ||||
773 | # endpoint is an error. | ||||
774 | Foswiki::Validation::expireValidationKeys($cgis) | ||||
775 | unless ( $this->{request}->action() eq 'login' | ||||
776 | or ( $ENV{REDIRECT_STATUS} || 0 ) >= 400 ); | ||||
777 | |||||
778 | my $usingStrikeOne = 0; | ||||
779 | if ( | ||||
780 | $Foswiki::cfg{Validation}{Method} eq 'strikeone' | ||||
781 | |||||
782 | # Add the onsubmit handler to the form | ||||
783 | && $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/ | ||||
784 | Foswiki::Validation::addOnSubmit($1)/gei | ||||
785 | ) | ||||
786 | { | ||||
787 | |||||
788 | # At least one form has been touched; add the validation | ||||
789 | # cookie | ||||
790 | my $valCookie = Foswiki::Validation::getCookie($cgis); | ||||
791 | $valCookie->secure( $this->{request}->secure ); | ||||
792 | $this->{response} | ||||
793 | ->cookies( [ $this->{response}->cookies, $valCookie ] ); | ||||
794 | |||||
795 | # Add the JS module to the page. Note that this is *not* | ||||
796 | # incorporated into the foswikilib.js because that module | ||||
797 | # is conditionally loaded under the control of the | ||||
798 | # templates, and we have to be *sure* it gets loaded. | ||||
799 | my $src = $this->{prefs}->getPreference('FWSRC') || ''; | ||||
800 | $this->addToZone( 'script', 'JavascriptFiles/strikeone', <<JS ); | ||||
801 | <script type="text/javascript" src="$Foswiki::cfg{PubUrlPath}/$Foswiki::cfg{SystemWebName}/JavascriptFiles/strikeone$src.js"></script> | ||||
802 | JS | ||||
803 | $usingStrikeOne = 1; | ||||
804 | } | ||||
805 | |||||
806 | # Inject validation key in HTML forms | ||||
807 | my $context = | ||||
808 | $this->{request}->url( -full => 1, -path => 1, -query => 1 ) . time(); | ||||
809 | $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/ | ||||
810 | $1 . Foswiki::Validation::addValidationKey( | ||||
811 | $cgis, $context, $usingStrikeOne )/gei; | ||||
812 | } | ||||
813 | |||||
814 | 1 | 4µs | 1 | 21.0ms | if ( $contentType ne 'text/plain' ) { # spent 21.0ms making 1 call to Foswiki::_renderZones |
815 | |||||
816 | $text = $this->_renderZones($text); | ||||
817 | } | ||||
818 | |||||
819 | # SMELL: can't compute; faking content-type for backwards compatibility; | ||||
820 | # any other information might become bogus later anyway | ||||
821 | # Validate format of content-type (defined in rfc2616) | ||||
822 | 1 | 4µs | my $tch = qr/[^\[\]()<>@,;:\\"\/?={}\s]/o; | ||
823 | 1 | 36µs | if ( $contentType =~ /($tch+\/$tch+(\s*;\s*$tch+=($tch+|"[^"]*"))*)$/oi ) { | ||
824 | $contentType = $1; | ||||
825 | } | ||||
826 | else { | ||||
827 | $contentType = "text/plain;contenttype=invalid"; | ||||
828 | } | ||||
829 | 1 | 3µs | my $hdr = "Content-type: " . $1 . "\r\n"; | ||
830 | |||||
831 | # Call final handler | ||||
832 | 1 | 4µs | 1 | 6µs | $this->{plugins}->dispatch( 'completePageHandler', $text, $hdr ); # spent 6µs making 1 call to Foswiki::Plugins::dispatch |
833 | |||||
834 | # cache final page, but only view | ||||
835 | 1 | 200ns | my $cachedPage; | ||
836 | 1 | 1µs | if ( $contentType ne 'text/plain' ) { | ||
837 | 1 | 2µs | if ( $Foswiki::cfg{Cache}{Enabled} | ||
838 | && ( $this->inContext('view') || $this->inContext('rest') ) ) | ||||
839 | { | ||||
840 | $cachedPage = $this->{cache}->cachePage( $contentType, $text ); | ||||
841 | $this->{cache}->renderDirtyAreas( \$text ) | ||||
842 | if $cachedPage->{isDirty}; | ||||
843 | } | ||||
844 | else { | ||||
845 | |||||
846 | # remove <dirtyarea> tags | ||||
847 | 1 | 25µs | $text =~ s/<\/?dirtyarea[^>]*>//go; | ||
848 | } | ||||
849 | |||||
850 | # Remove <nop> and <noautolink> tags | ||||
851 | 1 | 6.33ms | $text =~ s/([\t ]?)[ \t]*<\/?(nop|noautolink)\/?>/$1/gis; | ||
852 | |||||
853 | # Check that the templates specified clean HTML | ||||
854 | 1 | 2µs | 1 | 2µs | if (DEBUG) { # spent 2µs making 1 call to Assert::ASSERTS_OFF |
855 | |||||
856 | # When tracing is enabled in Foswiki::Templates, then there will | ||||
857 | # always be a <!--bodyend--> after </html>. So we need to disable | ||||
858 | # this check. | ||||
859 | require Foswiki::Templates; | ||||
860 | if ( !Foswiki::Templates->TRACE | ||||
861 | && $contentType =~ m#text/html# | ||||
862 | && $text =~ m#</html>(.*?\S.*)$#s ) | ||||
863 | { | ||||
864 | ASSERT( 0, <<BOGUS ); | ||||
865 | Junk after </html>: $1. Templates may be bogus | ||||
866 | - Check for excess blank lines at ends of .tmpl files | ||||
867 | - or newlines after %TMPL:INCLUDE | ||||
868 | - You can enable TRACE in Foswiki::Templates to help debug | ||||
869 | BOGUS | ||||
870 | } | ||||
871 | } | ||||
872 | } | ||||
873 | |||||
874 | 1 | 4µs | 1 | 225µs | $this->generateHTTPHeaders( $pageType, $contentType, $text, $cachedPage ); # spent 225µs making 1 call to Foswiki::generateHTTPHeaders |
875 | |||||
876 | # SMELL: null operation. the http headers are written out | ||||
877 | # during Foswiki::Engine::finalize | ||||
878 | # $hdr = $this->{response}->printHeaders; | ||||
879 | |||||
880 | 1 | 11µs | 1 | 90µs | $this->{response}->print($text); # spent 90µs making 1 call to Foswiki::Response::print |
881 | } | ||||
882 | |||||
883 | =begin TML | ||||
884 | |||||
885 | ---++ ObjectMethod generateHTTPHeaders( $pageType, $contentType, $text, $cachedPage ) | ||||
886 | |||||
887 | All parameters are optional. | ||||
888 | |||||
889 | * =$pageType= - May be "edit", which will cause headers to be generated that force caching for 24 hours, to prevent Codev.BackFromPreviewLosesText bug, which caused data loss with IE5 and IE6. | ||||
890 | * =$contentType= - page content type | text/html | ||||
891 | * =$text= - page content | ||||
892 | * =$cachedPage= - a pointer to the page container as fetched from the page cache | ||||
893 | |||||
894 | =cut | ||||
895 | |||||
896 | # spent 225µs (77+148) within Foswiki::generateHTTPHeaders which was called:
# once (77µs+148µs) by Foswiki::writeCompletePage at line 874 | ||||
897 | 1 | 19µs | my ( $this, $pageType, $contentType, $text, $cachedPage ) = @_; | ||
898 | |||||
899 | 1 | 1µs | my $hopts = {}; | ||
900 | |||||
901 | # Handle Edit pages - future versions will extend to caching | ||||
902 | # of other types of page, with expiry time driven by page type. | ||||
903 | 1 | 1µs | if ( $pageType && $pageType eq 'edit' ) { | ||
904 | |||||
905 | # Get time now in HTTP header format | ||||
906 | my $lastModifiedString = | ||||
907 | Foswiki::Time::formatTime( time, '$http', 'gmtime' ); | ||||
908 | |||||
909 | # Expiry time is set high to avoid any data loss. Each instance of | ||||
910 | # Edit page has a unique URL with time-string suffix (fix for | ||||
911 | # RefreshEditPage), so this long expiry time simply means that the | ||||
912 | # browser Back button always works. The next Edit on this page | ||||
913 | # will use another URL and therefore won't use any cached | ||||
914 | # version of this Edit page. | ||||
915 | my $expireHours = 24; | ||||
916 | my $expireSeconds = $expireHours * 60 * 60; | ||||
917 | |||||
918 | # and cache control headers, to ensure edit page | ||||
919 | # is cached until required expiry time. | ||||
920 | $hopts->{'last-modified'} = $lastModifiedString; | ||||
921 | $hopts->{expires} = "+${expireHours}h"; | ||||
922 | $hopts->{'cache-control'} = "max-age=$expireSeconds"; | ||||
923 | } | ||||
924 | |||||
925 | # DEPRECATED plugins header handler. Plugins should use | ||||
926 | # modifyHeaderHandler instead. | ||||
927 | 1 | 5µs | 1 | 6µs | my $pluginHeaders = # spent 6µs making 1 call to Foswiki::Plugins::dispatch |
928 | $this->{plugins}->dispatch( 'writeHeaderHandler', $this->{request} ) | ||||
929 | || ''; | ||||
930 | 1 | 200ns | if ($pluginHeaders) { | ||
931 | foreach ( split /\r?\n/, $pluginHeaders ) { | ||||
932 | |||||
933 | # Implicit untaint OK; data from plugin handler | ||||
934 | if (m/^([\-a-z]+): (.*)$/i) { | ||||
935 | $hopts->{$1} = $2; | ||||
936 | } | ||||
937 | } | ||||
938 | } | ||||
939 | |||||
940 | 1 | 300ns | $contentType = 'text/html' unless $contentType; | ||
941 | 1 | 9µs | $contentType .= '; charset=' . $Foswiki::cfg{Site}{CharSet} | ||
942 | if $contentType ne '' | ||||
943 | && $contentType =~ m!^text/! | ||||
944 | && $contentType !~ /\bcharset\b/ | ||||
945 | && $Foswiki::cfg{Site}{CharSet}; | ||||
946 | |||||
947 | # use our version of the content type | ||||
948 | 1 | 2µs | $hopts->{'Content-Type'} = $contentType; | ||
949 | |||||
950 | # New (since 1.026) | ||||
951 | 1 | 3µs | 1 | 82µs | $this->{plugins} # spent 82µs making 1 call to Foswiki::Plugins::dispatch |
952 | ->dispatch( 'modifyHeaderHandler', $hopts, $this->{request} ); | ||||
953 | |||||
954 | # add http compression and conditional cache controls | ||||
955 | 1 | 3µs | 1 | 3µs | if ( !$this->inContext('command_line') && $text ) { # spent 3µs making 1 call to Foswiki::inContext |
956 | |||||
957 | if ( $Foswiki::cfg{HttpCompress} | ||||
958 | && $ENV{'HTTP_ACCEPT_ENCODING'} | ||||
959 | && $ENV{'HTTP_ACCEPT_ENCODING'} =~ /(x-gzip|gzip)/i ) | ||||
960 | { | ||||
961 | my $encoding = $1; | ||||
962 | $hopts->{'Content-Encoding'} = $encoding; | ||||
963 | $hopts->{'Vary'} = 'Accept-Encoding'; | ||||
964 | |||||
965 | # check if we take the version from the cache | ||||
966 | if ( $cachedPage && !$cachedPage->{isDirty} ) { | ||||
967 | $text = $cachedPage->{text}; | ||||
968 | } | ||||
969 | else { | ||||
970 | require Compress::Zlib; | ||||
971 | $text = Compress::Zlib::memGzip($text); | ||||
972 | } | ||||
973 | } | ||||
974 | elsif ($cachedPage | ||||
975 | && !$cachedPage->{isDirty} | ||||
976 | && $Foswiki::cfg{HttpCompress} ) | ||||
977 | { | ||||
978 | |||||
979 | # Outch, we need to uncompressed pages from cache again | ||||
980 | # Note, this is effort to avoid under any circumstances as | ||||
981 | # the page has been compressed when it has been created and now | ||||
982 | # is uncompressed again to get back the original. For now the | ||||
983 | # only know situation this can happen is for older browsers like IE6 | ||||
984 | # which does not understand gzip'ed http encodings | ||||
985 | require Compress::Zlib; | ||||
986 | $text = Compress::Zlib::memGunzip($text); | ||||
987 | } | ||||
988 | |||||
989 | # we need to force the browser into a check on every | ||||
990 | # request; let the server decide on an 304 as below | ||||
991 | $hopts->{'Cache-Control'} = 'max-age=0'; | ||||
992 | |||||
993 | # check etag and last modification time | ||||
994 | # if we have a cached page on the server side | ||||
995 | if ($cachedPage) { | ||||
996 | my $etag = $cachedPage->{etag}; | ||||
997 | my $lastModified = $cachedPage->{lastModified}; | ||||
998 | |||||
999 | $hopts->{'ETag'} = $etag; | ||||
1000 | $hopts->{'Last-Modified'} = $lastModified if $lastModified; | ||||
1001 | |||||
1002 | # only send a 304 if both criteria are true | ||||
1003 | my $etagFlag = 1; | ||||
1004 | my $lastModifiedFlag = 1; | ||||
1005 | |||||
1006 | # check etag | ||||
1007 | unless ( $ENV{'HTTP_IF_NONE_MATCH'} | ||||
1008 | && $etag eq $ENV{'HTTP_IF_NONE_MATCH'} ) | ||||
1009 | { | ||||
1010 | $etagFlag = 0; | ||||
1011 | } | ||||
1012 | |||||
1013 | # check last-modified | ||||
1014 | unless ( $ENV{'HTTP_IF_MODIFIED_SINCE'} | ||||
1015 | && $lastModified eq $ENV{'HTTP_IF_MODIFIED_SINCE'} ) | ||||
1016 | { | ||||
1017 | $lastModifiedFlag = 0; | ||||
1018 | } | ||||
1019 | |||||
1020 | # finally decide on a 304 reply | ||||
1021 | if ( $etagFlag && $lastModified ) { | ||||
1022 | $hopts->{'Status'} = '304 Not Modified'; | ||||
1023 | $text = ''; | ||||
1024 | |||||
1025 | #print STDERR "NOT modified\n"; | ||||
1026 | } | ||||
1027 | } | ||||
1028 | |||||
1029 | # write back to text | ||||
1030 | $_[3] = $text; | ||||
1031 | } | ||||
1032 | |||||
1033 | 1 | 9µs | 1 | 8µs | $hopts->{"X-FoswikiAction"} = $this->{request}->action; # spent 8µs making 1 call to Foswiki::Request::action |
1034 | 1 | 5µs | 1 | 4µs | $hopts->{"X-FoswikiURI"} = $this->{request}->uri; # spent 4µs making 1 call to Foswiki::Request::uri |
1035 | |||||
1036 | # The headers method resets all headers to what we pass | ||||
1037 | # what we want is simply ensure our headers are there | ||||
1038 | 1 | 12µs | 1 | 46µs | $this->{response}->setDefaultHeaders($hopts); # spent 46µs making 1 call to Foswiki::Response::setDefaultHeaders |
1039 | } | ||||
1040 | |||||
1041 | # Tests if the $redirect is an external URL, returning false if | ||||
1042 | # AllowRedirectUrl is denied | ||||
1043 | sub _isRedirectSafe { | ||||
1044 | my $redirect = shift; | ||||
1045 | |||||
1046 | return 1 if ( $Foswiki::cfg{AllowRedirectUrl} ); | ||||
1047 | return 1 if $redirect =~ m#^/#; # relative URL - OK | ||||
1048 | |||||
1049 | #TODO: this should really use URI | ||||
1050 | # Compare protocol, host name and port number | ||||
1051 | if ( $redirect =~ m!^(.*?://[^/?#]*)! ) { | ||||
1052 | |||||
1053 | # implicit untaints OK because result not used. uc retaints | ||||
1054 | # if use locale anyway. | ||||
1055 | my $target = uc($1); | ||||
1056 | |||||
1057 | $Foswiki::cfg{DefaultUrlHost} =~ m!^(.*?://[^/]*)!; | ||||
1058 | return 1 if ( $target eq uc($1) ); | ||||
1059 | |||||
1060 | if ( $Foswiki::cfg{PermittedRedirectHostUrls} ) { | ||||
1061 | foreach my $red ( | ||||
1062 | split( /\s*,\s*/, $Foswiki::cfg{PermittedRedirectHostUrls} ) ) | ||||
1063 | { | ||||
1064 | $red =~ m!^(.*?://[^/]*)!; | ||||
1065 | return 1 if ( $target eq uc($1) ); | ||||
1066 | } | ||||
1067 | } | ||||
1068 | } | ||||
1069 | return 0; | ||||
1070 | } | ||||
1071 | |||||
1072 | =begin TML | ||||
1073 | |||||
1074 | ---++ ObjectMethod redirectto($url) -> $url | ||||
1075 | |||||
1076 | If the CGI parameter 'redirectto' is present on the query, then will validate | ||||
1077 | that it is a legal redirection target (url or topic name). If 'redirectto' | ||||
1078 | is not present on the query, performs the same steps on $url. | ||||
1079 | |||||
1080 | Returns undef if the target is not valid, and the target URL otherwise. | ||||
1081 | |||||
1082 | =cut | ||||
1083 | |||||
1084 | sub redirectto { | ||||
1085 | my ( $this, $url ) = @_; | ||||
1086 | |||||
1087 | my $redirecturl = $this->{request}->param('redirectto'); | ||||
1088 | $redirecturl = $url unless $redirecturl; | ||||
1089 | |||||
1090 | return unless $redirecturl; | ||||
1091 | |||||
1092 | if ( $redirecturl =~ m#^$regex{linkProtocolPattern}://#o ) { | ||||
1093 | |||||
1094 | # assuming URL | ||||
1095 | return $redirecturl if _isRedirectSafe($redirecturl); | ||||
1096 | return; | ||||
1097 | } | ||||
1098 | |||||
1099 | # assuming 'web.topic' or 'topic' | ||||
1100 | my ( $w, $t ) = | ||||
1101 | $this->normalizeWebTopicName( $this->{webName}, $redirecturl ); | ||||
1102 | |||||
1103 | # capture anchor | ||||
1104 | my ( $topic, $anchor ) = split( '#', $t, 2 ); | ||||
1105 | $t = $topic if $topic; | ||||
1106 | my @attrs = (); | ||||
1107 | push( @attrs, '#' => $anchor ) if $anchor; | ||||
1108 | |||||
1109 | return $this->getScriptUrl( 0, 'view', $w, $t, @attrs ); | ||||
1110 | } | ||||
1111 | |||||
1112 | =begin TML | ||||
1113 | |||||
1114 | ---++ StaticMethod splitAnchorFromUrl( $url ) -> ( $url, $anchor ) | ||||
1115 | |||||
1116 | Takes a full url (including possible query string) and splits off the anchor. | ||||
1117 | The anchor includes the # sign. Returns an empty string if not found in the url. | ||||
1118 | |||||
1119 | =cut | ||||
1120 | |||||
1121 | sub splitAnchorFromUrl { | ||||
1122 | my ($url) = @_; | ||||
1123 | |||||
1124 | ( $url, my $anchor ) = $url =~ m/^(.*?)(#(.*?))*$/; | ||||
1125 | return ( $url, $anchor ); | ||||
1126 | } | ||||
1127 | |||||
1128 | =begin TML | ||||
1129 | |||||
1130 | ---++ ObjectMethod redirect( $url, $passthrough ) | ||||
1131 | |||||
1132 | * $url - url or topic to redirect to | ||||
1133 | * $passthrough - (optional) parameter to pass through current query | ||||
1134 | parameters (see below) | ||||
1135 | |||||
1136 | Redirects the request to =$url=, *unless* | ||||
1137 | 1 It is overridden by a plugin declaring a =redirectCgiQueryHandler= | ||||
1138 | (a dangerous, deprecated handler!) | ||||
1139 | 1 =$session->{request}= is =undef= or | ||||
1140 | Thus a redirect is only generated when in a CGI context. | ||||
1141 | |||||
1142 | Normally this method will ignore parameters to the current query. Sometimes, | ||||
1143 | for example when redirecting to a login page during authentication (and then | ||||
1144 | again from the login page to the original requested URL), you want to make | ||||
1145 | sure all parameters are passed on, and for this $passthrough should be set to | ||||
1146 | true. In this case it will pass all parameters that were passed to the | ||||
1147 | current query on to the redirect target. If the request_method for the | ||||
1148 | current query was GET, then all parameters will be passed by encoding them | ||||
1149 | in the URL (after ?). If the request_method was POST, then there is a risk the | ||||
1150 | URL would be too big for the receiver, so it caches the form data and passes | ||||
1151 | over a cache reference in the redirect GET. | ||||
1152 | |||||
1153 | NOTE: Passthrough is only meaningful if the redirect target is on the same | ||||
1154 | server. | ||||
1155 | |||||
1156 | =cut | ||||
1157 | |||||
1158 | sub redirect { | ||||
1159 | my ( $this, $url, $passthru ) = @_; | ||||
1160 | ASSERT( defined $url ) if DEBUG; | ||||
1161 | |||||
1162 | return unless $this->{request}; | ||||
1163 | |||||
1164 | ( $url, my $anchor ) = splitAnchorFromUrl($url); | ||||
1165 | |||||
1166 | if ( $passthru && defined $this->{request}->method() ) { | ||||
1167 | my $existing = ''; | ||||
1168 | if ( $url =~ s/\?(.*)$// ) { | ||||
1169 | $existing = $1; # implicit untaint OK; recombined later | ||||
1170 | } | ||||
1171 | if ( uc( $this->{request}->method() ) eq 'POST' ) { | ||||
1172 | |||||
1173 | # Redirecting from a post to a get | ||||
1174 | my $cache = $this->cacheQuery(); | ||||
1175 | if ($cache) { | ||||
1176 | if ( $url eq '/' ) { | ||||
1177 | $url = $this->getScriptUrl( 1, 'view' ); | ||||
1178 | } | ||||
1179 | $url .= $cache; | ||||
1180 | } | ||||
1181 | } | ||||
1182 | else { | ||||
1183 | |||||
1184 | # Redirecting a get to a get; no need to use passthru | ||||
1185 | if ( $this->{request}->query_string() ) { | ||||
1186 | $url .= '?' . $this->{request}->query_string(); | ||||
1187 | } | ||||
1188 | if ($existing) { | ||||
1189 | if ( $url =~ /\?/ ) { | ||||
1190 | $url .= ';'; | ||||
1191 | } | ||||
1192 | else { | ||||
1193 | $url .= '?'; | ||||
1194 | } | ||||
1195 | $url .= $existing; | ||||
1196 | } | ||||
1197 | } | ||||
1198 | } | ||||
1199 | |||||
1200 | # prevent phishing by only allowing redirect to configured host | ||||
1201 | # do this check as late as possible to catch _any_ last minute hacks | ||||
1202 | # TODO: this should really use URI | ||||
1203 | if ( !_isRedirectSafe($url) ) { | ||||
1204 | |||||
1205 | # goto oops if URL is trying to take us somewhere dangerous | ||||
1206 | $url = $this->getScriptUrl( | ||||
1207 | 1, 'oops', | ||||
1208 | $this->{webName} || $Foswiki::cfg{UsersWebName}, | ||||
1209 | $this->{topicName} || $Foswiki::cfg{HomeTopicName}, | ||||
1210 | template => 'oopsredirectdenied', | ||||
1211 | def => 'redirect_denied', | ||||
1212 | param1 => "$url", | ||||
1213 | param2 => "$Foswiki::cfg{DefaultUrlHost}", | ||||
1214 | ); | ||||
1215 | } | ||||
1216 | |||||
1217 | $url .= $anchor if $anchor; | ||||
1218 | |||||
1219 | # Dangerous, deprecated handler! Might work, probably won't. | ||||
1220 | return | ||||
1221 | if ( $this->{plugins} | ||||
1222 | ->dispatch( 'redirectCgiQueryHandler', $this->{response}, $url ) ); | ||||
1223 | |||||
1224 | $url = $this->getLoginManager()->rewriteRedirectUrl($url); | ||||
1225 | |||||
1226 | # Foswiki::Response::redirect doesn't automatically pass on the cookies | ||||
1227 | # for us, so we have to do it explicitly; otherwise the session cookie | ||||
1228 | # won't get passed on. | ||||
1229 | $this->{response} | ||||
1230 | ->redirect( -url => $url, -cookies => $this->{response}->cookies() ); | ||||
1231 | } | ||||
1232 | |||||
1233 | =begin TML | ||||
1234 | |||||
1235 | ---++ ObjectMethod cacheQuery() -> $queryString | ||||
1236 | |||||
1237 | Caches the current query in the params cache, and returns a rewritten | ||||
1238 | query string for the cache to be picked up again on the other side of a | ||||
1239 | redirect. | ||||
1240 | |||||
1241 | We can't encode post params into a redirect, because they may exceed the | ||||
1242 | size of the GET request. So we cache the params, and reload them when the | ||||
1243 | redirect target is reached. | ||||
1244 | |||||
1245 | =cut | ||||
1246 | |||||
1247 | sub cacheQuery { | ||||
1248 | my $this = shift; | ||||
1249 | my $query = $this->{request}; | ||||
1250 | |||||
1251 | return '' unless ( scalar( $query->param() ) ); | ||||
1252 | |||||
1253 | # Don't double-cache | ||||
1254 | return '' if ( $query->param('foswiki_redirect_cache') ); | ||||
1255 | |||||
1256 | require Foswiki::Request::Cache; | ||||
1257 | my $uid = Foswiki::Request::Cache->new()->save($query); | ||||
1258 | if ( $Foswiki::cfg{UsePathForRedirectCache} ) { | ||||
1259 | return '/foswiki_redirect_cache/' . $uid; | ||||
1260 | } | ||||
1261 | else { | ||||
1262 | return '?foswiki_redirect_cache=' . $uid; | ||||
1263 | } | ||||
1264 | } | ||||
1265 | |||||
1266 | =begin TML | ||||
1267 | |||||
1268 | ---++ ObjectMethod getCGISession() -> $cgisession | ||||
1269 | |||||
1270 | Get the CGI::Session object associated with this session, if there is | ||||
1271 | one. May return undef. | ||||
1272 | |||||
1273 | =cut | ||||
1274 | |||||
1275 | # spent 42µs (12+30) within Foswiki::getCGISession which was called:
# once (12µs+30µs) by Foswiki::writeCompletePage at line 766 | ||||
1276 | 1 | 9µs | 1 | 30µs | $_[0]->{users}->getCGISession(); # spent 30µs making 1 call to Foswiki::Users::getCGISession |
1277 | } | ||||
1278 | |||||
1279 | =begin TML | ||||
1280 | |||||
1281 | ---++ ObjectMethod getLoginManager() -> $loginManager | ||||
1282 | |||||
1283 | Get the Foswiki::LoginManager object associated with this session, if there is | ||||
1284 | one. May return undef. | ||||
1285 | |||||
1286 | =cut | ||||
1287 | |||||
1288 | # spent 108µs (73+35) within Foswiki::getLoginManager which was called 10 times, avg 11µs/call:
# 5 times (36µs+19µs) by Foswiki::Render::getRenderedVersion at line 1464 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 11µs/call
# 2 times (16µs+7µs) by Foswiki::LoginManager::_LOGIN at line 1150 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm, avg 12µs/call
# once (11µs+6µs) by Foswiki::Func::setSessionValue at line 377 of /var/www/foswiki11/lib/Foswiki/Func.pm
# once (5µs+2µs) by Foswiki::Func::clearSessionValue at line 394 of /var/www/foswiki11/lib/Foswiki/Func.pm
# once (5µs+2µs) by Foswiki::UI::__ANON__[/var/www/foswiki11/lib/Foswiki/UI.pm:318] at line 315 of /var/www/foswiki11/lib/Foswiki/UI.pm | ||||
1289 | 10 | 66µs | 10 | 35µs | $_[0]->{users}->getLoginManager(); # spent 35µs making 10 calls to Foswiki::Users::getLoginManager, avg 4µs/call |
1290 | } | ||||
1291 | |||||
1292 | =begin TML | ||||
1293 | |||||
1294 | ---++ StaticMethod isValidWikiWord( $name ) -> $boolean | ||||
1295 | |||||
1296 | Check for a valid WikiWord or WikiName | ||||
1297 | |||||
1298 | =cut | ||||
1299 | |||||
1300 | sub isValidWikiWord { | ||||
1301 | my $name = shift || ''; | ||||
1302 | return ( $name =~ m/^$regex{wikiWordRegex}$/o ); | ||||
1303 | } | ||||
1304 | |||||
1305 | =begin TML | ||||
1306 | |||||
1307 | ---++ StaticMethod isValidTopicName( $name [, $nonww] ) -> $boolean | ||||
1308 | |||||
1309 | Check for a valid topic =$name=. If =$nonww=, then accept non wiki-words | ||||
1310 | (though they must still be composed of only valid, unfiltered characters) | ||||
1311 | |||||
1312 | =cut | ||||
1313 | |||||
1314 | # Note: must work on tainted names. | ||||
1315 | # spent 104µs within Foswiki::isValidTopicName which was called 9 times, avg 12µs/call:
# 7 times (57µs+0s) by Foswiki::INCLUDE at line 176 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 8µs/call
# 2 times (47µs+0s) by Foswiki::Sandbox::validateTopicName at line 160 of /var/www/foswiki11/lib/Foswiki/Sandbox.pm, avg 23µs/call | ||||
1316 | 9 | 7µs | my ( $name, $nonww ) = @_; | ||
1317 | |||||
1318 | 9 | 7µs | return 0 unless defined $name && $name ne ''; | ||
1319 | 9 | 78µs | return 1 if ( $name =~ m/^$regex{topicNameRegex}$/o ); | ||
1320 | 2 | 500ns | return 0 unless $nonww; | ||
1321 | 2 | 13µs | return 0 if $name =~ /$cfg{NameFilter}/o; | ||
1322 | 2 | 7µs | return 1; | ||
1323 | } | ||||
1324 | |||||
1325 | =begin TML | ||||
1326 | |||||
1327 | ---++ StaticMethod isValidWebName( $name, $system ) -> $boolean | ||||
1328 | |||||
1329 | STATIC Check for a valid web name. If $system is true, then | ||||
1330 | system web names are considered valid (names starting with _) | ||||
1331 | otherwise only user web names are valid | ||||
1332 | |||||
1333 | If $Foswiki::cfg{EnableHierarchicalWebs} is off, it will also return false | ||||
1334 | when a nested web name is passed to it. | ||||
1335 | |||||
1336 | =cut | ||||
1337 | |||||
1338 | # Note: must work on tainted names. | ||||
1339 | # spent 1.16ms within Foswiki::isValidWebName which was called 182 times, avg 6µs/call:
# 182 times (1.16ms+0s) by Foswiki::Sandbox::validateWebName at line 145 of /var/www/foswiki11/lib/Foswiki/Sandbox.pm, avg 6µs/call | ||||
1340 | 182 | 92µs | my $name = shift || ''; | ||
1341 | 182 | 43µs | my $sys = shift; | ||
1342 | 182 | 262µs | return 1 if ( $sys && $name =~ m/^$regex{defaultWebNameRegex}$/o ); | ||
1343 | 179 | 1.11ms | return ( $name =~ m/^$regex{webNameRegex}$/o ); | ||
1344 | } | ||||
1345 | |||||
1346 | =begin TML | ||||
1347 | |||||
1348 | ---++ StaticMethod isValidEmailAddress( $name ) -> $boolean | ||||
1349 | |||||
1350 | STATIC Check for a valid email address name. | ||||
1351 | |||||
1352 | =cut | ||||
1353 | |||||
1354 | # Note: must work on tainted names. | ||||
1355 | sub isValidEmailAddress { | ||||
1356 | my $name = shift || ''; | ||||
1357 | return $name =~ /^$regex{emailAddrRegex}$/o; | ||||
1358 | } | ||||
1359 | |||||
1360 | =begin TML | ||||
1361 | |||||
1362 | ---++ ObjectMethod getSkin () -> $string | ||||
1363 | |||||
1364 | Get the currently requested skin path | ||||
1365 | |||||
1366 | =cut | ||||
1367 | |||||
1368 | # spent 6.67ms (1.65+5.02) within Foswiki::getSkin which was called 45 times, avg 148µs/call:
# 42 times (1.52ms+4.65ms) by Foswiki::Templates::readTemplate at line 230 of /var/www/foswiki11/lib/Foswiki/Templates.pm, avg 147µs/call
# 2 times (87µs+265µs) by Foswiki::UI::View::view at line 326 of /var/www/foswiki11/lib/Foswiki/UI/View.pm, avg 176µs/call
# once (36µs+103µs) by Foswiki::UI::View::view at line 349 of /var/www/foswiki11/lib/Foswiki/UI/View.pm | ||||
1369 | 45 | 25µs | my $this = shift; | ||
1370 | |||||
1371 | 45 | 8µs | my @skinpath; | ||
1372 | 45 | 13µs | my $skins; | ||
1373 | |||||
1374 | 45 | 53µs | if ( $this->{request} ) { | ||
1375 | 45 | 290µs | 45 | 1.96ms | $skins = $this->{request}->param('cover'); # spent 1.96ms making 45 calls to Foswiki::Request::param, avg 44µs/call |
1376 | 45 | 21µs | if ( defined $skins | ||
1377 | && $skins =~ /([$regex{mixedAlphaNum}.,\s]+)/o ) | ||||
1378 | { | ||||
1379 | |||||
1380 | # Implicit untaint ok - validated | ||||
1381 | $skins = $1; | ||||
1382 | push( @skinpath, split( /,\s]+/, $skins ) ); | ||||
1383 | } | ||||
1384 | } | ||||
1385 | |||||
1386 | 45 | 324µs | 45 | 2.30ms | $skins = $this->{prefs}->getPreference('COVER'); # spent 2.30ms making 45 calls to Foswiki::Prefs::getPreference, avg 51µs/call |
1387 | 45 | 17µs | if ( defined $skins | ||
1388 | && $skins =~ /([$regex{mixedAlphaNum}.,\s]+)/o ) | ||||
1389 | { | ||||
1390 | |||||
1391 | # Implicit untaint ok - validated | ||||
1392 | $skins = $1; | ||||
1393 | push( @skinpath, split( /[,\s]+/, $skins ) ); | ||||
1394 | } | ||||
1395 | |||||
1396 | 45 | 161µs | 45 | 763µs | $skins = $this->{request} ? $this->{request}->param('skin') : undef; # spent 763µs making 45 calls to Foswiki::Request::param, avg 17µs/call |
1397 | 45 | 12µs | $skins = $this->{prefs}->getPreference('SKIN') unless $skins; | ||
1398 | |||||
1399 | 45 | 323µs | if ( defined $skins && $skins =~ /([$regex{mixedAlphaNum}.,\s]+)/o ) { | ||
1400 | |||||
1401 | # Implicit untaint ok - validated | ||||
1402 | 45 | 51µs | $skins = $1; | ||
1403 | 45 | 189µs | push( @skinpath, split( /[,\s]+/, $skins ) ); | ||
1404 | } | ||||
1405 | |||||
1406 | 45 | 252µs | return join( ',', @skinpath ); | ||
1407 | } | ||||
1408 | |||||
1409 | =begin TML | ||||
1410 | |||||
1411 | ---++ ObjectMethod getScriptUrl( $absolute, $script, $web, $topic, ... ) -> $scriptURL | ||||
1412 | |||||
1413 | Returns the URL to a Foswiki script, providing the web and topic as | ||||
1414 | "path info" parameters. The result looks something like this: | ||||
1415 | "http://host/foswiki/bin/$script/$web/$topic". | ||||
1416 | * =...= - an arbitrary number of name,value parameter pairs that will be url-encoded and added to the url. The special parameter name '#' is reserved for specifying an anchor. e.g. <tt>getScriptUrl('x','y','view','#'=>'XXX',a=>1,b=>2)</tt> will give <tt>.../view/x/y?a=1&b=2#XXX</tt> | ||||
1417 | |||||
1418 | If $absolute is set, generates an absolute URL. $absolute is advisory only; | ||||
1419 | Foswiki can decide to generate absolute URLs (for example when run from the | ||||
1420 | command-line) even when relative URLs have been requested. | ||||
1421 | |||||
1422 | The default script url is taken from {ScriptUrlPath}, unless there is | ||||
1423 | an exception defined for the given script in {ScriptUrlPaths}. Both | ||||
1424 | {ScriptUrlPath} and {ScriptUrlPaths} may be absolute or relative URIs. If | ||||
1425 | they are absolute, then they will always generate absolute URLs. if they | ||||
1426 | are relative, then they will be converted to absolute when required (e.g. | ||||
1427 | when running from the command line, or when generating rss). If | ||||
1428 | $script is not given, absolute URLs will always be generated. | ||||
1429 | |||||
1430 | If either the web or the topic is defined, will generate a full url (including web and topic). Otherwise will generate only up to the script name. An undefined web will default to the main web name. | ||||
1431 | |||||
1432 | =cut | ||||
1433 | |||||
1434 | # spent 1.75ms (995µs+751µs) within Foswiki::getScriptUrl which was called 48 times, avg 36µs/call:
# 17 times (444µs+391µs) by Foswiki::Render::_renderExistingWikiWord at line 677 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 49µs/call
# 16 times (198µs+39µs) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:270] at line 270, avg 15µs/call
# 9 times (87µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:268] at line 268, avg 10µs/call
# 2 times (110µs+170µs) by Foswiki::UI::View::revisionsAround at line 492 of /var/www/foswiki11/lib/Foswiki/UI/View.pm, avg 140µs/call
# 2 times (66µs+93µs) by Foswiki::UI::View::revisionsAround at line 480 of /var/www/foswiki11/lib/Foswiki/UI/View.pm, avg 80µs/call
# 2 times (89µs+58µs) by Foswiki::LoginManager::ApacheLogin::loginUrl at line 102 of /var/www/foswiki11/lib/Foswiki/LoginManager/ApacheLogin.pm, avg 74µs/call | ||||
1435 | 48 | 81µs | my ( $this, $absolute, $script, $web, $topic, @params ) = @_; | ||
1436 | |||||
1437 | 48 | 82µs | 39 | 110µs | $absolute ||= # spent 110µs making 39 calls to Foswiki::inContext, avg 3µs/call |
1438 | ( $this->inContext('command_line') | ||||
1439 | || $this->inContext('rss') | ||||
1440 | || $this->inContext('absolute_urls') ); | ||||
1441 | |||||
1442 | # SMELL: topics and webs that contain spaces? | ||||
1443 | |||||
1444 | 48 | 9µs | my $url; | ||
1445 | 48 | 68µs | if ( defined $Foswiki::cfg{ScriptUrlPaths} && $script ) { | ||
1446 | $url = $Foswiki::cfg{ScriptUrlPaths}{$script}; | ||||
1447 | } | ||||
1448 | 48 | 13µs | unless ( defined($url) ) { | ||
1449 | 14 | 13µs | $url = $Foswiki::cfg{ScriptUrlPath}; | ||
1450 | 14 | 6µs | if ($script) { | ||
1451 | 12 | 14µs | $url .= '/' unless $url =~ /\/$/; | ||
1452 | 12 | 5µs | $url .= $script; | ||
1453 | 12 | 28µs | if ( | ||
1454 | rindex( $url, $Foswiki::cfg{ScriptSuffix} ) != | ||||
1455 | ( length($url) - length( $Foswiki::cfg{ScriptSuffix} ) ) ) | ||||
1456 | { | ||||
1457 | $url .= $Foswiki::cfg{ScriptSuffix} if $script; | ||||
1458 | } | ||||
1459 | } | ||||
1460 | } | ||||
1461 | |||||
1462 | 48 | 111µs | if ( $absolute && $url !~ /^[a-z]+:/ ) { | ||
1463 | |||||
1464 | # See http://www.ietf.org/rfc/rfc2396.txt for the definition of | ||||
1465 | # "absolute URI". Foswiki bastardises this definition by assuming | ||||
1466 | # that all relative URLs lack the <authority> component as well. | ||||
1467 | $url = $this->{urlHost} . $url; | ||||
1468 | } | ||||
1469 | |||||
1470 | 48 | 23µs | if ( $web || $topic ) { | ||
1471 | 23 | 88µs | 23 | 311µs | ( $web, $topic ) = $this->normalizeWebTopicName( $web, $topic ); # spent 311µs making 23 calls to Foswiki::normalizeWebTopicName, avg 14µs/call |
1472 | |||||
1473 | 23 | 91µs | 23 | 89µs | $url .= urlEncode( '/' . $web . '/' . $topic ); # spent 89µs making 23 calls to Foswiki::urlEncode, avg 4µs/call |
1474 | |||||
1475 | 23 | 60µs | 23 | 241µs | $url .= _make_params( 0, @params ); # spent 241µs making 23 calls to Foswiki::_make_params, avg 10µs/call |
1476 | } | ||||
1477 | |||||
1478 | 48 | 186µs | return $url; | ||
1479 | } | ||||
1480 | |||||
1481 | # spent 241µs (206+35) within Foswiki::_make_params which was called 23 times, avg 10µs/call:
# 23 times (206µs+35µs) by Foswiki::getScriptUrl at line 1475, avg 10µs/call | ||||
1482 | 23 | 10µs | my $notfirst = shift; | ||
1483 | 23 | 10µs | my $url = ''; | ||
1484 | 23 | 5µs | my $ps = ''; | ||
1485 | 23 | 6µs | my $anchor = ''; | ||
1486 | 23 | 35µs | while ( my $p = shift @_ ) { | ||
1487 | 6 | 5µs | if ( $p eq '#' ) { | ||
1488 | $anchor = '#' . urlEncode( shift(@_) ); | ||||
1489 | } | ||||
1490 | else { | ||||
1491 | 6 | 3µs | my $v = shift(@_); | ||
1492 | 6 | 2µs | $v = '' unless defined $v; | ||
1493 | 6 | 27µs | 12 | 36µs | $ps .= ';' . urlEncode($p) . '=' . urlEncode($v); # spent 36µs making 12 calls to Foswiki::urlEncode, avg 3µs/call |
1494 | } | ||||
1495 | } | ||||
1496 | 23 | 7µs | if ($ps) { | ||
1497 | 4 | 15µs | $ps =~ s/^;/?/ unless $notfirst; | ||
1498 | 4 | 2µs | $url .= $ps; | ||
1499 | } | ||||
1500 | 23 | 92µs | return $url . $anchor; | ||
1501 | } | ||||
1502 | |||||
1503 | =begin TML | ||||
1504 | |||||
1505 | ---++ ObjectMethod getPubUrl($absolute, $web, $topic, $attachment) -> $url | ||||
1506 | |||||
1507 | Composes a pub url. If $absolute is set, returns an absolute URL. | ||||
1508 | If $absolute is set, generates an absolute URL. $absolute is advisory only; | ||||
1509 | Foswiki can decide to generate absolute URLs (for example when run from the | ||||
1510 | command-line) even when relative URLs have been requested. | ||||
1511 | |||||
1512 | $web, $topic and $attachment are optional. A partial URL path will be | ||||
1513 | generated if one or all is not given. | ||||
1514 | |||||
1515 | =cut | ||||
1516 | |||||
1517 | # spent 518µs (386+132) within Foswiki::getPubUrl which was called 36 times, avg 14µs/call:
# 33 times (333µs+75µs) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:241] at line 241, avg 12µs/call
# 2 times (11µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:240] at line 240, avg 6µs/call
# once (42µs+58µs) by Foswiki::_getIconUrl at line 134 of /var/www/foswiki11/lib/Foswiki/Macros/ICON.pm | ||||
1518 | 36 | 34µs | my ( $this, $absolute, $web, $topic, $attachment ) = @_; | ||
1519 | |||||
1520 | 36 | 56µs | 33 | 75µs | $absolute ||= # spent 75µs making 33 calls to Foswiki::inContext, avg 2µs/call |
1521 | ( $this->inContext('command_line') | ||||
1522 | || $this->inContext('rss') | ||||
1523 | || $this->inContext('absolute_urls') ); | ||||
1524 | |||||
1525 | 36 | 16µs | my $url = ''; | ||
1526 | 36 | 27µs | $url .= $Foswiki::cfg{PubUrlPath}; | ||
1527 | 36 | 74µs | if ( $absolute && $url !~ /^[a-z]+:/ ) { | ||
1528 | |||||
1529 | # See http://www.ietf.org/rfc/rfc2396.txt for the definition of | ||||
1530 | # "absolute URI". Foswiki bastardises this definition by assuming | ||||
1531 | # that all relative URLs lack the <authority> component as well. | ||||
1532 | $url = $this->{urlHost} . $url; | ||||
1533 | } | ||||
1534 | 36 | 15µs | if ( $web || $topic || $attachment ) { | ||
1535 | 1 | 5µs | 1 | 30µs | ( $web, $topic ) = $this->normalizeWebTopicName( $web, $topic ); # spent 30µs making 1 call to Foswiki::normalizeWebTopicName |
1536 | |||||
1537 | 1 | 2µs | my $path = '/' . $web . '/' . $topic; | ||
1538 | 1 | 1µs | if ($attachment) { | ||
1539 | 1 | 900ns | $path .= '/' . $attachment; | ||
1540 | |||||
1541 | # Attachments are served directly by web server, need to handle | ||||
1542 | # URL encoding specially | ||||
1543 | 1 | 6µs | 1 | 28µs | $url .= urlEncodeAttachment($path); # spent 28µs making 1 call to Foswiki::urlEncodeAttachment |
1544 | } | ||||
1545 | else { | ||||
1546 | $url .= urlEncode($path); | ||||
1547 | } | ||||
1548 | } | ||||
1549 | |||||
1550 | 36 | 136µs | return $url; | ||
1551 | } | ||||
1552 | |||||
1553 | =begin TML | ||||
1554 | |||||
1555 | ---++ ObjectMethod deepWebList($filter, $web) -> @list | ||||
1556 | |||||
1557 | Deep list subwebs of the named web. $filter is a Foswiki::WebFilter | ||||
1558 | object that is used to filter the list. The listing of subwebs is | ||||
1559 | dependent on $Foswiki::cfg{EnableHierarchicalWebs} being true. | ||||
1560 | |||||
1561 | Webs are returned as absolute web pathnames. | ||||
1562 | |||||
1563 | =cut | ||||
1564 | |||||
1565 | # spent 8.35s (1.90ms+8.35) within Foswiki::deepWebList which was called 2 times, avg 4.18s/call:
# 2 times (1.90ms+8.35s) by Foswiki::Func::getListOfWebs at line 1477 of /var/www/foswiki11/lib/Foswiki/Func.pm, avg 4.18s/call | ||||
1566 | 2 | 4µs | my ( $this, $filter, $rootWeb ) = @_; | ||
1567 | 2 | 600ns | my @list; | ||
1568 | 2 | 11µs | 2 | 67µs | my $webObject = new Foswiki::Meta( $this, $rootWeb ); # spent 67µs making 2 calls to Foswiki::Meta::new, avg 33µs/call |
1569 | 2 | 14µs | 2 | 92.1ms | my $it = $webObject->eachWeb( $Foswiki::cfg{EnableHierarchicalWebs} ); # spent 92.1ms making 2 calls to Foswiki::Meta::eachWeb, avg 46.0ms/call |
1570 | 2 | 1µs | return $it->all() unless $filter; | ||
1571 | 2 | 7µs | 2 | 19µs | while ( $it->hasNext() ) { # spent 19µs making 2 calls to Foswiki::ListIterator::hasNext, avg 10µs/call |
1572 | 100 | 76µs | my $w = $rootWeb || ''; | ||
1573 | 100 | 22µs | $w .= '/' if $w; | ||
1574 | 100 | 263µs | 100 | 946µs | $w .= $it->next(); # spent 946µs making 100 calls to Foswiki::ListIterator::next, avg 9µs/call |
1575 | 100 | 680µs | 200 | 8.26s | if ( $filter->ok( $this, $w ) ) { # spent 8.26s making 100 calls to Foswiki::WebFilter::ok, avg 82.6ms/call
# spent 891µs making 100 calls to Foswiki::ListIterator::hasNext, avg 9µs/call |
1576 | push( @list, $w ); | ||||
1577 | } | ||||
1578 | } | ||||
1579 | 2 | 347µs | return @list; | ||
1580 | } | ||||
1581 | |||||
1582 | =begin TML | ||||
1583 | |||||
1584 | ---++ ObjectMethod normalizeWebTopicName( $web, $topic ) -> ( $web, $topic ) | ||||
1585 | |||||
1586 | Normalize a Web<nop>.<nop>TopicName | ||||
1587 | |||||
1588 | See =Foswiki::Func= for a full specification of the expansion (not duplicated | ||||
1589 | here) | ||||
1590 | |||||
1591 | *WARNING* if there is no web specification (in the web or topic parameters) | ||||
1592 | the web defaults to $Foswiki::cfg{UsersWebName}. If there is no topic | ||||
1593 | specification, or the topic is '0', the topic defaults to the web home topic | ||||
1594 | name. | ||||
1595 | |||||
1596 | *WARNING* if the input topic name is tainted, then the output web and | ||||
1597 | topic names will be tainted. | ||||
1598 | |||||
1599 | =cut | ||||
1600 | |||||
1601 | # spent 993ms (924+68.8) within Foswiki::normalizeWebTopicName which was called 81918 times, avg 12µs/call:
# 81336 times (918ms+68.1ms) by Foswiki::Func::normalizeWebTopicName at line 2834 of /var/www/foswiki11/lib/Foswiki/Func.pm, avg 12µs/call
# 377 times (3.90ms+316µs) by Foswiki::Users::getCanonicalUserID at line 504 of /var/www/foswiki11/lib/Foswiki/Users.pm, avg 11µs/call
# 98 times (1.20ms+151µs) by Foswiki::Templates::_readTemplateFile at line 459 of /var/www/foswiki11/lib/Foswiki/Templates.pm, avg 14µs/call
# 42 times (441µs+56µs) by Foswiki::VAR at line 15 of /var/www/foswiki11/lib/Foswiki/Macros/VAR.pm, avg 12µs/call
# 23 times (277µs+34µs) by Foswiki::getScriptUrl at line 1471, avg 14µs/call
# 17 times (222µs+25µs) by Foswiki::Render::_handleSquareBracketedLink at line 902 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 15µs/call
# 7 times (117µs+16µs) by Foswiki::INCLUDE at line 172 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 19µs/call
# 7 times (99µs+10µs) by Foswiki::If::OP_istopic::evaluate at line 33 of /var/www/foswiki11/lib/Foswiki/If/OP_istopic.pm, avg 16µs/call
# 5 times (54µs+4µs) by Foswiki::Func::_checkWTA at line 73 of /var/www/foswiki11/lib/Foswiki/Func.pm, avg 11µs/call
# 3 times (27µs+3µs) by Foswiki::REVINFO at line 20 of /var/www/foswiki11/lib/Foswiki/Macros/REVINFO.pm, avg 10µs/call
# once (52µs+87µs) by Foswiki::_lookupIcon at line 29 of /var/www/foswiki11/lib/Foswiki/Macros/ICON.pm
# once (56µs+4µs) by Foswiki::Prefs::loadSitePreferences at line 376 of /var/www/foswiki11/lib/Foswiki/Prefs.pm
# once (26µs+3µs) by Foswiki::getPubUrl at line 1535 | ||||
1602 | 81918 | 54.9ms | my ( $this, $web, $topic ) = @_; | ||
1603 | |||||
1604 | 81918 | 67.1ms | 81918 | 54.6ms | ASSERT( defined $topic ) if DEBUG; # spent 54.6ms making 81918 calls to Assert::ASSERTS_OFF, avg 667ns/call |
1605 | |||||
1606 | 81918 | 242ms | if ( $topic =~ m|^(.*)[./](.*?)$| ) { | ||
1607 | 17725 | 16.7ms | $web = $1; | ||
1608 | 17725 | 5.61ms | $topic = $2; | ||
1609 | |||||
1610 | 17725 | 19.1ms | 17725 | 14.1ms | if ( DEBUG && !UNTAINTED( $_[2] ) ) { # spent 14.1ms making 17725 calls to Assert::ASSERTS_OFF, avg 794ns/call |
1611 | |||||
1612 | # retaint data untainted by RE above | ||||
1613 | $web = TAINT($web); | ||||
1614 | $topic = TAINT($topic); | ||||
1615 | } | ||||
1616 | } | ||||
1617 | 81918 | 13.2ms | $web ||= $cfg{UsersWebName}; | ||
1618 | 81918 | 8.90ms | $topic ||= $cfg{HomeTopicName}; | ||
1619 | |||||
1620 | # MAINWEB and TWIKIWEB expanded for compatibility reasons | ||||
1621 | 81918 | 72.2ms | while ( | ||
1622 | $web =~ s/%((MAIN|TWIKI|USERS|SYSTEM|DOC)WEB)%/ | ||||
1623 | 2 | 17µs | 2 | 71µs | $this->_expandMacroOnTopicRendering( $1 ) || ''/e # spent 155µs making 2 calls to Foswiki::_expandMacroOnTopicRendering, avg 77µs/call, recursion: max depth 3, sum of overlapping time 84µs |
1624 | ) | ||||
1625 | { | ||||
1626 | } | ||||
1627 | |||||
1628 | # Normalize web name to use / and not . as a subweb separator | ||||
1629 | 81918 | 25.0ms | $web =~ s#\.#/#g; | ||
1630 | |||||
1631 | 81918 | 431ms | return ( $web, $topic ); | ||
1632 | } | ||||
1633 | |||||
1634 | =begin TML | ||||
1635 | |||||
1636 | ---++ ClassMethod new( $defaultUser, $query, \%initialContext ) | ||||
1637 | |||||
1638 | Constructs a new Foswiki session object. A unique session object exists for | ||||
1639 | ever transaction with Foswiki, for example every browser request, or every | ||||
1640 | script run. Session objects do not persist between mod_perl runs. | ||||
1641 | |||||
1642 | * =$defaultUser= is the username (*not* the wikiname) of the default | ||||
1643 | user you want to be logged-in, if none is available from a session | ||||
1644 | or browser. Used mainly for unit tests and debugging, it is typically | ||||
1645 | undef, in which case the default user is taken from | ||||
1646 | $Foswiki::cfg{DefaultUserName}. | ||||
1647 | * =$query= the Foswiki::Request query (may be undef, in which case an | ||||
1648 | empty query is used) | ||||
1649 | * =\%initialContext= - reference to a hash containing context | ||||
1650 | name=value pairs to be pre-installed in the context hash. May be undef. | ||||
1651 | |||||
1652 | =cut | ||||
1653 | |||||
1654 | # spent 1.72s (531µs+1.72) within Foswiki::new which was called:
# once (531µs+1.72s) by Foswiki::UI::__ANON__[/var/www/foswiki11/lib/Foswiki/UI.pm:318] at line 306 of /var/www/foswiki11/lib/Foswiki/UI.pm | ||||
1655 | 1 | 900ns | my ( $class, $defaultUser, $query, $initialContext ) = @_; | ||
1656 | 1 | 2µs | 1 | 2µs | Monitor::MARK("Static init over; make Foswiki object"); # spent 2µs making 1 call to Monitor::__ANON__[/var/www/foswiki11/lib/Monitor.pm:101] |
1657 | 1 | 1µs | 1 | 1µs | ASSERT( !$query || UNIVERSAL::isa( $query, 'Foswiki::Request' ) ) if DEBUG; # spent 1µs making 1 call to Assert::ASSERTS_OFF |
1658 | |||||
1659 | # Compatibility; not used except maybe in plugins | ||||
1660 | # Note, this returns in Foswiki 1.2 | ||||
1661 | 1 | 2µs | $Foswiki::cfg{TempfileDir} = "$Foswiki::cfg{WorkingDir}/tmp" | ||
1662 | unless defined( $Foswiki::cfg{TempfileDir} ); | ||||
1663 | |||||
1664 | 1 | 1µs | if ( $Foswiki::cfg{WarningFileName} | ||
1665 | && $Foswiki::cfg{Log}{Implementation} eq 'Foswiki::Logger::PlainFile' ) | ||||
1666 | { | ||||
1667 | |||||
1668 | # Admin has already expressed a preference for where they want their | ||||
1669 | # logfiles to go, and has obviously not re-run configure yet. | ||||
1670 | $Foswiki::cfg{Log}{Implementation} = 'Foswiki::Logger::Compatibility'; | ||||
1671 | |||||
1672 | #print STDERR "WARNING: Foswiki is using the compatibility logger. Please re-run configure and check your logfiles settings\n"; | ||||
1673 | } | ||||
1674 | |||||
1675 | # Make sure LogFielname is defined for use in old plugins, | ||||
1676 | # but don't overwrite the setting from configure, if there is one. | ||||
1677 | # This is especially important when the admin has *chosen* | ||||
1678 | # to use the compatibility logger. (Some old TWiki heritage | ||||
1679 | # plugins write directly to the configured LogFileName | ||||
1680 | 1 | 500ns | if ( not $Foswiki::cfg{LogFileName} ) { | ||
1681 | 1 | 1µs | if ( $Foswiki::cfg{Log}{Implementation} eq | ||
1682 | 'Foswiki::Logger::Compatibility' ) | ||||
1683 | { | ||||
1684 | my $stamp = | ||||
1685 | Foswiki::Time::formatTime( time(), '$year$mo', 'servertime' ); | ||||
1686 | my $defaultLogDir = "$Foswiki::cfg{DataDir}"; | ||||
1687 | $Foswiki::cfg{LogFileName} = $defaultLogDir . "/log$stamp.txt"; | ||||
1688 | |||||
1689 | #print STDERR "Overrode LogFileName to $Foswiki::cfg{LogFileName} for CompatibilityLogger\n" | ||||
1690 | } | ||||
1691 | else { | ||||
1692 | 1 | 2µs | $Foswiki::cfg{LogFileName} = "$Foswiki::cfg{Log}{Dir}/events.log"; | ||
1693 | |||||
1694 | #print STDERR "Overrode LogFileName to $Foswiki::cfg{LogFileName} for PlainFileLogger\n" | ||||
1695 | } | ||||
1696 | } | ||||
1697 | |||||
1698 | # Set command_line context if there is no query | ||||
1699 | 1 | 200ns | $initialContext ||= defined($query) ? {} : { command_line => 1 }; | ||
1700 | |||||
1701 | 1 | 100ns | $query ||= new Foswiki::Request(); | ||
1702 | 1 | 6µs | my $this = bless( { sandbox => 'Foswiki::Sandbox' }, $class ); | ||
1703 | |||||
1704 | 1 | 3µs | 1 | 2.80ms | if ( defined $Foswiki::cfg{Site}{CharSet} ) { # spent 2.80ms making 1 call to CGI::charset |
1705 | |||||
1706 | # Ensure the auto-encoding in CGI uses the correct character set. | ||||
1707 | # CGI defaults to iso-8859-1, and has a special exception for | ||||
1708 | # iso-8859-1 and windows1252 in CGI::escapeHTML which breaks | ||||
1709 | # UTF-8 content. See Item758. Get this wrong, and CGI will | ||||
1710 | # fail to encode certain UTF-8 characters correctly. | ||||
1711 | # Note we cannot call CGI::charset in begin block. We must have | ||||
1712 | # the CGI object created because otherwise Perl 5.8 versions of | ||||
1713 | # CGI will lose things like its temp files. | ||||
1714 | CGI::charset( $Foswiki::cfg{Site}{CharSet} ); | ||||
1715 | } | ||||
1716 | 1 | 2µs | 1 | 2µs | if (SINGLE_SINGLETONS_TRACE) { # spent 2µs making 1 call to Foswiki::SINGLE_SINGLETONS_TRACE |
1717 | require Data::Dumper; | ||||
1718 | print STDERR "new $this: " | ||||
1719 | . Data::Dumper->Dump( [ [caller], [ caller(1) ] ] ); | ||||
1720 | } | ||||
1721 | |||||
1722 | 1 | 400ns | $this->{request} = $query; | ||
1723 | 1 | 300ns | $this->{cgiQuery} = $query; # for backwards compatibility in contribs | ||
1724 | 1 | 4µs | 1 | 13µs | $this->{response} = new Foswiki::Response(); # spent 13µs making 1 call to Foswiki::Response::new |
1725 | 1 | 17µs | 1 | 11µs | $this->{digester} = new Digest::MD5(); # spent 11µs making 1 call to Digest::MD5::new |
1726 | |||||
1727 | # This is required in case we get an exception during | ||||
1728 | # initialisation, so that we have a session to handle it with. | ||||
1729 | 1 | 2µs | 1 | 2µs | ASSERT( !$Foswiki::Plugins::SESSION ) if SINGLE_SINGLETONS; # spent 2µs making 1 call to Foswiki::SINGLE_SINGLETONS |
1730 | 1 | 300ns | $Foswiki::Plugins::SESSION = $this; | ||
1731 | 1 | 1µs | 1 | 800ns | ASSERT( $Foswiki::Plugins::SESSION->isa('Foswiki') ) if DEBUG; # spent 800ns making 1 call to Assert::ASSERTS_OFF |
1732 | |||||
1733 | # Tell Foswiki::Response which charset we are using if not default | ||||
1734 | 1 | 8µs | if ( defined $Foswiki::cfg{Site}{CharSet} | ||
1735 | && $Foswiki::cfg{Site}{CharSet} !~ /^iso-?8859-?1$/io ) | ||||
1736 | { | ||||
1737 | $this->{response}->charset( $Foswiki::cfg{Site}{CharSet} ); | ||||
1738 | } | ||||
1739 | |||||
1740 | # hash of zone records | ||||
1741 | 1 | 600ns | $this->{_zones} = (); | ||
1742 | |||||
1743 | # hash of occurences of RENDERZONE | ||||
1744 | 1 | 200ns | $this->{_renderZonePlaceholder} = (); | ||
1745 | |||||
1746 | 1 | 1µs | $this->{context} = $initialContext; | ||
1747 | |||||
1748 | 1 | 2µs | if ( $Foswiki::cfg{Cache}{Enabled} ) { | ||
1749 | require Foswiki::PageCache; | ||||
1750 | $this->{cache} = new Foswiki::PageCache($this); | ||||
1751 | } | ||||
1752 | 1 | 4µs | 1 | 1.00ms | my $prefs = new Foswiki::Prefs($this); # spent 1.00ms making 1 call to Foswiki::Prefs::new |
1753 | 1 | 700ns | $this->{prefs} = $prefs; | ||
1754 | 1 | 5µs | 1 | 29µs | $this->{plugins} = new Foswiki::Plugins($this); # spent 29µs making 1 call to Foswiki::Plugins::new |
1755 | |||||
1756 | 1 | 21µs | eval "require $Foswiki::cfg{Store}{Implementation}"; # spent 66µs executing statements in string eval | ||
1757 | 1 | 2µs | 1 | 2µs | ASSERT( !$@, $@ ) if DEBUG; # spent 2µs making 1 call to Assert::ASSERTS_OFF |
1758 | 1 | 8µs | 1 | 10µs | $this->{store} = $Foswiki::cfg{Store}{Implementation}->new(); # spent 10µs making 1 call to Foswiki::Store::new |
1759 | |||||
1760 | #Monitor::MARK("Created store"); | ||||
1761 | |||||
1762 | 1 | 4µs | 1 | 19.3ms | $this->{users} = new Foswiki::Users($this); # spent 19.3ms making 1 call to Foswiki::Users::new |
1763 | |||||
1764 | #Monitor::MARK("Created users object"); | ||||
1765 | |||||
1766 | #{urlHost} is needed by loadSession.. | ||||
1767 | 1 | 4µs | 1 | 157µs | my $url = $query->url(); # spent 157µs making 1 call to Foswiki::Request::url |
1768 | 1 | 5µs | if ( $url | ||
1769 | && !$Foswiki::cfg{ForceDefaultUrlHost} | ||||
1770 | && $url =~ m{^([^:]*://[^/]*).*$} ) | ||||
1771 | { | ||||
1772 | 1 | 2µs | $this->{urlHost} = $1; | ||
1773 | |||||
1774 | 1 | 700ns | if ( $Foswiki::cfg{RemovePortNumber} ) { | ||
1775 | $this->{urlHost} =~ s/\:[0-9]+$//; | ||||
1776 | } | ||||
1777 | |||||
1778 | # If the urlHost in the url is localhost, this is a lot less | ||||
1779 | # useful than the default url host. This is because new CGI("") | ||||
1780 | # assigns this host by default - it's a default setting, used | ||||
1781 | # when there is nothing better available. | ||||
1782 | 1 | 3µs | if ( $this->{urlHost} =~ /^(https?:\/\/)localhost$/i ) { | ||
1783 | my $protocol = $1; | ||||
1784 | |||||
1785 | #only replace localhost _if_ the protocol matches the one specified in the DefaultUrlHost | ||||
1786 | if ( $Foswiki::cfg{DefaultUrlHost} =~ /^$protocol/i ) { | ||||
1787 | $this->{urlHost} = $Foswiki::cfg{DefaultUrlHost}; | ||||
1788 | } | ||||
1789 | } | ||||
1790 | } | ||||
1791 | else { | ||||
1792 | $this->{urlHost} = $Foswiki::cfg{DefaultUrlHost}; | ||||
1793 | } | ||||
1794 | 1 | 2µs | 1 | 1µs | ASSERT( $this->{urlHost} ) if DEBUG; # spent 1µs making 1 call to Assert::ASSERTS_OFF |
1795 | |||||
1796 | # Load (or create) the CGI session | ||||
1797 | 1 | 4µs | 1 | 39.0ms | $this->{remoteUser} = $this->{users}->loadSession($defaultUser); # spent 39.0ms making 1 call to Foswiki::Users::loadSession |
1798 | |||||
1799 | # Make %ENV safer, preventing hijack of the search path. The | ||||
1800 | # environment is set per-query, so this can't be done in a BEGIN. | ||||
1801 | # TWikibug:Item4382: Default $ENV{PATH} must be untainted because | ||||
1802 | # Foswiki runs with use strict and calling external programs that | ||||
1803 | # writes on the disk will fail unless Perl seens it as set to safe value. | ||||
1804 | 1 | 4µs | if ( $Foswiki::cfg{SafeEnvPath} ) { | ||
1805 | $ENV{PATH} = $Foswiki::cfg{SafeEnvPath}; | ||||
1806 | } | ||||
1807 | else { | ||||
1808 | |||||
1809 | # SMELL: how can we validate the PATH? | ||||
1810 | $ENV{PATH} = Foswiki::Sandbox::untaintUnchecked( $ENV{PATH} ); | ||||
1811 | } | ||||
1812 | 1 | 8µs | delete @ENV{qw( IFS CDPATH ENV BASH_ENV )}; | ||
1813 | |||||
1814 | 1 | 1µs | if ( $Foswiki::cfg{GetScriptUrlFromCgi} | ||
1815 | && $url | ||||
1816 | && $url =~ m{^[^:]*://[^/]*(.*)/.*$} | ||||
1817 | && $1 ) | ||||
1818 | { | ||||
1819 | |||||
1820 | # SMELL: this is a really dangerous hack. It will fail | ||||
1821 | # spectacularly with mod_perl. | ||||
1822 | # SMELL: why not just use $query->script_name? | ||||
1823 | # SMELL: unchecked implicit untaint? | ||||
1824 | $this->{scriptUrlPath} = $1; | ||||
1825 | } | ||||
1826 | |||||
1827 | 1 | 500ns | my $web = ''; | ||
1828 | 1 | 2µs | 1 | 19µs | my $topic = $query->param('topic'); # spent 19µs making 1 call to Foswiki::Request::param |
1829 | 1 | 800ns | if ($topic) { | ||
1830 | 1 | 26µs | if ( $topic =~ m#^$regex{linkProtocolPattern}://#o | ||
1831 | && $this->{request} ) | ||||
1832 | { | ||||
1833 | |||||
1834 | # SMELL: this is a result of Codev.GoBoxUnderstandsURLs, | ||||
1835 | # an unrequested, undocumented, and AFAICT pretty useless | ||||
1836 | #"feature". It should be deprecated (or silently removed; I | ||||
1837 | # really, really doubt anyone is using it) | ||||
1838 | $this->{webName} = ''; | ||||
1839 | $this->redirect($topic); | ||||
1840 | return $this; | ||||
1841 | } | ||||
1842 | elsif ( $topic =~ m#^(.*)[./](.*?)$# ) { | ||||
1843 | |||||
1844 | # is '?topic=Webname.SomeTopic' | ||||
1845 | # implicit untaint OK - validated later | ||||
1846 | 1 | 1µs | $web = $1; | ||
1847 | 1 | 900ns | $topic = $2; | ||
1848 | 1 | 2µs | $web =~ s/\./\//g; | ||
1849 | |||||
1850 | # jump to WebHome if 'bin/script?topic=Webname.' | ||||
1851 | 1 | 400ns | $topic = $Foswiki::cfg{HomeTopicName} if ( $web && !$topic ); | ||
1852 | } | ||||
1853 | |||||
1854 | # otherwise assume 'bin/script/Webname?topic=SomeTopic' | ||||
1855 | } | ||||
1856 | else { | ||||
1857 | $topic = ''; | ||||
1858 | } | ||||
1859 | |||||
1860 | 1 | 2µs | 1 | 3µs | my $pathInfo = $query->path_info(); # spent 3µs making 1 call to Foswiki::Request::pathInfo |
1861 | |||||
1862 | # Truncate the path_info at any quote | ||||
1863 | 1 | 800ns | if ( $pathInfo =~ m/['"]/g ) { | ||
1864 | $pathInfo = substr( $pathInfo, 0, ( ( pos $pathInfo ) - 1 ) ); | ||||
1865 | } | ||||
1866 | |||||
1867 | 1 | 500ns | $pathInfo =~ s|//+|/|g; # multiple //'s are illogical | ||
1868 | |||||
1869 | # Get the web and topic names from PATH_INFO | ||||
1870 | 1 | 900ns | if ( $pathInfo =~ m#^/(.*)[./](.*?)$# ) { | ||
1871 | |||||
1872 | # is '/Webname/SomeTopic' or '/Webname' | ||||
1873 | # implicit untaint OK - validated later | ||||
1874 | $web = $1 unless $web; | ||||
1875 | $topic = $2 unless $topic; | ||||
1876 | $web =~ s/\./\//g; | ||||
1877 | } | ||||
1878 | elsif ( $pathInfo =~ m#^/(.*?)$# ) { | ||||
1879 | |||||
1880 | # is 'bin/script/Webname' or 'bin/script/' | ||||
1881 | # implicit untaint OK - validated later | ||||
1882 | $web = $1 unless $web; | ||||
1883 | } | ||||
1884 | 1 | 3µs | 1 | 8µs | my $topicNameTemp = $this->UTF82SiteCharSet($topic); # spent 8µs making 1 call to Foswiki::UTF82SiteCharSet |
1885 | 1 | 400ns | if ($topicNameTemp) { | ||
1886 | $topic = $topicNameTemp; | ||||
1887 | } | ||||
1888 | |||||
1889 | # Item3270 - here's the appropriate place to enforce spec | ||||
1890 | # http://develop.twiki.org/~twiki4/cgi-bin/view/Bugs/Item3270 | ||||
1891 | 1 | 2µs | $topic = ucfirst($topic); | ||
1892 | |||||
1893 | # Validate and untaint topic name from path info | ||||
1894 | 1 | 4µs | 1 | 60µs | $this->{topicName} = Foswiki::Sandbox::untaint( $topic, # spent 60µs making 1 call to Foswiki::Sandbox::untaint |
1895 | \&Foswiki::Sandbox::validateTopicName ); | ||||
1896 | |||||
1897 | # Set the requestedWebName before applying defaults - used by statistics | ||||
1898 | # generation. Note: This is validated using Topic name rules to permit | ||||
1899 | # names beginning with lower case. | ||||
1900 | 1 | 3µs | 1 | 25µs | $this->{requestedWebName} = # spent 25µs making 1 call to Foswiki::Sandbox::untaint |
1901 | Foswiki::Sandbox::untaint( $web, \&Foswiki::Sandbox::validateTopicName ); | ||||
1902 | |||||
1903 | # Validate web name from path info | ||||
1904 | 1 | 4µs | 1 | 52µs | $this->{webName} = # spent 52µs making 1 call to Foswiki::Sandbox::untaint |
1905 | Foswiki::Sandbox::untaint( $web, \&Foswiki::Sandbox::validateWebName ); | ||||
1906 | |||||
1907 | 1 | 700ns | if ( !defined $this->{webName} && !defined $this->{topicName} ) { | ||
1908 | $this->{webName} = $Foswiki::cfg{UsersWebName}; | ||||
1909 | $this->{topicName} = $Foswiki::cfg{HomeTopicName}; | ||||
1910 | } | ||||
1911 | |||||
1912 | 1 | 600ns | $this->{webName} = '' | ||
1913 | unless ( defined $this->{webName} ); | ||||
1914 | |||||
1915 | 1 | 700ns | $this->{topicName} = $Foswiki::cfg{HomeTopicName} | ||
1916 | unless ( defined $this->{topicName} ); | ||||
1917 | |||||
1918 | # Convert UTF-8 web and topic name from URL into site charset if | ||||
1919 | # necessary | ||||
1920 | # SMELL: merge these two cases, browsers just don't mix two encodings | ||||
1921 | # in one URL - can also simplify into 2 lines by making function | ||||
1922 | # return unprocessed text if no conversion | ||||
1923 | 1 | 2µs | 1 | 5µs | my $webNameTemp = $this->UTF82SiteCharSet( $this->{webName} ); # spent 5µs making 1 call to Foswiki::UTF82SiteCharSet |
1924 | 1 | 300ns | if ($webNameTemp) { | ||
1925 | $this->{webName} = $webNameTemp; | ||||
1926 | } | ||||
1927 | |||||
1928 | 1 | 2µs | $this->{scriptUrlPath} = $Foswiki::cfg{ScriptUrlPath}; | ||
1929 | |||||
1930 | # Form definition cache | ||||
1931 | 1 | 800ns | $this->{forms} = {}; | ||
1932 | |||||
1933 | # Push global preferences from %SYSTEMWEB%.DefaultPreferences | ||||
1934 | 1 | 3µs | 1 | 175ms | $prefs->loadDefaultPreferences(); # spent 175ms making 1 call to Foswiki::Prefs::loadDefaultPreferences |
1935 | |||||
1936 | #Monitor::MARK("Loaded default prefs"); | ||||
1937 | |||||
1938 | # SMELL: what happens if we move this into the Foswiki::Users::new? | ||||
1939 | 1 | 10µs | 1 | 98.2ms | $this->{user} = $this->{users}->initialiseUser( $this->{remoteUser} ); # spent 98.2ms making 1 call to Foswiki::Users::initialiseUser |
1940 | |||||
1941 | #Monitor::MARK("Initialised user"); | ||||
1942 | |||||
1943 | # Static session variables that can be expanded in topics when they | ||||
1944 | # are enclosed in % signs | ||||
1945 | # SMELL: should collapse these into one. The duplication is pretty | ||||
1946 | # pointless. | ||||
1947 | 1 | 7µs | 1 | 18µs | $prefs->setInternalPreferences( # spent 18µs making 1 call to Foswiki::Prefs::setInternalPreferences |
1948 | BASEWEB => $this->{webName}, | ||||
1949 | BASETOPIC => $this->{topicName}, | ||||
1950 | INCLUDINGTOPIC => $this->{topicName}, | ||||
1951 | INCLUDINGWEB => $this->{webName} | ||||
1952 | ); | ||||
1953 | |||||
1954 | # Push plugin settings | ||||
1955 | 1 | 4µs | 1 | 1.30s | $this->{plugins}->settings(); # spent 1.30s making 1 call to Foswiki::Plugins::settings |
1956 | |||||
1957 | # Now the rest of the preferences | ||||
1958 | 1 | 8µs | 1 | 17.7ms | $prefs->loadSitePreferences(); # spent 17.7ms making 1 call to Foswiki::Prefs::loadSitePreferences |
1959 | |||||
1960 | # User preferences only available if we can get to a valid wikiname, | ||||
1961 | # which depends on the user mapper. | ||||
1962 | 1 | 8µs | 1 | 9µs | my $wn = $this->{users}->getWikiName( $this->{user} ); # spent 9µs making 1 call to Foswiki::Users::getWikiName |
1963 | 1 | 3µs | 1 | 145µs | if ($wn) { # spent 145µs making 1 call to Foswiki::Prefs::setUserPreferences |
1964 | $prefs->setUserPreferences($wn); | ||||
1965 | } | ||||
1966 | |||||
1967 | 1 | 6µs | 1 | 4.53ms | $prefs->pushTopicContext( $this->{webName}, $this->{topicName} ); # spent 4.53ms making 1 call to Foswiki::Prefs::pushTopicContext |
1968 | |||||
1969 | #Monitor::MARK("Preferences all set up"); | ||||
1970 | |||||
1971 | 1 | 8µs | 1 | 2.49ms | if ( $this->{users}->isAdmin( $this->{user} ) ) { # spent 2.49ms making 1 call to Foswiki::Users::isAdmin |
1972 | $this->{context}{isadmin} = 1; | ||||
1973 | } | ||||
1974 | |||||
1975 | # Finish plugin initialization - register handlers | ||||
1976 | 1 | 5µs | 1 | 49.9ms | $this->{plugins}->enable(); # spent 49.9ms making 1 call to Foswiki::Plugins::enable |
1977 | |||||
1978 | 1 | 6µs | 1 | 5µs | Monitor::MARK("Foswiki object created"); # spent 5µs making 1 call to Monitor::__ANON__[/var/www/foswiki11/lib/Monitor.pm:101] |
1979 | |||||
1980 | 1 | 11µs | return $this; | ||
1981 | } | ||||
1982 | |||||
1983 | =begin TML | ||||
1984 | |||||
1985 | ---++ ObjectMethod renderer() | ||||
1986 | Get a reference to the renderer object. Done lazily because not everyone | ||||
1987 | needs the renderer. | ||||
1988 | |||||
1989 | =cut | ||||
1990 | |||||
1991 | # spent 12.9ms (11.5+1.41) within Foswiki::renderer which was called 14 times, avg 922µs/call:
# 5 times (29µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm:331] at line 317 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 6µs/call
# 5 times (16µs+0s) by Foswiki::Meta::renderTML at line 3117 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 3µs/call
# 3 times (6µs+0s) by Foswiki::REVINFO at line 38 of /var/www/foswiki11/lib/Foswiki/Macros/REVINFO.pm, avg 2µs/call
# once (11.5ms+1.41ms) by Foswiki::META at line 19 of /var/www/foswiki11/lib/Foswiki/Macros/META.pm | ||||
1992 | 14 | 10µs | my ($this) = @_; | ||
1993 | |||||
1994 | 14 | 10µs | unless ( $this->{renderer} ) { | ||
1995 | 1 | 100µs | require Foswiki::Render; | ||
1996 | 1 | 7µs | 1 | 12µs | $this->{renderer} = new Foswiki::Render($this); # spent 12µs making 1 call to Foswiki::Render::new |
1997 | } | ||||
1998 | 14 | 50µs | return $this->{renderer}; | ||
1999 | } | ||||
2000 | |||||
2001 | =begin TML | ||||
2002 | |||||
2003 | ---++ ObjectMethod attach() | ||||
2004 | Get a reference to the attach object. Done lazily because not everyone | ||||
2005 | needs the attach. | ||||
2006 | |||||
2007 | =cut | ||||
2008 | |||||
2009 | # spent 2.36ms (2.25+104µs) within Foswiki::attach which was called:
# once (2.25ms+104µs) by Foswiki::META at line 19 of /var/www/foswiki11/lib/Foswiki/Macros/META.pm | ||||
2010 | 1 | 700ns | my ($this) = @_; | ||
2011 | |||||
2012 | 1 | 1µs | unless ( $this->{attach} ) { | ||
2013 | 1 | 76µs | require Foswiki::Attach; | ||
2014 | 1 | 8µs | 1 | 14µs | $this->{attach} = new Foswiki::Attach($this); # spent 14µs making 1 call to Foswiki::Attach::new |
2015 | } | ||||
2016 | 1 | 5µs | return $this->{attach}; | ||
2017 | } | ||||
2018 | |||||
2019 | =begin TML | ||||
2020 | |||||
2021 | ---++ ObjectMethod templates() | ||||
2022 | Get a reference to the templates object. Done lazily because not everyone | ||||
2023 | needs the templates. | ||||
2024 | |||||
2025 | =cut | ||||
2026 | |||||
2027 | # spent 3.14ms (2.83+310µs) within Foswiki::templates which was called 168 times, avg 19µs/call:
# 41 times (213µs+0s) by Foswiki::Search::loadTemplates at line 508 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 5µs/call
# 41 times (104µs+0s) by Foswiki::Search::loadTemplates at line 523 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 3µs/call
# 41 times (75µs+0s) by Foswiki::Search::loadTemplates at line 524 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (73µs+0s) by Foswiki::Search::loadTemplates at line 535 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 2 times (10µs+0s) by Foswiki::LoginManager::_LOGIN at line 1156 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm, avg 5µs/call
# once (2.35ms+310µs) by Foswiki::UI::View::view at line 239 of /var/www/foswiki11/lib/Foswiki/UI/View.pm
# once (6µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:283] at line 283 | ||||
2028 | 168 | 73µs | my ($this) = @_; | ||
2029 | |||||
2030 | 168 | 81µs | unless ( $this->{templates} ) { | ||
2031 | 1 | 142µs | require Foswiki::Templates; | ||
2032 | 1 | 7µs | 1 | 13µs | $this->{templates} = new Foswiki::Templates($this); # spent 13µs making 1 call to Foswiki::Templates::new |
2033 | } | ||||
2034 | 168 | 551µs | return $this->{templates}; | ||
2035 | } | ||||
2036 | |||||
2037 | =begin TML | ||||
2038 | |||||
2039 | ---++ ObjectMethod i18n() | ||||
2040 | Get a reference to the i18n object. Done lazily because not everyone | ||||
2041 | needs the i18ner. | ||||
2042 | |||||
2043 | =cut | ||||
2044 | |||||
2045 | # spent 4.67ms (3.51+1.16) within Foswiki::i18n which was called 48 times, avg 97µs/call:
# 33 times (3.45ms+1.16ms) by Foswiki::MAKETEXT at line 50 of /var/www/foswiki11/lib/Foswiki/Macros/MAKETEXT.pm, avg 140µs/call
# 12 times (44µs+0s) by Foswiki::Search::formatResult at line 1195 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 4µs/call
# 3 times (12µs+0s) by Foswiki::Meta::haveAccess at line 1812 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 4µs/call | ||||
2046 | 48 | 26µs | my ($this) = @_; | ||
2047 | |||||
2048 | 48 | 29µs | unless ( $this->{i18n} ) { | ||
2049 | 1 | 161µs | require Foswiki::I18N; | ||
2050 | |||||
2051 | # language information; must be loaded after | ||||
2052 | # *all possible preferences sources* are available | ||||
2053 | 1 | 11µs | 1 | 1.00ms | $this->{i18n} = new Foswiki::I18N($this); # spent 1.00ms making 1 call to Foswiki::I18N::new |
2054 | } | ||||
2055 | 48 | 176µs | return $this->{i18n}; | ||
2056 | } | ||||
2057 | |||||
2058 | =begin TML | ||||
2059 | |||||
2060 | ---++ ObjectMethod logger() | ||||
2061 | |||||
2062 | =cut | ||||
2063 | |||||
2064 | # spent 2.96ms (2.55+416µs) within Foswiki::logger which was called 3 times, avg 988µs/call:
# once (2.53ms+416µs) by Foswiki::Plugins::load at line 205 of /var/www/foswiki11/lib/Foswiki/Plugins.pm
# once (10µs+0s) by Foswiki::Plugins::enable at line 272 of /var/www/foswiki11/lib/Foswiki/Plugins.pm
# once (8µs+0s) by Foswiki::logEvent at line 2269 | ||||
2065 | 3 | 4µs | my $this = shift; | ||
2066 | |||||
2067 | 3 | 3µs | unless ( $this->{logger} ) { | ||
2068 | 1 | 2µs | if ( $Foswiki::cfg{Log}{Implementation} eq 'none' ) { | ||
2069 | $this->{logger} = Foswiki::Logger->new(); | ||||
2070 | } | ||||
2071 | else { | ||||
2072 | 1 | 27µs | eval "require $Foswiki::cfg{Log}{Implementation}"; # spent 65µs executing statements in string eval | ||
2073 | 1 | 2µs | if ($@) { | ||
2074 | print STDERR "Logger load failed: $@"; | ||||
2075 | $this->{logger} = Foswiki::Logger->new(); | ||||
2076 | } | ||||
2077 | else { | ||||
2078 | 1 | 8µs | 1 | 9µs | $this->{logger} = $Foswiki::cfg{Log}{Implementation}->new(); # spent 9µs making 1 call to Foswiki::Logger::PlainFile::new |
2079 | } | ||||
2080 | } | ||||
2081 | } | ||||
2082 | |||||
2083 | 3 | 20µs | return $this->{logger}; | ||
2084 | } | ||||
2085 | |||||
2086 | =begin TML | ||||
2087 | |||||
2088 | ---++ ObjectMethod search() | ||||
2089 | Get a reference to the search object. Done lazily because not everyone | ||||
2090 | needs the searcher. | ||||
2091 | |||||
2092 | =cut | ||||
2093 | |||||
2094 | # spent 49.6ms (44.0+5.65) within Foswiki::search which was called 17563 times, avg 3µs/call:
# 8760 times (19.6ms+0s) by Foswiki::Search::InfoCache::addTopic at line 99 of /var/www/foswiki11/lib/Foswiki/Search/InfoCache.pm, avg 2µs/call
# 8760 times (19.1ms+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 230 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 2µs/call
# 40 times (5.32ms+5.65ms) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/SEARCH.pm:33] at line 32 of /var/www/foswiki11/lib/Foswiki/Macros/SEARCH.pm, avg 274µs/call
# once (8µs+0s) by Foswiki::Users::TopicUserMapping::_getListOfGroups at line 1630 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm
# once (2µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 114 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm
# once (2µs+0s) by Foswiki::Users::TopicUserMapping::_getListOfGroups at line 1636 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm | ||||
2095 | 17563 | 7.01ms | my ($this) = @_; | ||
2096 | |||||
2097 | 17563 | 8.18ms | unless ( $this->{search} ) { | ||
2098 | 1 | 73µs | require Foswiki::Search; | ||
2099 | 1 | 6µs | 1 | 10µs | $this->{search} = new Foswiki::Search($this); # spent 10µs making 1 call to Foswiki::Search::new |
2100 | } | ||||
2101 | 17563 | 91.2ms | return $this->{search}; | ||
2102 | } | ||||
2103 | |||||
2104 | =begin TML | ||||
2105 | |||||
2106 | ---++ ObjectMethod net() | ||||
2107 | Get a reference to the net object. Done lazily because not everyone | ||||
2108 | needs the net. | ||||
2109 | |||||
2110 | =cut | ||||
2111 | |||||
2112 | sub net { | ||||
2113 | my ($this) = @_; | ||||
2114 | |||||
2115 | unless ( $this->{net} ) { | ||||
2116 | require Foswiki::Net; | ||||
2117 | $this->{net} = new Foswiki::Net($this); | ||||
2118 | } | ||||
2119 | return $this->{net}; | ||||
2120 | } | ||||
2121 | |||||
2122 | =begin TML | ||||
2123 | |||||
2124 | ---++ ObjectMethod DESTROY() | ||||
2125 | |||||
2126 | called by Perl when the Foswiki object goes out of scope | ||||
2127 | (maybe should be used kist to ASSERT that finish() was called.. | ||||
2128 | |||||
2129 | =cut | ||||
2130 | |||||
2131 | #sub DESTROY { | ||||
2132 | # my $this = shift; | ||||
2133 | # $this->finish(); | ||||
2134 | #} | ||||
2135 | |||||
2136 | =begin TML | ||||
2137 | |||||
2138 | ---++ ObjectMethod finish() | ||||
2139 | Break circular references. | ||||
2140 | |||||
2141 | =cut | ||||
2142 | |||||
2143 | # Note to developers; please undef *all* fields in the object explicitly, | ||||
2144 | # whether they are references or not. That way this method is "golden | ||||
2145 | # documentation" of the live fields in the object. | ||||
2146 | # spent 12.5ms (2.32+10.2) within Foswiki::finish which was called:
# once (2.32ms+10.2ms) by Foswiki::UI::_execute at line 436 of /var/www/foswiki11/lib/Foswiki/UI.pm | ||||
2147 | 1 | 800ns | my $this = shift; | ||
2148 | |||||
2149 | # Print any macros that are never loaded | ||||
2150 | #print STDERR "NEVER USED\n"; | ||||
2151 | #for my $i (keys %macros) { | ||||
2152 | # print STDERR "\t$i\n" unless defined $macros{$i}; | ||||
2153 | #} | ||||
2154 | 1 | 5µs | $_->finish() foreach values %{ $this->{forms} }; | ||
2155 | 1 | 1µs | undef $this->{forms}; | ||
2156 | 1 | 3µs | foreach my $key ( | ||
2157 | qw(plugins users prefs templates renderer net | ||||
2158 | store search attach access security i18n cache) | ||||
2159 | ) | ||||
2160 | { | ||||
2161 | next | ||||
2162 | 13 | 16µs | unless ref( $this->{$key} ); | ||
2163 | 9 | 100µs | 9 | 10.2ms | $this->{$key}->finish(); # spent 4.10ms making 1 call to Foswiki::Prefs::finish
# spent 2.87ms making 1 call to Foswiki::Search::finish
# spent 1.79ms making 1 call to Foswiki::Users::finish
# spent 668µs making 1 call to Foswiki::Plugins::finish
# spent 659µs making 1 call to Foswiki::Templates::finish
# spent 40µs making 1 call to Foswiki::I18N::Fallback::finish
# spent 35µs making 1 call to Foswiki::Store::VC::Store::finish
# spent 8µs making 1 call to Foswiki::Render::finish
# spent 5µs making 1 call to Foswiki::Attach::finish |
2164 | 9 | 2.11ms | undef $this->{$key}; | ||
2165 | } | ||||
2166 | |||||
2167 | #TODO: the logger doesn't seem to have a finish... | ||||
2168 | # $this->{logger}->finish() if $this->{logger}; | ||||
2169 | 1 | 9µs | undef $this->{logger}; | ||
2170 | |||||
2171 | 1 | 1µs | undef $this->{_zones}; | ||
2172 | 1 | 400ns | undef $this->{_renderZonePlaceholder}; | ||
2173 | |||||
2174 | 1 | 400ns | undef $this->{request}; | ||
2175 | 1 | 1µs | undef $this->{cgiQuery}; | ||
2176 | |||||
2177 | 1 | 30µs | undef $this->{digester}; | ||
2178 | 1 | 2µs | 1 | 9µs | undef $this->{urlHost}; # spent 9µs making 1 call to Digest::MD5::DESTROY |
2179 | 1 | 4µs | undef $this->{web}; | ||
2180 | 1 | 300ns | undef $this->{topic}; | ||
2181 | 1 | 600ns | undef $this->{webName}; | ||
2182 | 1 | 300ns | undef $this->{topicName}; | ||
2183 | 1 | 7µs | undef $this->{_ICONSPACE}; | ||
2184 | 1 | 600ns | undef $this->{_EXT2ICON}; | ||
2185 | 1 | 900ns | undef $this->{_KNOWNICON}; | ||
2186 | 1 | 500ns | undef $this->{_ICONSTEMPLATE}; | ||
2187 | 1 | 400ns | undef $this->{context}; | ||
2188 | 1 | 500ns | undef $this->{remoteUser}; | ||
2189 | 1 | 1µs | undef $this->{requestedWebName}; # Web name before renaming | ||
2190 | 1 | 300ns | undef $this->{scriptUrlPath}; | ||
2191 | 1 | 500ns | undef $this->{user}; | ||
2192 | 1 | 800ns | undef $this->{_INCLUDES}; | ||
2193 | 1 | 300ns | undef $this->{response}; | ||
2194 | 1 | 1µs | undef $this->{evaluating_if}; | ||
2195 | 1 | 1µs | undef $this->{_addedToHEAD}; | ||
2196 | 1 | 1µs | undef $this->{sandbox}; | ||
2197 | 1 | 900ns | undef $this->{evaluatingEval}; | ||
2198 | |||||
2199 | 1 | 500ns | undef $this->{DebugVerificationCode}; # from Foswiki::UI::Register | ||
2200 | 1 | 4µs | 1 | 4µs | if (SINGLE_SINGLETONS_TRACE) { # spent 4µs making 1 call to Foswiki::SINGLE_SINGLETONS_TRACE |
2201 | require Data::Dumper; | ||||
2202 | print STDERR "finish $this: " | ||||
2203 | . Data::Dumper->Dump( [ [caller], [ caller(1) ] ] ); | ||||
2204 | } | ||||
2205 | 1 | 2µs | 1 | 2µs | if (SINGLE_SINGLETONS) { # spent 2µs making 1 call to Foswiki::SINGLE_SINGLETONS |
2206 | ASSERT( defined $Foswiki::Plugins::SESSION ); | ||||
2207 | ASSERT( $Foswiki::Plugins::SESSION == $this ); | ||||
2208 | ASSERT( $Foswiki::Plugins::SESSION->isa('Foswiki') ); | ||||
2209 | } | ||||
2210 | 1 | 400ns | undef $Foswiki::Plugins::SESSION; | ||
2211 | |||||
2212 | 1 | 8µs | 1 | 2µs | if (DEBUG) { # spent 2µs making 1 call to Assert::ASSERTS_OFF |
2213 | my $remaining = join ',', grep { defined $this->{$_} } keys %$this; | ||||
2214 | ASSERT( 0, | ||||
2215 | "Fields with defined values in " | ||||
2216 | . ref($this) | ||||
2217 | . "->finish(): " | ||||
2218 | . $remaining ) | ||||
2219 | if $remaining; | ||||
2220 | } | ||||
2221 | } | ||||
2222 | |||||
2223 | =begin TML | ||||
2224 | |||||
2225 | ---++ ObjectMethod logEvent( $action, $webTopic, $extra, $user ) | ||||
2226 | * =$action= - what happened, e.g. view, save, rename | ||||
2227 | * =$webTopic= - what it happened to | ||||
2228 | * =$extra= - extra info, such as minor flag | ||||
2229 | * =$user= - login name of user - default current user, | ||||
2230 | or failing that the user agent | ||||
2231 | |||||
2232 | Write the log for an event to the logfile | ||||
2233 | |||||
2234 | =cut | ||||
2235 | |||||
2236 | # spent 450µs (48+402) within Foswiki::logEvent which was called:
# once (48µs+402µs) by Foswiki::UI::View::view at line 213 of /var/www/foswiki11/lib/Foswiki/UI/View.pm | ||||
2237 | 1 | 2µs | my $this = shift; | ||
2238 | |||||
2239 | 1 | 500ns | my $action = shift || ''; | ||
2240 | 1 | 500ns | my $webTopic = shift || ''; | ||
2241 | 1 | 1µs | my $extra = shift || ''; | ||
2242 | 1 | 400ns | my $user = shift; | ||
2243 | |||||
2244 | return | ||||
2245 | 1 | 4µs | if ( defined $Foswiki::cfg{Log}{Action}{$action} | ||
2246 | && !$Foswiki::cfg{Log}{Action}{$action} ); | ||||
2247 | |||||
2248 | 1 | 1µs | $user ||= $this->{user}; | ||
2249 | 1 | 8µs | 1 | 10µs | $user = ( $this->{users}->getLoginName($user) || 'unknown' ) # spent 10µs making 1 call to Foswiki::Users::getLoginName |
2250 | if ( $this->{users} ); | ||||
2251 | |||||
2252 | 1 | 2µs | my $cgiQuery = $this->{request}; | ||
2253 | 1 | 500ns | if ($cgiQuery) { | ||
2254 | 1 | 4µs | 1 | 35µs | my $agent = $cgiQuery->user_agent(); # spent 35µs making 1 call to Foswiki::Request::userAgent |
2255 | 1 | 400ns | if ($agent) { | ||
2256 | $extra .= ' ' if $extra; | ||||
2257 | if ( $agent =~ /(MSIE 6|MSIE 7|Firefox|Opera|Konqueror|Safari)/ ) { | ||||
2258 | $extra .= $1; | ||||
2259 | } | ||||
2260 | else { | ||||
2261 | $agent =~ m/([\w]+)/; | ||||
2262 | $extra .= $1; | ||||
2263 | } | ||||
2264 | } | ||||
2265 | } | ||||
2266 | |||||
2267 | 1 | 6µs | 1 | 7µs | my $remoteAddr = $this->{request}->remoteAddress() || ''; # spent 7µs making 1 call to Foswiki::Request::remoteAddress |
2268 | |||||
2269 | 1 | 18µs | 2 | 350µs | $this->logger->log( 'info', $user, $action, $webTopic, $extra, # spent 342µs making 1 call to Foswiki::Logger::PlainFile::log
# spent 8µs making 1 call to Foswiki::logger |
2270 | $remoteAddr ); | ||||
2271 | } | ||||
2272 | |||||
2273 | =begin TML | ||||
2274 | |||||
2275 | ---++ StaticMethod validatePattern( $pattern ) -> $pattern | ||||
2276 | |||||
2277 | Validate a pattern provided in a parameter to $pattern so that | ||||
2278 | dangerous chars (interpolation and execution) are disabled. | ||||
2279 | |||||
2280 | =cut | ||||
2281 | |||||
2282 | sub validatePattern { | ||||
2283 | my $pattern = shift; | ||||
2284 | |||||
2285 | # Escape unescaped $ and @ characters that might interpolate | ||||
2286 | # an internal variable. | ||||
2287 | # There is no need to defuse (??{ and (?{ as perl won't allow | ||||
2288 | # it anyway, unless one uses re 'eval' which we won't do | ||||
2289 | $pattern =~ s/(^|[^\\])([\$\@])/$1\\$2/g; | ||||
2290 | return $pattern; | ||||
2291 | } | ||||
2292 | |||||
2293 | =begin TML | ||||
2294 | |||||
2295 | ---++ ObjectMethod inlineAlert($template, $def, ... ) -> $string | ||||
2296 | |||||
2297 | Format an error for inline inclusion in rendered output. The message string | ||||
2298 | is obtained from the template 'oops'.$template, and the DEF $def is | ||||
2299 | selected. The parameters (...) are used to populate %PARAM1%..%PARAMn% | ||||
2300 | |||||
2301 | =cut | ||||
2302 | |||||
2303 | sub inlineAlert { | ||||
2304 | my $this = shift; | ||||
2305 | my $template = shift; | ||||
2306 | my $def = shift; | ||||
2307 | |||||
2308 | # web and topic can be anything; they are not used | ||||
2309 | my $topicObject = | ||||
2310 | Foswiki::Meta->new( $this, $this->{webName}, $this->{topicName} ); | ||||
2311 | my $text = $this->templates->readTemplate( 'oops' . $template ); | ||||
2312 | if ($text) { | ||||
2313 | my $blah = $this->templates->expandTemplate($def); | ||||
2314 | $text =~ s/%INSTANTIATE%/$blah/; | ||||
2315 | |||||
2316 | $text = $topicObject->expandMacros($text); | ||||
2317 | my $n = 1; | ||||
2318 | while ( defined( my $param = shift ) ) { | ||||
2319 | $text =~ s/%PARAM$n%/$param/g; | ||||
2320 | $n++; | ||||
2321 | } | ||||
2322 | |||||
2323 | # Suppress missing params | ||||
2324 | $text =~ s/%PARAM\d+%//g; | ||||
2325 | |||||
2326 | # Suppress missing params | ||||
2327 | $text =~ s/%PARAM\d+%//g; | ||||
2328 | } | ||||
2329 | else { | ||||
2330 | |||||
2331 | # Error in the template system. | ||||
2332 | $text = $topicObject->renderTML(<<MESSAGE); | ||||
2333 | ---+ Foswiki Installation Error | ||||
2334 | Template 'oops$template' not found or returned no text, expanding $def. | ||||
2335 | |||||
2336 | Check your configuration settings for {TemplateDir} and {TemplatePath} | ||||
2337 | or check for syntax errors in templates, or a missing TMPL:END. | ||||
2338 | MESSAGE | ||||
2339 | } | ||||
2340 | |||||
2341 | return $text; | ||||
2342 | } | ||||
2343 | |||||
2344 | =begin TML | ||||
2345 | |||||
2346 | ---++ StaticMethod parseSections($text) -> ($string,$sectionlistref) | ||||
2347 | |||||
2348 | Generic parser for sections within a topic. Sections are delimited | ||||
2349 | by STARTSECTION and ENDSECTION, which may be nested, overlapped or | ||||
2350 | otherwise abused. The parser builds an array of sections, which is | ||||
2351 | ordered by the order of the STARTSECTION within the topic. It also | ||||
2352 | removes all the SECTION tags from the text, and returns the text | ||||
2353 | and the array of sections. | ||||
2354 | |||||
2355 | Each section is a =Foswiki::Attrs= object, which contains the attributes | ||||
2356 | {type, name, start, end} | ||||
2357 | where start and end are character offsets in the | ||||
2358 | string *after all section tags have been removed*. All sections | ||||
2359 | are required to be uniquely named; if a section is unnamed, it | ||||
2360 | will be given a generated name. Sections may overlap or nest. | ||||
2361 | |||||
2362 | See test/unit/Fn_SECTION.pm for detailed testcases that | ||||
2363 | round out the spec. | ||||
2364 | |||||
2365 | =cut | ||||
2366 | |||||
2367 | # spent 158µs within Foswiki::parseSections which was called 6 times, avg 26µs/call:
# 6 times (158µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm:331] at line 251 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 26µs/call | ||||
2368 | |||||
2369 | 6 | 11µs | my $text = shift; | ||
2370 | |||||
2371 | 6 | 2µs | return ( '', [] ) unless defined $text; | ||
2372 | |||||
2373 | 6 | 1µs | my %sections; | ||
2374 | 6 | 4µs | my @list = (); | ||
2375 | |||||
2376 | 6 | 2µs | my $seq = 0; | ||
2377 | 6 | 5µs | my $ntext = ''; | ||
2378 | 6 | 2µs | my $offset = 0; | ||
2379 | 6 | 47µs | foreach my $bit ( split( /(%(?:START|END)SECTION(?:{.*?})?%)/, $text ) ) { | ||
2380 | 6 | 26µs | if ( $bit =~ /^%STARTSECTION(?:{(.*)})?%$/ ) { | ||
2381 | require Foswiki::Attrs; | ||||
2382 | |||||
2383 | # SMELL: unchecked implicit untaint? | ||||
2384 | my $attrs = new Foswiki::Attrs($1); | ||||
2385 | $attrs->{type} ||= 'section'; | ||||
2386 | $attrs->{name} = | ||||
2387 | $attrs->{_DEFAULT} | ||||
2388 | || $attrs->{name} | ||||
2389 | || '_SECTION' . $seq++; | ||||
2390 | delete $attrs->{_DEFAULT}; | ||||
2391 | my $id = $attrs->{type} . ':' . $attrs->{name}; | ||||
2392 | if ( $sections{$id} ) { | ||||
2393 | |||||
2394 | # error, this named section already defined, ignore | ||||
2395 | next; | ||||
2396 | } | ||||
2397 | |||||
2398 | # close open unnamed sections of the same type | ||||
2399 | foreach my $s (@list) { | ||||
2400 | if ( $s->{end} < 0 | ||||
2401 | && $s->{type} eq $attrs->{type} | ||||
2402 | && $s->{name} =~ /^_SECTION\d+$/ ) | ||||
2403 | { | ||||
2404 | $s->{end} = $offset; | ||||
2405 | } | ||||
2406 | } | ||||
2407 | $attrs->{start} = $offset; | ||||
2408 | $attrs->{end} = -1; # open section | ||||
2409 | $sections{$id} = $attrs; | ||||
2410 | push( @list, $attrs ); | ||||
2411 | } | ||||
2412 | elsif ( $bit =~ /^%ENDSECTION(?:{(.*)})?%$/ ) { | ||||
2413 | require Foswiki::Attrs; | ||||
2414 | |||||
2415 | # SMELL: unchecked implicit untaint? | ||||
2416 | my $attrs = new Foswiki::Attrs($1); | ||||
2417 | $attrs->{type} ||= 'section'; | ||||
2418 | $attrs->{name} = $attrs->{_DEFAULT} || $attrs->{name} || ''; | ||||
2419 | delete $attrs->{_DEFAULT}; | ||||
2420 | unless ( $attrs->{name} ) { | ||||
2421 | |||||
2422 | # find the last open unnamed section of this type | ||||
2423 | foreach my $s ( reverse @list ) { | ||||
2424 | if ( $s->{end} == -1 | ||||
2425 | && $s->{type} eq $attrs->{type} | ||||
2426 | && $s->{name} =~ /^_SECTION\d+$/ ) | ||||
2427 | { | ||||
2428 | $attrs->{name} = $s->{name}; | ||||
2429 | last; | ||||
2430 | } | ||||
2431 | } | ||||
2432 | |||||
2433 | # ignore it if no matching START found | ||||
2434 | next unless $attrs->{name}; | ||||
2435 | } | ||||
2436 | my $id = $attrs->{type} . ':' . $attrs->{name}; | ||||
2437 | if ( !$sections{$id} || $sections{$id}->{end} >= 0 ) { | ||||
2438 | |||||
2439 | # error, no such open section, ignore | ||||
2440 | next; | ||||
2441 | } | ||||
2442 | $sections{$id}->{end} = $offset; | ||||
2443 | } | ||||
2444 | else { | ||||
2445 | 6 | 8µs | $ntext .= $bit; | ||
2446 | 6 | 4µs | $offset = length($ntext); | ||
2447 | } | ||||
2448 | } | ||||
2449 | |||||
2450 | # close open sections | ||||
2451 | 6 | 7µs | foreach my $s (@list) { | ||
2452 | $s->{end} = $offset if $s->{end} < 0; | ||||
2453 | } | ||||
2454 | |||||
2455 | 6 | 41µs | return ( $ntext, \@list ); | ||
2456 | } | ||||
2457 | |||||
2458 | =begin TML | ||||
2459 | |||||
2460 | ---++ ObjectMethod expandMacrosOnTopicCreation ( $topicObject ) | ||||
2461 | |||||
2462 | * =$topicObject= - the topic | ||||
2463 | |||||
2464 | Expand only that subset of Foswiki variables that are | ||||
2465 | expanded during topic creation, in the body text and | ||||
2466 | PREFERENCE meta only. The expansion is in-place inside | ||||
2467 | the topic object. | ||||
2468 | |||||
2469 | # SMELL: no plugin handler | ||||
2470 | |||||
2471 | =cut | ||||
2472 | |||||
2473 | sub expandMacrosOnTopicCreation { | ||||
2474 | my ( $this, $topicObject ) = @_; | ||||
2475 | |||||
2476 | # Make sure func works, for registered tag handlers | ||||
2477 | if (SINGLE_SINGLETONS) { | ||||
2478 | ASSERT( defined $Foswiki::Plugins::SESSION ); | ||||
2479 | ASSERT( $Foswiki::Plugins::SESSION == $this ); | ||||
2480 | } | ||||
2481 | local $Foswiki::Plugins::SESSION = $this; | ||||
2482 | ASSERT( $Foswiki::Plugins::SESSION->isa('Foswiki') ) if DEBUG; | ||||
2483 | |||||
2484 | my $text = $topicObject->text(); | ||||
2485 | if ($text) { | ||||
2486 | |||||
2487 | # Chop out templateonly sections | ||||
2488 | my ( $ntext, $sections ) = parseSections($text); | ||||
2489 | if ( scalar(@$sections) ) { | ||||
2490 | |||||
2491 | # Note that if named templateonly sections overlap, | ||||
2492 | # the behaviour is undefined. | ||||
2493 | foreach my $s ( reverse @$sections ) { | ||||
2494 | if ( $s->{type} eq 'templateonly' ) { | ||||
2495 | $ntext = | ||||
2496 | substr( $ntext, 0, $s->{start} ) | ||||
2497 | . substr( $ntext, $s->{end}, length($ntext) ); | ||||
2498 | } | ||||
2499 | else { | ||||
2500 | |||||
2501 | # put back non-templateonly sections | ||||
2502 | my $start = $s->remove('start'); | ||||
2503 | my $end = $s->remove('end'); | ||||
2504 | $ntext = | ||||
2505 | substr( $ntext, 0, $start ) | ||||
2506 | . '%STARTSECTION{' | ||||
2507 | . $s->stringify() . '}%' | ||||
2508 | . substr( $ntext, $start, $end - $start ) | ||||
2509 | . '%ENDSECTION{' | ||||
2510 | . $s->stringify() . '}%' | ||||
2511 | . substr( $ntext, $end, length($ntext) ); | ||||
2512 | } | ||||
2513 | } | ||||
2514 | $text = $ntext; | ||||
2515 | } | ||||
2516 | |||||
2517 | $text = _processMacros( $this, $text, \&_expandMacroOnTopicCreation, | ||||
2518 | $topicObject, 16 ); | ||||
2519 | |||||
2520 | # expand all variables for type="expandvariables" sections | ||||
2521 | ( $ntext, $sections ) = parseSections($text); | ||||
2522 | if ( scalar(@$sections) ) { | ||||
2523 | foreach my $s ( reverse @$sections ) { | ||||
2524 | if ( $s->{type} eq 'expandvariables' ) { | ||||
2525 | my $etext = | ||||
2526 | substr( $ntext, $s->{start}, $s->{end} - $s->{start} ); | ||||
2527 | $this->innerExpandMacros( \$etext, $topicObject ); | ||||
2528 | $ntext = | ||||
2529 | substr( $ntext, 0, $s->{start} ) | ||||
2530 | . $etext | ||||
2531 | . substr( $ntext, $s->{end}, length($ntext) ); | ||||
2532 | } | ||||
2533 | else { | ||||
2534 | |||||
2535 | # put back non-expandvariables sections | ||||
2536 | my $start = $s->remove('start'); | ||||
2537 | my $end = $s->remove('end'); | ||||
2538 | $ntext = | ||||
2539 | substr( $ntext, 0, $start ) | ||||
2540 | . '%STARTSECTION{' | ||||
2541 | . $s->stringify() . '}%' | ||||
2542 | . substr( $ntext, $start, $end - $start ) | ||||
2543 | . '%ENDSECTION{' | ||||
2544 | . $s->stringify() . '}%' | ||||
2545 | . substr( $ntext, $end, length($ntext) ); | ||||
2546 | } | ||||
2547 | } | ||||
2548 | $text = $ntext; | ||||
2549 | } | ||||
2550 | |||||
2551 | # kill markers used to prevent variable expansion | ||||
2552 | $text =~ s/%NOP%//g; | ||||
2553 | $topicObject->text($text); | ||||
2554 | } | ||||
2555 | |||||
2556 | # Expand preferences | ||||
2557 | my @prefs = $topicObject->find('PREFERENCE'); | ||||
2558 | foreach my $p (@prefs) { | ||||
2559 | $p->{value} = | ||||
2560 | _processMacros( $this, $p->{value}, \&_expandMacroOnTopicCreation, | ||||
2561 | $topicObject, 16 ); | ||||
2562 | |||||
2563 | # kill markers used to prevent variable expansion | ||||
2564 | $p->{value} =~ s/%NOP%//g; | ||||
2565 | |||||
2566 | } | ||||
2567 | } | ||||
2568 | |||||
2569 | =begin TML | ||||
2570 | |||||
2571 | ---++ StaticMethod entityEncode( $text, $extras ) -> $encodedText | ||||
2572 | |||||
2573 | Escape special characters to HTML numeric entities. This is *not* a generic | ||||
2574 | encoding, it is tuned specifically for use in Foswiki. | ||||
2575 | |||||
2576 | HTML4.0 spec: | ||||
2577 | "Certain characters in HTML are reserved for use as markup and must be | ||||
2578 | escaped to appear literally. The "<" character may be represented with | ||||
2579 | an <em>entity</em>, <strong class=html>&lt;</strong>. Similarly, ">" | ||||
2580 | is escaped as <strong class=html>&gt;</strong>, and "&" is escaped | ||||
2581 | as <strong class=html>&amp;</strong>. If an attribute value contains a | ||||
2582 | double quotation mark and is delimited by double quotation marks, then the | ||||
2583 | quote should be escaped as <strong class=html>&quot;</strong>. | ||||
2584 | |||||
2585 | Other entities exist for special characters that cannot easily be entered | ||||
2586 | with some keyboards..." | ||||
2587 | |||||
2588 | This method encodes HTML special and any non-printable ascii | ||||
2589 | characters (except for \n and \r) using numeric entities. | ||||
2590 | |||||
2591 | FURTHER this method also encodes characters that are special in Foswiki | ||||
2592 | meta-language. | ||||
2593 | |||||
2594 | $extras is an optional param that may be used to include *additional* | ||||
2595 | characters in the set of encoded characters. It should be a string | ||||
2596 | containing the additional chars. | ||||
2597 | |||||
2598 | =cut | ||||
2599 | |||||
2600 | sub entityEncode { | ||||
2601 | my ( $text, $extra ) = @_; | ||||
2602 | $extra ||= ''; | ||||
2603 | |||||
2604 | # encode all non-printable 7-bit chars (< \x1f), | ||||
2605 | # except \n (\xa) and \r (\xd) | ||||
2606 | # encode HTML special characters '>', '<', '&', ''' and '"'. | ||||
2607 | # encode TML special characters '%', '|', '[', ']', '@', '_', | ||||
2608 | # '*', and '=' | ||||
2609 | $text =~ | ||||
2610 | s/([[\x01-\x09\x0b\x0c\x0e-\x1f"%&'*<=>@[_\|$extra])/'&#'.ord($1).';'/ge; | ||||
2611 | return $text; | ||||
2612 | } | ||||
2613 | |||||
2614 | =begin TML | ||||
2615 | |||||
2616 | ---++ StaticMethod entityDecode ( $encodedText ) -> $text | ||||
2617 | |||||
2618 | Decodes all numeric entities (e.g. &#123;). _Does not_ decode | ||||
2619 | named entities such as &amp; (use HTML::Entities for that) | ||||
2620 | |||||
2621 | =cut | ||||
2622 | |||||
2623 | sub entityDecode { | ||||
2624 | my $text = shift; | ||||
2625 | |||||
2626 | $text =~ s/&#(\d+);/chr($1)/ge; | ||||
2627 | return $text; | ||||
2628 | } | ||||
2629 | |||||
2630 | =begin TML | ||||
2631 | |||||
2632 | ---++ StaticMethod urlEncodeAttachment ( $text ) | ||||
2633 | |||||
2634 | For attachments, URL-encode specially to 'freeze' any characters >127 in the | ||||
2635 | site charset (e.g. ISO-8859-1 or KOI8-R), by doing URL encoding into native | ||||
2636 | charset ($siteCharset) - used when generating attachment URLs, to enable the | ||||
2637 | web server to serve attachments, including images, directly. | ||||
2638 | |||||
2639 | This encoding is required to handle the cases of: | ||||
2640 | |||||
2641 | - browsers that generate UTF-8 URLs automatically from site charset URLs - now quite common | ||||
2642 | - web servers that directly serve attachments, using the site charset for | ||||
2643 | filenames, and cannot convert UTF-8 URLs into site charset filenames | ||||
2644 | |||||
2645 | The aim is to prevent the browser from converting a site charset URL in the web | ||||
2646 | page to a UTF-8 URL, which is the default. Hence we 'freeze' the URL into the | ||||
2647 | site character set through URL encoding. | ||||
2648 | |||||
2649 | In two cases, no URL encoding is needed: For EBCDIC mainframes, we assume that | ||||
2650 | site charset URLs will be translated (outbound and inbound) by the web server to/from an | ||||
2651 | EBCDIC character set. For sites running in UTF-8, there's no need for Foswiki to | ||||
2652 | do anything since all URLs and attachment filenames are already in UTF-8. | ||||
2653 | |||||
2654 | =cut | ||||
2655 | |||||
2656 | # spent 28µs (21+6) within Foswiki::urlEncodeAttachment which was called:
# once (21µs+6µs) by Foswiki::getPubUrl at line 1543 | ||||
2657 | 1 | 1µs | my ($text) = @_; | ||
2658 | |||||
2659 | 1 | 1µs | my $usingEBCDIC = ( 'A' eq chr(193) ); # Only true on EBCDIC mainframes | ||
2660 | |||||
2661 | 1 | 6µs | if ( | ||
2662 | ( | ||||
2663 | defined( $Foswiki::cfg{Site}{CharSet} ) | ||||
2664 | and $Foswiki::cfg{Site}{CharSet} =~ /^utf-?8$/i | ||||
2665 | ) | ||||
2666 | or $usingEBCDIC | ||||
2667 | ) | ||||
2668 | { | ||||
2669 | |||||
2670 | # Just let browser do UTF-8 URL encoding | ||||
2671 | return $text; | ||||
2672 | } | ||||
2673 | |||||
2674 | # Freeze into site charset through URL encoding | ||||
2675 | 1 | 12µs | 1 | 6µs | return urlEncode($text); # spent 6µs making 1 call to Foswiki::urlEncode |
2676 | } | ||||
2677 | |||||
2678 | =begin TML | ||||
2679 | |||||
2680 | ---++ StaticMethod urlEncode( $string ) -> encoded string | ||||
2681 | |||||
2682 | Encode by converting characters that are illegal in URLs to | ||||
2683 | their %NN equivalents. This method is used for encoding | ||||
2684 | strings that must be embedded _verbatim_ in URLs; it cannot | ||||
2685 | be applied to URLs themselves, as it escapes reserved | ||||
2686 | characters such as = and ?. | ||||
2687 | |||||
2688 | RFC 1738, Dec. '94: | ||||
2689 | <verbatim> | ||||
2690 | ...Only alphanumerics [0-9a-zA-Z], the special | ||||
2691 | characters $-_.+!*'(), and reserved characters used for their | ||||
2692 | reserved purposes may be used unencoded within a URL. | ||||
2693 | </verbatim> | ||||
2694 | |||||
2695 | Reserved characters are $&+,/:;=?@ - these are _also_ encoded by | ||||
2696 | this method. | ||||
2697 | |||||
2698 | This URL-encoding handles all character encodings including ISO-8859-*, | ||||
2699 | KOI8-R, EUC-* and UTF-8. | ||||
2700 | |||||
2701 | This may not handle EBCDIC properly, as it generates an EBCDIC URL-encoded | ||||
2702 | URL, but mainframe web servers seem to translate this outbound before it hits browser | ||||
2703 | - see CGI::Util::escape for another approach. | ||||
2704 | |||||
2705 | =cut | ||||
2706 | |||||
2707 | # spent 175µs within Foswiki::urlEncode which was called 56 times, avg 3µs/call:
# 23 times (89µs+0s) by Foswiki::getScriptUrl at line 1473, avg 4µs/call
# 12 times (36µs+0s) by Foswiki::_make_params at line 1493, avg 3µs/call
# 10 times (27µs+0s) by Foswiki::Request::queryString at line 207 of /var/www/foswiki11/lib/Foswiki/Request.pm, avg 3µs/call
# 10 times (17µs+0s) by Foswiki::Request::queryString at line 208 of /var/www/foswiki11/lib/Foswiki/Request.pm, avg 2µs/call
# once (6µs+0s) by Foswiki::urlEncodeAttachment at line 2675 | ||||
2708 | 56 | 27µs | my $text = shift; | ||
2709 | |||||
2710 | 56 | 53µs | $text =~ s/([^0-9a-zA-Z-_.:~!*'\/])/'%'.sprintf('%02x',ord($1))/ge; | ||
2711 | |||||
2712 | 56 | 179µs | return $text; | ||
2713 | } | ||||
2714 | |||||
2715 | =begin TML | ||||
2716 | |||||
2717 | ---++ StaticMethod urlDecode( $string ) -> decoded string | ||||
2718 | |||||
2719 | Reverses the encoding done in urlEncode. | ||||
2720 | |||||
2721 | =cut | ||||
2722 | |||||
2723 | sub urlDecode { | ||||
2724 | my $text = shift; | ||||
2725 | |||||
2726 | $text =~ s/%([\da-f]{2})/chr(hex($1))/gei; | ||||
2727 | |||||
2728 | return $text; | ||||
2729 | } | ||||
2730 | |||||
2731 | =begin TML | ||||
2732 | |||||
2733 | ---++ StaticMethod isTrue( $value, $default ) -> $boolean | ||||
2734 | |||||
2735 | Returns 1 if =$value= is true, and 0 otherwise. "true" means set to | ||||
2736 | something with a Perl true value, with the special cases that "off", | ||||
2737 | "false" and "no" (case insensitive) are forced to false. Leading and | ||||
2738 | trailing spaces in =$value= are ignored. | ||||
2739 | |||||
2740 | If the value is undef, then =$default= is returned. If =$default= is | ||||
2741 | not specified it is taken as 0. | ||||
2742 | |||||
2743 | =cut | ||||
2744 | |||||
2745 | # spent 7.13ms within Foswiki::isTrue which was called 1515 times, avg 5µs/call:
# 94 times (1.46ms+0s) by Foswiki::WebFilter::ok at line 39 of /var/www/foswiki11/lib/Foswiki/WebFilter.pm, avg 16µs/call
# 81 times (598µs+0s) by Foswiki::Search::InfoCache::sortResults at line 138 of /var/www/foswiki11/lib/Foswiki/Search/InfoCache.pm, avg 7µs/call
# 41 times (399µs+0s) by Foswiki::Search::searchWeb at line 400 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 10µs/call
# 41 times (339µs+0s) by Foswiki::Search::InfoCache::_getListOfWebs at line 442 of /var/www/foswiki11/lib/Foswiki/Search/InfoCache.pm, avg 8µs/call
# 41 times (313µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::query at line 66 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 8µs/call
# 41 times (305µs+0s) by Foswiki::Search::searchWeb at line 258 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 7µs/call
# 41 times (238µs+0s) by Foswiki::Search::searchWeb at line 295 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 6µs/call
# 41 times (219µs+0s) by Foswiki::Search::searchWeb at line 260 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 5µs/call
# 41 times (215µs+0s) by Foswiki::Search::formatResults at line 601 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 5µs/call
# 41 times (194µs+0s) by Foswiki::Search::formatResults at line 722 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 5µs/call
# 41 times (182µs+0s) by Foswiki::Search::formatResults at line 723 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 4µs/call
# 41 times (182µs+0s) by Foswiki::Search::formatResults at line 603 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 4µs/call
# 41 times (120µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::query at line 82 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 3µs/call
# 41 times (92µs+0s) by Foswiki::Search::searchWeb at line 250 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (80µs+0s) by Foswiki::Search::searchWeb at line 401 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (80µs+0s) by Foswiki::Search::searchWeb at line 277 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (77µs+0s) by Foswiki::Search::searchWeb at line 261 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (72µs+0s) by Foswiki::Search::formatResults at line 602 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (69µs+0s) by Foswiki::Search::searchWeb at line 293 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (68µs+0s) by Foswiki::Search::searchWeb at line 299 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (66µs+0s) by Foswiki::Search::formatResults at line 735 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (66µs+0s) by Foswiki::Search::formatResults at line 600 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (64µs+0s) by Foswiki::Search::formatResults at line 604 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (62µs+0s) by Foswiki::Search::searchWeb at line 255 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 41 times (61µs+0s) by Foswiki::Search::searchWeb at line 309 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 1µs/call
# 41 times (57µs+0s) by Foswiki::Search::searchWeb at line 315 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 1µs/call
# 41 times (55µs+0s) by Foswiki::Search::formatResults at line 738 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 1µs/call
# 41 times (55µs+0s) by Foswiki::Search::formatResults at line 736 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 1µs/call
# 41 times (54µs+0s) by Foswiki::Search::searchWeb at line 310 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 1µs/call
# 41 times (53µs+0s) by Foswiki::Search::searchWeb at line 317 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 1µs/call
# 40 times (320µs+0s) by Foswiki::Store::SearchAlgorithms::Forking::query at line 171 of /var/www/foswiki11/lib/Foswiki/Store/SearchAlgorithms/Forking.pm, avg 8µs/call
# 40 times (278µs+0s) by Foswiki::Search::InfoCache::_getListOfWebs at line 488 of /var/www/foswiki11/lib/Foswiki/Search/InfoCache.pm, avg 7µs/call
# 40 times (215µs+0s) by Foswiki::Store::SearchAlgorithms::Forking::query at line 187 of /var/www/foswiki11/lib/Foswiki/Store/SearchAlgorithms/Forking.pm, avg 5µs/call
# 40 times (90µs+0s) by Foswiki::Search::searchWeb at line 460 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 2µs/call
# 14 times (95µs+0s) by Foswiki::Func::getPreferencesFlag at line 819 of /var/www/foswiki11/lib/Foswiki/Func.pm, avg 7µs/call
# 6 times (112µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm:331] at line 291 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 19µs/call
# 5 times (50µs+0s) by Foswiki::Render::getRenderedVersion at line 1428 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 10µs/call
# 3 times (8µs+0s) by Foswiki::URLPARAM at line 20 of /var/www/foswiki11/lib/Foswiki/Macros/URLPARAM.pm, avg 3µs/call
# 2 times (11µs+0s) by Foswiki::Func::isTrue at line 2966 of /var/www/foswiki11/lib/Foswiki/Func.pm, avg 5µs/call
# once (54µs+0s) by Foswiki::_includeWarning at line 94 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm
# once (2µs+0s) by Foswiki::Search::searchWeb at line 304 of /var/www/foswiki11/lib/Foswiki/Search.pm | ||||
2746 | 1515 | 1.02ms | my ( $value, $default ) = @_; | ||
2747 | |||||
2748 | 1515 | 417µs | $default ||= 0; | ||
2749 | |||||
2750 | 1515 | 2.76ms | return $default unless defined($value); | ||
2751 | |||||
2752 | 607 | 3.07ms | $value =~ s/^\s*(.*?)\s*$/$1/gi; | ||
2753 | 607 | 152µs | $value =~ s/off//gi; | ||
2754 | 607 | 130µs | $value =~ s/no//gi; | ||
2755 | 607 | 115µs | $value =~ s/false//gi; | ||
2756 | 607 | 5.77ms | return ($value) ? 1 : 0; | ||
2757 | } | ||||
2758 | |||||
2759 | =begin TML | ||||
2760 | |||||
2761 | ---++ StaticMethod spaceOutWikiWord( $word, $sep ) -> $string | ||||
2762 | |||||
2763 | Spaces out a wiki word by inserting a string (default: one space) between each word component. | ||||
2764 | With parameter $sep any string may be used as separator between the word components; if $sep is undefined it defaults to a space. | ||||
2765 | |||||
2766 | =cut | ||||
2767 | |||||
2768 | # spent 88µs within Foswiki::spaceOutWikiWord which was called 2 times, avg 44µs/call:
# 2 times (88µs+0s) by Foswiki::SPACEOUT at line 11 of /var/www/foswiki11/lib/Foswiki/Macros/SPACEOUT.pm, avg 44µs/call | ||||
2769 | 2 | 2µs | my ( $word, $sep ) = @_; | ||
2770 | |||||
2771 | # Both could have the value 0 so we cannot use simple = || '' | ||||
2772 | 2 | 1µs | $word = defined($word) ? $word : ''; | ||
2773 | 2 | 2µs | $sep = defined($sep) ? $sep : ' '; | ||
2774 | 2 | 52µs | $word =~ | ||
2775 | s/([$regex{lowerAlpha}])([$regex{upperAlpha}$regex{numeric}]+)/$1$sep$2/go; | ||||
2776 | 2 | 17µs | $word =~ s/([$regex{numeric}])([$regex{upperAlpha}])/$1$sep$2/go; | ||
2777 | 2 | 15µs | return $word; | ||
2778 | } | ||||
2779 | |||||
2780 | =begin TML | ||||
2781 | |||||
2782 | ---++ ObjectMethod innerExpandMacros(\$text, $topicObject) | ||||
2783 | Expands variables by replacing the variables with their | ||||
2784 | values. Some example variables: %<nop>TOPIC%, %<nop>SCRIPTURL%, | ||||
2785 | %<nop>WIKINAME%, etc. | ||||
2786 | $web and $incs are passed in for recursive include expansion. They can | ||||
2787 | safely be undef. | ||||
2788 | The rules for tag expansion are: | ||||
2789 | 1 Tags are expanded left to right, in the order they are encountered. | ||||
2790 | 1 Tags are recursively expanded as soon as they are encountered - | ||||
2791 | the algorithm is inherently single-pass | ||||
2792 | 1 A tag is not "encountered" until the matching }% has been seen, by | ||||
2793 | which time all tags in parameters will have been expanded | ||||
2794 | 1 Tag expansions that create new tags recursively are limited to a | ||||
2795 | set number of hierarchical levels of expansion | ||||
2796 | |||||
2797 | =cut | ||||
2798 | |||||
2799 | # spent 59.1s (2.01ms+59.1) within Foswiki::innerExpandMacros which was called 49 times, avg 1.21s/call:
# 18 times (646µs+-646µs) by Foswiki::If::OP_dollar::evaluate at line 40 of /var/www/foswiki11/lib/Foswiki/If/OP_dollar.pm, avg 0s/call
# 7 times (290µs+59.1s) by Foswiki::expandMacros at line 3342, avg 8.44s/call
# 7 times (256µs+952µs) by Foswiki::expandMacros at line 3352, avg 173µs/call
# 6 times (271µs+-271µs) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm:331] at line 310 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 0s/call
# 6 times (356µs+-356µs) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm:331] at line 297 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 0s/call
# 5 times (193µs+-193µs) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm:331] at line 328 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 0s/call | ||||
2800 | 49 | 36µs | my ( $this, $text, $topicObject ) = @_; | ||
2801 | |||||
2802 | # push current context | ||||
2803 | 49 | 102µs | 49 | 377µs | my $memTopic = $this->{prefs}->getPreference('TOPIC'); # spent 377µs making 49 calls to Foswiki::Prefs::getPreference, avg 8µs/call |
2804 | 49 | 96µs | 49 | 297µs | my $memWeb = $this->{prefs}->getPreference('WEB'); # spent 297µs making 49 calls to Foswiki::Prefs::getPreference, avg 6µs/call |
2805 | |||||
2806 | # Historically this couldn't be called on web objects. | ||||
2807 | 49 | 108µs | 49 | 115µs | my $webContext = $topicObject->web || $this->{webName}; # spent 115µs making 49 calls to Foswiki::Meta::web, avg 2µs/call |
2808 | 49 | 90µs | 49 | 111µs | my $topicContext = $topicObject->topic || $this->{topicName}; # spent 111µs making 49 calls to Foswiki::Meta::topic, avg 2µs/call |
2809 | |||||
2810 | 49 | 88µs | 49 | 401µs | $this->{prefs}->setInternalPreferences( # spent 401µs making 49 calls to Foswiki::Prefs::setInternalPreferences, avg 8µs/call |
2811 | TOPIC => $topicContext, | ||||
2812 | WEB => $webContext | ||||
2813 | ); | ||||
2814 | |||||
2815 | # Escape ' !%VARIABLE%' | ||||
2816 | 49 | 220µs | $$text =~ s/(?<=\s)!%($regex{tagNameRegex})/%$1/g; | ||
2817 | |||||
2818 | # Make sure func works, for registered tag handlers | ||||
2819 | 49 | 117µs | 49 | 108µs | if (SINGLE_SINGLETONS) { # spent 108µs making 49 calls to Foswiki::SINGLE_SINGLETONS, avg 2µs/call |
2820 | ASSERT( defined $Foswiki::Plugins::SESSION ); | ||||
2821 | ASSERT( $Foswiki::Plugins::SESSION == $this ); | ||||
2822 | } | ||||
2823 | 49 | 34µs | local $Foswiki::Plugins::SESSION = $this; | ||
2824 | 49 | 67µs | 49 | 53µs | ASSERT( $Foswiki::Plugins::SESSION->isa('Foswiki') ) if DEBUG; # spent 53µs making 49 calls to Assert::ASSERTS_OFF, avg 1µs/call |
2825 | |||||
2826 | # NOTE TO DEBUGGERS | ||||
2827 | # The depth parameter in the following call controls the maximum number | ||||
2828 | # of levels of expansion. If it is set to 1 then only macros in the | ||||
2829 | # topic will be expanded; macros that they in turn generate will be | ||||
2830 | # left unexpanded. If it is set to 2 then the expansion will stop after | ||||
2831 | # the first recursive inclusion, and so on. This is incredible useful | ||||
2832 | # when debugging. The default, 16, was selected empirically. | ||||
2833 | 49 | 164µs | 49 | 59.1s | $$text = _processMacros( $this, $$text, \&_expandMacroOnTopicRendering, # spent 76.5s making 49 calls to Foswiki::_processMacros, avg 1.56s/call, recursion: max depth 4, sum of overlapping time 17.4s |
2834 | $topicObject, 16 ); | ||||
2835 | |||||
2836 | # restore previous context | ||||
2837 | 49 | 291µs | 49 | 397µs | $this->{prefs}->setInternalPreferences( # spent 397µs making 49 calls to Foswiki::Prefs::setInternalPreferences, avg 8µs/call |
2838 | TOPIC => $memTopic, | ||||
2839 | WEB => $memWeb | ||||
2840 | ); | ||||
2841 | } | ||||
2842 | |||||
2843 | =begin TML | ||||
2844 | |||||
2845 | ---++ StaticMethod takeOutBlocks( \$text, $tag, \%map ) -> $text | ||||
2846 | * =$text= - Text to process | ||||
2847 | * =$tag= - XML-style tag. | ||||
2848 | * =\%map= - Reference to a hash to contain the removed blocks | ||||
2849 | |||||
2850 | Return value: $text with blocks removed | ||||
2851 | |||||
2852 | Searches through $text and extracts blocks delimited by an XML-style tag, | ||||
2853 | storing the extracted block, and replacing with a token string which is | ||||
2854 | not affected by TML rendering. The text after these substitutions is | ||||
2855 | returned. | ||||
2856 | |||||
2857 | =cut | ||||
2858 | |||||
2859 | # spent 2.00ms within Foswiki::takeOutBlocks which was called 106 times, avg 19µs/call:
# 71 times (657µs+0s) by Foswiki::_processMacros at line 2988, avg 9µs/call
# 7 times (188µs+0s) by Foswiki::expandMacros at line 3324, avg 27µs/call
# 7 times (185µs+0s) by Foswiki::expandMacros at line 3344, avg 26µs/call
# 6 times (169µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm:331] at line 300 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 28µs/call
# 5 times (485µs+0s) by Foswiki::Render::getRenderedVersion at line 1130 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 97µs/call
# 5 times (169µs+0s) by Foswiki::Render::getRenderedVersion at line 1129 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 34µs/call
# 5 times (145µs+0s) by Foswiki::Render::getRenderedVersion at line 1161 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 29µs/call | ||||
2860 | 106 | 144µs | my ( $intext, $tag, $map ) = @_; | ||
2861 | |||||
2862 | 106 | 1.75ms | return $intext unless ( $intext =~ m/<$tag\b/i ); | ||
2863 | |||||
2864 | 2 | 900ns | my $out = ''; | ||
2865 | 2 | 400ns | my $depth = 0; | ||
2866 | 2 | 300ns | my $scoop; | ||
2867 | 2 | 400ns | my $tagParams; | ||
2868 | |||||
2869 | 2 | 63µs | foreach my $token ( split( /(<\/?$tag[^>]*>)/i, $intext ) ) { | ||
2870 | 58 | 106µs | if ( $token =~ /<$tag\b([^>]*)?>/i ) { | ||
2871 | 14 | 3µs | $depth++; | ||
2872 | 14 | 6µs | if ( $depth eq 1 ) { | ||
2873 | 14 | 10µs | $tagParams = $1; | ||
2874 | 14 | 4µs | next; | ||
2875 | } | ||||
2876 | } | ||||
2877 | elsif ( $token =~ /<\/$tag>/i ) { | ||||
2878 | 14 | 3µs | if ( $depth > 0 ) { | ||
2879 | 14 | 10µs | $depth--; | ||
2880 | 14 | 4µs | if ( $depth eq 0 ) { | ||
2881 | 14 | 7µs | my $placeholder = "$tag$BLOCKID"; | ||
2882 | 14 | 2µs | $BLOCKID++; | ||
2883 | 14 | 25µs | $map->{$placeholder}{text} = $scoop; | ||
2884 | 14 | 12µs | $map->{$placeholder}{params} = $tagParams; | ||
2885 | 14 | 9µs | $out .= "$OC$placeholder$CC"; | ||
2886 | 14 | 2µs | $scoop = ''; | ||
2887 | 14 | 4µs | next; | ||
2888 | } | ||||
2889 | } | ||||
2890 | } | ||||
2891 | 30 | 17µs | if ( $depth > 0 ) { | ||
2892 | $scoop .= $token; | ||||
2893 | } | ||||
2894 | else { | ||||
2895 | 16 | 8µs | $out .= $token; | ||
2896 | } | ||||
2897 | } | ||||
2898 | |||||
2899 | # unmatched tags | ||||
2900 | 2 | 2µs | if ( defined($scoop) && ( $scoop ne '' ) ) { | ||
2901 | my $placeholder = "$tag$BLOCKID"; | ||||
2902 | $BLOCKID++; | ||||
2903 | $map->{$placeholder}{text} = $scoop; | ||||
2904 | $map->{$placeholder}{params} = $tagParams; | ||||
2905 | $out .= "$OC$placeholder$CC"; | ||||
2906 | } | ||||
2907 | |||||
2908 | 2 | 17µs | return $out; | ||
2909 | } | ||||
2910 | |||||
2911 | =begin TML | ||||
2912 | |||||
2913 | ---++ StaticMethod putBackBlocks( \$text, \%map, $tag, $newtag, $callBack ) -> $text | ||||
2914 | |||||
2915 | Return value: $text with blocks added back | ||||
2916 | * =\$text= - reference to text to process | ||||
2917 | * =\%map= - map placeholders to blocks removed by takeOutBlocks | ||||
2918 | * =$tag= - Tag name processed by takeOutBlocks | ||||
2919 | * =$newtag= - Tag name to use in output, in place of $tag. | ||||
2920 | If undefined, uses $tag. | ||||
2921 | * =$callback= - Reference to function to call on each block | ||||
2922 | being inserted (optional) | ||||
2923 | |||||
2924 | Reverses the actions of takeOutBlocks. | ||||
2925 | |||||
2926 | Each replaced block is processed by the callback (if there is one) before | ||||
2927 | re-insertion. | ||||
2928 | |||||
2929 | Parameters to the outermost cut block are replaced into the open tag, | ||||
2930 | even if that tag is changed. This allows things like =<verbatim class=''>= | ||||
2931 | to be changed to =<pre class=''>= | ||||
2932 | |||||
2933 | If you set $newtag to '', replaces the taken-out block with the contents | ||||
2934 | of the block, not including the open/close. This is used for <literal>, | ||||
2935 | for example. | ||||
2936 | |||||
2937 | =cut | ||||
2938 | |||||
2939 | # spent 830µs (795+35) within Foswiki::putBackBlocks which was called 99 times, avg 8µs/call:
# 71 times (354µs+0s) by Foswiki::_processMacros at line 3110, avg 5µs/call
# 7 times (30µs+0s) by Foswiki::expandMacros at line 3377, avg 4µs/call
# 6 times (29µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm:331] at line 306 of /var/www/foswiki11/lib/Foswiki/Macros/INCLUDE.pm, avg 5µs/call
# 5 times (276µs+35µs) by Foswiki::Render::getRenderedVersion at line 1456 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 62µs/call
# 5 times (58µs+0s) by Foswiki::Render::getRenderedVersion at line 1445 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 12µs/call
# 5 times (48µs+0s) by Foswiki::Render::getRenderedVersion at line 1451 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 10µs/call | ||||
2940 | 99 | 91µs | my ( $text, $map, $tag, $newtag, $callback ) = @_; | ||
2941 | |||||
2942 | 99 | 39µs | $newtag = $tag if ( !defined($newtag) ); | ||
2943 | |||||
2944 | 99 | 482µs | foreach my $placeholder ( keys %$map ) { | ||
2945 | 72 | 116µs | if ( $placeholder =~ /^$tag\d+$/ ) { | ||
2946 | 14 | 12µs | my $params = $map->{$placeholder}{params} || ''; | ||
2947 | 14 | 7µs | my $val = $map->{$placeholder}{text}; | ||
2948 | 14 | 24µs | 14 | 35µs | $val = &$callback($val) if ( defined($callback) ); # spent 35µs making 14 calls to Foswiki::Render::_filterLiteral, avg 3µs/call |
2949 | 14 | 9µs | if ( $newtag eq '' ) { | ||
2950 | 14 | 116µs | $$text =~ s($OC$placeholder$CC)($val); | ||
2951 | } | ||||
2952 | else { | ||||
2953 | $$text =~ s($OC$placeholder$CC) | ||||
2954 | (<$newtag$params>$val</$newtag>); | ||||
2955 | } | ||||
2956 | 14 | 19µs | delete( $map->{$placeholder} ); | ||
2957 | } | ||||
2958 | } | ||||
2959 | } | ||||
2960 | |||||
2961 | # Process Foswiki %TAGS{}% by parsing the input tokenised into | ||||
2962 | # % separated sections. The parser is a simple stack-based parse, | ||||
2963 | # sufficient to ensure nesting of tags is correct, but no more | ||||
2964 | # than that. | ||||
2965 | # $depth limits the number of recursive expansion steps that | ||||
2966 | # can be performed on expanded tags. | ||||
2967 | sub _processMacros { | ||||
2968 | 86 | 155µs | my ( $this, $text, $tagf, $topicObject, $depth ) = @_; | ||
2969 | 86 | 26µs | my $tell = 0; | ||
2970 | |||||
2971 | 86 | 57µs | return '' if ( ( !defined($text) ) | ||
2972 | || ( $text eq '' ) ); | ||||
2973 | |||||
2974 | #no tags to process | ||||
2975 | 86 | 220µs | return $text unless ( $text =~ /%/ ); | ||
2976 | |||||
2977 | 71 | 14µs | unless ($depth) { | ||
2978 | my $mess = "Max recursive depth reached: $text"; | ||||
2979 | $this->logger->log( 'warning', $mess ); | ||||
2980 | |||||
2981 | # prevent recursive expansion that just has been detected | ||||
2982 | # from happening in the error message | ||||
2983 | $text =~ s/%(.*?)%/$1/go; | ||||
2984 | return $text; | ||||
2985 | } | ||||
2986 | |||||
2987 | 71 | 46µs | my $verbatim = {}; | ||
2988 | 71 | 135µs | 71 | 657µs | $text = takeOutBlocks( $text, 'verbatim', $verbatim ); # spent 657µs making 71 calls to Foswiki::takeOutBlocks, avg 9µs/call |
2989 | |||||
2990 | 71 | 33µs | my $dirtyAreas = {}; | ||
2991 | 71 | 65µs | $text = takeOutBlocks( $text, 'dirtyarea', $dirtyAreas ) | ||
2992 | if $Foswiki::cfg{Cache}{Enabled}; | ||||
2993 | |||||
2994 | 71 | 1.24ms | my @queue = split( /(%)/, $text ); | ||
2995 | 71 | 12µs | my @stack; | ||
2996 | 71 | 31µs | my $stackTop = ''; # the top stack entry. Done this way instead of | ||
2997 | # referring to the top of the stack for efficiency. This var | ||||
2998 | # should be considered to be $stack[$#stack] | ||||
2999 | |||||
3000 | 71 | 264µs | while ( scalar(@queue) ) { | ||
3001 | |||||
3002 | #print STDERR "QUEUE:".join("\n ", map { "'$_'" } @queue)."\n"; | ||||
3003 | 1887 | 791µs | my $token = shift(@queue); | ||
3004 | |||||
3005 | #print STDERR ' ' x $tell,"PROCESSING $token \n"; | ||||
3006 | |||||
3007 | # each % sign either closes an existing stacked context, or | ||||
3008 | # opens a new context. | ||||
3009 | 1887 | 1.13ms | if ( $token eq '%' ) { | ||
3010 | |||||
3011 | #print STDERR ' ' x $tell,"CONSIDER $stackTop\n"; | ||||
3012 | # If this is a closing }%, try to rejoin the previous | ||||
3013 | # tokens until we get to a valid tag construct. This is | ||||
3014 | # a bit of a hack, but it's hard to think of a better | ||||
3015 | # way to do this without a full parse that takes % signs | ||||
3016 | # in tag parameters into account. | ||||
3017 | 923 | 540µs | if ( $stackTop =~ /}$/s ) { | ||
3018 | 231 | 963µs | while ( scalar(@stack) | ||
3019 | && $stackTop !~ /^%$regex{tagNameRegex}\{.*}$/so ) | ||||
3020 | { | ||||
3021 | 18 | 7µs | my $top = $stackTop; | ||
3022 | |||||
3023 | #print STDERR ' ' x $tell,"COLLAPSE $top \n"; | ||||
3024 | 18 | 48µs | $stackTop = pop(@stack) . $top; | ||
3025 | } | ||||
3026 | } | ||||
3027 | |||||
3028 | # /s so you can have newlines in parameters | ||||
3029 | 923 | 2.36ms | if ( $stackTop =~ m/^%(($regex{tagNameRegex})(?:{(.*)})?)$/so ) { | ||
3030 | |||||
3031 | # SMELL: unchecked implicit untaint? | ||||
3032 | 452 | 981µs | my ( $expr, $tag, $args ) = ( $1, $2, $3 ); | ||
3033 | |||||
3034 | #print STDERR ' ' x $tell,"POP $tag\n"; | ||||
3035 | #Monitor::MARK("Before $tag"); | ||||
3036 | 452 | 1.06ms | 452 | 59.1s | my $e = &$tagf( $this, $tag, $args, $topicObject ); # spent 76.5s making 452 calls to Foswiki::_expandMacroOnTopicRendering, avg 169ms/call, recursion: max depth 3, sum of overlapping time 17.4s |
3037 | |||||
3038 | #Monitor::MARK("After $tag"); | ||||
3039 | |||||
3040 | 452 | 171µs | if ( defined($e) ) { | ||
3041 | |||||
3042 | #print STDERR ' ' x $tell--,"EXPANDED $tag -> $e\n"; | ||||
3043 | 442 | 367µs | $stackTop = pop(@stack); | ||
3044 | |||||
3045 | # Don't bother recursively expanding unless there are | ||||
3046 | # unexpanded tags in the result. | ||||
3047 | 442 | 863µs | unless ( $e =~ /%$regex{tagNameRegex}(?:{.*})?%/so ) { | ||
3048 | 405 | 425µs | $stackTop .= $e; | ||
3049 | 405 | 317µs | next; | ||
3050 | } | ||||
3051 | |||||
3052 | # Recursively expand tags in the expansion of $tag | ||||
3053 | $stackTop .= | ||||
3054 | 37 | 202µs | 37 | 0s | $this->_processMacros( $e, $tagf, $topicObject, # spent 9.34s making 37 calls to Foswiki::_processMacros, avg 252ms/call, recursion: max depth 5, sum of overlapping time 9.34s |
3055 | $depth - 1 ); | ||||
3056 | } | ||||
3057 | else { | ||||
3058 | |||||
3059 | #print STDERR ' ' x $tell++,"EXPAND $tag FAILED\n"; | ||||
3060 | # To handle %NOP | ||||
3061 | # correctly, we have to handle the %VAR% case differently | ||||
3062 | # to the %VAR{}% case when a variable expansion fails. | ||||
3063 | # This is so that recursively define variables e.g. | ||||
3064 | # %A%B%D% expand correctly, but at the same time we ensure | ||||
3065 | # that a mismatched }% can't accidentally close a context | ||||
3066 | # that was left open when a tag expansion failed. | ||||
3067 | # However TWiki didn't do this, so for compatibility | ||||
3068 | # we have to accept that %NOP can never be fixed. if it | ||||
3069 | # could, then we could uncomment the following: | ||||
3070 | |||||
3071 | #if( $stackTop =~ /}$/ ) { | ||||
3072 | # # %VAR{...}% case | ||||
3073 | # # We need to push the unexpanded expression back | ||||
3074 | # # onto the stack, but we don't want it to match the | ||||
3075 | # # tag expression again. So we protect the %'s | ||||
3076 | # $stackTop = "%$expr%"; | ||||
3077 | #} else | ||||
3078 | #{ | ||||
3079 | |||||
3080 | # %VAR% case. | ||||
3081 | # In this case we *do* want to match the tag expression | ||||
3082 | # again, as an embedded %VAR% may have expanded to | ||||
3083 | # create a valid outer expression. This is directly | ||||
3084 | # at odds with the %VAR{...}% case. | ||||
3085 | 10 | 7µs | push( @stack, $stackTop ); | ||
3086 | 10 | 3µs | $stackTop = '%'; # open new context | ||
3087 | #} | ||||
3088 | } | ||||
3089 | } | ||||
3090 | else { | ||||
3091 | 471 | 602µs | push( @stack, $stackTop ); | ||
3092 | 471 | 164µs | $stackTop = '%'; # push a new context | ||
3093 | #$tell++; | ||||
3094 | } | ||||
3095 | } | ||||
3096 | else { | ||||
3097 | 964 | 499µs | $stackTop .= $token; | ||
3098 | } | ||||
3099 | } | ||||
3100 | |||||
3101 | # Run out of input. Gather up everything in the stack. | ||||
3102 | 71 | 34µs | while ( scalar(@stack) ) { | ||
3103 | 21 | 37µs | my $expr = $stackTop; | ||
3104 | 21 | 12µs | $stackTop = pop(@stack); | ||
3105 | 21 | 61µs | $stackTop .= $expr; | ||
3106 | } | ||||
3107 | |||||
3108 | 71 | 51µs | putBackBlocks( \$stackTop, $dirtyAreas, 'dirtyarea' ) | ||
3109 | if $Foswiki::cfg{Cache}{Enabled}; | ||||
3110 | 71 | 145µs | 71 | 354µs | putBackBlocks( \$stackTop, $verbatim, 'verbatim' ); # spent 354µs making 71 calls to Foswiki::putBackBlocks, avg 5µs/call |
3111 | |||||
3112 | #print STDERR "FINAL $stackTop\n"; | ||||
3113 | |||||
3114 | 71 | 368µs | return $stackTop; | ||
3115 | } | ||||
3116 | |||||
3117 | # Handle expansion of a tag during topic rendering | ||||
3118 | # $tag is the tag name | ||||
3119 | # $args is the bit in the {} (if there are any) | ||||
3120 | # $topicObject should be passed for dynamic tags (not needed for | ||||
3121 | # session or constant tags | ||||
3122 | sub _expandMacroOnTopicRendering { | ||||
3123 | 454 | 411µs | my ( $this, $tag, $args, $topicObject ) = @_; | ||
3124 | |||||
3125 | 454 | 268µs | require Foswiki::Attrs; | ||
3126 | 454 | 75µs | my $attrs; | ||
3127 | |||||
3128 | 454 | 906µs | 454 | 11.3ms | my $e = $this->{prefs}->getPreference($tag); # spent 11.3ms making 454 calls to Foswiki::Prefs::getPreference, avg 25µs/call |
3129 | 454 | 463µs | if ( defined $e ) { | ||
3130 | 101 | 32µs | if ( $args && $args =~ /\S/ ) { | ||
3131 | $attrs = new Foswiki::Attrs( $args, 0 ); | ||||
3132 | $attrs->{DEFAULT} = $attrs->{_DEFAULT}; | ||||
3133 | $e = $this->_processMacros( | ||||
3134 | $e, | ||||
3135 | sub { | ||||
3136 | my ( $this, $tag, $args, $topicObject ) = @_; | ||||
3137 | return | ||||
3138 | defined $attrs->{$tag} | ||||
3139 | ? expandStandardEscapes( $attrs->{$tag} ) | ||||
3140 | : undef; | ||||
3141 | }, | ||||
3142 | $topicObject, | ||||
3143 | 1 | ||||
3144 | ); | ||||
3145 | } | ||||
3146 | } | ||||
3147 | elsif ( exists( $macros{$tag} ) ) { | ||||
3148 | 343 | 179µs | unless ( defined( $macros{$tag} ) ) { | ||
3149 | |||||
3150 | # Demand-load the macro module | ||||
3151 | 16 | 55µs | die $tag unless $tag =~ /([A-Z_:]+)/i; | ||
3152 | 16 | 15µs | $tag = $1; | ||
3153 | 16 | 826µs | eval "require Foswiki::Macros::$tag"; # spent 206µs executing statements in string eval
# spent 195µs executing statements in 2 string evals (merged)
# spent 191µs executing statements in string eval
# spent 168µs executing statements in string eval
# spent 149µs executing statements in string eval
# spent 138µs executing statements in string eval
# spent 129µs executing statements in string eval
# spent 118µs executing statements in string eval
# spent 116µs executing statements in string eval
# spent 110µs executing statements in string eval
# spent 91µs executing statements in string eval
# spent 83µs executing statements in string eval
# spent 75µs executing statements in string eval
# spent 73µs executing statements in string eval
# spent 72µs executing statements in string eval | ||
3154 | 16 | 7µs | die $@ if $@; | ||
3155 | 16 | 529µs | $macros{$tag} = eval "\\&$tag"; # spent 7µs executing statements in 2 string evals (merged)
# spent 5µs executing statements in string eval
# spent 5µs executing statements in string eval
# spent 4µs executing statements in string eval
# spent 4µs executing statements in string eval
# spent 4µs executing statements in string eval
# spent 4µs executing statements in string eval
# spent 4µs executing statements in string eval
# spent 4µs executing statements in string eval
# spent 3µs executing statements in string eval
# spent 3µs executing statements in string eval
# spent 3µs executing statements in string eval
# spent 3µs executing statements in string eval
# spent 2µs executing statements in string eval
# spent 2µs executing statements in string eval | ||
3156 | 16 | 8µs | die $@ if $@; | ||
3157 | } | ||||
3158 | |||||
3159 | 343 | 1.70ms | 343 | 7.77ms | $attrs = new Foswiki::Attrs( $args, $contextFreeSyntax{$tag} ); # spent 7.77ms making 343 calls to Foswiki::Attrs::new, avg 23µs/call |
3160 | 343 | 1.21ms | 343 | 67.4s | $e = &{ $macros{$tag} }( $this, $attrs, $topicObject ); # spent 49.6s making 40 calls to Foswiki::SEARCH, avg 1.24s/call
# spent 18.3s making 7 calls to Foswiki::INCLUDE, avg 2.61s/call, recursion: max depth 2, sum of overlapping time 8.98s
# spent 8.35s making 4 calls to Foswiki::Func::__ANON__[/var/www/foswiki11/lib/Foswiki/Func.pm:611], avg 2.09s/call
# spent 77.0ms making 41 calls to Foswiki::IF, avg 1.88ms/call
# spent 20.3ms making 3 calls to Foswiki::META, avg 6.76ms/call
# spent 5.63ms making 33 calls to Foswiki::MAKETEXT, avg 171µs/call
# spent 5.24ms making 42 calls to Foswiki::VAR, avg 125µs/call
# spent 4.47ms making 3 calls to Foswiki::REVINFO, avg 1.49ms/call
# spent 2.75ms making 1 call to Foswiki::QUERY
# spent 859µs making 1 call to Foswiki::ICONURL
# spent 673µs making 2 calls to Foswiki::LoginManager::_LOGIN, avg 337µs/call
# spent 590µs making 33 calls to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:241], avg 18µs/call
# spent 482µs making 5 calls to Foswiki::WIKINAME, avg 96µs/call
# spent 342µs making 16 calls to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:270], avg 21µs/call
# spent 337µs making 2 calls to Foswiki::WIKIUSERNAME, avg 168µs/call
# spent 296µs making 5 calls to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:211], avg 59µs/call
# spent 224µs making 4 calls to Foswiki::ADDTOZONE, avg 56µs/call
# spent 222µs making 2 calls to Foswiki::USERNAME, avg 111µs/call
# spent 167µs making 3 calls to Foswiki::URLPARAM, avg 56µs/call
# spent 161µs making 9 calls to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:268], avg 18µs/call
# spent 134µs making 15 calls to Foswiki::ENCODE, avg 9µs/call
# spent 113µs making 41 calls to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:368], avg 3µs/call
# spent 112µs making 2 calls to Foswiki::SPACEOUT, avg 56µs/call
# spent 93µs making 1 call to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:244]
# spent 79µs making 1 call to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:279]
# spent 77µs making 1 call to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:283]
# spent 45µs making 14 calls to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:372], avg 3µs/call
# spent 37µs making 2 calls to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:417], avg 19µs/call
# spent 26µs making 4 calls to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:361], avg 6µs/call
# spent 25µs making 2 calls to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:240], avg 12µs/call
# spent 22µs making 1 call to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:267]
# spent 9µs making 1 call to Foswiki::LoginManager::ApacheLogin::__ANON__[/var/www/foswiki11/lib/Foswiki/LoginManager/ApacheLogin.pm:46]
# spent 8µs making 1 call to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:404]
# spent 3µs making 1 call to Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki.pm:366] |
3161 | } | ||||
3162 | elsif ( $args && $args =~ /\S/ ) { | ||||
3163 | 1 | 3µs | 1 | 65µs | $attrs = new Foswiki::Attrs($args); # spent 65µs making 1 call to Foswiki::Attrs::new |
3164 | 1 | 700ns | if ( defined $attrs->{default} ) { | ||
3165 | $e = expandStandardEscapes( $attrs->{default} ); | ||||
3166 | } | ||||
3167 | } | ||||
3168 | 454 | 2.15ms | return $e; | ||
3169 | } | ||||
3170 | |||||
3171 | # Handle expansion of a tag during new topic creation. When creating a | ||||
3172 | # new topic from a template we only expand a subset of the available legal | ||||
3173 | # tags, and we expand %NOP% differently. | ||||
3174 | sub _expandMacroOnTopicCreation { | ||||
3175 | my $this = shift; | ||||
3176 | |||||
3177 | # my( $tag, $args, $topicObject ) = @_; | ||||
3178 | |||||
3179 | # Required for Cairo compatibility. Ignore %NOP{...}% | ||||
3180 | # %NOP% is *not* ignored until all variable expansion is complete, | ||||
3181 | # otherwise them inside-out rule would remove it too early e.g. | ||||
3182 | # %GM%NOP%TIME -> %GMTIME -> 12:00. So we ignore it here and scrape it | ||||
3183 | # out later. We *have* to remove %NOP{...}% because it can foul up | ||||
3184 | # brace-matching. | ||||
3185 | return '' if $_[0] eq 'NOP' && defined $_[1]; | ||||
3186 | |||||
3187 | # Only expand a subset of legal tags. Warning: $this->{user} may be | ||||
3188 | # overridden during this call, when a new user topic is being created. | ||||
3189 | # This is what we want to make sure new user templates are populated | ||||
3190 | # correctly, but you need to think about this if you extend the set of | ||||
3191 | # tags expanded here. | ||||
3192 | return | ||||
3193 | unless $_[0] =~ | ||||
3194 | /^(URLPARAM|DATE|(SERVER|GM)TIME|(USER|WIKI)NAME|WIKIUSERNAME|USERINFO)$/; | ||||
3195 | |||||
3196 | return $this->_expandMacroOnTopicRendering(@_); | ||||
3197 | } | ||||
3198 | |||||
3199 | =begin TML | ||||
3200 | |||||
3201 | ---++ ObjectMethod enterContext( $id, $val ) | ||||
3202 | |||||
3203 | Add the context id $id into the set of active contexts. The $val | ||||
3204 | can be anything you like, but should always evaluate to boolean | ||||
3205 | TRUE. | ||||
3206 | |||||
3207 | An example of the use of contexts is in the use of tag | ||||
3208 | expansion. The commonTagsHandler in plugins is called every | ||||
3209 | time tags need to be expanded, and the context of that expansion | ||||
3210 | is signalled by the expanding module using a context id. So the | ||||
3211 | forms module adds the context id "form" before invoking common | ||||
3212 | tags expansion. | ||||
3213 | |||||
3214 | Contexts are not just useful for tag expansion; they are also | ||||
3215 | relevant when rendering. | ||||
3216 | |||||
3217 | Contexts are intended for use mainly by plugins. Core modules can | ||||
3218 | use $session->inContext( $id ) to determine if a context is active. | ||||
3219 | |||||
3220 | =cut | ||||
3221 | |||||
3222 | # spent 182µs within Foswiki::enterContext which was called 42 times, avg 4µs/call:
# 36 times (154µs+0s) by Foswiki::Plugin::registerHandlers at line 285 of /var/www/foswiki11/lib/Foswiki/Plugin.pm, avg 4µs/call
# once (12µs+0s) by Foswiki::UI::View::view at line 371 of /var/www/foswiki11/lib/Foswiki/UI/View.pm
# once (4µs+0s) by Foswiki::UI::View::view at line 397 of /var/www/foswiki11/lib/Foswiki/UI/View.pm
# once (4µs+0s) by Foswiki::LoginManager::ApacheLogin::new at line 43 of /var/www/foswiki11/lib/Foswiki/LoginManager/ApacheLogin.pm
# once (4µs+0s) by Foswiki::UI::View::view at line 391 of /var/www/foswiki11/lib/Foswiki/UI/View.pm
# once (3µs+0s) by Foswiki::Users::new at line 120 of /var/www/foswiki11/lib/Foswiki/Users.pm
# once (2µs+0s) by Foswiki::Users::new at line 121 of /var/www/foswiki11/lib/Foswiki/Users.pm | ||||
3223 | 42 | 32µs | my ( $this, $id, $val ) = @_; | ||
3224 | 42 | 17µs | $val ||= 1; | ||
3225 | 42 | 190µs | $this->{context}->{$id} = $val; | ||
3226 | } | ||||
3227 | |||||
3228 | =begin TML | ||||
3229 | |||||
3230 | ---++ ObjectMethod leaveContext( $id ) | ||||
3231 | |||||
3232 | Remove the context id $id from the set of active contexts. | ||||
3233 | (see =enterContext= for more information on contexts) | ||||
3234 | |||||
3235 | =cut | ||||
3236 | |||||
3237 | # spent 32µs within Foswiki::leaveContext which was called 4 times, avg 8µs/call:
# once (12µs+0s) by Foswiki::UI::View::view at line 399 of /var/www/foswiki11/lib/Foswiki/UI/View.pm
# once (9µs+0s) by Foswiki::UI::View::view at line 393 of /var/www/foswiki11/lib/Foswiki/UI/View.pm
# once (6µs+0s) by Foswiki::UI::View::view at line 373 of /var/www/foswiki11/lib/Foswiki/UI/View.pm
# once (5µs+0s) by Foswiki::LoginManager::new at line 165 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm | ||||
3238 | 4 | 6µs | my ( $this, $id ) = @_; | ||
3239 | 4 | 5µs | my $res = $this->{context}->{$id}; | ||
3240 | 4 | 8µs | delete $this->{context}->{$id}; | ||
3241 | 4 | 23µs | return $res; | ||
3242 | } | ||||
3243 | |||||
3244 | =begin TML | ||||
3245 | |||||
3246 | ---++ ObjectMethod inContext( $id ) | ||||
3247 | |||||
3248 | Return the value for the given context id | ||||
3249 | (see =enterContext= for more information on contexts) | ||||
3250 | |||||
3251 | =cut | ||||
3252 | |||||
3253 | # spent 264µs within Foswiki::inContext which was called 97 times, avg 3µs/call:
# 39 times (110µs+0s) by Foswiki::getScriptUrl at line 1437, avg 3µs/call
# 33 times (75µs+0s) by Foswiki::getPubUrl at line 1520, avg 2µs/call
# 8 times (30µs+0s) by Foswiki::If::OP_context::evaluate at line 36 of /var/www/foswiki11/lib/Foswiki/If/OP_context.pm, avg 4µs/call
# 5 times (14µs+0s) by Foswiki::LoginManager::endRenderingHandler at line 890 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm, avg 3µs/call
# 4 times (12µs+0s) by Foswiki::Func::__ANON__[/var/www/foswiki11/lib/Foswiki/Func.pm:611] at line 598 of /var/www/foswiki11/lib/Foswiki/Func.pm, avg 3µs/call
# 2 times (6µs+0s) by Foswiki::LoginManager::_LOGIN at line 1152 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm, avg 3µs/call
# once (6µs+0s) by Foswiki::LoginManager::checkAccess at line 589 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (3µs+0s) by Foswiki::LoginManager::makeLoginManager at line 91 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (3µs+0s) by Foswiki::generateHTTPHeaders at line 955
# once (2µs+0s) by Foswiki::LoginManager::userLoggedIn at line 699 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (2µs+0s) by Foswiki::LoginManager::loadSession at line 306 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (2µs+0s) by Foswiki::LoginManager::makeLoginManager at line 130 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm | ||||
3254 | 97 | 57µs | my ( $this, $id ) = @_; | ||
3255 | 97 | 413µs | return $this->{context}->{$id}; | ||
3256 | } | ||||
3257 | |||||
3258 | =begin TML | ||||
3259 | |||||
3260 | ---++ StaticMethod registerTagHandler( $tag, $fnref, $syntax ) | ||||
3261 | |||||
3262 | STATIC Add a tag handler to the function tag handlers. | ||||
3263 | * =$tag= name of the tag e.g. MYTAG | ||||
3264 | * =$fnref= Function to execute. Will be passed ($session, \%params, $web, $topic ) | ||||
3265 | * =$syntax= somewhat legacy - 'classic' or 'context-free' (context-free may be removed in future) | ||||
3266 | |||||
3267 | |||||
3268 | $syntax parameter: | ||||
3269 | Way back in prehistory, back when the dinosaur still roamed the earth, | ||||
3270 | Crawford tried to extend the tag syntax of macros such that they could be processed | ||||
3271 | by a context-free parser (hence the "context-free") | ||||
3272 | and bring them into line with HTML. | ||||
3273 | This work was banjaxed by one particular tyrranosaur, | ||||
3274 | who felt that the existing syntax was perfect. | ||||
3275 | However by that time Crawford had used it in a couple of places - most notable in the action tracker. | ||||
3276 | |||||
3277 | The syntax isn't vastly different from what's there; the differences are: | ||||
3278 | 1 Use either type of quote for parameters | ||||
3279 | 2 Optional quotes on parameter values e.g. recurse=on | ||||
3280 | 3 Standardised use of \ for escapes | ||||
3281 | 4 Boolean (valueless) options (i.e. recurse instead of recurse="on" | ||||
3282 | |||||
3283 | |||||
3284 | =cut | ||||
3285 | |||||
3286 | # spent 185µs within Foswiki::registerTagHandler which was called 55 times, avg 3µs/call:
# 44 times (162µs+0s) by Foswiki::Func::registerTagHandler at line 612 of /var/www/foswiki11/lib/Foswiki/Func.pm, avg 4µs/call
# once (3µs+0s) by Foswiki::Plugins::new at line 74 of /var/www/foswiki11/lib/Foswiki/Plugins.pm
# once (3µs+0s) by Foswiki::LoginManager::new at line 174 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (2µs+0s) by Foswiki::Plugins::new at line 76 of /var/www/foswiki11/lib/Foswiki/Plugins.pm
# once (2µs+0s) by Foswiki::LoginManager::new at line 176 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (2µs+0s) by Foswiki::LoginManager::new at line 178 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (2µs+0s) by Foswiki::Plugins::new at line 78 of /var/www/foswiki11/lib/Foswiki/Plugins.pm
# once (2µs+0s) by Foswiki::LoginManager::new at line 177 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (2µs+0s) by Foswiki::LoginManager::new at line 175 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (2µs+0s) by Foswiki::LoginManager::new at line 179 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (2µs+0s) by Foswiki::LoginManager::new at line 180 of /var/www/foswiki11/lib/Foswiki/LoginManager.pm
# once (2µs+0s) by Foswiki::LoginManager::ApacheLogin::new at line 46 of /var/www/foswiki11/lib/Foswiki/LoginManager/ApacheLogin.pm | ||||
3287 | 55 | 37µs | my ( $tag, $fnref, $syntax ) = @_; | ||
3288 | 55 | 78µs | $macros{$tag} = $fnref; | ||
3289 | 55 | 165µs | if ( $syntax && $syntax eq 'context-free' ) { | ||
3290 | $contextFreeSyntax{$tag} = 1; | ||||
3291 | } | ||||
3292 | } | ||||
3293 | |||||
3294 | =begin TML | ||||
3295 | |||||
3296 | ---++ ObjectMethod expandMacros( $text, $topicObject ) -> $text | ||||
3297 | |||||
3298 | Processes %<nop>VARIABLE%, and %<nop>TOC% syntax; also includes | ||||
3299 | 'commonTagsHandler' plugin hook. | ||||
3300 | |||||
3301 | Returns the text of the topic, after file inclusion, variable substitution, | ||||
3302 | table-of-contents generation, and any plugin changes from commonTagsHandler. | ||||
3303 | |||||
3304 | $topicObject may be undef when, for example, expanding templates, or one-off strings | ||||
3305 | at a time when meta isn't available. | ||||
3306 | |||||
3307 | DO NOT CALL THIS DIRECTLY; use $topicObject->expandMacros instead. | ||||
3308 | |||||
3309 | =cut | ||||
3310 | |||||
3311 | # spent 59.1s (638µs+59.1) within Foswiki::expandMacros which was called 7 times, avg 8.45s/call:
# 7 times (638µs+59.1s) by Foswiki::Meta::expandMacros at line 3103 of /var/www/foswiki11/lib/Foswiki/Meta.pm, avg 8.45s/call | ||||
3312 | 7 | 16µs | my ( $this, $text, $topicObject ) = @_; | ||
3313 | |||||
3314 | 7 | 2µs | return '' unless defined $text; | ||
3315 | |||||
3316 | # Plugin Hook (for cache Plugins only) | ||||
3317 | 7 | 52µs | 21 | 730µs | $this->{plugins} # spent 839µs making 7 calls to Foswiki::Plugins::dispatch, avg 120µs/call, recursion: max depth 1, sum of overlapping time 140µs
# spent 17µs making 7 calls to Foswiki::Meta::topic, avg 2µs/call
# spent 16µs making 7 calls to Foswiki::Meta::web, avg 2µs/call |
3318 | ->dispatch( 'beforeCommonTagsHandler', $text, $topicObject->topic, | ||||
3319 | $topicObject->web, $topicObject ); | ||||
3320 | |||||
3321 | #use a "global var", so included topics can extract and putback | ||||
3322 | #their verbatim blocks safetly. | ||||
3323 | 7 | 5µs | my $verbatim = {}; | ||
3324 | 7 | 20µs | 7 | 188µs | $text = takeOutBlocks( $text, 'verbatim', $verbatim ); # spent 188µs making 7 calls to Foswiki::takeOutBlocks, avg 27µs/call |
3325 | |||||
3326 | # take out dirty areas | ||||
3327 | 7 | 5µs | my $dirtyAreas = {}; | ||
3328 | 7 | 9µs | $text = takeOutBlocks( $text, 'dirtyarea', $dirtyAreas ) | ||
3329 | if $Foswiki::cfg{Cache}{Enabled}; | ||||
3330 | |||||
3331 | # Require defaults for plugin handlers :-( | ||||
3332 | 7 | 18µs | 7 | 18µs | my $webContext = $topicObject->web || $this->{webName}; # spent 18µs making 7 calls to Foswiki::Meta::web, avg 3µs/call |
3333 | 7 | 14µs | 7 | 19µs | my $topicContext = $topicObject->topic || $this->{topicName}; # spent 19µs making 7 calls to Foswiki::Meta::topic, avg 3µs/call |
3334 | |||||
3335 | 7 | 17µs | 7 | 21µs | my $memW = $this->{prefs}->getPreference('INCLUDINGWEB'); # spent 21µs making 7 calls to Foswiki::Prefs::getPreference, avg 3µs/call |
3336 | 7 | 14µs | 7 | 16µs | my $memT = $this->{prefs}->getPreference('INCLUDINGTOPIC'); # spent 16µs making 7 calls to Foswiki::Prefs::getPreference, avg 2µs/call |
3337 | 7 | 16µs | 7 | 78µs | $this->{prefs}->setInternalPreferences( # spent 78µs making 7 calls to Foswiki::Prefs::setInternalPreferences, avg 11µs/call |
3338 | INCLUDINGWEB => $webContext, | ||||
3339 | INCLUDINGTOPIC => $topicContext | ||||
3340 | ); | ||||
3341 | |||||
3342 | 7 | 18µs | 7 | 59.1s | $this->innerExpandMacros( \$text, $topicObject ); # spent 59.1s making 7 calls to Foswiki::innerExpandMacros, avg 8.44s/call |
3343 | |||||
3344 | 7 | 19µs | 7 | 185µs | $text = takeOutBlocks( $text, 'verbatim', $verbatim ); # spent 185µs making 7 calls to Foswiki::takeOutBlocks, avg 26µs/call |
3345 | |||||
3346 | # Plugin Hook | ||||
3347 | 7 | 22µs | 7 | 7.43ms | $this->{plugins} # spent 7.84ms making 7 calls to Foswiki::Plugins::dispatch, avg 1.12ms/call, recursion: max depth 1, sum of overlapping time 417µs |
3348 | ->dispatch( 'commonTagsHandler', $text, $topicContext, $webContext, 0, | ||||
3349 | $topicObject ); | ||||
3350 | |||||
3351 | # process tags again because plugin hook may have added more in | ||||
3352 | 7 | 19µs | 7 | 1.21ms | $this->innerExpandMacros( \$text, $topicObject ); # spent 1.21ms making 7 calls to Foswiki::innerExpandMacros, avg 173µs/call |
3353 | |||||
3354 | 7 | 18µs | 7 | 52µs | $this->{prefs}->setInternalPreferences( # spent 52µs making 7 calls to Foswiki::Prefs::setInternalPreferences, avg 7µs/call |
3355 | INCLUDINGWEB => $memW, | ||||
3356 | INCLUDINGTOPIC => $memT | ||||
3357 | ); | ||||
3358 | |||||
3359 | # 'Special plugin tag' TOC hack, must be done after all other expansions | ||||
3360 | # are complete, and has to reprocess the entire topic. | ||||
3361 | |||||
3362 | 7 | 60µs | if ( $text =~ /%TOC(?:{.*})?%/ ) { | ||
3363 | require Foswiki::Macros::TOC; | ||||
3364 | $text =~ s/%TOC(?:{(.*?)})?%/$this->TOC($text, $topicObject, $1)/ge; | ||||
3365 | } | ||||
3366 | |||||
3367 | # Codev.FormattedSearchWithConditionalOutput: remove <nop> lines, | ||||
3368 | # possibly introduced by SEARCHes with conditional CALC. This needs | ||||
3369 | # to be done after CALC and before table rendering in order to join | ||||
3370 | # table rows properly | ||||
3371 | 7 | 54µs | $text =~ s/^<nop>\r?\n//gm; | ||
3372 | |||||
3373 | # restore dirty areas | ||||
3374 | 7 | 6µs | putBackBlocks( \$text, $dirtyAreas, 'dirtyarea' ) | ||
3375 | if $Foswiki::cfg{Cache}{Enabled}; | ||||
3376 | |||||
3377 | 7 | 15µs | 7 | 30µs | putBackBlocks( \$text, $verbatim, 'verbatim' ); # spent 30µs making 7 calls to Foswiki::putBackBlocks, avg 4µs/call |
3378 | |||||
3379 | # Foswiki Plugin Hook (for cache Plugins only) | ||||
3380 | 7 | 15µs | 7 | 159µs | $this->{plugins} # spent 195µs making 7 calls to Foswiki::Plugins::dispatch, avg 28µs/call, recursion: max depth 1, sum of overlapping time 36µs |
3381 | ->dispatch( 'afterCommonTagsHandler', $text, $topicContext, $webContext, | ||||
3382 | $topicObject ); | ||||
3383 | |||||
3384 | 7 | 42µs | return $text; | ||
3385 | } | ||||
3386 | |||||
3387 | =begin TML | ||||
3388 | |||||
3389 | ---++ ObjectMethod addToZone($zone, $id, $data, $requires) | ||||
3390 | |||||
3391 | Add =$data= identified as =$id= to =$zone=, which will later be expanded (with | ||||
3392 | renderZone() - implements =%<nop>RENDERZONE%=). =$ids= are unique within | ||||
3393 | the zone that they are added - dependencies between =$ids= in different zones | ||||
3394 | will not be resolved, except for the special case of =head= and =script= zones | ||||
3395 | when ={MergeHeadAndScriptZones}= is enabled. | ||||
3396 | |||||
3397 | In this case, they are treated as separate zones when adding to them, but as | ||||
3398 | one merged zone when rendering, i.e. a call to render either =head= or =script= | ||||
3399 | zones will actually render both zones in this one call. Both zones are undef'd | ||||
3400 | afterward to avoid double rendering of content from either zone, to support | ||||
3401 | proper behaviour when =head= and =script= are rendered with separate calls even | ||||
3402 | when ={MergeHeadAndScriptZones}= is set. See ZoneTests/explicit_RENDERZONE*. | ||||
3403 | |||||
3404 | This behaviour allows an addToZone('head') call to require an id that has been | ||||
3405 | added to =script= only. | ||||
3406 | |||||
3407 | * =$zone= - name of the zone | ||||
3408 | * =$id= - unique identifier | ||||
3409 | * =$data= - content | ||||
3410 | * =$requires= - optional, comma-separated string of =$id= identifiers | ||||
3411 | that should precede the content | ||||
3412 | |||||
3413 | <blockquote class="foswikiHelp">%X% | ||||
3414 | *Note:* Read the developer supplement at Foswiki:Development.AddToZoneFromPluginHandlers if you | ||||
3415 | are calling =addToZone()= from a rendering or macro/tag-related plugin handler | ||||
3416 | </blockquote> | ||||
3417 | |||||
3418 | Implements =%<nop>ADDTOZONE%=. | ||||
3419 | |||||
3420 | =cut | ||||
3421 | |||||
3422 | # spent 358µs within Foswiki::addToZone which was called 16 times, avg 22µs/call:
# 12 times (234µs+0s) by Foswiki::Func::addToZone at line 2657 of /var/www/foswiki11/lib/Foswiki/Func.pm, avg 19µs/call
# 4 times (124µs+0s) by Foswiki::ADDTOZONE at line 38 of /var/www/foswiki11/lib/Foswiki/Macros/ADDTOZONE.pm, avg 31µs/call | ||||
3423 | 16 | 23µs | my ( $this, $zone, $id, $data, $requires ) = @_; | ||
3424 | |||||
3425 | 16 | 5µs | $requires ||= ''; | ||
3426 | |||||
3427 | # get a random one | ||||
3428 | 16 | 3µs | unless ($id) { | ||
3429 | $id = int( rand(10000) ) + 1; | ||||
3430 | } | ||||
3431 | |||||
3432 | # get zone, or create record | ||||
3433 | 16 | 18µs | my $thisZone = $this->{_zones}{$zone}; | ||
3434 | 16 | 8µs | unless ( defined $thisZone ) { | ||
3435 | $this->{_zones}{$zone} = $thisZone = {}; | ||||
3436 | } | ||||
3437 | |||||
3438 | 16 | 5µs | my @requires; | ||
3439 | 16 | 84µs | foreach my $req ( split( /\s*,\s*/, $requires ) ) { | ||
3440 | 23 | 35µs | unless ( $thisZone->{$req} ) { | ||
3441 | $thisZone->{$req} = { | ||||
3442 | id => $req, | ||||
3443 | zone => $zone, | ||||
3444 | requires => [], | ||||
3445 | missingrequires => [], | ||||
3446 | text => '', | ||||
3447 | populated => 0 | ||||
3448 | }; | ||||
3449 | } | ||||
3450 | 23 | 33µs | push( @requires, $thisZone->{$req} ); | ||
3451 | } | ||||
3452 | |||||
3453 | # store record within zone | ||||
3454 | 16 | 10µs | my $zoneID = $thisZone->{$id}; | ||
3455 | 16 | 6µs | unless ($zoneID) { | ||
3456 | 14 | 19µs | $zoneID = { id => $id }; | ||
3457 | 14 | 18µs | $thisZone->{$id} = $zoneID; | ||
3458 | } | ||||
3459 | |||||
3460 | # override previous properties | ||||
3461 | 16 | 11µs | $zoneID->{zone} = $zone; | ||
3462 | 16 | 14µs | $zoneID->{requires} = \@requires; | ||
3463 | 16 | 14µs | $zoneID->{missingrequires} = []; | ||
3464 | 16 | 12µs | $zoneID->{text} = $data; | ||
3465 | 16 | 8µs | $zoneID->{populated} = 1; | ||
3466 | |||||
3467 | 16 | 64µs | return; | ||
3468 | } | ||||
3469 | |||||
3470 | sub _renderZoneById { | ||||
3471 | my $this = shift; | ||||
3472 | my $id = shift; | ||||
3473 | |||||
3474 | return '' unless defined $id; | ||||
3475 | |||||
3476 | my $renderZone = $this->{_renderZonePlaceholder}{$id}; | ||||
3477 | |||||
3478 | return '' unless defined $renderZone; | ||||
3479 | |||||
3480 | my $params = $renderZone->{params}; | ||||
3481 | my $topicObject = $renderZone->{topicObject}; | ||||
3482 | my $zone = $params->{_DEFAULT} || $params->{zone}; | ||||
3483 | |||||
3484 | return _renderZone( $this, $zone, $params, $topicObject ); | ||||
3485 | } | ||||
3486 | |||||
3487 | # This private function is used in ZoneTests | ||||
3488 | sub _renderZone { | ||||
3489 | 2 | 3µs | my ( $this, $zone, $params, $topicObject ) = @_; | ||
3490 | |||||
3491 | # Check the zone is defined and has not already been rendered | ||||
3492 | 2 | 4µs | return '' unless $zone && $this->{_zones}{$zone}; | ||
3493 | |||||
3494 | 2 | 3µs | $params->{header} ||= ''; | ||
3495 | 2 | 2µs | $params->{footer} ||= ''; | ||
3496 | 2 | 800ns | $params->{chomp} ||= 'off'; | ||
3497 | 2 | 2µs | $params->{missingformat} = '$id: requires= missing ids: $missingids'; | ||
3498 | 2 | 2µs | $params->{format} = '$item<!--<literal>$missing</literal>-->' | ||
3499 | unless defined $params->{format}; | ||||
3500 | 2 | 2µs | $params->{separator} = '$n()' unless defined $params->{separator}; | ||
3501 | |||||
3502 | 2 | 11µs | 2 | 54µs | unless ( defined $topicObject ) { # spent 54µs making 2 calls to Foswiki::Meta::new, avg 27µs/call |
3503 | $topicObject = | ||||
3504 | Foswiki::Meta->new( $this, $this->{webName}, $this->{topicName} ); | ||||
3505 | } | ||||
3506 | |||||
3507 | # Loop through the vertices of the graph, in any order, initiating | ||||
3508 | # a depth-first search for any vertex that has not already been | ||||
3509 | # visited by a previous search. The desired topological sorting is | ||||
3510 | # the reverse postorder of these searches. That is, we can construct | ||||
3511 | # the ordering as a list of vertices, by adding each vertex to the | ||||
3512 | # start of the list at the time when the depth-first search is | ||||
3513 | # processing that vertex and has returned from processing all children | ||||
3514 | # of that vertex. Since each edge and vertex is visited once, the | ||||
3515 | # algorithm runs in linear time. | ||||
3516 | 2 | 2µs | my %visited; | ||
3517 | 2 | 700ns | my @total; | ||
3518 | |||||
3519 | # When {MergeHeadAndScriptZones} is set, try to treat head and script | ||||
3520 | # zones as merged for compatibility with ADDTOHEAD usage where requirements | ||||
3521 | # have been moved to the script zone. See ZoneTests/Item9317 | ||||
3522 | 2 | 28µs | if ( $Foswiki::cfg{MergeHeadAndScriptZones} | ||
3523 | and ( ( $zone eq 'head' ) or ( $zone eq 'script' ) ) ) | ||||
3524 | { | ||||
3525 | my @zoneIDs = ( | ||||
3526 | values %{ $this->{_zones}{head} }, | ||||
3527 | values %{ $this->{_zones}{script} } | ||||
3528 | ); | ||||
3529 | |||||
3530 | foreach my $zoneID (@zoneIDs) { | ||||
3531 | $this->_visitZoneID( $zoneID, \%visited, \@total ); | ||||
3532 | } | ||||
3533 | undef $this->{_zones}{head}; | ||||
3534 | undef $this->{_zones}{script}; | ||||
3535 | } | ||||
3536 | else { | ||||
3537 | 2 | 19µs | my @zoneIDs = values %{ $this->{_zones}{$zone} }; | ||
3538 | |||||
3539 | 2 | 2µs | foreach my $zoneID (@zoneIDs) { | ||
3540 | 20 | 45µs | 20 | 302µs | $this->_visitZoneID( $zoneID, \%visited, \@total ); # spent 302µs making 20 calls to Foswiki::_visitZoneID, avg 15µs/call |
3541 | } | ||||
3542 | |||||
3543 | # kill a zone once it has been rendered, to prevent it being | ||||
3544 | # added twice (e.g. by duplicate %RENDERZONEs or by automatic | ||||
3545 | # zone expansion in the head or script) | ||||
3546 | 2 | 4µs | undef $this->{_zones}{$zone}; | ||
3547 | } | ||||
3548 | |||||
3549 | # nothing rendered for a zone with no ADDTOZONE calls | ||||
3550 | 2 | 2µs | return '' unless scalar(@total) > 0; | ||
3551 | |||||
3552 | 2 | 2µs | my @result = (); | ||
3553 | 2 | 2µs | my $missingformat = $params->{missingformat}; | ||
3554 | 2 | 3µs | foreach my $item (@total) { | ||
3555 | 20 | 15µs | my $text = $item->{text}; | ||
3556 | 20 | 15µs | my @missingids = @{ $item->{missingrequires} }; | ||
3557 | 20 | 16µs | my $missingformat = | ||
3558 | ( scalar(@missingids) ) ? $params->{missingformat} : ''; | ||||
3559 | |||||
3560 | 20 | 10µs | if ( $params->{'chomp'} ) { | ||
3561 | 20 | 15µs | $text =~ s/^\s+//g; | ||
3562 | 20 | 43µs | $text =~ s/\s+$//g; | ||
3563 | } | ||||
3564 | |||||
3565 | # ASSERT($text, "No content for zone id $item->{id} in zone $zone") | ||||
3566 | # if DEBUG; | ||||
3567 | |||||
3568 | 20 | 5µs | next unless $text; | ||
3569 | 14 | 10µs | my $id = $item->{id} || ''; | ||
3570 | 14 | 5µs | my $line = $params->{format}; | ||
3571 | 14 | 9µs | if ( scalar(@missingids) ) { | ||
3572 | 2 | 6µs | $line =~ s/\$missing\b/$missingformat/g; | ||
3573 | 2 | 10µs | $line =~ s/\$missingids\b/join(', ', @missingids)/ge; | ||
3574 | } | ||||
3575 | else { | ||||
3576 | 12 | 28µs | $line =~ s/\$missing\b/\$id/g; | ||
3577 | } | ||||
3578 | 14 | 32µs | $line =~ s/\$item\b/$text/g; | ||
3579 | 14 | 34µs | $line =~ s/\$id\b/$id/g; | ||
3580 | 14 | 9µs | $line =~ s/\$zone\b/$item->{zone}/g; | ||
3581 | 14 | 20µs | push @result, $line if $line; | ||
3582 | } | ||||
3583 | 2 | 19µs | 2 | 83µs | my $result = # spent 83µs making 2 calls to Foswiki::expandStandardEscapes, avg 42µs/call |
3584 | expandStandardEscapes( $params->{header} | ||||
3585 | . join( $params->{separator}, @result ) | ||||
3586 | . $params->{footer} ); | ||||
3587 | |||||
3588 | # delay rendering the zone until now | ||||
3589 | 2 | 6µs | 2 | 16.4ms | $result = $topicObject->expandMacros($result); # spent 16.4ms making 2 calls to Foswiki::Meta::expandMacros, avg 8.18ms/call |
3590 | 2 | 4µs | 2 | 3.46ms | $result = $topicObject->renderTML($result); # spent 3.46ms making 2 calls to Foswiki::Meta::renderTML, avg 1.73ms/call |
3591 | |||||
3592 | 2 | 69µs | return $result; | ||
3593 | } | ||||
3594 | |||||
3595 | sub _visitZoneID { | ||||
3596 | 43 | 24µs | my ( $this, $zoneID, $visited, $list ) = @_; | ||
3597 | |||||
3598 | 43 | 83µs | return if $visited->{$zoneID}; | ||
3599 | |||||
3600 | 20 | 30µs | $visited->{$zoneID} = 1; | ||
3601 | |||||
3602 | 20 | 35µs | foreach my $requiredZoneID ( @{ $zoneID->{requires} } ) { | ||
3603 | 23 | 3µs | my $zoneIDToVisit; | ||
3604 | |||||
3605 | 23 | 11µs | if ( $Foswiki::cfg{MergeHeadAndScriptZones} | ||
3606 | and not $requiredZoneID->{populated} ) | ||||
3607 | { | ||||
3608 | |||||
3609 | # Compatibility mode, where we are trying to treat head and script | ||||
3610 | # zones as merged, and a required ZoneID isn't populated. Try | ||||
3611 | # opposite zone to see if it exists there instead. Item9317 | ||||
3612 | if ( $requiredZoneID->{zone} eq 'head' ) { | ||||
3613 | $zoneIDToVisit = | ||||
3614 | $this->{_zones}{script}{ $requiredZoneID->{id} }; | ||||
3615 | } | ||||
3616 | else { | ||||
3617 | $zoneIDToVisit = $this->{_zones}{head}{ $requiredZoneID->{id} }; | ||||
3618 | } | ||||
3619 | if ( not $zoneIDToVisit->{populated} ) { | ||||
3620 | |||||
3621 | # Oops, the required ZoneID doesn't exist there either; reset | ||||
3622 | $zoneIDToVisit = $requiredZoneID; | ||||
3623 | } | ||||
3624 | } | ||||
3625 | else { | ||||
3626 | 23 | 7µs | $zoneIDToVisit = $requiredZoneID; | ||
3627 | } | ||||
3628 | 23 | 41µs | 23 | 0s | $this->_visitZoneID( $zoneIDToVisit, $visited, $list ); # spent 163µs making 23 calls to Foswiki::_visitZoneID, avg 7µs/call, recursion: max depth 3, sum of overlapping time 163µs |
3629 | |||||
3630 | 23 | 32µs | if ( not $zoneIDToVisit->{populated} ) { | ||
3631 | |||||
3632 | # Finally, we got to here and the required ZoneID just cannot be | ||||
3633 | # found in either head or script (or other) zones, so record it for | ||||
3634 | # diagnostic purposes ($missingids format token) | ||||
3635 | push( @{ $zoneID->{missingrequires} }, $zoneIDToVisit->{id} ); | ||||
3636 | } | ||||
3637 | } | ||||
3638 | 20 | 9µs | push( @{$list}, $zoneID ); | ||
3639 | |||||
3640 | 20 | 49µs | return; | ||
3641 | } | ||||
3642 | |||||
3643 | # This private function is used in ZoneTests | ||||
3644 | # spent 21.0ms (177µs+20.8) within Foswiki::_renderZones which was called:
# once (177µs+20.8ms) by Foswiki::writeCompletePage at line 814 | ||||
3645 | 1 | 19µs | my ( $this, $text ) = @_; | ||
3646 | |||||
3647 | # Render zones that were pulled out by Foswiki/Macros/RENDERZONE.pm | ||||
3648 | # NOTE: once a zone has been rendered it is cleared, so cannot | ||||
3649 | # be rendered again. | ||||
3650 | |||||
3651 | 1 | 27µs | $text =~ s/${RENDERZONE_MARKER}RENDERZONE{(.*?)}${RENDERZONE_MARKER}/ | ||
3652 | _renderZoneById($this, $1)/geo; | ||||
3653 | |||||
3654 | # get the head zone and insert it at the end of the </head> | ||||
3655 | # *if it has not already been rendered* | ||||
3656 | 1 | 10µs | 1 | 2.77ms | my $headZone = _renderZone( $this, 'head', { chomp => "on" } ); # spent 2.77ms making 1 call to Foswiki::_renderZone |
3657 | 1 | 36µs | $text =~ s!(</head>)!$headZone\n$1!i if $headZone; | ||
3658 | |||||
3659 | # SMELL: Item9480 - can't trust that _renderzone(head) above has truly | ||||
3660 | # flushed both script and head zones empty when {MergeHeadAndScriptZones} = 1. | ||||
3661 | 1 | 6µs | 1 | 18.1ms | my $scriptZone = _renderZone( $this, 'script', { chomp => "on" } ); # spent 18.1ms making 1 call to Foswiki::_renderZone |
3662 | 1 | 53µs | $text =~ s!(</head>)!$scriptZone\n$1!i if $scriptZone; | ||
3663 | |||||
3664 | 1 | 1µs | chomp($text); | ||
3665 | |||||
3666 | 1 | 21µs | return $text; | ||
3667 | } | ||||
3668 | |||||
3669 | =begin TML | ||||
3670 | |||||
3671 | ---++ StaticMethod readFile( $filename ) -> $text | ||||
3672 | |||||
3673 | Returns the entire contents of the given file, which can be specified in any | ||||
3674 | format acceptable to the Perl open() function. Fast, but inherently unsafe. | ||||
3675 | |||||
3676 | WARNING: Never, ever use this for accessing topics or attachments! Use the | ||||
3677 | Store API for that. This is for global control files only, and should be | ||||
3678 | used *only* if there is *absolutely no alternative*. | ||||
3679 | |||||
3680 | =cut | ||||
3681 | |||||
3682 | sub readFile { | ||||
3683 | my $name = shift; | ||||
3684 | my $IN_FILE; | ||||
3685 | open( $IN_FILE, "<$name" ) || return ''; | ||||
3686 | local $/ = undef; | ||||
3687 | my $data = <$IN_FILE>; | ||||
3688 | close($IN_FILE); | ||||
3689 | $data = '' unless ( defined($data) ); | ||||
3690 | return $data; | ||||
3691 | } | ||||
3692 | |||||
3693 | =begin TML | ||||
3694 | |||||
3695 | ---++ StaticMethod expandStandardEscapes($str) -> $unescapedStr | ||||
3696 | |||||
3697 | Expands standard escapes used in parameter values to block evaluation. See | ||||
3698 | System.FormatTokens for a full list of supported tokens. | ||||
3699 | |||||
3700 | =cut | ||||
3701 | |||||
3702 | # spent 1.06ms within Foswiki::expandStandardEscapes which was called 96 times, avg 11µs/call:
# 40 times (508µs+0s) by Foswiki::Search::searchWeb at line 457 of /var/www/foswiki11/lib/Foswiki/Search.pm, avg 13µs/call
# 21 times (136µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/IF.pm:43] at line 41 of /var/www/foswiki11/lib/Foswiki/Macros/IF.pm, avg 6µs/call
# 20 times (215µs+0s) by Foswiki::__ANON__[/var/www/foswiki11/lib/Foswiki/Macros/IF.pm:43] at line 37 of /var/www/foswiki11/lib/Foswiki/Macros/IF.pm, avg 11µs/call
# 9 times (76µs+0s) by Foswiki::USERINFO at line 126 of /var/www/foswiki11/lib/Foswiki/Macros/USERINFO.pm, avg 8µs/call
# 3 times (37µs+0s) by Foswiki::Render::renderRevisionInfo at line 1737 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 12µs/call
# 2 times (83µs+0s) by Foswiki::_renderZone at line 3583, avg 42µs/call
# once (5µs+0s) by Foswiki::META at line 19 of /var/www/foswiki11/lib/Foswiki/Macros/META.pm | ||||
3703 | 96 | 63µs | my $text = shift; | ||
3704 | |||||
3705 | # expand '$n()' and $n! to new line | ||||
3706 | 96 | 104µs | $text =~ s/\$n\(\)/\n/gs; | ||
3707 | 96 | 180µs | $text =~ s/\$n(?=[^$regex{mixedAlpha}]|$)/\n/gos; | ||
3708 | |||||
3709 | # filler, useful for nested search | ||||
3710 | 96 | 50µs | $text =~ s/\$nop(\(\))?//gs; | ||
3711 | |||||
3712 | # $quot -> " | ||||
3713 | 96 | 89µs | $text =~ s/\$quot(\(\))?/\"/gs; | ||
3714 | |||||
3715 | # $comma -> , | ||||
3716 | 96 | 35µs | $text =~ s/\$comma(\(\))?/,/gs; | ||
3717 | |||||
3718 | # $percent -> % | ||||
3719 | 96 | 75µs | $text =~ s/\$perce?nt(\(\))?/\%/gs; | ||
3720 | |||||
3721 | # $lt -> < | ||||
3722 | 96 | 87µs | $text =~ s/\$lt(\(\))?/\</gs; | ||
3723 | |||||
3724 | # $gt -> > | ||||
3725 | 96 | 35µs | $text =~ s/\$gt(\(\))?/\>/gs; | ||
3726 | |||||
3727 | # $amp -> & | ||||
3728 | 96 | 33µs | $text =~ s/\$amp(\(\))?/\&/gs; | ||
3729 | |||||
3730 | # $dollar -> $, done last to avoid creating the above tokens | ||||
3731 | 96 | 35µs | $text =~ s/\$dollar(\(\))?/\$/gs; | ||
3732 | |||||
3733 | 96 | 312µs | return $text; | ||
3734 | } | ||||
3735 | |||||
3736 | =begin TML | ||||
3737 | |||||
3738 | ---++ ObjectMethod webExists( $web ) -> $boolean | ||||
3739 | |||||
3740 | Test if web exists | ||||
3741 | * =$web= - Web name, required, e.g. ='Sandbox'= | ||||
3742 | |||||
3743 | A web _has_ to have a preferences topic to be a web. | ||||
3744 | |||||
3745 | =cut | ||||
3746 | |||||
3747 | # spent 14.4ms (1.68+12.7) within Foswiki::webExists which was called 177 times, avg 81µs/call:
# 95 times (982µs+9.03ms) by Foswiki::WebFilter::ok at line 36 of /var/www/foswiki11/lib/Foswiki/WebFilter.pm, avg 105µs/call
# 41 times (453µs+1.99ms) by Foswiki::Store::QueryAlgorithms::BruteForce::query at line 63 of /var/www/foswiki11/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 59µs/call
# 40 times (229µs+1.61ms) by Foswiki::Store::SearchAlgorithms::Forking::query at line 168 of /var/www/foswiki11/lib/Foswiki/Store/SearchAlgorithms/Forking.pm, avg 46µs/call
# once (17µs+56µs) by Foswiki::UI::checkWebExists at line 488 of /var/www/foswiki11/lib/Foswiki/UI.pm | ||||
3748 | 177 | 184µs | my ( $this, $web ) = @_; | ||
3749 | |||||
3750 | 177 | 217µs | 177 | 185µs | ASSERT( UNTAINTED($web), 'web is tainted' ) if DEBUG; # spent 185µs making 177 calls to Assert::ASSERTS_OFF, avg 1µs/call |
3751 | 177 | 1.02ms | 177 | 12.5ms | return $this->{store}->webExists($web); # spent 12.5ms making 177 calls to Foswiki::Store::VC::Store::webExists, avg 71µs/call |
3752 | } | ||||
3753 | |||||
3754 | =begin TML | ||||
3755 | |||||
3756 | ---++ ObjectMethod topicExists( $web, $topic ) -> $boolean | ||||
3757 | |||||
3758 | Test if topic exists | ||||
3759 | * =$web= - Web name, optional, e.g. ='Main'= | ||||
3760 | * =$topic= - Topic name, required, e.g. ='TokyoOffice'=, or ="Main.TokyoOffice"= | ||||
3761 | |||||
3762 | =cut | ||||
3763 | |||||
3764 | # spent 3.15s (598ms+2.55) within Foswiki::topicExists which was called 46261 times, avg 68µs/call:
# 46125 times (597ms+2.54s) by Foswiki::Search::InfoCache::__ANON__[/var/www/foswiki11/lib/Foswiki/Search/InfoCache.pm:579] at line 577 of /var/www/foswiki11/lib/Foswiki/Search/InfoCache.pm, avg 68µs/call
# 98 times (1.06ms+5.18ms) by Foswiki::Templates::_readTemplateFile at line 462 of /var/www/foswiki11/lib/Foswiki/Templates.pm, avg 64µs/call
# 17 times (195µs+1.35ms) by Foswiki::Render::_renderWikiWord at line 613 of /var/www/foswiki11/lib/Foswiki/Render.pm, avg 91µs/call
# 7 times (74µs+484µs) by Foswiki::If::OP_istopic::evaluate at line 34 of /var/www/foswiki11/lib/Foswiki/If/OP_istopic.pm, avg 80µs/call
# 7 times (78µs+438µs) by Foswiki::Plugin::topicWeb at line 374 of /var/www/foswiki11/lib/Foswiki/Plugin.pm, avg 74µs/call
# 3 times (35µs+162µs) by Foswiki::Users::TopicUserMapping::eachGroupMember at line 698 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm, avg 66µs/call
# once (15µs+142µs) by Foswiki::_lookupIcon at line 31 of /var/www/foswiki11/lib/Foswiki/Macros/ICON.pm
# once (16µs+89µs) by Foswiki::Users::TopicUserMapping::_loadMapping at line 1676 of /var/www/foswiki11/lib/Foswiki/Users/TopicUserMapping.pm
# once (12µs+66µs) by Foswiki::Func::topicExists at line 1565 of /var/www/foswiki11/lib/Foswiki/Func.pm
# once (9µs+42µs) by Foswiki::UI::View::view at line 121 of /var/www/foswiki11/lib/Foswiki/UI/View.pm | ||||
3765 | 46261 | 29.8ms | my ( $this, $web, $topic ) = @_; | ||
3766 | 46261 | 42.2ms | 46261 | 40.5ms | ASSERT( UNTAINTED($web), 'web is tainted' ) if DEBUG; # spent 40.5ms making 46261 calls to Assert::ASSERTS_OFF, avg 876ns/call |
3767 | 46261 | 44.9ms | 46261 | 35.3ms | ASSERT( UNTAINTED($topic), 'topic is tainted' ) if DEBUG; # spent 35.3ms making 46261 calls to Assert::ASSERTS_OFF, avg 762ns/call |
3768 | 46261 | 214ms | 46261 | 2.47s | return $this->{store}->topicExists( $web, $topic ); # spent 2.47s making 46261 calls to Foswiki::Store::VC::Store::topicExists, avg 53µs/call |
3769 | } | ||||
3770 | |||||
3771 | =begin TML | ||||
3772 | |||||
3773 | ---+++ ObjectMethod getWorkArea( $key ) -> $directorypath | ||||
3774 | |||||
3775 | Gets a private directory uniquely identified by $key. The directory is | ||||
3776 | intended as a work area for plugins etc. The directory will exist. | ||||
3777 | |||||
3778 | =cut | ||||
3779 | |||||
3780 | # spent 111µs (25+86) within Foswiki::getWorkArea which was called:
# once (25µs+86µs) by Foswiki::Func::getWorkArea at line 2745 of /var/www/foswiki11/lib/Foswiki/Func.pm | ||||
3781 | 1 | 1µs | my ( $this, $key ) = @_; | ||
3782 | 1 | 22µs | 1 | 86µs | return $this->{store}->getWorkArea($key); # spent 86µs making 1 call to Foswiki::Store::getWorkArea |
3783 | } | ||||
3784 | |||||
3785 | =begin TML | ||||
3786 | |||||
3787 | ---++ ObjectMethod getApproxRevTime ( $web, $topic ) -> $epochSecs | ||||
3788 | |||||
3789 | Get an approximate rev time for the latest rev of the topic. This method | ||||
3790 | is used to optimise searching. Needs to be as fast as possible. | ||||
3791 | |||||
3792 | SMELL: is there a reason this is in Foswiki.pm, and not in Search? | ||||
3793 | |||||
3794 | =cut | ||||
3795 | |||||
3796 | sub getApproxRevTime { | ||||
3797 | my ( $this, $web, $topic ) = @_; | ||||
3798 | |||||
3799 | my $metacache = $this->search->metacache; | ||||
3800 | if ( $metacache->hasCached( $web, $topic ) ) { | ||||
3801 | |||||
3802 | #don't kill me - this should become a property on Meta | ||||
3803 | return $metacache->get( $web, $topic )->{modified}; | ||||
3804 | } | ||||
3805 | |||||
3806 | return $this->{store}->getApproxRevTime( $web, $topic ); | ||||
3807 | } | ||||
3808 | |||||
3809 | 1 | 9µs | 1; | ||
3810 | __END__ | ||||
sub Foswiki::__ANON__; # xsub |