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