File Coverage

blib/lib/HTML/Mason/Request.pm
Criterion Covered Total %
statement 638 672 94.9
branch 285 338 84.3
condition 73 98 74.4
subroutine 84 85 98.8
pod 36 41 87.8
total 1116 1234 90.4


line stmt bran cond sub pod time code
1             # -*- cperl-indent-level: 4; cperl-continued-brace-offset: -4; cperl-continued-statement-offset: 4 -*-
2              
3             # Copyright (c) 1998-2005 by Jonathan Swartz. All rights reserved.
4             # This program is free software; you can redistribute it and/or modify it
5             # under the same terms as Perl itself.
6              
7              
8             #
9             # A note about the internals:
10             #
11             # Because request is the single most intensively used piece of the
12             # Mason architecture, this module is often the best target for
13             # optimization.
14             #
15             # By far, the two methods called most often are comp() and print().
16             # We have attempted to optimize the parts of these methods that handle
17             # the _normal_ path through the code.
18             #
19             # Code paths that are followed less frequently (like the path that
20             # handles the $mods{store} parameter in comp, for example) are
21             # intentionally not optimized because doing so would clutter the code
22             # while providing a minimal benefit.
23             #
24             # Many of the optimizations consist of ignoring defined interfaces for
25             # accessing parts of the request object's internal data structure, and
26             # instead accessing it directly.
27             #
28             # We have attempted to comment these various optimizations
29             # appropriately, so that future hackers understand that we did indeed
30             # mean to not use the relevant interface in that particular spot.
31             #
32              
33             package HTML::Mason::Request;
34             $HTML::Mason::Request::VERSION = '1.58';
35 33     33   202 use strict;
  33         85  
  33         989  
36 33     33   156 use warnings;
  33         404  
  33         954  
37              
38 32     32   158 use File::Spec;
  32         65  
  32         628  
39 32     32   8911 use HTML::Mason::Cache::BaseCache;
  32         76  
  32         898  
40 32     32   8517 use HTML::Mason::Plugin::Context;
  32         81  
  32         920  
41 32     32   9028 use HTML::Mason::Tools qw(can_weaken read_file compress_path load_pkg pkg_loaded absolute_comp_path);
  32         88  
  32         2603  
42 32     32   10476 use HTML::Mason::Utils;
  32         75  
  32         1345  
43 32     32   8419 use Log::Any qw($log);
  32         189175  
  32         156  
44 32     32   61528 use Class::Container;
  32         98311  
  32         1067  
45 32     32   300 use base qw(Class::Container);
  32         75  
  32         3803  
46              
47             # Stack frame constants
48 32     32   203 use constant STACK_COMP => 0;
  32         67  
  32         1799  
49 32     32   172 use constant STACK_ARGS => 1;
  32         60  
  32         1257  
50 32     32   161 use constant STACK_BUFFER => 2;
  32         60  
  32         1193  
51 32     32   168 use constant STACK_MODS => 3;
  32         58  
  32         1192  
52 32     32   154 use constant STACK_PATH => 4;
  32         67  
  32         1255  
53 32     32   175 use constant STACK_BASE_COMP => 5;
  32         59  
  32         1152  
54 32     32   161 use constant STACK_IN_CALL_SELF => 6;
  32         57  
  32         1124  
55 32     32   153 use constant STACK_BUFFER_IS_FLUSHABLE => 7;
  32         60  
  32         1147  
56 32     32   163 use constant STACK_HIDDEN_BUFFER => 8;
  32         65  
  32         1573  
57              
58             # HTML::Mason::Exceptions always exports rethrow_exception() and isa_mason_exception()
59 32         278 use HTML::Mason::Exceptions( abbr => [qw(error param_error syntax_error
60 32     32   192 top_level_not_found_error error)] );
  32         83  
61              
62 32     32   172 use Params::Validate qw(:all);
  32         61  
  32         13821  
63             Params::Validate::validation_options( on_fail => sub { param_error( join '', @_ ) } );
64              
65             BEGIN
66             {
67             __PACKAGE__->valid_params
68             (
69             args =>
70             { type => ARRAYREF, default => [],
71             descr => "Array of arguments to initial component",
72             public => 0 },
73              
74             autoflush =>
75             { parse => 'boolean', default => 0, type => SCALAR,
76             descr => "Whether output should be buffered or sent immediately" },
77              
78             comp =>
79             { type => SCALAR | OBJECT, optional => 0,
80             descr => "Initial component, either an absolute path or a component object",
81             public => 0 },
82              
83             data_cache_api =>
84             { parse => 'string', default => '1.1', type => SCALAR,
85             regex => qr/^(?:1\.0|1\.1|chi)$/,
86             descr => "Data cache API to use: 1.0, 1.1, or chi" },
87              
88             data_cache_defaults =>
89             { parse => 'hash_list', type => HASHREF|UNDEF, optional => 1,
90             descr => "A hash of default parameters for Cache::Cache or CHI" },
91              
92             declined_comps =>
93             { type => HASHREF, optional => 1,
94             descr => "Hash of components that have been declined in previous parent requests",
95             public => 0 },
96              
97             dhandler_name =>
98             { parse => 'string', default => 'dhandler', type => SCALAR,
99             descr => "The filename to use for Mason's 'dhandler' capability" },
100              
101             interp =>
102             { isa => 'HTML::Mason::Interp',
103             descr => "An interpreter for Mason control functions",
104             public => 0 },
105              
106             error_format =>
107             { parse => 'string', type => SCALAR, default => 'text',
108             callbacks => { "HTML::Mason::Exception->can( method )'" =>
109 97         9952 sub { HTML::Mason::Exception->can("as_$_[0]"); } },
110             descr => "How error conditions are returned to the caller (brief, text, line or html)" },
111              
112             error_mode =>
113             { parse => 'string', type => SCALAR, default => 'fatal',
114             regex => qr/^(?:output|fatal)$/,
115             descr => "How error conditions are manifest (output or fatal)" },
116              
117             component_error_handler =>
118             { parse => 'code', type => CODEREF|SCALAR, default => \&rethrow_exception,
119             descr => "A subroutine reference called on component compilation or runtime errors" },
120              
121             max_recurse =>
122             { parse => 'string', default => 32, type => SCALAR,
123             descr => "The maximum recursion depth for component, inheritance, and request stack" },
124              
125             out_method =>
126             { parse => 'code' ,type => CODEREF|SCALARREF,
127 6         80 default => sub { print STDOUT $_[0] },
128 32     32   1578 descr => "A subroutine or scalar reference through which all output will pass" },
129              
130             # Only used when creating subrequests
131             parent_request =>
132             { isa => __PACKAGE__,
133             default => undef,
134             public => 0,
135             },
136              
137             plugins =>
138             { parse => 'list', default => [], type => ARRAYREF,
139             descr => 'List of plugin classes or objects to run hooks around components and requests' },
140              
141             # Only used when creating subrequests
142             request_depth =>
143             { type => SCALAR,
144             default => 1,
145             public => 0,
146             },
147              
148             );
149             }
150              
151             my @read_write_params;
152 32     32   3519 BEGIN { @read_write_params = qw(
153             autoflush
154             component_error_handler
155             data_cache_api
156             data_cache_defaults
157             dhandler_name
158             error_format
159             error_mode
160             max_recurse
161             out_method
162             ); }
163              
164             use HTML::Mason::MethodMaker
165             ( read_only => [ qw(
166             count
167             dhandler_arg
168             initialized
169             interp
170             parent_request
171             plugin_instances
172             request_depth
173             request_comp
174             ) ],
175              
176 32         117 read_write => [ map { [ $_ => __PACKAGE__->validation_spec->{$_} ] }
  288         4187  
177             @read_write_params ]
178 32     32   216 );
  32         62  
179              
180 82     82   246 sub _properties { @read_write_params }
181              
182             sub new
183             {
184 479     479 1 20850 my $class = shift;
185 479         1673 my $self = $class->SUPER::new(@_);
186              
187             # These are mandatory values for all requests.
188             #
189 479         49490 %$self = (%$self,
190             dhandler_arg => undef,
191             execd => 0,
192             initialized => 0,
193             stack => [],
194             top_stack => undef,
195             wrapper_chain => undef,
196             wrapper_index => undef,
197             notes => {},
198             );
199              
200 479         1845 $self->{request_comp} = delete($self->{comp});
201 479         1199 $self->{request_args} = delete($self->{args});
202 479 50       2020 if (UNIVERSAL::isa($self->{request_args}, 'HASH')) {
203 0         0 $self->{request_args} = [%{$self->{request_args}}];
  0         0  
204             }
205 479         1554 $self->{count} = ++$self->{interp}{request_count};
206 479 100       1507 if (ref($self->{out_method}) eq 'SCALAR') {
207 16         25 my $bufref = $self->{out_method};
208 16     13   83 $self->{out_method} = sub { $$bufref .= $_[0] };
  13         45  
209             }
210             $self->{use_internal_component_caches} =
211 479         1585 $self->{interp}->use_internal_component_caches;
212 479         1639 $self->_initialize;
213              
214 444         3052 return $self;
215             }
216              
217             # in the future this method may do something completely different but
218             # for now this works just fine.
219             sub instance {
220 29     29 1 135 return $HTML::Mason::Commands::m; #; this comment fixes a parsing bug in Emacs cperl-mode
221             }
222              
223             # Attempt to load each plugin module once per process
224             my %plugin_loaded;
225              
226             sub _initialize {
227 479     479   1020 my ($self) = @_;
228              
229 479 100       1368 local $SIG{'__DIE__'} = $self->component_error_handler
230             if $self->component_error_handler;
231              
232 479         966 eval {
233             # Check the static_source touch file, if it exists, before the
234             # first component is loaded.
235             #
236 479         1477 $self->interp->check_static_source_touch_file();
237              
238             # request_comp can be an absolute path or component object. If a path,
239             # load into object.
240 479         994 my $request_comp = $self->{request_comp};
241 479         818 my ($path);
242 479 100       1240 if (!ref($request_comp)) {
    50          
243 472         3723 $request_comp =~ s{/+}{/}g;
244 472         1446 $self->{top_path} = $path = $request_comp;
245             $log->debugf("top path is '%s'", $self->{top_path})
246 472 100       2475 if $log->is_debug;
247              
248 472         5808 my $retry_count = 0;
249             search: {
250 472         737 $request_comp = $self->interp->load($path);
  483         1166  
251              
252 455 100       1729 last search unless $self->use_dhandlers;
253              
254             # If path was not found, check for dhandler.
255 453 100       1211 unless ($request_comp) {
256 25 100       65 if ( $request_comp = $self->interp->find_comp_upwards($path, $self->dhandler_name) ) {
257 20         48 my $parent_path = $request_comp->dir_path;
258 20         345 ($self->{dhandler_arg} = $self->{top_path}) =~ s{^$parent_path/?}{};
259             $log->debugf("found dhandler '%s', dhandler_arg '%s'", $parent_path, $self->{dhandler_arg})
260 20 50       82 if $log->is_debug;
261             }
262             }
263              
264             # If the component was declined previously in this
265             # request, look for the next dhandler up the
266             # tree.
267 453 100 100     2510 if ($request_comp and $self->{declined_comps}->{$request_comp->comp_id}) {
268 12         24 $path = $request_comp->dir_path;
269 12 100       23 if ($request_comp->name eq $self->dhandler_name) {
270 6 100       15 if ($path eq '/') {
271 1         2 undef $request_comp;
272 1         2 last search; # End search if /dhandler declined
273             } else {
274 5         24 $path =~ s:/[^\/]+$::;
275 5   100     18 $path ||= '/';
276             }
277             }
278 11 50       35 if ($retry_count++ > $self->max_recurse) {
279 0         0 error "could not find dhandler after " . $self->max_recurse . " tries (infinite loop bug?)";
280             }
281 11         24 redo search;
282             }
283             }
284              
285 444 100       1447 unless ($self->{request_comp} = $request_comp) {
286             top_level_not_found_error "could not find component for initial path '$self->{top_path}' " .
287             "(component roots are: " .
288 7         40 join(", ", map { "'" . $_->[1] . "'" } $self->{interp}->comp_root_array) .
  9         72  
289             ")";
290             }
291              
292             } elsif ( ! UNIVERSAL::isa( $request_comp, 'HTML::Mason::Component' ) ) {
293 0         0 param_error "comp ($request_comp) must be a component path or a component object";
294             }
295              
296             # Construct a plugin instance for each plugin class in each request.
297             #
298 444         969 $self->{has_plugins} = 0;
299 444         978 $self->{plugin_instances} = [];
300 444         768 foreach my $plugin (@{ delete $self->{plugins} }) {
  444         1262  
301 25         38 $self->{has_plugins} = 1;
302 25         44 my $plugin_instance = $plugin;
303 25 100       49 unless (ref $plugin) {
304              
305             # Load information about each plugin class once per
306             # process. Right now the only information we need is
307             # whether there is a new() method.
308             #
309 23 100       50 unless ($plugin_loaded{$plugin}) {
310             # Load plugin package if it isn't already loaded.
311             #
312             {
313 32     32   226 no strict 'refs';
  32         64  
  32         8241  
  13         16  
314 13 50       15 unless (keys %{$plugin . "::"}) {
  13         96  
315 0         0 eval "use $plugin;";
316 0 0       0 die $@ if $@;
317             }
318             }
319 13         28 $plugin_loaded{$plugin} = 1;
320             }
321 23         151 $plugin_instance = $plugin->new();
322             }
323 25         32 push @{$self->{plugin_instances}}, $plugin_instance;
  25         66  
324             }
325 444         819 $self->{plugin_instances_reverse} = [reverse(@{$self->{plugin_instances}})];
  444         1157  
326              
327             # Check for autoflush and !enable_autoflush
328             #
329 444 100 100     1623 if ($self->{autoflush} && !$self->interp->compiler->enable_autoflush) {
330 1         15 die "Cannot use autoflush unless enable_autoflush is set";
331             }
332              
333             };
334              
335 479         1914 my $err = $@;
336 479 100 66     1358 if ($err and !$self->_aborted_or_declined($err)) {
337 36         126 $self->_handle_error($err);
338             } else {
339 443         1846 $self->{initialized} = 1;
340             }
341             }
342              
343             sub use_dhandlers
344             {
345 456     456 0 789 my $self = shift;
346 456   66     2234 return (defined $self->{dhandler_name} and length $self->{dhandler_name});
347             }
348              
349             sub alter_superclass
350             {
351 2     2 0 106 my $self = shift;
352 2         3 my $new_super = shift;
353              
354 2         4 my $class = caller;
355              
356 2         3 my $isa_ref;
357             {
358 32     32   243 no strict 'refs';
  32         63  
  32         2871  
  2         73  
359 2         63 my @isa = @{ $class . '::ISA' };
  2         19  
360 2         8 $isa_ref = \@isa;
361             }
362              
363             # handles multiple inheritance properly and preserve
364             # inheritance order
365 2         7 for ( my $x = 0; $x <= $#{$isa_ref} ; $x++ )
  2         8  
366             {
367 2 50       13 if ( $isa_ref->[$x]->isa('HTML::Mason::Request') )
368             {
369 2         4 my $old_super = $isa_ref->[$x];
370              
371 2 50       5 if ( $old_super ne $new_super )
372             {
373 0         0 $isa_ref->[$x] = $new_super;
374             }
375              
376 2         4 last;
377             }
378             }
379              
380             {
381 32     32   174 no strict 'refs';
  32         65  
  32         158019  
  2         2  
382 2         3 @{ $class . '::ISA' } = @{ $isa_ref };
  2         44  
  2         3  
383             }
384              
385 2         7 $class->valid_params( %{ $class->valid_params } );
  2         8  
386             }
387              
388             sub exec {
389 444     444 1 1071 my ($self) = @_;
390              
391             # If the request failed to initialize, the error has already been handled
392             # at the bottom of _initialize(); just return.
393 444 100       1331 return unless $self->initialized();
394              
395 443 100       1287 local $SIG{'__DIE__'} = $self->component_error_handler
396             if $self->component_error_handler;
397              
398             # Cheap way to prevent users from executing the same request twice.
399             #
400 443 100       1464 if ($self->{execd}++) {
401 1         7 error "Can only call exec() once for a given request object. Did you want to use a subrequest?";
402             }
403              
404             # Check for infinite subrequest loop.
405             #
406 442 100       1250 error "subrequest depth > " . $self->max_recurse . " (infinite subrequest loop?)"
407             if $self->request_depth > $self->max_recurse;
408              
409             #
410             # $m is a dynamically scoped global containing this
411             # request. This needs to be defined in the HTML::Mason::Commands
412             # package, as well as the component package if that is different.
413             #
414 441         873 local $HTML::Mason::Commands::m = $self;
415              
416             # Dynamically scoped global pointing at the top of the request stack.
417             #
418 441         748 $self->{top_stack} = undef;
419              
420             # Save context of subroutine for use inside eval.
421 441         706 my $wantarray = wantarray;
422 441         695 my @result;
423              
424             # Initialize output buffer to interpreter's preallocated buffer
425             # before clearing, to reduce memory reallocations.
426             #
427 441         1111 $self->{request_buffer} = $self->interp->preallocated_output_buffer;
428 441         863 $self->{request_buffer} = '';
429              
430 441 100       1903 $log->debugf("starting request for '%s'", $self->request_comp->title)
431             if $log->is_debug;
432              
433 441         4183 eval {
434             # Build wrapper chain and index.
435 441         1145 my $request_comp = $self->request_comp;
436 441         700 my $first_comp;
437             {
438 441         629 my @wrapper_chain = ($request_comp);
  441         979  
439              
440 441         1622 for (my $parent = $request_comp->parent; $parent; $parent = $parent->parent) {
441 26         60 unshift(@wrapper_chain,$parent);
442 26 50       78 error "inheritance chain length > " . $self->max_recurse . " (infinite inheritance loop?)"
443             if (@wrapper_chain > $self->max_recurse);
444             }
445              
446 441         764 $first_comp = $wrapper_chain[0];
447 441         1221 $self->{wrapper_chain} = [@wrapper_chain];
448             $self->{wrapper_index} = { map
449 441         1258 { $wrapper_chain[$_]->comp_id => $_ }
  467         1214  
450             (0..$#wrapper_chain)
451             };
452             }
453              
454             # Get original request_args array reference to avoid copying.
455 441         1037 my $request_args = $self->{request_args};
456             {
457 441         648 local *SELECTED;
  441         1132  
458 441         3409 tie *SELECTED, 'Tie::Handle::Mason';
459              
460 441         1610 my $old = select SELECTED;
461 441         2047 my $mods = {base_comp => $request_comp, store => \($self->{request_buffer}), flushable => 1};
462              
463 441 100       1221 if ($self->{has_plugins}) {
464 20         75 my $context = bless
465             [$self, $request_args],
466             'HTML::Mason::Plugin::Context::StartRequest';
467 20         32 eval {
468 20         24 foreach my $plugin_instance (@{$self->plugin_instances}) {
  20         44  
469 25         107 $plugin_instance->start_request_hook( $context );
470             }
471             };
472 20 100       67 if ($@) {
473 1         7 select $old;
474 1         3 rethrow_exception $@;
475             }
476             }
477              
478 440 100       1284 if ($wantarray) {
    100          
479 2         4 @result = eval {$self->comp($mods, $first_comp, @$request_args)};
  2         6  
480             } elsif (defined($wantarray)) {
481 16         23 $result[0] = eval {$self->comp($mods, $first_comp, @$request_args)};
  16         59  
482             } else {
483 422         681 eval {$self->comp($mods, $first_comp, @$request_args)};
  422         1626  
484             }
485            
486 440         1381 my $error = $@;
487              
488 440 100       1142 if ($self->{has_plugins}) {
489             # plugins called in reverse order when exiting.
490             my $context = bless
491 19         87 [$self, $request_args, \$self->{request_buffer}, $wantarray, \@result, \$error],
492             'HTML::Mason::Plugin::Context::EndRequest';
493 19         34 eval {
494 19         47 foreach my $plugin_instance (@{$self->{plugin_instances_reverse}}) {
  19         43  
495 24         106 $plugin_instance->end_request_hook( $context );
496             }
497             };
498 19 100       125 if ($@) {
499             # plugin errors take precedence over component errors
500 1         6 $error = $@;
501             }
502             }
503            
504 440         1886 select $old;
505 440         1489 rethrow_exception $error;
506             }
507             };
508              
509 441 100       2166 $log->debugf("finishing request for '%s'", $self->request_comp->title)
510             if $log->is_debug;
511              
512             # Purge code cache if necessary.
513 441         4330 $self->interp->purge_code_cache;
514              
515             # Handle errors.
516 441         863 my $err = $@;
517 441 100 100     1225 if ($err and !$self->_aborted_or_declined($err)) {
518 82         241 $self->_handle_error($err);
519 6         83 return;
520             }
521              
522             # If there's anything in the output buffer, send it to out_method.
523             # Otherwise skip out_method call to avoid triggering side effects
524             # (e.g. HTTP header sending).
525 359 100       1076 if (length($self->{request_buffer}) > 0) {
526 336         1132 $self->out_method->($self->{request_buffer});
527             }
528              
529             # Return aborted value or result.
530 359 100       1201 @result = ($err->aborted_value) if $self->aborted($err);
531 359 100       1062 @result = ($err->declined_value) if $self->declined($err);
532 359 100       2817 return $wantarray ? @result : defined($wantarray) ? $result[0] : undef;
    100          
533             }
534              
535             #
536             # Display or die with error as dictated by error_mode and error_format.
537             #
538             sub _handle_error
539             {
540 118     118   232 my ($self, $err) = @_;
541              
542 118         280 $self->interp->purge_code_cache;
543              
544 118 100       317 rethrow_exception $err if $self->is_subrequest;
545              
546             # Set error format for when error is stringified.
547 78 100       301 if (UNIVERSAL::can($err, 'format')) {
548 77         242 $err->format($self->error_format);
549             }
550              
551             # In fatal mode, die with error. In display mode, output stringified error.
552 78 100       240 if ($self->error_mode eq 'fatal') {
553 71         200 rethrow_exception $err;
554             } else {
555 7 50       19 if ( UNIVERSAL::isa( $self->out_method, 'CODE' ) ) {
556             # This may not be set if an error occurred in
557             # _initialize(), for example with a compilation error.
558             # But the output method may rely on being able to get at
559             # the request object. This is a nasty code smell but
560             # fixing it properly is probably out of scope.
561             #
562             # Previously this method could only be called from exec().
563             #
564             # Without this one of the tests in 16-live_cgi.t was
565             # failing.
566 7   33     34 local $HTML::Mason::Commands::m ||= $self;
567 7         17 $self->out_method->("$err");
568             } else {
569 0         0 ${ $self->out_method } = "$err";
  0         0  
570             }
571             }
572             }
573              
574             sub subexec
575             {
576 66     66 1 108 my $self = shift;
577 66         91 my $comp = shift;
578              
579 66         166 $self->make_subrequest(comp=>$comp, args=>\@_)->exec;
580             }
581              
582             sub make_subrequest
583             {
584 82     82 1 273 my ($self, %params) = @_;
585 82         185 my $interp = $self->interp;
586              
587             # Coerce a string 'comp' parameter into an absolute path. Don't
588             # create it if it's missing, though - it's required, but for
589             # consistency we let exceptions be thrown later.
590             $params{comp} = absolute_comp_path($params{comp}, $self->current_comp->dir_path)
591 82 100 66     427 if exists $params{comp} && !ref($params{comp});
592              
593             # Give subrequest the same values as parent request for read/write params
594 82         219 my %defaults = map { ($_, $self->$_()) } $self->_properties;
  738         1510  
595              
596 82 100       242 unless ( $params{out_method} )
597             {
598             $defaults{out_method} = sub {
599 35     35   86 $self->print($_[0]);
600 80         329 };
601             }
602              
603             # Make subrequest, and set parent_request and request_depth appropriately.
604 82         333 my $subreq =
605             $interp->make_request(%defaults, %params,
606             parent_request => $self,
607             request_depth => $self->request_depth + 1);
608              
609 77         528 return $subreq;
610             }
611              
612             sub is_subrequest
613             {
614 127     127 0 207 my ($self) = @_;
615              
616 127 100       339 return $self->parent_request ? 1 : 0;
617             }
618              
619             sub clear_and_abort
620             {
621 1     1 1 3 my $self = shift;
622              
623 1         4 $self->clear_buffer;
624 1         3 $self->abort(@_);
625             }
626              
627             sub abort
628             {
629 12     12 1 38 my ($self, $aborted_value) = @_;
630 12         191 HTML::Mason::Exception::Abort->throw( error => 'Request->abort was called', aborted_value => $aborted_value );
631             }
632              
633             #
634             # Determine whether $err (or $@ by default) is an Abort exception.
635             #
636             sub aborted {
637 512     512 1 1093 my ($self, $err) = @_;
638 512 100       1220 $err = $@ if !defined($err);
639 512         1504 return isa_mason_exception( $err, 'Abort' );
640             }
641              
642             #
643             # Determine whether $err (or $@ by default) is an Decline exception.
644             #
645             sub declined {
646 501     501 1 1086 my ($self, $err) = @_;
647 501 100       1110 $err = $@ if !defined($err);
648 501         1203 return isa_mason_exception( $err, 'Decline' );
649             }
650              
651             sub _aborted_or_declined {
652 148     148   1025 my ($self, $err) = @_;
653 148   100     387 return $self->aborted($err) || $self->declined($err);
654             }
655              
656             #
657             # Return a new cache object specific to this component.
658             #
659             sub cache
660             {
661 82     82 1 237 my ($self, %options) = @_;
662              
663             # If using 1.0x cache API, save off options for end of routine.
664 82         144 my %old_cache_options;
665 82 100       215 if ($self->data_cache_api eq '1.0') {
666 30         87 %old_cache_options = %options;
667 30         72 %options = ();
668             }
669              
670             # Combine defaults with options passed in here.
671 82 50       238 if ($self->data_cache_defaults) {
672 0         0 %options = (%{$self->data_cache_defaults}, %options);
  0         0  
673             }
674              
675             # If using the CHI API, just create and return a CHI handle. Namespace will be escaped by CHI.
676 82 50       171 if ($self->data_cache_api eq 'chi') {
677 0   0     0 my $chi_root_class = delete($options{chi_root_class}) || 'CHI';
678 0         0 load_pkg($chi_root_class);
679 0 0       0 if (!exists($options{namespace})) {
680 0         0 $options{namespace} = $self->current_comp->comp_id;
681             }
682 0 0 0     0 if (!exists($options{driver}) && !exists($options{driver_class})) {
683 0 0       0 $options{driver} = $self->interp->cache_dir ? 'File' : 'Memory';
684 0 0       0 $options{global} = 1 if $options{driver} eq 'Memory';
685             }
686 0   0     0 $options{root_dir} ||= $self->interp->cache_dir;
687 0         0 return $chi_root_class->new(%options);
688             }
689              
690 82   66     401 $options{cache_root} ||= $self->interp->cache_dir;
691 82   33     396 $options{namespace} ||= compress_path($self->current_comp->comp_id);
692              
693             # Determine cache_class, adding 'Cache::' in front of user's
694             # specification if necessary.
695 82 100       222 my $cache_class = $self->interp->cache_dir ? 'Cache::FileCache' : 'Cache::MemoryCache';
696 82 100       238 if ($options{cache_class}) {
697 2         5 $cache_class = $options{cache_class};
698 2 100       8 $cache_class = "Cache::$cache_class" unless $cache_class =~ /::/;
699 2         5 delete($options{cache_class});
700             }
701              
702             # Now prefix cache class with "HTML::Mason::". This will be a
703             # dynamically constructed package that simply inherits from
704             # HTML::Mason::Cache::BaseCache and the chosen cache class.
705 82         189 my $mason_cache_class = "HTML::Mason::$cache_class";
706 82 100       227 unless (pkg_loaded($mason_cache_class)) {
707 4         21 load_pkg('Cache::Cache', '$m->cache requires the Cache::Cache module, available from CPAN.');
708 4         15 load_pkg($cache_class, 'Fix your Cache::Cache installation or choose another cache class.');
709             # need to break up mention of VERSION var or else CPAN/EU::MM can choke when running 'r'
710 4     3   286 eval sprintf('package %s; use base qw(HTML::Mason::Cache::BaseCache %s); use vars qw($' . 'VERSION); $' . 'VERSION = 1.0;',
  3     3   21  
  3         5  
  3         698  
  3         17  
  3         5  
  3         89  
711             $mason_cache_class, $cache_class);
712 4 50       16 error "Error constructing mason cache class $mason_cache_class: $@" if $@;
713             }
714              
715 82 50       466 my $cache = $mason_cache_class->new (\%options)
716             or error "could not create cache object";
717              
718             # Implement 1.0x cache API or just return cache object.
719 82 100       17060 if ($self->data_cache_api eq '1.0') {
720 30         101 return $self->_cache_1_x($cache, %old_cache_options);
721             } else {
722 52         258 return $cache;
723             }
724             }
725              
726             #
727             # Implement 1.0x cache API in terms of Cache::Cache.
728             # Supported: action, busy_lock, expire_at, expire_if, expire_in, expire_next, key, value
729             # Silently not supported: keep_in_memory, tie_class
730             #
731             sub _cache_1_x
732             {
733 30     30   86 my ($self, $cache, %options) = @_;
734              
735 30   100     106 my $action = $options{action} || 'retrieve';
736 30   100     96 my $key = $options{key} || 'main';
737            
738 30 100       88 if ($action eq 'retrieve') {
    100          
    100          
    50          
739            
740             # Validate parameters.
741 20 50       142 if (my @invalids = grep(!/^(expire_if|action|key|busy_lock|keep_in_memory|tie_class)$/, keys(%options))) {
742 0         0 param_error "cache: invalid parameter '$invalids[0]' for action '$action'\n";
743             }
744              
745             # Handle expire_if.
746 20 100       60 if (my $sub = $options{expire_if}) {
747 2 50       6 if (my $obj = $cache->get_object($key)) {
748 2 100       736 if ($sub->($obj->get_created_at)) {
749 1         6 $cache->expire($key);
750             }
751             }
752             }
753              
754             # Return the value or undef, handling busy_lock.
755 20 100       710 if (my $result = $cache->get($key, ($options{busy_lock} ? (busy_lock=>$options{busy_lock}) : ()))) {
    100          
756 11         149 return $result;
757             } else {
758 9         490 return undef;
759             }
760              
761             } elsif ($action eq 'store') {
762              
763             # Validate parameters
764 8 50       87 if (my @invalids = grep(!/^(expire_(at|next|in)|action|key|value|keep_in_memory|tie_class)$/, keys(%options))) {
765 0         0 param_error "cache: invalid parameter '$invalids[0]' for action '$action'\n";
766             }
767 8 50       27 param_error "cache: no store value provided" unless exists($options{value});
768              
769             # Determine $expires_in if expire flag given. For the "next"
770             # options, we're jumping through hoops to find the *top* of
771             # the next hour or day.
772             #
773 8         13 my $expires_in;
774 8         12 my $time = time;
775 8 100       30 if (exists($options{expire_at})) {
    50          
    50          
776 2 50       16 param_error "cache: invalid expire_at value '$options{expire_at}' - must be a numeric time value\n" if $options{expire_at} !~ /^[0-9]+$/;
777 2         6 $expires_in = $options{expire_at} - $time;
778             } elsif (exists($options{expire_next})) {
779 0         0 my $term = $options{expire_next};
780 0         0 my ($sec, $min, $hour) = localtime($time);
781 0 0       0 if ($term eq 'hour') {
    0          
782 0         0 $expires_in = 60*(59-$min)+(60-$sec);
783             } elsif ($term eq 'day') {
784 0         0 $expires_in = 3600*(23-$hour)+60*(59-$min)+(60-$sec);
785             } else {
786 0         0 param_error "cache: invalid expire_next value '$term' - must be 'hour' or 'day'\n";
787             }
788             } elsif (exists($options{expire_in})) {
789 0         0 $expires_in = $options{expire_in};
790             }
791              
792             # Set and return the value.
793 8         15 my $value = $options{value};
794 8         33 $cache->set($key, $value, $expires_in);
795 8         9440 return $value;
796              
797             } elsif ($action eq 'expire') {
798 1 50       5 my @keys = (ref($key) eq 'ARRAY') ? @$key : ($key);
799 1         3 foreach my $key (@keys) {
800 2         761 $cache->expire($key);
801             }
802              
803             } elsif ($action eq 'keys') {
804 1         14 return $cache->get_keys;
805             }
806             }
807              
808             sub cache_self {
809 51     51 1 149 my ($self, %options) = @_;
810              
811 51 100       179 return if $self->{top_stack}->[STACK_IN_CALL_SELF]->{'CACHE_SELF'};
812              
813 33         92 my (%store_options, %retrieve_options);
814 33         0 my ($expires_in, $key, $cache);
815 33 100       95 if ($self->data_cache_api eq '1.0') {
816 3         7 foreach (qw(key expire_if busy_lock)) {
817 9 100       22 $retrieve_options{$_} = $options{$_} if (exists($options{$_}));
818             }
819 3         6 foreach (qw(key expire_at expire_next expire_in)) {
820 12 100       26 $store_options{$_} = $options{$_} if (exists($options{$_}));
821             }
822             } else {
823             #
824             # key, expires_in/expire_in, expire_if and busy_lock go into
825             # the set and get methods as appropriate. All other options
826             # are passed into $self->cache.
827             #
828 30         80 foreach (qw(expire_if busy_lock)) {
829 60 100       146 $retrieve_options{$_} = delete($options{$_}) if (exists($options{$_}));
830             }
831 30   100     170 $expires_in = delete $options{expires_in} || delete $options{expire_in} || 'never';
832 30   100     98 $key = delete $options{key} || '__mason_cache_self__';
833 30         105 $cache = $self->cache(%options);
834             }
835              
836 33         70 my ($output, @retval, $error);
837              
838 33 100       83 my $cached =
839             ( $self->data_cache_api eq '1.0' ?
840             $self->cache(%retrieve_options) :
841             $cache->get($key, %retrieve_options)
842             );
843              
844 33 100       2228 if ($cached) {
845 15         41 ($output, my $retval) = @$cached;
846 15         30 @retval = @$retval;
847             } else {
848 18         93 $self->call_self( \$output, \@retval, \$error, 'CACHE_SELF' );
849              
850             # If user aborted or declined, store in cache and print output
851             # before repropagating.
852             #
853 18 100       60 rethrow_exception $error
854             unless ($self->_aborted_or_declined($error));
855              
856 16         77 my $value = [$output, \@retval];
857 16 100       55 if ($self->data_cache_api eq '1.0') {
858 1         5 $self->cache(action=>'store', key=>$key, value=>$value, %store_options);
859             } else {
860 15         65 $cache->set($key, $value, $expires_in);
861             }
862             }
863              
864             #
865             # Print the component output.
866             #
867 31         18531 $self->print($output);
868              
869             #
870             # Rethrow abort/decline exception if any.
871             #
872 31         109 rethrow_exception $error;
873              
874             #
875             # Return the component return value in case the caller is interested,
876             # followed by 1 indicating the cache retrieval success.
877             #
878 29         238 return (@retval, 1);
879             }
880              
881             sub call_self
882             {
883 26     26 1 71 my ($self, $output, $retval, $error, $tag) = @_;
884              
885             # Keep track of each individual invocation of call_self in the
886             # component, via $tag. $tag is 'CACHE_SELF' or 'FILTER' when used
887             # by $m->cache_self and <%filter> sections respectively.
888             #
889 26   100     84 $tag ||= 'DEFAULT';
890 26         55 my $top_stack = $self->{top_stack};
891 26   100     79 $top_stack->[STACK_IN_CALL_SELF] ||= {};
892 26 100       77 return if $top_stack->[STACK_IN_CALL_SELF]->{$tag};
893 22         78 local $top_stack->[STACK_IN_CALL_SELF]->{$tag} = 1;
894              
895             # Determine wantarray based on retval reference
896 22 50       105 my $wantarray =
    100          
897             ( defined $retval ?
898             ( UNIVERSAL::isa( $retval, 'ARRAY' ) ? 1 : 0 ) :
899             undef
900             );
901              
902             # If output or retval references were left undefined, just point
903             # them to a dummy variable.
904             #
905 22         37 my $dummy;
906 22   100     60 $output ||= \$dummy;
907 22   100     58 $retval ||= \$dummy;
908              
909             # Temporarily put $output in place of the current top buffer.
910 22         47 local $top_stack->[STACK_BUFFER] = $output;
911              
912             # Call the component again, capturing output, return value and
913             # error. Don't catch errors unless the error reference was specified.
914             #
915 22         42 my $comp = $top_stack->[STACK_COMP];
916 22         33 my $args = $top_stack->[STACK_ARGS];
917 22         39 my @result;
918 22         36 eval {
919 22 100       54 if ($wantarray) {
    50          
920 20         80 @$retval = $comp->run(@$args);
921             } elsif (defined $wantarray) {
922 0         0 $$retval = $comp->run(@$args);
923             } else {
924 2         6 $comp->run(@$args);
925             }
926             };
927 22 100       92 if ($@) {
928 4 50       28 if ($error) {
929 4         8 $$error = $@;
930             } else {
931 0         0 die $@;
932             }
933             }
934              
935             # Return 1, indicating that this invocation of call_self is done.
936             #
937 22         78 return 1;
938             }
939              
940             sub call_dynamic {
941 22     22 0 53 my ($m, $key, @args) = @_;
942 22 100       57 my $comp = ($m->current_comp->is_subcomp) ? $m->current_comp->owner : $m->current_comp;
943 22 100 66     84 if (!defined($comp->dynamic_subs_request) or $comp->dynamic_subs_request ne $m) {
944 13         88 $comp->dynamic_subs_init;
945 8         25 $comp->dynamic_subs_request($m);
946             }
947              
948 17         73 return $comp->run_dynamic_sub($key, @args);
949             }
950              
951             sub call_next {
952 23     23 1 61 my ($self,@extra_args) = @_;
953 23 50       63 my $comp = $self->fetch_next
954             or error "call_next: no next component to invoke";
955 23         74 return $self->comp({base_comp=>$self->request_comp}, $comp, @{$self->current_args}, @extra_args);
  23         59  
956             }
957              
958             sub caller
959             {
960 3     3 1 9 my ($self) = @_;
961 3         11 return $self->callers(1);
962             }
963              
964             #
965             # Return a specified component from the stack, or the whole stack as a list.
966             #
967             sub callers
968             {
969 48     48 1 94 my ($self, $levels_back) = @_;
970 48 100       139 if (defined($levels_back)) {
971 39         89 my $frame = $self->_stack_frame($levels_back);
972 39 100       104 return unless defined $frame;
973 31         111 return $frame->[STACK_COMP];
974             } else {
975 9         22 my $depth = $self->depth;
976 9         35 return map($_->[STACK_COMP], $self->_stack_frames);
977             }
978             }
979              
980             #
981             # Return a specified argument list from the stack.
982             #
983             sub caller_args
984             {
985 3     3 1 7 my ($self, $levels_back) = @_;
986 3 50       9 param_error "caller_args expects stack level as argument" unless defined $levels_back;
987              
988 3         9 my $frame = $self->_stack_frame($levels_back);
989 3 50       10 return unless $frame;
990 3         5 my $args = $frame->[STACK_ARGS];
991 3 50       18 return wantarray ? @$args : { @$args };
992             }
993              
994             sub comp_exists
995             {
996 17     17 1 35 my ($self, $path) = @_;
997              
998             # In order to support SELF, PARENT, REQUEST, subcomponents and
999             # methods, it is easiest just to defer to fetch_comp.
1000             #
1001 17 100       30 return $self->fetch_comp($path) ? 1 : 0;
1002             }
1003              
1004             sub decline
1005             {
1006 9     9 1 19 my ($self) = @_;
1007              
1008 9         29 $self->clear_buffer;
1009             my $subreq = $self->make_subrequest
1010             (comp => $self->{top_path},
1011             args => $self->{request_args},
1012 9         31 declined_comps => {$self->request_comp->comp_id, 1, %{$self->{declined_comps}}});
  9         35  
1013 8         34 my $retval = $subreq->exec;
1014 7         50 HTML::Mason::Exception::Decline->throw( error => 'Request->decline was called', declined_value => $retval );
1015             }
1016              
1017             #
1018             # Return the current number of stack levels. 1 means top level, 0
1019             # means that no component has been called yet.
1020             #
1021             sub depth
1022             {
1023 1292     1292 1 1852 return scalar @{ $_[0]->{stack} };
  1292         3262  
1024             }
1025              
1026             #
1027             # Given a component path (absolute or relative), returns a component.
1028             # Handles SELF, PARENT, REQUEST, comp:method, relative->absolute
1029             # conversion, and local subcomponents.
1030             #
1031             # fetch_comp handles caching if use_internal_component_caches is on.
1032             # _fetch_comp does the real work.
1033             #
1034             sub fetch_comp
1035             {
1036 800     800 1 2180 my ($self, $path, $current_comp, $error, $exists_only) = @_;
1037              
1038 800 100       1744 return undef unless defined($path);
1039 798   66     4012 $current_comp ||= $self->{top_stack}->[STACK_COMP];
1040              
1041             return $self->_fetch_comp($path, $current_comp, $error)
1042 798 100       3097 unless $self->{use_internal_component_caches};
1043              
1044 35         60 my $fetch_comp_cache = $current_comp->{fetch_comp_cache};
1045 35 100       73 unless (defined($fetch_comp_cache->{$path})) {
1046              
1047             # Cache the component objects associated with
1048             # uncanonicalized paths like ../foo/bar.html. SELF and
1049             # REQUEST are dynamic and cannot be cached. Weaken the
1050             # references in this cache so that we don't hang on to the
1051             # coponent if it disappears from the main code cache.
1052             #
1053             # See Interp::_initialize for the definition of
1054             # use_internal_component_caches and the conditions under
1055             # which we can create this cache safely.
1056             #
1057 11 50       53 if ($path =~ /^(?:SELF|REQUEST)/) {
1058 0         0 return $self->_fetch_comp($path, $current_comp, $error);
1059             } else {
1060 11         34 $fetch_comp_cache->{$path} =
1061             $self->_fetch_comp($path, $current_comp, $error);
1062 11 50       36 Scalar::Util::weaken($fetch_comp_cache->{$path}) if can_weaken;
1063             }
1064             }
1065              
1066 35         118 return $fetch_comp_cache->{$path};
1067             }
1068              
1069             sub _fetch_comp
1070             {
1071 774     774   1850 my ($self, $path, $current_comp, $error) = @_;
1072              
1073             #
1074             # Handle paths SELF, PARENT, and REQUEST
1075             #
1076 774 100       1923 if ($path eq 'SELF') {
1077 63         123 return $self->base_comp;
1078             }
1079 711 100       1672 if ($path eq 'PARENT') {
1080 8         19 my $c = $current_comp->parent;
1081 8 100 100     30 $$error = "PARENT designator used from component with no parent" if !$c && defined($error);
1082 8         26 return $c;
1083             }
1084 703 100       1604 if ($path eq 'REQUEST') {
1085 4         13 return $self->request_comp;
1086             }
1087              
1088             #
1089             # Handle paths of the form comp_path:method_name
1090             #
1091 699 100       2075 if (index($path,':') != -1) {
1092 75         90 my $method_comp;
1093 75         223 my ($owner_path,$method_name) = split(':',$path,2);
1094 75 100       190 if (my $owner_comp = $self->fetch_comp($owner_path, $current_comp, $error)) {
1095 73 100       233 if ($owner_comp->_locate_inherited('methods',$method_name,\$method_comp)) {
1096 68         222 return $method_comp;
1097             } else {
1098 5 100       16 $$error = "no such method '$method_name' for component " . $owner_comp->title if defined($error);
1099             }
1100             } else {
1101 2 100 33     6 $$error ||= "could not find component for path '$owner_path'\n" if defined($error);
1102             }
1103              
1104 7         35 return $method_comp;
1105             }
1106              
1107             #
1108             # If path does not contain a slash, check for a subcomponent in the
1109             # current component first.
1110             #
1111 624 100       2137 if ($path !~ /\//) {
1112             # Check my subcomponents.
1113 460 100       1873 if (my $subcomp = $current_comp->subcomps($path)) {
1114 56         204 return $subcomp;
1115             }
1116             # If I am a subcomponent, also check my owner's subcomponents.
1117             # This won't work when we go to multiply embedded subcomponents...
1118 404 100 66     1374 if ($current_comp->is_subcomp and my $subcomp = $current_comp->owner->subcomps($path)) {
1119 5         15 return $subcomp;
1120             }
1121             }
1122              
1123             #
1124             # Otherwise pass the canonicalized absolute path to interp->load.
1125             #
1126 563         1961 $path = absolute_comp_path($path, $current_comp->dir_path);
1127 563         2159 my $comp = $self->interp->load($path);
1128              
1129 563         2919 return $comp;
1130             }
1131              
1132             #
1133             # Fetch the index of the next component in wrapper chain. If current
1134             # component is not in chain, search the component stack for the most
1135             # recent one that was.
1136             #
1137             sub _fetch_next_helper {
1138 29     29   54 my ($self) = @_;
1139 29         84 my $index = $self->{wrapper_index}->{$self->current_comp->comp_id};
1140 29 100       81 unless (defined($index)) {
1141 2         7 my @callers = $self->callers;
1142 2         5 shift(@callers);
1143 2   100     13 while (my $comp = shift(@callers) and !defined($index)) {
1144 2         6 $index = $self->{wrapper_index}->{$comp->comp_id};
1145             }
1146             }
1147 29         48 return $index;
1148             }
1149              
1150             #
1151             # Fetch next component in wrapper chain.
1152             #
1153             sub fetch_next {
1154 26     26 1 53 my ($self) = @_;
1155 26         64 my $index = $self->_fetch_next_helper;
1156 26 50       71 error "fetch_next: cannot find next component in chain"
1157             unless defined($index);
1158 26         98 return $self->{wrapper_chain}->[$index+1];
1159             }
1160              
1161             #
1162             # Fetch remaining components in wrapper chain.
1163             #
1164             sub fetch_next_all {
1165 3     3 1 7 my ($self) = @_;
1166 3         8 my $index = $self->_fetch_next_helper;
1167 3 50       6 error "fetch_next_all: cannot find next component in chain"
1168             unless defined($index);
1169 3         3 my @wc = @{$self->{wrapper_chain}};
  3         8  
1170 3         18 return @wc[($index+1)..$#wc];
1171             }
1172              
1173             sub file
1174             {
1175 3     3 1 14 my ($self,$file) = @_;
1176 3         17 my $interp = $self->interp;
1177 3 50       51 unless ( File::Spec->file_name_is_absolute($file) ) {
1178             # use owner if current comp is a subcomp
1179 3 100       17 my $context_comp =
1180             ( $self->current_comp->is_subcomp ?
1181             $self->current_comp->owner :
1182             $self->current_comp );
1183              
1184 3 50       20 if ($context_comp->is_file_based) {
1185 3         18 my $source_dir = $context_comp->source_dir;
1186 3         42 $file = File::Spec->catfile( $source_dir, $file );
1187             } else {
1188 0         0 $file = File::Spec->catfile( File::Spec->rootdir, $file );
1189             }
1190             }
1191 3         26 my $content = read_file($file,1);
1192 3         18 return $content;
1193             }
1194              
1195             sub print
1196             {
1197 3417     3417 1 5571 my $self = shift;
1198              
1199             # $self->{top_stack} is always defined _except_ in the case of a
1200             # call to print inside a start-/end-request plugin.
1201             my $bufref =
1202             ( defined $self->{top_stack}
1203             ? $self->{top_stack}->[STACK_BUFFER]
1204             : \$self->{request_buffer}
1205 3417 100       6983 );
1206              
1207             # use 'if defined' for maximum efficiency; grep creates a list.
1208 3417         5778 for ( @_ ) {
1209 3421 100       8283 $$bufref .= $_ if defined;
1210             }
1211              
1212 3417 100       8501 $self->flush_buffer if $self->{autoflush};
1213             }
1214              
1215             *out = \&print;
1216              
1217             #
1218             # Execute the given component
1219             #
1220             sub comp {
1221 1184     1184 1 2160 my $self = shift;
1222 1184         3827 my $log_is_debug = $log->is_debug;
1223              
1224             # Get modifiers: optional hash reference passed in as first argument.
1225             # Merge multiple hash references to simplify user and internal usage.
1226             #
1227 1184         9864 my %mods;
1228 1184         3517 %mods = (%{shift()}, %mods) while ref($_[0]) eq 'HASH';
  532         2927  
1229              
1230             # Get component path or object. If a path, load into object.
1231             #
1232 1184         1929 my $path;
1233 1184         1898 my $comp = shift;
1234 1184 100       2693 if (!ref($comp)) {
1235 686 50       1589 die "comp called without component - must pass a path or component object"
1236             unless defined($comp);
1237 686         1122 $path = $comp;
1238 686         1025 my $error;
1239 686 100 66     1947 $comp = $self->fetch_comp($path, undef, \$error)
1240             or error($error || "could not find component for path '$path'\n");
1241             }
1242              
1243             # Increment depth and check for maximum recursion. Depth starts at 1.
1244             #
1245 1175         3280 my $depth = $self->depth;
1246             error "$depth levels deep in component stack (infinite recursive call?)\n"
1247 1175 100       3041 if $depth >= $self->{max_recurse};
1248              
1249             # Log start of component call.
1250             #
1251 1174 100       2413 $log->debugf("entering component '%s' [depth %d]", $comp->title(), $depth)
1252             if $log_is_debug;
1253              
1254             # Keep the same output buffer unless store modifier was passed. If we have
1255             # a filter, put the filter buffer on the stack instead of the regular buffer.
1256             #
1257 1174         2097 my $filter_buffer = '';
1258 1174 100       2996 my $top_buffer = defined($mods{store}) ? $mods{store} : $self->{top_stack}->[STACK_BUFFER];
1259 1174 100       2739 my $stack_buffer = $comp->{has_filter} ? \$filter_buffer : $top_buffer;
1260 1174 100 100     4349 my $flushable = exists $mods{flushable} ? $mods{flushable} : ($self->{top_stack}->[STACK_BUFFER_IS_FLUSHABLE] && ! defined($mods{store})) ;
1261              
1262             # Add new stack frame and point dynamically scoped $self->{top_stack} at it.
1263 1174         1813 push @{ $self->{stack} },
  1174         4717  
1264             [ $comp, # STACK_COMP
1265             \@_, # STACK_ARGS
1266             $stack_buffer, # STACK_BUFFER
1267             \%mods, # STACK_MODS
1268             $path, # STACK_PATH
1269             undef, # STACK_BASE_COMP
1270             undef, # STACK_IN_CALL_SELF
1271             $flushable, # STACK_BUFFER_IS_FLUSHABLE
1272             ];
1273 1174         3376 local $self->{top_stack} = $self->{stack}->[-1];
1274              
1275             # Run start_component hooks for each plugin.
1276             #
1277 1174 100       2744 if ($self->{has_plugins}) {
1278 54         151 my $context = bless
1279             [$self, $comp, \@_],
1280             'HTML::Mason::Plugin::Context::StartComponent';
1281              
1282 54         74 foreach my $plugin_instance (@{$self->{plugin_instances}}) {
  54         98  
1283 74         221 $plugin_instance->start_component_hook( $context );
1284             }
1285             }
1286              
1287             # Finally, call the component.
1288             #
1289 1173         2066 my $wantarray = wantarray;
1290 1173         1707 my @result;
1291            
1292 1173         1873 eval {
1293             # By putting an empty block here, we protect against stack
1294             # corruption when a component calls next or last outside of a
1295             # loop. See 05-request.t #28 for a test.
1296             {
1297 1173 100       1709 if ($wantarray) {
  1173 100       2823  
1298 14         51 @result = $comp->run(@_);
1299             } elsif (defined $wantarray) {
1300 22         80 $result[0] = $comp->run(@_);
1301             } else {
1302 1137         4332 $comp->run(@_);
1303             }
1304             }
1305             };
1306 1173         4178 my $error = $@;
1307              
1308             # Run component's filter if there is one, and restore true top buffer
1309             # (e.g. in case a plugin prints something).
1310             #
1311 1173 100       2838 if ($comp->{has_filter}) {
1312             # We have to check $comp->filter because abort or error may
1313             # occur before filter gets defined in component. In such cases
1314             # there should be no output, but should look into this more.
1315             #
1316 33 100       102 if (defined($comp->filter)) {
1317 31         93 $$top_buffer .= $comp->filter->($filter_buffer);
1318             }
1319 31         215 $self->{top_stack}->[STACK_BUFFER] = $top_buffer;
1320             }
1321              
1322             # Run end_component hooks for each plugin, in reverse order.
1323             #
1324 1171 100       2639 if ($self->{has_plugins}) {
1325 53         157 my $context = bless
1326             [$self, $comp, \@_, $wantarray, \@result, \$error],
1327             'HTML::Mason::Plugin::Context::EndComponent';
1328            
1329 53         77 foreach my $plugin_instance (@{$self->{plugin_instances_reverse}}) {
  53         136  
1330 73         182 $plugin_instance->end_component_hook( $context );
1331             }
1332             }
1333              
1334             # This is very important in order to avoid memory leaks, since we
1335             # stick the arguments on the stack. If we don't pop the stack,
1336             # they don't get cleaned up until the component exits.
1337 1168         1666 pop @{ $self->{stack} };
  1168         2321  
1338              
1339             # Log end of component call.
1340             #
1341 1168 100       2607 $log->debug(sprintf("exiting component '%s' [depth %d]", $comp->title(), $depth))
1342             if $log_is_debug;
1343              
1344             # Repropagate error if one occurred, otherwise return result.
1345 1168 100       2411 rethrow_exception $error if $error;
1346 1019 100       5087 return $wantarray ? @result : $result[0];
1347             }
1348              
1349             #
1350             # Like comp, but return component output.
1351             #
1352             sub scomp {
1353 21     21 1 54 my $self = shift;
1354 21         47 my $buf;
1355 21         111 $self->comp({store => \$buf},@_);
1356 21         113 return $buf;
1357             }
1358              
1359             sub has_content {
1360 2     2 1 4 my $self = shift;
1361 2         7 return defined($self->{top_stack}->[STACK_MODS]->{content});
1362             }
1363              
1364             sub content {
1365 45     45 1 68 my $self = shift;
1366 45         82 my $content = $self->{top_stack}->[STACK_MODS]->{content};
1367 45 100       108 return undef unless defined($content);
1368              
1369             # Run the content routine with the previous stack frame active and
1370             # with output going to a new buffer.
1371             #
1372 43         68 my $err;
1373             my $buffer;
1374 43         52 my $save_frame = pop @{ $self->{stack} };
  43         88  
1375             {
1376 43         82 local $self->{top_stack} = $self->{stack}[-1];
  43         85  
1377 43         75 local $self->{top_stack}->[STACK_BUFFER] = \$buffer;
1378 43         73 local $self->{top_stack}->[STACK_BUFFER_IS_FLUSHABLE] = 0;
1379 43         89 local $self->{top_stack}->[STACK_HIDDEN_BUFFER] = $save_frame->[STACK_BUFFER];
1380 43         75 eval { $content->(); };
  43         95  
1381 43         108 $err = $@;
1382             }
1383              
1384 43         56 push @{ $self->{stack} }, $save_frame;
  43         74  
1385              
1386 43         131 rethrow_exception $err;
1387              
1388             # Return the output from the content routine.
1389             #
1390 43         118 return $buffer;
1391             }
1392              
1393             sub notes {
1394 3     3 1 4 my $self = shift;
1395 3 100       9 return $self->{notes} unless @_;
1396            
1397 2         3 my $key = shift;
1398 2 100       8 return $self->{notes}{$key} unless @_;
1399            
1400 1         3 return $self->{notes}{$key} = shift;
1401             }
1402              
1403             sub clear_buffer
1404             {
1405 28     28 1 56 my $self = shift;
1406              
1407 28         47 foreach my $frame (@{$self->{stack}}) {
  28         94  
1408 40         76 my $bufref = $frame->[STACK_BUFFER];
1409 40         77 $$bufref = '';
1410 40         66 $bufref = $frame->[STACK_HIDDEN_BUFFER];
1411 40 100       143 $$bufref = '' if $bufref;
1412             }
1413             }
1414              
1415             sub flush_buffer
1416             {
1417 147     147 1 280 my $self = shift;
1418              
1419             $self->out_method->($self->{request_buffer})
1420 147 100       630 if length $self->{request_buffer};
1421 147         356 $self->{request_buffer} = '';
1422              
1423 147 50 66     666 if ( $self->{top_stack}->[STACK_BUFFER_IS_FLUSHABLE]
1424             && $self->{top_stack}->[STACK_BUFFER] )
1425             {
1426 140         281 my $comp = $self->{top_stack}->[STACK_COMP];
1427 140 100 66     483 if ( $comp->has_filter()
1428             && defined $comp->filter() )
1429             {
1430             $self->out_method->
1431 2         4 ( $comp->filter->( ${ $self->{top_stack}->[STACK_BUFFER] } ) );
  2         11  
1432             }
1433             else
1434             {
1435 138         263 $self->out_method->( ${ $self->{top_stack}->[STACK_BUFFER] } );
  138         561  
1436             }
1437 140         283 ${$self->{top_stack}->[STACK_BUFFER]} = '';
  140         718  
1438             }
1439             }
1440              
1441             sub request_args
1442             {
1443 3     3 1 7 my ($self) = @_;
1444 3 100       9 if (wantarray) {
1445 1         2 return @{$self->{request_args}};
  1         14  
1446             } else {
1447 2         3 return { @{$self->{request_args}} };
  2         8  
1448             }
1449             }
1450              
1451             # For backward compatibility:
1452             *top_args = \&request_args;
1453             *top_comp = \&request_comp;
1454              
1455             #
1456             # Subroutine called by every component while in debug mode, convenient
1457             # for breakpointing.
1458             #
1459             sub debug_hook
1460             {
1461 0     0 0 0 1;
1462             }
1463              
1464              
1465             #
1466             # stack handling
1467             #
1468              
1469             # Return the stack frame $levels down from the top of the stack.
1470             # If $levels is negative, count from the bottom of the stack.
1471             #
1472             sub _stack_frame {
1473 42     42   68 my ($self, $levels) = @_;
1474 42         73 my $depth = $self->depth();
1475 42         50 my $index;
1476 42 100       80 if ($levels < 0) {
1477 9         14 $index = (-1 * $levels) - 1;
1478             } else {
1479 33         57 $index = $depth-1 - $levels;
1480             }
1481 42 100 100     156 return if $index < 0 or $index >= $depth;
1482 34         78 return $self->{stack}->[$index];
1483             }
1484              
1485             # Return all stack frames, in order from the top of the stack to the
1486             # initial frame.
1487             sub _stack_frames {
1488 9     9   19 my ($self) = @_;
1489              
1490 9         18 my $depth = $self->depth;
1491 9         31 return reverse map { $self->{stack}->[$_] } (0..$depth-1);
  27         84  
1492             }
1493              
1494             #
1495             # Accessor methods for top of stack elements.
1496             #
1497 320     320 1 1429 sub current_comp { return $_[0]->{top_stack}->[STACK_COMP] }
1498 23     23 1 103 sub current_args { return $_[0]->{top_stack}->[STACK_ARGS] }
1499              
1500             sub base_comp {
1501 89     89 1 136 my ($self) = @_;
1502              
1503 89 50       169 return unless $self->{top_stack};
1504              
1505 89 100       178 unless ( defined $self->{top_stack}->[STACK_BASE_COMP] ) {
1506 40         81 $self->_compute_base_comp_for_frame( $self->depth - 1 );
1507             }
1508 89         279 return $self->{top_stack}->[STACK_BASE_COMP];
1509             }
1510              
1511             #
1512             # Determine the base_comp for a stack frame. See the user
1513             # documentation for base_comp for a description of these rules.
1514             #
1515             sub _compute_base_comp_for_frame {
1516 48     48   97 my ($self, $frame_num) = @_;
1517 48 50       109 die "Invalid frame number: $frame_num" if $frame_num < 0;
1518              
1519 48         76 my $frame = $self->{stack}->[$frame_num];
1520              
1521 48 100       107 unless (defined($frame->[STACK_BASE_COMP])) {
1522 44         70 my $mods = $frame->[STACK_MODS];
1523 44         61 my $path = $frame->[STACK_PATH];
1524 44         61 my $comp = $frame->[STACK_COMP];
1525            
1526 44         63 my $base_comp;
1527 44 100 100     162 if (exists($mods->{base_comp})) {
    100 100        
    100 66        
1528 32         57 $base_comp = $mods->{base_comp};
1529             } elsif (!$path ||
1530             $path =~ m/^(?:SELF|PARENT|REQUEST)(?:\:..*)?$/ ||
1531             ($comp->is_subcomp && !$comp->is_method)) {
1532 8         27 $base_comp = $self->_compute_base_comp_for_frame($frame_num-1);
1533             } elsif ($path =~ m/(.*):/) {
1534 1         4 my $calling_comp = $self->{stack}->[$frame_num-1]->[STACK_COMP];
1535 1         2 $base_comp = $self->fetch_comp($1, $calling_comp);
1536             } else {
1537 3         6 $base_comp = $comp;
1538             }
1539 44         84 $frame->[STACK_BASE_COMP] = $base_comp;
1540             }
1541 48         87 return $frame->[STACK_BASE_COMP];
1542             }
1543              
1544             sub log
1545             {
1546 2     2 1 3 my ($self) = @_;
1547 2         5 return $self->current_comp->logger();
1548             }
1549              
1550             package Tie::Handle::Mason;
1551             $Tie::Handle::Mason::VERSION = '1.58';
1552             sub TIEHANDLE
1553             {
1554 441     441   1015 my $class = shift;
1555              
1556              
1557 441         1403 return bless {}, $class;
1558             }
1559              
1560             sub PRINT
1561             {
1562 116     116   263 my $self = shift;
1563              
1564 116         225 my $old = select STDOUT;
1565             # Use direct $m access instead of Request->instance() to optimize common case
1566 116         270 $HTML::Mason::Commands::m->print(@_);
1567              
1568 116         471 select $old;
1569             }
1570              
1571             sub PRINTF
1572             {
1573 2     2   6 my $self = shift;
1574              
1575             # apparently sprintf(@_) won't work, it needs to be a scalar
1576             # followed by a list
1577 2         17 $self->PRINT(sprintf(shift, @_));
1578             }
1579              
1580             1;
1581              
1582             __END__