Filename | /usr/local/src/github.com/foswiki/core/lib/Foswiki/OopsException.pm |
Statements | Executed 11 statements in 1.24ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 24µs | 31µs | BEGIN@93 | Foswiki::OopsException::
1 | 1 | 1 | 17µs | 58µs | BEGIN@99 | Foswiki::OopsException::
1 | 1 | 1 | 16µs | 34µs | BEGIN@94 | Foswiki::OopsException::
1 | 1 | 1 | 9µs | 9µs | BEGIN@96 | Foswiki::OopsException::
0 | 0 | 0 | 0s | 0s | _prepareResponse | Foswiki::OopsException::
0 | 0 | 0 | 0s | 0s | generate | Foswiki::OopsException::
0 | 0 | 0 | 0s | 0s | new | Foswiki::OopsException::
0 | 0 | 0 | 0s | 0s | redirect | Foswiki::OopsException::
0 | 0 | 0 | 0s | 0s | stringify | Foswiki::OopsException::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # See bottom of file for license and copyright information | ||||
2 | |||||
3 | =begin TML | ||||
4 | |||||
5 | ---+ package Foswiki::OopsException | ||||
6 | |||||
7 | Exception used to raise a request to output a preformatted page. | ||||
8 | |||||
9 | Despite the name, =oops= is not used just for errors; it is also used | ||||
10 | for one-time redirection, for example during the registration process. | ||||
11 | |||||
12 | The =Foswiki::UI::run= function, which is in the call stack for almost | ||||
13 | all cases where an =OopsException= will be thrown, traps the exception | ||||
14 | and outputs an =oops= page to the browser. This requires | ||||
15 | the name of a template file from the =templates= directory, which it | ||||
16 | expands. Parameter values passed to the exception are instantiated in | ||||
17 | the expanded template. The =oops= page is output with an HTTP status | ||||
18 | appropriate to the event that caused the exception (default 500). | ||||
19 | |||||
20 | Extensions may throw =Foswiki::OopsException=. For example: | ||||
21 | |||||
22 | <verbatim> | ||||
23 | use Error qw(:try); | ||||
24 | |||||
25 | ... | ||||
26 | |||||
27 | throw Foswiki::OopsException( 'bathplugin', | ||||
28 | status => 418, | ||||
29 | web => $web, | ||||
30 | topic => $topic, | ||||
31 | params => [ 'big toe', 'stuck in', 'hot tap' ] ); | ||||
32 | </verbatim> | ||||
33 | This will raise an exception that uses the =bathplugin.tmpl= template. If | ||||
34 | =UI::run= handles the exception it will generate a redirect to: | ||||
35 | <verbatim> | ||||
36 | oops?template=bathplugin;param1=bigtoe;param2=hot%20tap | ||||
37 | </verbatim> | ||||
38 | The =bathplugin.tmpl= might contain: | ||||
39 | (<nop> inserted to prevent translation interface from extracting these examples) | ||||
40 | <verbatim> | ||||
41 | %TMPL:INCLUDE{"oops"}% | ||||
42 | %TMPL:DEF{"titleaction"}% %<nop>MAKETEXT{"Bathing problem"}% %TMPL:END% | ||||
43 | %TMPL:DEF{"heading"}%%<nop>MAKETEXT{"Problem filling bath"}%%TMPL:END% | ||||
44 | %TMPL:DEF{"topicactionbuttons"}%%TMPL:P{"oktopicaction"}%%TMPL:END% | ||||
45 | %TMPL:DEF{"script"}%<meta http-equiv="refresh" content="0;url=%SCRIPTURL{view}%/%WEB%/%TOPIC%" />%TMPL:END% | ||||
46 | %TMPL:DEF{"pagetitle"}%%TMPL:P{"heading"}%%TMPL:END% | ||||
47 | %TMPL:DEF{"webaction"}% *%<nop>MAKETEXT{"Warning"}%* %TMPL:END% | ||||
48 | %TMPL:DEF{"message"}% | ||||
49 | %<nop>MAKETEXT{"Your bath cannot be filled because your [_1] is [_2] the [_3]" args="drain,flooding,basement"}%%TMPL:END% | ||||
50 | </verbatim> | ||||
51 | In this case the =oops= page will be rendered with a 418 ("I'm a teapot") | ||||
52 | status in the HTTP header. | ||||
53 | |||||
54 | A more practical example for plugins authors that does not require them to | ||||
55 | provide their own template file involves use of the generic message template | ||||
56 | available from =oopsattention.tmpl=: | ||||
57 | <verbatim> | ||||
58 | throw Foswiki::OopsException( 'oopsattention', def => 'generic', | ||||
59 | params => [ Operation is not allowed ] ); | ||||
60 | </verbatim> | ||||
61 | |||||
62 | Note that to protect against cross site scripting all parameter values are | ||||
63 | automatically and unconditionally entity-encoded so you cannot pass macros | ||||
64 | if you need messages to be automatically translated you either need to handle | ||||
65 | it in the perl code before throwing Foswiki::OopsException or put the %MAKETEXT | ||||
66 | in the template. You cannot pass macros through the parameters. | ||||
67 | |||||
68 | API version $Date$ (revision $Rev$) | ||||
69 | |||||
70 | *Since* _date_ indicates where functions or parameters have been added since | ||||
71 | the baseline of the API (TWiki release 4.2.3). The _date_ indicates the | ||||
72 | earliest date of a Foswiki release that will support that function or | ||||
73 | parameter. | ||||
74 | |||||
75 | *Deprecated* _date_ indicates where a function or parameters has been | ||||
76 | [[http://en.wikipedia.org/wiki/Deprecation][deprecated]]. Deprecated | ||||
77 | functions will still work, though they should | ||||
78 | _not_ be called in new plugins and should be replaced in older plugins | ||||
79 | as soon as possible. Deprecated parameters are simply ignored in Foswiki | ||||
80 | releases after _date_. | ||||
81 | |||||
82 | *Until* _date_ indicates where a function or parameter has been removed. | ||||
83 | The _date_ indicates the latest date at which Foswiki releases still supported | ||||
84 | the function or parameter. | ||||
85 | |||||
86 | =cut | ||||
87 | |||||
88 | # THIS PACKAGE IS PART OF THE PUBLISHED API USED BY EXTENSION AUTHORS. | ||||
89 | # DO NOT CHANGE THE EXISTING APIS (well thought out extensions are OK) | ||||
90 | # AND ENSURE ALL POD DOCUMENTATION IS COMPLETE AND ACCURATE. | ||||
91 | |||||
92 | package Foswiki::OopsException; | ||||
93 | 2 | 44µs | 2 | 38µs | # spent 31µs (24+7) within Foswiki::OopsException::BEGIN@93 which was called:
# once (24µs+7µs) by Foswiki::Plugin::BEGIN@15 at line 93 # spent 31µs making 1 call to Foswiki::OopsException::BEGIN@93
# spent 7µs making 1 call to strict::import |
94 | 2 | 42µs | 2 | 51µs | # spent 34µs (16+18) within Foswiki::OopsException::BEGIN@94 which was called:
# once (16µs+18µs) by Foswiki::Plugin::BEGIN@15 at line 94 # spent 34µs making 1 call to Foswiki::OopsException::BEGIN@94
# spent 18µs making 1 call to warnings::import |
95 | |||||
96 | 2 | 57µs | 1 | 9µs | # spent 9µs within Foswiki::OopsException::BEGIN@96 which was called:
# once (9µs+0s) by Foswiki::Plugin::BEGIN@15 at line 96 # spent 9µs making 1 call to Foswiki::OopsException::BEGIN@96 |
97 | 1 | 9µs | our @ISA = ('Error'); | ||
98 | |||||
99 | 2 | 1.08ms | 2 | 99µs | # spent 58µs (17+41) within Foswiki::OopsException::BEGIN@99 which was called:
# once (17µs+41µs) by Foswiki::Plugin::BEGIN@15 at line 99 # spent 58µs making 1 call to Foswiki::OopsException::BEGIN@99
# spent 41µs making 1 call to Assert::import |
100 | |||||
101 | 1 | 2µs | our $VERSION = '$Rev'; | ||
102 | |||||
103 | =begin TML | ||||
104 | |||||
105 | ---++ ClassMethod new( $template, ...) | ||||
106 | * =template= is the name of an oops template. e.g. 'bathplugin' refers to =templates/oopsbathplugin.tmpl= | ||||
107 | The remaining parameters are interpreted as key-value pairs. The following keys are used: | ||||
108 | * =web= will be used as the web for the oops | ||||
109 | * =topic= will be used as the topic for the oops | ||||
110 | * =def= - is the (optional) name of a TMPL:DEF within the template | ||||
111 | * =keep= - if set, the exception handler should try its damnedest to retain parameter values from the query. | ||||
112 | * =params= is a reference to an array of parameters. These will be substituted for !%PARAM1%, !%PARAM2% ... !%PARAMn% in the template. | ||||
113 | |||||
114 | For an example of how to use the =def= parameter, see the =oopsattention= | ||||
115 | template. | ||||
116 | |||||
117 | NOTE: parameter values are automatically and unconditionally entity-encoded | ||||
118 | |||||
119 | =cut | ||||
120 | |||||
121 | sub new { | ||||
122 | my $class = shift; | ||||
123 | my $template = shift; | ||||
124 | my $this = $class->SUPER::new(); | ||||
125 | $this->{template} = $template || 'generic'; | ||||
126 | $this->{status} = 500; # default server error | ||||
127 | ASSERT( scalar(@_) % 2 == 0, join( ";", map { $_ || 'undef' } @_ ) ) | ||||
128 | if DEBUG; | ||||
129 | while ( my $key = shift @_ ) { | ||||
130 | my $val = shift @_; | ||||
131 | if ( $key eq 'params' ) { | ||||
132 | if ( ref($val) ne 'ARRAY' ) { | ||||
133 | $val = [$val]; | ||||
134 | } | ||||
135 | $this->{params} = $val; | ||||
136 | } | ||||
137 | else { | ||||
138 | $this->{$key} = $val || ''; | ||||
139 | } | ||||
140 | } | ||||
141 | return $this; | ||||
142 | } | ||||
143 | |||||
144 | =begin TML | ||||
145 | |||||
146 | ---++ ObjectMethod stringify( [$session] ) -> $string | ||||
147 | |||||
148 | Generates a string representation for the object. if a session is passed in, | ||||
149 | and the exception specifies a def, then that def is expanded. This is to allow | ||||
150 | internal expansion of oops exceptions for example when performing bulk | ||||
151 | operations, and also for debugging. | ||||
152 | |||||
153 | =cut | ||||
154 | |||||
155 | sub stringify { | ||||
156 | my ( $this, $session ) = @_; | ||||
157 | |||||
158 | if ( $this->{template} && $this->{def} && $session ) { | ||||
159 | |||||
160 | # load the defs | ||||
161 | $session->templates->readTemplate( 'oops' . $this->{template}, | ||||
162 | no_oops => 1 ); | ||||
163 | my $message = $session->templates->expandTemplate( $this->{def} ) | ||||
164 | || "Failed to find '$this->{def}' in 'oops$this->{template}'"; | ||||
165 | my $topicObject = | ||||
166 | Foswiki::Meta->new( $session, $this->{web}, $this->{topic} ); | ||||
167 | $message = $topicObject->expandMacros($message); | ||||
168 | my $n = 1; | ||||
169 | foreach my $param ( @{ $this->{params} } ) { | ||||
170 | $message =~ s/%PARAM$n%/$param/g; | ||||
171 | $n++; | ||||
172 | } | ||||
173 | return $message; | ||||
174 | } | ||||
175 | else { | ||||
176 | my $s = 'OopsException('; | ||||
177 | $s .= $this->{template}; | ||||
178 | $s .= '/' . $this->{def} if $this->{def}; | ||||
179 | $s .= ' web=>' . $this->{web} if $this->{web}; | ||||
180 | $s .= ' topic=>' . $this->{topic} if $this->{topic}; | ||||
181 | $s .= ' keep=>1' if $this->{keep}; | ||||
182 | if ( defined $this->{params} ) { | ||||
183 | $s .= ' params=>[' . join( ',', @{ $this->{params} } ) . ']'; | ||||
184 | } | ||||
185 | return $s . ')' . ( (DEBUG) ? $this->stacktrace : '' ); | ||||
186 | } | ||||
187 | } | ||||
188 | |||||
189 | # Generate a redirect to an 'oops' script for this exception. | ||||
190 | # | ||||
191 | # If the 'keep' parameter is set in the | ||||
192 | # exception, it saves parameter values into the query as well. This is needed | ||||
193 | # if the query string might get lost during a passthrough, due to a POST | ||||
194 | # being redirected to a GET. | ||||
195 | # This redirect has been replaced by the generate function below and should | ||||
196 | # not be called in new code. | ||||
197 | sub redirect { | ||||
198 | my ( $this, $session ) = @_; | ||||
199 | |||||
200 | my @p = $this->_prepareResponse($session); | ||||
201 | my $url = | ||||
202 | $session->getScriptUrl( 1, 'oops', $this->{web}, $this->{topic}, @p ); | ||||
203 | $session->redirect( $url, 1 ); | ||||
204 | } | ||||
205 | |||||
206 | =begin TML | ||||
207 | |||||
208 | ---++ ObjectMethod generate( $session ) | ||||
209 | |||||
210 | Generate an error page for the exception. This will output the error page | ||||
211 | to the browser. The default HTTP Status for an Oops page is 500. This | ||||
212 | can be overridden using the 'status => ' parameter to the constructor. | ||||
213 | |||||
214 | =cut | ||||
215 | |||||
216 | sub generate { | ||||
217 | my ( $this, $session ) = @_; | ||||
218 | |||||
219 | my @p = $this->_prepareResponse($session); | ||||
220 | $session->{response}->status( $this->{status} ); | ||||
221 | require Foswiki::UI::Oops; | ||||
222 | Foswiki::UI::Oops::oops( $session, $this->{web}, $this->{topic}, | ||||
223 | $session->{request}, 0 ); | ||||
224 | } | ||||
225 | |||||
226 | sub _prepareResponse { | ||||
227 | my ( $this, $session ) = @_; | ||||
228 | my @p = (); | ||||
229 | |||||
230 | $this->{template} = "oops$this->{template}" | ||||
231 | unless $this->{template} =~ /^oops/; | ||||
232 | push( @p, template => $this->{template} ); | ||||
233 | push( @p, def => $this->{def} ) if $this->{def}; | ||||
234 | my $n = 1; | ||||
235 | push( @p, map { 'param' . ( $n++ ) => $_ } @{ $this->{params} } ); | ||||
236 | while ( my $p = shift(@p) ) { | ||||
237 | $session->{request}->param( -name => $p, -value => shift(@p) ); | ||||
238 | } | ||||
239 | return @p; | ||||
240 | } | ||||
241 | |||||
242 | 1 | 6µs | 1; | ||
243 | __END__ |