← Index
NYTProf Performance Profile   « block view • line view • sub view »
For /usr/local/src/github.com/foswiki/core/bin/view
  Run on Sun Dec 4 17:17:59 2011
Reported on Sun Dec 4 17:27:02 2011

Filename/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm
StatementsExecuted 242758 statements in 1.16s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
135751110409ms550msFoswiki::::normalizeWebTopicNameFoswiki::normalizeWebTopicName
113111149ms183sFoswiki::::expandMacrosFoswiki::expandMacros (recurses: max depth 1, inclusive time 2.39s)
232163147ms183sFoswiki::::innerExpandMacrosFoswiki::innerExpandMacros (recurses: max depth 2, inclusive time 4.77s)
23622194.6ms183sFoswiki::::_processMacrosFoswiki::_processMacros (recurses: max depth 4, inclusive time 99.0s)
1223734788.7ms89.4msFoswiki::::isTrueFoswiki::isTrue
23797237.2ms49.2msFoswiki::::takeOutBlocksFoswiki::takeOutBlocks
5621134.8ms183sFoswiki::::_expandMacroOnTopicRenderingFoswiki::_expandMacroOnTopicRendering (recurses: max depth 2, inclusive time 4.39s)
11121.7ms26.4msFoswiki::::BEGIN@607Foswiki::BEGIN@607
235517.9ms20.5msFoswiki::::rendererFoswiki::renderer
12486215.3ms16.3msFoswiki::::putBackBlocksFoswiki::putBackBlocks
11111.9ms18.7msFoswiki::::BEGIN@49Foswiki::BEGIN@49
1037511.1ms24.5msFoswiki::::searchFoswiki::search
20115.11ms11.1msFoswiki::::parseSectionsFoswiki::parseSections
96544.94ms10.6msFoswiki::::getScriptUrlFoswiki::getScriptUrl
1114.91ms14.4msFoswiki::::BEGIN@613Foswiki::BEGIN@613
95864.91ms6.68msFoswiki::::expandStandardEscapesFoswiki::expandStandardEscapes
211064.80ms11.1msFoswiki::::templatesFoswiki::templates
1114.46ms4.63msFoswiki::::attachFoswiki::attach
1114.43ms9.19msFoswiki::::BEGIN@47Foswiki::BEGIN@47
1114.16ms31.2msFoswiki::::BEGIN@608Foswiki::BEGIN@608
1114.05ms4.19msFoswiki::::BEGIN@609Foswiki::BEGIN@609
1114.01ms4.47msFoswiki::::loggerFoswiki::logger
59333.98ms5.08msFoswiki::::i18nFoswiki::i18n
155873.64ms24.9msFoswiki::::topicExistsFoswiki::topicExists
1113.17ms7.91msFoswiki::::BEGIN@610Foswiki::BEGIN@610
1113.08ms10.1msFoswiki::::BEGIN@611Foswiki::BEGIN@611
1112.94ms3.41msFoswiki::::BEGIN@48Foswiki::BEGIN@48
3251442.05ms2.05msFoswiki::::inContextFoswiki::inContext
1112.00ms2.08msFoswiki::::BEGIN@51Foswiki::BEGIN@51
1111.52ms2.07msFoswiki::::BEGIN@612Foswiki::BEGIN@612
2211.49ms59.0msFoswiki::::_renderZoneFoswiki::_renderZone
1111.21ms4.68msFoswiki::::BEGIN@46Foswiki::BEGIN@46
90321.17ms1.48msFoswiki::::urlEncodeFoswiki::urlEncode
56211.17ms1.17msFoswiki::::_visitZoneIDFoswiki::_visitZoneID (recurses: max depth 3, inclusive time 661µs)
21541.15ms1.15msFoswiki::::addToZoneFoswiki::addToZone
1111.12ms1.59msFoswiki::::BEGIN@50Foswiki::BEGIN@50
55111.09ms1.31msFoswiki::::make_paramsFoswiki::make_params
36211.01ms1.48msFoswiki::::getPubUrlFoswiki::getPubUrl
1111.01ms8.04msFoswiki::::finishFoswiki::finish
112211.01ms13.5msFoswiki::::accessFoswiki::access
111955µs81.8sFoswiki::::newFoswiki::new
111781µs50.1msFoswiki::::BEGIN@134Foswiki::BEGIN@134
111576µs806µsFoswiki::::BEGIN@2053Foswiki::BEGIN@2053
732543µs2.86msFoswiki::::getSkinFoswiki::getSkin
2322512µs716µsFoswiki::::isValidTopicNameFoswiki::isValidTopicName
111425µs558µsFoswiki::::BEGIN@606Foswiki::BEGIN@606
111415µs70.7msFoswiki::::writeCompletePageFoswiki::writeCompletePage
2711389µs1.58msFoswiki::::__ANON__[:266]Foswiki::__ANON__[:266]
36113355µs355µsFoswiki::::registerTagHandlerFoswiki::registerTagHandler
2796347µs347µsFoswiki::::enterContextFoswiki::enterContext
2511256µs1.44msFoswiki::::__ANON__[:239]Foswiki::__ANON__[:239]
4711236µs236µsFoswiki::::__ANON__[:365]Foswiki::__ANON__[:365]
1411210µs1.16msFoswiki::::__ANON__[:268]Foswiki::__ANON__[:268]
1253186µs293µsFoswiki::::getLoginManagerFoswiki::getLoginManager
911183µs1.47msFoswiki::::__ANON__[:281]Foswiki::__ANON__[:281]
111140µs59.3msFoswiki::::_renderZonesFoswiki::_renderZones
311140µs221µsFoswiki::::isValidWebNameFoswiki::isValidWebName
111136µs810µsFoswiki::::generateHTTPHeadersFoswiki::generateHTTPHeaders
1111127µs419µsFoswiki::::__ANON__[:238]Foswiki::__ANON__[:238]
111122µs8.65msFoswiki::::logEventFoswiki::logEvent
44281µs81µsFoswiki::::leaveContextFoswiki::leaveContext
51176µs1.01msFoswiki::::__ANON__[:209]Foswiki::__ANON__[:209]
22266µs420µsFoswiki::::webExistsFoswiki::webExists
11157µs92µsFoswiki::::_getLibDirFoswiki::_getLibDir
11148µs99µsFoswiki::::spaceOutWikiWordFoswiki::spaceOutWikiWord
61143µs43µsFoswiki::::__ANON__[:369]Foswiki::__ANON__[:369]
21137µs220µsFoswiki::::__ANON__[:242]Foswiki::__ANON__[:242]
22135µs51µsFoswiki::::UTF82SiteCharSetFoswiki::UTF82SiteCharSet
21128µs40µsFoswiki::::__ANON__[:405]Foswiki::__ANON__[:405]
11124µs31µsFoswiki::::BEGIN@44Foswiki::BEGIN@44
31122µs22µsFoswiki::::__ANON__[:358]Foswiki::__ANON__[:358]
11119µs35µsFoswiki::::__ANON__[:265]Foswiki::__ANON__[:265]
11119µs69µsFoswiki::::getCGISessionFoswiki::getCGISession
11118µs330µsFoswiki::::__ANON__[:277]Foswiki::__ANON__[:277]
11116µs34µsFoswiki::::BEGIN@45Foswiki::BEGIN@45
1119µs9µsFoswiki::::BEGIN@604Foswiki::BEGIN@604
1119µs9µsFoswiki::::BEGIN@605Foswiki::BEGIN@605
1118µs8µsFoswiki::::__ANON__[:363]Foswiki::__ANON__[:363]
1117µs7µsFoswiki::::__ANON__[:401]Foswiki::__ANON__[:401]
0000s0sFoswiki::::__ANON__[:149]Foswiki::__ANON__[:149]
0000s0sFoswiki::::__ANON__[:182]Foswiki::__ANON__[:182]
0000s0sFoswiki::::__ANON__[:184]Foswiki::__ANON__[:184]
0000s0sFoswiki::::__ANON__[:186]Foswiki::__ANON__[:186]
0000s0sFoswiki::::__ANON__[:193]Foswiki::__ANON__[:193]
0000s0sFoswiki::::__ANON__[:200]Foswiki::__ANON__[:200]
0000s0sFoswiki::::__ANON__[:215]Foswiki::__ANON__[:215]
0000s0sFoswiki::::__ANON__[:224]Foswiki::__ANON__[:224]
0000s0sFoswiki::::__ANON__[:234]Foswiki::__ANON__[:234]
0000s0sFoswiki::::__ANON__[:237]Foswiki::__ANON__[:237]
0000s0sFoswiki::::__ANON__[:248]Foswiki::__ANON__[:248]
0000s0sFoswiki::::__ANON__[:256]Foswiki::__ANON__[:256]
0000s0sFoswiki::::__ANON__[:260]Foswiki::__ANON__[:260]
0000s0sFoswiki::::__ANON__[:273]Foswiki::__ANON__[:273]
0000s0sFoswiki::::__ANON__[:295]Foswiki::__ANON__[:295]
0000s0sFoswiki::::__ANON__[:296]Foswiki::__ANON__[:296]
0000s0sFoswiki::::__ANON__[:297]Foswiki::__ANON__[:297]
0000s0sFoswiki::::__ANON__[:298]Foswiki::__ANON__[:298]
0000s0sFoswiki::::__ANON__[:299]Foswiki::__ANON__[:299]
0000s0sFoswiki::::__ANON__[:3047]Foswiki::__ANON__[:3047]
0000s0sFoswiki::::__ANON__[:338]Foswiki::__ANON__[:338]
0000s0sFoswiki::::__ANON__[:355]Foswiki::__ANON__[:355]
0000s0sFoswiki::::__ANON__[:356]Foswiki::__ANON__[:356]
0000s0sFoswiki::::__ANON__[:357]Foswiki::__ANON__[:357]
0000s0sFoswiki::::__ANON__[:359]Foswiki::__ANON__[:359]
0000s0sFoswiki::::__ANON__[:361]Foswiki::__ANON__[:361]
0000s0sFoswiki::::__ANON__[:362]Foswiki::__ANON__[:362]
0000s0sFoswiki::::__ANON__[:364]Foswiki::__ANON__[:364]
0000s0sFoswiki::::__ANON__[:366]Foswiki::__ANON__[:366]
0000s0sFoswiki::::__ANON__[:367]Foswiki::__ANON__[:367]
0000s0sFoswiki::::__ANON__[:368]Foswiki::__ANON__[:368]
0000s0sFoswiki::::__ANON__[:370]Foswiki::__ANON__[:370]
0000s0sFoswiki::::__ANON__[:371]Foswiki::__ANON__[:371]
0000s0sFoswiki::::__ANON__[:372]Foswiki::__ANON__[:372]
0000s0sFoswiki::::__ANON__[:373]Foswiki::__ANON__[:373]
0000s0sFoswiki::::__ANON__[:374]Foswiki::__ANON__[:374]
0000s0sFoswiki::::_expandMacroOnTopicCreationFoswiki::_expandMacroOnTopicCreation
0000s0sFoswiki::::_isRedirectSafeFoswiki::_isRedirectSafe
0000s0sFoswiki::::_renderZoneByIdFoswiki::_renderZoneById
0000s0sFoswiki::::cacheQueryFoswiki::cacheQuery
0000s0sFoswiki::::deepWebListFoswiki::deepWebList
0000s0sFoswiki::::entityDecodeFoswiki::entityDecode
0000s0sFoswiki::::entityEncodeFoswiki::entityEncode
0000s0sFoswiki::::expandMacrosOnTopicCreationFoswiki::expandMacrosOnTopicCreation
0000s0sFoswiki::::getApproxRevTimeFoswiki::getApproxRevTime
0000s0sFoswiki::::getWorkAreaFoswiki::getWorkArea
0000s0sFoswiki::::inlineAlertFoswiki::inlineAlert
0000s0sFoswiki::::isValidEmailAddressFoswiki::isValidEmailAddress
0000s0sFoswiki::::isValidWikiWordFoswiki::isValidWikiWord
0000s0sFoswiki::::netFoswiki::net
0000s0sFoswiki::::readFileFoswiki::readFile
0000s0sFoswiki::::redirectFoswiki::redirect
0000s0sFoswiki::::redirecttoFoswiki::redirectto
0000s0sFoswiki::::splitAnchorFromUrlFoswiki::splitAnchorFromUrl
0000s0sFoswiki::::urlDecodeFoswiki::urlDecode
0000s0sFoswiki::::urlEncodeAttachmentFoswiki::urlEncodeAttachment
0000s0sFoswiki::::validatePatternFoswiki::validatePattern
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2package Foswiki;
3
4=begin TML
5
6---+ package Foswiki
7
8Foswiki operates by creating a singleton object (known as the Session
9object) that acts as a point of reference for all the different
10modules in the system. This package is the class for this singleton,
11and also contains the vast bulk of the basic constants and the per-
12site configuration mechanisms.
13
14Global variables are avoided wherever possible to avoid problems
15with 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 * =access= 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
44243µs238µs
# spent 31µs (24+7) within Foswiki::BEGIN@44 which was called: # once (24µs+7µs) by main::BEGIN@27 at line 44
use strict;
# spent 31µs making 1 call to Foswiki::BEGIN@44 # spent 7µs making 1 call to strict::import
45241µs251µs
# spent 34µs (16+18) within Foswiki::BEGIN@45 which was called: # once (16µs+18µs) by main::BEGIN@27 at line 45
use warnings;
# spent 34µs making 1 call to Foswiki::BEGIN@45 # spent 18µs making 1 call to warnings::import
462162µs24.73ms
# spent 4.68ms (1.21+3.47) within Foswiki::BEGIN@46 which was called: # once (1.21ms+3.47ms) by main::BEGIN@27 at line 46
use Assert;
# spent 4.68ms making 1 call to Foswiki::BEGIN@46 # spent 46µs making 1 call to Assert::import
472168µs29.64ms
# spent 9.19ms (4.43+4.76) within Foswiki::BEGIN@47 which was called: # once (4.43ms+4.76ms) by main::BEGIN@27 at line 47
use Error qw( :try );
# spent 9.19ms making 1 call to Foswiki::BEGIN@47 # spent 448µs making 1 call to Error::import
482171µs13.41ms
# spent 3.41ms (2.94+476µs) within Foswiki::BEGIN@48 which was called: # once (2.94ms+476µs) by main::BEGIN@27 at line 48
use Monitor ();
# spent 3.41ms making 1 call to Foswiki::BEGIN@48
492180µs118.7ms
# spent 18.7ms (11.9+6.87) within Foswiki::BEGIN@49 which was called: # once (11.9ms+6.87ms) by main::BEGIN@27 at line 49
use CGI (); # Always required to get html generation tags;
# spent 18.7ms making 1 call to Foswiki::BEGIN@49
502191µs11.59ms
# spent 1.59ms (1.12+472µs) within Foswiki::BEGIN@50 which was called: # once (1.12ms+472µs) by main::BEGIN@27 at line 50
use Digest::MD5 (); # For passthru and validation
# spent 1.59ms making 1 call to Foswiki::BEGIN@50
5124.84ms12.08ms
# spent 2.08ms (2.00+83µs) within Foswiki::BEGIN@51 which was called: # once (2.00ms+83µs) by main::BEGIN@27 at line 51
use Foswiki::Configure::Load ();
# spent 2.08ms making 1 call to Foswiki::BEGIN@51
52
53127µsrequire 5.005; # For regex objects and internationalisation
54
55# Site configuration constants
5612µsour %cfg;
57
58# Other computed constants
5912µsour $foswikiLibDir;
6011µsour %regex;
6111µsour %macros;
6211µsour %contextFreeSyntax;
6311µsour $VERSION;
6411µsour $RELEASE;
6512µsour $TRUE = 1;
6611µsour $FALSE = 0;
671800nsour $engine;
6812µsour $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
7611µsour $RENDERZONE_MARKER = "\3";
77
78# Used by takeOut/putBack blocks
7911µsour $BLOCKID = 0;
8012µsour $OC = "<!--\0";
8111µsour $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.
8611µsour $inUnitTestMode = 0;
87
88# Returns the full path of the directory containing Foswiki.pm
89
# spent 92µs (57+35) within Foswiki::_getLibDir which was called: # once (57µs+35µs) by Foswiki::BEGIN@134 at line 588
sub _getLibDir {
9012µs return $foswikiLibDir if $foswikiLibDir;
91
9213µs $foswikiLibDir = $INC{'Foswiki.pm'};
93
94 # fix path relative to location of called script
9519µs13µs if ( $foswikiLibDir =~ /^\./ ) {
# spent 3µs making 1 call to Foswiki::CORE:match
96 print STDERR
97"WARNING: Foswiki lib path $foswikiLibDir is relative; you should make it absolute, otherwise some scripts may not run from the command line.";
98 my $bin;
99
100 # SMELL : Should not assume environment variables; get data from request
101 if ( $ENV{SCRIPT_FILENAME}
102 && $ENV{SCRIPT_FILENAME} =~ m#^(.+)/.+?$# )
103 {
104
105 # CGI script name
106 # implicit untaint OK, because of use of $SCRIPT_FILENAME
107 $bin = $1;
108 }
109 elsif ( $0 =~ m#^(.*)/.*?$# ) {
110
111 # program name
112 # implicit untaint OK, because of use of $PROGRAM_NAME ($0)
113 $bin = $1;
114 }
115 else {
116
117 # last ditch; relative to current directory.
118 require Cwd;
119 $bin = Cwd::cwd();
120 }
121 $foswikiLibDir = "$bin/$foswikiLibDir/";
122
123 # normalize "/../" and "/./"
124 while ( $foswikiLibDir =~ s|([\\/])[^\\/]+[\\/]\.\.[\\/]|$1| ) {
125 }
126 $foswikiLibDir =~ s|([\\/])\.[\\/]|$1|g;
127 }
128164µs1030µs $foswikiLibDir =~ s|([\\/])[\\/]*|$1|g; # reduce "//" to "/"
# spent 25µs making 9 calls to Foswiki::CORE:substcont, avg 3µs/call # spent 5µs making 1 call to Foswiki::CORE:subst
12919µs13µs $foswikiLibDir =~ s|[\\/]$||; # cut trailing "/"
# spent 3µs making 1 call to Foswiki::CORE:subst
130
13116µs return $foswikiLibDir;
132}
133
134
# spent 50.1ms (781µs+49.4) within Foswiki::BEGIN@134 which was called: # once (781µs+49.4ms) by main::BEGIN@27 at line 601
BEGIN {
135
136 #Monitor::MARK("Start of BEGIN block in Foswiki.pm");
13717µs15µs if (DEBUG) {
# spent 5µs making 1 call to Assert::ASSERTS_OFF
138 if ( not $Assert::soft ) {
139
140 # If ASSERTs are on (and not soft), then warnings are errors.
141 # Paranoid, but the only way to be sure we eliminate them all.
142 # Look out also for $cfg{WarningsAreErrors}, below, which
143 # is another way to install this handler without enabling
144 # ASSERTs
145 # ASSERTS are turned on by defining the environment variable
146 # FOSWIKI_ASSERTS. If ASSERTs are off, this is assumed to be a
147 # production environment, and no stack traces or paths are
148 # output to the browser.
149 $SIG{'__WARN__'} = sub { die @_ };
150 $Error::Debug = 1; # verbose stack traces, please
151 }
152 else {
153
154 # ASSERTs are soft, so warnings are not errors
155 # but ASSERTs are enabled. This is useful for tracking down
156 # problems that only manifest on production servers.
157 # Consequently, this is only useful when
158 # $cfg{WarningsAreErrors} is NOT enabled
159 $Error::Debug = 0; # no verbose stack traces
160 }
161 }
162 else {
16312µs $Error::Debug = 0; # no verbose stack traces
164 }
165
166 # DO NOT CHANGE THE FORMAT OF $VERSION
167 # Automatically expanded on checkin of this module
16812µs $VERSION = '$Date$ $Rev$ ';
16911µs $RELEASE = 'Foswiki-1.2.0-alpha';
17019µs13µs $VERSION =~ s/^.*?\((.*)\).*: (\d+) .*?$/$RELEASE, $1, build $2/;
# spent 3µs making 1 call to Foswiki::CORE:subst
171
172 # Default handlers for different %TAGS%
173 # Where an entry is set as 'undef', the tag will be demand-loaded
174 # from Foswiki::Macros, if it is used. This tactic is used to reduce
175 # the load time of this module, especially when it is used from
176 # REST handlers.
177 %macros = (
178 ADDTOHEAD => undef,
179
180 # deprecated, use ADDTOZONE instead
181 ADDTOZONE => undef,
182 ALLVARIABLES => sub { $_[0]->{prefs}->stringify() },
183 ATTACHURL =>
184 sub { return $_[0]->getPubUrl( 1, $_[2]->web, $_[2]->topic ); },
185 ATTACHURLPATH =>
186 sub { return $_[0]->getPubUrl( 0, $_[2]->web, $_[2]->topic ); },
187 DATE => sub {
188 Foswiki::Time::formatTime(
189 time(),
190 $Foswiki::cfg{DefaultDateFormat},
191 $Foswiki::cfg{DisplayTimeValues}
192 );
193 },
194 DISPLAYTIME => sub {
195 Foswiki::Time::formatTime(
196 time(),
197 $_[1]->{_DEFAULT} || '',
198 $Foswiki::cfg{DisplayTimeValues}
199 );
200 },
201 ENCODE => undef,
202 ENV => undef,
203 EXPAND => undef,
204 FORMAT => undef,
205 FORMFIELD => undef,
206
# spent 1.01ms (76µs+936µs) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:209] which was called 5 times, avg 202µs/call: # 5 times (76µs+936µs) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 202µs/call
GMTIME => sub {
207581µs5936µs Foswiki::Time::formatTime( time(), $_[1]->{_DEFAULT} || '',
# spent 936µs making 5 calls to Foswiki::Time::formatTime, avg 187µs/call
208 'gmtime' );
209 },
210 GROUPINFO => undef,
211 GROUPS => undef,
212 HTTP_HOST =>
213
214 #deprecated functionality, now implemented using %ENV%
215 sub { $_[0]->{request}->header('Host') || '' },
216 HTTP => undef,
217 HTTPS => undef,
218 ICON => undef,
219 ICONURL => undef,
220 ICONURLPATH => undef,
221 IF => undef,
222 INCLUDE => undef,
223 INTURLENCODE => undef,
224 LANGUAGE => sub { $_[0]->i18n->language(); },
225 LANGUAGES => undef,
226 MAKETEXT => undef,
227 META => undef, # deprecated
228 METASEARCH => undef, # deprecated
229 NOP =>
230
231 # Remove NOP tag in template topics but show content.
232 # Used in template _topics_ (not templates, per se, but
233 # topics used as templates for new topics)
234 sub { $_[1]->{_RAW} ? $_[1]->{_RAW} : '<nop>' },
235 PLUGINVERSION => sub {
236 $_[0]->{plugins}->getPluginVersion( $_[1]->{_DEFAULT} );
237 },
23811121µs11292µs
# spent 419µs (127+292) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:238] which was called 11 times, avg 38µs/call: # 11 times (127µs+292µs) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 38µs/call
PUBURL => sub { $_[0]->getPubUrl(1) },
# spent 292µs making 11 calls to Foswiki::getPubUrl, avg 27µs/call
23925236µs251.19ms
# spent 1.44ms (256µs+1.19) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:239] which was called 25 times, avg 58µs/call: # 25 times (256µs+1.19ms) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 58µs/call
PUBURLPATH => sub { $_[0]->getPubUrl(0) },
# spent 1.19ms making 25 calls to Foswiki::getPubUrl, avg 48µs/call
240 QUERY => undef,
241 QUERYPARAMS => undef,
242242µs2184µs
# spent 220µs (37+184) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:242] which was called 2 times, avg 110µs/call: # 2 times (37µs+184µs) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 110µs/call
QUERYSTRING => sub { $_[0]->{request}->queryString() },
# spent 184µs making 2 calls to Foswiki::Request::queryString, avg 92µs/call
243 RELATIVETOPICPATH => undef,
244 REMOTE_ADDR =>
245
246 # DEPRECATED, now implemented using %ENV%
247 #move to compatibility plugin in Foswiki 2.0
248 sub { $_[0]->{request}->remoteAddress() || ''; },
249 REMOTE_PORT =>
250
251 # DEPRECATED
252 # CGI/1.1 (RFC 3875) doesn't specify REMOTE_PORT,
253 # but some webservers implement it. However, since
254 # it's not RFC compliant, Foswiki should not rely on
255 # it. So we get more portability.
256 sub { '' },
257 REMOTE_USER =>
258
259 # DEPRECATED
260 sub { $_[0]->{request}->remoteUser() || '' },
261 RENDERZONE => undef,
262 REVINFO => undef,
263 REVTITLE => undef,
264 REVARG => undef,
265120µs116µs
# spent 35µs (19+16) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:265] which was called: # once (19µs+16µs) by Foswiki::_expandMacroOnTopicRendering at line 3066
SCRIPTNAME => sub { $_[0]->{request}->action() },
# spent 16µs making 1 call to Foswiki::Request::action
26627351µs271.19ms
# spent 1.58ms (389µs+1.19) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:266] which was called 27 times, avg 59µs/call: # 27 times (389µs+1.19ms) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 59µs/call
SCRIPTURL => sub { $_[0]->getScriptUrl( 1, $_[1]->{_DEFAULT} || '' ) },
# spent 1.19ms making 27 calls to Foswiki::getScriptUrl, avg 44µs/call
267 SCRIPTURLPATH =>
26814181µs14948µs
# spent 1.16ms (210µs+948µs) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:268] which was called 14 times, avg 83µs/call: # 14 times (210µs+948µs) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 83µs/call
sub { $_[0]->getScriptUrl( 0, $_[1]->{_DEFAULT} || '' ) },
# spent 948µs making 14 calls to Foswiki::getScriptUrl, avg 68µs/call
269 SEARCH => undef,
270 SEP =>
271
272 # Shortcut to %TMPL:P{"sep"}%
273 sub { $_[0]->templates->expandTemplate('sep') },
274
# spent 330µs (18+312) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:277] which was called: # once (18µs+312µs) by Foswiki::_expandMacroOnTopicRendering at line 3066
SERVERTIME => sub {
275123µs1312µs Foswiki::Time::formatTime( time(), $_[1]->{_DEFAULT} || '',
# spent 312µs making 1 call to Foswiki::Time::formatTime
276 'servertime' );
277 },
278 SHOWPREFERENCE => undef,
279 SPACEDTOPIC => undef,
280 SPACEOUT => undef,
2819163µs181.28ms
# spent 1.47ms (183µs+1.28) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:281] which was called 9 times, avg 163µs/call: # 9 times (183µs+1.28ms) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 163µs/call
'TMPL:P' => sub { $_[0]->templates->tmplP( $_[1] ) },
# spent 1.20ms making 9 calls to Foswiki::Templates::tmplP, avg 134µs/call # spent 79µs making 9 calls to Foswiki::templates, avg 9µs/call
282 TOPICLIST => undef,
283 URLENCODE => undef,
284 URLPARAM => undef,
285 USERINFO => undef,
286 USERNAME => undef,
287 VAR => undef,
288 WEBLIST => undef,
289 WIKINAME => undef,
290 WIKIUSERNAME => undef,
291 DISPLAYDEPENDENCIES => undef,
292
293 # Constant tag strings _not_ dependent on config. These get nicely
294 # optimised by the compiler.
295 ENDSECTION => sub { '' },
296 WIKIVERSION => sub { $VERSION },
297 STARTSECTION => sub { '' },
298 STARTINCLUDE => sub { '' },
299 STOPINCLUDE => sub { '' },
3001259µs );
30112µs $contextFreeSyntax{IF} = 1;
302
30314µs unless ( ( $Foswiki::cfg{DetailedOS} = $^O ) ) {
304 require Config;
305 $Foswiki::cfg{DetailedOS} = $Config::Config{'osname'};
306 }
30712µs $Foswiki::cfg{OS} = 'UNIX';
308148µs724µs if ( $Foswiki::cfg{DetailedOS} =~ /darwin/i ) { # MacOS X
# spent 24µs making 7 calls to Foswiki::CORE:match, avg 3µs/call
309 $Foswiki::cfg{OS} = 'UNIX';
310 }
311 elsif ( $Foswiki::cfg{DetailedOS} =~ /Win/i ) {
312 $Foswiki::cfg{OS} = 'WINDOWS';
313 }
314 elsif ( $Foswiki::cfg{DetailedOS} =~ /vms/i ) {
315 $Foswiki::cfg{OS} = 'VMS';
316 }
317 elsif ( $Foswiki::cfg{DetailedOS} =~ /bsdos/i ) {
318 $Foswiki::cfg{OS} = 'UNIX';
319 }
320 elsif ( $Foswiki::cfg{DetailedOS} =~ /dos/i ) {
321 $Foswiki::cfg{OS} = 'DOS';
322 }
323 elsif ( $Foswiki::cfg{DetailedOS} =~ /^MacOS$/i ) { # MacOS 9 or earlier
324 $Foswiki::cfg{OS} = 'MACINTOSH';
325 }
326 elsif ( $Foswiki::cfg{DetailedOS} =~ /os2/i ) {
327 $Foswiki::cfg{OS} = 'OS2';
328 }
329
330 # readConfig is defined in Foswiki::Configure::Load to allow overriding it
33118µs124.5ms if ( Foswiki::Configure::Load::readConfig() ) {
# spent 24.5ms making 1 call to Foswiki::Configure::Load::readConfig
33213µs $Foswiki::cfg{isVALID} = 1;
333 }
334
33512µs if ( $Foswiki::cfg{WarningsAreErrors} ) {
336
337 # Note: Warnings are always errors if ASSERTs are enabled
338 $SIG{'__WARN__'} = sub { die @_ };
339 }
340
34112µs if ( $Foswiki::cfg{UseLocale} ) {
342 require locale;
343 import locale();
344 }
345
346 # If not set, default to strikeone validation
34712µs $Foswiki::cfg{Validation}{Method} ||= 'strikeone';
34812µs $Foswiki::cfg{Validation}{ValidForTime} = $Foswiki::cfg{LeaseLength}
349 unless defined $Foswiki::cfg{Validation}{ValidForTime};
35013µs $Foswiki::cfg{Validation}{MaxKeys} = 1000
351 unless defined $Foswiki::cfg{Validation}{MaxKeys};
352
353 # Constant tags dependent on the config
354 $macros{ALLOWLOGINNAME} =
355120µs sub { $Foswiki::cfg{Register}{AllowLoginName} || 0 };
35615µs $macros{AUTHREALM} = sub { $Foswiki::cfg{AuthRealm} };
35714µs $macros{DEFAULTURLHOST} = sub { $Foswiki::cfg{DefaultUrlHost} };
358429µs
# spent 22µs within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:358] which was called 3 times, avg 7µs/call: # 3 times (22µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 7µs/call
$macros{HOMETOPIC} = sub { $Foswiki::cfg{HomeTopicName} };
35914µs $macros{LOCALSITEPREFS} = sub { $Foswiki::cfg{LocalSitePreferences} };
360 $macros{NOFOLLOW} =
36114µs sub { $Foswiki::cfg{NoFollow} ? 'rel=' . $Foswiki::cfg{NoFollow} : '' };
36214µs $macros{NOTIFYTOPIC} = sub { $Foswiki::cfg{NotifyTopicName} };
363214µs
# spent 8µs within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:363] which was called: # once (8µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3066
$macros{SCRIPTSUFFIX} = sub { $Foswiki::cfg{ScriptSuffix} };
36415µs $macros{STATISTICSTOPIC} = sub { $Foswiki::cfg{Stats}{TopicName} };
36548294µs
# spent 236µs within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:365] which was called 47 times, avg 5µs/call: # 47 times (236µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 5µs/call
$macros{SYSTEMWEB} = sub { $Foswiki::cfg{SystemWebName} };
36614µs $macros{TRASHWEB} = sub { $Foswiki::cfg{TrashWebName} };
36714µs $macros{SANDBOXWEB} = sub { $Foswiki::cfg{SandboxWebName} };
36813µs $macros{WIKIADMINLOGIN} = sub { $Foswiki::cfg{AdminUserLogin} };
369750µs
# spent 43µs within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:369] which was called 6 times, avg 7µs/call: # 6 times (43µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 7µs/call
$macros{USERSWEB} = sub { $Foswiki::cfg{UsersWebName} };
37014µs $macros{WEBPREFSTOPIC} = sub { $Foswiki::cfg{WebPrefsTopicName} };
37113µs $macros{WIKIPREFSTOPIC} = sub { $Foswiki::cfg{SitePrefsTopicName} };
37214µs $macros{WIKIUSERSTOPIC} = sub { $Foswiki::cfg{UsersTopicName} };
37313µs $macros{WIKIWEBMASTER} = sub { $Foswiki::cfg{WebMasterEmail} };
37414µs $macros{WIKIWEBMASTERNAME} = sub { $Foswiki::cfg{WebMasterName} };
375
376 # locale setup
377 #
378 #
379 # Note that 'use locale' must be done in BEGIN block for regexes and
380 # sorting to work properly, although regexes can still work without
381 # this in 'non-locale regexes' mode.
382
38312µs if ( $Foswiki::cfg{UseLocale} ) {
384
385 # Set environment variables for grep
386 $ENV{LC_CTYPE} = $Foswiki::cfg{Site}{Locale};
387
388 # Load POSIX for I18N support.
389 require POSIX;
390 import POSIX qw( locale_h LC_CTYPE LC_COLLATE );
391
392 # SMELL: mod_perl compatibility note: If Foswiki is running under Apache,
393 # won't this play with the Apache process's locale settings too?
394 # What effects would this have?
395 setlocale( &LC_CTYPE, $Foswiki::cfg{Site}{Locale} );
396 setlocale( &LC_COLLATE, $Foswiki::cfg{Site}{Locale} );
397 }
398
399
# spent 7µs within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:401] which was called: # once (7µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3066
$macros{CHARSET} = sub {
400110µs $Foswiki::cfg{Site}{CharSet};
40114µs };
402
403
# spent 40µs (28+12) within Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:405] which was called 2 times, avg 20µs/call: # 2 times (28µs+12µs) by Foswiki::_expandMacroOnTopicRendering at line 3066, avg 20µs/call
$macros{LANG} = sub {
404243µs212µs $Foswiki::cfg{Site}{Locale} =~ m/^([a-z]+_[a-z]+)/i ? $1 : 'en_US';
# spent 12µs making 2 calls to Foswiki::CORE:match, avg 6µs/call
40514µs };
406
407 # Set up pre-compiled regexes for use in rendering. All regexes with
408 # unchanging variables in match should use the '/o' option.
409 # In the regex hash, all precompiled REs have "Regex" at the
410 # end of the name. Anything else is a string, either intended
411 # for use as a character class, or as a sub-expression in
412 # another compiled RE.
413
414 # Build up character class components for use in regexes.
415 # Depends on locale mode and Perl version, and finally on
416 # whether locale-based regexes are turned off.
41716µs if ( $] < 5.006 or not $Foswiki::cfg{Site}{LocaleRegexes} ) {
418
419 # No locales needed/working, or Perl 5.005, so just use
420 # any additional national characters defined in LocalSite.cfg
421 $regex{upperAlpha} = 'A-Z' . $Foswiki::cfg{UpperNational};
422 $regex{lowerAlpha} = 'a-z' . $Foswiki::cfg{LowerNational};
423 $regex{numeric} = '\d';
424 $regex{mixedAlpha} = $regex{upperAlpha} . $regex{lowerAlpha};
425 }
426 else {
427
428 # Perl 5.006 or higher with working locales
42913µs $regex{upperAlpha} = '[:upper:]';
43012µs $regex{lowerAlpha} = '[:lower:]';
43112µs $regex{numeric} = '[:digit:]';
43212µs $regex{mixedAlpha} = '[:alpha:]';
433 }
43413µs $regex{mixedAlphaNum} = $regex{mixedAlpha} . $regex{numeric};
43513µs $regex{lowerAlphaNum} = $regex{lowerAlpha} . $regex{numeric};
43613µs $regex{upperAlphaNum} = $regex{upperAlpha} . $regex{numeric};
437
438 # Compile regexes for efficiency and ease of use
439 # Note: qr// locks in regex modes (i.e. '-xism' here) - see Friedl
440 # book at http://regex.info/.
441
44213µs $regex{linkProtocolPattern} = $Foswiki::cfg{LinkProtocolPattern};
443
444 # Header patterns based on '+++'. The '###' are reserved for numbered
445 # headers
446 # '---++ Header', '---## Header'
447116µs15µs $regex{headerPatternDa} = qr/^---+(\++|\#+)(.*)$/m;
# spent 5µs making 1 call to Foswiki::CORE:qr
448
449 # '<h6>Header</h6>
45018µs13µs $regex{headerPatternHt} = qr/^<h([1-6])>(.+?)<\/h\1>/mi;
# spent 3µs making 1 call to Foswiki::CORE:qr
451
452 # '---++!! Header' or '---++ Header %NOTOC% ^top'
45312µs $regex{headerPatternNoTOC} = '(\!\!+|%NOTOC%)';
454
455 # Foswiki concept regexes
456148µs234µs $regex{wikiWordRegex} = qr(
# spent 31µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
457 [$regex{upperAlpha}]+
458 [$regex{lowerAlphaNum}]+
459 [$regex{upperAlpha}]+
460 [$regex{mixedAlphaNum}]*
461 )xo;
462127µs216µs $regex{webNameBaseRegex} =
# spent 13µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
463 qr/[$regex{upperAlpha}]+[$regex{mixedAlphaNum}_]*/o;
46413µs if ( $Foswiki::cfg{EnableHierarchicalWebs} ) {
465140µs229µs $regex{webNameRegex} = qr(
# spent 26µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
466 $regex{webNameBaseRegex}
467 (?:(?:[\.\/]$regex{webNameBaseRegex})+)*
468 )xo;
469 }
470 else {
471 $regex{webNameRegex} = $regex{webNameBaseRegex};
472 }
473126µs215µs $regex{defaultWebNameRegex} = qr/_[$regex{mixedAlphaNum}_]+/o;
# spent 12µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
474126µs216µs $regex{anchorRegex} = qr/\#[$regex{mixedAlphaNum}_]+/o;
# spent 13µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
475126µs216µs $regex{abbrevRegex} = qr/[$regex{upperAlpha}]{3,}s?\b/o;
# spent 13µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
476
477146µs232µs $regex{topicNameRegex} =
# spent 30µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
478 qr/(?:(?:$regex{wikiWordRegex})|(?:$regex{abbrevRegex}))/o;
479
480 # Email regex, e.g. for WebNotify processing and email matching
481 # during rendering.
482
483126µs216µs my $emailAtom = qr([A-Z0-9\Q!#\$%&'*+-/=?^_`{|}~\E])i; # Per RFC 5322
# spent 14µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
484
485 # Valid TLD's at http://data.iana.org/TLD/tlds-alpha-by-domain.txt
486 # Version 2011083000, Last Updated Tue Aug 30 14:07:02 2011 UTC
48718µs13µs my $validTLD =
# spent 3µs making 1 call to Foswiki::CORE:qr
488qr(AERO|ARPA|ASIA|BIZ|CAT|COM|COOP|EDU|GOV|INFO|INT|JOBS|MIL|MOBI|MUSEUM|NAME|NET|ORG|PRO|TEL|TRAVEL|XXX)i;
489
490195µs283µs $regex{emailAddrRegex} = qr(
# spent 80µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
491 (?: # LEFT Side of Email address
492 (?:$emailAtom+ # Valid characters left side of email address
493 (?:\.$emailAtom+)* # And 0 or more dotted atoms
494 )
495 |
496 (?:"[\x21\x23-\x5B\x5D-\x7E\s]+?") # or a quoted string per RFC 5322
497 )
498 @
499 (?: # RIGHT side of Email address
500 (?: # FQDN
501 [a-z0-9-]+ # hostname part
502 (?:\.[a-z0-9-]+)* # 0 or more alphanumeric domains following a dot.
503 \.(?: # TLD
504 (?:[a-z]{2,2}) # 2 character TLD
505 |
506 $validTLD # TLD's longer than 2 characters
507 )
508 )
509 |
510 (?:\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\]) # dotted triplets IP Address
511 )
512 )oxi;
513
514 # Item11185: This is how things were before we began Operation Unicode:
515 #
516 # $regex{filenameInvalidCharRegex} = qr/[^$regex{mixedAlphaNum}\. _-]/o;
517 #
518 # It was only used in Foswiki::Sandbox::sanitizeAttachmentName(), which now
519 # uses $Foswiki::cfg{NameFilter} instead.
520 # See RobustnessTests::test_sanitizeAttachmentName
521 #
522 # Actually, this is used in GenPDFPrincePlugin; let's copy NameFilter
52313µs $regex{filenameInvalidCharRegex} = $Foswiki::cfg{NameFilter};
524
525 # Multi-character alpha-based regexes
526125µs214µs $regex{mixedAlphaNumRegex} = qr/[$regex{mixedAlphaNum}]*/o;
# spent 12µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
527
528 # %TAG% name
52914µs $regex{tagNameRegex} =
530 '[' . $regex{mixedAlpha} . '][' . $regex{mixedAlphaNum} . '_:]*';
531
532 # Set statement in a topic
53312µs $regex{bulletRegex} = '^(?:\t| )+\*';
53413µs $regex{setRegex} = $regex{bulletRegex} . '\s+(Set|Local)\s+';
53513µs $regex{setVarRegex} =
536 $regex{setRegex} . '(' . $regex{tagNameRegex} . ')\s*=\s*(.*)$';
537
538 # Character encoding regexes
539
540 # 7-bit ASCII only
541115µs14µs $regex{validAsciiStringRegex} = qr/^[\x00-\x7F]+$/o;
# spent 4µs making 1 call to Foswiki::CORE:qr
542
543 # Regex to match only a valid UTF-8 character, taking care to avoid
544 # security holes due to overlong encodings by excluding the relevant
545 # gaps in UTF-8 encoding space - see 'perldoc perlunicode', Unicode
546 # Encodings section. Tested against Markus Kuhn's UTF-8 test file
547 # at http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt.
548110µs13µs $regex{validUtf8CharRegex} = qr{
# spent 3µs making 1 call to Foswiki::CORE:qr
549 # Single byte - ASCII
550 [\x00-\x7F]
551 |
552
553 # 2 bytes
554 [\xC2-\xDF][\x80-\xBF]
555 |
556
557 # 3 bytes
558
559 # Avoid illegal codepoints - negative lookahead
560 (?!\xEF\xBF[\xBE\xBF])
561
562 # Match valid codepoints
563 (?:
564 ([\xE0][\xA0-\xBF])|
565 ([\xE1-\xEC\xEE-\xEF][\x80-\xBF])|
566 ([\xED][\x80-\x9F])
567 )
568 [\x80-\xBF]
569 |
570
571 # 4 bytes
572 (?:
573 ([\xF0][\x90-\xBF])|
574 ([\xF1-\xF3][\x80-\xBF])|
575 ([\xF4][\x80-\x8F])
576 )
577 [\x80-\xBF][\x80-\xBF]
578 }xo;
579
580165µs254µs $regex{validUtf8StringRegex} = qr/^(?:$regex{validUtf8CharRegex})+$/o;
# spent 50µs making 1 call to Foswiki::CORE:regcomp # spent 3µs making 1 call to Foswiki::CORE:qr
581
582 # Check for unsafe search regex mode (affects filtering in) - default
583 # to safe mode
58412µs $Foswiki::cfg{ForceUnsafeRegexes} = 0
585 unless defined $Foswiki::cfg{ForceUnsafeRegexes};
586
587 # initialize lib directory early because of later 'cd's
58816µs192µs _getLibDir();
# spent 92µs making 1 call to Foswiki::_getLibDir
589
590 # initialize the runtime engine
59112µs if ( !defined $Foswiki::cfg{Engine} ) {
592
593 # Caller did not define an engine; try and work it out (mainly for
594 # the benefit of pre-1.0 CGI scripts)
595 $Foswiki::cfg{Engine} = 'Foswiki::Engine::Legacy';
596 }
597169µs $engine = eval qq(use $Foswiki::cfg{Engine}; $Foswiki::cfg{Engine}->new);
# spent 189µs executing statements in string eval
# includes 2.06ms spent executing 1 call to 1 sub defined therein.
598113µs die $@ if $@;
599
600 #Monitor::MARK('End of BEGIN block in Foswiki.pm');
601135µs150.1ms}
# spent 50.1ms making 1 call to Foswiki::BEGIN@134
602
603# Components that all requests need
604238µs19µs
# spent 9µs within Foswiki::BEGIN@604 which was called: # once (9µs+0s) by main::BEGIN@27 at line 604
use Foswiki::Response ();
# spent 9µs making 1 call to Foswiki::BEGIN@604
605240µs19µs
# spent 9µs within Foswiki::BEGIN@605 which was called: # once (9µs+0s) by main::BEGIN@27 at line 605
use Foswiki::Request ();
# spent 9µs making 1 call to Foswiki::BEGIN@605
6062129µs1558µs
# spent 558µs (425+133) within Foswiki::BEGIN@606 which was called: # once (425µs+133µs) by main::BEGIN@27 at line 606
use Foswiki::Logger ();
# spent 558µs making 1 call to Foswiki::BEGIN@606
6072249µs126.4ms
# spent 26.4ms (21.7+4.68) within Foswiki::BEGIN@607 which was called: # once (21.7ms+4.68ms) by main::BEGIN@27 at line 607
use Foswiki::Meta ();
# spent 26.4ms making 1 call to Foswiki::BEGIN@607
6082205µs131.2ms
# spent 31.2ms (4.16+27.0) within Foswiki::BEGIN@608 which was called: # once (4.16ms+27.0ms) by main::BEGIN@27 at line 608
use Foswiki::Sandbox ();
# spent 31.2ms making 1 call to Foswiki::BEGIN@608
6092174µs14.19ms
# spent 4.19ms (4.05+144µs) within Foswiki::BEGIN@609 which was called: # once (4.05ms+144µs) by main::BEGIN@27 at line 609
use Foswiki::Time ();
# spent 4.19ms making 1 call to Foswiki::BEGIN@609
6102148µs17.91ms
# spent 7.91ms (3.17+4.74) within Foswiki::BEGIN@610 which was called: # once (3.17ms+4.74ms) by main::BEGIN@27 at line 610
use Foswiki::Prefs ();
# spent 7.91ms making 1 call to Foswiki::BEGIN@610
6112153µs110.1ms
# spent 10.1ms (3.08+7.06) within Foswiki::BEGIN@611 which was called: # once (3.08ms+7.06ms) by main::BEGIN@27 at line 611
use Foswiki::Plugins ();
# spent 10.1ms making 1 call to Foswiki::BEGIN@611
6122171µs12.07ms
# spent 2.07ms (1.52+549µs) within Foswiki::BEGIN@612 which was called: # once (1.52ms+549µs) by main::BEGIN@27 at line 612
use Foswiki::Store ();
# spent 2.07ms making 1 call to Foswiki::BEGIN@612
61328.43ms114.4ms
# spent 14.4ms (4.91+9.51) within Foswiki::BEGIN@613 which was called: # once (4.91ms+9.51ms) by main::BEGIN@27 at line 613
use Foswiki::Users ();
# spent 14.4ms making 1 call to Foswiki::BEGIN@613
614
615
# spent 51µs (35+16) within Foswiki::UTF82SiteCharSet which was called 2 times, avg 26µs/call: # once (21µs+9µs) by Foswiki::new at line 1808 # once (15µs+7µs) by Foswiki::new at line 1847
sub UTF82SiteCharSet {
61626µs my ( $this, $text ) = @_;
617
618 # Detect character encoding of the full topic name from URL
619252µs416µs return if ( $text =~ $regex{validAsciiStringRegex} );
# spent 9µs making 2 calls to Foswiki::CORE:match, avg 4µs/call # spent 7µs making 2 calls to Foswiki::CORE:regcomp, avg 3µs/call
620
621 # SMELL: all this regex stuff should go away.
622 # If not UTF-8 - assume in site character set, no conversion required
623 if ( $^O eq 'darwin' ) {
624
625 #this is a gross over-generalisation - as not all darwins are apple's
626 # and not all darwins use apple's perl
627 my $trial = $text;
628 $trial =~ s/$regex{validUtf8CharRegex}//g;
629 return unless ( length($trial) == 0 );
630 }
631 else {
632
633 #SMELL: this seg faults on OSX leopard. (and possibly others)
634 return unless ( $text =~ $regex{validUtf8StringRegex} );
635 }
636
637 # If site charset is already UTF-8, there is no need to convert anything:
638 if ( $Foswiki::cfg{Site}{CharSet} =~ /^utf-?8$/i ) {
639
640 # warn if using Perl older than 5.8
641 if ( $] < 5.008 ) {
642 $this->logger->log( 'warning',
643 'UTF-8 not remotely supported on Perl '
644 . $]
645 . ' - use Perl 5.8 or higher..' );
646 }
647
648 return $text;
649 }
650
651 # Convert into ISO-8859-1 if it is the site charset. This conversion
652 # is *not valid for ISO-8859-15*.
653 if ( $Foswiki::cfg{Site}{CharSet} =~ /^iso-?8859-?1$/i ) {
654
655 # ISO-8859-1 maps onto first 256 codepoints of Unicode
656 # (conversion from 'perldoc perluniintro')
657 $text =~ s/ ([\xC2\xC3]) ([\x80-\xBF]) /
658 chr( ord($1) << 6 & 0xC0 | ord($2) & 0x3F )
659 /egx;
660 }
661 else {
662
663 # Convert from UTF-8 into some other site charset
664 if ( $] >= 5.008 ) {
665 require Encode;
666 import Encode qw(:fallbacks);
667
668 # Map $Foswiki::cfg{Site}{CharSet} into real encoding name
669 my $charEncoding =
670 Encode::resolve_alias( $Foswiki::cfg{Site}{CharSet} );
671 if ( not $charEncoding ) {
672 $this->logger->log( 'warning',
673 'Conversion to "'
674 . $Foswiki::cfg{Site}{CharSet}
675 . '" not supported, or name not recognised - check '
676 . '"perldoc Encode::Supported"' );
677 }
678 else {
679
680 # Convert text using Encode:
681 # - first, convert from UTF8 bytes into internal
682 # (UTF-8) characters
683 $text = Encode::decode( 'utf8', $text );
684
685 # - then convert into site charset from internal UTF-8,
686 # inserting \x{NNNN} for characters that can't be converted
687 $text = Encode::encode( $charEncoding, $text, &FB_PERLQQ() );
688 }
689 }
690 else {
691 require Unicode::MapUTF8; # Pre-5.8 Perl versions
692 my $charEncoding = $Foswiki::cfg{Site}{CharSet};
693 if ( not Unicode::MapUTF8::utf8_supported_charset($charEncoding) ) {
694 $this->logger->log( 'warning',
695 'Conversion to "'
696 . $Foswiki::cfg{Site}{CharSet}
697 . '" not supported, or name not recognised - check '
698 . '"perldoc Unicode::MapUTF8"' );
699 }
700 else {
701
702 # Convert text
703 $text = Unicode::MapUTF8::from_utf8(
704 {
705 -string => $text,
706 -charset => $charEncoding
707 }
708 );
709
710 # FIXME: Check for failed conversion?
711 }
712 }
713 }
714 return $text;
715}
716
717=begin TML
718
719---++ ObjectMethod writeCompletePage( $text, $pageType, $contentType )
720
721Write a complete HTML page with basic header to the browser.
722 * =$text= is the text of the page script (&lt;html&gt; to &lt;/html&gt; if it's HTML)
723 * =$pageType= - May be "edit", which will cause headers to be generated that force
724 caching for 24 hours, to prevent Codev.BackFromPreviewLosesText bug, which caused
725 data loss with IE5 and IE6.
726 * =$contentType= - page content type | text/html
727
728This method removes noautolink and nop tags before outputting the page unless
729$contentType is text/plain.
730
731=cut
732
733
# spent 70.7ms (415µs+70.3) within Foswiki::writeCompletePage which was called: # once (415µs+70.3ms) by Foswiki::UI::View::view at line 402 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm
sub writeCompletePage {
734136µs my ( $this, $text, $pageType, $contentType ) = @_;
73512µs $contentType ||= 'text/html';
736
73719µs169µs my $cgis = $this->getCGISession();
# spent 69µs making 1 call to Foswiki::getCGISession
73816µs if ( $cgis
739 && $contentType eq 'text/html'
740 && $Foswiki::cfg{Validation}{Method} ne 'none' )
741 {
742
743 # Don't expire the validation key through login, or when
744 # endpoint is an error.
745125µs2165µs Foswiki::Validation::expireValidationKeys($cgis)
# spent 147µs making 1 call to Foswiki::Validation::expireValidationKeys # spent 18µs making 1 call to Foswiki::Request::action
746 unless ( $this->{request}->action() eq 'login'
747 or ( $ENV{REDIRECT_STATUS} || 0 ) >= 400 );
748
74912µs my $usingStrikeOne = 0;
7501186µs3160µs if (
# spent 93µs making 2 calls to Foswiki::CORE:substcont, avg 46µs/call # spent 68µs making 1 call to Foswiki::CORE:subst
751 $Foswiki::cfg{Validation}{Method} eq 'strikeone'
752
753 # Add the onsubmit handler to the form
754 && $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/
755111µs160µs Foswiki::Validation::addOnSubmit($1)/gei
# spent 60µs making 1 call to Foswiki::Validation::addOnSubmit
756 )
757 {
758
759 # At least one form has been touched; add the validation
760 # cookie
76117µs1557µs my $valCookie = Foswiki::Validation::getCookie($cgis);
# spent 557µs making 1 call to Foswiki::Validation::getCookie
762118µs222µs $valCookie->secure( $this->{request}->secure );
# spent 12µs making 1 call to CGI::Cookie::secure # spent 9µs making 1 call to Foswiki::Request::secure
763119µs221µs $this->{response}
# spent 21µs making 2 calls to Foswiki::Response::cookies, avg 10µs/call
764 ->cookies( [ $this->{response}->cookies, $valCookie ] );
765
766 # Add the JS module to the page. Note that this is *not*
767 # incorporated into the foswikilib.js because that module
768 # is conditionally loaded under the control of the
769 # templates, and we have to be *sure* it gets loaded.
77019µs1131µs my $src = $this->{prefs}->getPreference('FWSRC') || '';
# spent 131µs making 1 call to Foswiki::Prefs::getPreference
771114µs162µs $this->addToZone( 'head', 'JavascriptFiles/strikeone', <<JS );
# spent 62µs making 1 call to Foswiki::addToZone
772<script type="text/javascript" src="$Foswiki::cfg{PubUrlPath}/$Foswiki::cfg{SystemWebName}/JavascriptFiles/strikeone$src.js"></script>
773JS
77412µs $usingStrikeOne = 1;
775 }
776
777 # Inject validation key in HTML forms
778118µs1545µs my $context =
# spent 545µs making 1 call to Foswiki::Request::url
779 $this->{request}->url( -full => 1, -path => 1, -query => 1 ) . time();
7801142µs3121µs $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/
# spent 70µs making 2 calls to Foswiki::CORE:substcont, avg 35µs/call # spent 51µs making 1 call to Foswiki::CORE:subst
781113µs1319µs $1 . Foswiki::Validation::addValidationKey(
# spent 319µs making 1 call to Foswiki::Validation::addValidationKey
782 $cgis, $context, $usingStrikeOne )/gei;
783 }
784
78514µs if ( $contentType ne 'text/plain' ) {
786
787111µs159.3ms $text = $this->_renderZones($text);
# spent 59.3ms making 1 call to Foswiki::_renderZones
788 }
789
790 # SMELL: can't compute; faking content-type for backwards compatibility;
791 # any other information might become bogus later anyway
79214µs my $hdr = "Content-type: " . $contentType . "\r\n";
793
794 # Call final handler
79517µs114µs $this->{plugins}->dispatch( 'completePageHandler', $text, $hdr );
# spent 14µs making 1 call to Foswiki::Plugins::dispatch
796
797 # cache final page, but only view
79811µs my $cachedPage;
79913µs if ( $contentType ne 'text/plain' ) {
80014µs if ( $Foswiki::cfg{Cache}{Enabled}
801 && ( $this->inContext('view') || $this->inContext('rest') ) )
802 {
803 $cachedPage = $this->{cache}->cachePage( $contentType, $text );
804 $this->{cache}->renderDirtyAreas( \$text )
805 if $cachedPage->{isDirty};
806 }
807 else {
808
809 # remove <dirtyarea> tags
810131µs125µs $text =~ s/<\/?dirtyarea[^>]*>//go;
# spent 25µs making 1 call to Foswiki::CORE:subst
811 }
812
813 # Remove <nop> and <noautolink> tags
81417.78ms17.78ms $text =~ s/([\t ]?)[ \t]*<\/?(nop|noautolink)\/?>/$1/gis;
# spent 7.78ms making 1 call to Foswiki::CORE:subst
815
816 # Check that the templates specified clean HTML
81716µs14µs if (DEBUG) {
# spent 4µs making 1 call to Assert::ASSERTS_OFF
818
819 # When tracing is enabled in Foswiki::Templates, then there will
820 # always be a <!--bodyend--> after </html>. So we need to disable
821 # this check.
822 require Foswiki::Templates;
823 if ( !Foswiki::Templates->TRACE
824 && $contentType =~ m#text/html#
825 && $text =~ m#</html>(.*?\S.*)$#s )
826 {
827 ASSERT( 0, <<BOGUS );
828Junk after </html>: $1. Templates may be bogus
829- Check for excess blank lines at ends of .tmpl files
830- or newlines after %TMPL:INCLUDE
831- You can enable TRACE in Foswiki::Templates to help debug
832BOGUS
833 }
834 }
835 }
836
837110µs1810µs $this->generateHTTPHeaders( $pageType, $contentType, $text, $cachedPage );
# spent 810µs making 1 call to Foswiki::generateHTTPHeaders
838
839 # SMELL: null operation. the http headers are written out
840 # during Foswiki::Engine::finalize
841 # $hdr = $this->{response}->printHeaders;
842
843120µs1153µs $this->{response}->print($text);
# spent 153µs making 1 call to Foswiki::Response::print
844}
845
846=begin TML
847
848---++ ObjectMethod generateHTTPHeaders( $pageType, $contentType, $text, $cachedPage )
849
850All parameters are optional.
851
852 * =$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.
853 * =$contentType= - page content type | text/html
854 * =$text= - page content
855 * =$cachedPage= - a pointer to the page container as fetched from the page cache
856
857=cut
858
859
# spent 810µs (136+674) within Foswiki::generateHTTPHeaders which was called: # once (136µs+674µs) by Foswiki::writeCompletePage at line 837
sub generateHTTPHeaders {
860113µs my ( $this, $pageType, $contentType, $text, $cachedPage ) = @_;
861
86212µs my $hopts = {};
863
864 # Handle Edit pages - future versions will extend to caching
865 # of other types of page, with expiry time driven by page type.
86612µs if ( $pageType && $pageType eq 'edit' ) {
867
868 # Get time now in HTTP header format
869 my $lastModifiedString =
870 Foswiki::Time::formatTime( time, '$http', 'gmtime' );
871
872 # Expiry time is set high to avoid any data loss. Each instance of
873 # Edit page has a unique URL with time-string suffix (fix for
874 # RefreshEditPage), so this long expiry time simply means that the
875 # browser Back button always works. The next Edit on this page
876 # will use another URL and therefore won't use any cached
877 # version of this Edit page.
878 my $expireHours = 24;
879 my $expireSeconds = $expireHours * 60 * 60;
880
881 # and cache control headers, to ensure edit page
882 # is cached until required expiry time.
883 $hopts->{'last-modified'} = $lastModifiedString;
884 $hopts->{expires} = "+${expireHours}h";
885 $hopts->{'cache-control'} = "max-age=$expireSeconds";
886 }
887
888 # DEPRECATED plugins header handler. Plugins should use
889 # modifyHeaderHandler instead.
89018µs118µs my $pluginHeaders =
# spent 18µs making 1 call to Foswiki::Plugins::dispatch
891 $this->{plugins}->dispatch( 'writeHeaderHandler', $this->{request} )
892 || '';
89311µs if ($pluginHeaders) {
894 foreach ( split /\r?\n/, $pluginHeaders ) {
895
896 # Implicit untaint OK; data from plugin handler
897 if (m/^([\-a-z]+): (.*)$/i) {
898 $hopts->{$1} = $2;
899 }
900 }
901 }
902
90311µs $contentType = 'text/html' unless $contentType;
904123µs27µs $contentType .= '; charset=' . $Foswiki::cfg{Site}{CharSet}
# spent 7µs making 2 calls to Foswiki::CORE:match, avg 4µs/call
905 if $contentType ne ''
906 && $contentType =~ m!^text/!
907 && $contentType !~ /\bcharset\b/
908 && $Foswiki::cfg{Site}{CharSet};
909
910 # use our version of the content type
91115µs $hopts->{'Content-Type'} = $contentType;
912
913 # New (since 1.026)
91416µs1404µs $this->{plugins}
# spent 404µs making 1 call to Foswiki::Plugins::dispatch
915 ->dispatch( 'modifyHeaderHandler', $hopts, $this->{request} );
916
917 # add http compression and conditional cache controls
91818µs17µs if ( !$this->inContext('command_line') && $text ) {
# spent 7µs making 1 call to Foswiki::inContext
919
92013µs if ( $Foswiki::cfg{HttpCompress}
921 && $ENV{'HTTP_ACCEPT_ENCODING'}
922 && $ENV{'HTTP_ACCEPT_ENCODING'} =~ /(x-gzip|gzip)/i )
923 {
924 my $encoding = $1;
925 $hopts->{'Content-Encoding'} = $encoding;
926 $hopts->{'Vary'} = 'Accept-Encoding';
927
928 # check if we take the version from the cache
929 if ( $cachedPage && !$cachedPage->{isDirty} ) {
930 $text = $cachedPage->{text};
931 }
932 else {
933 require Compress::Zlib;
934 $text = Compress::Zlib::memGzip($text);
935 }
936 }
937 elsif ($cachedPage
938 && !$cachedPage->{isDirty}
939 && $Foswiki::cfg{HttpCompress} )
940 {
941
942 # Outch, we need to uncompressed pages from cache again
943 # Note, this is effort to avoid under any circumstances as
944 # the page has been compressed when it has been created and now
945 # is uncompressed again to get back the original. For now the
946 # only know situation this can happen is for older browsers like IE6
947 # which does not understand gzip'ed http encodings
948 require Compress::Zlib;
949 $text = Compress::Zlib::memGunzip($text);
950 }
951
952 # we need to force the browser into a check on every
953 # request; let the server decide on an 304 as below
95415µs $hopts->{'Cache-Control'} = 'max-age=0';
955
956 # check etag and last modification time
957 # if we have a cached page on the server side
95811µs if ($cachedPage) {
959 my $etag = $cachedPage->{etag};
960 my $lastModified = $cachedPage->{lastModified};
961
962 $hopts->{'ETag'} = $etag;
963 $hopts->{'Last-Modified'} = $lastModified if $lastModified;
964
965 # only send a 304 if both criteria are true
966 my $etagFlag = 1;
967 my $lastModifiedFlag = 1;
968
969 # check etag
970 unless ( $ENV{'HTTP_IF_NONE_MATCH'}
971 && $etag eq $ENV{'HTTP_IF_NONE_MATCH'} )
972 {
973 $etagFlag = 0;
974 }
975
976 # check last-modified
977 unless ( $ENV{'HTTP_IF_MODIFIED_SINCE'}
978 && $lastModified eq $ENV{'HTTP_IF_MODIFIED_SINCE'} )
979 {
980 $lastModifiedFlag = 0;
981 }
982
983 # finally decide on a 304 reply
984 if ( $etagFlag && $lastModified ) {
985 $hopts->{'Status'} = '304 Not Modified';
986 $text = '';
987
988 #print STDERR "NOT modified\n";
989 }
990 }
991
992 # write back to text
99317µs $_[3] = $text;
994 }
995
996111µs110µs $hopts->{"X-FoswikiAction"} = $this->{request}->action;
# spent 10µs making 1 call to Foswiki::Request::action
99718µs17µs $hopts->{"X-FoswikiURI"} = $this->{request}->uri;
# spent 7µs making 1 call to Foswiki::Request::uri
998
999 # The headers method resets all headers to what we pass
1000 # what we want is simply ensure our headers are there
1001118µs1221µs $this->{response}->setDefaultHeaders($hopts);
# spent 221µs making 1 call to Foswiki::Response::setDefaultHeaders
1002}
1003
1004# Tests if the $redirect is an external URL, returning false if
1005# AllowRedirectUrl is denied
1006sub _isRedirectSafe {
1007 my $redirect = shift;
1008
1009 return 1 if ( $Foswiki::cfg{AllowRedirectUrl} );
1010 return 1 if $redirect =~ m#^/#; # relative URL - OK
1011
1012 #TODO: this should really use URI
1013 # Compare protocol, host name and port number
1014 if ( $redirect =~ m!^(.*?://[^/?#]*)! ) {
1015
1016 # implicit untaints OK because result not used. uc retaints
1017 # if use locale anyway.
1018 my $target = uc($1);
1019
1020 $Foswiki::cfg{DefaultUrlHost} =~ m!^(.*?://[^/]*)!;
1021 return 1 if ( $target eq uc($1) );
1022
1023 if ( $Foswiki::cfg{PermittedRedirectHostUrls} ) {
1024 foreach my $red (
1025 split( /\s*,\s*/, $Foswiki::cfg{PermittedRedirectHostUrls} ) )
1026 {
1027 $red =~ m!^(.*?://[^/]*)!;
1028 return 1 if ( $target eq uc($1) );
1029 }
1030 }
1031 }
1032 return 0;
1033}
1034
1035=begin TML
1036
1037---++ ObjectMethod redirectto($url) -> $url
1038Gets a redirect url from CGI parameter 'redirectto', if present on the query.
1039
1040If the redirectto CGI parameter specifies a valid redirection target it is
1041returned; otherwise the original URL passed in the parameter is returned.
1042
1043Conditions for a valid redirection target are:
1044 * The target matches the linkProtocolPattern regex, and redirection
1045 to the url _isRedirectSafe
1046 * The target specified a topic, or a Web.Topic (redirect will be to
1047 'view')
1048
1049=cut
1050
1051sub redirectto {
1052 my ( $this, $url ) = @_;
1053 ASSERT($url) if DEBUG;
1054
1055 my $redirecturl = $this->{request}->param('redirectto');
1056 return $url unless $redirecturl;
1057
1058 if ( $redirecturl =~ m#^$regex{linkProtocolPattern}://#o ) {
1059
1060 # assuming URL
1061 if ( _isRedirectSafe($redirecturl) ) {
1062 return $redirecturl;
1063 }
1064 else {
1065 return $url;
1066 }
1067 }
1068
1069 # assuming 'web.topic' or 'topic'
1070 my ( $w, $t ) =
1071 $this->normalizeWebTopicName( $this->{webName}, $redirecturl );
1072
1073 # capture anchor
1074 my ( $topic, $anchor ) = split( '#', $t, 2 );
1075 $t = $topic if $topic;
1076 my @attrs = ();
1077 push( @attrs, '#' => $anchor ) if $anchor;
1078
1079 return $this->getScriptUrl( 1, 'view', $w, $t, @attrs );
1080}
1081
1082=begin TML
1083
1084---++ StaticMethod splitAnchorFromUrl( $url ) -> ( $url, $anchor )
1085
1086Takes a full url (including possible query string) and splits off the anchor.
1087The anchor includes the # sign. Returns an empty string if not found in the url.
1088
1089=cut
1090
1091sub splitAnchorFromUrl {
1092 my ($url) = @_;
1093
1094 ( $url, my $anchor ) = $url =~ m/^(.*?)(#(.*?))*$/;
1095 return ( $url, $anchor );
1096}
1097
1098=begin TML
1099
1100---++ ObjectMethod redirect( $url, $passthrough )
1101
1102 * $url - url or topic to redirect to
1103 * $passthrough - (optional) parameter to pass through current query
1104 parameters (see below)
1105
1106Redirects the request to =$url=, *unless*
1107 1 It is overridden by a plugin declaring a =redirectCgiQueryHandler=
1108 (a dangerous, deprecated handler!)
1109 1 =$session->{request}= is =undef= or
1110Thus a redirect is only generated when in a CGI context.
1111
1112Normally this method will ignore parameters to the current query. Sometimes,
1113for example when redirecting to a login page during authentication (and then
1114again from the login page to the original requested URL), you want to make
1115sure all parameters are passed on, and for this $passthrough should be set to
1116true. In this case it will pass all parameters that were passed to the
1117current query on to the redirect target. If the request_method for the
1118current query was GET, then all parameters will be passed by encoding them
1119in the URL (after ?). If the request_method was POST, then there is a risk the
1120URL would be too big for the receiver, so it caches the form data and passes
1121over a cache reference in the redirect GET.
1122
1123NOTE: Passthrough is only meaningful if the redirect target is on the same
1124server.
1125
1126=cut
1127
1128sub redirect {
1129 my ( $this, $url, $passthru ) = @_;
1130 ASSERT( defined $url ) if DEBUG;
1131
1132 return unless $this->{request};
1133
1134 ( $url, my $anchor ) = splitAnchorFromUrl($url);
1135
1136 if ( $passthru && defined $this->{request}->method() ) {
1137 my $existing = '';
1138 if ( $url =~ s/\?(.*)$// ) {
1139 $existing = $1; # implicit untaint OK; recombined later
1140 }
1141 if ( uc( $this->{request}->method() ) eq 'POST' ) {
1142
1143 # Redirecting from a post to a get
1144 my $cache = $this->cacheQuery();
1145 if ($cache) {
1146 if ( $url eq '/' ) {
1147 $url = $this->getScriptUrl( 1, 'view' );
1148 }
1149 $url .= $cache;
1150 }
1151 }
1152 else {
1153
1154 # Redirecting a get to a get; no need to use passthru
1155 if ( $this->{request}->query_string() ) {
1156 $url .= '?' . $this->{request}->query_string();
1157 }
1158 if ($existing) {
1159 if ( $url =~ /\?/ ) {
1160 $url .= ';';
1161 }
1162 else {
1163 $url .= '?';
1164 }
1165 $url .= $existing;
1166 }
1167 }
1168 }
1169
1170 # prevent phishing by only allowing redirect to configured host
1171 # do this check as late as possible to catch _any_ last minute hacks
1172 # TODO: this should really use URI
1173 if ( !_isRedirectSafe($url) ) {
1174
1175 # goto oops if URL is trying to take us somewhere dangerous
1176 $url = $this->getScriptUrl(
1177 1, 'oops',
1178 $this->{webName} || $Foswiki::cfg{UsersWebName},
1179 $this->{topicName} || $Foswiki::cfg{HomeTopicName},
1180 template => 'oopsredirectdenied',
1181 def => 'redirect_denied',
1182 param1 => "$url",
1183 param2 => "$Foswiki::cfg{DefaultUrlHost}",
1184 );
1185 }
1186
1187 $url .= $anchor if $anchor;
1188
1189 # Dangerous, deprecated handler! Might work, probably won't.
1190 return
1191 if ( $this->{plugins}
1192 ->dispatch( 'redirectCgiQueryHandler', $this->{response}, $url ) );
1193
1194 $url = $this->getLoginManager()->rewriteRedirectUrl($url);
1195
1196 # Foswiki::Response::redirect doesn't automatically pass on the cookies
1197 # for us, so we have to do it explicitly; otherwise the session cookie
1198 # won't get passed on.
1199 $this->{response}
1200 ->redirect( -url => $url, -cookies => $this->{response}->cookies() );
1201}
1202
1203=begin TML
1204
1205---++ ObjectMethod cacheQuery() -> $queryString
1206
1207Caches the current query in the params cache, and returns a rewritten
1208query string for the cache to be picked up again on the other side of a
1209redirect.
1210
1211We can't encode post params into a redirect, because they may exceed the
1212size of the GET request. So we cache the params, and reload them when the
1213redirect target is reached.
1214
1215=cut
1216
1217sub cacheQuery {
1218 my $this = shift;
1219 my $query = $this->{request};
1220
1221 return '' unless ( scalar( $query->param() ) );
1222
1223 # Don't double-cache
1224 return '' if ( $query->param('foswiki_redirect_cache') );
1225
1226 require Foswiki::Request::Cache;
1227 my $uid = Foswiki::Request::Cache->new()->save($query);
1228 if ( $Foswiki::cfg{UsePathForRedirectCache} ) {
1229 return '/foswiki_redirect_cache/' . $uid;
1230 }
1231 else {
1232 return '?foswiki_redirect_cache=' . $uid;
1233 }
1234}
1235
1236=begin TML
1237
1238---++ ObjectMethod getCGISession() -> $cgisession
1239
1240Get the CGI::Session object associated with this session, if there is
1241one. May return undef.
1242
1243=cut
1244
1245
# spent 69µs (19+50) within Foswiki::getCGISession which was called: # once (19µs+50µs) by Foswiki::writeCompletePage at line 737
sub getCGISession {
1246118µs150µs $_[0]->{users}->getCGISession();
# spent 50µs making 1 call to Foswiki::Users::getCGISession
1247}
1248
1249=begin TML
1250
1251---++ ObjectMethod getLoginManager() -> $loginManager
1252
1253Get the Foswiki::LoginManager object associated with this session, if there is
1254one. May return undef.
1255
1256=cut
1257
1258
# spent 293µs (186+106) within Foswiki::getLoginManager which was called 12 times, avg 24µs/call: # 5 times (97µs+53µs) by Foswiki::Render::getRenderedVersion at line 1443 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 30µs/call # 2 times (35µs+21µs) by Foswiki::LoginManager::_LOGOUT at line 1080 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm, avg 28µs/call # 2 times (18µs+10µs) by Foswiki::LoginManager::_LOGIN at line 1040 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm, avg 14µs/call # 2 times (18µs+10µs) by Foswiki::LoginManager::_LOGOUTURL at line 1061 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm, avg 14µs/call # once (18µs+12µs) by Foswiki::UI::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/UI.pm:318] at line 315 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI.pm
sub getLoginManager {
125912156µs12106µs $_[0]->{users}->getLoginManager();
# spent 106µs making 12 calls to Foswiki::Users::getLoginManager, avg 9µs/call
1260}
1261
1262=begin TML
1263
1264---++ StaticMethod isValidWikiWord( $name ) -> $boolean
1265
1266Check for a valid WikiWord or WikiName
1267
1268=cut
1269
1270sub isValidWikiWord {
1271 my $name = shift || '';
1272 return ( $name =~ m/^$regex{wikiWordRegex}$/o );
1273}
1274
1275=begin TML
1276
1277---++ StaticMethod isValidTopicName( $name [, $nonww] ) -> $boolean
1278
1279Check for a valid topic =$name=. If =$nonww=, then accept non wiki-words
1280(though they must still be composed of only valid, unfiltered characters)
1281
1282=cut
1283
1284# Note: must work on tainted names.
1285
# spent 716µs (512+205) within Foswiki::isValidTopicName which was called 23 times, avg 31µs/call: # 20 times (436µs+115µs) by Foswiki::INCLUDE at line 176 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 28µs/call # 3 times (75µs+90µs) by Foswiki::Sandbox::validateTopicName at line 162 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Sandbox.pm, avg 55µs/call
sub isValidTopicName {
12862353µs my ( $name, $nonww ) = @_;
1287
12882347µs return 0 unless defined $name && $name ne '';
128923508µs46185µs return 1 if ( $name =~ m/^$regex{topicNameRegex}$/o );
# spent 95µs making 23 calls to Foswiki::CORE:match, avg 4µs/call # spent 90µs making 23 calls to Foswiki::CORE:regcomp, avg 4µs/call
129034µs return 0 unless $nonww;
1291346µs620µs return 0 if $name =~ /$cfg{NameFilter}/o;
# spent 14µs making 3 calls to Foswiki::CORE:regcomp, avg 5µs/call # spent 5µs making 3 calls to Foswiki::CORE:match, avg 2µs/call
1292318µs return 1;
1293}
1294
1295=begin TML
1296
1297---++ StaticMethod isValidWebName( $name, $system ) -> $boolean
1298
1299STATIC Check for a valid web name. If $system is true, then
1300system web names are considered valid (names starting with _)
1301otherwise only user web names are valid
1302
1303If $Foswiki::cfg{EnableHierarchicalWebs} is off, it will also return false
1304when a nested web name is passed to it.
1305
1306=cut
1307
1308# Note: must work on tainted names.
1309
# spent 221µs (140+81) within Foswiki::isValidWebName which was called 3 times, avg 74µs/call: # 3 times (140µs+81µs) by Foswiki::Sandbox::validateWebName at line 147 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Sandbox.pm, avg 74µs/call
sub isValidWebName {
131036µs my $name = shift || '';
131135µs my $sys = shift;
1312369µs628µs return 1 if ( $sys && $name =~ m/^$regex{defaultWebNameRegex}$/o );
# spent 23µs making 3 calls to Foswiki::CORE:regcomp, avg 8µs/call # spent 5µs making 3 calls to Foswiki::CORE:match, avg 2µs/call
13133145µs653µs return ( $name =~ m/^$regex{webNameRegex}$/o );
# spent 36µs making 3 calls to Foswiki::CORE:regcomp, avg 12µs/call # spent 17µs making 3 calls to Foswiki::CORE:match, avg 6µs/call
1314}
1315
1316=begin TML
1317
1318---++ StaticMethod isValidEmailAddress( $name ) -> $boolean
1319
1320STATIC Check for a valid email address name.
1321
1322=cut
1323
1324# Note: must work on tainted names.
1325sub isValidEmailAddress {
1326 my $name = shift || '';
1327 return $name =~ /^$regex{emailAddrRegex}$/o;
1328}
1329
1330=begin TML
1331
1332---++ ObjectMethod getSkin () -> $string
1333
1334Get the currently requested skin path
1335
1336=cut
1337
1338
# spent 2.86ms (543µs+2.31) within Foswiki::getSkin which was called 7 times, avg 408µs/call: # 4 times (337µs+1.34ms) by Foswiki::Templates::readTemplate at line 223 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm, avg 419µs/call # 2 times (150µs+711µs) by Foswiki::UI::View::view at line 323 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm, avg 430µs/call # once (57µs+263µs) by Foswiki::UI::View::view at line 346 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm
sub getSkin {
1339711µs my $this = shift;
1340
134179µs my @skinpath;
1342716µs my $skins;
1343
1344725µs if ( $this->{request} ) {
1345758µs7469µs $skins = $this->{request}->param('cover');
# spent 469µs making 7 calls to Foswiki::Request::param, avg 67µs/call
1346712µs if ( defined $skins
1347 && $skins =~ /([$regex{mixedAlphaNum}.,\s]+)/o )
1348 {
1349
1350 # Implicit untaint ok - validated
1351 $skins = $1;
1352 push( @skinpath, split( /,\s]+/, $skins ) );
1353 }
1354 }
1355
1356767µs7511µs $skins = $this->{prefs}->getPreference('COVER');
# spent 511µs making 7 calls to Foswiki::Prefs::getPreference, avg 73µs/call
1357711µs if ( defined $skins
1358 && $skins =~ /([$regex{mixedAlphaNum}.,\s]+)/o )
1359 {
1360
1361 # Implicit untaint ok - validated
1362 $skins = $1;
1363 push( @skinpath, split( /[,\s]+/, $skins ) );
1364 }
1365
1366744µs7312µs $skins = $this->{request} ? $this->{request}->param('skin') : undef;
# spent 312µs making 7 calls to Foswiki::Request::param, avg 45µs/call
1367750µs7941µs $skins = $this->{prefs}->getPreference('SKIN') unless $skins;
# spent 941µs making 7 calls to Foswiki::Prefs::getPreference, avg 134µs/call
1368
13697171µs1481µs if ( defined $skins && $skins =~ /([$regex{mixedAlphaNum}.,\s]+)/o ) {
# spent 49µs making 7 calls to Foswiki::CORE:match, avg 7µs/call # spent 32µs making 7 calls to Foswiki::CORE:regcomp, avg 5µs/call
1370
1371 # Implicit untaint ok - validated
1372721µs $skins = $1;
1373754µs push( @skinpath, split( /[,\s]+/, $skins ) );
1374 }
1375
1376765µs return join( ',', @skinpath );
1377}
1378
1379=begin TML
1380
1381---++ ObjectMethod getScriptUrl( $absolute, $script, $web, $topic, ... ) -> $scriptURL
1382
1383Returns the URL to a Foswiki script, providing the web and topic as
1384"path info" parameters. The result looks something like this:
1385"http://host/foswiki/bin/$script/$web/$topic".
1386 * =...= - 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>
1387
1388If $absolute is set, generates an absolute URL. $absolute is advisory only;
1389Foswiki can decide to generate absolute URLs (for example when run from the
1390command-line) even when relative URLs have been requested.
1391
1392The default script url is taken from {ScriptUrlPath}, unless there is
1393an exception defined for the given script in {ScriptUrlPaths}. Both
1394{ScriptUrlPath} and {ScriptUrlPaths} may be absolute or relative URIs. If
1395they are absolute, then they will always generate absolute URLs. if they
1396are relative, then they will be converted to absolute when required (e.g.
1397when running from the command line, or when generating rss). If
1398$script is not given, absolute URLs will always be generated.
1399
1400If 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.
1401
1402=cut
1403
1404
# spent 10.6ms (4.94+5.66) within Foswiki::getScriptUrl which was called 96 times, avg 110µs/call: # 50 times (2.79ms+4.11ms) by Foswiki::Render::_renderExistingWikiWord at line 667 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 138µs/call # 27 times (1.09ms+106µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:266] at line 266, avg 44µs/call # 14 times (619µs+329µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:268] at line 268, avg 68µs/call # 3 times (290µs+780µs) by Foswiki::Func::getScriptUrl at line 167 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 357µs/call # 2 times (147µs+334µs) by Foswiki::LoginManager::_LOGOUTURL at line 1063 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm, avg 240µs/call
sub getScriptUrl {
140596292µs my ( $this, $absolute, $script, $web, $topic, @params ) = @_;
1406
140796951µs1981.23ms $absolute ||=
# spent 1.23ms making 198 calls to Foswiki::inContext, avg 6µs/call
1408 ( $this->inContext('command_line')
1409 || $this->inContext('rss')
1410 || $this->inContext('absolute_urls') );
1411
1412 # SMELL: topics and webs that contain spaces?
1413
141496121µs my $url;
141596303µs if ( defined $Foswiki::cfg{ScriptUrlPaths} && $script ) {
141694279µs $url = $Foswiki::cfg{ScriptUrlPaths}{$script};
1417 }
141896146µs unless ( defined($url) ) {
14191740µs $url = $Foswiki::cfg{ScriptUrlPath};
14201742µs if ($script) {
142115122µs1532µs $url .= '/' unless $url =~ /\/$/;
# spent 32µs making 15 calls to Foswiki::CORE:match, avg 2µs/call
14221521µs $url .= $script;
14231562µs if (
1424 rindex( $url, $Foswiki::cfg{ScriptSuffix} ) !=
1425 ( length($url) - length( $Foswiki::cfg{ScriptSuffix} ) ) )
1426 {
1427 $url .= $Foswiki::cfg{ScriptSuffix} if $script;
1428 }
1429 }
1430 }
1431
143296428µs3099µs if ( $absolute && $url !~ /^[a-z]+:/ ) {
# spent 99µs making 30 calls to Foswiki::CORE:match, avg 3µs/call
1433
1434 # See http://www.ietf.org/rfc/rfc2396.txt for the definition of
1435 # "absolute URI". Foswiki bastardises this definition by assuming
1436 # that all relative URLs lack the <authority> component as well.
14373098µs $url = $this->{urlHost} . $url;
1438 }
1439
144096203µs if ( $web || $topic ) {
144155380µs552.26ms ( $web, $topic ) = $this->normalizeWebTopicName( $web, $topic );
# spent 2.26ms making 55 calls to Foswiki::normalizeWebTopicName, avg 41µs/call
1442
144355355µs55720µs $url .= urlEncode( '/' . $web . '/' . $topic );
# spent 720µs making 55 calls to Foswiki::urlEncode, avg 13µs/call
1444
144555304µs551.31ms $url .= make_params(@params);
# spent 1.31ms making 55 calls to Foswiki::make_params, avg 24µs/call
1446 }
1447
144896596µs return $url;
1449}
1450
1451=begin TML
1452
1453---++ StaticMethod make_params(...)
1454Generate a URL parameters string from parameters given. A parameter named '#' will
1455generate an anchor.
1456
1457=cut
1458
1459
# spent 1.31ms (1.09+227µs) within Foswiki::make_params which was called 55 times, avg 24µs/call: # 55 times (1.09ms+227µs) by Foswiki::getScriptUrl at line 1445, avg 24µs/call
sub make_params {
14605587µs my $url = '';
14615569µs my @ps;
14625573µs my $anchor = '';
146355202µs while ( my $p = shift @_ ) {
14641030µs if ( $p eq '#' ) {
1465 $anchor = '#' . urlEncode( shift(@_) );
1466 }
1467 else {
14681016µs my $v = shift(@_);
14691014µs $v = '' unless defined $v;
147010105µs20227µs push( @ps, urlEncode($p) . '=' . urlEncode($v) );
# spent 227µs making 20 calls to Foswiki::urlEncode, avg 11µs/call
1471 }
1472 }
14735591µs if ( scalar(@ps) ) {
14744123µs $url .= '?' . join( ';', @ps );
1475 }
147655320µs return $url . $anchor;
1477}
1478
1479=begin TML
1480
1481---++ ObjectMethod getPubUrl($absolute, $web, $topic, $attachment) -> $url
1482
1483Composes a pub url. If $absolute is set, returns an absolute URL.
1484If $absolute is set, generates an absolute URL. $absolute is advisory only;
1485Foswiki can decide to generate absolute URLs (for example when run from the
1486command-line) even when relative URLs have been requested.
1487
1488$web, $topic and $attachment are optional. A partial URL path will be
1489generated if one or all is not given.
1490
1491=cut
1492
1493
# spent 1.48ms (1.01+469µs) within Foswiki::getPubUrl which was called 36 times, avg 41µs/call: # 25 times (741µs+447µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:239] at line 239, avg 48µs/call # 11 times (270µs+22µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:238] at line 238, avg 27µs/call
sub getPubUrl {
14943674µs my ( $this, $absolute, $web, $topic, $attachment ) = @_;
1495
149636335µs75447µs $absolute ||=
# spent 447µs making 75 calls to Foswiki::inContext, avg 6µs/call
1497 ( $this->inContext('command_line')
1498 || $this->inContext('rss')
1499 || $this->inContext('absolute_urls') );
1500
15013654µs my $url = '';
15023672µs $url .= $Foswiki::cfg{PubUrlPath};
150336146µs1122µs if ( $absolute && $url !~ /^[a-z]+:/ ) {
# spent 22µs making 11 calls to Foswiki::CORE:match, avg 2µs/call
1504
1505 # See http://www.ietf.org/rfc/rfc2396.txt for the definition of
1506 # "absolute URI". Foswiki bastardises this definition by assuming
1507 # that all relative URLs lack the <authority> component as well.
15081128µs $url = $this->{urlHost} . $url;
1509 }
15103648µs if ( $web || $topic || $attachment ) {
1511 ( $web, $topic ) = $this->normalizeWebTopicName( $web, $topic );
1512
1513 my $path = '/' . $web . '/' . $topic;
1514 if ($attachment) {
1515 $path .= '/' . $attachment;
1516
1517 # Attachments are served directly by web server, need to handle
1518 # URL encoding specially
1519 $url .= urlEncodeAttachment($path);
1520 }
1521 else {
1522 $url .= urlEncode($path);
1523 }
1524 }
1525
152636215µs return $url;
1527}
1528
1529=begin TML
1530
1531---++ ObjectMethod deepWebList($filter, $web) -> @list
1532
1533Deep list subwebs of the named web. $filter is a Foswiki::WebFilter
1534object that is used to filter the list. The listing of subwebs is
1535dependent on $Foswiki::cfg{EnableHierarchicalWebs} being true.
1536
1537Webs are returned as absolute web pathnames.
1538
1539=cut
1540
1541sub deepWebList {
1542 my ( $this, $filter, $rootWeb ) = @_;
1543 my @list;
1544 my $webObject = new Foswiki::Meta( $this, $rootWeb );
1545 my $it = $webObject->eachWeb( $Foswiki::cfg{EnableHierarchicalWebs} );
1546 return $it->all() unless $filter;
1547 while ( $it->hasNext() ) {
1548 my $w = $rootWeb || '';
1549 $w .= '/' if $w;
1550 $w .= $it->next();
1551 if ( $filter->ok( $this, $w ) ) {
1552 push( @list, $w );
1553 }
1554 }
1555 return @list;
1556}
1557
1558=begin TML
1559
1560---++ ObjectMethod normalizeWebTopicName( $web, $topic ) -> ( $web, $topic )
1561
1562Normalize a Web<nop>.<nop>TopicName
1563
1564See =Foswiki::Func= for a full specification of the expansion (not duplicated
1565here)
1566
1567*WARNING* if there is no web specification (in the web or topic parameters)
1568the web defaults to $Foswiki::cfg{UsersWebName}. If there is no topic
1569specification, or the topic is '0', the topic defaults to the web home topic
1570name.
1571
1572*WARNING* if the input topic name is tainted, then the output web and
1573topic names will be tainted.
1574
1575=cut
1576
1577
# spent 550ms (409+141) within Foswiki::normalizeWebTopicName which was called 13575 times, avg 41µs/call: # 12255 times (369ms+127ms) by Foswiki::Func::normalizeWebTopicName at line 2773 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 40µs/call # 1099 times (31.8ms+11.2ms) by Foswiki::Func::_checkWTA at line 75 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 39µs/call # 70 times (3.00ms+1.25ms) by Foswiki::Templates::_readTemplateFile at line 499 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm, avg 61µs/call # 55 times (1.65ms+608µs) by Foswiki::getScriptUrl at line 1441, avg 41µs/call # 32 times (1.10ms+407µs) by Foswiki::Render::_handleSquareBracketedLink at line 890 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 47µs/call # 30 times (937µs+334µs) by Foswiki::Users::getCanonicalUserID at line 486 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users.pm, avg 42µs/call # 20 times (821µs+291µs) by Foswiki::INCLUDE at line 172 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 56µs/call # 6 times (267µs+101µs) by Foswiki::If::OP_istopic::evaluate at line 33 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/If/OP_istopic.pm, avg 61µs/call # 6 times (210µs+68µs) by Foswiki::REVINFO at line 20 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/REVINFO.pm, avg 46µs/call # once (63µs+26µs) by Foswiki::Prefs::loadSitePreferences at line 373 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Prefs.pm # once (36µs+15µs) by Foswiki::Form::new at line 81 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm
sub normalizeWebTopicName {
15781357526.6ms my ( $this, $web, $topic ) = @_;
1579
15801357556.9ms1357541.9ms ASSERT( defined $topic ) if DEBUG;
# spent 41.9ms making 13575 calls to Assert::ASSERTS_OFF, avg 3µs/call
1581
158213575121ms1357557.9ms if ( $topic =~ m|^(.*)[./](.*?)$| ) {
# spent 57.9ms making 13575 calls to Foswiki::CORE:match, avg 4µs/call
1583138366µs $web = $1;
1584138241µs $topic = $2;
1585
1586138706µs138521µs if ( DEBUG && !UNTAINTED( $_[2] ) ) {
# spent 521µs making 138 calls to Assert::ASSERTS_OFF, avg 4µs/call
1587
1588 # retaint data untainted by RE above
1589 $web = TAINT($web);
1590 $topic = TAINT($topic);
1591 }
1592 }
15931357517.3ms $web ||= $cfg{UsersWebName};
15941357516.2ms $topic ||= $cfg{HomeTopicName};
1595
1596 # MAINWEB and TWIKIWEB expanded for compatibility reasons
15971357599.2ms1357520.0ms while (
# spent 20.0ms making 13575 calls to Foswiki::CORE:subst, avg 1µs/call
1598 $web =~ s/%((MAIN|TWIKI|USERS|SYSTEM|DOC)WEB)%/
1599 $this->_expandMacroOnTopicRendering( $1 ) || ''/e
1600 )
1601 {
1602 }
1603
1604 # Normalize web name to use / and not . as a subweb separator
16051357573.9ms1357520.8ms $web =~ s#\.#/#g;
# spent 20.8ms making 13575 calls to Foswiki::CORE:subst, avg 2µs/call
1606
16071357586.8ms return ( $web, $topic );
1608}
1609
1610=begin TML
1611
1612---++ ClassMethod new( $defaultUser, $query, \%initialContext )
1613
1614Constructs a new Foswiki session object. A unique session object exists for
1615ever transaction with Foswiki, for example every browser request, or every
1616script run. Session objects do not persist between mod_perl runs.
1617
1618 * =$defaultUser= is the username (*not* the wikiname) of the default
1619 user you want to be logged-in, if none is available from a session
1620 or browser. Used mainly for unit tests and debugging, it is typically
1621 undef, in which case the default user is taken from
1622 $Foswiki::cfg{DefaultUserName}.
1623 * =$query= the Foswiki::Request query (may be undef, in which case an
1624 empty query is used)
1625 * =\%initialContext= - reference to a hash containing context
1626 name=value pairs to be pre-installed in the context hash. May be undef.
1627
1628=cut
1629
1630
# spent 81.8s (955µs+81.8) within Foswiki::new which was called: # once (955µs+81.8s) by Foswiki::UI::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/UI.pm:318] at line 306 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI.pm
sub new {
163113µs my ( $class, $defaultUser, $query, $initialContext ) = @_;
1632
163315µs14µs Monitor::MARK("Static init over; make Foswiki object");
163416µs14µs ASSERT( !$query || UNIVERSAL::isa( $query, 'Foswiki::Request' ) )
# spent 4µs making 1 call to Assert::ASSERTS_OFF
1635 if DEBUG;
1636
1637 # Compatibility; not used except maybe in plugins
163815µs $Foswiki::cfg{TempfileDir} = "$Foswiki::cfg{WorkingDir}/tmp"
1639 unless defined( $Foswiki::cfg{TempfileDir} );
164014µs if ( defined $Foswiki::cfg{WarningFileName}
1641 && $Foswiki::cfg{Log}{Implementation} eq 'Foswiki::Logger::PlainFile' )
1642 {
1643
1644 # Admin has already expressed a preference for where they want their
1645 # logfiles to go, and has obviously not re-run configure yet.
1646 $Foswiki::cfg{Log}{Implementation} = 'Foswiki::Logger::Compatibility';
1647
1648#print STDERR "WARNING: Foswiki is using the compatibility logger. Please re-run configure and check your logfiles settings\n";
1649 }
1650 else {
1651
1652 # Otherwise make sure it is defined for use in plugins,
1653 # but don't overwrite the setting from configure, if there is one.
1654 # This is especially important when the admin has *chosen*
1655 # to use the compatibility logger.
165614µs if ( not defined $Foswiki::cfg{LogFileName} ) {
165714µs $Foswiki::cfg{LogFileName} = "$Foswiki::cfg{Log}{Dir}/events.log";
1658 }
1659 }
1660
1661 # Set command_line context if there is no query
166211µs $initialContext ||= defined($query) ? {} : { command_line => 1 };
1663
166411µs $query ||= new Foswiki::Request();
1665112µs my $this = bless( { sandbox => 'Foswiki::Sandbox' }, $class );
1666
1667 # Tell Foswiki::Response which charset we are using if not default
166812µs $Foswiki::cfg{Site}{CharSet} ||= 'iso-8859-1';
1669
167012µs $this->{request} = $query;
167112µs $this->{cgiQuery} = $query; # for backwards compatibility in contribs
1672110µs123µs $this->{response} = new Foswiki::Response();
# spent 23µs making 1 call to Foswiki::Response::new
1673133µs118µs $this->{digester} = new Digest::MD5();
# spent 18µs making 1 call to Digest::MD5::new
1674
1675 # This is required in case we get an exception during
1676 # initialisation, so that we have a session to handle it with.
167712µs $Foswiki::Plugins::SESSION = $this;
1678
1679 # hash of zone records
168012µs $this->{_zones} = ();
1681
1682 # hash of occurences of RENDERZONE
168312µs $this->{_renderZonePlaceholder} = ();
1684
168512µs $this->{context} = $initialContext;
1686
168713µs if ( $Foswiki::cfg{Cache}{Enabled} ) {
1688 require Foswiki::PageCache;
1689 $this->{cache} = new Foswiki::PageCache($this);
1690 }
1691111µs11.99ms my $prefs = new Foswiki::Prefs($this);
# spent 1.99ms making 1 call to Foswiki::Prefs::new
169212µs $this->{prefs} = $prefs;
1693111µs176µs $this->{plugins} = new Foswiki::Plugins($this);
# spent 76µs making 1 call to Foswiki::Plugins::new
1694
1695132µs eval "require $Foswiki::cfg{Store}{Implementation}";
# spent 114µs executing statements in string eval
169617µs15µs ASSERT( !$@, $@ ) if DEBUG;
# spent 5µs making 1 call to Assert::ASSERTS_OFF
1697117µs173µs $this->{store} = $Foswiki::cfg{Store}{Implementation}->new();
# spent 73µs making 1 call to Foswiki::Store::new
1698
1699 #Monitor::MARK("Created store");
1700
1701111µs161.6ms $this->{users} = new Foswiki::Users($this);
# spent 61.6ms making 1 call to Foswiki::Users::new
1702
1703 #Monitor::MARK("Created users object");
1704
1705 #{urlHost} is needed by loadSession..
170619µs1331µs my $url = $query->url();
# spent 331µs making 1 call to Foswiki::Request::url
1707119µs18µs if ( $url && $url =~ m{^([^:]*://[^/]*).*$} ) {
# spent 8µs making 1 call to Foswiki::CORE:match
170815µs $this->{urlHost} = $1;
1709
1710 # If the urlHost in the url is localhost, this is a lot less
1711 # useful than the default url host. This is because new CGI("")
1712 # assigns this host by default - it's a default setting, used
1713 # when there is nothing better available.
171414µs if ( $this->{urlHost} eq 'http://localhost' ) {
1715 $this->{urlHost} = $Foswiki::cfg{DefaultUrlHost};
1716 }
1717 elsif ( $Foswiki::cfg{RemovePortNumber} ) {
1718 $this->{urlHost} =~ s/\:[0-9]+$//;
1719 }
1720 }
1721 else {
1722 $this->{urlHost} = $Foswiki::cfg{DefaultUrlHost};
1723 }
172416µs14µs ASSERT( $this->{urlHost} ) if DEBUG;
# spent 4µs making 1 call to Assert::ASSERTS_OFF
1725
1726 # Load (or create) the CGI session
172719µs1137ms $this->{remoteUser} = $this->{users}->loadSession($defaultUser);
# spent 137ms making 1 call to Foswiki::Users::loadSession
1728
1729 # Make %ENV safer, preventing hijack of the search path. The
1730 # environment is set per-query, so this can't be done in a BEGIN.
1731 # TWikibug:Item4382: Default $ENV{PATH} must be untainted because
1732 # Foswiki runs with use strict and calling external programs that
1733 # writes on the disk will fail unless Perl seens it as set to safe value.
173414µs if ( $Foswiki::cfg{SafeEnvPath} ) {
1735113µs $ENV{PATH} = $Foswiki::cfg{SafeEnvPath};
1736 }
1737 else {
1738
1739 # SMELL: how can we validate the PATH?
1740 $ENV{PATH} = Foswiki::Sandbox::untaintUnchecked( $ENV{PATH} );
1741 }
1742117µs delete @ENV{qw( IFS CDPATH ENV BASH_ENV )};
1743
174412µs if ( $Foswiki::cfg{GetScriptUrlFromCgi}
1745 && $url
1746 && $url =~ m{^[^:]*://[^/]*(.*)/.*$}
1747 && $1 )
1748 {
1749
1750 # SMELL: this is a really dangerous hack. It will fail
1751 # spectacularly with mod_perl.
1752 # SMELL: why not just use $query->script_name?
1753 # SMELL: unchecked implicit untaint?
1754 $this->{scriptUrlPath} = $1;
1755 }
1756
175712µs my $web = '';
175818µs153µs my $topic = $query->param('topic');
# spent 53µs making 1 call to Foswiki::Request::param
175913µs if ($topic) {
1760 if ( $topic =~ m#^$regex{linkProtocolPattern}://#o
1761 && $this->{request} )
1762 {
1763
1764 # SMELL: this is a result of Codev.GoBoxUnderstandsURLs,
1765 # an unrequested, undocumented, and AFAICT pretty useless
1766 #"feature". It should be deprecated (or silently removed; I
1767 # really, really doubt anyone is using it)
1768 $this->{webName} = '';
1769 $this->redirect($topic);
1770 return $this;
1771 }
1772 elsif ( $topic =~ m#^(.*)[./](.*?)$# ) {
1773
1774 # is '?topic=Webname.SomeTopic'
1775 # implicit untaint OK - validated later
1776 $web = $1;
1777 $topic = $2;
1778 $web =~ s/\./\//g;
1779
1780 # jump to WebHome if 'bin/script?topic=Webname.'
1781 $topic = $Foswiki::cfg{HomeTopicName} if ( $web && !$topic );
1782 }
1783
1784 # otherwise assume 'bin/script/Webname?topic=SomeTopic'
1785 }
1786 else {
178712µs $topic = '';
1788 }
1789
179019µs18µs my $pathInfo = $query->path_info();
# spent 8µs making 1 call to Foswiki::Request::pathInfo
1791111µs13µs $pathInfo =~ s|//+|/|g; # multiple //'s are illogical
# spent 3µs making 1 call to Foswiki::CORE:subst
1792
1793 # Get the web and topic names from PATH_INFO
1794118µs18µs if ( $pathInfo =~ m#^/(.*)[./](.*?)$# ) {
# spent 8µs making 1 call to Foswiki::CORE:match
1795
1796 # is '/Webname/SomeTopic' or '/Webname'
1797 # implicit untaint OK - validated later
179814µs $web = $1 unless $web;
179912µs $topic = $2 unless $topic;
1800110µs12µs $web =~ s/\./\//g;
# spent 2µs making 1 call to Foswiki::CORE:subst
1801 }
1802 elsif ( $pathInfo =~ m#^/(.*?)$# ) {
1803
1804 # is 'bin/script/Webname' or 'bin/script/'
1805 # implicit untaint OK - validated later
1806 $web = $1 unless $web;
1807 }
180818µs130µs my $topicNameTemp = $this->UTF82SiteCharSet($topic);
# spent 30µs making 1 call to Foswiki::UTF82SiteCharSet
180911µs if ($topicNameTemp) {
1810 $topic = $topicNameTemp;
1811 }
1812
1813 # Item3270 - here's the appropriate place to enforce spec
1814 # http://develop.twiki.org/~twiki4/cgi-bin/view/Bugs/Item3270
181513µs $topic = ucfirst($topic);
1816
1817 # Validate and untaint topic name from path info
1818110µs1167µs $this->{topicName} = Foswiki::Sandbox::untaint( $topic,
# spent 167µs making 1 call to Foswiki::Sandbox::untaint
1819 \&Foswiki::Sandbox::validateTopicName );
1820
1821 # Set the requestedWebName before applying defaults - used by statistics
1822 # generation. Note: This is validated using Topic name rules to permit
1823 # names beginning with lower case.
1824110µs172µs $this->{requestedWebName} =
# spent 72µs making 1 call to Foswiki::Sandbox::untaint
1825 Foswiki::Sandbox::untaint( $web, \&Foswiki::Sandbox::validateTopicName );
1826
1827 # Validate web name from path info
182818µs1186µs $this->{webName} =
# spent 186µs making 1 call to Foswiki::Sandbox::untaint
1829 Foswiki::Sandbox::untaint( $web, \&Foswiki::Sandbox::validateWebName );
1830
183112µs if ( !defined $this->{webName} && !defined $this->{topicName} ) {
1832 $this->{webName} = $Foswiki::cfg{UsersWebName};
1833 $this->{topicName} = $Foswiki::cfg{HomeTopicName};
1834 }
1835
183612µs $this->{webName} = ''
1837 unless ( defined $this->{webName} );
1838
183912µs $this->{topicName} = $Foswiki::cfg{HomeTopicName}
1840 unless ( defined $this->{topicName} );
1841
1842 # Convert UTF-8 web and topic name from URL into site charset if
1843 # necessary
1844 # SMELL: merge these two cases, browsers just don't mix two encodings
1845 # in one URL - can also simplify into 2 lines by making function
1846 # return unprocessed text if no conversion
184717µs121µs my $webNameTemp = $this->UTF82SiteCharSet( $this->{webName} );
# spent 21µs making 1 call to Foswiki::UTF82SiteCharSet
184812µs if ($webNameTemp) {
1849 $this->{webName} = $webNameTemp;
1850 }
1851
185214µs $this->{scriptUrlPath} = $Foswiki::cfg{ScriptUrlPath};
1853
1854 # Form definition cache
185513µs $this->{forms} = {};
1856
1857 # Push global preferences from %SYSTEMWEB%.DefaultPreferences
185818µs1282ms $prefs->loadDefaultPreferences();
# spent 282ms making 1 call to Foswiki::Prefs::loadDefaultPreferences
1859
1860 #Monitor::MARK("Loaded default prefs");
1861
1862 # SMELL: what happens if we move this into the Foswiki::Users::new?
1863124µs146.6ms $this->{user} = $this->{users}->initialiseUser( $this->{remoteUser} );
# spent 46.6ms making 1 call to Foswiki::Users::initialiseUser
1864
1865 #Monitor::MARK("Initialised user");
1866
1867 # Static session variables that can be expanded in topics when they
1868 # are enclosed in % signs
1869 # SMELL: should collapse these into one. The duplication is pretty
1870 # pointless.
1871116µs148µs $prefs->setInternalPreferences(
# spent 48µs making 1 call to Foswiki::Prefs::setInternalPreferences
1872 BASEWEB => $this->{webName},
1873 BASETOPIC => $this->{topicName},
1874 INCLUDINGTOPIC => $this->{topicName},
1875 INCLUDINGWEB => $this->{webName}
1876 );
1877
1878 # Push plugin settings
1879110µs1318µs $this->{plugins}->settings();
# spent 318µs making 1 call to Foswiki::Plugins::settings
1880
1881 # Now the rest of the preferences
188216µs16.00ms $prefs->loadSitePreferences();
# spent 6.00ms making 1 call to Foswiki::Prefs::loadSitePreferences
1883
1884 # User preferences only available if we can get to a valid wikiname,
1885 # which depends on the user mapper.
1886116µs1750µs my $wn = $this->{users}->getWikiName( $this->{user} );
# spent 750µs making 1 call to Foswiki::Users::getWikiName
188713µs if ($wn) {
188817µs17.72ms $prefs->setUserPreferences($wn);
# spent 7.72ms making 1 call to Foswiki::Prefs::setUserPreferences
1889 }
1890
1891111µs112.5ms $prefs->pushTopicContext( $this->{webName}, $this->{topicName} );
# spent 12.5ms making 1 call to Foswiki::Prefs::pushTopicContext
1892
1893 #Monitor::MARK("Preferences all set up");
1894
1895 # Finish plugin initialization - register handlers
1896113µs181.2s $this->{plugins}->enable();
# spent 81.2s making 1 call to Foswiki::Plugins::enable
1897
1898114µs112µs Monitor::MARK("Foswiki object created");
1899
1900134µs return $this;
1901}
1902
1903=begin TML
1904
1905---++ ObjectMethod renderer()
1906Get a reference to the renderer object. Done lazily because not everyone
1907needs the renderer.
1908
1909=cut
1910
1911
# spent 20.5ms (17.9+2.57) within Foswiki::renderer which was called 23 times, avg 892µs/call: # 7 times (17.8ms+2.57ms) by Foswiki::FORMFIELD at line 22 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMFIELD.pm, avg 2.91ms/call # 6 times (61µs+0s) by Foswiki::REVINFO at line 38 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/REVINFO.pm, avg 10µs/call # 5 times (50µs+0s) by Foswiki::Meta::renderTML at line 3144 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm, avg 10µs/call # 4 times (55µs+0s) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm:326] at line 312 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 14µs/call # once (8µs+0s) by Foswiki::META at line 41 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/META.pm
sub renderer {
19122344µs my ($this) = @_;
1913
19142344µs unless ( $this->{renderer} ) {
19151115µs require Foswiki::Render;
1916112µs125µs $this->{renderer} = new Foswiki::Render($this);
# spent 25µs making 1 call to Foswiki::Render::new
1917 }
191823183µs return $this->{renderer};
1919}
1920
1921=begin TML
1922
1923---++ ObjectMethod attach()
1924Get a reference to the attach object. Done lazily because not everyone
1925needs the attach.
1926
1927=cut
1928
1929
# spent 4.63ms (4.46+175µs) within Foswiki::attach which was called: # once (4.46ms+175µs) by Foswiki::META at line 33 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/META.pm
sub attach {
193012µs my ($this) = @_;
1931
193214µs unless ( $this->{attach} ) {
19331148µs require Foswiki::Attach;
1934114µs124µs $this->{attach} = new Foswiki::Attach($this);
# spent 24µs making 1 call to Foswiki::Attach::new
1935 }
193619µs return $this->{attach};
1937}
1938
1939=begin TML
1940
1941---++ ObjectMethod templates()
1942Get a reference to the templates object. Done lazily because not everyone
1943needs the templates.
1944
1945=cut
1946
1947
# spent 11.1ms (4.80+6.30) within Foswiki::templates which was called 21 times, avg 528µs/call: # 9 times (79µs+0s) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:281] at line 281, avg 9µs/call # 3 times (30µs+0s) by Foswiki::Func::expandTemplate at line 2441 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 10µs/call # 2 times (21µs+0s) by Foswiki::LoginManager::_LOGOUT at line 1086 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm, avg 10µs/call # once (4.61ms+6.30ms) by Foswiki::UI::View::view at line 229 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm # once (14µs+0s) by Foswiki::Search::loadTemplates at line 480 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (13µs+0s) by Foswiki::Form::renderForDisplay at line 595 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm # once (9µs+0s) by Foswiki::Func::loadTemplate at line 2409 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm # once (9µs+0s) by Foswiki::Search::loadTemplates at line 507 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (8µs+0s) by Foswiki::Search::loadTemplates at line 495 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (8µs+0s) by Foswiki::Search::loadTemplates at line 496 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm
sub templates {
19482141µs my ($this) = @_;
1949
19502140µs unless ( $this->{templates} ) {
19511134µs require Foswiki::Templates;
1952111µs128µs $this->{templates} = new Foswiki::Templates($this);
# spent 28µs making 1 call to Foswiki::Templates::new
1953 }
195421187µs return $this->{templates};
1955}
1956
1957=begin TML
1958
1959---++ ObjectMethod i18n()
1960Get a reference to the i18n object. Done lazily because not everyone
1961needs the i18ner.
1962
1963=cut
1964
1965
# spent 5.08ms (3.98+1.10) within Foswiki::i18n which was called 59 times, avg 86µs/call: # 52 times (3.90ms+1.10ms) by Foswiki::MAKETEXT at line 38 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/MAKETEXT.pm, avg 96µs/call # 6 times (62µs+0s) by Foswiki::Search::formatResult at line 1200 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 10µs/call # once (15µs+0s) by Foswiki::Plugins::JQueryPlugin::UI::init at line 63 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Plugins/JQueryPlugin/UI.pm
sub i18n {
196659103µs my ($this) = @_;
1967
196859104µs unless ( $this->{i18n} ) {
19691105µs require Foswiki::I18N;
1970
1971 # language information; must be loaded after
1972 # *all possible preferences sources* are available
1973114µs1927µs $this->{i18n} = new Foswiki::I18N($this);
# spent 927µs making 1 call to Foswiki::I18N::new
1974 }
197559365µs return $this->{i18n};
1976}
1977
1978=begin TML
1979
1980---++ ObjectMethod logger()
1981
1982=cut
1983
1984
# spent 4.47ms (4.01+453µs) within Foswiki::logger which was called: # once (4.01ms+453µs) by Foswiki::logEvent at line 2194
sub logger {
198512µs my $this = shift;
1986
1987164µs unless ( $this->{logger} ) {
198815µs if ( $Foswiki::cfg{Log}{Implementation} eq 'none' ) {
1989 $this->{logger} = Foswiki::Logger->new();
1990 }
1991 else {
1992186µs eval "require $Foswiki::cfg{Log}{Implementation}";
# spent 151µs executing statements in string eval
199313µs if ($@) {
1994 print STDERR "Logger load failed: $@";
1995 $this->{logger} = Foswiki::Logger->new();
1996 }
1997 else {
1998116µs123µs $this->{logger} = $Foswiki::cfg{Log}{Implementation}->new();
# spent 23µs making 1 call to Foswiki::Logger::PlainFile::new
1999 }
2000 }
2001 }
2002
2003110µs return $this->{logger};
2004}
2005
2006=begin TML
2007
2008---++ ObjectMethod search()
2009Get a reference to the search object. Done lazily because not everyone
2010needs the searcher.
2011
2012=cut
2013
2014
# spent 24.5ms (11.1+13.5) within Foswiki::search which was called 103 times, avg 238µs/call: # 55 times (10.7ms+13.5ms) by Foswiki::Meta::load at line 468 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm, avg 439µs/call # 22 times (186µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:187] at line 179 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 8µs/call # 22 times (166µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:187] at line 169 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 8µs/call # once (14µs+0s) by Foswiki::Users::TopicUserMapping::_getListOfGroups at line 1526 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm # once (10µs+0s) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMAT.pm:65] at line 62 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMAT.pm # once (8µs+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 78 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm # once (7µs+0s) by Foswiki::Users::TopicUserMapping::_getListOfGroups at line 1532 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm
sub search {
2015103191µs my ($this) = @_;
2016
2017103181µs unless ( $this->{search} ) {
20181132µs require Foswiki::Search;
2019113µs122µs $this->{search} = new Foswiki::Search($this);
# spent 22µs making 1 call to Foswiki::Search::new
2020 }
2021103741µs return $this->{search};
2022}
2023
2024=begin TML
2025
2026---++ ObjectMethod net()
2027Get a reference to the net object. Done lazily because not everyone
2028needs the net.
2029
2030=cut
2031
2032sub net {
2033 my ($this) = @_;
2034
2035 unless ( $this->{net} ) {
2036 require Foswiki::Net;
2037 $this->{net} = new Foswiki::Net($this);
2038 }
2039 return $this->{net};
2040}
2041
2042=begin TML
2043
2044---++ ObjectMethod access()
2045Get a reference to the ACL object.
2046
2047=cut
2048
2049
# spent 13.5ms (1.01+12.5) within Foswiki::access which was called 112 times, avg 120µs/call: # 56 times (572µs+12.5ms) by Foswiki::Meta::haveAccess at line 1836 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm, avg 233µs/call # 56 times (435µs+0s) by Foswiki::Meta::haveAccess at line 1837 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm, avg 8µs/call
sub access {
2050112189µs my ($this) = @_;
2051
2052112196µs unless ( $this->{access} ) {
205329.30ms1806µs
# spent 806µs (576+230) within Foswiki::BEGIN@2053 which was called: # once (576µs+230µs) by main::BEGIN@27 at line 2053
use Foswiki::Access;
# spent 806µs making 1 call to Foswiki::BEGIN@2053
2054113µs112.5ms $this->{access} = new Foswiki::Access($this);
# spent 12.5ms making 1 call to Foswiki::Access::new
2055 }
2056112766µs return $this->{access};
2057}
2058
2059=begin TML
2060
2061---++ ObjectMethod DESTROY()
2062
2063called by Perl when the Foswiki object goes out of scope
2064(maybe should be used kist to ASSERT that finish() was called..
2065
2066=cut
2067
2068#sub DESTROY {
2069# my $this = shift;
2070# $this->finish();
2071#}
2072
2073=begin TML
2074
2075---++ ObjectMethod finish()
2076Break circular references.
2077
2078=cut
2079
2080# Note to developers; please undef *all* fields in the object explicitly,
2081# whether they are references or not. That way this method is "golden
2082# documentation" of the live fields in the object.
2083
# spent 8.04ms (1.01+7.03) within Foswiki::finish which was called: # once (1.01ms+7.03ms) by Foswiki::UI::_execute at line 436 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI.pm
sub finish {
208412µs my $this = shift;
2085
2086 # Print any macros that are never loaded
2087 #print STDERR "NEVER USED\n";
2088 #for my $i (keys %macros) {
2089 # print STDERR "\t$i\n" unless defined $macros{$i};
2090 #}
2091224µs11.25ms $_->finish() foreach values %{ $this->{forms} };
# spent 1.25ms making 1 call to Foswiki::Form::finish
2092116µs undef $this->{forms};
209318µs foreach my $key (
2094 qw(plugins users prefs templates renderer net
2095 store search attach access i18n cache logger)
2096 )
2097 {
2098 next
20991335µs unless ref( $this->{$key} );
210011253µs115.77ms $this->{$key}->finish();
# spent 3.25ms making 1 call to Foswiki::Users::finish # spent 880µs making 1 call to Foswiki::Prefs::finish # spent 648µs making 1 call to Foswiki::Plugins::finish # spent 628µs making 1 call to Foswiki::Search::finish # spent 195µs making 1 call to Foswiki::Templates::finish # spent 62µs making 1 call to Foswiki::Store::VC::Store::finish # spent 57µs making 1 call to Foswiki::I18N::Fallback::finish # spent 20µs making 1 call to Foswiki::Render::finish # spent 9µs making 1 call to Foswiki::Attach::finish # spent 9µs making 1 call to Foswiki::Access::finish # spent 8µs making 1 call to Foswiki::Logger::finish
210111544µs undef $this->{$key};
2102 }
2103
210413µs undef $this->{_zones};
210511µs undef $this->{_renderZonePlaceholder};
2106
210712µs undef $this->{request};
210812µs undef $this->{cgiQuery};
2109
2110145µs undef $this->{digester};
211112µs111µs undef $this->{urlHost};
# spent 11µs making 1 call to Digest::MD5::DESTROY
211212µs undef $this->{web};
211314µs undef $this->{topic};
211412µs undef $this->{webName};
211512µs undef $this->{topicName};
211614µs undef $this->{_ICONSPACE};
211712µs undef $this->{_EXT2ICON};
211812µs undef $this->{_KNOWNICON};
211911µs undef $this->{_ICONSTEMPLATE};
212012µs undef $this->{context};
212112µs undef $this->{remoteUser};
212212µs undef $this->{requestedWebName}; # Web name before renaming
212313µs undef $this->{scriptUrlPath};
212412µs undef $this->{user};
212512µs undef $this->{_INCLUDES};
212612µs undef $this->{response};
212713µs undef $this->{evaluating_if};
212812µs undef $this->{_addedToHEAD};
212912µs undef $this->{sandbox};
213012µs undef $this->{evaluatingEval};
2131
213212µs undef $this->{DebugVerificationCode}; # from Foswiki::UI::Register
2133
2134116µs15µs if (DEBUG) {
# spent 5µs making 1 call to Assert::ASSERTS_OFF
2135 my $remaining = join ',', grep { defined $this->{$_} } keys %$this;
2136 ASSERT( 0,
2137 "Fields with defined values in "
2138 . ref($this)
2139 . "->finish(): "
2140 . $remaining )
2141 if $remaining;
2142 }
2143}
2144
2145=begin TML
2146
2147---++ ObjectMethod logEvent( $action, $webTopic, $extra, $user )
2148 * =$action= - what happened, e.g. view, save, rename
2149 * =$webTopic= - what it happened to
2150 * =$extra= - extra info, such as minor flag
2151 * =$user= - login name of user - default current user,
2152 or failing that the user agent
2153
2154Write the log for an event to the logfile
2155
2156=cut
2157
2158
# spent 8.65ms (122µs+8.53) within Foswiki::logEvent which was called: # once (122µs+8.53ms) by Foswiki::UI::View::view at line 203 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm
sub logEvent {
215913µs my $this = shift;
2160
216112µs my $action = shift || '';
216212µs my $webTopic = shift || '';
216312µs my $extra = shift || '';
216411µs my $user = shift;
2165
2166 return
216715µs if ( defined $Foswiki::cfg{Log}{Action}{$action}
2168 && !$Foswiki::cfg{Log}{Action}{$action} );
2169
217012µs $user ||= $this->{user};
2171118µs121µs $user = ( $this->{users}->getLoginName($user) || 'unknown' )
# spent 21µs making 1 call to Foswiki::Users::getLoginName
2172 if ( $this->{users} );
2173
217412µs my $cgiQuery = $this->{request};
217513µs if ($cgiQuery) {
2176113µs190µs my $agent = $cgiQuery->user_agent();
# spent 90µs making 1 call to Foswiki::Request::userAgent
217713µs if ($agent) {
217811µs $extra .= ' ' if $extra;
2179130µs116µs if ( $agent =~
# spent 16µs making 1 call to Foswiki::CORE:match
2180/(MSIE 6|MSIE 7|MSIE 8|MSI 9|Firefox|Opera|Konqueror|Chrome|Safari)/
2181 )
2182 {
218318µs $extra .= $1;
2184 }
2185 else {
2186 $agent =~ m/([\w]+)/;
2187 $extra .= $1;
2188 }
2189 }
2190 }
2191
2192113µs113µs my $remoteAddr = $this->{request}->remoteAddress() || '';
# spent 13µs making 1 call to Foswiki::Request::remoteAddress
2193
2194123µs28.39ms $this->logger->log( 'info', $user, $action, $webTopic, $extra,
# spent 4.47ms making 1 call to Foswiki::logger # spent 3.92ms making 1 call to Foswiki::Logger::PlainFile::log
2195 $remoteAddr );
2196}
2197
2198=begin TML
2199
2200---++ StaticMethod validatePattern( $pattern ) -> $pattern
2201
2202Validate a pattern provided in a parameter to $pattern so that
2203dangerous chars (interpolation and execution) are disabled.
2204
2205=cut
2206
2207sub validatePattern {
2208 my $pattern = shift;
2209
2210 # Escape unescaped $ and @ characters that might interpolate
2211 # an internal variable.
2212 # There is no need to defuse (??{ and (?{ as perl won't allow
2213 # it anyway, unless one uses re 'eval' which we won't do
2214 $pattern =~ s/(^|[^\\])([\$\@])/$1\\$2/g;
2215 return $pattern;
2216}
2217
2218=begin TML
2219
2220---++ ObjectMethod inlineAlert($template, $def, ... ) -> $string
2221
2222Format an error for inline inclusion in rendered output. The message string
2223is obtained from the template 'oops'.$template, and the DEF $def is
2224selected. The parameters (...) are used to populate %PARAM1%..%PARAMn%
2225
2226=cut
2227
2228sub inlineAlert {
2229 my $this = shift;
2230 my $template = shift;
2231 my $def = shift;
2232
2233 # web and topic can be anything; they are not used
2234 my $topicObject =
2235 Foswiki::Meta->new( $this, $this->{webName}, $this->{topicName} );
2236 my $text = $this->templates->readTemplate( 'oops' . $template );
2237 if ($text) {
2238 my $blah = $this->templates->expandTemplate($def);
2239 $text =~ s/%INSTANTIATE%/$blah/;
2240
2241 $text = $topicObject->expandMacros($text);
2242 my $n = 1;
2243 while ( defined( my $param = shift ) ) {
2244 $text =~ s/%PARAM$n%/$param/g;
2245 $n++;
2246 }
2247
2248 # Suppress missing params
2249 $text =~ s/%PARAM\d+%//g;
2250
2251 # Suppress missing params
2252 $text =~ s/%PARAM\d+%//g;
2253 }
2254 else {
2255
2256 # Error in the template system.
2257 $text = $topicObject->renderTML(<<MESSAGE);
2258---+ Foswiki Installation Error
2259Template '$template' not found.
2260
2261Check your configuration settings for {TemplateDir} and {TemplatePath}
2262MESSAGE
2263 }
2264
2265 return $text;
2266}
2267
2268=begin TML
2269
2270---++ StaticMethod parseSections($text) -> ($string,$sectionlistref)
2271
2272Generic parser for sections within a topic. Sections are delimited
2273by STARTSECTION and ENDSECTION, which may be nested, overlapped or
2274otherwise abused. The parser builds an array of sections, which is
2275ordered by the order of the STARTSECTION within the topic. It also
2276removes all the SECTION tags from the text, and returns the text
2277and the array of sections.
2278
2279Each section is a =Foswiki::Attrs= object, which contains the attributes
2280{type, name, start, end}
2281where start and end are character offsets in the
2282string *after all section tags have been removed*. All sections
2283are required to be uniquely named; if a section is unnamed, it
2284will be given a generated name. Sections may overlap or nest.
2285
2286See test/unit/Fn_SECTION.pm for detailed testcases that
2287round out the spec.
2288
2289=cut
2290
2291
# spent 11.1ms (5.11+5.96) within Foswiki::parseSections which was called 20 times, avg 553µs/call: # 20 times (5.11ms+5.96ms) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm:326] at line 250 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 553µs/call
sub parseSections {
2292
22932094µs my $text = shift;
2294
22952032µs return ( '', [] ) unless defined $text;
2296
22972028µs my %sections;
22982041µs my @list = ();
2299
23002034µs my $seq = 0;
23012045µs my $ntext = '';
23022029µs my $offset = 0;
230320428µs foreach my $bit ( split( /(%(?:START|END)SECTION(?:{.*?})?%)/, $text ) ) {
23041402.03ms250602µs if ( $bit =~ /^%STARTSECTION(?:{(.*)})?%$/ ) {
# spent 602µs making 250 calls to Foswiki::CORE:match, avg 2µs/call
23053054µs require Foswiki::Attrs;
2306
2307 # SMELL: unchecked implicit untaint?
230830196µs302.78ms my $attrs = new Foswiki::Attrs($1);
# spent 2.78ms making 30 calls to Foswiki::Attrs::new, avg 93µs/call
23093098µs $attrs->{type} ||= 'section';
23103089µs $attrs->{name} =
2311 $attrs->{_DEFAULT}
2312 || $attrs->{name}
2313 || '_SECTION' . $seq++;
23143066µs delete $attrs->{_DEFAULT};
23153091µs my $id = $attrs->{type} . ':' . $attrs->{name};
23163049µs if ( $sections{$id} ) {
2317
2318 # error, this named section already defined, ignore
2319 next;
2320 }
2321
2322 # close open unnamed sections of the same type
232330105µs foreach my $s (@list) {
232430116µs if ( $s->{end} < 0
2325 && $s->{type} eq $attrs->{type}
2326 && $s->{name} =~ /^_SECTION\d+$/ )
2327 {
2328 $s->{end} = $offset;
2329 }
2330 }
233130107µs $attrs->{start} = $offset;
23323058µs $attrs->{end} = -1; # open section
233330126µs $sections{$id} = $attrs;
23343073µs push( @list, $attrs );
2335 }
2336 elsif ( $bit =~ /^%ENDSECTION(?:{(.*)})?%$/ ) {
23373051µs require Foswiki::Attrs;
2338
2339 # SMELL: unchecked implicit untaint?
234030211µs302.58ms my $attrs = new Foswiki::Attrs($1);
# spent 2.58ms making 30 calls to Foswiki::Attrs::new, avg 86µs/call
23413078µs $attrs->{type} ||= 'section';
23423064µs $attrs->{name} = $attrs->{_DEFAULT} || $attrs->{name} || '';
23433059µs delete $attrs->{_DEFAULT};
23443049µs unless ( $attrs->{name} ) {
2345
2346 # find the last open unnamed section of this type
2347 foreach my $s ( reverse @list ) {
2348 if ( $s->{end} == -1
2349 && $s->{type} eq $attrs->{type}
2350 && $s->{name} =~ /^_SECTION\d+$/ )
2351 {
2352 $attrs->{name} = $s->{name};
2353 last;
2354 }
2355 }
2356
2357 # ignore it if no matching START found
2358 next unless $attrs->{name};
2359 }
23603097µs my $id = $attrs->{type} . ':' . $attrs->{name};
23613081µs if ( !$sections{$id} || $sections{$id}->{end} >= 0 ) {
2362
2363 # error, no such open section, ignore
2364 next;
2365 }
236630154µs $sections{$id}->{end} = $offset;
2367 }
2368 else {
236980206µs $ntext .= $bit;
237080138µs $offset = length($ntext);
2371 }
2372 }
2373
2374 # close open sections
237520102µs foreach my $s (@list) {
237630102µs $s->{end} = $offset if $s->{end} < 0;
2377 }
2378
237920251µs return ( $ntext, \@list );
2380}
2381
2382=begin TML
2383
2384---++ ObjectMethod expandMacrosOnTopicCreation ( $topicObject )
2385
2386 * =$topicObject= - the topic
2387
2388Expand only that subset of Foswiki variables that are
2389expanded during topic creation, in the body text and
2390PREFERENCE meta only. The expansion is in-place inside
2391the topic object.
2392
2393# SMELL: no plugin handler
2394
2395=cut
2396
2397sub expandMacrosOnTopicCreation {
2398 my ( $this, $topicObject ) = @_;
2399
2400 # Make sure func works, for registered tag handlers
2401 local $Foswiki::Plugins::SESSION = $this;
2402
2403 my $text = $topicObject->text();
2404 if ($text) {
2405
2406 # Chop out templateonly sections
2407 my ( $ntext, $sections ) = parseSections($text);
2408 if ( scalar(@$sections) ) {
2409
2410 # Note that if named templateonly sections overlap,
2411 # the behaviour is undefined.
2412 foreach my $s ( reverse @$sections ) {
2413 if ( $s->{type} eq 'templateonly' ) {
2414 $ntext =
2415 substr( $ntext, 0, $s->{start} )
2416 . substr( $ntext, $s->{end}, length($ntext) );
2417 }
2418 else {
2419
2420 # put back non-templateonly sections
2421 my $start = $s->remove('start');
2422 my $end = $s->remove('end');
2423 $ntext =
2424 substr( $ntext, 0, $start )
2425 . '%STARTSECTION{'
2426 . $s->stringify() . '}%'
2427 . substr( $ntext, $start, $end - $start )
2428 . '%ENDSECTION{'
2429 . $s->stringify() . '}%'
2430 . substr( $ntext, $end, length($ntext) );
2431 }
2432 }
2433 $text = $ntext;
2434 }
2435
2436 $text = _processMacros( $this, $text, \&_expandMacroOnTopicCreation,
2437 $topicObject, 16 );
2438
2439 # expand all variables for type="expandvariables" sections
2440 ( $ntext, $sections ) = parseSections($text);
2441 if ( scalar(@$sections) ) {
2442 foreach my $s ( reverse @$sections ) {
2443 if ( $s->{type} eq 'expandvariables' ) {
2444 my $etext =
2445 substr( $ntext, $s->{start}, $s->{end} - $s->{start} );
2446 $this->innerExpandMacros( \$etext, $topicObject );
2447 $ntext =
2448 substr( $ntext, 0, $s->{start} )
2449 . $etext
2450 . substr( $ntext, $s->{end}, length($ntext) );
2451 }
2452 else {
2453
2454 # put back non-expandvariables sections
2455 my $start = $s->remove('start');
2456 my $end = $s->remove('end');
2457 $ntext =
2458 substr( $ntext, 0, $start )
2459 . '%STARTSECTION{'
2460 . $s->stringify() . '}%'
2461 . substr( $ntext, $start, $end - $start )
2462 . '%ENDSECTION{'
2463 . $s->stringify() . '}%'
2464 . substr( $ntext, $end, length($ntext) );
2465 }
2466 }
2467 $text = $ntext;
2468 }
2469
2470 # kill markers used to prevent variable expansion
2471 $text =~ s/%NOP%//g;
2472 $topicObject->text($text);
2473 }
2474
2475 # Expand preferences
2476 my @prefs = $topicObject->find('PREFERENCE');
2477 foreach my $p (@prefs) {
2478 $p->{value} =
2479 _processMacros( $this, $p->{value}, \&_expandMacroOnTopicCreation,
2480 $topicObject, 16 );
2481
2482 # kill markers used to prevent variable expansion
2483 $p->{value} =~ s/%NOP%//g;
2484 }
2485}
2486
2487=begin TML
2488
2489---++ StaticMethod entityEncode( $text, $extras ) -> $encodedText
2490
2491Escape special characters to HTML numeric entities. This is *not* a generic
2492encoding, it is tuned specifically for use in Foswiki.
2493
2494HTML4.0 spec:
2495"Certain characters in HTML are reserved for use as markup and must be
2496escaped to appear literally. The "&lt;" character may be represented with
2497an <em>entity</em>, <strong class=html>&amp;lt;</strong>. Similarly, "&gt;"
2498is escaped as <strong class=html>&amp;gt;</strong>, and "&amp;" is escaped
2499as <strong class=html>&amp;amp;</strong>. If an attribute value contains a
2500double quotation mark and is delimited by double quotation marks, then the
2501quote should be escaped as <strong class=html>&amp;quot;</strong>.</p>
2502
2503Other entities exist for special characters that cannot easily be entered
2504with some keyboards..."
2505
2506This method encodes HTML special and any non-printable ascii
2507characters (except for \n and \r) using numeric entities.
2508
2509FURTHER this method also encodes characters that are special in Foswiki
2510meta-language.
2511
2512$extras is an optional param that may be used to include *additional*
2513characters in the set of encoded characters. It should be a string
2514containing the additional chars.
2515
2516=cut
2517
2518sub entityEncode {
2519 my ( $text, $extra ) = @_;
2520 $extra ||= '';
2521
2522 # encode all non-printable 7-bit chars (< \x1f),
2523 # except \n (\xa) and \r (\xd)
2524 # encode HTML special characters '>', '<', '&', ''' and '"'.
2525 # encode TML special characters '%', '|', '[', ']', '@', '_',
2526 # '*', and '='
2527 $text =~
2528 s/([[\x01-\x09\x0b\x0c\x0e-\x1f"%&'*<=>@[_\|$extra])/'&#'.ord($1).';'/ge;
2529 return $text;
2530}
2531
2532=begin TML
2533
2534---++ StaticMethod entityDecode ( $encodedText ) -> $text
2535
2536Decodes all numeric entities (e.g. &amp;#123;). _Does not_ decode
2537named entities such as &amp;amp; (use HTML::Entities for that)
2538
2539=cut
2540
2541sub entityDecode {
2542 my $text = shift;
2543
2544 $text =~ s/&#(\d+);/chr($1)/ge;
2545 return $text;
2546}
2547
2548=begin TML
2549
2550---++ StaticMethod urlEncodeAttachment ( $text )
2551
2552For attachments, URL-encode specially to 'freeze' any characters >127 in the
2553site charset (e.g. ISO-8859-1 or KOI8-R), by doing URL encoding into native
2554charset ($siteCharset) - used when generating attachment URLs, to enable the
2555web server to serve attachments, including images, directly.
2556
2557This encoding is required to handle the cases of:
2558
2559 - browsers that generate UTF-8 URLs automatically from site charset URLs - now quite common
2560 - web servers that directly serve attachments, using the site charset for
2561 filenames, and cannot convert UTF-8 URLs into site charset filenames
2562
2563The aim is to prevent the browser from converting a site charset URL in the web
2564page to a UTF-8 URL, which is the default. Hence we 'freeze' the URL into the
2565site character set through URL encoding.
2566
2567In two cases, no URL encoding is needed: For EBCDIC mainframes, we assume that
2568site charset URLs will be translated (outbound and inbound) by the web server to/from an
2569EBCDIC character set. For sites running in UTF-8, there's no need for Foswiki to
2570do anything since all URLs and attachment filenames are already in UTF-8.
2571
2572=cut
2573
2574sub urlEncodeAttachment {
2575 my ($text) = @_;
2576
2577 my $usingEBCDIC = ( 'A' eq chr(193) ); # Only true on EBCDIC mainframes
2578
2579 if ( $Foswiki::cfg{Site}{CharSet} =~ /^utf-?8$/i or $usingEBCDIC ) {
2580
2581 # Just let browser do UTF-8 URL encoding
2582 return $text;
2583 }
2584
2585 # Freeze into site charset through URL encoding
2586 return urlEncode($text);
2587}
2588
2589=begin TML
2590
2591---++ StaticMethod urlEncode( $string ) -> encoded string
2592
2593Encode by converting characters that are illegal in URLs to
2594their %NN equivalents. This method is used for encoding
2595strings that must be embedded _verbatim_ in URLs; it cannot
2596be applied to URLs themselves, as it escapes reserved
2597characters such as = and ?.
2598
2599RFC 1738, Dec. '94:
2600 <verbatim>
2601 ...Only alphanumerics [0-9a-zA-Z], the special
2602 characters $-_.+!*'(), and reserved characters used for their
2603 reserved purposes may be used unencoded within a URL.
2604 </verbatim>
2605
2606Reserved characters are $&+,/:;=?@ - these are _also_ encoded by
2607this method.
2608
2609This URL-encoding handles all character encodings including ISO-8859-*,
2610KOI8-R, EUC-* and UTF-8.
2611
2612This may not handle EBCDIC properly, as it generates an EBCDIC URL-encoded
2613URL, but mainframe web servers seem to translate this outbound before it hits browser
2614- see CGI::Util::escape for another approach.
2615
2616=cut
2617
2618
# spent 1.48ms (1.17+307µs) within Foswiki::urlEncode which was called 90 times, avg 16µs/call: # 55 times (585µs+135µs) by Foswiki::getScriptUrl at line 1443, avg 13µs/call # 20 times (187µs+40µs) by Foswiki::make_params at line 1470, avg 11µs/call # 15 times (400µs+132µs) by Foswiki::ENCODE at line 81 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/ENCODE.pm, avg 36µs/call
sub urlEncode {
261990147µs my $text = shift;
2620
2621119934µs122307µs $text =~ s/([^0-9a-zA-Z-_.:~!*'\/])/'%'.sprintf('%02x',ord($1))/ge;
# spent 214µs making 90 calls to Foswiki::CORE:subst, avg 2µs/call # spent 93µs making 32 calls to Foswiki::CORE:substcont, avg 3µs/call
2622
262390459µs return $text;
2624}
2625
2626=begin TML
2627
2628---++ StaticMethod urlDecode( $string ) -> decoded string
2629
2630Reverses the encoding done in urlEncode.
2631
2632=cut
2633
2634sub urlDecode {
2635 my $text = shift;
2636
2637 $text =~ s/%([\da-f]{2})/chr(hex($1))/gei;
2638
2639 return $text;
2640}
2641
2642=begin TML
2643
2644---++ StaticMethod isTrue( $value, $default ) -> $boolean
2645
2646Returns 1 if =$value= is true, and 0 otherwise. "true" means set to
2647something with a Perl true value, with the special cases that "off",
2648"false" and "no" (case insensitive) are forced to false. Leading and
2649trailing spaces in =$value= are ignored.
2650
2651If the value is undef, then =$default= is returned. If =$default= is
2652not specified it is taken as 0.
2653
2654=cut
2655
2656
# spent 89.4ms (88.7+738µs) within Foswiki::isTrue which was called 12237 times, avg 7µs/call: # 12167 times (87.0ms+20µs) by Foswiki::Func::isTrue at line 2905 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 7µs/call # 20 times (807µs+417µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm:326] at line 290 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 61µs/call # 5 times (177µs+82µs) by Foswiki::Render::getRenderedVersion at line 1411 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 52µs/call # 4 times (35µs+0s) by Foswiki::Func::getPreferencesFlag at line 780 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 9µs/call # 2 times (37µs+13µs) by Foswiki::Search::formatResults at line 572 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 25µs/call # 2 times (37µs+13µs) by Foswiki::Search::formatResults at line 690 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 25µs/call # 2 times (36µs+13µs) by Foswiki::Search::formatResults at line 677 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 25µs/call # 2 times (37µs+13µs) by Foswiki::Search::formatResults at line 575 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 25µs/call # 2 times (36µs+13µs) by Foswiki::Search::formatResults at line 574 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 24µs/call # 2 times (36µs+12µs) by Foswiki::Search::formatResults at line 678 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 24µs/call # 2 times (35µs+13µs) by Foswiki::Search::formatResults at line 693 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 24µs/call # 2 times (20µs+0s) by Foswiki::URLPARAM at line 20 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/URLPARAM.pm, avg 10µs/call # 2 times (18µs+0s) by Foswiki::Search::formatResults at line 571 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 9µs/call # 2 times (14µs+0s) by Foswiki::Search::formatResults at line 691 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 7µs/call # 2 times (14µs+0s) by Foswiki::Search::formatResults at line 573 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm, avg 7µs/call # once (39µs+20µs) by Foswiki::Search::searchWeb at line 408 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (38µs+20µs) by Foswiki::Search::searchWeb at line 264 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (36µs+18µs) by Foswiki::Store::Interfaces::QueryAlgorithm::getListOfWebs at line 453 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm # once (30µs+18µs) by Foswiki::Search::searchWeb at line 270 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (30µs+14µs) by Foswiki::Search::searchWeb at line 409 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (29µs+13µs) by Foswiki::Search::searchWeb at line 272 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (29µs+13µs) by Foswiki::Search::searchWeb at line 276 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (29µs+13µs) by Foswiki::Search::searchWeb at line 286 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (17µs+0s) by Foswiki::Search::InfoCache::sortResults at line 137 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search/InfoCache.pm # once (9µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:228] at line 217 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm # once (8µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::query at line 122 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm # once (8µs+0s) by Foswiki::Search::searchWeb at line 338 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (8µs+0s) by Foswiki::Search::searchWeb at line 257 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (8µs+0s) by Foswiki::Search::searchWeb at line 262 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (7µs+0s) by Foswiki::Search::searchWeb at line 281 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (7µs+0s) by Foswiki::Search::searchWeb at line 292 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (7µs+0s) by Foswiki::Search::searchWeb at line 287 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (7µs+0s) by Foswiki::Search::searchWeb at line 263 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm # once (7µs+0s) by Foswiki::Search::searchWeb at line 294 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Search.pm
sub isTrue {
26571223725.5ms my ( $value, $default ) = @_;
2658
26591223715.4ms $default ||= 0;
2660
26611223770.1ms return $default unless defined($value);
2662
2663411.05ms123558µs $value =~ s/^\s*(.*?)\s*$/$1/gi;
# spent 287µs making 82 calls to Foswiki::CORE:substcont, avg 3µs/call # spent 271µs making 41 calls to Foswiki::CORE:subst, avg 7µs/call
266441237µs4168µs $value =~ s/off//gi;
# spent 68µs making 41 calls to Foswiki::CORE:subst, avg 2µs/call
266541215µs4159µs $value =~ s/no//gi;
# spent 59µs making 41 calls to Foswiki::CORE:subst, avg 1µs/call
266641210µs4153µs $value =~ s/false//gi;
# spent 53µs making 41 calls to Foswiki::CORE:subst, avg 1µs/call
266741286µs return ($value) ? 1 : 0;
2668}
2669
2670=begin TML
2671
2672---++ StaticMethod spaceOutWikiWord( $word, $sep ) -> $string
2673
2674Spaces out a wiki word by inserting a string (default: one space) between each word component.
2675With parameter $sep any string may be used as separator between the word components; if $sep is undefined it defaults to a space.
2676
2677=cut
2678
2679
# spent 99µs (48+51) within Foswiki::spaceOutWikiWord which was called: # once (48µs+51µs) by Foswiki::SPACEOUT at line 11 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/SPACEOUT.pm
sub spaceOutWikiWord {
268012µs my ( $word, $sep ) = @_;
2681
2682 # Both could have the value 0 so we cannot use simple = || ''
268312µs $word = defined($word) ? $word : '';
268412µs $sep = defined($sep) ? $sep : ' ';
2685161µs436µs $word =~
# spent 25µs making 1 call to Foswiki::CORE:regcomp # spent 7µs making 2 calls to Foswiki::CORE:substcont, avg 3µs/call # spent 5µs making 1 call to Foswiki::CORE:subst
2686s/([$regex{lowerAlpha}])([$regex{upperAlpha}$regex{numeric}]+)/$1$sep$2/go;
2687128µs215µs $word =~ s/([$regex{numeric}])([$regex{upperAlpha}])/$1$sep$2/go;
# spent 13µs making 1 call to Foswiki::CORE:regcomp # spent 2µs making 1 call to Foswiki::CORE:subst
2688110µs return $word;
2689}
2690
2691=begin TML
2692
2693---++ ObjectMethod innerExpandMacros(\$text, $topicObject)
2694Expands variables by replacing the variables with their
2695values. Some example variables: %<nop>TOPIC%, %<nop>SCRIPTURL%,
2696%<nop>WIKINAME%, etc.
2697$web and $incs are passed in for recursive include expansion. They can
2698safely be undef.
2699The rules for tag expansion are:
2700 1 Tags are expanded left to right, in the order they are encountered.
2701 1 Tags are recursively expanded as soon as they are encountered -
2702 the algorithm is inherently single-pass
2703 1 A tag is not "encountered" until the matching }% has been seen, by
2704 which time all tags in parameters will have been expanded
2705 1 Tag expansions that create new tags recursively are limited to a
2706 set number of hierarchical levels of expansion
2707
2708=cut
2709
2710
# spent 183s (147ms+183) within Foswiki::innerExpandMacros which was called 2321 times, avg 78.7ms/call: # 1131 times (71.5ms+183s) by Foswiki::expandMacros at line 3248, avg 162ms/call # 1131 times (70.8ms+-66.0ms) by Foswiki::expandMacros at line 3258, avg 4µs/call # 20 times (1.71ms+-1.71ms) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm:326] at line 296 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 0s/call # 20 times (1.40ms+-1.40ms) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm:326] at line 305 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 0s/call # 15 times (1.03ms+-1.03ms) by Foswiki::If::OP_dollar::evaluate at line 40 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/If/OP_dollar.pm, avg 0s/call # 4 times (255µs+-255µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm:326] at line 323 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/INCLUDE.pm, avg 0s/call
sub innerExpandMacros {
271123214.54ms my ( $this, $text, $topicObject ) = @_;
2712
2713 # push current context
2714232112.5ms232118.6ms my $memTopic = $this->{prefs}->getPreference('TOPIC');
# spent 18.6ms making 2321 calls to Foswiki::Prefs::getPreference, avg 8µs/call
2715232112.7ms232118.0ms my $memWeb = $this->{prefs}->getPreference('WEB');
# spent 18.0ms making 2321 calls to Foswiki::Prefs::getPreference, avg 8µs/call
2716
2717 # Historically this couldn't be called on web objects.
2718232112.2ms232116.2ms my $webContext = $topicObject->web || $this->{webName};
# spent 16.2ms making 2321 calls to Foswiki::Meta::web, avg 7µs/call
2719232112.0ms232115.7ms my $topicContext = $topicObject->topic || $this->{topicName};
# spent 15.7ms making 2321 calls to Foswiki::Meta::topic, avg 7µs/call
2720
2721232112.2ms232147.1ms $this->{prefs}->setInternalPreferences(
# spent 47.1ms making 2321 calls to Foswiki::Prefs::setInternalPreferences, avg 20µs/call
2722 TOPIC => $topicContext,
2723 WEB => $webContext
2724 );
2725
2726 # Escape ' !%VARIABLE%'
2727232128.6ms464210.5ms $$text =~ s/(?<=\s)!%($regex{tagNameRegex})/&#37;$1/g;
# spent 5.27ms making 2321 calls to Foswiki::CORE:subst, avg 2µs/call # spent 5.23ms making 2321 calls to Foswiki::CORE:regcomp, avg 2µs/call
2728
2729 # Make sure func works, for registered tag handlers
273023213.45ms $Foswiki::Plugins::SESSION = $this;
2731
2732 # NOTE TO DEBUGGERS
2733 # The depth parameter in the following call controls the maximum number
2734 # of levels of expansion. If it is set to 1 then only macros in the
2735 # topic will be expanded; macros that they in turn generate will be
2736 # left unexpanded. If it is set to 2 then the expansion will stop after
2737 # the first recursive inclusion, and so on. This is incredible useful
2738 # when debugging. The default, 16, was selected empirically.
2739232117.1ms2321183s $$text = _processMacros( $this, $$text, \&_expandMacroOnTopicRendering,
# spent 187s making 2321 calls to Foswiki::_processMacros, avg 80.6ms/call, recursion: max depth 3, sum of overlapping time 4.46s
2740 $topicObject, 16 );
2741
2742 # restore previous context
2743232122.1ms232147.5ms $this->{prefs}->setInternalPreferences(
# spent 47.5ms making 2321 calls to Foswiki::Prefs::setInternalPreferences, avg 20µs/call
2744 TOPIC => $memTopic,
2745 WEB => $memWeb
2746 );
2747}
2748
2749=begin TML
2750
2751---++ StaticMethod takeOutBlocks( \$text, $tag, \%map ) -> $text
2752 * =$text= - Text to process
2753 * =$tag= - XML-style tag.
2754 * =\%map= - Reference to a hash to contain the removed blocks
2755
2756Return value: $text with blocks removed
2757
2758Searches through $text and extracts blocks delimited by an XML-style tag,
2759storing the extracted block, and replacing with a token string which is
2760not affected by TML rendering. The text after these substitutions is
2761returned.
2762
2763=cut
2764
2765
# spent 49.2ms (37.2+12.0) within Foswiki::takeOutBlocks which was called 2379 times, avg 21µs/call: # 1131 times (17.0ms+5.30ms) by Foswiki::expandMacros at line 3230, avg 20µs/call # 1131 times (16.2ms+4.99ms) by Foswiki::expandMacros at line 3250, avg 19µs/call # 97 times (1.52ms+579µs) by Foswiki::_processMacros at line 2894, avg 22µs/call # 5 times (1.59ms+628µs) by Foswiki::Render::getRenderedVersion at line 1115 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 443µs/call # 5 times (668µs+313µs) by Foswiki::Render::getRenderedVersion at line 1414 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 196µs/call # 5 times (96µs+127µs) by Foswiki::Render::getRenderedVersion at line 1146 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 45µs/call # 5 times (114µs+108µs) by Foswiki::Render::getRenderedVersion at line 1114 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 45µs/call
sub takeOutBlocks {
276623796.96ms my ( $intext, $tag, $map ) = @_;
2767
2768237941.2ms475811.4ms return $intext unless ( $intext =~ m/<$tag\b/i );
# spent 6.51ms making 2379 calls to Foswiki::CORE:match, avg 3µs/call # spent 4.88ms making 2379 calls to Foswiki::CORE:regcomp, avg 2µs/call
2769
277047µs my $out = '';
277146µs my $depth = 0;
277245µs my $scoop;
277345µs my $tagParams;
2774
27754416µs431µs foreach my $token ( split( /(<\/?$tag[^>]*>)/i, $intext ) ) {
# spent 31µs making 4 calls to Foswiki::CORE:regcomp, avg 8µs/call
2776801.46ms282630µs if ( $token =~ /<$tag\b([^>]*)?>/i ) {
# spent 383µs making 141 calls to Foswiki::CORE:match, avg 3µs/call # spent 247µs making 141 calls to Foswiki::CORE:regcomp, avg 2µs/call
27771924µs $depth++;
27781933µs if ( $depth eq 1 ) {
27791946µs $tagParams = $1;
27801932µs next;
2781 }
2782 }
2783 elsif ( $token =~ /<\/$tag>/i ) {
27841924µs if ( $depth > 0 ) {
27851937µs $depth--;
27861930µs if ( $depth eq 0 ) {
27871946µs my $placeholder = "$tag$BLOCKID";
27881924µs $BLOCKID++;
27891978µs $map->{$placeholder}{text} = $scoop;
27901938µs $map->{$placeholder}{params} = $tagParams;
27911952µs $out .= "$OC$placeholder$CC";
27921925µs $scoop = '';
27931935µs next;
2794 }
2795 }
2796 }
279742175µs if ( $depth > 0 ) {
27981935µs $scoop .= $token;
2799 }
2800 else {
28012354µs $out .= $token;
2802 }
2803 }
2804
2805 # unmatched tags
280647µs if ( defined($scoop) && ( $scoop ne '' ) ) {
2807 my $placeholder = "$tag$BLOCKID";
2808 $BLOCKID++;
2809 $map->{$placeholder}{text} = $scoop;
2810 $map->{$placeholder}{params} = $tagParams;
2811 $out .= "$OC$placeholder$CC";
2812 }
2813
2814453µs return $out;
2815}
2816
2817=begin TML
2818
2819---++ StaticMethod putBackBlocks( \$text, \%map, $tag, $newtag, $callBack ) -> $text
2820
2821Return value: $text with blocks added back
2822 * =\$text= - reference to text to process
2823 * =\%map= - map placeholders to blocks removed by takeOutBlocks
2824 * =$tag= - Tag name processed by takeOutBlocks
2825 * =$newtag= - Tag name to use in output, in place of $tag.
2826 If undefined, uses $tag.
2827 * =$callback= - Reference to function to call on each block
2828 being inserted (optional)
2829
2830Reverses the actions of takeOutBlocks.
2831
2832Each replaced block is processed by the callback (if there is one) before
2833re-insertion.
2834
2835Parameters to the outermost cut block are replaced into the open tag,
2836even if that tag is changed. This allows things like =&lt;verbatim class=''>=
2837to be changed to =&lt;pre class=''>=
2838
2839If you set $newtag to '', replaces the taken-out block with the contents
2840of the block, not including the open/close. This is used for &lt;literal>,
2841for example.
2842
2843=cut
2844
2845
# spent 16.3ms (15.3+931µs) within Foswiki::putBackBlocks which was called 1248 times, avg 13µs/call: # 1131 times (12.4ms+0s) by Foswiki::expandMacros at line 3283, avg 11µs/call # 97 times (1.19ms+0s) by Foswiki::_processMacros at line 3016, avg 12µs/call # 5 times (663µs+463µs) by Foswiki::Render::getRenderedVersion at line 1435 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 225µs/call # 5 times (476µs+220µs) by Foswiki::Render::getRenderedVersion at line 1421 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 139µs/call # 5 times (296µs+129µs) by Foswiki::Render::getRenderedVersion at line 1424 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 85µs/call # 5 times (292µs+119µs) by Foswiki::Render::getRenderedVersion at line 1430 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 82µs/call
sub putBackBlocks {
284612482.69ms my ( $text, $map, $tag, $newtag, $callback ) = @_;
2847
284812481.92ms $newtag = $tag if ( !defined($newtag) );
2849
2850124810.5ms foreach my $placeholder ( keys %$map ) {
28511181.51ms236517µs if ( $placeholder =~ /^$tag\d+$/ ) {
# spent 332µs making 118 calls to Foswiki::CORE:regcomp, avg 3µs/call # spent 185µs making 118 calls to Foswiki::CORE:match, avg 2µs/call
28521944µs my $params = $map->{$placeholder}{params} || '';
28531936µs my $val = $map->{$placeholder}{text};
28541997µs17103µs $val = &$callback($val) if ( defined($callback) );
# spent 103µs making 17 calls to Foswiki::Render::_filterLiteral, avg 6µs/call
28551955µs if ( $newtag eq '' ) {
285617384µs34241µs $$text =~ s($OC$placeholder$CC)($val);
# spent 136µs making 17 calls to Foswiki::CORE:regcomp, avg 8µs/call # spent 105µs making 17 calls to Foswiki::CORE:subst, avg 6µs/call
2857 }
2858 else {
28592128µs870µs $$text =~ s($OC$placeholder$CC)
# spent 33µs making 4 calls to Foswiki::CORE:substcont, avg 8µs/call # spent 20µs making 2 calls to Foswiki::CORE:subst, avg 10µs/call # spent 18µs making 2 calls to Foswiki::CORE:regcomp, avg 9µs/call
2860 (<$newtag$params>$val</$newtag>);
2861 }
28621957µs delete( $map->{$placeholder} );
2863 }
2864 }
2865}
2866
2867# Process Foswiki %TAGS{}% by parsing the input tokenised into
2868# % separated sections. The parser is a simple stack-based parse,
2869# sufficient to ensure nesting of tags is correct, but no more
2870# than that.
2871# $depth limits the number of recursive expansion steps that
2872# can be performed on expanded tags.
2873
# spent 183s (94.6ms+183) within Foswiki::_processMacros which was called 2362 times, avg 77.3ms/call: # 2321 times (79.3ms+183s) by Foswiki::innerExpandMacros at line 2739, avg 78.7ms/call # 41 times (15.2ms+-15.2ms) by Foswiki::_processMacros at line 2960, avg 0s/call
sub _processMacros {
287423626.93ms my ( $this, $text, $tagf, $topicObject, $depth ) = @_;
287523623.04ms my $tell = 0;
2876
287723624.95ms return '' if ( ( !defined($text) )
2878 || ( $text eq '' ) );
2879
2880 #no tags to process
2881233227.6ms23324.99ms return $text unless ( $text =~ /%/ );
# spent 4.99ms making 2332 calls to Foswiki::CORE:match, avg 2µs/call
2882
288397125µs unless ($depth) {
2884 my $mess = "Max recursive depth reached: $text";
2885 $this->logger->log( 'warning', $mess );
2886
2887 # prevent recursive expansion that just has been detected
2888 # from happening in the error message
2889 $text =~ s/%(.*?)%/$1/go;
2890 return $text;
2891 }
2892
289397221µs my $verbatim = {};
289497616µs972.10ms $text = takeOutBlocks( $text, 'verbatim', $verbatim );
# spent 2.10ms making 97 calls to Foswiki::takeOutBlocks, avg 22µs/call
2895
289697169µs my $dirtyAreas = {};
289797215µs $text = takeOutBlocks( $text, 'dirtyarea', $dirtyAreas )
2898 if $Foswiki::cfg{Cache}{Enabled};
2899
2900972.48ms my @queue = split( /(%)/, $text );
290197124µs my @stack;
290297172µs my $stackTop = ''; # the top stack entry. Done this way instead of
2903 # referring to the top of the stack for efficiency. This var
2904 # should be considered to be $stack[$#stack]
2905
2906971.17ms while ( scalar(@queue) ) {
2907
2908 #print STDERR "QUEUE:".join("\n ", map { "'$_'" } @queue)."\n";
290923904.43ms my $token = shift(@queue);
2910
2911 #print STDERR ' ' x $tell,"PROCESSING $token \n";
2912
2913 # each % sign either closes an existing stacked context, or
2914 # opens a new context.
291523908.67ms if ( $token eq '%' ) {
2916
2917 #print STDERR ' ' x $tell,"CONSIDER $stackTop\n";
2918 # If this is a closing }%, try to rejoin the previous
2919 # tokens until we get to a valid tag construct. This is
2920 # a bit of a hack, but it's hard to think of a better
2921 # way to do this without a full parse that takes % signs
2922 # in tag parameters into account.
292311657.73ms11652.14ms if ( $stackTop =~ /}$/s ) {
# spent 2.14ms making 1165 calls to Foswiki::CORE:match, avg 2µs/call
29242463.55ms4901.26ms while ( scalar(@stack)
# spent 933µs making 245 calls to Foswiki::CORE:match, avg 4µs/call # spent 327µs making 245 calls to Foswiki::CORE:regcomp, avg 1µs/call
2925 && $stackTop !~ /^%$regex{tagNameRegex}\{.*}$/so )
2926 {
2927611µs my $top = $stackTop;
2928
2929 #print STDERR ' ' x $tell,"COLLAPSE $top \n";
29306101µs1227µs $stackTop = pop(@stack) . $top;
# spent 19µs making 6 calls to Foswiki::CORE:match, avg 3µs/call # spent 8µs making 6 calls to Foswiki::CORE:regcomp, avg 1µs/call
2931 }
2932 }
2933
2934 # /s so you can have newlines in parameters
2935116514.6ms23305.35ms if ( $stackTop =~ m/^%(($regex{tagNameRegex})(?:{(.*)})?)$/so ) {
# spent 3.83ms making 1165 calls to Foswiki::CORE:match, avg 3µs/call # spent 1.52ms making 1165 calls to Foswiki::CORE:regcomp, avg 1µs/call
2936
2937 # SMELL: unchecked implicit untaint?
29385622.20ms my ( $expr, $tag, $args ) = ( $1, $2, $3 );
2939
2940 #print STDERR ' ' x $tell,"POP $tag\n";
2941 #Monitor::MARK("Before $tag");
29425623.30ms562183s my $e = &$tagf( $this, $tag, $args, $topicObject );
# spent 187s making 562 calls to Foswiki::_expandMacroOnTopicRendering, avg 333ms/call, recursion: max depth 2, sum of overlapping time 4.39s
2943
2944 #Monitor::MARK("After $tag");
2945
2946562881µs if ( defined($e) ) {
2947
2948 #print STDERR ' ' x $tell--,"EXPANDED $tag -> $e\n";
29495551.31ms $stackTop = pop(@stack);
2950
2951 # Don't bother recursively expanding unless there are
2952 # unexpanded tags in the result.
29535556.19ms11101.91ms unless ( $e =~ /%$regex{tagNameRegex}(?:{.*})?%/so ) {
# spent 1.11ms making 555 calls to Foswiki::CORE:match, avg 2µs/call # spent 798µs making 555 calls to Foswiki::CORE:regcomp, avg 1µs/call
29545141.29ms $stackTop .= $e;
29555141.21ms next;
2956 }
2957
2958 # Recursively expand tags in the expansion of $tag
2959 $stackTop .=
296041502µs410s $this->_processMacros( $e, $tagf, $topicObject,
# spent 94.5s making 41 calls to Foswiki::_processMacros, avg 2.31s/call, recursion: max depth 4, sum of overlapping time 94.5s
2961 $depth - 1 );
2962 }
2963 else {
2964
2965 #print STDERR ' ' x $tell++,"EXPAND $tag FAILED\n";
2966 # To handle %NOP
2967 # correctly, we have to handle the %VAR% case differently
2968 # to the %VAR{}% case when a variable expansion fails.
2969 # This is so that recursively define variables e.g.
2970 # %A%B%D% expand correctly, but at the same time we ensure
2971 # that a mismatched }% can't accidentally close a context
2972 # that was left open when a tag expansion failed.
2973 # However TWiki didn't do this, so for compatibility
2974 # we have to accept that %NOP can never be fixed. if it
2975 # could, then we could uncomment the following:
2976
2977 #if( $stackTop =~ /}$/ ) {
2978 # # %VAR{...}% case
2979 # # We need to push the unexpanded expression back
2980 # # onto the stack, but we don't want it to match the
2981 # # tag expression again. So we protect the %'s
2982 # $stackTop = "&#37;$expr&#37;";
2983 #} else
2984 #{
2985
2986 # %VAR% case.
2987 # In this case we *do* want to match the tag expression
2988 # again, as an embedded %VAR% may have expanded to
2989 # create a valid outer expression. This is directly
2990 # at odds with the %VAR{...}% case.
2991717µs push( @stack, $stackTop );
2992712µs $stackTop = '%'; # open new context
2993 #}
2994 }
2995 }
2996 else {
29976031.72ms push( @stack, $stackTop );
29986031.03ms $stackTop = '%'; # push a new context
2999 #$tell++;
3000 }
3001 }
3002 else {
300312252.32ms $stackTop .= $token;
3004 }
3005 }
3006
3007 # Run out of input. Gather up everything in the stack.
300897267µs while ( scalar(@stack) ) {
30094995µs my $expr = $stackTop;
30104983µs $stackTop = pop(@stack);
301149235µs $stackTop .= $expr;
3012 }
3013
301497216µs putBackBlocks( \$stackTop, $dirtyAreas, 'dirtyarea' )
3015 if $Foswiki::cfg{Cache}{Enabled};
301697576µs971.19ms putBackBlocks( \$stackTop, $verbatim, 'verbatim' );
# spent 1.19ms making 97 calls to Foswiki::putBackBlocks, avg 12µs/call
3017
3018 #print STDERR "FINAL $stackTop\n";
3019
302097849µs return $stackTop;
3021}
3022
3023# Handle expansion of a tag during topic rendering
3024# $tag is the tag name
3025# $args is the bit in the {} (if there are any)
3026# $topicObject should be passed for dynamic tags (not needed for
3027# session or constant tags
3028
# spent 183s (34.8ms+183) within Foswiki::_expandMacroOnTopicRendering which was called 562 times, avg 325ms/call: # 562 times (34.8ms+183s) by Foswiki::_processMacros at line 2942, avg 325ms/call
sub _expandMacroOnTopicRendering {
30295621.20ms my ( $this, $tag, $args, $topicObject ) = @_;
3030
3031562983µs require Foswiki::Attrs;
3032562701µs my $attrs;
3033
30345623.35ms56234.8ms my $e = $this->{prefs}->getPreference($tag);
# spent 34.8ms making 562 calls to Foswiki::Prefs::getPreference, avg 62µs/call
30355621.84ms314µs if ( defined $e ) {
# spent 14µs making 3 calls to Foswiki::CORE:match, avg 5µs/call
3036196276µs if ( $args && $args =~ /\S/ ) {
3037 $attrs = new Foswiki::Attrs( $args, 0 );
3038 $attrs->{DEFAULT} = $attrs->{_DEFAULT};
3039 $e = $this->_processMacros(
3040 $e,
3041 sub {
3042 my ( $this, $tag, $args, $topicObject ) = @_;
3043 return
3044 defined $attrs->{$tag}
3045 ? expandStandardEscapes( $attrs->{$tag} )
3046 : undef;
3047 },
3048 $topicObject,
3049 1
3050 );
3051 }
3052 }
3053 elsif ( exists( $macros{$tag} ) ) {
3054359606µs unless ( defined( $macros{$tag} ) ) {
3055
3056 # Demand-load the macro module
305717167µs1779µs die $tag unless $tag =~ /([A-Z_:]+)/i;
# spent 79µs making 17 calls to Foswiki::CORE:match, avg 5µs/call
30581739µs $tag = $1;
305917918µs eval "require Foswiki::Macros::$tag";
# spent 256µs executing statements in 2 string evals (merged) # spent 151µs executing statements in string eval # spent 145µs executing statements in string eval # spent 144µs executing statements in string eval # spent 141µs executing statements in string eval # spent 138µs executing statements in string eval # spent 116µs executing statements in string eval # spent 113µs executing statements in string eval # spent 106µs executing statements in string eval # spent 103µs executing statements in string eval # spent 102µs executing statements in string eval # spent 98µs executing statements in string eval # spent 95µs executing statements in string eval # spent 93µs executing statements in string eval # spent 89µs executing statements in string eval # spent 88µs executing statements in string eval
30601723µs die $@ if $@;
306117559µs $macros{$tag} = eval "\\&$tag";
# spent 10µ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 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval
30621730µs die $@ if $@;
3063 }
3064
30653592.87ms35933.2ms $attrs = new Foswiki::Attrs( $args, $contextFreeSyntax{$tag} );
# spent 33.2ms making 359 calls to Foswiki::Attrs::new, avg 92µs/call
30667183.89ms359184s $e = &{ $macros{$tag} }( $this, $attrs, $topicObject );
# spent 176s making 3 calls to Foswiki::Func::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm:573], avg 58.6s/call # spent 9.38s making 20 calls to Foswiki::INCLUDE, avg 469ms/call, recursion: max depth 1, sum of overlapping time 3.03s # spent 1.37s making 3 calls to Foswiki::META, avg 456ms/call # spent 134ms making 75 calls to Foswiki::IF, avg 1.78ms/call # spent 49.6ms making 6 calls to Foswiki::REVINFO, avg 8.27ms/call # spent 30.4ms making 7 calls to Foswiki::FORMFIELD, avg 4.34ms/call # spent 11.1ms making 1 call to Foswiki::QUERY # spent 10.9ms making 52 calls to Foswiki::MAKETEXT, avg 209µs/call # spent 10.1ms making 2 calls to Foswiki::LoginManager::_LOGOUT, avg 5.03ms/call # spent 1.58ms making 27 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:266], avg 59µs/call # spent 1.53ms making 4 calls to Foswiki::WIKIUSERNAME, avg 384µs/call # spent 1.47ms making 9 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:281], avg 163µs/call # spent 1.44ms making 25 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:239], avg 58µs/call # spent 1.16ms making 15 calls to Foswiki::ENCODE, avg 77µs/call # spent 1.16ms making 14 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:268], avg 83µs/call # spent 1.01ms making 5 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:209], avg 202µs/call # spent 825µs making 1 call to Foswiki::FORMAT # spent 751µs making 3 calls to Foswiki::WIKINAME, avg 250µs/call # spent 419µs making 11 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:238], avg 38µs/call # spent 385µs making 4 calls to Foswiki::ADDTOZONE, avg 96µs/call # spent 331µs making 2 calls to Foswiki::URLPARAM, avg 165µs/call # spent 330µs making 1 call to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:277] # spent 308µs making 1 call to Foswiki::USERNAME # spent 236µs making 47 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:365], avg 5µs/call # spent 220µs making 2 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:242], avg 110µs/call # spent 120µs making 1 call to Foswiki::SPACEOUT # spent 88µs making 1 call to Foswiki::ADDTOHEAD # spent 80µs making 2 calls to Foswiki::LoginManager::_LOGIN, avg 40µs/call # spent 77µs making 1 call to Foswiki::REVARG # spent 43µs making 6 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:369], avg 7µs/call # spent 40µs making 2 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:405], avg 20µs/call # spent 35µs making 1 call to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:265] # spent 22µs making 3 calls to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:358], avg 7µs/call # spent 8µs making 1 call to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:363] # spent 7µs making 1 call to Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki.pm:401]
3067 }
3068 elsif ( $args && $args =~ /\S/ ) {
3069318µs3334µs $attrs = new Foswiki::Attrs($args);
# spent 334µs making 3 calls to Foswiki::Attrs::new, avg 111µs/call
307036µs if ( defined $attrs->{default} ) {
3071 $e = expandStandardEscapes( $attrs->{default} );
3072 }
3073 }
30745623.76ms return $e;
3075}
3076
3077# Handle expansion of a tag during new topic creation. When creating a
3078# new topic from a template we only expand a subset of the available legal
3079# tags, and we expand %NOP% differently.
3080sub _expandMacroOnTopicCreation {
3081 my $this = shift;
3082
3083 # my( $tag, $args, $topicObject ) = @_;
3084
3085 # Required for Cairo compatibility. Ignore %NOP{...}%
3086 # %NOP% is *not* ignored until all variable expansion is complete,
3087 # otherwise them inside-out rule would remove it too early e.g.
3088 # %GM%NOP%TIME -> %GMTIME -> 12:00. So we ignore it here and scrape it
3089 # out later. We *have* to remove %NOP{...}% because it can foul up
3090 # brace-matching.
3091 return '' if $_[0] eq 'NOP' && defined $_[1];
3092
3093 # Only expand a subset of legal tags. Warning: $this->{user} may be
3094 # overridden during this call, when a new user topic is being created.
3095 # This is what we want to make sure new user templates are populated
3096 # correctly, but you need to think about this if you extend the set of
3097 # tags expanded here.
3098 return
3099 unless $_[0] =~
3100/^(URLPARAM|DATE|(SERVER|GM)TIME|(USER|WIKI)NAME|WIKIUSERNAME|USERINFO)$/;
3101
3102 return $this->_expandMacroOnTopicRendering(@_);
3103}
3104
3105=begin TML
3106
3107---++ ObjectMethod enterContext( $id, $val )
3108
3109Add the context id $id into the set of active contexts. The $val
3110can be anything you like, but should always evaluate to boolean
3111TRUE.
3112
3113An example of the use of contexts is in the use of tag
3114expansion. The commonTagsHandler in plugins is called every
3115time tags need to be expanded, and the context of that expansion
3116is signalled by the expanding module using a context id. So the
3117forms module adds the context id "form" before invoking common
3118tags expansion.
3119
3120Contexts are not just useful for tag expansion; they are also
3121relevant when rendering.
3122
3123Contexts are intended for use mainly by plugins. Core modules can
3124use $session->inContext( $id ) to determine if a context is active.
3125
3126=cut
3127
3128
# spent 347µs within Foswiki::enterContext which was called 27 times, avg 13µs/call: # 19 times (249µs+0s) by Foswiki::Plugin::registerHandlers at line 278 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Plugin.pm, avg 13µs/call # once (22µs+0s) by Foswiki::UI::View::view at line 368 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm # once (14µs+0s) by Foswiki::UI::View::view at line 388 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm # once (13µs+0s) by Foswiki::UI::View::view at line 394 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm # once (12µs+0s) by Foswiki::Users::HtPasswdUser::readOnly at line 124 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/HtPasswdUser.pm # once (11µs+0s) by Foswiki::LoginManager::userLoggedIn at line 643 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (9µs+0s) by Foswiki::LoginManager::TemplateLogin::new at line 37 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager/TemplateLogin.pm # once (8µs+0s) by Foswiki::Users::new at line 120 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users.pm # once (7µs+0s) by Foswiki::Users::new at line 121 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users.pm
sub enterContext {
31292776µs my ( $this, $id, $val ) = @_;
31302745µs $val ||= 1;
313127268µs $this->{context}->{$id} = $val;
3132}
3133
3134=begin TML
3135
3136---++ ObjectMethod leaveContext( $id )
3137
3138Remove the context id $id from the set of active contexts.
3139(see =enterContext= for more information on contexts)
3140
3141=cut
3142
3143
# spent 81µs within Foswiki::leaveContext which was called 4 times, avg 20µs/call: # once (26µs+0s) by Foswiki::UI::View::view at line 396 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm # once (22µs+0s) by Foswiki::UI::View::view at line 370 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm # once (21µs+0s) by Foswiki::UI::View::view at line 390 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm # once (12µs+0s) by Foswiki::LoginManager::new at line 152 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm
sub leaveContext {
3144414µs my ( $this, $id ) = @_;
3145411µs my $res = $this->{context}->{$id};
3146421µs delete $this->{context}->{$id};
3147444µs return $res;
3148}
3149
3150=begin TML
3151
3152---++ ObjectMethod inContext( $id )
3153
3154Return the value for the given context id
3155(see =enterContext= for more information on contexts)
3156
3157=cut
3158
3159
# spent 2.05ms within Foswiki::inContext which was called 325 times, avg 6µs/call: # 198 times (1.23ms+0s) by Foswiki::getScriptUrl at line 1407, avg 6µs/call # 75 times (447µs+0s) by Foswiki::getPubUrl at line 1496, avg 6µs/call # 33 times (223µs+0s) by Foswiki::If::OP_context::evaluate at line 36 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/If/OP_context.pm, avg 7µs/call # 5 times (39µs+0s) by Foswiki::LoginManager::endRenderingHandler at line 780 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm, avg 8µs/call # 3 times (26µs+0s) by Foswiki::Func::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm:573] at line 564 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 9µs/call # 2 times (16µs+0s) by Foswiki::LoginManager::_LOGOUT at line 1082 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm, avg 8µs/call # 2 times (13µs+0s) by Foswiki::LoginManager::_LOGIN at line 1042 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm, avg 7µs/call # once (13µs+0s) by Foswiki::LoginManager::checkAccess at line 495 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (9µs+0s) by Foswiki::LoginManager::userLoggedIn at line 605 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (8µs+0s) by Foswiki::LoginManager::makeLoginManager at line 121 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (8µs+0s) by Foswiki::LoginManager::makeLoginManager at line 89 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (8µs+0s) by Foswiki::LoginManager::loadSession at line 288 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (7µs+0s) by Foswiki::generateHTTPHeaders at line 918 # once (7µs+0s) by Foswiki::LoginManager::checkAccess at line 497 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm
sub inContext {
3160325560µs my ( $this, $id ) = @_;
31613251.94ms return $this->{context}->{$id};
3162}
3163
3164=begin TML
3165
3166---++ StaticMethod registerTagHandler( $tag, $fnref, $syntax )
3167
3168STATIC Add a tag handler to the function tag handlers.
3169 * =$tag= name of the tag e.g. MYTAG
3170 * =$fnref= Function to execute. Will be passed ($session, \%params, $web, $topic )
3171 * =$syntax= somewhat legacy - 'classic' or 'context-free' (context-free may be removed in future)
3172
3173
3174$syntax parameter:
3175Way back in prehistory, back when the dinosaur still roamed the earth,
3176Crawford tried to extend the tag syntax of macros such that they could be processed
3177by a context-free parser (hence the "context-free")
3178and bring them into line with HTML.
3179This work was banjaxed by one particular tyrranosaur,
3180who felt that the existing syntax was perfect.
3181However by that time Crawford had used it in a couple of places - most notable in the action tracker.
3182
3183The syntax isn't vastly different from what's there; the differences are:
3184 1 Use either type of quote for parameters
3185 2 Optional quotes on parameter values e.g. recurse=on
3186 3 Standardised use of \ for escapes
3187 4 Boolean (valueless) options (i.e. recurse instead of recurse="on"
3188
3189
3190=cut
3191
3192
# spent 355µs within Foswiki::registerTagHandler which was called 36 times, avg 10µs/call: # 26 times (272µs+0s) by Foswiki::Func::registerTagHandler at line 574 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 10µs/call # once (11µs+0s) by Foswiki::LoginManager::new at line 157 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (11µs+0s) by Foswiki::Plugins::new at line 70 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Plugins.pm # once (8µs+0s) by Foswiki::Plugins::new at line 74 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Plugins.pm # once (8µs+0s) by Foswiki::Plugins::new at line 72 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Plugins.pm # once (8µs+0s) by Foswiki::LoginManager::new at line 159 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (8µs+0s) by Foswiki::LoginManager::new at line 158 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (7µs+0s) by Foswiki::LoginManager::new at line 162 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (7µs+0s) by Foswiki::LoginManager::new at line 161 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (7µs+0s) by Foswiki::LoginManager::new at line 160 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm # once (7µs+0s) by Foswiki::LoginManager::new at line 163 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/LoginManager.pm
sub registerTagHandler {
31933684µs my ( $tag, $fnref, $syntax ) = @_;
319436105µs $macros{$tag} = $fnref;
319536253µs if ( $syntax && $syntax eq 'context-free' ) {
3196 $contextFreeSyntax{$tag} = 1;
3197 }
3198}
3199
3200=begin TML
3201
3202---++ ObjectMethod expandMacros( $text, $topicObject ) -> $text
3203
3204Processes %<nop>VARIABLE%, and %<nop>TOC% syntax; also includes
3205'commonTagsHandler' plugin hook.
3206
3207Returns the text of the topic, after file inclusion, variable substitution,
3208table-of-contents generation, and any plugin changes from commonTagsHandler.
3209
3210$topicObject may be undef when, for example, expanding templates, or one-off strings
3211at a time when meta isn't available.
3212
3213DO NOT CALL THIS DIRECTLY; use $topicObject->expandMacros instead.
3214
3215=cut
3216
3217
# spent 183s (149ms+183) within Foswiki::expandMacros which was called 1131 times, avg 162ms/call: # 1131 times (149ms+183s) by Foswiki::Meta::expandMacros at line 3129 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Meta.pm, avg 162ms/call
sub expandMacros {
321811313.29ms my ( $this, $text, $topicObject ) = @_;
3219
322011311.65ms return '' unless defined $text;
3221
3222 # Plugin Hook (for cache Plugins only)
3223113115.0ms3393176ms $this->{plugins}
# spent 160ms making 1131 calls to Foswiki::Plugins::dispatch, avg 142µs/call, recursion: max depth 1, sum of overlapping time 306µs # spent 7.98ms making 1131 calls to Foswiki::Meta::topic, avg 7µs/call # spent 7.87ms making 1131 calls to Foswiki::Meta::web, avg 7µs/call
3224 ->dispatch( 'beforeCommonTagsHandler', $text, $topicObject->topic,
3225 $topicObject->web, $topicObject );
3226
3227 #use a "global var", so included topics can extract and putback
3228 #their verbatim blocks safetly.
322911312.15ms my $verbatim = {};
323011317.14ms113122.3ms $text = takeOutBlocks( $text, 'verbatim', $verbatim );
# spent 22.3ms making 1131 calls to Foswiki::takeOutBlocks, avg 20µs/call
3231
3232 # take out dirty areas
323311311.98ms my $dirtyAreas = {};
323411312.43ms $text = takeOutBlocks( $text, 'dirtyarea', $dirtyAreas )
3235 if $Foswiki::cfg{Cache}{Enabled};
3236
3237 # Require defaults for plugin handlers :-(
323811316.42ms11318.23ms my $webContext = $topicObject->web || $this->{webName};
# spent 8.23ms making 1131 calls to Foswiki::Meta::web, avg 7µs/call
323911315.95ms11317.80ms my $topicContext = $topicObject->topic || $this->{topicName};
# spent 7.80ms making 1131 calls to Foswiki::Meta::topic, avg 7µs/call
3240
324111316.69ms11319.58ms my $memW = $this->{prefs}->getPreference('INCLUDINGWEB');
# spent 9.58ms making 1131 calls to Foswiki::Prefs::getPreference, avg 8µs/call
324211316.12ms11318.67ms my $memT = $this->{prefs}->getPreference('INCLUDINGTOPIC');
# spent 8.67ms making 1131 calls to Foswiki::Prefs::getPreference, avg 8µs/call
324311316.11ms113125.0ms $this->{prefs}->setInternalPreferences(
# spent 25.0ms making 1131 calls to Foswiki::Prefs::setInternalPreferences, avg 22µs/call
3244 INCLUDINGWEB => $webContext,
3245 INCLUDINGTOPIC => $topicContext
3246 );
3247
324811316.69ms1131183s $this->innerExpandMacros( \$text, $topicObject );
# spent 184s making 1131 calls to Foswiki::innerExpandMacros, avg 163ms/call, recursion: max depth 1, sum of overlapping time 1.46s
3249
325011317.02ms113121.2ms $text = takeOutBlocks( $text, 'verbatim', $verbatim );
# spent 21.2ms making 1131 calls to Foswiki::takeOutBlocks, avg 19µs/call
3251
3252 # Plugin Hook
325311316.52ms1131229ms $this->{plugins}
# spent 229ms making 1131 calls to Foswiki::Plugins::dispatch, avg 203µs/call, recursion: max depth 1, sum of overlapping time 450µs
3254 ->dispatch( 'commonTagsHandler', $text, $topicContext, $webContext, 0,
3255 $topicObject );
3256
3257 # process tags again because plugin hook may have added more in
325811316.31ms11314.84ms $this->innerExpandMacros( \$text, $topicObject );
# spent 177ms making 1131 calls to Foswiki::innerExpandMacros, avg 156µs/call, recursion: max depth 1, sum of overlapping time 172ms
3259
326011316.35ms113122.8ms $this->{prefs}->setInternalPreferences(
# spent 22.8ms making 1131 calls to Foswiki::Prefs::setInternalPreferences, avg 20µs/call
3261 INCLUDINGWEB => $memW,
3262 INCLUDINGTOPIC => $memT
3263 );
3264
3265 # 'Special plugin tag' TOC hack, must be done after all other expansions
3266 # are complete, and has to reprocess the entire topic.
3267
326811317.53ms11312.67ms if ( $text =~ /%TOC(?:{.*})?%/ ) {
# spent 2.67ms making 1131 calls to Foswiki::CORE:match, avg 2µs/call
3269 require Foswiki::Macros::TOC;
3270 $text =~ s/%TOC(?:{(.*?)})?%/$this->TOC($text, $topicObject, $1)/ge;
3271 }
3272
3273 # Codev.FormattedSearchWithConditionalOutput: remove <nop> lines,
3274 # possibly introduced by SEARCHes with conditional CALC. This needs
3275 # to be done after CALC and before table rendering in order to join
3276 # table rows properly
327711316.44ms11312.20ms $text =~ s/^<nop>\r?\n//gm;
# spent 2.20ms making 1131 calls to Foswiki::CORE:subst, avg 2µs/call
3278
3279 # restore dirty areas
328011312.21ms putBackBlocks( \$text, $dirtyAreas, 'dirtyarea' )
3281 if $Foswiki::cfg{Cache}{Enabled};
3282
328311316.29ms113112.4ms putBackBlocks( \$text, $verbatim, 'verbatim' );
# spent 12.4ms making 1131 calls to Foswiki::putBackBlocks, avg 11µs/call
3284
3285 # Foswiki Plugin Hook (for cache Plugins only)
328611316.34ms113175.0ms $this->{plugins}
# spent 75.2ms making 1131 calls to Foswiki::Plugins::dispatch, avg 66µs/call, recursion: max depth 1, sum of overlapping time 130µs
3287 ->dispatch( 'afterCommonTagsHandler', $text, $topicContext, $webContext,
3288 $topicObject );
3289
329011319.04ms return $text;
3291}
3292
3293=begin TML
3294
3295---++ ObjectMethod addToZone($zone, $id, $data, $requires)
3296
3297Add =$data= identified as =$id= to =$zone=, which will later be expanded (with
3298renderZone() - implements =%<nop>RENDERZONE%=). =$ids= are unique within
3299the zone that they are added - dependencies between =$ids= in different zones
3300will not be resolved, except for the special case of =head= and =script= zones
3301when ={MergeHeadAndScriptZones}= is enabled.
3302
3303In this case, they are treated as separate zones when adding to them, but as
3304one merged zone when rendering, i.e. a call to render either =head= or =script=
3305zones will actually render both zones in this one call. Both zones are undef'd
3306afterward to avoid double rendering of content from either zone, to support
3307proper behaviour when =head= and =script= are rendered with separate calls even
3308when ={MergeHeadAndScriptZones}= is set. See ZoneTests/explicit_RENDERZONE*.
3309
3310This behaviour allows an addToZone('head') call to require an id that has been
3311added to =script= only.
3312
3313 * =$zone= - name of the zone
3314 * =$id= - unique identifier
3315 * =$data= - content
3316 * =$requires= - optional, comma-separated string of =$id= identifiers
3317 that should precede the content
3318
3319<blockquote class="foswikiHelp">%X%
3320*Note:* Read the developer supplement at Foswiki:Development.AddToZoneFromPluginHandlers if you
3321are calling =addToZone()= from a rendering or macro/tag-related plugin handler
3322</blockquote>
3323
3324Implements =%<nop>ADDTOZONE%=.
3325
3326=cut
3327
3328
# spent 1.15ms within Foswiki::addToZone which was called 21 times, avg 55µs/call: # 14 times (754µs+0s) by Foswiki::Func::addToZone at line 2596 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 54µs/call # 4 times (218µs+0s) by Foswiki::ADDTOZONE at line 38 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/ADDTOZONE.pm, avg 54µs/call # once (62µs+0s) by Foswiki::writeCompletePage at line 771 # once (61µs+0s) by Foswiki::ADDTOHEAD at line 29 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/ADDTOHEAD.pm # once (51µs+0s) by Foswiki::Func::addToHEAD at line 3574 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm
sub addToZone {
33292181µs my ( $this, $zone, $id, $data, $requires ) = @_;
3330
33312129µs $requires ||= '';
3332
3333 # get a random one
33342127µs unless ($id) {
3335 $id = int( rand(10000) ) + 1;
3336 }
3337
3338 # get zone, or create record
33392154µs my $thisZone = $this->{_zones}{$zone};
33402131µs unless ( defined $thisZone ) {
334128µs $this->{_zones}{$zone} = $thisZone = {};
3342 }
3343
33442133µs my @requires;
334521155µs foreach my $req ( split( /\s*,\s*/, $requires ) ) {
33463462µs unless ( $thisZone->{$req} ) {
3347424µs $thisZone->{$req} = {
3348 id => $req,
3349 zone => $zone,
3350 requires => [],
3351 missingrequires => [],
3352 text => '',
3353 populated => 0
3354 };
3355 }
335634119µs push( @requires, $thisZone->{$req} );
3357 }
3358
3359 # store record within zone
33602138µs my $zoneID = $thisZone->{$id};
33612149µs unless ($zoneID) {
33621860µs $zoneID = { id => $id };
33631855µs $thisZone->{$id} = $zoneID;
3364 }
3365
3366 # override previous properties
33672142µs $zoneID->{zone} = $zone;
33682144µs $zoneID->{requires} = \@requires;
33692142µs $zoneID->{missingrequires} = [];
33702146µs $zoneID->{text} = $data;
33712133µs $zoneID->{populated} = 1;
3372
337321142µs return;
3374}
3375
3376sub _renderZoneById {
3377 my $this = shift;
3378 my $id = shift;
3379
3380 return '' unless defined $id;
3381
3382 my $renderZone = $this->{_renderZonePlaceholder}{$id};
3383
3384 return '' unless defined $renderZone;
3385
3386 my $params = $renderZone->{params};
3387 my $topicObject = $renderZone->{topicObject};
3388 my $zone = $params->{_DEFAULT} || $params->{zone};
3389
3390 return _renderZone( $this, $zone, $params, $topicObject );
3391}
3392
3393# This private function is used in ZoneTests
3394
# spent 59.0ms (1.49+57.5) within Foswiki::_renderZone which was called 2 times, avg 29.5ms/call: # once (800µs+45.2ms) by Foswiki::_renderZones at line 3562 # once (693µs+12.3ms) by Foswiki::_renderZones at line 3567
sub _renderZone {
339527µs my ( $this, $zone, $params, $topicObject ) = @_;
3396
3397 # Check the zone is defined and has not already been rendered
339827µs return '' unless $zone && $this->{_zones}{$zone};
3399
340026µs $params->{header} ||= '';
340124µs $params->{footer} ||= '';
340223µs $params->{chomp} ||= 'off';
340324µs $params->{missingformat} = '$id: requires= missing ids: $missingids';
340427µs $params->{format} = '$item<!--<literal>$missing</literal>-->'
3405 unless defined $params->{format};
340625µs $params->{separator} = '$n()' unless defined $params->{separator};
3407
340826µs unless ( defined $topicObject ) {
3409220µs2122µs $topicObject =
# spent 122µs making 2 calls to Foswiki::Meta::new, avg 61µs/call
3410 Foswiki::Meta->new( $this, $this->{webName}, $this->{topicName} );
3411 }
3412
3413 # Loop through the vertices of the graph, in any order, initiating
3414 # a depth-first search for any vertex that has not already been
3415 # visited by a previous search. The desired topological sorting is
3416 # the reverse postorder of these searches. That is, we can construct
3417 # the ordering as a list of vertices, by adding each vertex to the
3418 # start of the list at the time when the depth-first search is
3419 # processing that vertex and has returned from processing all children
3420 # of that vertex. Since each edge and vertex is visited once, the
3421 # algorithm runs in linear time.
342223µs my %visited;
342323µs my @total;
3424
3425 # When {MergeHeadAndScriptZones} is set, try to treat head and script
3426 # zones as merged for compatibility with ADDTOHEAD usage where requirements
3427 # have been moved to the script zone. See ZoneTests/Item9317
3428238µs if ( $Foswiki::cfg{MergeHeadAndScriptZones}
3429 and ( ( $zone eq 'head' ) or ( $zone eq 'script' ) ) )
3430 {
3431 my @zoneIDs = (
3432 values %{ $this->{_zones}{head} },
3433 values %{ $this->{_zones}{script} }
3434 );
3435
3436 foreach my $zoneID (@zoneIDs) {
3437 $this->_visitZoneID( $zoneID, \%visited, \@total );
3438 }
3439 undef $this->{_zones}{head};
3440 undef $this->{_zones}{script};
3441 }
3442 else {
3443433µs my @zoneIDs = values %{ $this->{_zones}{$zone} };
3444
344527µs foreach my $zoneID (@zoneIDs) {
344622156µs221.17ms $this->_visitZoneID( $zoneID, \%visited, \@total );
# spent 1.17ms making 22 calls to Foswiki::_visitZoneID, avg 53µs/call
3447 }
3448
3449 # kill a zone once it has been rendered, to prevent it being
3450 # added twice (e.g. by duplicate %RENDERZONEs or by automatic
3451 # zone expansion in the head or script)
345226µs undef $this->{_zones}{$zone};
3453 }
3454
3455 # nothing rendered for a zone with no ADDTOZONE calls
345624µs return '' unless scalar(@total) > 0;
3457
345824µs my @result = ();
345925µs my $missingformat = $params->{missingformat};
3460213µs foreach my $item (@total) {
34612249µs my $text = $item->{text};
346244102µs my @missingids = @{ $item->{missingrequires} };
34632235µs my $missingformat =
3464 ( scalar(@missingids) ) ? $params->{missingformat} : '';
3465
34662258µs if ( $params->{'chomp'} ) {
346722145µs2249µs $text =~ s/^\s+//g;
# spent 49µs making 22 calls to Foswiki::CORE:subst, avg 2µs/call
346822199µs22107µs $text =~ s/\s+$//g;
# spent 107µs making 22 calls to Foswiki::CORE:subst, avg 5µs/call
3469 }
3470
3471 # ASSERT($text, "No content for zone id $item->{id} in zone $zone")
3472 # if DEBUG;
3473
34742229µs next unless $text;
34751732µs my $id = $item->{id} || '';
34761725µs my $line = $params->{format};
34771747µs if ( scalar(@missingids) ) {
3478 $line =~ s/\$missing\b/$missingformat/g;
3479 $line =~ s/\$missingids\b/join(', ', @missingids)/ge;
3480 }
3481 else {
348217160µs1780µs $line =~ s/\$missing\b/\$id/g;
# spent 80µs making 17 calls to Foswiki::CORE:subst, avg 5µs/call
3483 }
348417151µs1776µs $line =~ s/\$item\b/$text/g;
# spent 76µs making 17 calls to Foswiki::CORE:subst, avg 4µs/call
348517152µs1779µs $line =~ s/\$id\b/$id/g;
# spent 79µs making 17 calls to Foswiki::CORE:subst, avg 5µs/call
348617101µs1731µs $line =~ s/\$zone\b/$item->{zone}/g;
# spent 31µs making 17 calls to Foswiki::CORE:subst, avg 2µs/call
34871770µs push @result, $line if $line;
3488 }
3489227µs2226µs my $result =
# spent 226µs making 2 calls to Foswiki::expandStandardEscapes, avg 113µs/call
3490 expandStandardEscapes( $params->{header}
3491 . join( $params->{separator}, @result )
3492 . $params->{footer} );
3493
3494 # delay rendering the zone until now
3495214µs232.2ms $result = $topicObject->expandMacros($result);
# spent 32.2ms making 2 calls to Foswiki::Meta::expandMacros, avg 16.1ms/call
3496214µs223.3ms $result = $topicObject->renderTML($result);
# spent 23.3ms making 2 calls to Foswiki::Meta::renderTML, avg 11.6ms/call
3497
34982134µs return $result;
3499}
3500
3501
# spent 1.17ms (1.17+-0ns) within Foswiki::_visitZoneID which was called 56 times, avg 21µs/call: # 34 times (488µs+-488µs) by Foswiki::_visitZoneID at line 3534, avg 0s/call # 22 times (683µs+487µs) by Foswiki::_renderZone at line 3446, avg 53µs/call
sub _visitZoneID {
35025694µs my ( $this, $zoneID, $visited, $list ) = @_;
3503
350456236µs return if $visited->{$zoneID};
3505
35062261µs $visited->{$zoneID} = 1;
3507
350844143µs foreach my $requiredZoneID ( @{ $zoneID->{requires} } ) {
35093442µs my $zoneIDToVisit;
3510
35113480µs if ( $Foswiki::cfg{MergeHeadAndScriptZones}
3512 and not $requiredZoneID->{populated} )
3513 {
3514
3515 # Compatibility mode, where we are trying to treat head and script
3516 # zones as merged, and a required ZoneID isn't populated. Try
3517 # opposite zone to see if it exists there instead. Item9317
3518 if ( $requiredZoneID->{zone} eq 'head' ) {
3519 $zoneIDToVisit =
3520 $this->{_zones}{script}{ $requiredZoneID->{id} };
3521 }
3522 else {
3523 $zoneIDToVisit = $this->{_zones}{head}{ $requiredZoneID->{id} };
3524 }
3525 if ( not $zoneIDToVisit->{populated} ) {
3526
3527 # Oops, the required ZoneID doesn't exist there either; reset
3528 $zoneIDToVisit = $requiredZoneID;
3529 }
3530 }
3531 else {
35323446µs $zoneIDToVisit = $requiredZoneID;
3533 }
353434166µs340s $this->_visitZoneID( $zoneIDToVisit, $visited, $list );
# spent 661µs making 34 calls to Foswiki::_visitZoneID, avg 19µs/call, recursion: max depth 3, sum of overlapping time 661µs
3535
353634112µs if ( not $zoneIDToVisit->{populated} ) {
3537
3538 # Finally, we got to here and the required ZoneID just cannot be
3539 # found in either head or script (or other) zones, so record it for
3540 # diagnostic purposes ($missingids format token)
354128µs push( @{ $zoneID->{missingrequires} }, $zoneIDToVisit->{id} );
3542 }
3543 }
35444494µs push( @{$list}, $zoneID );
3545
354622103µs return;
3547}
3548
3549# This private function is used in ZoneTests
3550
# spent 59.3ms (140µs+59.1) within Foswiki::_renderZones which was called: # once (140µs+59.1ms) by Foswiki::writeCompletePage at line 787
sub _renderZones {
3551120µs my ( $this, $text ) = @_;
3552
3553 # Render zones that were pulled out by Foswiki/Macros/RENDERZONE.pm
3554 # NOTE: once a zone has been rendered it is cleared, so cannot
3555 # be rendered again.
3556
3557146µs230µs $text =~ s/${RENDERZONE_MARKER}RENDERZONE{(.*?)}${RENDERZONE_MARKER}/
# spent 18µs making 1 call to Foswiki::CORE:regcomp # spent 12µs making 1 call to Foswiki::CORE:subst
3558 _renderZoneById($this, $1)/geo;
3559
3560 # get the head zone and insert it at the end of the </head>
3561 # *if it has not already been rendered*
3562118µs146.0ms my $headZone = _renderZone( $this, 'head', { chomp => "on" } );
# spent 46.0ms making 1 call to Foswiki::_renderZone
35631105µs382µs $text =~ s!(</head>)!$headZone\n$1!i if $headZone;
# spent 49µs making 1 call to Foswiki::CORE:subst # spent 33µs making 2 calls to Foswiki::CORE:substcont, avg 16µs/call
3564
3565 # SMELL: Item9480 - can't trust that _renderzone(head) above has truly
3566 # flushed both script and head zones empty when {MergeHeadAndScriptZones} = 1.
3567111µs113.0ms my $scriptZone = _renderZone( $this, 'script', { chomp => "on" } );
# spent 13.0ms making 1 call to Foswiki::_renderZone
3568192µs374µs $text =~ s!(</head>)!$scriptZone\n$1!i if $scriptZone;
# spent 45µs making 1 call to Foswiki::CORE:subst # spent 28µs making 2 calls to Foswiki::CORE:substcont, avg 14µs/call
3569
357013µs chomp($text);
3571
3572129µs return $text;
3573}
3574
3575=begin TML
3576
3577---++ StaticMethod readFile( $filename ) -> $text
3578
3579Returns the entire contents of the given file, which can be specified in any
3580format acceptable to the Perl open() function. Fast, but inherently unsafe.
3581
3582WARNING: Never, ever use this for accessing topics or attachments! Use the
3583Store API for that. This is for global control files only, and should be
3584used *only* if there is *absolutely no alternative*.
3585
3586=cut
3587
3588sub readFile {
3589 my $name = shift;
3590 my $IN_FILE;
3591 open( $IN_FILE, "<$name" ) || return '';
3592 local $/ = undef;
3593 my $data = <$IN_FILE>;
3594 close($IN_FILE);
3595 $data = '' unless ( defined($data) );
3596 return $data;
3597}
3598
3599=begin TML
3600
3601---++ StaticMethod expandStandardEscapes($str) -> $unescapedStr
3602
3603Expands standard escapes used in parameter values to block evaluation. See
3604System.FormatTokens for a full list of supported tokens.
3605
3606=cut
3607
3608
# spent 6.68ms (4.91+1.77) within Foswiki::expandStandardEscapes which was called 95 times, avg 70µs/call: # 61 times (3.19ms+1.03ms) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/IF.pm:43] at line 41 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/IF.pm, avg 69µs/call # 14 times (687µs+313µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/IF.pm:43] at line 37 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/IF.pm, avg 71µs/call # 8 times (414µs+143µs) by Foswiki::USERINFO at line 112 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/USERINFO.pm, avg 70µs/call # 7 times (362µs+138µs) by Foswiki::Render::renderFORMFIELD at line 1073 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 71µs/call # 2 times (113µs+113µs) by Foswiki::_renderZone at line 3489, avg 113µs/call # once (50µs+14µs) by Foswiki::META at line 41 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/META.pm # once (48µs+14µs) by Foswiki::FORMAT at line 21 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMAT.pm # once (47µs+14µs) by Foswiki::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMAT.pm:65] at line 64 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Macros/FORMAT.pm
sub expandStandardEscapes {
360995165µs my $text = shift;
3610
3611 # expand '$n()' and $n! to new line
361295743µs95225µs $text =~ s/\$n\(\)/\n/gs;
# spent 225µs making 95 calls to Foswiki::CORE:subst, avg 2µs/call
3613951.05ms190318µs $text =~ s/\$n(?=[^$regex{mixedAlpha}]|$)/\n/gos;
# spent 175µs making 95 calls to Foswiki::CORE:subst, avg 2µs/call # spent 143µs making 95 calls to Foswiki::CORE:regcomp, avg 2µs/call
3614
3615 # filler, useful for nested search
361695505µs95140µs $text =~ s/\$nop(\(\))?//gs;
# spent 140µs making 95 calls to Foswiki::CORE:subst, avg 1µs/call
3617
3618 # $quot -> "
361995563µs95195µs $text =~ s/\$quot(\(\))?/\"/gs;
# spent 195µs making 95 calls to Foswiki::CORE:subst, avg 2µs/call
3620
3621 # $comma -> ,
362295516µs95136µs $text =~ s/\$comma(\(\))?/,/gs;
# spent 136µs making 95 calls to Foswiki::CORE:subst, avg 1µs/call
3623
3624 # $percent -> %
362595583µs95207µs $text =~ s/\$perce?nt(\(\))?/\%/gs;
# spent 207µs making 95 calls to Foswiki::CORE:subst, avg 2µs/call
3626
3627 # $lt -> <
362895509µs95145µs $text =~ s/\$lt(\(\))?/\</gs;
# spent 145µs making 95 calls to Foswiki::CORE:subst, avg 2µs/call
3629
3630 # $gt -> >
363195495µs95140µs $text =~ s/\$gt(\(\))?/\>/gs;
# spent 140µs making 95 calls to Foswiki::CORE:subst, avg 1µs/call
3632
3633 # $amp -> &
363495488µs95134µs $text =~ s/\$amp(\(\))?/\&/gs;
# spent 134µs making 95 calls to Foswiki::CORE:subst, avg 1µs/call
3635
3636 # $dollar -> $, done last to avoid creating the above tokens
363795488µs95135µs $text =~ s/\$dollar(\(\))?/\$/gs;
# spent 135µs making 95 calls to Foswiki::CORE:subst, avg 1µs/call
3638
363995627µs return $text;
3640}
3641
3642=begin TML
3643
3644---++ ObjectMethod webExists( $web ) -> $boolean
3645
3646Test if web exists
3647 * =$web= - Web name, required, e.g. ='Sandbox'=
3648
3649A web _has_ to have a preferences topic to be a web.
3650
3651=cut
3652
3653
# spent 420µs (66+355) within Foswiki::webExists which was called 2 times, avg 210µs/call: # once (39µs+183µs) by Foswiki::UI::checkWebExists at line 477 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI.pm # once (27µs+171µs) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:228] at line 214 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm
sub webExists {
365426µs my ( $this, $web ) = @_;
3655
365629µs26µs ASSERT( UNTAINTED($web), 'web is tainted' ) if DEBUG;
# spent 6µs making 2 calls to Assert::ASSERTS_OFF, avg 3µs/call
3657252µs2348µs return $this->{store}->webExists($web);
# spent 348µs making 2 calls to Foswiki::Store::VC::Store::webExists, avg 174µs/call
3658}
3659
3660=begin TML
3661
3662---++ ObjectMethod topicExists( $web, $topic ) -> $boolean
3663
3664Test if topic exists
3665 * =$web= - Web name, optional, e.g. ='Main'=
3666 * =$topic= - Topic name, required, e.g. ='TokyoOffice'=, or ="Main.TokyoOffice"=
3667
3668=cut
3669
3670
# spent 24.9ms (3.64+21.2) within Foswiki::topicExists which was called 155 times, avg 160µs/call: # 72 times (1.60ms+9.87ms) by Foswiki::Render::_renderWikiWord at line 603 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm, avg 159µs/call # 70 times (1.67ms+9.31ms) by Foswiki::Templates::_readTemplateFile at line 502 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Templates.pm, avg 157µs/call # 6 times (175µs+971µs) by Foswiki::If::OP_istopic::evaluate at line 34 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/If/OP_istopic.pm, avg 191µs/call # 2 times (56µs+366µs) by Foswiki::Func::topicExists at line 1502 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Func.pm, avg 211µs/call # 2 times (70µs+287µs) by Foswiki::Users::TopicUserMapping::eachGroupMember at line 644 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Users/TopicUserMapping.pm, avg 179µs/call # once (26µs+175µs) by Foswiki::Form::new at line 97 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Form.pm # once (22µs+141µs) by Foswiki::Render::_renderWikiWord at line 612 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Render.pm # once (28µs+106µs) by Foswiki::UI::View::view at line 111 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/UI/View.pm
sub topicExists {
3671155306µs my ( $this, $web, $topic ) = @_;
3672155679µs155510µs ASSERT( UNTAINTED($web), 'web is tainted' ) if DEBUG;
# spent 510µs making 155 calls to Assert::ASSERTS_OFF, avg 3µs/call
3673155666µs155481µs ASSERT( UNTAINTED($topic), 'topic is tainted' ) if DEBUG;
# spent 481µs making 155 calls to Assert::ASSERTS_OFF, avg 3µs/call
36741551.43ms15520.2ms return $this->{store}->topicExists( $web, $topic );
# spent 20.2ms making 155 calls to Foswiki::Store::VC::Store::topicExists, avg 131µs/call
3675}
3676
3677=begin TML
3678
3679---+++ ObjectMethod getWorkArea( $key ) -> $directorypath
3680
3681Gets a private directory uniquely identified by $key. The directory is
3682intended as a work area for plugins etc. The directory will exist.
3683
3684=cut
3685
3686sub getWorkArea {
3687 my ( $this, $key ) = @_;
3688 return $this->{store}->getWorkArea($key);
3689}
3690
3691=begin TML
3692
3693---++ ObjectMethod getApproxRevTime ( $web, $topic ) -> $epochSecs
3694
3695Get an approximate rev time for the latest rev of the topic. This method
3696is used to optimise searching. Needs to be as fast as possible.
3697
3698SMELL: is there a reason this is in Foswiki.pm, and not in Search?
3699
3700=cut
3701
3702sub getApproxRevTime {
3703 my ( $this, $web, $topic ) = @_;
3704
3705 my $metacache = $this->search->metacache;
3706 if ( $metacache->hasCached( $web, $topic ) ) {
3707
3708 #don't kill me - this should become a property on Meta
3709 return $metacache->get( $web, $topic )->{modified};
3710 }
3711
3712 return $this->{store}->getApproxRevTime( $web, $topic );
3713}
3714
3715113µs1;
3716__END__