← Index
NYTProf Performance Profile   « line view »
For ./view
  Run on Fri Jul 31 18:42:36 2015
Reported on Fri Jul 31 18:48:13 2015

Filename/var/www/foswikidev/core/lib/Foswiki.pm
StatementsExecuted 1001070 statements in 1.30s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
990881311658ms658msFoswiki::::normalizeWebTopicNameFoswiki::normalizeWebTopicName
526036594.3ms101msFoswiki::::searchFoswiki::search
2712119.6ms137sFoswiki::::_processMacrosFoswiki::_processMacros (recurses: max depth 5, inclusive time 186ms)
5372116.9ms137sFoswiki::::_expandMacroOnTopicRenderingFoswiki::_expandMacroOnTopicRendering (recurses: max depth 3, inclusive time 151ms)
11111.5ms13.4msFoswiki::::BEGIN@642Foswiki::BEGIN@642
11110.2ms15.1msFoswiki::::BEGIN@51Foswiki::BEGIN@51
100118.76ms137sFoswiki::::expandMacrosFoswiki::expandMacros (recurses: max depth 2, inclusive time 62.2ms)
14337.85ms9.03msFoswiki::::rendererFoswiki::renderer
310736.55ms6.55msFoswiki::::takeOutBlocksFoswiki::takeOutBlocks
14793995.93ms5.93msFoswiki::::isTrueFoswiki::isTrue
238635.22ms137sFoswiki::::innerExpandMacrosFoswiki::innerExpandMacros (recurses: max depth 3, inclusive time 171ms)
1114.94ms23.4msFoswiki::::writeCompletePageFoswiki::writeCompletePage
1114.49ms11.4msFoswiki::::BEGIN@48Foswiki::BEGIN@48
1113.97ms55.0msFoswiki::::BEGIN@53Foswiki::BEGIN@53
1751043.22ms3.45msFoswiki::::templatesFoswiki::templates
1112.79ms3.13msFoswiki::::BEGIN@50Foswiki::BEGIN@50
1112.75ms13.1msFoswiki::::BEGIN@647Foswiki::BEGIN@647
1112.68ms2.78msFoswiki::::attachFoswiki::attach
1112.34ms12.2msFoswiki::::BEGIN@643Foswiki::BEGIN@643
1112.17ms6.33msFoswiki::::BEGIN@646Foswiki::BEGIN@646
1112.07ms3.57msFoswiki::::BEGIN@644Foswiki::BEGIN@644
1111.83ms4.47msFoswiki::::loggerFoswiki::logger
1111.79ms4.30msFoswiki::::BEGIN@645Foswiki::BEGIN@645
50321.61ms6.54msFoswiki::::getSkinFoswiki::getSkin
60331.59ms2.34msFoswiki::::i18nFoswiki::i18n
1111.52ms2.46msFoswiki::::BEGIN@208Foswiki::BEGIN@208
1111.43ms11.5msFoswiki::::finishFoswiki::finish
210631.18ms1.18msFoswiki::::putBackBlocksFoswiki::putBackBlocks
504211.12ms8.48msFoswiki::::accessFoswiki::access
1111.00ms1.35msFoswiki::::BEGIN@52Foswiki::BEGIN@52
10076964µs964µsFoswiki::::expandStandardEscapesFoswiki::expandStandardEscapes
111947µs1.03msFoswiki::::BEGIN@641Foswiki::BEGIN@641
10611895µs958µsFoswiki::::isValidWebNameFoswiki::isValidWebName
4122788µs788µsFoswiki::::addToZoneFoswiki::addToZone
5465757µs1.43msFoswiki::::getScriptUrlFoswiki::getScriptUrl
431756µs18.0msFoswiki::::_renderZoneFoswiki::_renderZone
1561010754µs11.1msFoswiki::::topicExistsFoswiki::topicExists
111651µs3.01msFoswiki::::BEGIN@46Foswiki::BEGIN@46
111500µs940µsFoswiki::::spaceOutWikiWordFoswiki::spaceOutWikiWord
5933476µs940µsFoswiki::::getPubURLFoswiki::getPubURL
10133442µs7.35msFoswiki::::webExistsFoswiki::webExists
1722422µs1.00msFoswiki::::isValidTopicNameFoswiki::isValidTopicName
8921383µs383µsFoswiki::::_visitZoneIDFoswiki::_visitZoneID (recurses: max depth 3, inclusive time 243µs)
111360µs36.6msFoswiki::::BEGIN@176Foswiki::BEGIN@176
7273273µs544µsFoswiki::::urlEncodeFoswiki::urlEncode
135135257µs257µsFoswiki::::inContextFoswiki::inContext
24031244µs244µsFoswiki::::SINGLE_SINGLETONSFoswiki::SINGLE_SINGLETONS
411240µs34.1msFoswiki::::inlineAlertFoswiki::inlineAlert
111231µs251msFoswiki::::newFoswiki::new
211230µs37.7msFoswiki::::deepWebListFoswiki::deepWebList
111225µs17.6msFoswiki::::load_packageFoswiki::load_package
5411201µs282µsFoswiki::::make_paramsFoswiki::make_params
62134154µs154µsFoswiki::::registerTagHandlerFoswiki::registerTagHandler
4985140µs140µsFoswiki::::enterContextFoswiki::enterContext
111128µs18.2msFoswiki::::_renderZonesFoswiki::_renderZones
811103µs103µsFoswiki::::parseSectionsFoswiki::parseSections
631196µs96µsFoswiki::::__ANON__[:401]Foswiki::__ANON__[:401]
11163µs390µsFoswiki::::_parsePathFoswiki::_parsePath
106456µs83µsFoswiki::::getLoginManagerFoswiki::getLoginManager
61144µs185µsFoswiki::::__ANON__[:247]Foswiki::__ANON__[:247]
11137µs141µsFoswiki::::generateHTTPHeadersFoswiki::generateHTTPHeaders
44228µs28µsFoswiki::::leaveContextFoswiki::leaveContext
11124µs49µsFoswiki::::BEGIN@44Foswiki::BEGIN@44
21122µs18.0msFoswiki::::_renderZoneByIdFoswiki::_renderZoneById
101121µs21µsFoswiki::::__ANON__[:405]Foswiki::__ANON__[:405]
21118µs145µsFoswiki::::__ANON__[:323]Foswiki::__ANON__[:323]
11116µs24µsFoswiki::::BEGIN@45Foswiki::BEGIN@45
11115µs39µsFoswiki::::BEGIN@47Foswiki::BEGIN@47
11115µs15µsFoswiki::::BEGIN@55Foswiki::BEGIN@55
51114µs14µsFoswiki::::__ANON__[:394]Foswiki::__ANON__[:394]
11113µs13µsFoswiki::::_getLibDirFoswiki::_getLibDir
11112µs106µsFoswiki::::__ANON__[:289]Foswiki::__ANON__[:289]
21111µs37µsFoswiki::::getCGISessionFoswiki::getCGISession
11111µs61µsFoswiki::::getWorkAreaFoswiki::getWorkArea
11111µs11µsFoswiki::::setCacheControlFoswiki::setCacheControl
11110µs24µsFoswiki::::BEGIN@2114Foswiki::BEGIN@2114
1119µs19µsFoswiki::::BEGIN@2116Foswiki::BEGIN@2116
1118µs13µsFoswiki::::__ANON__[:312]Foswiki::__ANON__[:312]
2118µs8µsFoswiki::::__ANON__[:344]Foswiki::__ANON__[:344]
2118µs8µsFoswiki::::__ANON__[:347]Foswiki::__ANON__[:347]
1117µs69µsFoswiki::::urlDecodeFoswiki::urlDecode
1117µs7µsFoswiki::::BEGIN@49Foswiki::BEGIN@49
2215µs5µsFoswiki::::SINGLE_SINGLETONS_TRACEFoswiki::SINGLE_SINGLETONS_TRACE
1115µs5µsFoswiki::::__ANON__[:409]Foswiki::__ANON__[:409]
1115µs5µsFoswiki::::satisfiedByCacheFoswiki::satisfiedByCache
1114µs4µsFoswiki::::BEGIN@639Foswiki::BEGIN@639
1114µs4µsFoswiki::::__ANON__[:243]Foswiki::__ANON__[:243]
1114µs4µsFoswiki::::__ANON__[:450]Foswiki::__ANON__[:450]
1114µs4µsFoswiki::::__ANON__[:399]Foswiki::__ANON__[:399]
1113µs3µsFoswiki::::BEGIN@640Foswiki::BEGIN@640
0000s0sFoswiki::::__ANON__[:191]Foswiki::__ANON__[:191]
0000s0sFoswiki::::__ANON__[:221]Foswiki::__ANON__[:221]
0000s0sFoswiki::::__ANON__[:230]Foswiki::__ANON__[:230]
0000s0sFoswiki::::__ANON__[:237]Foswiki::__ANON__[:237]
0000s0sFoswiki::::__ANON__[:253]Foswiki::__ANON__[:253]
0000s0sFoswiki::::__ANON__[:262]Foswiki::__ANON__[:262]
0000s0sFoswiki::::__ANON__[:274]Foswiki::__ANON__[:274]
0000s0sFoswiki::::__ANON__[:277]Foswiki::__ANON__[:277]
0000s0sFoswiki::::__ANON__[:295]Foswiki::__ANON__[:295]
0000s0sFoswiki::::__ANON__[:303]Foswiki::__ANON__[:303]
0000s0sFoswiki::::__ANON__[:307]Foswiki::__ANON__[:307]
0000s0sFoswiki::::__ANON__[:319]Foswiki::__ANON__[:319]
0000s0sFoswiki::::__ANON__[:329]Foswiki::__ANON__[:329]
0000s0sFoswiki::::__ANON__[:3416]Foswiki::__ANON__[:3416]
0000s0sFoswiki::::__ANON__[:343]Foswiki::__ANON__[:343]
0000s0sFoswiki::::__ANON__[:345]Foswiki::__ANON__[:345]
0000s0sFoswiki::::__ANON__[:346]Foswiki::__ANON__[:346]
0000s0sFoswiki::::__ANON__[:348]Foswiki::__ANON__[:348]
0000s0sFoswiki::::__ANON__[:349]Foswiki::__ANON__[:349]
0000s0sFoswiki::::__ANON__[:350]Foswiki::__ANON__[:350]
0000s0sFoswiki::::__ANON__[:391]Foswiki::__ANON__[:391]
0000s0sFoswiki::::__ANON__[:392]Foswiki::__ANON__[:392]
0000s0sFoswiki::::__ANON__[:393]Foswiki::__ANON__[:393]
0000s0sFoswiki::::__ANON__[:395]Foswiki::__ANON__[:395]
0000s0sFoswiki::::__ANON__[:397]Foswiki::__ANON__[:397]
0000s0sFoswiki::::__ANON__[:398]Foswiki::__ANON__[:398]
0000s0sFoswiki::::__ANON__[:400]Foswiki::__ANON__[:400]
0000s0sFoswiki::::__ANON__[:402]Foswiki::__ANON__[:402]
0000s0sFoswiki::::__ANON__[:403]Foswiki::__ANON__[:403]
0000s0sFoswiki::::__ANON__[:404]Foswiki::__ANON__[:404]
0000s0sFoswiki::::__ANON__[:406]Foswiki::__ANON__[:406]
0000s0sFoswiki::::__ANON__[:407]Foswiki::__ANON__[:407]
0000s0sFoswiki::::__ANON__[:408]Foswiki::__ANON__[:408]
0000s0sFoswiki::::__ANON__[:410]Foswiki::__ANON__[:410]
0000s0sFoswiki::::__ANON__[:437]Foswiki::__ANON__[:437]
0000s0sFoswiki::::_expandMacroOnTopicCreationFoswiki::_expandMacroOnTopicCreation
0000s0sFoswiki::::_gzipAcceptedFoswiki::_gzipAccepted
0000s0sFoswiki::::_isRedirectSafeFoswiki::_isRedirectSafe
0000s0sFoswiki::::cacheQueryFoswiki::cacheQuery
0000s0sFoswiki::::entityDecodeFoswiki::entityDecode
0000s0sFoswiki::::entityEncodeFoswiki::entityEncode
0000s0sFoswiki::::expandMacrosOnTopicCreationFoswiki::expandMacrosOnTopicCreation
0000s0sFoswiki::::getApproxRevTimeFoswiki::getApproxRevTime
0000s0sFoswiki::::isValidEmailAddressFoswiki::isValidEmailAddress
0000s0sFoswiki::::isValidWikiWordFoswiki::isValidWikiWord
0000s0sFoswiki::::logEventFoswiki::logEvent
0000s0sFoswiki::::netFoswiki::net
0000s0sFoswiki::::readFileFoswiki::readFile
0000s0sFoswiki::::redirectFoswiki::redirect
0000s0sFoswiki::::redirecttoFoswiki::redirectto
0000s0sFoswiki::::reset_i18nFoswiki::reset_i18n
0000s0sFoswiki::::setETagsFoswiki::setETags
0000s0sFoswiki::::splitAnchorFromUrlFoswiki::splitAnchorFromUrl
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
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
44251µs275µs
# spent 49µs (24+25) within Foswiki::BEGIN@44 which was called: # once (24µs+25µs) by main::BEGIN@27 at line 44
use strict;
# spent 49µs making 1 call to Foswiki::BEGIN@44 # spent 25µs making 1 call to strict::import
45242µs232µs
# spent 24µs (16+8) within Foswiki::BEGIN@45 which was called: # once (16µs+8µs) by main::BEGIN@27 at line 45
use warnings;
# spent 24µs making 1 call to Foswiki::BEGIN@45 # spent 8µs making 1 call to warnings::import
462171µs23.07ms
# spent 3.01ms (651µs+2.36) within Foswiki::BEGIN@46 which was called: # once (651µs+2.36ms) by main::BEGIN@27 at line 46
use Assert;
# spent 3.01ms making 1 call to Foswiki::BEGIN@46 # spent 58µs making 1 call to Exporter::import
472104µs262µs
# spent 39µs (15+24) within Foswiki::BEGIN@47 which was called: # once (15µs+24µs) by main::BEGIN@27 at line 47
use Cwd qw( abs_path );
# spent 39µs making 1 call to Foswiki::BEGIN@47 # spent 24µs making 1 call to Exporter::import
482173µs214.0ms
# spent 11.4ms (4.49+6.89) within Foswiki::BEGIN@48 which was called: # once (4.49ms+6.89ms) by main::BEGIN@27 at line 48
use Error qw( :try );
# spent 11.4ms making 1 call to Foswiki::BEGIN@48 # spent 2.60ms making 1 call to Error::import
49231µs17µs
# spent 7µs within Foswiki::BEGIN@49 which was called: # once (7µs+0s) by main::BEGIN@27 at line 49
use File::Spec ();
# spent 7µs making 1 call to Foswiki::BEGIN@49
502170µs13.13ms
# spent 3.13ms (2.79+342µs) within Foswiki::BEGIN@50 which was called: # once (2.79ms+342µs) by main::BEGIN@27 at line 50
use Monitor ();
# spent 3.13ms making 1 call to Foswiki::BEGIN@50
512159µs115.1ms
# spent 15.1ms (10.2+4.99) within Foswiki::BEGIN@51 which was called: # once (10.2ms+4.99ms) by main::BEGIN@27 at line 51
use CGI (); # Always required to get html generation tags;
# spent 15.1ms making 1 call to Foswiki::BEGIN@51
522155µs11.35ms
# spent 1.35ms (1.00+350µs) within Foswiki::BEGIN@52 which was called: # once (1.00ms+350µs) by main::BEGIN@27 at line 52
use Digest::MD5 (); # For passthru and validation
# spent 1.35ms making 1 call to Foswiki::BEGIN@52
532142µs155.0ms
# spent 55.0ms (3.97+51.0) within Foswiki::BEGIN@53 which was called: # once (3.97ms+51.0ms) by main::BEGIN@27 at line 53
use Foswiki::Configure::Load ();
# spent 55.0ms making 1 call to Foswiki::BEGIN@53
54
552617µs115µs
# spent 15µs within Foswiki::BEGIN@55 which was called: # once (15µs+0s) by main::BEGIN@27 at line 55
use 5.006; # First version to accept v-numbers.
# spent 15µs making 1 call to Foswiki::BEGIN@55
56
57# Item13331 - use CGI::ENCODE_ENTITIES introduced in CGI>=4.14 to restrict encoding
58# in CGI's html rendering code to only these; note that CGI's default values
59# still breaks some unicode byte strings
6011µs$CGI::ENCODE_ENTITIES = q{&<>"'};
61
62#SMELL: Perl 5.10.0 on Mac OSX Snow Leopard warns "v-string in use/require non-portable"
63112µsrequire 5.008_008; # see http://foswiki.org/Development/RequirePerl588
64
65# Site configuration constants
661500nsour %cfg;
67
68# Other computed constants
691100nsour $foswikiLibDir;
701100nsour %regex;
711100nsour %macros;
7210sour %contextFreeSyntax;
731100nsour $VERSION;
741100nsour $RELEASE;
751300nsour $UNICODE = 1; # flag that extensions can use to test if the core is unicode
761100nsour $TRUE = 1;
771100nsour $FALSE = 0;
781100nsour $engine;
791300nsour $TranslationToken = "\0"; # Do not deprecate - used in many plugins
801100nsour $system_message; # Important broadcast message from the system
811500nsmy $bootstrap_message = ''; # Bootstrap message.
82
83# Note: the following marker is used in text to mark RENDERZONE
84# macros that have been hoisted from the source text of a page. It is
85# carefully chosen so that it is (1) not normally present in written
86# text (2) does not combine with other characters to form valid
87# wide-byte characters and (3) does not conflict with other markers used
88# by Foswiki/Render.pm
891200nsour $RENDERZONE_MARKER = "\3";
90
91# Used by takeOut/putBack blocks
921100nsour $BLOCKID = 0;
931300nsour $OC = "<!--\0";
941300nsour $CC = "\0-->";
95
96# This variable is set if Foswiki is running in unit test mode.
97# It is provided so that modules can detect unit test mode to avoid
98# corrupting data spaces.
991300nsour $inUnitTestMode = 0;
100
101240443µs
# spent 244µs within Foswiki::SINGLE_SINGLETONS which was called 240 times, avg 1µs/call: # 238 times (241µs+0s) by Foswiki::innerExpandMacros at line 3080, avg 1µs/call # once (2µs+0s) by Foswiki::finish at line 2529 # once (1µs+0s) by Foswiki::new at line 2075
sub SINGLE_SINGLETONS { 0 }
10228µs
# spent 5µs within Foswiki::SINGLE_SINGLETONS_TRACE which was called 2 times, avg 3µs/call: # once (4µs+0s) by Foswiki::finish at line 2524 # once (2µs+0s) by Foswiki::new at line 2063
sub SINGLE_SINGLETONS_TRACE { 0 }
103
104# Returns the full path of the directory containing Foswiki.pm
105
# spent 13µs within Foswiki::_getLibDir which was called: # once (13µs+0s) by Foswiki::BEGIN@176 at line 623
sub _getLibDir {
1061300ns return $foswikiLibDir if $foswikiLibDir;
107
1081900ns $foswikiLibDir = $INC{'Foswiki.pm'};
109
110 # fix path relative to location of called script
11111µs if ( $foswikiLibDir =~ m/^\./ ) {
112 print STDERR
113"WARNING: Foswiki lib path $foswikiLibDir is relative; you should make it absolute, otherwise some scripts may not run from the command line.";
114 my $bin;
115
116 # SMELL : Should not assume environment variables; get data from request
117 if ( $ENV{SCRIPT_FILENAME}
118 && $ENV{SCRIPT_FILENAME} =~ m#^(.+)/.+?$# )
119 {
120
121 # CGI script name
122 # implicit untaint OK, because of use of $SCRIPT_FILENAME
123 $bin = $1;
124 }
125 elsif ( $0 =~ m#^(.*)/.*?$# ) {
126
127 # program name
128 # implicit untaint OK, because of use of $PROGRAM_NAME ($0)
129 $bin = $1;
130 }
131 else {
132
133 # last ditch; relative to current directory.
134 require Cwd;
135 $bin = Cwd::cwd();
136 }
137 $foswikiLibDir = "$bin/$foswikiLibDir/";
138
139 # normalize "/../" and "/./"
140 while ( $foswikiLibDir =~ s|([\\/])[^\\/]+[\\/]\.\.[\\/]|$1| ) {
141 }
142 $foswikiLibDir =~ s|([\\/])\.[\\/]|$1|g;
143 }
14418µs $foswikiLibDir =~ s|([\\/])[\\/]*|$1|g; # reduce "//" to "/"
1451900ns $foswikiLibDir =~ s|[\\/]$||; # cut trailing "/"
146
14715µs return $foswikiLibDir;
148}
149
150# Character encoding/decoding stubs. Done so we can ovveride
151# if necessary (e.g. on OSX we may want to monkey-patch in a
152# NFC/NFD module)
153
154=begin TML
155
156---++ StaticMethod decode_utf8($octets) -> $unicode
157
158Decode a binary string of octets known to be encoded using UTF-8 into
159perl characters (unicode).
160
161=cut
162
16312µs*decode_utf8 = \&Encode::decode_utf8;
164
165=begin TML
166
167---++ StaticMethod encode_utf8($unicode) -> $octets
168
169Encode a perl character string into a binary string of octets
170encoded using UTF-8.
171
172=cut
173
1741600ns*encode_utf8 = \&Encode::encode_utf8;
175
176
# spent 36.6ms (360µs+36.2) within Foswiki::BEGIN@176 which was called: # once (360µs+36.2ms) by main::BEGIN@27 at line 636
BEGIN {
177
178 # First thing we do; make sure we print unicode errors
179110µs binmode( STDERR, ":utf8" );
180
181 #Monitor::MARK("Start of BEGIN block in Foswiki.pm");
1821300ns if (DEBUG) {
183 if ( not $Assert::soft ) {
184
185 # If ASSERTs are on (and not soft), then warnings are errors.
186 # Paranoid, but the only way to be sure we eliminate them all.
187 # ASSERTS are turned on by defining the environment variable
188 # FOSWIKI_ASSERTS. If ASSERTs are off, this is assumed to be a
189 # production environment, and no stack traces or paths are
190 # output to the browser.
191 $SIG{'__WARN__'} = sub { die @_ };
192 $Error::Debug = 1; # verbose stack traces, please
193 }
194 else {
195
196 # ASSERTs are soft, so warnings are not errors
197 # but ASSERTs are enabled. This is useful for tracking down
198 # problems that only manifest on production servers.
199 $Error::Debug = 0; # no verbose stack traces
200 }
201 }
202 else {
2031700ns $Error::Debug = 0; # no verbose stack traces
204 }
205
206 # DO NOT CHANGE THE FORMAT OF $VERSION.
207 # Use $RELEASE for a descriptive version.
20842.38ms42.58ms
# spent 2.46ms (1.52+932µs) within Foswiki::BEGIN@208 which was called: # once (1.52ms+932µs) by main::BEGIN@27 at line 208
use version 0.77; $VERSION = version->declare('v2.0.0_002');
# spent 2.46ms making 1 call to Foswiki::BEGIN@208 # spent 52µs making 1 call to version::vxs::declare # spent 48µs making 1 call to UNIVERSAL::VERSION # spent 21µs making 1 call to version::import
2091300ns $RELEASE = 'Foswiki-2.0.1-RC2';
210
211 # Default handlers for different %TAGS%
212 # Where an entry is set as 'undef', the tag will be demand-loaded
213 # from Foswiki::Macros, if it is used. This tactic is used to reduce
214 # the load time of this module, especially when it is used from
215 # REST handlers.
216 %macros = (
217 ADDTOHEAD => undef,
218
219 # deprecated, use ADDTOZONE instead
220 ADDTOZONE => undef,
221 ALLVARIABLES => sub { $_[0]->{prefs}->stringify() },
222 ATTACHURL => undef,
223 ATTACHURLPATH => undef,
224 DATE => sub {
225 Foswiki::Time::formatTime(
226 time(),
227 $Foswiki::cfg{DefaultDateFormat},
228 $Foswiki::cfg{DisplayTimeValues}
229 );
230 },
231 DISPLAYTIME => sub {
232 Foswiki::Time::formatTime(
233 time(),
234 $_[1]->{_DEFAULT} || '',
235 $Foswiki::cfg{DisplayTimeValues}
236 );
237 },
238 ENCODE => undef,
239 ENV => undef,
240 EXPAND => undef,
241 FORMAT => undef,
242 FORMFIELD => undef,
24315µs
# spent 4µs within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:243] which was called: # once (4µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3435
FOSWIKI_BROADCAST => sub { $Foswiki::system_message || '' },
244
# spent 185µs (44+141) within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:247] which was called 6 times, avg 31µs/call: # 6 times (44µs+141µs) by Foswiki::_expandMacroOnTopicRendering at line 3435, avg 31µs/call
GMTIME => sub {
245633µs6141µs Foswiki::Time::formatTime( time(), $_[1]->{_DEFAULT} || '',
# spent 141µs making 6 calls to Foswiki::Time::formatTime, avg 24µs/call
246 'gmtime' );
247 },
248 GROUPINFO => undef,
249 GROUPS => undef,
250 HTTP_HOST =>
251
252 #deprecated functionality, now implemented using %ENV%
253 sub { $_[0]->{request}->header('Host') || '' },
254 HTTP => undef,
255 HTTPS => undef,
256 ICON => undef,
257 ICONURL => undef,
258 ICONURLPATH => undef,
259 IF => undef,
260 INCLUDE => undef,
261 INTURLENCODE => undef,
262 LANGUAGE => sub { $_[0]->i18n->language(); },
263 LANGUAGES => undef,
264 MAKETEXT => undef,
265 META => undef, # deprecated
266 METASEARCH => undef, # deprecated
267 NONCE => undef,
268 PERLDEPENDENCYREPORT => undef,
269 NOP =>
270
271 # Remove NOP tag in template topics but show content.
272 # Used in template _topics_ (not templates, per se, but
273 # topics used as templates for new topics)
274 sub { $_[1]->{_RAW} ? $_[1]->{_RAW} : '<nop>' },
275 PLUGINVERSION => sub {
276 $_[0]->{plugins}->getPluginVersion( $_[1]->{_DEFAULT} );
277 },
278 PUBURL => undef,
279 PUBURLPATH => undef,
280 QUERY => undef,
281 QUERYPARAMS => undef,
282
# spent 106µs (12+94) within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:289] which was called: # once (12µs+94µs) by Foswiki::_expandMacroOnTopicRendering at line 3435
QUERYSTRING => sub {
28313µs194µs my $s = $_[0]->{request}->queryString();
# spent 94µs making 1 call to Foswiki::Request::queryString
284
285 # Aggressively encode QUERYSTRING (even more than the
286 # default) because it might be leveraged for XSS
28713µs $s =~ s/(['\/])/'%'.sprintf('%02x', ord($1))/ge;
28815µs return $s;
289 },
290 RELATIVETOPICPATH => undef,
291 REMOTE_ADDR =>
292
293 # DEPRECATED, now implemented using %ENV%
294 #move to compatibility plugin in Foswiki 2.0
295 sub { $_[0]->{request}->remoteAddress() || ''; },
296 REMOTE_PORT =>
297
298 # DEPRECATED
299 # CGI/1.1 (RFC 3875) doesn't specify REMOTE_PORT,
300 # but some webservers implement it. However, since
301 # it's not RFC compliant, Foswiki should not rely on
302 # it. So we get more portability.
303 sub { '' },
304 REMOTE_USER =>
305
306 # DEPRECATED
307 sub { $_[0]->{request}->remoteUser() || '' },
308 RENDERZONE => undef,
309 REVINFO => undef,
310 REVTITLE => undef,
311 REVARG => undef,
31217µs15µs
# spent 13µs (8+5) within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:312] which was called: # once (8µs+5µs) by Foswiki::_expandMacroOnTopicRendering at line 3435
SCRIPTNAME => sub { $_[0]->{request}->action() },
# spent 5µs making 1 call to Foswiki::Request::action
313 SCRIPTURL => undef,
314 SCRIPTURLPATH => undef,
315 SEARCH => undef,
316 SEP =>
317
318 # Shortcut to %TMPL:P{"sep"}%
319 sub { $_[0]->templates->expandTemplate('sep') },
320
# spent 145µs (18+127) within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:323] which was called 2 times, avg 72µs/call: # 2 times (18µs+127µs) by Foswiki::_expandMacroOnTopicRendering at line 3435, avg 72µs/call
SERVERTIME => sub {
321215µs2127µs Foswiki::Time::formatTime( time(), $_[1]->{_DEFAULT} || '',
# spent 127µs making 2 calls to Foswiki::Time::formatTime, avg 64µs/call
322 'servertime' );
323 },
324 SERVERINFORMATION => undef,
325 SET => undef,
326 SHOWPREFERENCE => undef,
327 SPACEDTOPIC => undef,
328 SPACEOUT => undef,
329 'TMPL:P' => sub { $_[0]->templates->tmplP( $_[1] ) },
330 TOPICLIST => undef,
331 URLENCODE => undef,
332 URLPARAM => undef,
333 USERINFO => undef,
334 USERNAME => undef,
335 VAR => undef,
336 WEBLIST => undef,
337 WIKINAME => undef,
338 WIKIUSERNAME => undef,
339 DISPLAYDEPENDENCIES => undef,
340
341 # Constant tag strings _not_ dependent on config. These get nicely
342 # optimised by the compiler.
343 STOPSECTION => sub { '' },
34428µs
# spent 8µs within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:344] which was called 2 times, avg 4µs/call: # 2 times (8µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3435, avg 4µs/call
ENDSECTION => sub { '' },
345 WIKIVERSION => sub { $VERSION },
346 WIKIRELEASE => sub { $RELEASE },
34728µs
# spent 8µs within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:347] which was called 2 times, avg 4µs/call: # 2 times (8µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3435, avg 4µs/call
STARTSECTION => sub { '' },
348 STARTINCLUDE => sub { '' },
349 STOPINCLUDE => sub { '' },
350 ENDINCLUDE => sub { '' },
351157µs );
3521900ns $contextFreeSyntax{IF} = 1;
353
354 # Load LocalSite.cfg
35513µs120.7ms if ( Foswiki::Configure::Load::readConfig( 0, 0, 0 ) ) {
# spent 20.7ms making 1 call to Foswiki::Configure::Load::readConfig
356 $Foswiki::cfg{isVALID} = 1;
357 }
358 else {
359 $bootstrap_message = Foswiki::Configure::Load::bootstrapConfig();
360 eval 'require Foswiki::Plugins::ConfigurePlugin';
361 die
362"LocalSite.cfg load failed, and ConfigurePlugin could not be loaded: $@"
363 if $@;
364 }
365
3661400ns if ( $Foswiki::cfg{UseLocale} ) {
367 require locale;
368 import locale();
369 }
370 elsif (DEBUG) {
371 eval { require Taint::Runtime; };
372 if ($@) {
373 print STDERR
374"DEVELOPER WARNING: taint mode could not be enabled. Is Taint::Runtime installed?\n";
375 }
376 else {
377 # Enable taint checking
378 Taint::Runtime::_taint_start();
379 }
380 }
381
382 # If not set, default to strikeone validation
3831500ns $Foswiki::cfg{Validation}{Method} ||= 'strikeone';
3841300ns $Foswiki::cfg{Validation}{ValidForTime} = $Foswiki::cfg{LeaseLength}
385 unless defined $Foswiki::cfg{Validation}{ValidForTime};
3861800ns $Foswiki::cfg{Validation}{MaxKeys} = 1000
387 unless defined $Foswiki::cfg{Validation}{MaxKeys};
388
389 # Constant tags dependent on the config
390 $macros{ALLOWLOGINNAME} =
39112µs sub { $Foswiki::cfg{Register}{AllowLoginName} || 0 };
39211µs $macros{AUTHREALM} = sub { $Foswiki::cfg{AuthRealm} };
39311µs $macros{DEFAULTURLHOST} = sub { $Foswiki::cfg{DefaultUrlHost} };
394616µs
# spent 14µs within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:394] which was called 5 times, avg 3µs/call: # 5 times (14µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3435, avg 3µs/call
$macros{HOMETOPIC} = sub { $Foswiki::cfg{HomeTopicName} };
39511µs $macros{LOCALSITEPREFS} = sub { $Foswiki::cfg{LocalSitePreferences} };
396 $macros{NOFOLLOW} =
39712µs sub { $Foswiki::cfg{NoFollow} ? 'rel=' . $Foswiki::cfg{NoFollow} : '' };
39812µs $macros{NOTIFYTOPIC} = sub { $Foswiki::cfg{NotifyTopicName} };
39928µs
# spent 4µs within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:399] which was called: # once (4µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3435
$macros{SCRIPTSUFFIX} = sub { $Foswiki::cfg{ScriptSuffix} };
40012µs $macros{STATISTICSTOPIC} = sub { $Foswiki::cfg{Stats}{TopicName} };
40164151µs
# spent 96µs within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:401] which was called 63 times, avg 2µs/call: # 63 times (96µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3435, avg 2µs/call
$macros{SYSTEMWEB} = sub { $Foswiki::cfg{SystemWebName} };
40211µs $macros{TRASHWEB} = sub { $Foswiki::cfg{TrashWebName} };
40311µs $macros{SANDBOXWEB} = sub { $Foswiki::cfg{SandboxWebName} };
4041900ns $macros{WIKIADMINLOGIN} = sub { $Foswiki::cfg{AdminUserLogin} };
4051128µs
# spent 21µs within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:405] which was called 10 times, avg 2µs/call: # 10 times (21µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3435, avg 2µs/call
$macros{USERSWEB} = sub { $Foswiki::cfg{UsersWebName} };
40611µs $macros{WEBPREFSTOPIC} = sub { $Foswiki::cfg{WebPrefsTopicName} };
4071900ns $macros{WIKIPREFSTOPIC} = sub { $Foswiki::cfg{SitePrefsTopicName} };
4081900ns $macros{WIKIUSERSTOPIC} = sub { $Foswiki::cfg{UsersTopicName} };
40927µs
# spent 5µs within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:409] which was called: # once (5µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3435
$macros{WIKIWEBMASTER} = sub { $Foswiki::cfg{WebMasterEmail} };
41011µs $macros{WIKIWEBMASTERNAME} = sub { $Foswiki::cfg{WebMasterName} };
411
412 # locale setup
413 #
414 #
415 # Note that 'use locale' must be done in BEGIN block for regexes and
416 # sorting to work properly, although regexes can still work without
417 # this in 'non-locale regexes' mode.
418
4191200ns if ( $Foswiki::cfg{UseLocale} ) {
420
421 # Set environment variables for grep
422 $ENV{LC_CTYPE} = $Foswiki::cfg{Site}{Locale};
423
424 # Load POSIX for I18N support.
425 require POSIX;
426 import POSIX qw( locale_h LC_CTYPE LC_COLLATE );
427
428 # SMELL: mod_perl compatibility note: If Foswiki is running under Apache,
429 # won't this play with the Apache process's locale settings too?
430 # What effects would this have?
431 setlocale( &LC_CTYPE, $Foswiki::cfg{Site}{Locale} );
432 setlocale( &LC_COLLATE, $Foswiki::cfg{Site}{Locale} );
433 }
434
435 $macros{CHARSET} = sub {
436 'utf-8';
43711µs };
438
439
# spent 4µs within Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:450] which was called: # once (4µs+0s) by Foswiki::_expandMacroOnTopicRendering at line 3435
$macros{LANG} = sub {
4401800ns my $lang = 'en'; # the default
44111µs if ( $Foswiki::cfg{UseLocale}
442 && $Foswiki::cfg{Site}{Locale} =~ m/^([a-z]+)(?:_([a-z]+))?/i )
443 {
444
445# Locale identifiers use _ as the separator in the language, but a minus sign is required
446# for HTML (see http://www.ietf.org/rfc/rfc1766.txt)
447 $lang = $1 . ( $2 ? "-$2" : '' );
448 }
44914µs return $lang;
45012µs };
451
452 # Set up pre-compiled regexes for use in rendering.
453 # In the regex hash, all precompiled REs have "Regex" at the
454 # end of the name. Anything else is a string, either intended
455 # for use as a character class, or as a sub-expression in
456 # another compiled RE.
457
458 # Character class components for use in regexes.
459 # (Pre-UTF-8 compatibility; not used in core)
4601700ns $regex{upperAlpha} = '[:upper:]';
4611300ns $regex{lowerAlpha} = '[:lower:]';
4621400ns $regex{numeric} = '[:digit:]';
4631400ns $regex{mixedAlpha} = '[:alpha:]';
4641400ns $regex{mixedAlphaNum} = '[:alnum:]';
4651300ns $regex{lowerAlphaNum} = '[:lower:][:digit:]';
4661400ns $regex{upperAlphaNum} = '[:upper:][:digit:]';
467
468 # Compile regexes for efficiency and ease of use
469 # Note: qr// locks in regex modes (i.e. '-xism' here) - see Friedl
470 # book at http://regex.info/.
471
47211µs $regex{linkProtocolPattern} = $Foswiki::cfg{LinkProtocolPattern}
473 || '(file|ftp|gopher|https|http|irc|mailto|news|nntp|telnet)';
474
475 # Header patterns based on '+++'. The '###' are reserved for numbered
476 # headers
477 # '---++ Header', '---## Header'
47812µs $regex{headerPatternDa} = qr/^---+(\++|\#+)(.*)$/m;
479
480 # '<h6>Header</h6>
4811900ns $regex{headerPatternHt} = qr/^<h([1-6])>(.+?)<\/h\1>/mi;
482
483 # '---++!! Header' or '---++ Header %NOTOC% ^top'
4841500ns $regex{headerPatternNoTOC} = '(\!\!+|%NOTOC%)';
485
486 # Foswiki concept regexes
48711µs $regex{wikiWordRegex} = qr(
488 [[:upper:]]+
489 [[:lower:][:digit:]]+
490 [[:upper:]]+
491 [[:alnum:]]*
492 )xo;
4931900ns $regex{webNameBaseRegex} = qr/[[:upper:]]+[[:alnum:]_]*/;
4941500ns if ( $Foswiki::cfg{EnableHierarchicalWebs} ) {
495123µs $regex{webNameRegex} = qr(
496 $regex{webNameBaseRegex}
497 (?:(?:[\.\/]$regex{webNameBaseRegex})+)*
498 )xo;
499 }
500 else {
501 $regex{webNameRegex} = $regex{webNameBaseRegex};
502 }
50311µs $regex{defaultWebNameRegex} = qr/_[[:alnum:]_]+/;
50412µs $regex{anchorRegex} = qr/\#[[:alnum:]:._]+/;
5051600ns my $abbrevLength = $Foswiki::cfg{AcronymLength} || 3;
50619µs $regex{abbrevRegex} = qr/[[:upper:]]{$abbrevLength,}s?\b/;
507
508121µs $regex{topicNameRegex} =
509 qr/(?:(?:$regex{wikiWordRegex})|(?:$regex{abbrevRegex}))/;
510
511 # Email regex, e.g. for WebNotify processing and email matching
512 # during rendering.
513
51417µs my $emailAtom = qr([A-Z0-9\Q!#\$%&'*+-/=?^_`{|}~\E])i; # Per RFC 5322 ]
515
516 # Valid TLD's at http://data.iana.org/TLD/tlds-alpha-by-domain.txt
517 # Version 2012022300, Last Updated Thu Feb 23 15:07:02 2012 UTC
5181700ns my $validTLD = $Foswiki::cfg{Email}{ValidTLD};
519
520214µs unless ( eval { qr/$validTLD/ } ) {
521 $validTLD =
522qr(AERO|ARPA|ASIA|BIZ|CAT|COM|COOP|EDU|GOV|INFO|INT|JOBS|MIL|MOBI|MUSEUM|NAME|NET|ORG|PRO|TEL|TRAVEL|XXX)i;
523
524# Too early to log, should do something here other than die (which prevents fixing)
525# warn is trapped and turned into a die...
526#warn( "{Email}{ValidTLD} does not compile, using default" );
527 }
528
529147µs $regex{emailAddrRegex} = qr(
530 (?: # LEFT Side of Email address
531 (?:$emailAtom+ # Valid characters left side of email address
532 (?:\.$emailAtom+)* # And 0 or more dotted atoms
533 )
534 |
535 (?:"[\x21\x23-\x5B\x5D-\x7E\s]+?") # or a quoted string per RFC 5322
536 )
537 @
538 (?: # RIGHT side of Email address
539 (?: # FQDN
540 [a-z0-9-]+ # hostname part
541 (?:\.[a-z0-9-]+)* # 0 or more alphanumeric domains following a dot.
542 \.(?: # TLD
543 (?:[a-z]{2,2}) # 2 character TLD
544 |
545 $validTLD # TLD's longer than 2 characters
546 )
547 )
548 |
549 (?:\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\]) # dotted triplets IP Address
550 )
551 )oxi;
552
553 # Item11185: This is how things were before we began Operation Unicode:
554 #
555 # $regex{filenameInvalidCharRegex} = qr/[^[:alnum:]\. _-]/;
556 #
557 # It was only used in Foswiki::Sandbox::sanitizeAttachmentName(), which now
558 # uses $Foswiki::cfg{NameFilter} instead.
559 # See RobustnessTests::test_sanitizeAttachmentName
560 #
561 # Actually, this is used in GenPDFPrincePlugin; let's copy NameFilter
56216µs $regex{filenameInvalidCharRegex} = qr/$Foswiki::cfg{NameFilter}/;
563
564 # Multi-character alpha-based regexes
56512µs $regex{mixedAlphaNumRegex} = qr/[[:alnum:]]*/;
566
567 # %TAG% name
5681400ns $regex{tagNameRegex} = '[A-Za-z][A-Za-z0-9_:]*';
569
570 # Set statement in a topic
5711400ns $regex{bulletRegex} = '^(?:\t| )+\*';
57211µs $regex{setRegex} = $regex{bulletRegex} . '\s+(Set|Local)\s+';
57311µs $regex{setVarRegex} =
574 $regex{setRegex} . '(' . $regex{tagNameRegex} . ')\s*=\s*(.*)$';
575
576 # Character encoding regexes
577
578 # Regex to match only a valid UTF-8 character, taking care to avoid
579 # security holes due to overlong encodings by excluding the relevant
580 # gaps in UTF-8 encoding space - see 'perldoc perlunicode', Unicode
581 # Encodings section. Tested against Markus Kuhn's UTF-8 test file
582 # at http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt.
58311µs $regex{validUtf8CharRegex} = qr{
584 # Single byte - ASCII
585 [\x00-\x7F]
586 |
587
588 # 2 bytes
589 [\xC2-\xDF][\x80-\xBF]
590 |
591
592 # 3 bytes
593
594 # Avoid illegal codepoints - negative lookahead
595 (?!\xEF\xBF[\xBE\xBF])
596
597 # Match valid codepoints
598 (?:
599 ([\xE0][\xA0-\xBF])|
600 ([\xE1-\xEC\xEE-\xEF][\x80-\xBF])|
601 ([\xED][\x80-\x9F])
602 )
603 [\x80-\xBF]
604 |
605
606 # 4 bytes
607 (?:
608 ([\xF0][\x90-\xBF])|
609 ([\xF1-\xF3][\x80-\xBF])|
610 ([\xF4][\x80-\x8F])
611 )
612 [\x80-\xBF][\x80-\xBF]
613 }xo;
614
615130µs $regex{validUtf8StringRegex} = qr/^(?:$regex{validUtf8CharRegex})+$/;
616
617 # Check for unsafe search regex mode (affects filtering in) - default
618 # to safe mode
6191300ns $Foswiki::cfg{ForceUnsafeRegexes} = 0
620 unless defined $Foswiki::cfg{ForceUnsafeRegexes};
621
622 # initialize lib directory early because of later 'cd's
62312µs113µs _getLibDir();
# spent 13µs making 1 call to Foswiki::_getLibDir
624
625 # initialize the runtime engine
6261400ns if ( !defined $Foswiki::cfg{Engine} ) {
627
628 # Caller did not define an engine; try and work it out (mainly for
629 # the benefit of pre-1.0 CGI scripts)
630 $Foswiki::cfg{Engine} = 'Foswiki::Engine::Legacy';
631 }
632135µs $engine = eval qq(use $Foswiki::cfg{Engine}; $Foswiki::cfg{Engine}->new);
# spent 104µs executing statements in string eval
# includes 736µs spent executing 1 call to 1 sub defined therein.
63314µs die $@ if $@;
634
635 #Monitor::MARK('End of BEGIN block in Foswiki.pm');
636123µs136.6ms}
# spent 36.6ms making 1 call to Foswiki::BEGIN@176
637
638# Components that all requests need
639220µs14µs
# spent 4µs within Foswiki::BEGIN@639 which was called: # once (4µs+0s) by main::BEGIN@27 at line 639
use Foswiki::Response ();
# spent 4µs making 1 call to Foswiki::BEGIN@639
640218µs13µs
# spent 3µs within Foswiki::BEGIN@640 which was called: # once (3µs+0s) by main::BEGIN@27 at line 640
use Foswiki::Request ();
# spent 3µs making 1 call to Foswiki::BEGIN@640
641286µs11.03ms
# spent 1.03ms (947µs+79µs) within Foswiki::BEGIN@641 which was called: # once (947µs+79µs) by main::BEGIN@27 at line 641
use Foswiki::Logger ();
# spent 1.03ms making 1 call to Foswiki::BEGIN@641
6422144µs113.4ms
# spent 13.4ms (11.5+1.95) within Foswiki::BEGIN@642 which was called: # once (11.5ms+1.95ms) by main::BEGIN@27 at line 642
use Foswiki::Meta ();
# spent 13.4ms making 1 call to Foswiki::BEGIN@642
6432117µs112.2ms
# spent 12.2ms (2.34+9.82) within Foswiki::BEGIN@643 which was called: # once (2.34ms+9.82ms) by main::BEGIN@27 at line 643
use Foswiki::Sandbox ();
# spent 12.2ms making 1 call to Foswiki::BEGIN@643
6442103µs13.57ms
# spent 3.57ms (2.07+1.50) within Foswiki::BEGIN@644 which was called: # once (2.07ms+1.50ms) by main::BEGIN@27 at line 644
use Foswiki::Time ();
# spent 3.57ms making 1 call to Foswiki::BEGIN@644
645282µs14.30ms
# spent 4.30ms (1.79+2.51) within Foswiki::BEGIN@645 which was called: # once (1.79ms+2.51ms) by main::BEGIN@27 at line 645
use Foswiki::Prefs ();
# spent 4.30ms making 1 call to Foswiki::BEGIN@645
646290µs16.33ms
# spent 6.33ms (2.17+4.16) within Foswiki::BEGIN@646 which was called: # once (2.17ms+4.16ms) by main::BEGIN@27 at line 646
use Foswiki::Plugins ();
# spent 6.33ms making 1 call to Foswiki::BEGIN@646
64724.46ms113.1ms
# spent 13.1ms (2.75+10.4) within Foswiki::BEGIN@647 which was called: # once (2.75ms+10.4ms) by main::BEGIN@27 at line 647
use Foswiki::Users ();
# spent 13.1ms making 1 call to Foswiki::BEGIN@647
648
649=begin TML
650
651---++ ObjectMethod writeCompletePage( $text, $pageType, $contentType )
652
653Write a complete HTML page with basic header to the browser.
654 * =$text= is the text of the page script (&lt;html&gt; to &lt;/html&gt; if it's HTML)
655 * =$pageType= - May be "edit", which will cause headers to be generated that force
656 caching for 24 hours, to prevent Codev.BackFromPreviewLosesText bug, which caused
657 data loss with IE5 and IE6.
658 * =$contentType= - page content type | text/html
659
660This method removes noautolink and nop tags before outputting the page unless
661$contentType is text/plain.
662
663=cut
664
665
# spent 23.4ms (4.94+18.5) within Foswiki::writeCompletePage which was called: # once (4.94ms+18.5ms) by Foswiki::UI::View::view at line 472 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm
sub writeCompletePage {
66615µs my ( $this, $text, $pageType, $contentType ) = @_;
667
668 # true if the body is to be output without encoding to utf8
669 # first. This is the case if the body has been gzipped and/or
670 # rendered from the cache
67111µs my $binary_body = 0;
672
6731400ns $contentType ||= 'text/html';
674
67513µs19µs my $cgis = $this->{users}->getCGISession();
# spent 9µs making 1 call to Foswiki::Users::getCGISession
6761600ns if ( $cgis
677 && $contentType =~ m!^text/html!
678 && $Foswiki::cfg{Validation}{Method} ne 'none' )
679 {
680
681 # Don't expire the validation key through login, or when
682 # endpoint is an error.
683 Foswiki::Validation::expireValidationKeys($cgis)
684 unless ( $this->{request}->action() eq 'login'
685 or ( $ENV{REDIRECT_STATUS} || 0 ) >= 400 );
686
687 my $usingStrikeOne = $Foswiki::cfg{Validation}{Method} eq 'strikeone';
688 if ($usingStrikeOne) {
689
690 # add the validation cookie
691 my $valCookie = Foswiki::Validation::getCookie($cgis);
692 $valCookie->secure( $this->{request}->secure );
693 $this->{response}
694 ->cookies( [ $this->{response}->cookies, $valCookie ] );
695
696 # Add the strikeone JS module to the page.
697 my $src = (DEBUG) ? '.uncompressed' : '';
698 $this->addToZone(
699 'script',
700 'JavascriptFiles/strikeone',
701 '<script type="text/javascript" src="'
702 . $this->getPubURL(
703 $Foswiki::cfg{SystemWebName}, 'JavascriptFiles',
704 "strikeone$src.js"
705 )
706 . '"></script>',
707 'JQUERYPLUGIN'
708 );
709
710 # Add the onsubmit handler to the form
711 $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/
712 Foswiki::Validation::addOnSubmit($1)/gei;
713 }
714
715 my $context =
716 $this->{request}->url( -full => 1, -path => 1, -query => 1 ) . time();
717
718 # Inject validation key in HTML forms
719 $text =~ s/(<form[^>]*method=['"]POST['"][^>]*>)/
720 $1 . Foswiki::Validation::addValidationKey(
721 $cgis, $context, $usingStrikeOne )/gei;
722
723 #add validation key to HTTP header so we can update it for ajax use
724 $this->{response}->pushHeader(
725 'X-Foswiki-Validation',
726 Foswiki::Validation::generateValidationKey(
727 $cgis, $context, $usingStrikeOne
728 )
729 ) if ($cgis);
730 }
731
73214µs118.2ms if ( $contentType !~ m!^text/plain! ) {
# spent 18.2ms making 1 call to Foswiki::_renderZones
733
734 $text = $this->_renderZones($text);
735 }
736
737 # Validate format of content-type (defined in rfc2616)
73814µs my $tch = qr/[^\[\]()<>@,;:\\"\/?={}\s]/;
739134µs if ( $contentType =~ m/($tch+\/$tch+(\s*;\s*$tch+=($tch+|"[^"]*"))*)$/i ) {
740 $contentType = $1;
741 }
742 else {
743 # SMELL: can't compute; faking content-type for backwards compatibility;
744 # any other information might become bogus later anyway
745 $contentType = "text/plain;contenttype=invalid";
746 }
74712µs my $hdr = "Content-type: " . $1 . "\r\n";
748
749 # Call final handler
75012µs14µs $this->{plugins}->dispatch( 'completePageHandler', $text, $hdr );
# spent 4µs making 1 call to Foswiki::Plugins::dispatch
751
752 # cache final page, but only view and rest
7531200ns my $cachedPage;
7541800ns if ( $contentType ne 'text/plain' ) {
755
756 # Remove <nop> and <noautolink> tags
75714.79ms $text =~ s/([\t ]?)[ \t]*<\/?(nop|noautolink)\/?>/$1/gis;
75811µs if ( $Foswiki::cfg{Cache}{Enabled}
759 && ( $this->inContext('view') || $this->inContext('rest') ) )
760 {
761 $cachedPage = $this->{cache}->cachePage( $contentType, $text );
762 $this->{cache}->renderDirtyAreas( \$text )
763 if $cachedPage && $cachedPage->{isdirty};
764 }
765
766 # remove <dirtyarea> tags
767137µs $text =~ s/<\/?dirtyarea[^>]*>//g;
768
769 # Check that the templates specified clean HTML
7701400ns if (DEBUG) {
771
772 # When tracing is enabled in Foswiki::Templates, then there will
773 # always be a <!--bodyend--> after </html>. So we need to disable
774 # this check.
775 require Foswiki::Templates;
776 if ( !Foswiki::Templates->TRACE
777 && $contentType =~ m#text/html#
778 && $text =~ m#</html>(.*?\S.*)$#s )
779 {
780 ASSERT( 0, <<BOGUS );
781Junk after </html>: $1. Templates may be bogus
782- Check for excess blank lines at ends of .tmpl files
783- or newlines after %TMPL:INCLUDE
784- You can enable TRACE in Foswiki::Templates to help debug
785BOGUS
786 }
787 }
788 }
789
790113µs254µs $this->{response}->pushHeader( 'X-Foswiki-Monitor-renderTime',
# spent 32µs making 1 call to Foswiki::Request::getTime # spent 22µs making 1 call to Foswiki::Response::pushHeader
791 $this->{request}->getTime() );
792
79312µs my $hopts = { 'Content-Type' => $contentType };
794
79516µs111µs $this->setCacheControl( $pageType, $hopts );
# spent 11µs making 1 call to Foswiki::setCacheControl
796
7971400ns if ($cachedPage) {
798 $text = '' unless $this->setETags( $cachedPage, $hopts );
799 }
800
8011600ns if ( $Foswiki::cfg{HttpCompress} && length($text) ) {
802
803 # Generate a zipped page, if the client accepts them
804
805 # SMELL: $ENV{SPDY} is a non-standard way to detect spdy protocol
806 if ( my $encoding = _gzipAccepted() ) {
807 $hopts->{'Content-Encoding'} = $encoding;
808 $hopts->{'Vary'} = 'Accept-Encoding';
809
810 # check if we take the version from the cache. NOTE: we don't
811 # set X-Foswiki-Pagecache because this is *not* coming from
812 # the cache (well it is, but it was only just put there)
813 if ( $cachedPage && !$cachedPage->{isdirty} ) {
814 $text = $cachedPage->{data};
815 }
816 else {
817 # Not available from the cache, or it has dirty areas
818 require Compress::Zlib;
819 $text = Compress::Zlib::memGzip( encode_utf8($text) );
820 }
821 $binary_body = 1;
822 }
823 } # Otherwise fall through and generate plain text
824
825 # Generate (and print) HTTP headers.
82614µs1141µs $this->generateHTTPHeaders($hopts);
# spent 141µs making 1 call to Foswiki::generateHTTPHeaders
827
82817µs if ($binary_body) {
829 $this->{response}->body($text);
830 }
831 else {
83214µs189µs $this->{response}->print($text);
# spent 89µs making 1 call to Foswiki::Response::print
833 }
834}
835
836# PRIVATE
837sub _gzipAccepted {
838 my $encoding;
839 if ( ( $ENV{'HTTP_ACCEPT_ENCODING'} || '' ) =~
840 /(?:^|\b)((?:x-)?gzip)(?:$|\b)/ )
841 {
842 $encoding = $1;
843 }
844 elsif ( $ENV{'SPDY'} ) {
845 $encoding = 'gzip';
846 }
847 return $encoding;
848}
849
850=begin TML
851
852---++ ObjectMethod satisfiedByCache( $action, $web, $topic ) -> $boolean
853
854Try and satisfy the current request for the given web.topic from the cache, given
855the current action (view, edit, rest etc).
856
857If the action is satisfied, the cache content is written to the output and
858true is returned. Otherwise ntohing is written, and false is returned.
859
860Designed for calling from Foswiki::UI::*
861
862=cut
863
864
# spent 5µs within Foswiki::satisfiedByCache which was called: # once (5µs+0s) by Foswiki::UI::View::view at line 86 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm
sub satisfiedByCache {
86511µs my ( $this, $action, $web, $topic ) = @_;
866
8671800ns my $cache = $this->{cache};
86814µs return 0 unless $cache;
869
870 my $cachedPage = $cache->getPage( $web, $topic ) if $cache;
871 return 0 unless $cachedPage;
872
873 Foswiki::Func::writeDebug("found $web.$topic for $action in cache")
874 if Foswiki::PageCache::TRACE();
875 if ( int( $this->{response}->status() || 200 ) >= 500 ) {
876 Foswiki::Func::writeDebug(
877 "Cache retrieval skipped due to non-200 status code "
878 . $this->{response}->status() )
879 if DEBUG;
880 return 0;
881 }
882 Monitor::MARK("found page in cache");
883
884 my $hdrs = { 'Content-Type' => $cachedPage->{contenttype} };
885
886 # render uncacheable areas
887 my $text = $cachedPage->{data};
888
889 if ( $cachedPage->{isdirty} ) {
890 $cache->renderDirtyAreas( \$text );
891
892 # dirty pages are cached in unicode
893 $text = encode_utf8($text);
894 }
895 elsif ( $Foswiki::cfg{HttpCompress} ) {
896
897 # Does the client accept gzip?
898 if ( my $encoding = _gzipAccepted() ) {
899
900 # Cache has compressed data, just whack it out
901 $hdrs->{'Content-Encoding'} = $encoding;
902 $hdrs->{'Vary'} = 'Accept-Encoding';
903
904 # Mark the response so we know it was satisfied from the cache
905 $hdrs->{'X-Foswiki-PageCache'} = 1;
906 }
907 else {
908 # e.g. CLI request satisfied from the cache, or old browser that doesn't
909 # support gzip. Non-isdirty pages are cached already utf8-encoded, so
910 # all we have to do is unzip.
911 require Compress::Zlib;
912 $text = Compress::Zlib::memGunzip( $cachedPage->{data} );
913 }
914 } # else { Non-isdirty pages are stored already utf8-encoded }
915
916 # set status
917 my $response = $this->{response};
918 if ( $cachedPage->{status} == 302 ) {
919 $response->redirect( $cachedPage->{location} );
920 }
921 else {
922
923 # See Item9941
924 # Don't allow a 200 status to overwrite a status (possibly an error status)
925 # coming from elsewhere in the code. Note that 401's are not cached (they
926 # fail Foswiki::PageCache::isCacheable) but all other statuses are.
927 # SMELL: Cdot doesn't think any other status can get this far.
928 $response->status( $cachedPage->{status} )
929 unless int( $cachedPage->{status} ) == 200;
930 }
931
932 # set remaining headers
933 $text = undef unless $this->setETags( $cachedPage, $hdrs );
934 $this->generateHTTPHeaders($hdrs);
935
936 # send it out
937 $response->body($text) if defined $text;
938
939 Monitor::MARK('Wrote HTML');
940 $this->logger->log(
941 {
942 level => 'info',
943 action => $action,
944 webTopic => $web . '.' . $topic,
945 extra => '(cached)',
946 }
947 );
948
949 return 1;
950}
951
952=begin TML
953
954---++ ObjectMethod setCacheControl( $pageType, \%hopts )
955
956Set the cache control headers in a response
957
958 * =$pageType= - page type - 'view', ;edit' etc
959 * =\%hopts - ref to partially filled in hash of headers
960
961=cut
962
963
# spent 11µs within Foswiki::setCacheControl which was called: # once (11µs+0s) by Foswiki::writeCompletePage at line 795
sub setCacheControl {
96411µs my ( $this, $pageType, $hopts ) = @_;
965
96614µs if ( $pageType && $pageType eq 'edit' ) {
967
968 # Edit pages - future versions will extend to
969 # of other types of page, with expiry time driven by page type.
970
971 # Get time now in HTTP header format
972 my $lastModifiedString =
973 Foswiki::Time::formatTime( time, '$http', 'gmtime' );
974
975 # Expiry time is set high to avoid any data loss. Each instance of
976 # Edit page has a unique URL with time-string suffix (fix for
977 # RefreshEditPage), so this long expiry time simply means that the
978 # browser Back button always works. The next Edit on this page
979 # will use another URL and therefore won't use any cached
980 # version of this Edit page.
981 my $expireHours = 24;
982 my $expireSeconds = $expireHours * 60 * 60;
983
984 # and cache control headers, to ensure edit page
985 # is cached until required expiry time.
986 $hopts->{'last-modified'} = $lastModifiedString;
987 $hopts->{expires} = "+${expireHours}h";
988 $hopts->{'Cache-Control'} = "max-age=$expireSeconds";
989 }
990 else {
991
992 # we need to force the browser into a check on every
993 # request; let the server decide on an 304 as below
99411µs my $cacheControl = 'max-age=0';
995
996 # allow the admin to disable us from setting the max-age, as then
997 # it can't be set by apache
99812µs $cacheControl = $Foswiki::cfg{BrowserCacheControl}->{ $this->{webName} }
999 if ( $Foswiki::cfg{BrowserCacheControl}
1000 && defined(
1001 $Foswiki::cfg{BrowserCacheControl}->{ $this->{webName} } ) );
1002
1003 # don't remove the 'if'; we need the header to not be there at
1004 # all for the browser to use the cached version
100512µs $hopts->{'Cache-Control'} = $cacheControl if ( $cacheControl ne '' );
1006 }
1007}
1008
1009=begin TML
1010
1011---++ ObjectMethod setETags( $cachedPage, \%hopts ) -> $boolean
1012
1013Set etags (and modify status) depending on what the cached page specifies.
1014Return 1 if the page has been modified since it was last retrieved, 0 otherwise.
1015
1016 * =$cachedPage= - page cache to use
1017 * =\%hopts - ref to partially filled in hash of headers
1018
1019=cut
1020
1021sub setETags {
1022 my ( $this, $cachedPage, $hopts ) = @_;
1023
1024 # check etag and last modification time
1025 my $etag = $cachedPage->{etag};
1026 my $lastModified = $cachedPage->{lastmodified};
1027
1028 $hopts->{'ETag'} = $etag if $etag;
1029 $hopts->{'Last-Modified'} = $lastModified if $lastModified;
1030
1031 # only send a 304 if both criteria are true
1032 return 1
1033 unless (
1034 $etag
1035 && $lastModified
1036
1037 && $ENV{'HTTP_IF_NONE_MATCH'}
1038 && $etag eq $ENV{'HTTP_IF_NONE_MATCH'}
1039
1040 && $ENV{'HTTP_IF_MODIFIED_SINCE'}
1041 && $lastModified eq $ENV{'HTTP_IF_MODIFIED_SINCE'}
1042 );
1043
1044 # finally decide on a 304 reply
1045 $hopts->{'Status'} = '304 Not Modified';
1046
1047 #print STDERR "NOT modified\n";
1048 return 0;
1049}
1050
1051=begin TML
1052
1053---++ ObjectMethod generateHTTPHeaders( \%hopts )
1054
1055All parameters are optional.
1056 * =\%hopts - optional ref to partially filled in hash of headers (will be written to)
1057
1058=cut
1059
1060
# spent 141µs (37+104) within Foswiki::generateHTTPHeaders which was called: # once (37µs+104µs) by Foswiki::writeCompletePage at line 826
sub generateHTTPHeaders {
10611800ns my ( $this, $hopts ) = @_;
1062
10631400ns $hopts ||= {};
1064
1065 # DEPRECATED plugins header handler. Plugins should use
1066 # modifyHeaderHandler instead.
106713µs13µs my $pluginHeaders =
# spent 3µs making 1 call to Foswiki::Plugins::dispatch
1068 $this->{plugins}->dispatch( 'writeHeaderHandler', $this->{request} )
1069 || '';
10701400ns if ($pluginHeaders) {
1071 foreach ( split /\r?\n/, $pluginHeaders ) {
1072
1073 # Implicit untaint OK; data from plugin handler
1074 if (m/^([\-a-z]+): (.*)$/i) {
1075 $hopts->{$1} = $2;
1076 }
1077 }
1078 }
1079
10801900ns my $contentType = $hopts->{'Content-Type'};
10811200ns $contentType = 'text/html' unless $contentType;
108215µs $contentType .= '; charset=utf-8'
1083 if $contentType =~ m!^text/!
1084 && $contentType !~ /\bcharset\b/;
1085
1086 # use our version of the content type
10871700ns $hopts->{'Content-Type'} = $contentType;
1088
108916µs16µs $hopts->{'X-FoswikiAction'} = $this->{request}->action;
# spent 6µs making 1 call to Foswiki::Request::action
109013µs13µs $hopts->{'X-FoswikiURI'} = $this->{request}->uri;
# spent 3µs making 1 call to Foswiki::Request::uri
1091
1092 # Turn off XSS protection in DEBUG so it doesn't mask problems
1093 $hopts->{'X-XSS-Protection'} = 0 if DEBUG;
1094
109512µs150µs $this->{plugins}
# spent 50µs making 1 call to Foswiki::Plugins::dispatch
1096 ->dispatch( 'modifyHeaderHandler', $hopts, $this->{request} );
1097
1098 # The headers method resets all headers to what we pass
1099 # what we want is simply ensure our headers are there
110018µs142µs $this->{response}->setDefaultHeaders($hopts);
# spent 42µs making 1 call to Foswiki::Response::setDefaultHeaders
1101}
1102
1103# Tests if the $redirect is an external URL, returning false if
1104# AllowRedirectUrl is denied
1105sub _isRedirectSafe {
1106 my $redirect = shift;
1107
1108 return 1 if ( $Foswiki::cfg{AllowRedirectUrl} );
1109 return 1 if $redirect =~ m#^/#; # relative URL - OK
1110
1111 #TODO: this should really use URI
1112 # Compare protocol, host name and port number
1113 if ( $redirect =~ m!^(.*?://[^/?#]*)! ) {
1114
1115 # implicit untaints OK because result not used. uc retaints
1116 # if use locale anyway.
1117 my $target = uc($1);
1118
1119 $Foswiki::cfg{DefaultUrlHost} =~ m!^(.*?://[^/]*)!;
1120 return 1 if ( $target eq uc($1) );
1121
1122 if ( $Foswiki::cfg{PermittedRedirectHostUrls} ) {
1123 foreach my $red (
1124 split( /\s*,\s*/, $Foswiki::cfg{PermittedRedirectHostUrls} ) )
1125 {
1126 $red =~ m!^(.*?://[^/]*)!;
1127 return 1 if ( $target eq uc($1) );
1128 }
1129 }
1130 }
1131 return 0;
1132}
1133
1134=begin TML
1135
1136---++ ObjectMethod redirectto($url) -> $url
1137
1138If the CGI parameter 'redirectto' is present on the query, then will validate
1139that it is a legal redirection target (url or topic name). If 'redirectto'
1140is not present on the query, performs the same steps on $url.
1141
1142Returns undef if the target is not valid, and the target URL otherwise.
1143
1144=cut
1145
1146sub redirectto {
1147 my ( $this, $url ) = @_;
1148
1149 my $redirecturl = $this->{request}->param('redirectto');
1150 $redirecturl = $url unless $redirecturl;
1151
1152 return unless $redirecturl;
1153
1154 if ( $redirecturl =~ m#^$regex{linkProtocolPattern}://# ) {
1155
1156 # assuming URL
1157 return $redirecturl if _isRedirectSafe($redirecturl);
1158 return;
1159 }
1160
1161 my @attrs = ();
1162
1163 # capture anchor
1164 if ( $redirecturl =~ s/#(.*)// ) {
1165 push( @attrs, '#' => $1 );
1166 }
1167
1168 # capture params
1169 if ( $redirecturl =~ s/\?(.*)// ) {
1170 push( @attrs, map { split( '=', $_, 2 ) } split( /[;&]/, $1 ) );
1171 }
1172
1173 # assuming 'web.topic' or 'topic'
1174 my ( $w, $t ) =
1175 $this->normalizeWebTopicName( $this->{webName}, $redirecturl );
1176
1177 return $this->getScriptUrl( 0, 'view', $w, $t, @attrs );
1178}
1179
1180=begin TML
1181
1182---++ StaticMethod splitAnchorFromUrl( $url ) -> ( $url, $anchor )
1183
1184Takes a full url (including possible query string) and splits off the anchor.
1185The anchor includes the # sign. Returns an empty string if not found in the url.
1186
1187=cut
1188
1189sub splitAnchorFromUrl {
1190 my ($url) = @_;
1191
1192 ( $url, my $anchor ) = $url =~ m/^(.*?)(#(.*?))*$/;
1193 return ( $url, $anchor );
1194}
1195
1196=begin TML
1197
1198---++ ObjectMethod redirect( $url, $passthrough, $status )
1199
1200 * $url - url or topic to redirect to
1201 * $passthrough - (optional) parameter to pass through current query
1202 parameters (see below)
1203 * $status - HTTP status code (30x) to redirect with. Defaults to 302.
1204
1205Redirects the request to =$url=, *unless*
1206 1 It is overridden by a plugin declaring a =redirectCgiQueryHandler=
1207 (a dangerous, deprecated handler!)
1208 1 =$session->{request}= is =undef=
1209Thus a redirect is only generated when in a CGI context.
1210
1211Normally this method will ignore parameters to the current query. Sometimes,
1212for example when redirecting to a login page during authentication (and then
1213again from the login page to the original requested URL), you want to make
1214sure all parameters are passed on, and for this $passthrough should be set to
1215true. In this case it will pass all parameters that were passed to the
1216current query on to the redirect target. If the request_method for the
1217current query was GET, then all parameters will be passed by encoding them
1218in the URL (after ?). If the request_method was POST, then there is a risk the
1219URL would be too big for the receiver, so it caches the form data and passes
1220over a cache reference in the redirect GET.
1221
1222NOTE: Passthrough is only meaningful if the redirect target is on the same
1223server.
1224
1225=cut
1226
1227sub redirect {
1228 my ( $this, $url, $passthru, $status ) = @_;
1229 ASSERT( defined $url ) if DEBUG;
1230
1231 return unless $this->{request};
1232
1233 ( $url, my $anchor ) = splitAnchorFromUrl($url);
1234
1235 if ( $passthru && defined $this->{request}->method() ) {
1236 my $existing = '';
1237 if ( $url =~ s/\?(.*)$// ) {
1238 $existing = $1; # implicit untaint OK; recombined later
1239 }
1240 if ( uc( $this->{request}->method() ) eq 'POST' ) {
1241
1242 # Redirecting from a post to a get
1243 my $cache = $this->cacheQuery();
1244 if ($cache) {
1245 if ( $url eq '/' ) {
1246 $url = $this->getScriptUrl( 1, 'view' );
1247 }
1248 $url .= $cache;
1249 }
1250 }
1251 else {
1252
1253 # Redirecting a get to a get; no need to use passthru
1254 if ( $this->{request}->query_string() ) {
1255 $url .= '?' . $this->{request}->query_string();
1256 }
1257 if ($existing) {
1258 if ( $url =~ m/\?/ ) {
1259 $url .= ';';
1260 }
1261 else {
1262 $url .= '?';
1263 }
1264 $url .= $existing;
1265 }
1266 }
1267 }
1268
1269 # prevent phishing by only allowing redirect to configured host
1270 # do this check as late as possible to catch _any_ last minute hacks
1271 # TODO: this should really use URI
1272 if ( !_isRedirectSafe($url) ) {
1273
1274 # goto oops if URL is trying to take us somewhere dangerous
1275 $url = $this->getScriptUrl(
1276 1, 'oops',
1277 $this->{webName} || $Foswiki::cfg{UsersWebName},
1278 $this->{topicName} || $Foswiki::cfg{HomeTopicName},
1279 template => 'oopsredirectdenied',
1280 def => 'redirect_denied',
1281 param1 => "$url",
1282 param2 => "$Foswiki::cfg{DefaultUrlHost}",
1283 );
1284 }
1285
1286 $url .= $anchor if $anchor;
1287
1288 # Dangerous, deprecated handler! Might work, probably won't.
1289 return
1290 if ( $this->{plugins}
1291 ->dispatch( 'redirectCgiQueryHandler', $this->{response}, $url ) );
1292
1293 $url = $this->getLoginManager()->rewriteRedirectUrl($url);
1294
1295 # Foswiki::Response::redirect doesn't automatically pass on the cookies
1296 # for us, so we have to do it explicitly; otherwise the session cookie
1297 # won't get passed on.
1298 $this->{response}->redirect(
1299 -url => $url,
1300 -cookies => $this->{response}->cookies(),
1301 -status => $status,
1302 );
1303}
1304
1305=begin TML
1306
1307---++ ObjectMethod cacheQuery() -> $queryString
1308
1309Caches the current query in the params cache, and returns a rewritten
1310query string for the cache to be picked up again on the other side of a
1311redirect.
1312
1313We can't encode post params into a redirect, because they may exceed the
1314size of the GET request. So we cache the params, and reload them when the
1315redirect target is reached.
1316
1317=cut
1318
1319sub cacheQuery {
1320 my $this = shift;
1321 my $query = $this->{request};
1322
1323 return '' unless ( $query->param() );
1324
1325 # Don't double-cache
1326 return '' if ( $query->param('foswiki_redirect_cache') );
1327
1328 require Foswiki::Request::Cache;
1329 my $uid = Foswiki::Request::Cache->new()->save($query);
1330 if ( $Foswiki::cfg{UsePathForRedirectCache} ) {
1331 return '/foswiki_redirect_cache/' . $uid;
1332 }
1333 else {
1334 return '?foswiki_redirect_cache=' . $uid;
1335 }
1336}
1337
1338=begin TML
1339
1340---++ ObjectMethod getCGISession() -> $cgisession
1341
1342Get the CGI::Session object associated with this session, if there is
1343one. May return undef.
1344
1345=cut
1346
1347
# spent 37µs (11+26) within Foswiki::getCGISession which was called 2 times, avg 18µs/call: # 2 times (11µs+26µs) by Foswiki::Plugins::SubscribePlugin::_getNonce at line 180 of /var/www/foswikidev/core/lib/Foswiki/Plugins/SubscribePlugin.pm, avg 18µs/call
sub getCGISession {
1348211µs226µs $_[0]->{users}->getCGISession();
# spent 26µs making 2 calls to Foswiki::Users::getCGISession, avg 13µs/call
1349}
1350
1351=begin TML
1352
1353---++ ObjectMethod getLoginManager() -> $loginManager
1354
1355Get the Foswiki::LoginManager object associated with this session, if there is
1356one. May return undef.
1357
1358=cut
1359
1360
# spent 83µs (56+27) within Foswiki::getLoginManager which was called 10 times, avg 8µs/call: # 5 times (27µs+17µs) by Foswiki::Render::getRenderedVersion at line 567 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 9µs/call # once (13µs+3µs) by Foswiki::Func::setSessionValue at line 428 of /var/www/foswikidev/core/lib/Foswiki/Func.pm # once (5µs+2µs) by Foswiki::LoginManager::_LOGIN at line 1366 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (5µs+2µs) by Foswiki::UI::__ANON__[/var/www/foswikidev/core/lib/Foswiki/UI.pm:376] at line 373 of /var/www/foswikidev/core/lib/Foswiki/UI.pm # once (3µs+1µs) by Foswiki::LoginManager::_LOGOUTURL at line 1387 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (3µs+1µs) by Foswiki::Func::clearSessionValue at line 445 of /var/www/foswikidev/core/lib/Foswiki/Func.pm
sub getLoginManager {
13611051µs1027µs $_[0]->{users}->getLoginManager();
# spent 27µs making 10 calls to Foswiki::Users::getLoginManager, avg 3µs/call
1362}
1363
1364=begin TML
1365
1366---++ StaticMethod isValidWikiWord( $name ) -> $boolean
1367
1368Check for a valid WikiWord or WikiName
1369
1370=cut
1371
1372sub isValidWikiWord {
1373 my $name = shift || '';
1374 return ( $name =~ m/^$regex{wikiWordRegex}$/ );
1375}
1376
1377=begin TML
1378
1379---++ StaticMethod isValidTopicName( $name [, $nonww] ) -> $boolean
1380
1381Check for a valid topic =$name=. If =$nonww=, then accept non wiki-words
1382(though they must still be composed of only valid, unfiltered characters)
1383
1384=cut
1385
1386# Note: must work on tainted names.
1387
# spent 1.00ms (422µs+579µs) within Foswiki::isValidTopicName which was called 17 times, avg 59µs/call: # 12 times (355µs+579µs) by Foswiki::_includeTopic at line 147 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 78µs/call # 5 times (68µs+0s) by Foswiki::Sandbox::validateTopicName at line 167 of /var/www/foswikidev/core/lib/Foswiki/Sandbox.pm, avg 14µs/call
sub isValidTopicName {
13881710µs my ( $name, $nonww ) = @_;
1389
1390178µs return 0 unless defined $name && $name ne '';
139117397µs3579µs return 1 if ( $name =~ m/^$regex{topicNameRegex}$/ );
# spent 579µs making 3 calls to utf8::SWASHNEW, avg 193µs/call
13923600ns return 0 unless $nonww;
1393312µs return 0 if $name =~ m/$cfg{NameFilter}/;
1394311µs return 1;
1395}
1396
1397=begin TML
1398
1399---++ StaticMethod isValidWebName( $name, $system ) -> $boolean
1400
1401STATIC Check for a valid web name. If $system is true, then
1402system web names are considered valid (names starting with _)
1403otherwise only user web names are valid
1404
1405If $Foswiki::cfg{EnableHierarchicalWebs} is off, it will also return false
1406when a nested web name is passed to it.
1407
1408=cut
1409
1410# Note: must work on tainted names.
1411
# spent 958µs (895+63) within Foswiki::isValidWebName which was called 106 times, avg 9µs/call: # 106 times (895µs+63µs) by Foswiki::Sandbox::validateWebName at line 152 of /var/www/foswikidev/core/lib/Foswiki/Sandbox.pm, avg 9µs/call
sub isValidWebName {
141210640µs my $name = shift || '';
141310632µs my $sys = shift;
1414106246µs return 1 if ( $sys && $name =~ m/^$regex{defaultWebNameRegex}$/ );
1415104720µs163µs return ( $name =~ m/^$regex{webNameRegex}$/ );
# spent 63µs making 1 call to utf8::SWASHNEW
1416}
1417
1418=begin TML
1419
1420---++ StaticMethod isValidEmailAddress( $name ) -> $boolean
1421
1422STATIC Check for a valid email address name.
1423
1424=cut
1425
1426# Note: must work on tainted names.
1427sub isValidEmailAddress {
1428 my $name = shift || '';
1429 return $name =~ m/^$regex{emailAddrRegex}$/;
1430}
1431
1432=begin TML
1433
1434---++ ObjectMethod getSkin () -> $string
1435
1436Get the currently requested skin path
1437
1438=cut
1439
1440
# spent 6.54ms (1.61+4.93) within Foswiki::getSkin which was called 50 times, avg 131µs/call: # 47 times (1.57ms+4.80ms) by Foswiki::Templates::readTemplate at line 248 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 135µs/call # 2 times (28µs+89µs) by Foswiki::UI::View::view at line 390 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm, avg 59µs/call # once (15µs+44µs) by Foswiki::UI::View::view at line 413 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm
sub getSkin {
14415049µs my $this = shift;
1442
14435017µs my @skinpath;
14445033µs my $skins;
1445
14465063µs if ( $this->{request} ) {
144750305µs501.97ms $skins = $this->{request}->param('cover');
# spent 1.97ms making 50 calls to Foswiki::Request::param, avg 39µs/call
14485016µs if ( defined $skins
1449 && $skins =~ m/([[:alnum:].,\s]+)/ )
1450 {
1451
1452 # Implicit untaint ok - validated
1453 $skins = $1;
1454 push( @skinpath, split( /,\s]+/, $skins ) );
1455 }
1456 }
1457
145850333µs502.19ms $skins = $this->{prefs}->getPreference('COVER');
# spent 2.19ms making 50 calls to Foswiki::Prefs::getPreference, avg 44µs/call
14595014µs if ( defined $skins
1460 && $skins =~ m/([[:alnum:].,\s]+)/ )
1461 {
1462
1463 # Implicit untaint ok - validated
1464 $skins = $1;
1465 push( @skinpath, split( /[,\s]+/, $skins ) );
1466 }
1467
146850155µs50761µs $skins = $this->{request} ? $this->{request}->param('skin') : undef;
# spent 761µs making 50 calls to Foswiki::Request::param, avg 15µs/call
14695015µs $skins = $this->{prefs}->getPreference('SKIN') unless $skins;
1470
147150184µs if ( defined $skins && $skins =~ m/([[:alnum:].,\s]+)/ ) {
1472
1473 # Implicit untaint ok - validated
14745062µs $skins = $1;
147550158µs push( @skinpath, split( /[,\s]+/, $skins ) );
1476 }
1477
147850215µs return join( ',', @skinpath );
1479}
1480
1481=begin TML
1482
1483---++ ObjectMethod getScriptUrl( $absolute, $script, $web, $topic, ... ) -> $scriptURL
1484
1485Returns the URL to a Foswiki script, providing the web and topic as
1486"path info" parameters. The result looks something like this:
1487"http://host/foswiki/bin/$script/$web/$topic".
1488 * =...= - an arbitrary number of name,value parameter pairs that will
1489be url-encoded and added to the url. The special parameter name '#' is
1490reserved for specifying an anchor. e.g.
1491=getScriptUrl('x','y','view','#'=>'XXX',a=>1,b=>2)= will give
1492=.../view/x/y?a=1&b=2#XXX=
1493
1494If $absolute is set, generates an absolute URL. $absolute is advisory only;
1495Foswiki can decide to generate absolute URLs (for example when run from the
1496command-line) even when relative URLs have been requested.
1497
1498The default script url is taken from {ScriptUrlPath}, unless there is
1499an exception defined for the given script in {ScriptUrlPaths}. Both
1500{ScriptUrlPath} and {ScriptUrlPaths} may be absolute or relative URIs. If
1501they are absolute, then they will always generate absolute URLs. if they
1502are relative, then they will be converted to absolute when required (e.g.
1503when running from the command line, or when generating rss). If
1504$script is not given, absolute URLs will always be generated.
1505
1506If 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.
1507
1508As required by RFC3986, the returned URL will only contain the
1509allowed characters -A-Za-z0-9_.~!*\'();:@&=+$,/?%#[]
1510
1511=cut
1512
1513
# spent 1.43ms (757µs+668µs) within Foswiki::getScriptUrl which was called 54 times, avg 26µs/call: # 30 times (356µs+120µs) by Foswiki::SCRIPTURL at line 30 of /var/www/foswikidev/core/lib/Foswiki/Macros/SCRIPTURL.pm, avg 16µs/call # 18 times (289µs+317µs) by Foswiki::Render::_renderExistingWikiWord at line 1336 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 34µs/call # 2 times (44µs+112µs) by Foswiki::UI::View::revisionsAround at line 559 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm, avg 78µs/call # 2 times (31µs+70µs) by Foswiki::UI::View::revisionsAround at line 547 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm, avg 51µs/call # once (19µs+44µs) by Foswiki::LoginManager::_LOGOUTURL at line 1389 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (19µs+5µs) by Foswiki::Func::getScriptUrl at line 182 of /var/www/foswikidev/core/lib/Foswiki/Func.pm
sub getScriptUrl {
15145456µs my ( $this, $absolute, $script, $web, $topic, @params ) = @_;
1515
15165453µs4072µs $absolute ||=
# spent 72µs making 40 calls to Foswiki::inContext, avg 2µs/call
1517 ( $this->inContext('command_line') || $this->inContext('absolute_urls') );
1518
1519 # SMELL: topics and webs that contain spaces?
1520
1521546µs my $url;
15225450µs if ( defined $Foswiki::cfg{ScriptUrlPaths} && $script ) {
1523 $url = $Foswiki::cfg{ScriptUrlPaths}{$script};
1524 }
15255412µs unless ( defined($url) ) {
15261610µs $url = $Foswiki::cfg{ScriptUrlPath};
1527166µs if ($script) {
15281411µs $url .= '/' unless $url =~ m/\/$/;
1529145µs $url .= $script;
15301436µs if (
1531 rindex( $url, $Foswiki::cfg{ScriptSuffix} ) !=
1532 ( length($url) - length( $Foswiki::cfg{ScriptSuffix} ) ) )
1533 {
1534 $url .= $Foswiki::cfg{ScriptSuffix} if $script;
1535 }
1536 }
1537 }
1538
15395485µs if ( $absolute && $url !~ /^[a-z]+:/ ) {
1540
1541 # See http://www.ietf.org/rfc/rfc2396.txt for the definition of
1542 # "absolute URI". Foswiki bastardises this definition by assuming
1543 # that all relative URLs lack the <authority> component as well.
1544 $url = $this->{urlHost} . $url;
1545 }
1546
15475416µs if ($topic) {
15482350µs23120µs ( $web, $topic ) = $this->normalizeWebTopicName( $web, $topic );
# spent 120µs making 23 calls to Foswiki::normalizeWebTopicName, avg 5µs/call
1549
15502347µs23194µs $url .= urlEncode( '/' . $web . '/' . $topic );
# spent 194µs making 23 calls to Foswiki::urlEncode, avg 8µs/call
1551
1552 }
1553 elsif ($web) {
1554 $url .= urlEncode( '/' . $web );
1555 }
15565473µs54282µs $url .= make_params(@params);
# spent 282µs making 54 calls to Foswiki::make_params, avg 5µs/call
1557
155854124µs return $url;
1559}
1560
1561=begin TML
1562
1563---++ StaticMethod make_params(...)
1564Generate a URL parameters string from parameters given. A parameter
1565named '#' will generate a fragment identifier.
1566
1567=cut
1568
1569
# spent 282µs (201+81) within Foswiki::make_params which was called 54 times, avg 5µs/call: # 54 times (201µs+81µs) by Foswiki::getScriptUrl at line 1556, avg 5µs/call
sub make_params {
15705416µs my $url = '';
1571545µs my @ps;
1572547µs my $anchor = '';
15735443µs while ( my $p = shift @_ ) {
157473µs if ( $p eq '#' ) {
1575 $anchor = '#' . urlEncode( shift(@_) );
1576 }
1577 else {
157872µs my $v = shift(@_);
157971µs $v = '' unless defined $v;
1580716µs1481µs push( @ps, urlEncode($p) . '=' . urlEncode($v) );
# spent 81µs making 14 calls to Foswiki::urlEncode, avg 6µs/call
1581 }
1582 }
15835417µs if ( scalar(@ps) ) {
1584 @ps = sort(@ps) if (DEBUG);
158554µs $url .= '?' . join( ';', @ps );
1586 }
158754131µs return $url . $anchor;
1588}
1589
1590=begin TML
1591
1592---++ ObjectMethod getPubURL($web, $topic, $attachment, %options) -> $url
1593
1594Composes a pub url.
1595 * =$web= - name of the web for the URL, defaults to $session->{webName}
1596 * =$topic= - name of the topic, defaults to $session->{topicName}
1597 * =$attachment= - name of the attachment, defaults to no attachment
1598Supported %options are:
1599 * =topic_version= - version of topic to retrieve attachment from
1600 * =attachment_version= - version of attachment to retrieve
1601 * =absolute= - requests an absolute URL (rather than a relative path)
1602
1603If =$web= is not given, =$topic= and =$attachment= are ignored.
1604If =$topic= is not given, =$attachment= is ignored.
1605
1606If =topic_version= is not given, the most recent revision of the topic
1607will be linked. Similarly if attachment_version= is not given, the most recent
1608revision of the attachment will be assumed. If =topic_version= is specified
1609but =attachment_version= is not (or the specified =attachment_version= is not
1610present), then the most recent version of the attachment in that topic version
1611will be linked.
1612
1613If Foswiki is running in an absolute URL context (e.g. the skin requires
1614absolute URLs, such as print or rss, or Foswiki is running from the
1615command-line) then =absolute= will automatically be set.
1616
1617Note: for compatibility with older plugins, which use %PUBURL*% with
1618a constructed URL path, do not use =*= unless =web=, =topic=, and
1619=attachment= are all specified.
1620
1621As required by RFC3986, the returned URL will only contain the
1622allowed characters -A-Za-z0-9_.~!*\'();:@&=+$,/?%#[]
1623
1624=cut
1625
1626
# spent 940µs (476+464) within Foswiki::getPubURL which was called 59 times, avg 16µs/call: # 47 times (354µs+314µs) by Foswiki::PUBURL at line 25 of /var/www/foswikidev/core/lib/Foswiki/Macros/PUBURL.pm, avg 14µs/call # 11 times (111µs+88µs) by Foswiki::Func::getPubUrlPath at line 281 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 18µs/call # once (11µs+62µs) by Foswiki::_getIconURL at line 128 of /var/www/foswikidev/core/lib/Foswiki/Macros/ICON.pm
sub getPubURL {
16275968µs my ( $this, $web, $topic, $attachment, %options ) = @_;
1628
16295985µs5699µs $options{absolute} ||=
# spent 99µs making 56 calls to Foswiki::inContext, avg 2µs/call
1630 ( $this->inContext('command_line') || $this->inContext('absolute_urls') );
1631
163259244µs59365µs return $this->{store}
# spent 365µs making 59 calls to Foswiki::Store::getAttachmentURL, avg 6µs/call
1633 ->getAttachmentURL( $this, $web, $topic, $attachment, %options );
1634}
1635
1636=begin TML
1637
1638---++ ObjectMethod deepWebList($filter, $web) -> @list
1639
1640Deep list subwebs of the named web. $filter is a Foswiki::WebFilter
1641object that is used to filter the list. The listing of subwebs is
1642dependent on $Foswiki::cfg{EnableHierarchicalWebs} being true.
1643
1644Webs are returned as absolute web pathnames.
1645
1646=cut
1647
1648
# spent 37.7ms (230µs+37.5) within Foswiki::deepWebList which was called 2 times, avg 18.9ms/call: # 2 times (230µs+37.5ms) by Foswiki::Func::getListOfWebs at line 1543 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 18.9ms/call
sub deepWebList {
164922µs my ( $this, $filter, $rootWeb ) = @_;
16502300ns my @list;
165125µs221µs my $webObject = new Foswiki::Meta( $this, $rootWeb );
# spent 21µs making 2 calls to Foswiki::Meta::new, avg 11µs/call
165226µs217.9ms my $it = $webObject->eachWeb( $Foswiki::cfg{EnableHierarchicalWebs} );
# spent 17.9ms making 2 calls to Foswiki::Meta::eachWeb, avg 8.96ms/call
16532500ns return $it->all() unless $filter;
165425µs212µs while ( $it->hasNext() ) {
# spent 12µs making 2 calls to Foswiki::ListIterator::hasNext, avg 6µs/call
1655248µs my $w = $rootWeb || '';
1656245µs $w .= '/' if $w;
16572433µs24119µs $w .= $it->next();
# spent 119µs making 24 calls to Foswiki::ListIterator::next, avg 5µs/call
16582477µs4819.4ms if ( $filter->ok( $this, $w ) ) {
# spent 19.3ms making 24 calls to Foswiki::WebFilter::ok, avg 806µs/call # spent 88µs making 24 calls to Foswiki::ListIterator::hasNext, avg 4µs/call
1659 push( @list, $w );
1660 }
1661 }
1662216µs return @list;
1663}
1664
1665=begin TML
1666
1667---++ ObjectMethod normalizeWebTopicName( $web, $topic ) -> ( $web, $topic )
1668
1669Normalize a Web<nop>.<nop>TopicName
1670
1671See =Foswiki::Func= for a full specification of the expansion (not duplicated
1672here)
1673
1674*WARNING* if there is no web specification (in the web or topic parameters)
1675the web defaults to $Foswiki::cfg{UsersWebName}. If there is no topic
1676specification, or the topic is '0', the topic defaults to the web home topic
1677name.
1678
1679*WARNING* if the input topic name is tainted, then the output web and
1680topic names will be tainted.
1681
1682=cut
1683
1684
# spent 658ms (658+40µs) within Foswiki::normalizeWebTopicName which was called 99088 times, avg 7µs/call: # 98793 times (656ms+0s) by Foswiki::Func::normalizeWebTopicName at line 2970 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 7µs/call # 116 times (1.10ms+0s) by Foswiki::Templates::_readTemplateFile at line 535 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 9µs/call # 103 times (491µs+0s) by Foswiki::Func::_checkWTA at line 80 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 5µs/call # 23 times (120µs+0s) by Foswiki::getScriptUrl at line 1548, avg 5µs/call # 18 times (99µs+0s) by Foswiki::Render::_handleSquareBracketedLink at line 1562 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 5µs/call # 12 times (93µs+0s) by Foswiki::_includeTopic at line 143 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 8µs/call # 12 times (58µs+0s) by Foswiki::VAR at line 22 of /var/www/foswikidev/core/lib/Foswiki/Macros/VAR.pm, avg 5µs/call # 4 times (32µs+0s) by Foswiki::If::OP_istopic::evaluate at line 46 of /var/www/foswikidev/core/lib/Foswiki/If/OP_istopic.pm, avg 8µs/call # 3 times (18µs+0s) by Foswiki::REVINFO at line 27 of /var/www/foswikidev/core/lib/Foswiki/Macros/REVINFO.pm, avg 6µs/call # once (22µs+40µs) by Foswiki::_lookupIcon at line 34 of /var/www/foswikidev/core/lib/Foswiki/Macros/ICON.pm # once (13µs+0s) by Foswiki::Prefs::loadSitePreferences at line 381 of /var/www/foswikidev/core/lib/Foswiki/Prefs.pm # once (8µs+0s) by Foswiki::If::OP_allows::evaluate at line 48 of /var/www/foswikidev/core/lib/Foswiki/If/OP_allows.pm # once (7µs+0s) by Foswiki::_getIconURL at line 126 of /var/www/foswikidev/core/lib/Foswiki/Macros/ICON.pm
sub normalizeWebTopicName {
16859908859.6ms my ( $this, $web, $topic ) = @_;
1686
1687 ASSERT( defined $topic ) if DEBUG;
1688
1689 #SMELL: Item12567: Writing the separator as a character class for some reason
1690 # taints all the results including the data ouside the character class..
169199088255ms if ( defined $topic && $topic =~ m{^(.*)(?:\.|/)(.*?)$} ) {
16923518234.0ms $web = $1;
16933518210.5ms $topic = $2;
1694
1695351826.53ms if ( DEBUG && !UNTAINTED( $_[2] ) ) {
1696
1697 # retaint data untainted by RE above
1698 $web = TAINT($web);
1699 $topic = TAINT($topic);
1700 }
1701 }
17029908814.1ms $web ||= $cfg{UsersWebName};
1703990889.95ms $topic ||= $cfg{HomeTopicName};
1704
1705 # MAINWEB and TWIKIWEB expanded for compatibility reasons
17069908898.2ms while (
1707 $web =~ s/%((MAIN|TWIKI|USERS|SYSTEM|DOC)WEB)%/
170815µs10s $this->_expandMacroOnTopicRendering( $1 ) || ''/e
# spent 40µs making 1 call to Foswiki::_expandMacroOnTopicRendering, recursion: max depth 3, sum of overlapping time 40µs
1709 )
1710 {
1711 }
1712
1713 # Normalize web name to use / and not . as a subweb separator
17149908828.9ms $web =~ s#\.#/#g;
1715
171699088493ms return ( $web, $topic );
1717}
1718
1719=begin TML
1720
1721---++ StaticMethod load_package( $full_package_name )
1722
1723Will cleanly load the package or fail. This is better than 'eval "require $package"'.
1724
1725It is not perfect for Perl < 5.10. For Perl 5.8, if somewhere else 'eval "require $package"'
1726was used *earlier* for a module that fails to load, then not only is the failure not detected
1727then. Neither will it be detected here.
1728
1729The recommendation is to replace all dynamic require calls in Foswiki to be replaced with this call.
1730
1731This functionality used to be done via module Class::Load, but that had painful dependencies.
1732
1733See http://blog.fox.geek.nz/2010/11/searching-design-spec-for-ultimate.html for the gory details.
1734
1735=cut
1736
1737
# spent 17.6ms (225µs+17.3) within Foswiki::load_package which was called: # once (225µs+17.3ms) by Foswiki::new at line 2105
sub load_package {
17381700ns my $fullname = shift;
1739
1740 # Is it already loaded? If so, it might be an internal class an missing
1741 # from @INC, so skip it. See perldoc UNIVERSAL for what this does.
174229µs12µs return if eval { $fullname->isa($fullname) };
# spent 2µs making 1 call to UNIVERSAL::isa
1743
174414µs $fullname =~ s{::}{/}g;
17451500ns $fullname .= '.pm';
1746180µs require $fullname;
1747}
1748
1749=begin TML
1750
1751---++ Private _parsePath( $this, $webtopic, $defaultweb, $topicOverride )
1752
1753Parses the Web/Topic path parameters to safely establish a valid web and topic,
1754or assign safe defaults.
1755
1756 * $webtopic - A "web/topic" path. It might have originated from the query path_info,
1757 or from the topic= URL parameter. (only when the topic param contained a web component)
1758 * $defaultweb - The default web to use if the web part of webtopic is missing or invalid.
1759 This can be from the default UsersWebName, or from the url parameter defaultweb.
1760 * $topicOverride - A topic name to use instead of any topic provided in the pathinfo.
1761
1762Note if $webtopic ends with a trailing slash, it provides a hint that the last component should be
1763considered web. This allows disambiguation between a topic and subweb with the same name.
1764Trailing slash forces it to be recognized as a webname, otherwise the topic is shown.
1765Note. If the web doesn't exist, the force will be ignored. It's not possible to create a missing web
1766by referencing it in a URL.
1767
1768This routine sets two variables when encountering invalid input:
1769 * $this->{invalidWeb} contains original invalid web / pathinfo content when validation fails.
1770 * $this->{invalidTopic} Same function but for topic name
1771When invalid / illegal characters are encountered, the session {webName} and {topicName} will be
1772defaulted to safe defaults. Scripts using those fields should also test if the corresponding
1773invalid* versions are defined, and should throw an oops exception rathern than allowing execution
1774to proceed with defaulted values.
1775
1776The topic name will always have the first character converted to upper case, to prevent creation of
1777or access to invalid topics.
1778
1779=cut
1780
1781
# spent 390µs (63+328) within Foswiki::_parsePath which was called: # once (63µs+328µs) by Foswiki::new at line 2210
sub _parsePath {
17821500ns my $this = shift;
17831300ns my $webtopic = shift;
17841300ns my $defaultweb = shift;
17851700ns my $topicOverride = shift;
1786
1787 #print STDERR "_parsePath called WT ($webtopic) DEF ($defaultweb)\n";
1788
178911µs my $trailingSlash = ( $webtopic =~ s/\/$// );
1790
1791 #print STDERR "TRAILING = $trailingSlash\n";
1792
1793 # Remove any leading slashes or dots.
179411µs $webtopic =~ s/^[\/.]+//;
1795
179613µs my @parts = split /[\/.]+/, $webtopic;
17971200ns my $cur = 0;
17981200ns my @webs; # Collect valid webs from path
17991600ns my @badpath; # Collect all webs, including illegal
18001200ns my $temptopic; # Candidate topicname extracted from path, defaults.
1801
180211µs foreach (@parts) {
1803
1804 # Lax check on name to eliminate evil characters.
180536µs394µs my $p = Foswiki::Sandbox::untaint( $_,
# spent 94µs making 3 calls to Foswiki::Sandbox::untaint, avg 31µs/call
1806 \&Foswiki::Sandbox::validateTopicName );
18073500ns unless ($p) {
1808 push @badpath, $_;
1809 next;
1810 }
1811
181239µs if ( \$_ == \$parts[-1] ) { # This is the last part of path
1813
181416µs1140µs if ( $this->topicExists( join( '/', @webs ) || $defaultweb, $p )
# spent 140µs making 1 call to Foswiki::topicExists
1815 && !$trailingSlash )
1816 {
1817
1818 #print STDERR "Exists and no trailing slash\n";
1819
1820 # It exists in Store as a topic and there is no trailing slash
1821 $temptopic = $p || '';
1822 }
1823 elsif ( $this->webExists( join( '/', @webs, $p ) ) ) {
1824
1825 #print STDERR "Web Exists " . join( '/', @webs, $p ) . "\n";
1826
1827 # It exists in Store as a web
1828 push @badpath, $p;
1829 push @webs, $p;
1830 }
1831 elsif ($trailingSlash) {
1832
1833 #print STDERR "Web forced ...\n";
1834 if ( !$this->webExists( join( '/', @webs, $p ) )
1835 && $this->topicExists( join( '/', @webs ) || $defaultweb,
1836 $p ) )
1837 {
1838
1839 #print STDERR "Forced, but no such web, and topic exists";
1840 $temptopic = $p;
1841 }
1842 else {
1843
1844 #print STDERR "Append it to the webs\n";
1845 $p = Foswiki::Sandbox::untaint( $p,
1846 \&Foswiki::Sandbox::validateWebName );
1847
1848 unless ($p) {
1849 push @badpath, $_;
1850 next;
1851 }
1852 else {
1853 push @badpath, $p;
1854 push @webs, $p;
1855 }
1856 }
1857 }
1858 else {
1859 #print STDERR "Just a topic. " . scalar @webs . "\n";
1860 $temptopic = $p;
1861 }
1862 }
1863 else {
186425µs264µs $p = Foswiki::Sandbox::untaint( $p,
# spent 64µs making 2 calls to Foswiki::Sandbox::untaint, avg 32µs/call
1865 \&Foswiki::Sandbox::validateWebName );
186621µs unless ($p) {
1867 push @badpath, $_;
1868 next;
1869 }
1870 else {
187121µs push @badpath, $p;
18722800ns push @webs, $p;
1873 }
1874 }
1875 }
1876
187711µs my $web = join( '/', @webs );
18781800ns my $badweb = join( '/', @badpath );
1879
1880 # Set the requestedWebName before applying defaults - used by statistics
1881 # generation. Note: This is validated using Topic name rules to permit
1882 # names beginning with lower case.
188313µs116µs $this->{requestedWebName} =
# spent 16µs making 1 call to Foswiki::Sandbox::untaint
1884 Foswiki::Sandbox::untaint( $badweb,
1885 \&Foswiki::Sandbox::validateTopicName );
1886
1887 #print STDERR "Set requestedWebName to $this->{requestedWebName} \n"
1888 # if $this->{requestedWebName};
1889
189012µs if ( length($web) != length($badweb) ) {
1891
1892 #print STDERR "RESULTS:\nPATH: $web\nBAD: $badweb\n";
1893 $this->{invalidWeb} = $badweb;
1894 }
1895
18961300ns unless ($web) {
1897 $web = Foswiki::Sandbox::untaint( $defaultweb,
1898 \&Foswiki::Sandbox::validateWebName );
1899 unless ($web) {
1900 $this->{invalidWeb} = $defaultweb;
1901 $web = $Foswiki::cfg{UsersWebName};
1902 }
1903 }
1904
1905 # Override topicname if urlparam $topic is provided.
19061300ns $temptopic = $topicOverride if ($topicOverride);
1907
1908 # Provide a default topic if none specified
19091400ns $temptopic = $Foswiki::cfg{HomeTopicName} unless defined($temptopic);
1910
1911 # Item3270 - here's the appropriate place to enforce spec
1912 # http://develop.twiki.org/~twiki4/cgi-bin/view/Bugs/Item3270
191314µs113µs my $topic =
# spent 13µs making 1 call to Foswiki::Sandbox::untaint
1914 Foswiki::Sandbox::untaint( ucfirst($temptopic),
1915 \&Foswiki::Sandbox::validateTopicName );
1916
19171200ns unless ($topic) {
1918 $this->{invalidTopic} = $temptopic;
1919 $topic = $Foswiki::cfg{HomeTopicName};
1920
1921 #print STDERR "RESULTS:\nTOPIC $topic\nBAD: $temptopic\n";
1922 $this->{invalidTopic} = $temptopic;
1923 }
1924
1925 #print STDERR "PARSE returns web $web topic $topic\n";
1926
192714µs return ( $web, $topic );
1928}
1929
1930=begin TML
1931
1932---++ ClassMethod new( $defaultUser, $query, \%initialContext )
1933
1934Constructs a new Foswiki session object. A unique session object exists for
1935every transaction with Foswiki, for example every browser request, or every
1936script run. Session objects do not persist between mod_perl runs.
1937
1938 * =$defaultUser= is the username (*not* the wikiname) of the default
1939 user you want to be logged-in, if none is available from a session
1940 or browser. Used mainly for unit tests and debugging, it is typically
1941 undef, in which case the default user is taken from
1942 $Foswiki::cfg{DefaultUserName}.
1943 * =$query= the Foswiki::Request query (may be undef, in which case an
1944 empty query is used)
1945 * =\%initialContext= - reference to a hash containing context
1946 name=value pairs to be pre-installed in the context hash. May be undef.
1947
1948=cut
1949
1950
# spent 251ms (231µs+251) within Foswiki::new which was called: # once (231µs+251ms) by Foswiki::UI::__ANON__[/var/www/foswikidev/core/lib/Foswiki/UI.pm:376] at line 363 of /var/www/foswikidev/core/lib/Foswiki/UI.pm
sub new {
195111µs my ( $class, $defaultUser, $query, $initialContext ) = @_;
1952
195312µs12µs Monitor::MARK("Static init over; make Foswiki object");
1954 ASSERT( !$query || UNIVERSAL::isa( $query, 'Foswiki::Request' ) )
1955 if DEBUG;
1956
1957 # Override user to be admin if no configuration exists.
1958 # Do this really early, so that later changes in isBOOTSTRAPPING can't change
1959 # Foswiki's behavior.
19601600ns $defaultUser = 'admin' if ( $Foswiki::cfg{isBOOTSTRAPPING} );
1961
196213µs unless ( $Foswiki::cfg{TempfileDir} ) {
1963
1964 # Give it a sane default.
1965 if ( $^O eq 'MSWin32' ) {
1966
1967 # Windows default tmpdir is the C: root use something sane.
1968 # Configure does a better job, it should be run.
1969 $Foswiki::cfg{TempfileDir} = $Foswiki::cfg{WorkingDir};
1970 }
1971 else {
197216µs145µs $Foswiki::cfg{TempfileDir} = File::Spec->tmpdir();
# spent 45µs making 1 call to File::Spec::Unix::tmpdir
1973 }
1974 }
1975
1976 # Cover all the possibilities
197713µs $ENV{TMPDIR} = $Foswiki::cfg{TempfileDir};
197812µs $ENV{TEMP} = $Foswiki::cfg{TempfileDir};
197912µs $ENV{TMP} = $Foswiki::cfg{TempfileDir};
1980
1981 # Make sure CGI is also using the appropriate tempfile location
19821300ns $CGI::TMPDIRECTORY = $Foswiki::cfg{TempfileDir};
1983
1984 # Make %ENV safer, preventing hijack of the search path. The
1985 # environment is set per-query, so this can't be done in a BEGIN.
1986 # This MUST be done before any external programs are run via Sandbox.
1987 # or it will fail with taint errors. See Item13237
19881800ns if ( defined $Foswiki::cfg{SafeEnvPath} ) {
1989 $ENV{PATH} = $Foswiki::cfg{SafeEnvPath};
1990 }
1991 else {
1992 # Default $ENV{PATH} must be untainted because
1993 # Foswiki may be run with the -T flag.
1994 # SMELL: how can we validate the PATH?
199514µs18µs $ENV{PATH} = Foswiki::Sandbox::untaintUnchecked( $ENV{PATH} );
# spent 8µs making 1 call to Foswiki::Sandbox::untaintUnchecked
1996 }
199716µs delete @ENV{qw( IFS CDPATH ENV BASH_ENV )};
1998
199911µs if ( $Foswiki::cfg{WarningFileName}
2000 && $Foswiki::cfg{Log}{Implementation} eq 'Foswiki::Logger::PlainFile' )
2001 {
2002
2003 # Admin has already expressed a preference for where they want their
2004 # logfiles to go, and has obviously not re-run configure yet.
2005 $Foswiki::cfg{Log}{Implementation} = 'Foswiki::Logger::Compatibility';
2006
2007#print STDERR "WARNING: Foswiki is using the compatibility logger. Please re-run configure and check your logfiles settings\n";
2008 }
2009
2010 # Make sure LogFielname is defined for use in old plugins,
2011 # but don't overwrite the setting from configure, if there is one.
2012 # This is especially important when the admin has *chosen*
2013 # to use the compatibility logger. (Some old TWiki heritage
2014 # plugins write directly to the configured LogFileName
20151400ns if ( not $Foswiki::cfg{LogFileName} ) {
201612µs if ( $Foswiki::cfg{Log}{Implementation} eq
2017 'Foswiki::Logger::Compatibility' )
2018 {
2019 my $stamp =
2020 Foswiki::Time::formatTime( time(), '$year$mo', 'servertime' );
2021 my $defaultLogDir = "$Foswiki::cfg{DataDir}";
2022 $Foswiki::cfg{LogFileName} = $defaultLogDir . "/log$stamp.txt";
2023
2024#print STDERR "Overrode LogFileName to $Foswiki::cfg{LogFileName} for CompatibilityLogger\n"
2025 }
2026 else {
202712µs $Foswiki::cfg{LogFileName} = "$Foswiki::cfg{Log}{Dir}/events.log";
2028
2029#print STDERR "Overrode LogFileName to $Foswiki::cfg{LogFileName} for PlainFileLogger\n"
2030 }
2031 }
2032
2033 # Set command_line context if there is no query
20341300ns $initialContext ||= defined($query) ? {} : { command_line => 1 };
2035
2036 # This foswiki supports:
20371600ns $initialContext->{SUPPORTS_PARA_INDENT} = 1; # paragraph indent
20381300ns $initialContext->{SUPPORTS_PREF_SET_URLS} = 1; # ?Set+, ?Local+ etc URLs
203911µs if ( $Foswiki::cfg{Password} ) {
2040 $initialContext->{admin_available} = 1; # True if sudo supported.
2041 }
2042
20431200ns $query ||= new Foswiki::Request();
2044
2045 # Phase 2 of Bootstrap. Web settings require that the Foswiki request
2046 # has been parsed.
20471300ns if ( $Foswiki::cfg{isBOOTSTRAPPING} ) {
2048 my $phase2_message =
2049 Foswiki::Configure::Load::bootstrapWebSettings( $query->action() );
2050 unless ($system_message) { # Don't do this more than once.
2051 $system_message =
2052 ( $Foswiki::cfg{Engine} && $Foswiki::cfg{Engine} !~ /CLI/i )
2053 ? ( '<div class="foswikiHelp"> '
2054 . $bootstrap_message
2055 . $phase2_message
2056 . '</div>' )
2057 : $bootstrap_message . $phase2_message;
2058 }
2059 }
2060
206117µs my $this = bless( { sandbox => 'Foswiki::Sandbox' }, $class );
2062
206312µs12µs if (SINGLE_SINGLETONS_TRACE) {
# spent 2µs making 1 call to Foswiki::SINGLE_SINGLETONS_TRACE
2064 require Data::Dumper;
2065 print STDERR "new $this: "
2066 . Data::Dumper->Dump( [ [caller], [ caller(1) ] ] );
2067 }
2068
20691700ns $this->{request} = $query;
20701300ns $this->{cgiQuery} = $query; # for backwards compatibility in contribs
207114µs110µs $this->{response} = new Foswiki::Response();
# spent 10µs making 1 call to Foswiki::Response::new
2072
2073 # This is required in case we get an exception during
2074 # initialisation, so that we have a session to handle it with.
207511µs11µs ASSERT( !$Foswiki::Plugins::SESSION ) if SINGLE_SINGLETONS;
# spent 1µs making 1 call to Foswiki::SINGLE_SINGLETONS
20761300ns $Foswiki::Plugins::SESSION = $this;
2077 ASSERT( $Foswiki::Plugins::SESSION->isa('Foswiki') ) if DEBUG;
2078
2079 # hash of zone records
20801500ns $this->{_zones} = ();
2081
2082 # hash of occurences of RENDERZONE
20831200ns $this->{_renderZonePlaceholder} = ();
2084
20851600ns $this->{context} = $initialContext;
2086
2087 # Construct the plugins objects and load the code for the plugins,
2088 # calling any preload handlers.
208915µs1118ms $this->{plugins} = new Foswiki::Plugins($this);
# spent 118ms making 1 call to Foswiki::Plugins::new
2090
209112µs if ( $Foswiki::cfg{Cache}{Enabled} && $Foswiki::cfg{Cache}{Implementation} )
2092 {
2093 eval "require $Foswiki::cfg{Cache}{Implementation}";
2094 ASSERT( !$@, $@ ) if DEBUG;
2095 $this->{cache} = $Foswiki::cfg{Cache}{Implementation}->new();
2096 }
2097
2098111µs11.16ms my $prefs = new Foswiki::Prefs($this);
# spent 1.16ms making 1 call to Foswiki::Prefs::new
209911µs $this->{prefs} = $prefs;
2100
2101 # construct the store object
210212µs my $base = $Foswiki::cfg{Store}{Implementation}
2103 || 'Foswiki::Store::PlainFile';
2104
210513µs117.6ms load_package($base);
# spent 17.6ms making 1 call to Foswiki::load_package
2106
210712µs foreach my $class ( @{ $Foswiki::cfg{Store}{ImplementationClasses} } ) {
2108
2109 # this allows us to add an arbitary set of mixins for things
2110 # like recordChanges
2111
2112 # Rejig the store impl's ISA to use each Class in order.'
2113 load_package($class);
2114245µs238µs
# spent 24µs (10+14) within Foswiki::BEGIN@2114 which was called: # once (10µs+14µs) by main::BEGIN@27 at line 2114
no strict 'refs';
# spent 24µs making 1 call to Foswiki::BEGIN@2114 # spent 14µs making 1 call to strict::unimport
2115 push( @{ $class . '::ISA' }, $base );
211626.58ms229µs
# spent 19µs (9+10) within Foswiki::BEGIN@2116 which was called: # once (9µs+10µs) by main::BEGIN@27 at line 2116
use strict 'refs';
# spent 19µs making 1 call to Foswiki::BEGIN@2116 # spent 10µs making 1 call to strict::import
2117 $base = $class;
2118 }
2119
212018µs112µs $this->{store} = $base->new();
# spent 12µs making 1 call to Foswiki::Store::new
2121 ASSERT( $this->{store}, "no $base object created" ) if DEBUG;
2122
2123 #Monitor::MARK("Created store");
2124
2125120µs113µs $this->{digester} = new Digest::MD5();
# spent 13µs making 1 call to Digest::MD5::new
212616µs18.55ms $this->{users} = new Foswiki::Users($this);
# spent 8.55ms making 1 call to Foswiki::Users::new
2127
2128 #Monitor::MARK("Created users object");
2129
2130 #{urlHost} is needed by loadSession..
213114µs1200µs my $url = $query->url();
# spent 200µs making 1 call to Foswiki::Request::url
213215µs if ( $url
2133 && !$Foswiki::cfg{ForceDefaultUrlHost}
2134 && $url =~ m{^([^:]*://[^/]*).*$} )
2135 {
213613µs $this->{urlHost} = $1;
2137
21381800ns if ( $Foswiki::cfg{RemovePortNumber} ) {
2139 $this->{urlHost} =~ s/\:[0-9]+$//;
2140 }
2141
2142 # If the urlHost in the url is localhost, this is a lot less
2143 # useful than the default url host. This is because new CGI("")
2144 # assigns this host by default - it's a default setting, used
2145 # when there is nothing better available.
214613µs if ( $this->{urlHost} =~ m/^(https?:\/\/)localhost$/i ) {
2147 my $protocol = $1;
2148
2149#only replace localhost _if_ the protocol matches the one specified in the DefaultUrlHost
2150 if ( $Foswiki::cfg{DefaultUrlHost} =~ m/^$protocol/i ) {
2151 $this->{urlHost} = $Foswiki::cfg{DefaultUrlHost};
2152 }
2153 }
2154 }
2155 else {
2156 $this->{urlHost} = $Foswiki::cfg{DefaultUrlHost};
2157 }
2158 ASSERT( $this->{urlHost} ) if DEBUG;
2159
2160 # Load (or create) the CGI session
216114µs1168µs $this->{remoteUser} = $this->{users}->loadSession($defaultUser);
# spent 168µs making 1 call to Foswiki::Users::loadSession
2162
216312µs $this->{scriptUrlPath} = $Foswiki::cfg{ScriptUrlPath};
21641500ns if ( $Foswiki::cfg{GetScriptUrlFromCgi}
2165 && $url
2166 && $url =~ m{^[^:]*://[^/]*(.*)/.*$}
2167 && $1 )
2168 {
2169
2170 # SMELL: this is a really dangerous hack. It will fail
2171 # spectacularly with mod_perl.
2172 # SMELL: why not just use $query->script_name?
2173 # SMELL: unchecked implicit untaint?
2174 $this->{scriptUrlPath} = $1;
2175 }
2176
2177 # The web/topic can be provided by either the query path_info,
2178 # or by URL Parameters:
2179 # topic: Specifies web.topic or topic.
2180 # Overrides the path given in the URL
2181 # defaultweb: Overrides the default web, for use when topic=
2182 # does not provide a web.
2183 # path_info Defaults to the Users web Home topic
2184
2185 # Set the default for web
2186 # Development.AddWebParamToAllCgiScripts: enables
2187 # bin/script?topic=WebPreferences;defaultweb=Sandbox
218813µs116µs my $defaultweb = $query->param('defaultweb') || $Foswiki::cfg{UsersWebName};
# spent 16µs making 1 call to Foswiki::Request::param
2189
219015µs271µs my $webtopic = urlDecode( $query->path_info() || '' );
# spent 69µs making 1 call to Foswiki::urlDecode # spent 2µs making 1 call to Foswiki::Request::pathInfo
21911400ns my $topicOverride = '';
219212µs116µs my $topic = $query->param('topic');
# spent 16µs making 1 call to Foswiki::Request::param
21931500ns if ( defined $topic ) {
219413µs if ( $topic =~ m/[\/.]+/ ) {
2195 $webtopic = $topic;
2196
2197 #print STDERR "candidate webtopic set to $webtopic by query param\n";
2198 }
2199 else {
2200 $topicOverride = $topic;
2201
2202 #print STDERR
2203 # "candidate topic set to $topicOverride by query param\n";
2204 }
2205 }
2206
2207 # SMELL Scripts like rest, jsonrpc, don't use web/topic path.
2208 # So this ends up all bogus, but doesn't do any harm.
2209
221015µs1390µs ( my $web, $topic ) =
# spent 390µs making 1 call to Foswiki::_parsePath
2211 $this->_parsePath( $webtopic, $defaultweb, $topicOverride );
2212
22131700ns $this->{topicName} = $topic;
22141500ns $this->{webName} = $web;
2215
2216 # Form definition cache
221711µs $this->{forms} = {};
2218
2219 # Push global preferences from %SYSTEMWEB%.DefaultPreferences
222014µs118.7ms $prefs->loadDefaultPreferences();
# spent 18.7ms making 1 call to Foswiki::Prefs::loadDefaultPreferences
2221
2222 #Monitor::MARK("Loaded default prefs");
2223
2224 # SMELL: what happens if we move this into the Foswiki::Users::new?
2225 # Note: The initializeUserHandler() can override settings like
2226 # topicName and webName. For example, HomePagePlugin.
222715µs13.11ms $this->{user} = $this->{users}->initialiseUser( $this->{remoteUser} );
# spent 3.11ms making 1 call to Foswiki::Users::initialiseUser
2228
2229 #Monitor::MARK("Initialised user");
2230
2231 # Static session variables that can be expanded in topics when they
2232 # are enclosed in % signs
2233 # SMELL: should collapse these into one. The duplication is pretty
2234 # pointless.
223514µs114µs $prefs->setInternalPreferences(
# spent 14µs making 1 call to Foswiki::Prefs::setInternalPreferences
2236 BASEWEB => $this->{webName},
2237 BASETOPIC => $this->{topicName},
2238 INCLUDINGTOPIC => $this->{topicName},
2239 INCLUDINGWEB => $this->{webName}
2240 );
2241
2242 # Push plugin settings
224312µs112.0ms $this->{plugins}->settings();
# spent 12.0ms making 1 call to Foswiki::Plugins::settings
2244
2245 # Now the rest of the preferences
224613µs1817µs $prefs->loadSitePreferences();
# spent 817µs making 1 call to Foswiki::Prefs::loadSitePreferences
2247
2248 # User preferences only available if we can get to a valid wikiname,
2249 # which depends on the user mapper.
225014µs148µs my $wn = $this->{users}->getWikiName( $this->{user} );
# spent 48µs making 1 call to Foswiki::Users::getWikiName
225113µs1734µs if ($wn) {
# spent 734µs making 1 call to Foswiki::Prefs::setUserPreferences
2252 $prefs->setUserPreferences($wn);
2253 }
2254
225513µs13.32ms $prefs->pushTopicContext( $this->{webName}, $this->{topicName} );
# spent 3.32ms making 1 call to Foswiki::Prefs::pushTopicContext
2256
2257 #Monitor::MARK("Preferences all set up");
2258
2259 # Set both isadmin and authenticated contexts. If the current user
2260 # is admin, then they either authenticated, or we are in bootstrap.
226113µs1110µs if ( $this->{users}->isAdmin( $this->{user} ) ) {
# spent 110µs making 1 call to Foswiki::Users::isAdmin
22621800ns $this->{context}{authenticated} = 1;
22631900ns $this->{context}{isadmin} = 1;
2264 }
2265
2266 # Finish plugin initialization - register handlers
226713µs165.8ms $this->{plugins}->enable();
# spent 65.8ms making 1 call to Foswiki::Plugins::enable
2268
226913µs12µs Monitor::MARK("Foswiki object created");
2270
227117µs return $this;
2272}
2273
2274=begin TML
2275
2276---++ ObjectMethod renderer()
2277Get a reference to the renderer object. Done lazily because not everyone
2278needs the renderer.
2279
2280=cut
2281
2282
# spent 9.03ms (7.85+1.19) within Foswiki::renderer which was called 14 times, avg 645µs/call: # 6 times (7.83ms+1.19ms) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 324 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 1.50ms/call # 5 times (12µs+0s) by Foswiki::Meta::renderTML at line 3367 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 2µs/call # 3 times (6µs+0s) by Foswiki::REVINFO at line 45 of /var/www/foswikidev/core/lib/Foswiki/Macros/REVINFO.pm, avg 2µs/call
sub renderer {
2283147µs my ($this) = @_;
2284
2285147µs unless ( $this->{renderer} ) {
2286181µs require Foswiki::Render;
228715µs110µs $this->{renderer} = new Foswiki::Render($this);
# spent 10µs making 1 call to Foswiki::Render::new
2288 }
22891442µs return $this->{renderer};
2290}
2291
2292=begin TML
2293
2294---++ ObjectMethod attach()
2295Get a reference to the attach object. Done lazily because not everyone
2296needs the attach.
2297
2298=cut
2299
2300
# spent 2.78ms (2.68+97µs) within Foswiki::attach which was called: # once (2.68ms+97µs) by Foswiki::META at line 40 of /var/www/foswikidev/core/lib/Foswiki/Macros/META.pm
sub attach {
230111µs my ($this) = @_;
2302
23031900ns unless ( $this->{attach} ) {
2304176µs require Foswiki::Attach;
230516µs112µs $this->{attach} = new Foswiki::Attach($this);
# spent 12µs making 1 call to Foswiki::Attach::new
2306 }
230714µs return $this->{attach};
2308}
2309
2310=begin TML
2311
2312---++ ObjectMethod templates()
2313Get a reference to the templates object. Done lazily because not everyone
2314needs the templates.
2315
2316=cut
2317
2318
# spent 3.45ms (3.22+237µs) within Foswiki::templates which was called 175 times, avg 20µs/call: # 40 times (230µs+0s) by Foswiki::Search::loadTemplates at line 495 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 6µs/call # 40 times (79µs+0s) by Foswiki::Search::loadTemplates at line 510 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (72µs+0s) by Foswiki::Search::loadTemplates at line 522 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (69µs+0s) by Foswiki::Search::loadTemplates at line 511 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 4 times (12µs+0s) by Foswiki::inlineAlert at line 2619, avg 3µs/call # 4 times (8µs+0s) by Foswiki::inlineAlert at line 2621, avg 2µs/call # 4 times (6µs+0s) by Foswiki::Func::expandTemplate at line 2600 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 2µs/call # once (2.74ms+237µs) by Foswiki::Func::readTemplate at line 2535 of /var/www/foswikidev/core/lib/Foswiki/Func.pm # once (2µs+0s) by Foswiki::Func::loadTemplate at line 2568 of /var/www/foswikidev/core/lib/Foswiki/Func.pm # once (2µs+0s) by Foswiki::UI::View::view at line 292 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm
sub templates {
231917573µs my ($this) = @_;
2320
232117584µs unless ( $this->{templates} ) {
2322186µs require Foswiki::Templates;
232316µs120µs $this->{templates} = new Foswiki::Templates($this);
# spent 20µs making 1 call to Foswiki::Templates::new
2324 }
2325175513µs return $this->{templates};
2326}
2327
2328=begin TML
2329
2330---++ ObjectMethod i18n()
2331Get a reference to the i18n object. Done lazily because not everyone
2332needs the i18ner.
2333
2334=cut
2335
2336
# spent 2.34ms (1.59+755µs) within Foswiki::i18n which was called 60 times, avg 39µs/call: # 57 times (1.58ms+755µs) by Foswiki::MAKETEXT at line 57 of /var/www/foswikidev/core/lib/Foswiki/Macros/MAKETEXT.pm, avg 41µs/call # 2 times (4µs+0s) by Foswiki::Plugins::SubscribePlugin::_SUBSCRIBE at line 95 of /var/www/foswikidev/core/lib/Foswiki/Plugins/SubscribePlugin.pm, avg 2µs/call # once (2µs+0s) by Foswiki::Plugins::JQueryPlugin::UI::init at line 63 of /var/www/foswikidev/core/lib/Foswiki/Plugins/JQueryPlugin/UI.pm
sub i18n {
23376021µs my ($this) = @_;
2338
23396021µs unless ( $this->{i18n} ) {
2340171µs require Foswiki::I18N;
2341
2342 # language information; must be loaded after
2343 # *all possible preferences sources* are available
234415µs1540µs $this->{i18n} = new Foswiki::I18N($this);
# spent 540µs making 1 call to Foswiki::I18N::new
2345 }
234660135µs return $this->{i18n};
2347}
2348
2349=begin TML
2350
2351---++ ObjectMethod reset_i18n()
2352Kill the i18n object, if there is one, to force language re-initialisation.
2353Essential for changing language dynamically.
2354
2355=cut
2356
2357sub reset_i18n {
2358 my $this = shift;
2359
2360 return unless $this->{i18n};
2361 $this->{i18n}->finish();
2362 undef $this->{i18n};
2363}
2364
2365=begin TML
2366
2367---++ ObjectMethod logger()
2368
2369=cut
2370
2371
# spent 4.47ms (1.83+2.64) within Foswiki::logger which was called: # once (1.83ms+2.64ms) by Foswiki::UI::View::view at line 256 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm
sub logger {
23721700ns my $this = shift;
2373
237411µs unless ( $this->{logger} ) {
237512µs if ( $Foswiki::cfg{Log}{Implementation} eq 'none' ) {
2376 $this->{logger} = Foswiki::Logger->new();
2377 }
2378 else {
2379126µs eval "require $Foswiki::cfg{Log}{Implementation}";
# spent 62µs executing statements in string eval
23801700ns if ($@) {
2381 print STDERR "Logger load failed: $@";
2382 $this->{logger} = Foswiki::Logger->new();
2383 }
2384 else {
238517µs19µs $this->{logger} = $Foswiki::cfg{Log}{Implementation}->new();
# spent 9µs making 1 call to Foswiki::Logger::PlainFile::new
2386 }
2387 }
2388 }
2389
239014µs return $this->{logger};
2391}
2392
2393=begin TML
2394
2395---++ ObjectMethod search()
2396Get a reference to the search object. Done lazily because not everyone
2397needs the searcher.
2398
2399=cut
2400
2401
# spent 101ms (94.3+7.13) within Foswiki::search which was called 52603 times, avg 2µs/call: # 17520 times (29.7ms+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:194] at line 176 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 2µs/call # 17520 times (29.4ms+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:194] at line 186 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 2µs/call # 8760 times (14.7ms+0s) by Foswiki::Search::InfoCache::addTopic at line 105 of /var/www/foswikidev/core/lib/Foswiki/Search/InfoCache.pm, avg 2µs/call # 8760 times (14.7ms+0s) by Foswiki::Store::QueryAlgorithms::BruteForce::_webQuery at line 203 of /var/www/foswikidev/core/lib/Foswiki/Store/QueryAlgorithms/BruteForce.pm, avg 2µs/call # 40 times (65µs+0s) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/SEARCH.pm:40] at line 39 of /var/www/foswikidev/core/lib/Foswiki/Macros/SEARCH.pm, avg 2µs/call # 3 times (5.74ms+7.13ms) by Foswiki::Meta::unload at line 504 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 4.29ms/call
sub search {
24025260317.2ms my ($this) = @_;
2403
24045260317.4ms unless ( $this->{search} ) {
2405173µs require Foswiki::Search;
240616µs115µs $this->{search} = new Foswiki::Search($this);
# spent 15µs making 1 call to Foswiki::Search::new
2407 }
240852603161ms return $this->{search};
2409}
2410
2411=begin TML
2412
2413---++ ObjectMethod net()
2414Get a reference to the net object. Done lazily because not everyone
2415needs the net.
2416
2417=cut
2418
2419sub net {
2420 my ($this) = @_;
2421
2422 unless ( $this->{net} ) {
2423 require Foswiki::Net;
2424 $this->{net} = new Foswiki::Net($this);
2425 }
2426 return $this->{net};
2427}
2428
2429=begin TML
2430
2431---++ ObjectMethod access()
2432Get a reference to the ACL object.
2433
2434=cut
2435
2436
# spent 8.48ms (1.12+7.36) within Foswiki::access which was called 504 times, avg 17µs/call: # 252 times (779µs+7.36ms) by Foswiki::Meta::haveAccess at line 1925 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 32µs/call # 252 times (342µs+0s) by Foswiki::Meta::haveAccess at line 1926 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 1µs/call
sub access {
2437504138µs my ($this) = @_;
2438
2439504142µs unless ( $this->{access} ) {
2440170µs require Foswiki::Access;
244114µs17.25ms $this->{access} = Foswiki::Access->new($this);
# spent 7.25ms making 1 call to Foswiki::Access::new
2442 }
2443 ASSERT( $this->{access} ) if DEBUG;
2444504973µs return $this->{access};
2445}
2446
2447=begin TML
2448
2449---++ ObjectMethod DESTROY()
2450
2451called by Perl when the Foswiki object goes out of scope
2452(maybe should be used kist to ASSERT that finish() was called..
2453
2454=cut
2455
2456#sub DESTROY {
2457# my $this = shift;
2458# $this->finish();
2459#}
2460
2461=begin TML
2462
2463---++ ObjectMethod finish()
2464Break circular references.
2465
2466=cut
2467
2468# Note to developers; please undef *all* fields in the object explicitly,
2469# whether they are references or not. That way this method is "golden
2470# documentation" of the live fields in the object.
2471
# spent 11.5ms (1.43+10.1) within Foswiki::finish which was called: # once (1.43ms+10.1ms) by Foswiki::UI::_execute at line 501 of /var/www/foswikidev/core/lib/Foswiki/UI.pm
sub finish {
24721600ns my $this = shift;
2473
2474 # Print any macros that are never loaded
2475 #print STDERR "NEVER USED\n";
2476 #for my $i (keys %macros) {
2477 # print STDERR "\t$i\n" unless defined $macros{$i};
2478 #}
247913µs $_->finish() foreach values %{ $this->{forms} };
248011µs undef $this->{forms};
248112µs foreach my $key (
2482 qw(plugins users prefs templates renderer net
2483 store search attach access i18n cache logger)
2484 )
2485 {
2486 next
24871315µs unless ref( $this->{$key} );
24881190µs1110.1ms $this->{$key}->finish();
# spent 6.10ms making 1 call to Foswiki::Search::finish # spent 1.35ms making 1 call to Foswiki::Users::finish # spent 988µs making 1 call to Foswiki::Templates::finish # spent 861µs making 1 call to Foswiki::Prefs::finish # spent 703µs making 1 call to Foswiki::Plugins::finish # spent 37µs making 1 call to Foswiki::I18N::Fallback::finish # spent 30µs making 1 call to Foswiki::Store::Rcs::Store::finish # spent 5µs making 1 call to Foswiki::Render::finish # spent 4µs making 1 call to Foswiki::Attach::finish # spent 3µs making 1 call to Foswiki::Access::finish # spent 3µs making 1 call to Foswiki::Logger::finish
2489111.10ms undef $this->{$key};
2490 }
2491
249213µs undef $this->{_zones};
2493110µs undef $this->{_renderZonePlaceholder};
2494
24951700ns undef $this->{request};
24961300ns undef $this->{cgiQuery};
2497
24981162µs undef $this->{digester};
249912µs111µs undef $this->{urlHost};
# spent 11µs making 1 call to Digest::MD5::DESTROY
250011µs undef $this->{web};
250111µs undef $this->{topic};
25021500ns undef $this->{webName};
25031300ns undef $this->{topicName};
250412µs undef $this->{invalidWeb};
25051600ns undef $this->{invalidTopic};
250612µs undef $this->{_ICONSPACE};
25071700ns undef $this->{_EXT2ICON};
25081900ns undef $this->{_KNOWNICON};
250911µs undef $this->{_ICONSTEMPLATE};
25101600ns undef $this->{context};
251112µs undef $this->{remoteUser};
25121600ns undef $this->{requestedWebName}; # Web name before renaming
25131800ns undef $this->{scriptUrlPath};
25141700ns undef $this->{user};
25151800ns undef $this->{_INCLUDES};
25161300ns undef $this->{response};
251711µs undef $this->{evaluating_if};
25181600ns undef $this->{_addedToHEAD};
251912µs undef $this->{sandbox};
25201500ns undef $this->{evaluatingEval};
25211400ns undef $this->{_ffCache};
2522
25231600ns undef $this->{DebugVerificationCode}; # from Foswiki::UI::Register
252414µs14µs if (SINGLE_SINGLETONS_TRACE) {
# spent 4µs making 1 call to Foswiki::SINGLE_SINGLETONS_TRACE
2525 require Data::Dumper;
2526 print STDERR "finish $this: "
2527 . Data::Dumper->Dump( [ [caller], [ caller(1) ] ] );
2528 }
252912µs12µs if (SINGLE_SINGLETONS) {
# spent 2µs making 1 call to Foswiki::SINGLE_SINGLETONS
2530 ASSERT( defined $Foswiki::Plugins::SESSION );
2531 ASSERT( $Foswiki::Plugins::SESSION == $this );
2532 ASSERT( $Foswiki::Plugins::SESSION->isa('Foswiki') );
2533 }
25341600ns undef $Foswiki::Plugins::SESSION;
2535
253615µs if (DEBUG) {
2537 my $remaining = join ',', grep { defined $this->{$_} } keys %$this;
2538 ASSERT( 0,
2539 "Fields with defined values in "
2540 . ref($this)
2541 . "->finish(): "
2542 . $remaining )
2543 if $remaining;
2544 }
2545}
2546
2547=begin TML
2548
2549---++ DEPRECATED ObjectMethod logEvent( $action, $webTopic, $extra, $user )
2550 * =$action= - what happened, e.g. view, save, rename
2551 * =$webTopic= - what it happened to
2552 * =$extra= - extra info, such as minor flag
2553 * =$user= - login name of user - default current user,
2554 or failing that the user agent
2555
2556Write the log for an event to the logfile
2557
2558The method is deprecated, Call logger->log directly.
2559
2560=cut
2561
2562sub logEvent {
2563 my $this = shift;
2564
2565 my $action = shift || '';
2566 my $webTopic = shift || '';
2567 my $extra = shift || '';
2568 my $user = shift;
2569
2570 $this->logger->log(
2571 {
2572 level => 'info',
2573 action => $action || '',
2574 webTopic => $webTopic || '',
2575 extra => $extra || '',
2576 user => $user,
2577 }
2578 );
2579}
2580
2581=begin TML
2582
2583---++ StaticMethod validatePattern( $pattern ) -> $pattern
2584
2585Validate a pattern provided in a parameter to $pattern so that
2586dangerous chars (interpolation and execution) are disabled.
2587
2588=cut
2589
2590sub validatePattern {
2591 my $pattern = shift;
2592
2593 # Escape unescaped $ and @ characters that might interpolate
2594 # an internal variable.
2595 # There is no need to defuse (??{ and (?{ as perl won't allow
2596 # it anyway, unless one uses re 'eval' which we won't do
2597 $pattern =~ s/(^|[^\\])([\$\@])/$1\\$2/g;
2598 return $pattern;
2599}
2600
2601=begin TML
2602
2603---++ ObjectMethod inlineAlert($template, $def, ... ) -> $string
2604
2605Format an error for inline inclusion in rendered output. The message string
2606is obtained from the template 'oops'.$template, and the DEF $def is
2607selected. The parameters (...) are used to populate %PARAM1%..%PARAMn%
2608
2609=cut
2610
2611
# spent 34.1ms (240µs+33.8) within Foswiki::inlineAlert which was called 4 times, avg 8.52ms/call: # 4 times (240µs+33.8ms) by Foswiki::_includeWarning at line 102 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 8.52ms/call
sub inlineAlert {
261242µs my $this = shift;
261342µs my $template = shift;
261442µs my $def = shift;
2615
2616 # web and topic can be anything; they are not used
2617414µs444µs my $topicObject =
# spent 44µs making 4 calls to Foswiki::Meta::new, avg 11µs/call
2618 Foswiki::Meta->new( $this, $this->{webName}, $this->{topicName} );
2619423µs830.0ms my $text = $this->templates->readTemplate( 'oops' . $template );
# spent 30.0ms making 4 calls to Foswiki::Templates::readTemplate, avg 7.50ms/call # spent 12µs making 4 calls to Foswiki::templates, avg 3µs/call
262043µs if ($text) {
2621416µs8274µs my $blah = $this->templates->expandTemplate($def);
# spent 266µs making 4 calls to Foswiki::Templates::expandTemplate, avg 67µs/call # spent 8µs making 4 calls to Foswiki::templates, avg 2µs/call
2622420µs $text =~ s/%INSTANTIATE%/$blah/;
2623
2624414µs40s $text = $topicObject->expandMacros($text);
# spent 3.52ms making 4 calls to Foswiki::Meta::expandMacros, avg 880µs/call, recursion: max depth 2, sum of overlapping time 3.52ms
262542µs my $n = 1;
2626411µs while ( defined( my $param = shift ) ) {
2627874µs $text =~ s/%PARAM$n%/$param/g;
262882µs $n++;
2629 }
2630
2631 # Suppress missing params
263247µs $text =~ s/%PARAM\d+%//g;
2633
2634 # Suppress missing params
263546µs $text =~ s/%PARAM\d+%//g;
2636 }
2637 else {
2638
2639 # Error in the template system.
2640 $text = $topicObject->renderTML(<<MESSAGE);
2641---+ Foswiki Installation Error
2642Template 'oops$template' not found or returned no text, expanding $def.
2643
2644Check your configuration settings for {TemplateDir} and {TemplatePath}
2645or check for syntax errors in templates, or a missing TMPL:END.
2646MESSAGE
2647 }
2648
2649420µs return $text;
2650}
2651
2652=begin TML
2653
2654---++ StaticMethod parseSections($text) -> ($string,$sectionlistref)
2655
2656Generic parser for sections within a topic. Sections are delimited
2657by STARTSECTION and ENDSECTION, which may be nested, overlapped or
2658otherwise abused. The parser builds an array of sections, which is
2659ordered by the order of the STARTSECTION within the topic. It also
2660removes all the SECTION tags from the text, and returns the text
2661and the array of sections.
2662
2663Each section is a =Foswiki::Attrs= object, which contains the attributes
2664{type, name, start, end}
2665where start and end are character offsets in the
2666string *after all section tags have been removed*. All sections
2667are required to be uniquely named; if a section is unnamed, it
2668will be given a generated name. Sections may overlap or nest.
2669
2670See test/unit/Fn_SECTION.pm for detailed testcases that
2671round out the spec.
2672
2673=cut
2674
2675
# spent 103µs within Foswiki::parseSections which was called 8 times, avg 13µs/call: # 8 times (103µs+0s) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 230 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 13µs/call
sub parseSections {
2676
267786µs my $text = shift;
2678
267982µs return ( '', [] ) unless defined $text;
2680
268181µs my %sections;
268284µs my @list = ();
2683
268482µs my $seq = 0;
268582µs my $ntext = '';
268681µs my $offset = 0;
2687826µs foreach
2688 my $bit ( split( /(%(?:START|STOP|END)SECTION(?:{.*?})?%)/, $text ) )
2689 {
2690819µs if ( $bit =~ m/^%STARTSECTION(?:{(.*)})?%$/ ) {
2691 require Foswiki::Attrs;
2692
2693 # SMELL: unchecked implicit untaint?
2694 my $attrs = new Foswiki::Attrs($1);
2695 $attrs->{type} ||= 'section';
2696 $attrs->{name} =
2697 $attrs->{_DEFAULT}
2698 || $attrs->{name}
2699 || '_SECTION' . $seq++;
2700 delete $attrs->{_DEFAULT};
2701 my $id = $attrs->{type} . ':' . $attrs->{name};
2702 if ( $sections{$id} ) {
2703
2704 # error, this named section already defined, ignore
2705 next;
2706 }
2707
2708 # close open unnamed sections of the same type
2709 foreach my $s (@list) {
2710 if ( $s->{end} < 0
2711 && $s->{type} eq $attrs->{type}
2712 && $s->{name} =~ m/^_SECTION\d+$/ )
2713 {
2714 $s->{end} = $offset;
2715 }
2716 }
2717 $attrs->{start} = $offset;
2718 $attrs->{end} = -1; # open section
2719 $sections{$id} = $attrs;
2720 push( @list, $attrs );
2721 }
2722 elsif ( $bit =~ m/^%(?:END|STOP)SECTION(?:{(.*)})?%$/ ) {
2723 require Foswiki::Attrs;
2724
2725 # SMELL: unchecked implicit untaint?
2726 my $attrs = new Foswiki::Attrs($1);
2727 $attrs->{type} ||= 'section';
2728 $attrs->{name} = $attrs->{_DEFAULT} || $attrs->{name} || '';
2729 delete $attrs->{_DEFAULT};
2730 unless ( $attrs->{name} ) {
2731
2732 # find the last open unnamed section of this type
2733 foreach my $s ( reverse @list ) {
2734 if ( $s->{end} == -1
2735 && $s->{type} eq $attrs->{type}
2736 && $s->{name} =~ m/^_SECTION\d+$/ )
2737 {
2738 $attrs->{name} = $s->{name};
2739 last;
2740 }
2741 }
2742
2743 # ignore it if no matching START found
2744 next unless $attrs->{name};
2745 }
2746 my $id = $attrs->{type} . ':' . $attrs->{name};
2747 if ( !$sections{$id} || $sections{$id}->{end} >= 0 ) {
2748
2749 # error, no such open section, ignore
2750 next;
2751 }
2752 $sections{$id}->{end} = $offset;
2753 }
2754 else {
275585µs $ntext .= $bit;
275688µs $offset = length($ntext);
2757 }
2758 }
2759
2760 # close open sections
276186µs foreach my $s (@list) {
2762 $s->{end} = $offset if $s->{end} < 0;
2763 }
2764
2765833µs return ( $ntext, \@list );
2766}
2767
2768=begin TML
2769
2770---++ ObjectMethod expandMacrosOnTopicCreation ( $topicObject )
2771
2772 * =$topicObject= - the topic
2773
2774Expand only that subset of Foswiki variables that are
2775expanded during topic creation, in the body text and
2776PREFERENCE meta only. The expansion is in-place inside
2777the topic object.
2778
2779# SMELL: no plugin handler
2780
2781=cut
2782
2783sub expandMacrosOnTopicCreation {
2784 my ( $this, $topicObject ) = @_;
2785
2786 # Make sure func works, for registered tag handlers
2787 if (SINGLE_SINGLETONS) {
2788 ASSERT( defined $Foswiki::Plugins::SESSION );
2789 ASSERT( $Foswiki::Plugins::SESSION == $this );
2790 }
2791 local $Foswiki::Plugins::SESSION = $this;
2792 ASSERT( $Foswiki::Plugins::SESSION->isa('Foswiki') ) if DEBUG;
2793
2794 my $text = $topicObject->text();
2795 if ($text) {
2796
2797 # Chop out templateonly sections
2798 my ( $ntext, $sections ) = parseSections($text);
2799 if ( scalar(@$sections) ) {
2800
2801 # Note that if named templateonly sections overlap,
2802 # the behaviour is undefined.
2803
2804 # First excise all templateonly sections by replacing
2805 # with nulls of the same length. This keeps the string
2806 # length the same so offsets remain current.
2807 foreach my $s ( reverse @$sections ) {
2808 next unless ( $s->{type} eq 'templateonly' );
2809 my $r = "\0" x ( $s->{end} - $s->{start} );
2810 substr( $ntext, $s->{start}, $s->{end} - $s->{start}, $r );
2811 }
2812
2813 # Now restore the macros for other sections.
2814 foreach my $s ( reverse @$sections ) {
2815 next if ( $s->{type} eq 'templateonly' );
2816
2817 my $start = $s->remove('start');
2818 my $end = $s->remove('end');
2819 $ntext =
2820 substr( $ntext, 0, $start )
2821 . '%STARTSECTION{'
2822 . $s->{_RAW} . '}%'
2823 . substr( $ntext, $start, $end - $start )
2824 . '%ENDSECTION{'
2825 . $s->{_RAW} . '}%'
2826 . substr( $ntext, $end, length($ntext) );
2827 }
2828
2829 # Chop the nulls
2830 $ntext =~ s/\0*//g;
2831 $text = $ntext;
2832 }
2833
2834 $text = _processMacros( $this, $text, \&_expandMacroOnTopicCreation,
2835 $topicObject, 16 );
2836
2837 # expand all variables for type="expandvariables" sections
2838 ( $ntext, $sections ) = parseSections($text);
2839 if ( scalar(@$sections) ) {
2840 foreach my $s ( reverse @$sections ) {
2841 if ( $s->{type} eq 'expandvariables' ) {
2842 my $etext =
2843 substr( $ntext, $s->{start}, $s->{end} - $s->{start} );
2844 $this->innerExpandMacros( \$etext, $topicObject );
2845 $ntext =
2846 substr( $ntext, 0, $s->{start} )
2847 . $etext
2848 . substr( $ntext, $s->{end}, length($ntext) );
2849 }
2850 else {
2851
2852 # put back non-expandvariables sections
2853 my $start = $s->remove('start');
2854 my $end = $s->remove('end');
2855 $ntext =
2856 substr( $ntext, 0, $start )
2857 . '%STARTSECTION{'
2858 . $s->{_RAW} . '}%'
2859 . substr( $ntext, $start, $end - $start )
2860 . '%ENDSECTION{'
2861 . $s->{_RAW} . '}%'
2862 . substr( $ntext, $end, length($ntext) );
2863 }
2864 }
2865 $text = $ntext;
2866 }
2867
2868 # kill markers used to prevent variable expansion
2869 $text =~ s/%NOP%//g;
2870 $topicObject->text($text);
2871 }
2872
2873 # Expand preferences
2874 my @prefs = $topicObject->find('PREFERENCE');
2875 foreach my $p (@prefs) {
2876 $p->{value} =
2877 _processMacros( $this, $p->{value}, \&_expandMacroOnTopicCreation,
2878 $topicObject, 16 );
2879
2880 # kill markers used to prevent variable expansion
2881 $p->{value} =~ s/%NOP%//g;
2882 }
2883}
2884
2885=begin TML
2886
2887---++ StaticMethod entityEncode( $text [, $extras] ) -> $encodedText
2888
2889Escape special characters to HTML numeric entities. This is *not* a generic
2890encoding, it is tuned specifically for use in Foswiki.
2891
2892HTML4.0 spec:
2893"Certain characters in HTML are reserved for use as markup and must be
2894escaped to appear literally. The "&lt;" character may be represented with
2895an <em>entity</em>, <strong class=html>&amp;lt;</strong>. Similarly, "&gt;"
2896is escaped as <strong class=html>&amp;gt;</strong>, and "&amp;" is escaped
2897as <strong class=html>&amp;amp;</strong>. If an attribute value contains a
2898double quotation mark and is delimited by double quotation marks, then the
2899quote should be escaped as <strong class=html>&amp;quot;</strong>.
2900
2901Other entities exist for special characters that cannot easily be entered
2902with some keyboards..."
2903
2904This method encodes:
2905 * all non-printable 7-bit chars (< \x1f), except \n (\xa) and \r (\xd)
2906 * HTML special characters '>', '<', '&', ''' and '"'.
2907 * TML special characters '%', '|', '[', ']', '@', '_',
2908
2909$extras is an optional param that may be used to include *additional*
2910characters in the set of encoded characters. It should be a string
2911containing the additional chars.
2912
2913=cut
2914
2915sub entityEncode {
2916 my ( $text, $extra ) = @_;
2917 $extra = '' unless defined $extra;
2918
2919 # Safe on utf8 binary strings, as none of the characters has bit 7 set
2920 $text =~
2921 s/([[\x01-\x09\x0b\x0c\x0e-\x1f"%&'*<=>@[_\|$extra])/'&#'.ord($1).';'/ge;
2922 return $text;
2923}
2924
2925=begin TML
2926
2927---++ StaticMethod entityDecode ( $encodedText ) -> $text
2928
2929Decodes all numeric entities (e.g. &amp;#123;). _Does not_ decode
2930named entities such as &amp;amp; (use HTML::Entities for that)
2931
2932=cut
2933
2934sub entityDecode {
2935 my $text = shift;
2936
2937 $text =~ s/&#(\d+);/chr($1)/ge;
2938 return $text;
2939}
2940
2941=begin TML
2942
2943---++ StaticMethod urlEncode( $perlstring ) -> $bytestring
2944
2945Encode by converting characters that are reserved in URLs to
2946their %NN equivalents. This method is used for encoding
2947strings that must be embedded _verbatim_ in URLs; it cannot
2948be applied to URLs themselves, as it escapes reserved
2949characters such as = and ?.
2950
2951RFC 1738, Dec. '94:
2952 <verbatim>
2953 ...Only alphanumerics [0-9a-zA-Z], the special
2954 characters $-_.+!*'(), and reserved characters used for their
2955 reserved purposes may be used unencoded within a URL.
2956 </verbatim>
2957
2958However this function is tuned for use with Foswiki. As such, it
2959encodes *all* characters except 0-9a-zA-Z-_.:~!*#/
2960
2961=cut
2962
2963
# spent 544µs (273+271) within Foswiki::urlEncode which was called 72 times, avg 8µs/call: # 23 times (99µs+95µs) by Foswiki::getScriptUrl at line 1550, avg 8µs/call # 16 times (68µs+76µs) by Foswiki::Request::queryString at line 233 of /var/www/foswikidev/core/lib/Foswiki/Request.pm, avg 9µs/call # 16 times (56µs+48µs) by Foswiki::Request::queryString at line 234 of /var/www/foswikidev/core/lib/Foswiki/Request.pm, avg 7µs/call # 14 times (40µs+41µs) by Foswiki::make_params at line 1580, avg 6µs/call # once (4µs+5µs) by Foswiki::Store::getAttachmentURL at line 212 of /var/www/foswikidev/core/lib/Foswiki/Store.pm # once (3µs+3µs) by Foswiki::Store::getAttachmentURL at line 218 of /var/www/foswikidev/core/lib/Foswiki/Store.pm # once (3µs+3µs) by Foswiki::Store::getAttachmentURL at line 228 of /var/www/foswikidev/core/lib/Foswiki/Store.pm
sub urlEncode {
29647224µs my $text = shift;
2965
29667274µs72271µs $text = encode_utf8($text);
# spent 271µs making 72 calls to Encode::encode_utf8, avg 4µs/call
29677251µs $text =~ s{([^0-9a-zA-Z-_.:~!*#/])}{sprintf('%%%02x',ord($1))}ge;
2968
296972132µs return $text;
2970}
2971
2972=begin TML
2973
2974---++ StaticMethod urlDecode( $bytestring ) -> $perlstring
2975
2976Reverses the encoding done in urlEncode.
2977
2978=cut
2979
2980
# spent 69µs (7+62) within Foswiki::urlDecode which was called: # once (7µs+62µs) by Foswiki::new at line 2190
sub urlDecode {
29811700ns my $text = shift;
2982
29831800ns $text =~ s/%([\da-f]{2})/chr(hex($1))/gei;
298412µs162µs $text = decode_utf8($text);
# spent 62µs making 1 call to Encode::decode_utf8
2985
298615µs return $text;
2987}
2988
2989=begin TML
2990
2991---++ StaticMethod isTrue( $value, $default ) -> $boolean
2992
2993Returns 1 if =$value= is true, and 0 otherwise. "true" means set to
2994something with a Perl true value, with the special cases that "off",
2995"false" and "no" (case insensitive) are forced to false. Leading and
2996trailing spaces in =$value= are ignored.
2997
2998If the value is undef, then =$default= is returned. If =$default= is
2999not specified it is taken as 0.
3000
3001=cut
3002
3003
# spent 5.93ms within Foswiki::isTrue which was called 1479 times, avg 4µs/call: # 80 times (721µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:235] at line 224 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 9µs/call # 80 times (681µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::query at line 132 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 9µs/call # 80 times (228µs+0s) by Foswiki::Search::InfoCache::sortResults at line 145 of /var/www/foswikidev/core/lib/Foswiki/Search/InfoCache.pm, avg 3µs/call # 63 times (105µs+0s) by Foswiki::Func::isTrue at line 3102 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 2µs/call # 40 times (423µs+0s) by Foswiki::Search::searchWeb at line 423 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 11µs/call # 40 times (350µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::getListOfWebs at line 455 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 9µs/call # 40 times (319µs+0s) by Foswiki::Search::searchWeb at line 275 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 8µs/call # 40 times (283µs+0s) by Foswiki::Store::Interfaces::QueryAlgorithm::getListOfWebs at line 500 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 7µs/call # 40 times (266µs+0s) by Foswiki::Search::searchWeb at line 277 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 7µs/call # 40 times (205µs+0s) by Foswiki::Search::formatResults at line 587 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 5µs/call # 40 times (193µs+0s) by Foswiki::Search::searchWeb at line 286 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 5µs/call # 40 times (192µs+0s) by Foswiki::Search::formatResults at line 716 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 5µs/call # 40 times (184µs+0s) by Foswiki::Search::formatResults at line 717 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 5µs/call # 40 times (171µs+0s) by Foswiki::Search::formatResults at line 589 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 4µs/call # 40 times (122µs+0s) by Foswiki::Search::searchWeb at line 447 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 3µs/call # 40 times (85µs+0s) by Foswiki::Search::searchWeb at line 267 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (82µs+0s) by Foswiki::Search::searchWeb at line 353 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (76µs+0s) by Foswiki::Search::searchWeb at line 424 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (69µs+0s) by Foswiki::Search::searchWeb at line 278 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (67µs+0s) by Foswiki::Search::formatResults at line 586 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (65µs+0s) by Foswiki::Search::formatResults at line 588 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (65µs+0s) by Foswiki::Search::formatResults at line 729 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (62µs+0s) by Foswiki::Search::searchWeb at line 290 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (61µs+0s) by Foswiki::Search::searchWeb at line 272 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (60µs+0s) by Foswiki::Search::formatResults at line 590 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 2µs/call # 40 times (58µs+0s) by Foswiki::Search::searchWeb at line 284 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 1µs/call # 40 times (58µs+0s) by Foswiki::Search::searchWeb at line 306 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 1µs/call # 40 times (57µs+0s) by Foswiki::Search::searchWeb at line 308 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 1µs/call # 40 times (56µs+0s) by Foswiki::Search::searchWeb at line 300 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 1µs/call # 40 times (54µs+0s) by Foswiki::Search::formatResults at line 730 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 1µs/call # 40 times (54µs+0s) by Foswiki::Search::searchWeb at line 301 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 1µs/call # 40 times (53µs+0s) by Foswiki::Search::formatResults at line 732 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 1µs/call # 19 times (145µs+0s) by Foswiki::WebFilter::ok at line 51 of /var/www/foswikidev/core/lib/Foswiki/WebFilter.pm, avg 8µs/call # 13 times (57µs+0s) by Foswiki::Func::getPreferencesFlag at line 884 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 4µs/call # 8 times (70µs+0s) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 294 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 9µs/call # 6 times (56µs+0s) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 318 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 9µs/call # 5 times (49µs+0s) by Foswiki::Render::getRenderedVersion at line 528 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 10µs/call # 3 times (7µs+0s) by Foswiki::URLPARAM at line 27 of /var/www/foswikidev/core/lib/Foswiki/Macros/URLPARAM.pm, avg 2µs/call # 2 times (19µs+0s) by Foswiki::Plugins::SubscribePlugin::_SUBSCRIBE at line 90 of /var/www/foswikidev/core/lib/Foswiki/Plugins/SubscribePlugin.pm, avg 10µs/call
sub isTrue {
30041479973µs my ( $value, $default ) = @_;
3005
30061479372µs $default ||= 0;
3007
300814798.03ms return $default unless defined($value);
3009
30105212.30ms $value =~ s/^\s*(.*?)\s*$/$1/gi;
3011521131µs $value =~ s/off//gi;
3012521136µs $value =~ s/no//gi;
301352184µs $value =~ s/false//gi;
30145211.57ms return ($value) ? 1 : 0;
3015}
3016
3017=begin TML
3018
3019---++ StaticMethod spaceOutWikiWord( $word, $sep ) -> $string
3020
3021Spaces out a wiki word by inserting a string (default: one space) between each word component.
3022With parameter $sep any string may be used as separator between the word components; if $sep is undefined it defaults to a space.
3023
3024=cut
3025
3026
# spent 940µs (500+441) within Foswiki::spaceOutWikiWord which was called: # once (500µs+441µs) by Foswiki::SPACEOUT at line 18 of /var/www/foswikidev/core/lib/Foswiki/Macros/SPACEOUT.pm
sub spaceOutWikiWord {
302711µs my ( $word, $sep ) = @_;
3028
3029 # Both could have the value 0 so we cannot use simple = || ''
30301600ns $word = defined($word) ? $word : '';
30311700ns $sep = defined($sep) ? $sep : ' ';
30321400ns my $mark = "\001";
30331107µs2132µs $word =~ s/([[:upper:]])([[:digit:]])/$1$mark$2/g;
# spent 132µs making 2 calls to utf8::SWASHNEW, avg 66µs/call
3034121µs155µs $word =~ s/([[:digit:]])([[:upper:]])/$1$mark$2/g;
# spent 55µs making 1 call to utf8::SWASHNEW
30351181µs2142µs $word =~ s/([[:lower:]])([[:upper:][:digit:]]+)/$1$mark$2/g;
# spent 142µs making 2 calls to utf8::SWASHNEW, avg 71µs/call
30361161µs2112µs $word =~ s/([[:upper:]])([[:upper:]])(?=[[:lower:]])/$1$mark$2/g;
# spent 112µs making 2 calls to utf8::SWASHNEW, avg 56µs/call
3037110µs $word =~ s/$mark/$sep/g;
303815µs return $word;
3039}
3040
3041=begin TML
3042
3043---++ ObjectMethod innerExpandMacros(\$text, $topicObject)
3044Expands variables by replacing the variables with their
3045values. Some example variables: %<nop>TOPIC%, %<nop>SCRIPTURL%,
3046%<nop>WIKINAME%, etc.
3047$web and $incs are passed in for recursive include expansion. They can
3048safely be undef.
3049The rules for tag expansion are:
3050 1 Tags are expanded left to right, in the order they are encountered.
3051 1 Tags are recursively expanded as soon as they are encountered -
3052 the algorithm is inherently single-pass
3053 1 A tag is not "encountered" until the matching }% has been seen, by
3054 which time all tags in parameters will have been expanded
3055 1 Tag expansions that create new tags recursively are limited to a
3056 set number of hierarchical levels of expansion
3057
3058=cut
3059
3060
# spent 137s (5.22ms+137) within Foswiki::innerExpandMacros which was called 238 times, avg 576ms/call: # 100 times (2.14ms+137s) by Foswiki::expandMacros at line 3620, avg 1.37s/call # 100 times (2.16ms+-977µs) by Foswiki::expandMacros at line 3630, avg 12µs/call # 16 times (379µs+-379µs) by Foswiki::If::OP_dollar::evaluate at line 47 of /var/www/foswikidev/core/lib/Foswiki/If/OP_dollar.pm, avg 0s/call # 8 times (194µs+-194µs) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 313 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 0s/call # 8 times (192µs+-192µs) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 300 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 0s/call # 6 times (147µs+-147µs) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 336 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 0s/call
sub innerExpandMacros {
3061238106µs my ( $this, $text, $topicObject ) = @_;
3062
3063 # push current context
3064238306µs238572µs my $memTopic = $this->{prefs}->getPreference('TOPIC');
# spent 572µs making 238 calls to Foswiki::Prefs::getPreference, avg 2µs/call
3065238272µs238498µs my $memWeb = $this->{prefs}->getPreference('WEB');
# spent 498µs making 238 calls to Foswiki::Prefs::getPreference, avg 2µs/call
3066
3067 # Historically this couldn't be called on web objects.
3068238296µs238346µs my $webContext = $topicObject->web || $this->{webName};
# spent 346µs making 238 calls to Foswiki::Meta::web, avg 1µs/call
3069238264µs238312µs my $topicContext = $topicObject->topic || $this->{topicName};
# spent 312µs making 238 calls to Foswiki::Meta::topic, avg 1µs/call
3070
3071238282µs2381.14ms $this->{prefs}->setInternalPreferences(
# spent 1.14ms making 238 calls to Foswiki::Prefs::setInternalPreferences, avg 5µs/call
3072 TOPIC => $topicContext,
3073 WEB => $webContext
3074 );
3075
3076 # Escape ' !%VARIABLE%'
3077238491µs $$text =~ s/(?<=[\s\(\.])!%($regex{tagNameRegex})/&#37;$1/g;
3078
3079 # Make sure func works, for registered tag handlers
3080238262µs238241µs if (SINGLE_SINGLETONS) {
# spent 241µs making 238 calls to Foswiki::SINGLE_SINGLETONS, avg 1µs/call
3081 ASSERT( defined $Foswiki::Plugins::SESSION );
3082 ASSERT( $Foswiki::Plugins::SESSION == $this );
3083 }
308423879µs local $Foswiki::Plugins::SESSION = $this;
3085 ASSERT( $Foswiki::Plugins::SESSION->isa('Foswiki') ) if DEBUG;
3086
3087 # NOTE TO DEBUGGERS
3088 # The depth parameter in the following call controls the maximum number
3089 # of levels of expansion. If it is set to 1 then only macros in the
3090 # topic will be expanded; macros that they in turn generate will be
3091 # left unexpanded. If it is set to 2 then the expansion will stop after
3092 # the first recursive inclusion, and so on. This is incredible useful
3093 # when debugging. The default, 16, was selected empirically.
3094238410µs238137s $$text = _processMacros( $this, $$text, \&_expandMacroOnTopicRendering,
# spent 137s making 238 calls to Foswiki::_processMacros, avg 577ms/call, recursion: max depth 5, sum of overlapping time 163ms
3095 $topicObject, 16 );
3096
3097 # restore previous context
3098238800µs2381.09ms $this->{prefs}->setInternalPreferences(
# spent 1.09ms making 238 calls to Foswiki::Prefs::setInternalPreferences, avg 5µs/call
3099 TOPIC => $memTopic,
3100 WEB => $memWeb
3101 );
3102}
3103
3104=begin TML
3105
3106---++ StaticMethod takeOutBlocks( \$text, $tag, \%map ) -> $text
3107 * =$text= - Text to process
3108 * =$tag= - XML-style tag.
3109 * =\%map= - Reference to a hash to contain the removed blocks
3110
3111Return value: $text with blocks removed
3112
3113Searches through $text and extracts blocks delimited by an XML-style tag,
3114storing the extracted block, and replacing with a token string which is
3115not affected by TML rendering. The text after these substitutions is
3116returned.
3117
3118=cut
3119
3120
# spent 6.55ms within Foswiki::takeOutBlocks which was called 310 times, avg 21µs/call: # 100 times (1.07ms+0s) by Foswiki::expandMacros at line 3602, avg 11µs/call # 100 times (988µs+0s) by Foswiki::expandMacros at line 3622, avg 10µs/call # 87 times (1.76ms+0s) by Foswiki::_processMacros at line 3249, avg 20µs/call # 8 times (325µs+0s) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 303 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 41µs/call # 5 times (1.42ms+0s) by Foswiki::Render::getRenderedVersion at line 230 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 284µs/call # 5 times (603µs+0s) by Foswiki::Render::getRenderedVersion at line 229 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 121µs/call # 5 times (385µs+0s) by Foswiki::Render::getRenderedVersion at line 264 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 77µs/call
sub takeOutBlocks {
3121310188µs my ( $intext, $tag, $map ) = @_;
3122
31233109.93ms return $intext unless ( $intext =~ m/<$tag\b/i );
3124
31252800ns my $out = '';
31262800ns my $depth = 0;
31272400ns my $scoop;
31282400ns my $tagParams;
3129
31302270µs foreach my $token ( split( /(<\/?$tag[^>]*>)/i, $intext ) ) {
3131118485µs if ( $token =~ m/<$tag\b([^>]*)?>/i ) {
3132295µs $depth++;
3133299µs if ( $depth eq 1 ) {
31342915µs $tagParams = $1;
3135295µs next;
3136 }
3137 }
3138 elsif ( $token =~ m/<\/$tag>/i ) {
3139295µs if ( $depth > 0 ) {
31402911µs $depth--;
3141296µs if ( $depth eq 0 ) {
31422910µs my $placeholder = "$tag$BLOCKID";
3143294µs $BLOCKID++;
31442943µs $map->{$placeholder}{text} = $scoop;
31452914µs $map->{$placeholder}{params} = $tagParams;
31462921µs $out .= "$OC$placeholder$CC";
3147294µs $scoop = '';
3148297µs next;
3149 }
3150 }
3151 }
31526028µs if ( $depth > 0 ) {
3153 $scoop .= $token;
3154 }
3155 else {
31563113µs $out .= $token;
3157 }
3158 }
3159
3160 # unmatched tags
316122µs if ( defined($scoop) && ( $scoop ne '' ) ) {
3162 my $placeholder = "$tag$BLOCKID";
3163 $BLOCKID++;
3164 $map->{$placeholder}{text} = $scoop;
3165 $map->{$placeholder}{params} = $tagParams;
3166 $out .= "$OC$placeholder$CC";
3167 }
3168
316929µs return $out;
3170}
3171
3172=begin TML
3173
3174---++ StaticMethod putBackBlocks( \$text, \%map, $tag, $newtag, $callBack ) -> $text
3175
3176Return value: $text with blocks added back
3177 * =\$text= - reference to text to process
3178 * =\%map= - map placeholders to blocks removed by takeOutBlocks
3179 * =$tag= - Tag name processed by takeOutBlocks
3180 * =$newtag= - Tag name to use in output, in place of $tag.
3181 If undefined, uses $tag.
3182 * =$callback= - Reference to function to call on each block
3183 being inserted (optional)
3184
3185Reverses the actions of takeOutBlocks.
3186
3187Each replaced block is processed by the callback (if there is one) before
3188re-insertion.
3189
3190Parameters to the outermost cut block are replaced into the open tag,
3191even if that tag is changed. This allows things like =&lt;verbatim class=''>=
3192to be changed to =&lt;pre class=''>=
3193
3194If you set $newtag to '', replaces the taken-out block with the contents
3195of the block, not including the open/close. This is used for &lt;literal>,
3196for example.
3197
3198=cut
3199
3200
# spent 1.18ms within Foswiki::putBackBlocks which was called 210 times, avg 6µs/call: # 100 times (307µs+0s) by Foswiki::expandMacros at line 3655, avg 3µs/call # 87 times (290µs+0s) by Foswiki::_processMacros at line 3372, avg 3µs/call # 8 times (26µs+0s) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm:339] at line 309 of /var/www/foswikidev/core/lib/Foswiki/Macros/INCLUDE.pm, avg 3µs/call # 5 times (440µs+0s) by Foswiki::Render::getRenderedVersion at line 557 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 88µs/call # 5 times (60µs+0s) by Foswiki::Render::getRenderedVersion at line 551 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 12µs/call # 5 times (59µs+0s) by Foswiki::Render::getRenderedVersion at line 545 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 12µs/call
sub putBackBlocks {
3201210129µs my ( $text, $map, $tag, $newtag, $callback ) = @_;
3202
320321063µs $newtag = $tag if ( !defined($newtag) );
3204
3205210691µs foreach my $placeholder ( keys %$map ) {
3206141143µs if ( $placeholder =~ m/^$tag\d+$/ ) {
32072915µs my $params = $map->{$placeholder}{params} || '';
3208299µs my $val = $map->{$placeholder}{text};
3209293µs $val = &$callback($val) if ( defined($callback) );
32102914µs if ( $newtag eq '' ) {
321129299µs $$text =~ s($OC$placeholder$CC)($val);
3212 }
3213 else {
3214 $$text =~ s($OC$placeholder$CC)
3215 (<$newtag$params>$val</$newtag>);
3216 }
32172924µs delete( $map->{$placeholder} );
3218 }
3219 }
3220}
3221
3222# Process Foswiki %TAGS{}% by parsing the input tokenised into
3223# % separated sections. The parser is a simple stack-based parse,
3224# sufficient to ensure nesting of tags is correct, but no more
3225# than that.
3226# $depth limits the number of recursive expansion steps that
3227# can be performed on expanded tags.
3228
# spent 137s (19.6ms+137) within Foswiki::_processMacros which was called 271 times, avg 506ms/call: # 238 times (12.6ms+137s) by Foswiki::innerExpandMacros at line 3094, avg 576ms/call # 33 times (6.99ms+-6.99ms) by Foswiki::_processMacros at line 3315, avg 0s/call
sub _processMacros {
3229271218µs my ( $this, $text, $tagf, $topicObject, $depth ) = @_;
323027147µs my $tell = 0;
3231
3232271154µs return '' if ( ( !defined($text) )
3233 || ( $text eq '' ) );
3234
3235 #no tags to process
3236246600µs return $text unless ( $text =~ m/%/ );
3237
32388712µs unless ($depth) {
3239 my $mess = "Max recursive depth reached: $text";
3240 $this->logger->log( 'warning', $mess );
3241
3242 # prevent recursive expansion that just has been detected
3243 # from happening in the error message
3244 $text =~ s/%(.*?)%/$1/g;
3245 return $text;
3246 }
3247
32488742µs my $verbatim = {};
324987112µs871.76ms $text = takeOutBlocks( $text, 'verbatim', $verbatim );
# spent 1.76ms making 87 calls to Foswiki::takeOutBlocks, avg 20µs/call
3250
32518728µs my $dirtyAreas = {};
325287116µs87145µs $text = takeOutBlocks( $text, 'dirtyarea', $dirtyAreas )
# spent 145µs making 87 calls to Foswiki::Meta::isCacheable, avg 2µs/call
3253 if $topicObject->isCacheable();
3254
325587993µs my @queue = split( /(%)/, $text );
32568712µs my @stack;
32578721µs my $stackTop = ''; # the top stack entry. Done this way instead of
3258 # referring to the top of the stack for efficiency. This var
3259 # should be considered to be $stack[$#stack]
3260
326187222µs while ( scalar(@queue) ) {
3262
3263 #print STDERR "QUEUE:".join("\n ", map { "'$_'" } @queue)."\n";
32642248623µs my $token = shift(@queue);
3265
3266 #print STDERR ' ' x $tell,"PROCESSING $token \n";
3267
3268 # each % sign either closes an existing stacked context, or
3269 # opens a new context.
327022481.09ms if ( $token eq '%' ) {
3271
3272 #print STDERR ' ' x $tell,"CONSIDER $stackTop\n";
3273 # If this is a closing }%, try to rejoin the previous
3274 # tokens until we get to a valid tag construct. This is
3275 # a bit of a hack, but it's hard to think of a better
3276 # way to do this without a full parse that takes % signs
3277 # in tag parameters into account.
32781101711µs if ( $stackTop =~ m/}$/s ) {
3279251713µs while ( scalar(@stack)
3280 && $stackTop !~ /^%$regex{tagNameRegex}\{.*}$/s )
3281 {
32823510µs my $top = $stackTop;
3283
3284 #print STDERR ' ' x $tell,"COLLAPSE $top \n";
32853567µs $stackTop = pop(@stack) . $top;
3286 }
3287 }
3288
3289 # /s so you can have newlines in parameters
329011012.49ms if ( $stackTop =~ m/^%(($regex{tagNameRegex})(?:{(.*)})?)$/s ) {
3291
3292 # SMELL: unchecked implicit untaint?
3293536800µs my ( $expr, $tag, $args ) = ( $1, $2, $3 );
3294
3295 #Foswiki::Func::writeDebug("POP $tag") if $tracing;
3296 #Monitor::MARK("Before $tag");
3297536898µs536137s my $e = &$tagf( $this, $tag, $args, $topicObject );
# spent 137s making 536 calls to Foswiki::_expandMacroOnTopicRendering, avg 256ms/call, recursion: max depth 3, sum of overlapping time 151ms
3298
3299 #Monitor::MARK("After $tag");
3300
3301536152µs if ( defined($e) ) {
3302
3303 #Foswiki::Func::writeDebug("EXPANDED $tag -> $e") if $tracing;
3304503299µs $stackTop = pop(@stack);
3305
3306 # Don't bother recursively expanding unless there are
3307 # unexpanded tags in the result.
33085031.00ms unless ( $e =~ m/%$regex{tagNameRegex}(?:{.*})?%/s ) {
3309470471µs $stackTop .= $e;
3310470290µs next;
3311 }
3312
3313 # Recursively expand tags in the expansion of $tag
3314 $stackTop .=
331533107µs330s $this->_processMacros( $e, $tagf, $topicObject,
# spent 22.8ms making 33 calls to Foswiki::_processMacros, avg 691µs/call, recursion: max depth 4, sum of overlapping time 22.8ms
3316 $depth - 1 );
3317 }
3318 else {
3319
3320 #Foswiki::Func::writeDebug("EXPAND $tag FAILED") if $tracing;
3321 # To handle %NOP
3322 # correctly, we have to handle the %VAR% case differently
3323 # to the %VAR{}% case when a variable expansion fails.
3324 # This is so that recursively define variables e.g.
3325 # %A%B%D% expand correctly, but at the same time we ensure
3326 # that a mismatched }% can't accidentally close a context
3327 # that was left open when a tag expansion failed.
3328 # However TWiki didn't do this, so for compatibility
3329 # we have to accept that %NOP can never be fixed. if it
3330 # could, then we could uncomment the following:
3331
3332 #if( $stackTop =~ m/}$/ ) {
3333 # # %VAR{...}% case
3334 # # We need to push the unexpanded expression back
3335 # # onto the stack, but we don't want it to match the
3336 # # tag expression again. So we protect the %'s
3337 # $stackTop = "&#37;$expr&#37;";
3338 #} else
3339 #{
3340
3341 # %VAR% case.
3342 # In this case we *do* want to match the tag expression
3343 # again, as an embedded %VAR% may have expanded to
3344 # create a valid outer expression. This is directly
3345 # at odds with the %VAR{...}% case.
33463316µs push( @stack, $stackTop );
3347339µs $stackTop = '%'; # open new context
3348 #}
3349 }
3350 }
3351 else {
3352565459µs push( @stack, $stackTop );
3353565152µs $stackTop = '%'; # push a new context
3354 #$tell++;
3355 }
3356 }
3357 else {
33581147555µs $stackTop .= $token;
3359 }
3360 }
3361
3362 # Run out of input. Gather up everything in the stack.
33638730µs while ( scalar(@stack) ) {
33646025µs my $expr = $stackTop;
33656015µs $stackTop = pop(@stack);
33666050µs $stackTop .= $expr;
3367 }
3368
336987115µs87141µs putBackBlocks( \$stackTop, $dirtyAreas, 'dirtyarea' )
# spent 141µs making 87 calls to Foswiki::Meta::isCacheable, avg 2µs/call
3370 if $topicObject->isCacheable();
3371
337287115µs87290µs putBackBlocks( \$stackTop, $verbatim, 'verbatim' );
# spent 290µs making 87 calls to Foswiki::putBackBlocks, avg 3µs/call
3373
3374 #print STDERR "FINAL $stackTop\n";
3375
337687279µs return $stackTop;
3377}
3378
3379# Handle expansion of a tag during topic rendering
3380# $tag is the tag name
3381# $args is the bit in the {} (if there are any)
3382# $topicObject should be passed for dynamic tags (not needed for
3383# session or constant tags
3384
# spent 137s (16.9ms+137) within Foswiki::_expandMacroOnTopicRendering which was called 537 times, avg 255ms/call: # 536 times (16.9ms+137s) by Foswiki::_processMacros at line 3297, avg 256ms/call # once (18µs+-18µs) by Foswiki::normalizeWebTopicName at line 1708
sub _expandMacroOnTopicRendering {
3385537346µs my ( $this, $tag, $args, $topicObject ) = @_;
3386
3387537225µs require Foswiki::Attrs;
3388
3389537851µs53722.4ms my $e = $this->{prefs}->getPreference($tag);
# spent 22.4ms making 537 calls to Foswiki::Prefs::getPreference, avg 42µs/call
3390537470µs if ( defined $e ) {
339110720µs if ( $args && $args =~ m/\S/ ) {
3392 my $attrs = new Foswiki::Attrs( $args, 0 );
3393
3394 $e = $this->_processMacros(
3395 $e,
3396 sub {
3397 # Expand %DEFAULT and any parameter tags
3398 my ( $this, $tag, $args, $topicObject ) = @_;
3399 my $tattrs = new Foswiki::Attrs($args);
3400
3401 if ( $tag eq 'DEFAULT' ) {
3402
3403 # Define the %DEFAULT macro to return the value
3404 # passed (if any) or the default= parameter (if
3405 # present) otherwise.
3406 return $attrs->{_DEFAULT} if defined $attrs->{_DEFAULT};
3407 return $tattrs->{default} if defined $tattrs->{default};
3408
3409 # No default and no value - kill it.
3410 return '';
3411 }
3412 my $val = $attrs->{$tag};
3413 $val = $tattrs->{default} unless defined $val;
3414 return expandStandardEscapes($val) if defined $val;
3415 return undef;
3416 },
3417 $topicObject,
3418 1
3419 );
3420 }
3421 }
3422 elsif ( exists( $macros{$tag} ) ) {
3423397164µs unless ( defined( $macros{$tag} ) ) {
3424
3425 # Demand-load the macro module
34262139µs die $tag unless $tag =~ m/([A-Z_:]+)/i;
34272119µs $tag = $1;
342821565µs eval "require Foswiki::Macros::$tag";
# spent 123µs executing statements in 2 string evals (merged) # spent 72µs executing statements in string eval # spent 70µs executing statements in string eval # spent 68µs executing statements in string eval # spent 68µs executing statements in string eval # spent 67µs executing statements in string eval # spent 66µs executing statements in string eval # spent 64µs executing statements in string eval # spent 64µs executing statements in string eval # spent 63µs executing statements in string eval # spent 63µs executing statements in string eval # spent 63µs executing statements in string eval # spent 63µs executing statements in string eval # spent 60µs executing statements in string eval # spent 60µs executing statements in string eval # spent 58µs executing statements in string eval # spent 56µs executing statements in string eval # spent 56µs executing statements in string eval # spent 3µs executing statements in string eval # spent 2µs executing statements in string eval
3429215µs die $@ if $@;
343021434µs $macros{$tag} = eval "\\&$tag";
# spent 5µs executing statements in 2 string evals (merged) # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval # spent 2µs executing statements in string eval
3431218µs die $@ if $@;
3432 }
3433
34343971.49ms3977.72ms my $attrs = new Foswiki::Attrs( $args, $contextFreeSyntax{$tag} );
# spent 7.72ms making 397 calls to Foswiki::Attrs::new, avg 19µs/call
34353971.71ms397137s $e = &{ $macros{$tag} }( $this, $attrs, $topicObject );
# spent 137s making 40 calls to Foswiki::SEARCH, avg 3.42s/call # spent 132ms making 14 calls to Foswiki::Func::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Func.pm:662], avg 9.43ms/call # spent 199ms making 10 calls to Foswiki::INCLUDE, avg 19.9ms/call, recursion: max depth 2, sum of overlapping time 73.2ms # spent 48.4ms making 3 calls to Foswiki::REVINFO, avg 16.1ms/call # spent 39.8ms making 43 calls to Foswiki::IF, avg 925µs/call # spent 9.33ms making 3 calls to Foswiki::META, avg 3.11ms/call # spent 3.90ms making 57 calls to Foswiki::MAKETEXT, avg 68µs/call # spent 1.71ms making 1 call to Foswiki::QUERY # spent 997µs making 45 calls to Foswiki::PUBURLPATH, avg 22µs/call # spent 948µs making 1 call to Foswiki::SPACEOUT # spent 877µs making 12 calls to Foswiki::VAR, avg 73µs/call # spent 503µs making 17 calls to Foswiki::SCRIPTURLPATH, avg 30µs/call # spent 472µs making 1 call to Foswiki::ICONURL # spent 356µs making 7 calls to Foswiki::WIKINAME, avg 51µs/call # spent 355µs making 13 calls to Foswiki::SCRIPTURL, avg 27µs/call # spent 198µs making 5 calls to Foswiki::ADDTOZONE, avg 40µs/call # spent 185µs making 6 calls to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:247], avg 31µs/call # spent 160µs making 2 calls to Foswiki::WIKIUSERNAME, avg 80µs/call # spent 145µs making 2 calls to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:323], avg 72µs/call # spent 123µs making 2 calls to Foswiki::USERNAME, avg 61µs/call # spent 120µs making 3 calls to Foswiki::URLPARAM, avg 40µs/call # spent 106µs making 1 call to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:289] # spent 99µs making 15 calls to Foswiki::ENCODE, avg 7µs/call # spent 96µs making 63 calls to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:401], avg 2µs/call # spent 92µs making 1 call to Foswiki::LoginManager::_LOGOUTURL # spent 33µs making 2 calls to Foswiki::PUBURL, avg 16µs/call # spent 24µs making 1 call to Foswiki::LoginManager::_LOGIN # spent 21µs making 10 calls to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:405], avg 2µs/call # spent 14µs making 5 calls to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:394], avg 3µs/call # spent 13µs making 1 call to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:312] # spent 11µs making 2 calls to Foswiki::RENDERZONE, avg 6µs/call # spent 8µs making 2 calls to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:344], avg 4µs/call # spent 8µs making 2 calls to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:347], avg 4µs/call # spent 5µs making 1 call to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:409] # spent 4µs making 1 call to Foswiki::LoginManager::ApacheLogin::__ANON__[/var/www/foswikidev/core/lib/Foswiki/LoginManager/ApacheLogin.pm:53] # spent 4µs making 1 call to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:243] # spent 4µs making 1 call to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:450] # spent 4µs making 1 call to Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki.pm:399]
3436 }
3437 elsif ( $args && $args =~ m/\S/ ) {
3438
3439 # Arbitrary %SOMESTRING{default="xxx"}% will expand to xxx
3440 # in the absence of any definition.
344114µs160µs my $attrs = new Foswiki::Attrs($args);
# spent 60µs making 1 call to Foswiki::Attrs::new
344212µs if ( defined $attrs->{default} ) {
3443 $e = expandStandardEscapes( $attrs->{default} );
3444 }
3445 }
34465376.11ms return $e;
3447}
3448
3449# Handle expansion of a tag during new topic creation. When creating a
3450# new topic from a template we only expand a subset of the available legal
3451# tags, and we expand %NOP% differently.
3452sub _expandMacroOnTopicCreation {
3453 my $this = shift;
3454
3455 # my( $tag, $args, $topicObject ) = @_;
3456
3457 # Required for Cairo compatibility. Ignore %NOP{...}%
3458 # %NOP% is *not* ignored until all variable expansion is complete,
3459 # otherwise them inside-out rule would remove it too early e.g.
3460 # %GM%NOP%TIME -> %GMTIME -> 12:00. So we ignore it here and scrape it
3461 # out later. We *have* to remove %NOP{...}% because it can foul up
3462 # brace-matching.
3463 return '' if $_[0] eq 'NOP' && defined $_[1];
3464
3465 # Only expand a subset of legal tags. Warning: $this->{user} may be
3466 # overridden during this call, when a new user topic is being created.
3467 # This is what we want to make sure new user templates are populated
3468 # correctly, but you need to think about this if you extend the set of
3469 # tags expanded here.
3470 return
3471 unless $_[0] =~
3472m/^(URLPARAM|DATE|(SERVER|GM)TIME|(USER|WIKI)NAME|WIKIUSERNAME|USERINFO)$/;
3473
3474 return $this->_expandMacroOnTopicRendering(@_);
3475}
3476
3477=begin TML
3478
3479---++ ObjectMethod enterContext( $id, $val )
3480
3481Add the context id $id into the set of active contexts. The $val
3482can be anything you like, but should always evaluate to boolean
3483TRUE.
3484
3485An example of the use of contexts is in the use of tag
3486expansion. The commonTagsHandler in plugins is called every
3487time tags need to be expanded, and the context of that expansion
3488is signalled by the expanding module using a context id. So the
3489forms module adds the context id "form" before invoking common
3490tags expansion.
3491
3492Contexts are not just useful for tag expansion; they are also
3493relevant when rendering.
3494
3495Contexts are intended for use mainly by plugins. Core modules can
3496use $session->inContext( $id ) to determine if a context is active.
3497
3498=cut
3499
3500
# spent 140µs within Foswiki::enterContext which was called 49 times, avg 3µs/call: # 42 times (117µs+0s) by Foswiki::Plugin::registerHandlers at line 301 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm, avg 3µs/call # once (6µs+0s) by Foswiki::UI::View::view at line 464 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm # once (4µs+0s) by Foswiki::UI::View::view at line 458 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm # once (4µs+0s) by Foswiki::LoginManager::ApacheLogin::new at line 50 of /var/www/foswikidev/core/lib/Foswiki/LoginManager/ApacheLogin.pm # once (3µs+0s) by Foswiki::Users::new at line 121 of /var/www/foswikidev/core/lib/Foswiki/Users.pm # once (3µs+0s) by Foswiki::UI::View::view at line 438 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm # once (2µs+0s) by Foswiki::Users::new at line 122 of /var/www/foswikidev/core/lib/Foswiki/Users.pm # once (2µs+0s) by Foswiki::LoginManager::userLoggedIn at line 812 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm
sub enterContext {
35014931µs my ( $this, $id, $val ) = @_;
35024914µs $val ||= 1;
350349149µs $this->{context}->{$id} = $val;
3504}
3505
3506=begin TML
3507
3508---++ ObjectMethod leaveContext( $id )
3509
3510Remove the context id $id from the set of active contexts.
3511(see =enterContext= for more information on contexts)
3512
3513=cut
3514
3515
# spent 28µs within Foswiki::leaveContext which was called 4 times, avg 7µs/call: # once (10µs+0s) by Foswiki::UI::View::view at line 460 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm # once (6µs+0s) by Foswiki::UI::View::view at line 466 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm # once (6µs+0s) by Foswiki::UI::View::view at line 440 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm # once (5µs+0s) by Foswiki::LoginManager::new at line 181 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm
sub leaveContext {
351646µs my ( $this, $id ) = @_;
351744µs my $res = $this->{context}->{$id};
351848µs delete $this->{context}->{$id};
3519419µs return $res;
3520}
3521
3522=begin TML
3523
3524---++ ObjectMethod inContext( $id )
3525
3526Return the value for the given context id
3527(see =enterContext= for more information on contexts)
3528
3529=cut
3530
3531
# spent 257µs within Foswiki::inContext which was called 135 times, avg 2µs/call: # 56 times (99µs+0s) by Foswiki::getPubURL at line 1629, avg 2µs/call # 40 times (72µs+0s) by Foswiki::getScriptUrl at line 1516, avg 2µs/call # 14 times (28µs+0s) by Foswiki::Func::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Func.pm:662] at line 649 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 2µs/call # 12 times (28µs+0s) by Foswiki::If::OP_context::evaluate at line 43 of /var/www/foswikidev/core/lib/Foswiki/If/OP_context.pm, avg 2µs/call # 5 times (14µs+0s) by Foswiki::LoginManager::endRenderingHandler at line 1043 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm, avg 3µs/call # once (4µs+0s) by Foswiki::LoginManager::makeLoginManager at line 107 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::Plugins::HomePagePlugin::initializeUserHandler at line 31 of /var/www/foswikidev/core/lib/Foswiki/Plugins/HomePagePlugin.pm # once (2µs+0s) by Foswiki::LoginManager::loadSession at line 324 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::LoginManager::_LOGIN at line 1368 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::LoginManager::checkAccess at line 691 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::LoginManager::userLoggedIn at line 808 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::LoginManager::makeLoginManager at line 146 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::Plugins::HomePagePlugin::initializeUserHandler at line 35 of /var/www/foswikidev/core/lib/Foswiki/Plugins/HomePagePlugin.pm
sub inContext {
353213553µs my ( $this, $id ) = @_;
3533135402µs return $this->{context}->{$id};
3534}
3535
3536=begin TML
3537
3538---++ StaticMethod registerTagHandler( $tag, $fnref, $syntax )
3539
3540STATIC Add a tag handler to the function tag handlers.
3541 * =$tag= name of the tag e.g. MYTAG
3542 * =$fnref= Function to execute. Will be passed ($session, \%params, $web, $topic )
3543 * =$syntax= somewhat legacy - 'classic' or 'context-free' (context-free may be removed in future)
3544
3545
3546$syntax parameter:
3547Way back in prehistory, back when the dinosaur still roamed the earth,
3548Crawford tried to extend the tag syntax of macros such that they could be processed
3549by a context-free parser (hence the "context-free")
3550and bring them into line with HTML.
3551This work was banjaxed by one particular tyrranosaur,
3552who felt that the existing syntax was perfect.
3553However by that time Crawford had used it in a couple of places - most notable in the action tracker.
3554
3555The syntax isn't vastly different from what's there; the differences are:
3556 1 Use either type of quote for parameters
3557 2 Optional quotes on parameter values e.g. recurse=on
3558 3 Standardised use of \ for escapes
3559 4 Boolean (valueless) options (i.e. recurse instead of recurse="on"
3560
3561
3562=cut
3563
3564
# spent 154µs within Foswiki::registerTagHandler which was called 62 times, avg 2µs/call: # 50 times (126µs+0s) by Foswiki::Func::registerTagHandler at line 663 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 3µs/call # once (6µs+0s) by Foswiki::Plugins::new at line 84 of /var/www/foswikidev/core/lib/Foswiki/Plugins.pm # once (3µs+0s) by Foswiki::LoginManager::new at line 186 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::LoginManager::new at line 188 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::LoginManager::new at line 190 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::Plugins::new at line 88 of /var/www/foswikidev/core/lib/Foswiki/Plugins.pm # once (2µs+0s) by Foswiki::Plugins::new at line 89 of /var/www/foswikidev/core/lib/Foswiki/Plugins.pm # once (2µs+0s) by Foswiki::Plugins::new at line 86 of /var/www/foswikidev/core/lib/Foswiki/Plugins.pm # once (2µs+0s) by Foswiki::LoginManager::new at line 192 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::LoginManager::new at line 187 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::LoginManager::new at line 191 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm # once (2µs+0s) by Foswiki::LoginManager::ApacheLogin::new at line 53 of /var/www/foswikidev/core/lib/Foswiki/LoginManager/ApacheLogin.pm # once (2µs+0s) by Foswiki::LoginManager::new at line 189 of /var/www/foswikidev/core/lib/Foswiki/LoginManager.pm
sub registerTagHandler {
35656234µs my ( $tag, $fnref, $syntax ) = @_;
35666257µs $macros{$tag} = $fnref;
356762148µs if ( $syntax && $syntax eq 'context-free' ) {
3568 $contextFreeSyntax{$tag} = 1;
3569 }
3570}
3571
3572=begin TML
3573
3574---++ ObjectMethod expandMacros( $text, $topicObject ) -> $text
3575
3576Processes %<nop>VARIABLE%, and %<nop>TOC% syntax; also includes
3577'commonTagsHandler' plugin hook.
3578
3579Returns the text of the topic, after file inclusion, variable substitution,
3580table-of-contents generation, and any plugin changes from commonTagsHandler.
3581
3582$topicObject may be undef when, for example, expanding templates, or one-off strings
3583at a time when meta isn't available.
3584
3585DO NOT CALL THIS DIRECTLY; use $topicObject->expandMacros instead.
3586
3587=cut
3588
3589
# spent 137s (8.76ms+137) within Foswiki::expandMacros which was called 100 times, avg 1.37s/call: # 100 times (8.76ms+137s) by Foswiki::Meta::expandMacros at line 3353 of /var/www/foswikidev/core/lib/Foswiki/Meta.pm, avg 1.37s/call
sub expandMacros {
359010060µs my ( $this, $text, $topicObject ) = @_;
3591
359210016µs return '' unless defined $text;
3593
3594 # Plugin Hook
3595100332µs3004.75ms $this->{plugins}
# spent 4.51ms making 100 calls to Foswiki::Plugins::dispatch, avg 45µs/call, recursion: max depth 1, sum of overlapping time 52µs # spent 145µs making 100 calls to Foswiki::Meta::web, avg 1µs/call # spent 142µs making 100 calls to Foswiki::Meta::topic, avg 1µs/call
3596 ->dispatch( 'beforeCommonTagsHandler', $text, $topicObject->topic,
3597 $topicObject->web, $topicObject );
3598
3599 #use a "global var", so included topics can extract and putback
3600 #their verbatim blocks safetly.
360110045µs my $verbatim = {};
3602100136µs1001.07ms $text = takeOutBlocks( $text, 'verbatim', $verbatim );
# spent 1.07ms making 100 calls to Foswiki::takeOutBlocks, avg 11µs/call
3603
3604 # take out dirty areas
360510034µs my $dirtyAreas = {};
3606100130µs100172µs $text = takeOutBlocks( $text, 'dirtyarea', $dirtyAreas )
# spent 172µs making 100 calls to Foswiki::Meta::isCacheable, avg 2µs/call
3607 if $topicObject->isCacheable();
3608
3609 # Require defaults for plugin handlers :-(
3610100123µs100144µs my $webContext = $topicObject->web || $this->{webName};
# spent 144µs making 100 calls to Foswiki::Meta::web, avg 1µs/call
3611100114µs100134µs my $topicContext = $topicObject->topic || $this->{topicName};
# spent 134µs making 100 calls to Foswiki::Meta::topic, avg 1µs/call
3612
3613100159µs100211µs my $memW = $this->{prefs}->getPreference('INCLUDINGWEB');
# spent 211µs making 100 calls to Foswiki::Prefs::getPreference, avg 2µs/call
3614100117µs100155µs my $memT = $this->{prefs}->getPreference('INCLUDINGTOPIC');
# spent 155µs making 100 calls to Foswiki::Prefs::getPreference, avg 2µs/call
3615100129µs100553µs $this->{prefs}->setInternalPreferences(
# spent 553µs making 100 calls to Foswiki::Prefs::setInternalPreferences, avg 6µs/call
3616 INCLUDINGWEB => $webContext,
3617 INCLUDINGTOPIC => $topicContext
3618 );
3619
3620100156µs100137s $this->innerExpandMacros( \$text, $topicObject );
# spent 137s making 100 calls to Foswiki::innerExpandMacros, avg 1.37s/call, recursion: max depth 2, sum of overlapping time 26.3ms
3621
3622100127µs100988µs $text = takeOutBlocks( $text, 'verbatim', $verbatim );
# spent 988µs making 100 calls to Foswiki::takeOutBlocks, avg 10µs/call
3623
3624 # Plugin Hook
3625100157µs10016.5ms $this->{plugins}
# spent 16.7ms making 100 calls to Foswiki::Plugins::dispatch, avg 167µs/call, recursion: max depth 1, sum of overlapping time 122µs
3626 ->dispatch( 'commonTagsHandler', $text, $topicContext, $webContext, 0,
3627 $topicObject );
3628
3629 # process tags again because plugin hook may have added more in
3630100151µs1001.18ms $this->innerExpandMacros( \$text, $topicObject );
# spent 5.40ms making 100 calls to Foswiki::innerExpandMacros, avg 54µs/call, recursion: max depth 2, sum of overlapping time 4.21ms
3631
3632100125µs100420µs $this->{prefs}->setInternalPreferences(
# spent 420µs making 100 calls to Foswiki::Prefs::setInternalPreferences, avg 4µs/call
3633 INCLUDINGWEB => $memW,
3634 INCLUDINGTOPIC => $memT
3635 );
3636
3637 # 'Special plugin tag' TOC hack, must be done after all other expansions
3638 # are complete, and has to reprocess the entire topic.
3639
364010089µs if ( $text =~ m/%TOC(?:{.*})?%/ ) {
3641 require Foswiki::Macros::TOC;
3642 $text =~ s/%TOC(?:{(.*?)})?%/$this->TOC($text, $topicObject, $1)/ge;
3643 }
3644
3645 # Codev.FormattedSearchWithConditionalOutput: remove <nop> lines,
3646 # possibly introduced by SEARCHes with conditional CALC. This needs
3647 # to be done after CALC and before table rendering in order to join
3648 # table rows properly
3649100153µs $text =~ s/^<nop>\r?\n//gm;
3650
3651 # restore dirty areas
3652100124µs100166µs putBackBlocks( \$text, $dirtyAreas, 'dirtyarea' )
# spent 166µs making 100 calls to Foswiki::Meta::isCacheable, avg 2µs/call
3653 if $topicObject->isCacheable();
3654
3655100119µs100307µs putBackBlocks( \$text, $verbatim, 'verbatim' );
# spent 307µs making 100 calls to Foswiki::putBackBlocks, avg 3µs/call
3656
3657 # Foswiki Plugin Hook (for cache Plugins only)
3658100151µs1001.41ms $this->{plugins}
# spent 1.43ms making 100 calls to Foswiki::Plugins::dispatch, avg 14µs/call, recursion: max depth 1, sum of overlapping time 14µs
3659 ->dispatch( 'afterCommonTagsHandler', $text, $topicContext, $webContext,
3660 $topicObject );
3661
3662100322µs return $text;
3663}
3664
3665=begin TML
3666
3667---++ ObjectMethod addToZone($zone, $id, $data, $requires)
3668
3669Add =$data= identified as =$id= to =$zone=, which will later be expanded (with
3670renderZone() - implements =%<nop>RENDERZONE%=). =$ids= are unique within
3671the zone that they are added - dependencies between =$ids= in different zones
3672will not be resolved, except for the special case of =head= and =script= zones
3673when ={MergeHeadAndScriptZones}= is enabled.
3674
3675In this case, they are treated as separate zones when adding to them, but as
3676one merged zone when rendering, i.e. a call to render either =head= or =script=
3677zones will actually render both zones in this one call. Both zones are undef'd
3678afterward to avoid double rendering of content from either zone, to support
3679proper behaviour when =head= and =script= are rendered with separate calls even
3680when ={MergeHeadAndScriptZones}= is set. See ZoneTests/explicit_RENDERZONE*.
3681
3682This behaviour allows an addToZone('head') call to require an id that has been
3683added to =script= only.
3684
3685 * =$zone= - name of the zone
3686 * =$id= - unique identifier
3687 * =$data= - content
3688 * =$requires= - optional, comma-separated string of =$id= identifiers
3689 that should precede the content
3690
3691<blockquote class="foswikiHelp">%X%
3692*Note:* Read the developer supplement at Foswiki:Development.AddToZoneFromPluginHandlers if you
3693are calling =addToZone()= from a rendering or macro/tag-related plugin handler
3694</blockquote>
3695
3696Implements =%<nop>ADDTOZONE%=.
3697
3698=cut
3699
3700
# spent 788µs within Foswiki::addToZone which was called 41 times, avg 19µs/call: # 36 times (648µs+0s) by Foswiki::Func::addToZone at line 2782 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 18µs/call # 5 times (140µs+0s) by Foswiki::ADDTOZONE at line 43 of /var/www/foswikidev/core/lib/Foswiki/Macros/ADDTOZONE.pm, avg 28µs/call
sub addToZone {
37014134µs my ( $this, $zone, $id, $data, $requires ) = @_;
3702
3703418µs $requires ||= '';
3704
3705 # get a random one
3706417µs unless ($id) {
3707 $id = int( rand(10000) ) + 1;
3708 }
3709
3710 # get zone, or create record
37114126µs my $thisZone = $this->{_zones}{$zone};
37124110µs unless ( defined $thisZone ) {
3713 $this->{_zones}{$zone} = $thisZone = {};
3714 }
3715
3716415µs my @requires;
37174188µs foreach my $req ( split( /\s*,\s*/, $requires ) ) {
37185333µs unless ( $thisZone->{$req} ) {
3719 $thisZone->{$req} = {
3720 id => $req,
3721 zone => $zone,
3722 requires => [],
3723 missingrequires => [],
3724 text => '',
3725 populated => 0
3726 };
3727 }
37285351µs push( @requires, $thisZone->{$req} );
3729 }
3730
3731 # store record within zone
37324117µs my $zoneID = $thisZone->{$id};
37334112µs unless ($zoneID) {
37343332µs $zoneID = { id => $id };
37353329µs $thisZone->{$id} = $zoneID;
3736 }
3737
3738 # add class to script and link data
373941192µs $data =~ s/<script\s+((?![^>]*class=))/<script class='\$zone \$id' $1/g;
37404134µs $data =~ s/<link\s+((?![^>]class=))/<link class='\$zone \$id' $1/g;
37414146µs $data =~ s/<style\s+((?![^>]*class=))/<style class='\$zone \$id' $1/g;
3742
3743 # override previous properties
37444125µs $zoneID->{zone} = $zone;
37454123µs $zoneID->{requires} = \@requires;
37464121µs $zoneID->{missingrequires} = [];
37474129µs $zoneID->{text} = $data;
37484112µs $zoneID->{populated} = 1;
3749
375041113µs return;
3751}
3752
3753
# spent 18.0ms (22µs+18.0) within Foswiki::_renderZoneById which was called 2 times, avg 9.02ms/call: # 2 times (22µs+18.0ms) by Foswiki::_renderZones at line 3935, avg 9.02ms/call
sub _renderZoneById {
37542900ns my $this = shift;
375522µs my $id = shift;
3756
37572600ns return '' unless defined $id;
3758
375924µs my $renderZone = $this->{_renderZonePlaceholder}{$id};
3760
37612200ns return '' unless defined $renderZone;
3762
376322µs my $params = $renderZone->{params};
37642500ns my $topicObject = $renderZone->{topicObject};
376521µs my $zone = $params->{_DEFAULT} || $params->{zone};
3766
3767210µs218.0ms return _renderZone( $this, $zone, $params, $topicObject );
# spent 18.0ms making 2 calls to Foswiki::_renderZone, avg 9.01ms/call
3768}
3769
3770# This private function is used in ZoneTests
3771
# spent 18.0ms (756µs+17.3) within Foswiki::_renderZone which was called 4 times, avg 4.51ms/call: # 2 times (750µs+17.3ms) by Foswiki::_renderZoneById at line 3767, avg 9.01ms/call # once (4µs+0s) by Foswiki::_renderZones at line 3939 # once (2µs+0s) by Foswiki::_renderZones at line 3944
sub _renderZone {
377243µs my ( $this, $zone, $params, $topicObject ) = @_;
3773
3774 # Check the zone is defined and has not already been rendered
3775412µs return '' unless $zone && $this->{_zones}{$zone};
3776
377724µs $params->{header} ||= '';
377821µs $params->{footer} ||= '';
377921µs $params->{chomp} ||= 'off';
378021µs $params->{missingformat} = '$id: requires= missing ids: $missingids';
378122µs $params->{format} = '$item<!--<literal>$missing</literal>-->'
3782 unless defined $params->{format};
378322µs $params->{separator} = '$n()' unless defined $params->{separator};
3784
37852300ns unless ( defined $topicObject ) {
3786 $topicObject =
3787 Foswiki::Meta->new( $this, $this->{webName}, $this->{topicName} );
3788 }
3789
3790 # Loop through the vertices of the graph, in any order, initiating
3791 # a depth-first search for any vertex that has not already been
3792 # visited by a previous search. The desired topological sorting is
3793 # the reverse postorder of these searches. That is, we can construct
3794 # the ordering as a list of vertices, by adding each vertex to the
3795 # start of the list at the time when the depth-first search is
3796 # processing that vertex and has returned from processing all children
3797 # of that vertex. Since each edge and vertex is visited once, the
3798 # algorithm runs in linear time.
379921µs my %visited;
38002500ns my @total;
3801
3802 # When {MergeHeadAndScriptZones} is set, try to treat head and script
3803 # zones as merged for compatibility with ADDTOHEAD usage where requirements
3804 # have been moved to the script zone. See ZoneTests/Item9317
3805221µs if ( $Foswiki::cfg{MergeHeadAndScriptZones}
3806 and ( ( $zone eq 'head' ) or ( $zone eq 'script' ) ) )
3807 {
3808 my @zoneIDs = (
3809 values %{ $this->{_zones}{head} },
3810 values %{ $this->{_zones}{script} }
3811 );
3812
3813 foreach my $zoneID (@zoneIDs) {
3814 $this->_visitZoneID( $zoneID, \%visited, \@total );
3815 }
3816 undef $this->{_zones}{head};
3817 undef $this->{_zones}{script};
3818 }
3819 else {
3820218µs my @zoneIDs = values %{ $this->{_zones}{$zone} };
3821
382222µs foreach my $zoneID (@zoneIDs) {
38233853µs38383µs $this->_visitZoneID( $zoneID, \%visited, \@total );
# spent 383µs making 38 calls to Foswiki::_visitZoneID, avg 10µs/call
3824 }
3825
3826 # kill a zone once it has been rendered, to prevent it being
3827 # added twice (e.g. by duplicate %RENDERZONEs or by automatic
3828 # zone expansion in the head or script)
382923µs undef $this->{_zones}{$zone};
3830 }
3831
3832 # nothing rendered for a zone with no ADDTOZONE calls
383321µs return '' unless scalar(@total) > 0;
3834
383521µs my @result = ();
383621µs my $missingformat = $params->{missingformat};
383722µs foreach my $item (@total) {
38383821µs my $text = $item->{text};
38393819µs my @missingids = @{ $item->{missingrequires} };
38403811µs my $missingformat =
3841 ( scalar(@missingids) ) ? $params->{missingformat} : '';
3842
38433813µs if ( $params->{'chomp'} ) {
38443820µs $text =~ s/^\s+//g;
384538121µs $text =~ s/\s+$//g;
3846 }
3847
3848 # ASSERT($text, "No content for zone id $item->{id} in zone $zone")
3849 # if DEBUG;
3850
3851385µs next unless $text;
38522715µs my $id = $item->{id} || '';
3853276µs my $line = $params->{format};
38542711µs if ( scalar(@missingids) ) {
3855 $line =~ s/\$missing\b/$missingformat/g;
3856 $line =~ s/\$missingids\b/join(', ', @missingids)/ge;
3857 }
3858 else {
38592742µs $line =~ s/\$missing\b/\$id/g;
3860 }
38612744µs $line =~ s/\$item\b/$text/g;
38622772µs $line =~ s/\$id\b/$id/g;
38632772µs $line =~ s/\$zone\b/$item->{zone}/g;
38642729µs push @result, $line if $line;
3865 }
3866218µs2158µs my $result =
# spent 158µs making 2 calls to Foswiki::expandStandardEscapes, avg 79µs/call
3867 expandStandardEscapes( $params->{header}
3868 . join( $params->{separator}, @result )
3869 . $params->{footer} );
3870
3871 # delay rendering the zone until now
387224µs210.8ms $result = $topicObject->expandMacros($result);
# spent 10.8ms making 2 calls to Foswiki::Meta::expandMacros, avg 5.40ms/call
387323µs25.92ms $result = $topicObject->renderTML($result);
# spent 5.92ms making 2 calls to Foswiki::Meta::renderTML, avg 2.96ms/call
3874
3875268µs return $result;
3876}
3877
3878
# spent 383µs within Foswiki::_visitZoneID which was called 89 times, avg 4µs/call: # 51 times (176µs+-176µs) by Foswiki::_visitZoneID at line 3911, avg 0s/call # 38 times (207µs+176µs) by Foswiki::_renderZone at line 3823, avg 10µs/call
sub _visitZoneID {
38798931µs my ( $this, $zoneID, $visited, $list ) = @_;
3880
388189116µs return if $visited->{$zoneID};
3882
38833827µs $visited->{$zoneID} = 1;
3884
38853848µs foreach my $requiredZoneID ( @{ $zoneID->{requires} } ) {
3886515µs my $zoneIDToVisit;
3887
38885116µs if ( $Foswiki::cfg{MergeHeadAndScriptZones}
3889 and not $requiredZoneID->{populated} )
3890 {
3891
3892 # Compatibility mode, where we are trying to treat head and script
3893 # zones as merged, and a required ZoneID isn't populated. Try
3894 # opposite zone to see if it exists there instead. Item9317
3895 if ( $requiredZoneID->{zone} eq 'head' ) {
3896 $zoneIDToVisit =
3897 $this->{_zones}{script}{ $requiredZoneID->{id} };
3898 }
3899 else {
3900 $zoneIDToVisit = $this->{_zones}{head}{ $requiredZoneID->{id} };
3901 }
3902 if ( not $zoneIDToVisit->{populated} ) {
3903
3904 # Oops, the required ZoneID doesn't exist there either; reset
3905 $zoneIDToVisit = $requiredZoneID;
3906 }
3907 }
3908 else {
39095110µs $zoneIDToVisit = $requiredZoneID;
3910 }
39115151µs510s $this->_visitZoneID( $zoneIDToVisit, $visited, $list );
# spent 243µs making 51 calls to Foswiki::_visitZoneID, avg 5µs/call, recursion: max depth 3, sum of overlapping time 243µs
3912
39135137µs if ( not $zoneIDToVisit->{populated} ) {
3914
3915 # Finally, we got to here and the required ZoneID just cannot be
3916 # found in either head or script (or other) zones, so record it for
3917 # diagnostic purposes ($missingids format token)
3918 push( @{ $zoneID->{missingrequires} }, $zoneIDToVisit->{id} );
3919 }
3920 }
39213811µs push( @{$list}, $zoneID );
3922
39233858µs return;
3924}
3925
3926# This private function is used in ZoneTests
3927
# spent 18.2ms (128µs+18.0) within Foswiki::_renderZones which was called: # once (128µs+18.0ms) by Foswiki::writeCompletePage at line 732
sub _renderZones {
392817µs my ( $this, $text ) = @_;
3929
3930 # Render zones that were pulled out by Foswiki/Macros/RENDERZONE.pm
3931 # NOTE: once a zone has been rendered it is cleared, so cannot
3932 # be rendered again.
3933
3934189µs $text =~ s/${RENDERZONE_MARKER}RENDERZONE\{(.*?)\}${RENDERZONE_MARKER}/
393524µs218.0ms _renderZoneById($this, $1)/geo;
# spent 18.0ms making 2 calls to Foswiki::_renderZoneById, avg 9.02ms/call
3936
3937 # get the head zone and insert it at the end of the </head>
3938 # *if it has not already been rendered*
393914µs14µs my $headZone = _renderZone( $this, 'head', { chomp => "on" } );
# spent 4µs making 1 call to Foswiki::_renderZone
39401500ns $text =~ s!(</head>)!$headZone\n$1!i if $headZone;
3941
3942 # SMELL: Item9480 - can't trust that _renderzone(head) above has truly
3943 # flushed both script and head zones empty when {MergeHeadAndScriptZones} = 1.
394412µs12µs my $scriptZone = _renderZone( $this, 'script', { chomp => "on" } );
# spent 2µs making 1 call to Foswiki::_renderZone
39451400ns $text =~ s!(</head>)!$scriptZone\n$1!i if $scriptZone;
3946
394711µs chomp($text);
3948
3949114µs return $text;
3950}
3951
3952=begin TML
3953
3954---++ StaticMethod readFile( $filename ) -> $text
3955
3956Returns the entire contents of the given file, which can be specified in any
3957format acceptable to the Perl open() function. Fast, but inherently unsafe.
3958
3959WARNING: Never, ever use this for accessing topics or attachments! Use the
3960Store API for that. This is for global control files only, and should be
3961used *only* if there is *absolutely no alternative*.
3962
3963=cut
3964
3965sub readFile {
3966 my $name = shift;
3967 ASSERT(0) if DEBUG;
3968 my $IN_FILE;
3969 open( $IN_FILE, "<$name" ) || return '';
3970 local $/ = undef;
3971 my $data = <$IN_FILE>;
3972 close($IN_FILE);
3973 $data = '' unless ( defined($data) );
3974 return $data;
3975}
3976
3977=begin TML
3978
3979---++ StaticMethod expandStandardEscapes($str) -> $unescapedStr
3980
3981Expands standard escapes used in parameter values to block evaluation. See
3982System.FormatTokens for a full list of supported tokens.
3983
3984=cut
3985
3986
# spent 964µs within Foswiki::expandStandardEscapes which was called 100 times, avg 10µs/call: # 40 times (460µs+0s) by Foswiki::Search::searchWeb at line 444 of /var/www/foswikidev/core/lib/Foswiki/Search.pm, avg 12µs/call # 23 times (92µs+0s) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/IF.pm:50] at line 48 of /var/www/foswikidev/core/lib/Foswiki/Macros/IF.pm, avg 4µs/call # 20 times (164µs+0s) by Foswiki::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Macros/IF.pm:50] at line 44 of /var/www/foswikidev/core/lib/Foswiki/Macros/IF.pm, avg 8µs/call # 11 times (45µs+0s) by Foswiki::USERINFO at line 132 of /var/www/foswikidev/core/lib/Foswiki/Macros/USERINFO.pm, avg 4µs/call # 3 times (41µs+0s) by Foswiki::Render::renderRevisionInfo at line 787 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 14µs/call # 2 times (158µs+0s) by Foswiki::_renderZone at line 3866, avg 79µs/call # once (3µs+0s) by Foswiki::META at line 69 of /var/www/foswikidev/core/lib/Foswiki/Macros/META.pm
sub expandStandardEscapes {
398710077µs my $text = shift;
3988
3989 # expand '$n()' and $n! to new line
3990100118µs $text =~ s/\$n\(\)/\n/gs;
399110067µs $text =~ s/\$n(?=[^[:alpha:]]|$)/\n/gs;
3992
3993 # filler, useful for nested search
399410058µs $text =~ s/\$nop(\(\))?//gs;
3995
3996 # $quot -> "
399710070µs $text =~ s/\$quot(\(\))?/\"/gs;
3998
3999 # $comma -> ,
400010040µs $text =~ s/\$comma(\(\))?/,/gs;
4001
4002 # $percent -> %
400310063µs $text =~ s/\$perce?nt(\(\))?/\%/gs;
4004
4005 # $lt -> <
400610068µs $text =~ s/\$lt(\(\))?/\</gs;
4007
4008 # $gt -> >
400910059µs $text =~ s/\$gt(\(\))?/\>/gs;
4010
4011 # $amp -> &
401210041µs $text =~ s/\$amp(\(\))?/\&/gs;
4013
4014 # $dollar -> $, done last to avoid creating the above tokens
401510044µs $text =~ s/\$dollar(\(\))?/\$/gs;
4016
4017100264µs return $text;
4018}
4019
4020=begin TML
4021
4022---++ ObjectMethod webExists( $web ) -> $boolean
4023
4024Test if web exists
4025 * =$web= - Web name, required, e.g. ='Sandbox'=
4026
4027A web _has_ to have a preferences topic to be a web.
4028
4029=cut
4030
4031
# spent 7.35ms (442µs+6.90) within Foswiki::webExists which was called 101 times, avg 73µs/call: # 80 times (367µs+5.51ms) by Foswiki::Store::Interfaces::QueryAlgorithm::__ANON__[/var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm:235] at line 221 of /var/www/foswikidev/core/lib/Foswiki/Store/Interfaces/QueryAlgorithm.pm, avg 74µs/call # 20 times (65µs+1.32ms) by Foswiki::WebFilter::ok at line 48 of /var/www/foswikidev/core/lib/Foswiki/WebFilter.pm, avg 69µs/call # once (10µs+72µs) by Foswiki::UI::checkWebExists at line 572 of /var/www/foswikidev/core/lib/Foswiki/UI.pm
sub webExists {
403210161µs my ( $this, $web ) = @_;
4033
4034 ASSERT( UNTAINTED($web), 'web is tainted' ) if DEBUG;
4035101481µs1016.90ms return $this->{store}->webExists($web);
# spent 6.90ms making 101 calls to Foswiki::Store::Rcs::Store::webExists, avg 68µs/call
4036}
4037
4038=begin TML
4039
4040---++ ObjectMethod topicExists( $web, $topic ) -> $boolean
4041
4042Test if topic exists
4043 * =$web= - Web name, optional, e.g. ='Main'=
4044 * =$topic= - Topic name, required, e.g. ='TokyoOffice'=, or ="Main.TokyoOffice"=
4045
4046=cut
4047
4048
# spent 11.1ms (754µs+10.4) within Foswiki::topicExists which was called 156 times, avg 71µs/call: # 116 times (601µs+7.47ms) by Foswiki::Templates::_readTemplateFile at line 538 of /var/www/foswikidev/core/lib/Foswiki/Templates.pm, avg 70µs/call # 18 times (58µs+1.26ms) by Foswiki::Render::_renderWikiWord at line 1272 of /var/www/foswikidev/core/lib/Foswiki/Render.pm, avg 73µs/call # 7 times (30µs+517µs) by Foswiki::Plugin::topicWeb at line 391 of /var/www/foswikidev/core/lib/Foswiki/Plugin.pm, avg 78µs/call # 6 times (23µs+422µs) by Foswiki::Func::topicExists at line 1631 of /var/www/foswikidev/core/lib/Foswiki/Func.pm, avg 74µs/call # 4 times (14µs+283µs) by Foswiki::If::OP_istopic::evaluate at line 48 of /var/www/foswikidev/core/lib/Foswiki/If/OP_istopic.pm, avg 74µs/call # once (10µs+130µs) by Foswiki::_parsePath at line 1814 # once (4µs+78µs) by Foswiki::Users::TopicUserMapping::_loadMapping at line 1676 of /var/www/foswikidev/core/lib/Foswiki/Users/TopicUserMapping.pm # once (4µs+76µs) by Foswiki::_lookupIcon at line 36 of /var/www/foswikidev/core/lib/Foswiki/Macros/ICON.pm # once (4µs+64µs) by Foswiki::If::OP_allows::evaluate at line 54 of /var/www/foswikidev/core/lib/Foswiki/If/OP_allows.pm # once (4µs+56µs) by Foswiki::UI::View::view at line 125 of /var/www/foswikidev/core/lib/Foswiki/UI/View.pm
sub topicExists {
4049156104µs my ( $this, $web, $topic ) = @_;
4050 ASSERT( UNTAINTED($web), 'web is tainted' ) if DEBUG;
405115613µs ASSERT( UNTAINTED($topic), 'topic is tainted' ) if DEBUG;
4052156686µs15610.4ms return $this->{store}->topicExists( $web, $topic );
# spent 10.4ms making 156 calls to Foswiki::Store::Rcs::Store::topicExists, avg 66µs/call
4053}
4054
4055=begin TML
4056
4057---+++ ObjectMethod getWorkArea( $key ) -> $directorypath
4058
4059Gets a private directory uniquely identified by $key. The directory is
4060intended as a work area for plugins etc. The directory will exist.
4061
4062=cut
4063
4064
# spent 61µs (11+50) within Foswiki::getWorkArea which was called: # once (11µs+50µs) by Foswiki::Func::getWorkArea at line 2876 of /var/www/foswikidev/core/lib/Foswiki/Func.pm
sub getWorkArea {
406511µs my ( $this, $key ) = @_;
4066110µs150µs return $this->{store}->getWorkArea($key);
# spent 50µs making 1 call to Foswiki::Store::getWorkArea
4067}
4068
4069=begin TML
4070
4071---++ ObjectMethod getApproxRevTime ( $web, $topic ) -> $epochSecs
4072
4073Get an approximate rev time for the latest rev of the topic. This method
4074is used to optimise searching. Needs to be as fast as possible.
4075
4076SMELL: is there a reason this is in Foswiki.pm, and not in Search?
4077
4078=cut
4079
4080sub getApproxRevTime {
4081 my ( $this, $web, $topic ) = @_;
4082
4083 my $metacache = $this->search->metacache;
4084 if ( $metacache->hasCached( $web, $topic ) ) {
4085
4086 #don't kill me - this should become a property on Meta
4087 return $metacache->get( $web, $topic )->{modified};
4088 }
4089
4090 return $this->{store}->getApproxRevTime( $web, $topic );
4091}
4092
4093111µs1;
4094__END__