File Coverage

blib/lib/Waft.pm
Criterion Covered Total %
statement 561 896 62.6
branch 172 372 46.2
condition 63 166 37.9
subroutine 104 147 70.7
pod 28 92 30.4
total 928 1673 55.4


line stmt bran cond sub pod time code
1             package Waft;
2              
3 20     20   92726 use 5.005;
  20         67  
  20         722  
4 20     20   99 use strict;
  20         32  
  20         608  
5 20     20   94 use vars qw( $VERSION );
  20         36  
  20         1212  
6 20 50   20   40 BEGIN { eval { require warnings } ? 'warnings'->import : ( $^W = 1 ) }
  20         820  
7              
8 20     20   45285 use CGI qw( -no_debug );
  20         360182  
  20         149  
9 20     20   1351 use Fcntl qw( :DEFAULT );
  20         37  
  20         8828  
10 20     20   16749 use Symbol;
  20         17710  
  20         4954  
11             require File::Spec;
12              
13             $VERSION = '0.9910';
14              
15             $Waft::Backword_compatible_version = $VERSION;
16             @Waft::Allow_template_file_exts = qw( .html .css .js .txt );
17             $Waft::Cache = 1;
18             $Waft::Correct_NEXT_DISTINCT = 1;
19              
20             sub import {
21 2     2   18 my ($base, @mixins) = @_;
22              
23 2 50 33     19 if ( defined $mixins[0] and $mixins[0] eq 'with' ) {
24 2         3 shift @mixins;
25             }
26              
27 2 50       7 return if @mixins == 0;
28              
29 2         4 my $caller = caller;
30 2         5 my @bases = (@mixins, $base);
31              
32             BASE:
33 2         3 for my $base ( @bases ) {
34 8 100       28 if ( $base =~ /\A :: /xms ) {
35 4         8 $base = 'Waft' . $base;
36             }
37              
38 8 50       88 next BASE if $caller->isa($base);
39              
40 8         320 eval qq{ require $base };
41              
42 8 100       875 if ( $@ ) {
43 1 50       8 CORE::die($@) if $@ !~ /\ACan't locate .*? at \(eval /;
44              
45 20 50   20   125 if ( not do { no strict 'refs'; %{ "${base}::" } } ) {
  20         38  
  20         1304  
  1         2  
  1         1  
  1         6  
46 0         0 require Carp;
47              
48 0         0 Carp::croak($@);
49             }
50             }
51              
52 20     20   95 no strict 'refs';
  20         29  
  20         17205  
53 8         12 push @{ "${caller}::ISA" }, $base;
  8         102  
54             }
55              
56 2         4156 return;
57             }
58              
59             {
60             my %Backword_compatible_version_of;
61              
62             sub set_waft_backword_compatible_version {
63 2     2 1 19 my ($class, $backword_compatible_version) = @_;
64              
65 2 50       22 $class->die('This is class method') if $class->blessed;
66              
67 2         6 $Backword_compatible_version_of{$class}
68             = $backword_compatible_version;
69              
70 2         5 return;
71             }
72              
73             sub BCV {
74 124     124 0 151 my ($self) = @_;
75              
76 124   66     514 my $class = $self->blessed || $self;
77              
78 124   66     333 my $backword_compatible_version
79             = $Backword_compatible_version_of{$class}
80             || $Waft::Backword_compatible_version;
81              
82 124         519 return $backword_compatible_version;
83             }
84             }
85              
86 0     0 0 0 sub get_waft_backword_compatible_version { shift->BCV(@_) }
87              
88 20     20   106 eval q{ use Scalar::Util qw( blessed refaddr ); 1 } or do {
  20         31  
  20         2135  
89             *blessed = *blessed = sub {
90             my ($self) = @_;
91              
92             my $blessed = ref $self;
93              
94             return $blessed;
95             };
96              
97             *refaddr = *refaddr = sub {
98             my ($self) = @_;
99              
100             my $blessed_class = ref $self
101             or return;
102              
103             bless $self, __PACKAGE__;
104             my $refaddr = "$self";
105              
106             bless $self, $blessed_class;
107              
108             return $refaddr;
109             };
110             };
111              
112             sub die {
113 0     0 1 0 my ($self, @args) = @_;
114              
115 0     0   0 $self->dont_trust_me( sub { CORE::die(@_) }, @args );
  0         0  
116              
117 0         0 return;
118             }
119              
120             sub dont_trust_me {
121 5     5 0 10 my ($self, $coderef, @args) = @_;
122              
123 5   33     34 my $class = $self->blessed || $self;
124              
125 5         8 my $back;
126             CALLER:
127 5         48 while ( my @caller = caller $back++ ) {
128 10         19 my ($package, $filename, $line) = @caller;
129              
130 10 100 66     90 next CALLER if $package ne $class and $self->isa($package);
131              
132 5 100       12 if ( not grep { defined and length >= 1 } @args ) {
  6 100       32  
133 3         5 push @args, q{something's wrong};
134             }
135              
136 5         16 push @args, " at $filename line $line.\n";
137              
138 5         16 last CALLER;
139             }
140              
141 5         14 return $coderef->(@args);
142             }
143              
144             sub use_utf8 {
145 1     1 1 713 my ($class) = @_;
146              
147 1         6 $class->set_using_utf8(1);
148              
149 1         1 return;
150             }
151              
152             {
153             my %Using_utf8;
154              
155             sub set_using_utf8 {
156 1     1 0 1 my ($class, $using_utf8) = @_;
157              
158 1 50       8 $class->die('This is class method') if $class->blessed;
159              
160 1 50 33     10 return if $using_utf8 and not $class->can_use_utf8;
161              
162 1         2 $Using_utf8{$class} = $using_utf8;
163              
164 1         2 return;
165             }
166              
167             sub get_using_utf8 {
168 14     14 0 26 my ($self) = @_;
169              
170 14 50       40 if ($self->BCV < 0.53) {
171 0 0       0 return $self->stash->{use_utf8} if $self->blessed;
172             }
173              
174 14   33     69 my $class = $self->blessed || $self;
175              
176 14         26 my $using_utf8 = $Using_utf8{$class};
177              
178 14         63 return $using_utf8;
179             }
180             }
181              
182             sub can_use_utf8 {
183 1     1 0 3 my ($self) = @_;
184              
185 1         1 eval { require 5.008001 };
  1         13  
186 1 50       8 return 1 if not $@;
187 0         0 $self->warn($@);
188              
189 0         0 return;
190             }
191              
192             sub warn {
193 5     5 1 3375 my ($self, @args) = @_;
194              
195 5     5   31 $self->dont_trust_me( sub { CORE::warn(@_) }, @args );
  5         297  
196              
197 5         27 return;
198             }
199              
200             {
201             my %Allow_template_file_exts_arrayref_of;
202              
203             sub set_allow_template_file_exts {
204 4     4 1 251 my ($class, @allow_template_file_exts) = @_;
205              
206 4 50       16 $class->die('This is class method') if $class->blessed;
207              
208 4         7 $Allow_template_file_exts_arrayref_of{$class}
209             = \@allow_template_file_exts;
210              
211 4         9 return;
212             }
213              
214             sub get_allow_template_file_exts {
215 41   33 41 0 81 my $class = $_[1] || $_[0];
216              
217 41 100       87 return @{ $Allow_template_file_exts_arrayref_of{$class} }
  31         87  
218             if exists $Allow_template_file_exts_arrayref_of{$class};
219              
220 10         10 my $get_allowed_exts = do {
221 20     20   110 no strict 'refs';
  20         174  
  20         52977  
222 10         11 *{ "${class}::allow_template_file_exts" }{CODE};
  10         47  
223             };
224              
225             my @allow_template_file_exts
226 10 100       35 = $get_allowed_exts ? $get_allowed_exts->($class)
227             : @Waft::Allow_template_file_exts;
228              
229 10         34 $Allow_template_file_exts_arrayref_of{$class}
230             = \@allow_template_file_exts;
231              
232 10         26 return @allow_template_file_exts;
233             }
234             }
235              
236             {
237             my %Default_content_type_of;
238              
239             sub set_default_content_type {
240 0     0 1 0 my ($class, $default_content_type) = @_;
241              
242 0 0       0 $class->die('This is class method') if $class->blessed;
243              
244 0         0 $Default_content_type_of{$class} = $default_content_type;
245              
246 0         0 return;
247             }
248              
249             sub get_default_content_type {
250 0     0 0 0 my ($self) = @_;
251              
252 0   0     0 my $class = $self->blessed || $self;
253              
254 0   0     0 my $default_content_type = $Default_content_type_of{$class}
255             || 'text/html';
256              
257 0         0 return $default_content_type;
258             }
259             }
260              
261             sub waft {
262 0     0 1 0 my ($self, @args) = @_;
263              
264 0 0       0 if ($self->BCV < 0.53) {
265 0 0       0 if ( not $self->blessed ) {
266 0         0 ($self, @args) = $self->new(@args);
267             }
268              
269 0         0 $self->init_base_url;
270 0         0 $self->init_binmode;
271 0         0 $self->_load_query_param;
272             }
273              
274 0 0       0 if ( not $self->blessed ) {
275 0         0 $self = $self->new->initialize;
276             }
277              
278 0         0 my @return_values = $self->controller(@args);
279              
280 0 0       0 return wantarray ? ($self, @return_values) : $self;
281             }
282              
283             sub new {
284 14     14 1 1083 my ($class) = @_;
285              
286 14 50       115 $class->die('This is class method') if $class->blessed;
287              
288 14         22 my $self;
289 14         90 tie %$self, 'Waft::Object';
290 14         27 bless $self, $class;
291              
292 14 50       95 if ($class->BCV < 1.0) {
293 14         107 $class->define_subs_for_under_0_99x;
294             }
295              
296 14 50       80 if ($class->BCV < 0.53) {
297 0         0 ( undef, my @args ) = @_;
298              
299 0         0 $class->define_subs_for_under_0_52x;
300              
301 0         0 my $self;
302 0         0 tie %$self, 'Waft::Object';
303 0         0 bless $self, $class;
304              
305 0         0 my ($option_hashref, @return_values);
306              
307 0 0       0 if (ref $args[0] eq 'HASH') {
308 0         0 ($option_hashref, @return_values) = @args;
309             }
310             else {
311 0         0 $option_hashref = { @args };
312             }
313              
314 0   0     0 $option_hashref->{content_type} ||= $self->get_default_content_type;
315 0   0     0 $option_hashref->{headers} ||= [];
316              
317 0         0 my $stash = $self->stash;
318              
319 0         0 %$stash = %$option_hashref;
320              
321 0 0       0 if ($stash->{use_utf8}) {
322 0         0 $self->can_use_utf8; # carp in this method if cannot 'use utf8'
323             }
324              
325 0 0       0 return wantarray ? ($self, @return_values) : $self;
326             }
327              
328 14         75 return $self;
329             }
330              
331             sub initialize {
332 2     2 1 9 my ($self) = @_;
333              
334 2         10 $self->initialize_base_url;
335 2         14 $self->initialize_page;
336 2         12 $self->initialize_values;
337 2         13 $self->initialize_action;
338 2         35 $self->initialize_response_headers;
339 2         10 $self->initialize_binmode;
340              
341 2         4 return $self;
342             }
343              
344             sub initialize_base_url {
345 3     3 0 5 my ($self) = @_;
346              
347 3         18 my $base_url = $self->make_base_url;
348 3         19 $self->set_base_url($base_url);
349              
350 3         6 return;
351             }
352              
353             sub make_base_url {
354 3     3 0 6 my ($self) = @_;
355              
356 3   50     17 my $updir = $ENV{PATH_INFO} || q{};
357 3         8 my $updir_count = $updir =~ s{ /[^/]* }{../}gx;
358              
359 3         6 my $url;
360              
361 3 50 33     14 if ( defined $ENV{REQUEST_URI}
362             and $ENV{REQUEST_URI} =~ /\A ([^?]+) /xms
363             ) {
364 0         0 $url = $1;
365              
366 0         0 for (1 .. $updir_count) {
367 0         0 $url =~ s{ /[^/]* \z}{}x;
368             }
369             }
370             else {
371 3   66     47 $url = $ENV{SCRIPT_NAME} || $self->get_script_basename;
372             }
373              
374 3 50       26 my $base_url = $url =~ m{ ([^/]+) \z}xms ? "$updir$1"
375             : './';
376              
377 3         9 return $base_url;
378             }
379              
380             sub get_script_basename {
381 3     3 0 489 my ($self) = @_;
382              
383 3 100       5 return $FindBin::Script if eval { FindBin::again(); 1 };
  3         41  
  1         191  
384              
385 2         7 delete $INC{'FindBin.pm'};
386 2         1801 require FindBin;
387              
388 2         1989 return $FindBin::Script;
389             }
390              
391             sub set_base_url {
392 3     3 0 7 my ($self, $base_url) = @_;
393              
394 3 50       8 if ($self->BCV < 0.53) {
395 0         0 $self->stash->{url} = $base_url;
396             }
397              
398 3         12 $self->stash->{base_url} = $base_url;
399              
400 3         5 return;
401             }
402              
403             {
404             my %Stash;
405              
406 83   33 83 1 974 sub stash { $Stash{ $_[0]->refaddr or $_[0] }{ $_[1] or caller } ||= {} }
      33        
      100        
407              
408             sub DESTROY {
409 14     14   3571 my ($self) = @_;
410              
411 14         91 my $ident = $self->refaddr;
412 14         60 delete $Stash{$ident};
413              
414 14         920 return;
415             }
416             }
417              
418             sub initialize_page {
419 5     5 0 197 my ($self) = @_;
420              
421 5 100       28 my $page = $self->is_submitted ? $self->cgi->param('s')
422             : $self->cgi->param('p');
423              
424 5 100 100     12866 if ( $self->get_using_utf8 and defined $page ) {
425 1         3 utf8::encode($page);
426             }
427              
428 5         37 $page = $self->fix_and_validate_page($page);
429 5 100       38 $self->set_page( defined $page ? $page : 'default.html' );
430              
431 5         12 return;
432             }
433              
434             sub is_submitted {
435 8     8 0 11 my ($self) = @_;
436              
437 8         32 my $is_submitted = defined $self->cgi->param('s');
438              
439 8         169 return $is_submitted;
440             }
441              
442             sub cgi {
443 25     25 1 37 my ($self) = @_;
444              
445 25   66     55 my $query = ( $self->stash->{query} ||= $self->create_query_obj );
446              
447 25         9122 return $query;
448             }
449              
450             sub create_query_obj {
451 4     4 0 8 my ($self) = @_;
452              
453 4         29 my $query = CGI->new;
454              
455 4 100       12209 if ($self->get_using_utf8) {
456 2         97 eval qq{\n# line } . __LINE__ . q{ "} . __FILE__ . qq{"\n} . q{
457 1     1   8 use CGI 3.21 qw( -utf8 ); # -utf8 pragma is for 3.31 or later
  1     1   23  
  1         8  
  1         5  
  1         19  
  1         6  
458             };
459              
460 2 50       126 if ($@) {
    50          
461 0         0 $self->warn($@);
462             }
463             elsif ($query->VERSION < 3.31) {
464 0         0 $query->charset('utf-8');
465             }
466             }
467              
468 4         21 return $query;
469             }
470              
471             sub fix_and_validate_page {
472 5     5 0 13 my ($self, $page) = @_;
473              
474 5 100       18 return if not defined $page;
475              
476 3         26 $page =~ m{\A
477             (?! .* [/\\]{2,} )
478             (?! .* (?
479             (?! .* :: )
480             (.+) \z}xms;
481 3         69 my $untainted_page = $1;
482              
483 3 50 33     100 return $untainted_page
      33        
      33        
      33        
484             if defined $untainted_page
485             and not File::Spec->file_name_is_absolute($untainted_page)
486             and not $untainted_page eq 'CURRENT'
487             and not $untainted_page eq 'TEMPLATE'
488             and not $self->to_page_id($untainted_page) =~ / __indirect \z/xms;
489              
490 0         0 $self->warn(qq{Invalid requested page "$page"});
491              
492 0         0 return;
493             }
494              
495             sub to_page_id {
496 5     5 0 13 my (undef, $page) = @_;
497              
498 5         8 my $page_id = $page;
499 5         26 $page_id =~ s{ \.[^/:\\]* \z}{}xms;
500 5         12 $page_id =~ tr/0-9A-Za-z_/_/c;
501              
502 5         29 return $page_id;
503             }
504              
505             sub set_page {
506 5     5 0 13 my ($self, $page) = @_;
507              
508 5         16 $self->stash->{page} = $page;
509              
510 5         10 return;
511             }
512              
513             sub initialize_values {
514 4     4 0 9 my ($self, $joined_values) = @_;
515              
516 4         19 $self->clear_values;
517              
518 4   100     20 $joined_values ||= $self->cgi->param('v');
519              
520 4 100       61 return if not defined $joined_values;
521              
522 3         13 my @key_values_pairs = split /\x20/, $joined_values, -1;
523              
524             KEY_VALUES_PAIR:
525 3         8 for my $key_values_pair (@key_values_pairs) {
526 6         17 my ($key, @values) = split /-/, $key_values_pair, -1;
527              
528 6         53 $key = $self->unescape_space_percent_hyphen($key);
529 6         19 @values = $self->unescape_space_percent_hyphen(@values);
530              
531 6 50       20 if ($key eq 'ALL_VALUES') {
532 0         0 $self->warn(q{Invalid init value 'ALL_VALUES'});
533              
534 0         0 next KEY_VALUES_PAIR;
535             }
536              
537 6         57 $self->set_values( $key => @values );
538             }
539              
540 3         8 return;
541             }
542              
543             sub clear_values {
544 6     6 1 17 my ($self) = @_;
545              
546 6         10 %{ $self->value_hashref } = ();
  6         25  
547              
548 6         13 return;
549             }
550              
551 42     42 0 47 sub value_hashref { tied %{ $_[0] } }
  42         168  
552              
553             sub unescape_space_percent_hyphen {
554 12     12 0 24 my (undef, @values) = @_;
555              
556 12         17 for my $value (@values) {
557 12         30 $value =~ s/ %(2[05d]) / pack 'H2', $1 /egxms;
  6         17  
558             }
559              
560 12 100       66 return wantarray ? @values : $values[0];
561             }
562              
563             sub set_values {
564 9     9 1 30 my ($self, $key, @values) = @_;
565              
566 9         12 @{ $self->value_hashref->{$key} } = @values;
  9         21  
567              
568 9         24 return;
569             }
570              
571             sub initialize_action {
572 3     3 0 5 my ($self) = @_;
573              
574 3         50 my $action = $self->find_first_action;
575 3 100       26 $self->set_action( defined $action ? $action : 'direct' );
576              
577 3         7 return;
578             }
579              
580             sub find_first_action {
581 3     3 0 6 my ($self) = @_;
582              
583 3 100       8 return if not $self->is_submitted;
584              
585 2         15 my $page_id = $self->to_page_id($self->get_page);
586 2         2 my $global_action;
587              
588 2         7 my @param_names = $self->cgi->param;
589             PARAM_NAME:
590 2         36 for my $param_name ( @param_names ) {
591 6         20 my $action_id = $self->to_action_id($param_name);
592              
593 6 50       14 if ($self->BCV < 0.53) {
594 0 0       0 next PARAM_NAME if $action_id =~ /\A global_ /xms;
595             }
596              
597 6 50 33     44 next PARAM_NAME if $action_id =~ /(?: \A | _ ) direct \z/xms
      33        
598             or $action_id =~ /(?: \A | _ ) indirect \z/xms
599             or $action_id =~ /\A global__ /xms;
600              
601 6 50       62 return $param_name if $self->can("__${page_id}__$action_id");
602              
603 6 50       14 next PARAM_NAME if defined $global_action;
604              
605 6 50       12 if ($self->BCV < 0.53) {
606 0 0       0 if ( $self->can("global_$action_id") ) {
607 0         0 $global_action = "global_$param_name";
608             }
609              
610 0         0 next PARAM_NAME;
611             }
612              
613 6 100       39 if ( $self->can("global__$action_id") ) {
614 2         4 $global_action = "global__$param_name";
615             }
616              
617 6         14 next PARAM_NAME;
618             }
619              
620 2 50       10 return $global_action if defined $global_action;
621              
622 0 0       0 return 'submit' if $self->can("__${page_id}__submit");
623              
624 0 0       0 if ($self->BCV < 0.53) {
625 0 0       0 return 'global_submit' if $self->can('global_submit');
626             }
627              
628 0 0       0 return 'global__submit' if $self->can('global__submit');
629              
630 0         0 $self->warn('Requested parameters do not match with defined action');
631              
632 0         0 return;
633             }
634              
635 5     5 0 22 sub get_page { $_[0]->stash->{page} }
636              
637 2     2 1 9 sub page { shift->get_page(@_) }
638              
639             sub to_action_id {
640 6     6 0 11 my (undef, $action) = @_;
641              
642 6         7 my $action_id = $action;
643 6         11 $action_id =~ s/ \. .* \z//xms;
644              
645 6         11 return $action_id;
646             }
647              
648             sub set_action {
649 4     4 0 8 my ($self, $action) = @_;
650              
651 4         12 $self->stash->{action} = $action;
652              
653 4         8 return;
654             }
655              
656             sub initialize_response_headers {
657 3     3 0 6 my ($self) = @_;
658              
659 3         34 $self->set_response_headers( () );
660              
661 3         4 return;
662             }
663              
664             sub initialize_binmode {
665 3     3 0 5 my ($self) = @_;
666              
667 3 50       7 if ( $self->get_using_utf8 ) {
668 0         0 eval q{ binmode select, ':utf8' };
669             }
670             else {
671 20     20   135 no strict 'refs';
  20         58  
  20         35108  
672 3         19 binmode select;
673             }
674              
675 3         8 return;
676             }
677              
678             sub set_response_headers {
679 5     5 0 24 my ($self, @response_headers) = @_;
680              
681 5 50       11 if ($self->BCV < 0.53) {
682 0         0 $self->stash->{headers} = \@response_headers;
683              
684 0         0 return;
685             }
686              
687 5         22 $self->stash->{response_headers} = \@response_headers;
688              
689 5         14 return;
690             }
691              
692             sub controller {
693 0     0 0 0 my ($self, @relays) = @_;
694              
695 0 0 0     0 local $NEXT::SEEN if $NEXT::SEEN and $Waft::Correct_NEXT_DISTINCT;
696              
697 0 0       0 if ( my $coderef = $self->can('begin') ) {
698 0         0 @relays = $self->call_method($coderef, @relays);
699             }
700              
701 0         0 my $stash = $self->stash;
702 0         0 my $call_count;
703             METHOD:
704 0         0 while ( not $stash->{responded} ) {
705 0 0       0 if ( my $coderef = $self->can('before') ) {
706 0         0 @relays = $self->call_method($coderef, @relays);
707              
708 0 0       0 last METHOD if $stash->{responded};
709             }
710              
711 0 0       0 if ( my $coderef = $self->find_action_method ) {
712 0         0 @relays = $self->call_method($coderef, @relays);
713              
714 0 0       0 last METHOD if $stash->{responded};
715              
716 0 0       0 if ($self->BCV < 0.53) {
717 0 0       0 if ( $self->to_action_id($self->get_action) eq 'template' ) {
718 0         0 @relays = $self->call_template('CURRENT', @relays);
719              
720 0 0       0 last METHOD if $stash->{responded};
721             }
722             }
723              
724 0         0 next METHOD;
725             }
726             else {
727 0         0 $self->set_action('template');
728             }
729              
730 0         0 @relays = $self->call_template('CURRENT', @relays);
731              
732 0 0       0 last METHOD if $stash->{responded};
733             }
734             continue {
735 0 0       0 $self->die('Methods called too many times in controller')
736             if ++$call_count > 4;
737             }
738              
739 0 0       0 if ( $self->can('end') ) {
740 0         0 my @return_values = $self->end(@relays);
741              
742 0 0       0 if ( @return_values ) {
743 0         0 @relays = @return_values;
744             }
745             }
746              
747 0 0       0 return wantarray ? @relays : $relays[0];
748             }
749              
750             sub call_method {
751 1     1 0 3 my ($self, $method_coderef, @args) = @_;
752              
753 1         4 my @return_values = $self->$method_coderef(@args);
754              
755 1 0       5 return wantarray ? @return_values : $return_values[0]
    50          
756             if $self->stash->{responded};
757              
758 1         6 require B;
759 1         16 my $method_name = B::svref_2object($method_coderef)->GV->NAME;
760              
761 1 50 33     9 if ( $method_name eq 'begin' || $method_name eq 'before'
      33        
762             and @return_values == 0
763             ) {
764 0         0 my $next = { page => 'CURRENT', action => undef };
765 0         0 @return_values = ($next, @args);
766             }
767              
768 1         2 my $next = shift @return_values;
769 1 50       15 my ($next_page, $next_action)
    50          
770             = ref $next eq 'ARRAY' ? @$next
771             : ref $next eq 'HASH' ? ($next->{page}, $next->{action})
772             : ($next, undef);
773              
774 1 50       3 if ( not defined $next_page ) {
775 1 50       6 $next_page = $method_name eq 'begin' ? 'CURRENT'
    50          
776             : $method_name eq 'before' ? 'CURRENT'
777             : 'TEMPLATE';
778             }
779              
780 1 50       3 if ( not defined $next_action ) {
781 1 50       4 $next_action = $next_page eq 'TEMPLATE' ? 'template'
782             : 'indirect';
783             }
784              
785 1 50 33     7 if ($next_page eq 'CURRENT' or $next_page eq 'TEMPLATE') {
786             # don't change page
787             }
788             else {
789 0         0 $self->set_page($next_page);
790             }
791              
792 1 50 0     11 if ( $next_page eq 'CURRENT'
      33        
793             and $method_name eq 'begin' || $method_name eq 'before'
794             ) {
795             # don't change action
796             }
797             else {
798 1         7 $self->set_action($next_action);
799             }
800              
801 1         4 return @return_values;
802             }
803              
804             sub find_action_method {
805 0     0 0 0 my ($self) = @_;
806              
807 0         0 my $page_id = $self->to_page_id($self->get_page);
808 0         0 my $action_id = $self->to_action_id($self->get_action);
809              
810 0 0       0 if ($self->BCV < 0.53) {
811 0 0       0 if ($action_id eq 'direct') {
    0          
    0          
812 0   0     0 return $self->can("__${page_id}__direct")
813             || $self->can("__${page_id}")
814             || $self->can('global_direct');
815             }
816             elsif ($action_id eq 'indirect') {
817 0   0     0 return $self->can("__${page_id}__indirect")
818             || $self->can("__${page_id}")
819             || $self->can('global_indirect');
820             }
821             elsif ( $action_id =~ /\A global_ /xms ) {
822 0         0 return $self->can($action_id);
823             }
824             }
825              
826 0 0       0 if ($action_id eq 'direct') {
    0          
    0          
827 0   0     0 return $self->can("__${page_id}__direct")
828             || $self->can("__${page_id}")
829             || $self->can('global__direct');
830             }
831             elsif ($action_id eq 'indirect') {
832 0   0     0 return $self->can("__${page_id}__indirect")
833             || $self->can("__${page_id}")
834             || $self->can('global__indirect');
835             }
836             elsif ( $action_id =~ /\A global__ /xms ) {
837 0         0 return $self->can($action_id);
838             }
839              
840 0         0 return $self->can("__${page_id}__$action_id");
841             }
842              
843 2     2 0 8 sub get_action { $_[0]->stash->{action} }
844              
845 2     2 1 13 sub action { shift->get_action(@_) }
846              
847             sub call_template {
848 1     1 1 9 my ($self, $page, @args) = @_;
849              
850 1 50       3 if ($self->BCV < 0.53) {
851 0         0 $page =~ s/ .+ :: //xms;
852             }
853              
854 1 50 33     8 if ($page eq 'CURRENT' or $page eq 'TEMPLATE') {
855 0         0 $page = $self->get_page;
856             }
857              
858 1         7 my ($template_file, $template_class) = $self->get_template_file($page);
859              
860 1 50       4 if ( not defined $template_file ) {
861 0         0 $self->warn(qq{Requested page "$page" is not found});
862              
863 0     0   0 my $goto_not_found_coderef = sub { shift; 'not_found.html', @_ };
  0         0  
  0         0  
864              
865 0         0 return $self->call_method($goto_not_found_coderef, @args);
866             }
867              
868 1         7 my $template_coderef
869             = $self->compile_template_file($template_file, $template_class);
870              
871 1         10 return $self->call_method($template_coderef, @args);
872             }
873              
874 0     0 0 0 sub include { shift->call_template(@_) }
875              
876             sub get_template_file {
877 1     1 0 2 my ($self, $page) = @_;
878              
879 1 50 33     18 if ($page eq 'CURRENT' or $page eq 'TEMPLATE') {
880 0         0 $page = $self->get_page;
881             }
882              
883 1 50       14 if ( File::Spec->file_name_is_absolute($page) ) {
884 0 0       0 return if not -f $page;
885              
886 0         0 my $template_file = $page;
887 0   0     0 my $template_class = $self->blessed || $self;
888              
889 0         0 return $template_file, $template_class;
890             }
891              
892 1         6 return $self->find_template_file($page);
893             }
894              
895             {
896             my %Cached_template_file;
897              
898             sub find_template_file {
899 25     25 0 2802 my ($self, $page) = @_;
900              
901 25   33     92 my $class = $self->blessed || $self;
902              
903 25 100 100     116 return @{ $Cached_template_file{$class, $page} }
  3         13  
904             if $Waft::Cache and exists $Cached_template_file{$class, $page};
905              
906 22         65 my ($template_file, $template_class)
907             = $self->recursive_find_template_file($page, $class);
908              
909 22 100       57 return if not defined $template_file;
910              
911 17         58 $Cached_template_file{$class, $page}
912             = [$template_file, $template_class];
913              
914 17         52 return $template_file, $template_class;
915             }
916             }
917              
918             sub recursive_find_template_file {
919 41     41 0 59 my ($self, $page, $class, $seen) = @_;
920              
921 41 50       120 return if $seen->{$class}++;
922              
923 41         45 my $class_path = $class;
924 41         113 $class_path =~ s{ :: }{/}gxms;
925              
926 41         66 my $module_file = "$class_path.pm";
927             my @lib_dirs
928 41 50       819 = ! defined $INC{$module_file} ? @INC
    100          
929             : $INC{$module_file} =~ m{\A (.+) /\Q$module_file\E \z}xms ? ($1)
930             : @INC;
931              
932 41         54 my @finding_files;
933 41         78 push @finding_files, "$class_path.template/$page";
934 41 100       102 if ( $self->is_allowed_to_use_template_file_ext($page, $class) ) {
935 22         47 push @finding_files, "$class_path/$page";
936             }
937              
938 41         58 for my $lib_dir ( @lib_dirs ) {
939 59         62 for my $finding_file ( @finding_files ) {
940 88         130 my $template_file = "$lib_dir/$finding_file";
941              
942 88 100       1435 return $template_file, $class if -f $template_file;
943             }
944             }
945              
946 20     20   118 my @super_classes = do { no strict 'refs'; @{ "${class}::ISA" } };
  20         35  
  20         75621  
  24         30  
  24         25  
  24         88  
947 24         36 for my $super_class ( @super_classes ) {
948 19         60 my ($template_file, $template_class)
949             = $self->recursive_find_template_file($page, $super_class, $seen);
950              
951 19 100       70 return $template_file, $template_class if defined $template_file;
952             }
953              
954 15         38 return;
955             }
956              
957             sub is_allowed_to_use_template_file_ext {
958 41     41 0 64 my ($self, $page, $class) = @_;
959              
960 41 50       70 return if $self->BCV < 0.53;
961              
962             my @allow_template_file_exts
963 41         95 = $self->get_allow_template_file_exts($class);
964              
965             EXT:
966 41         71 for my $allow_template_file_ext ( @allow_template_file_exts ) {
967 67 50       116 if (length $allow_template_file_ext == 0) {
968 0 0       0 return 1 if $page !~ / \. /xms;
969              
970 0         0 next EXT;
971             }
972              
973 67 100       602 return 1 if $page =~ / \Q$allow_template_file_ext\E \z/xms;
974             }
975              
976 19         47 return;
977             }
978              
979             {
980             my %Cached_template_coderef;
981              
982             sub compile_template_file {
983 1     1 0 2 my ($self, $template_file, $template_class) = @_;
984              
985 1         27 my @stat = stat $template_file;
986 1 50       5 if ( not @stat ) {
987 0         0 $self->warn(qq{Failed to stat template file "$template_file"});
988              
989             my $goto_internal_server_error_coderef
990 0     0   0 = sub { shift; 'internal_server_error.html', @_ };
  0         0  
  0         0  
991              
992 0         0 return $goto_internal_server_error_coderef;
993             }
994 1         2 my $modified_time = $stat[9];
995              
996 1         3 my $template_name = "${template_class}::$template_file";
997 1         3 my $template_id = "$template_name-$modified_time";
998              
999 1 50 33     8 return $Cached_template_coderef{$template_id}
1000             if $Waft::Cache and exists $Cached_template_coderef{$template_id};
1001              
1002 1         31 my $old_template_id_regexp = qr/\A \Q$template_name\E - \d{14} \z/xms;
1003             CACHED_TEMPLATE:
1004 1         5 for my $cached_template_id ( keys %Cached_template_coderef ) {
1005             next CACHED_TEMPLATE
1006 0 0       0 if $cached_template_id !~ $old_template_id_regexp;
1007 0         0 delete $Cached_template_coderef{$cached_template_id};
1008             }
1009              
1010 1         7 my $template_scalarref = $self->read_template_file($template_file);
1011 1 50       5 if ( not $template_scalarref ) {
1012 0         0 $self->warn(qq{Failed to read template file "$template_file"});
1013              
1014 0     0   0 my $goto_forbidden_coderef = sub { shift; 'forbidden.html', @_ };
  0         0  
  0         0  
1015              
1016 0         0 return $goto_forbidden_coderef;
1017             }
1018              
1019 1         6 my $template_coderef = $self->compile_template(
1020             $template_scalarref, $template_file, $template_class
1021             );
1022              
1023 1         3 $Cached_template_coderef{$template_id} = $template_coderef;
1024              
1025 1         5 return $template_coderef;
1026             }
1027             }
1028              
1029             sub read_template_file {
1030 1     1 0 2 my ($self, $template_file) = @_;
1031              
1032 1 50       6 sysopen my $file_handle = gensym, $template_file, O_RDONLY
1033             or return;
1034              
1035 1         79 binmode $file_handle;
1036              
1037 1         2 my ($untainted_template) = do { local $/; <$file_handle> =~ / (.*) /xms };
  1         5  
  1         42  
1038              
1039 1         13 close $file_handle;
1040              
1041 1         4 return \$untainted_template;
1042             }
1043              
1044             sub compile_template {
1045 2     2 0 13 my ($self, $template, $template_file, $template_class) = @_;
1046              
1047 2 100       9 if (ref $template eq 'SCALAR') {
1048 1         30 $template = $$template;
1049             }
1050              
1051 2         133 $template =~ s{ (?<=
) }
1052 0         0 { $self->insert_output_waft_tags_method($1) }egixms;
1053              
1054 2         12 $template =~ / ( \x0D\x0A | [\x0A\x0D] ) /xms;
1055 2   50     9 my $break = $1 || "\n";
1056              
1057 2         7 $template = "%>$template<%";
1058              
1059 2         34 $template =~ s{ (?<= %> ) (?! <% ) (.+?) (?= <% ) }
1060 28         61 { $self->convert_text_part($1, $break) }egxms;
1061              
1062 2         49 $template
1063             =~ s{<% (?! \s*[\x0A\x0D]
1064             =[A-Za-z]
1065             )
1066             \s* j(?:sstr)? \s* = (.*?)
1067             %>}{\$__self->output( \$__self->jsstr_filter($1) );}gxms;
1068              
1069 2         40 $template
1070             =~ s{<% (?! \s*[\x0A\x0D]
1071             =[A-Za-z]
1072             )
1073             \s* p(?:lain)? \s* = (.*?)
1074             %>}{\$__self->output($1);}gxms;
1075              
1076 2         36 $template
1077             =~ s{<% (?! \s*[\x0A\x0D]
1078             =[A-Za-z]
1079             )
1080             \s* t(?:ext)? \s* = (.*?)
1081             %>}{\$__self->output( \$__self->text_filter($1) );}gxms;
1082              
1083 2         49 $template
1084             =~ s{<% (?! \s*[\x0A\x0D]
1085             =[A-Za-z]
1086             )
1087             \s* (?: w(?:ord)? \s* )? = (.*?)
1088             %>}{\$__self->output( \$__self->word_filter($1) );}gxms;
1089              
1090 2         41 $template =~ s/ %> | <% //gxms;
1091              
1092 2 50       7 $template = 'return sub {'
1093             . ( $self->BCV < 1.0 ? 'local $Waft::Self = $_[0];' : q{} )
1094             . 'my $__self = $_[0];'
1095             . $template
1096             . '}';
1097              
1098 2 50       8 if ( defined $template_class ) {
1099 2         9 $template = "package $template_class;" . $template;
1100             }
1101              
1102 2 50       9 if ( defined $template_file ) {
1103 2         8 $template = qq{# line 1 "$template_file"$break} . $template;
1104             }
1105              
1106 2         14 my $coderef = $self->compile(\$template);
1107              
1108 2 50       192 $self->die($@) if $@;
1109              
1110 2         7 return $coderef;
1111             }
1112              
1113             sub insert_output_waft_tags_method {
1114 0     0 0 0 my ($self, $form_block) = @_;
1115              
1116 0 0       0 return $form_block if $form_block =~ m{ \b (?:
1117             output_waft_tags
1118             | (?: (?i) waft(?: \s+ | _ ) tag s? )
1119             | form_elements # deprecated
1120             ) \b }xms;
1121              
1122 0         0 $form_block =~ s{ (?= < (?: input | select | textarea | label ) \b ) }
1123             {<% \$__self->output_waft_tags('ALL_VALUES'); %>}ixms;
1124              
1125 0         0 return $form_block;
1126             }
1127              
1128             sub output_waft_tags {
1129 0     0 0 0 my ($self, @keys_arrayref_or_key_value_pairs) = @_;
1130              
1131 0         0 $self->output( $self->get_waft_tags(@keys_arrayref_or_key_value_pairs) );
1132              
1133 0         0 return;
1134             }
1135              
1136             sub get_waft_tags {
1137 0     0 0 0 my ($self, @keys_arrayref_or_key_value_pairs) = @_;
1138              
1139 0         0 my $joined_values = $self->join_values(@keys_arrayref_or_key_value_pairs);
1140 0         0 my $waft_tags = q{ 1141             . $self->html_escape($self->get_page)
1142             . q{" /> 1143             . $self->html_escape($joined_values)
1144             . q{" />};
1145              
1146 0         0 return $waft_tags;
1147             }
1148              
1149             sub join_values {
1150 13     13 0 35 my ($self, @keys_arrayref_or_key_value_pairs) = @_;
1151              
1152 13         14 my %joined_values;
1153              
1154 13         29 my $value_hashref = $self->value_hashref;
1155             KEYS_ARRAYREF_OR_KEY:
1156 13         34 while ( @keys_arrayref_or_key_value_pairs ) {
1157 5         10 my $keys_arrayref_or_key = shift @keys_arrayref_or_key_value_pairs;
1158              
1159 5 50 33     26 if ( defined $keys_arrayref_or_key
1160             and $keys_arrayref_or_key eq 'ALL_VALUES'
1161             ) {
1162 5         16 $keys_arrayref_or_key = [ keys %$value_hashref ];
1163             }
1164              
1165 5 50       16 if (ref $keys_arrayref_or_key eq 'ARRAY') {
1166             KEY:
1167 5         8 for my $key ( @$keys_arrayref_or_key ) {
1168 12 50       27 if ( not defined $key ) {
1169 0         0 $self->warn('Use of uninitialized value');
1170 0         0 $key = q{};
1171             }
1172              
1173 12 50       19 next KEY if not exists $value_hashref->{$key};
1174              
1175 12         32 my @values = $self->get_values($key);
1176              
1177             VALUE:
1178 12         17 for my $value ( @values ) {
1179 14 50       37 next VALUE if defined $value;
1180 0         0 $self->warn('Use of uninitialized value');
1181 0         0 $value = q{};
1182             }
1183              
1184 12         30 @values = $self->escape_space_percent_hyphen(@values);
1185              
1186 12         22 $joined_values{$key} = join q{}, map { "-$_" } @values;
  14         52  
1187             }
1188              
1189 5         16 next KEYS_ARRAYREF_OR_KEY;
1190             }
1191              
1192 0         0 my $key;
1193              
1194 0 0       0 if ( defined $keys_arrayref_or_key ) {
1195 0         0 $key = $keys_arrayref_or_key;
1196             }
1197             else {
1198 0         0 $self->warn('Use of uninitialized value');
1199 0         0 $key = q{};
1200             }
1201              
1202 0         0 my @values;
1203              
1204 0 0       0 if ( @keys_arrayref_or_key_value_pairs ) {
1205 0         0 my $value_or_values_arrayref
1206             = shift @keys_arrayref_or_key_value_pairs;
1207              
1208 0 0       0 if ( not defined $value_or_values_arrayref ) {
    0          
1209 0         0 $self->warn('Use of uninitialized value');
1210 0         0 @values = (q{});
1211             }
1212             elsif (ref $value_or_values_arrayref eq 'ARRAY') {
1213 0         0 @values = @$value_or_values_arrayref;
1214              
1215             VALUE:
1216 0         0 for my $value ( @values ) {
1217 0 0       0 next VALUE if defined $value;
1218 0         0 $self->warn('Use of uninitialized value');
1219 0         0 $value = q{};
1220             }
1221             }
1222             else {
1223 0         0 @values = ($value_or_values_arrayref);
1224             }
1225             }
1226             else {
1227 0         0 $self->warn('Odd number of elements in arguments');
1228 0         0 @values = (q{});
1229             }
1230              
1231 0         0 @values = $self->escape_space_percent_hyphen(@values);
1232              
1233 0         0 $joined_values{$key} = join q{}, map { "-$_" } @values;
  0         0  
1234              
1235 0         0 next KEYS_ARRAYREF_OR_KEY;
1236             }
1237              
1238 12         22 my $joined_values
1239 13         46 = join q{ }, map { $self->escape_space_percent_hyphen($_)
1240             . $joined_values{$_}
1241             } sort keys %joined_values;
1242              
1243 13         50 return $joined_values;
1244             }
1245              
1246             {
1247             my @EMPTY;
1248              
1249             sub get_values {
1250 13     13 1 18 my ($self, $key, @i) = @_;
1251              
1252 13 50       56 return @{ $self->value_hashref->{$key} || \@EMPTY }[@i] if @i;
  1 100       2  
1253              
1254 12 50       14 return @{ $self->value_hashref->{$key} || \@EMPTY };
  12         19  
1255             }
1256             }
1257              
1258             sub escape_space_percent_hyphen {
1259 24     24 0 35 my (undef, @values) = @_;
1260              
1261 24         28 for my $value (@values) {
1262 26         58 $value =~ s/ ( [ %-] ) / '%' . unpack('H2', $1) /egxms;
  24         78  
1263             }
1264              
1265 24 100       78 return wantarray ? @values : $values[0];
1266             }
1267              
1268             sub convert_text_part {
1269 28     28 0 61 my (undef, $text_part, $break) = @_;
1270              
1271 28 100       93 if ($text_part =~ / ([^\x0A\x0D]*) ( [\x0A\x0D] .* ) /xms) {
1272 21         36 my ($first_line, $after_first_break) = ($1, $2);
1273              
1274 21 100       36 if (length $first_line > 0) {
1275 5         15 $first_line =~ s/ ( ['\\] ) /\\$1/gxms;
1276 5         11 $first_line = q{$__self->output('} . $first_line . q{');};
1277             }
1278              
1279 21         35 $after_first_break =~ s/ ( ["\$\@\\] ) /\\$1/gxms;
1280              
1281 21         73 my $breaks = $break x (
1282             $after_first_break =~ s/ \x0D\x0A /\\x0D\\x0A/gxms
1283             + $after_first_break =~ s/ \x0A /\\x0A/gxms
1284             + $after_first_break =~ s/ \x0D /\\x0D/gxms
1285             - 1
1286             );
1287              
1288 21         159 return $first_line . $break
1289             . qq{\$__self->output("$after_first_break");$breaks};
1290             }
1291              
1292 7         24 $text_part =~ s/ ( ['\\] ) /\\$1/gxms;
1293              
1294 7         52 return q{$__self->output('} . $text_part . q{');};
1295             }
1296              
1297             {
1298             package Waft::compile;
1299              
1300 2     2 0 3 sub Waft::compile { eval ${ $_[1] } }
  2         1205  
1301             }
1302              
1303             {
1304             my $OUTPUT_CONTENT_CODEREF;
1305              
1306             sub output {
1307 6   33 6 1 46 ( $_[0]->stash->{output} ||= do {
1308 0         0 my ($self) = @_;
1309              
1310 0         0 $self->output_response_headers;
1311 0         0 $self->stash->{responded} = 1;
1312              
1313 0         0 $OUTPUT_CONTENT_CODEREF;
1314             } )->(@_);
1315             }
1316              
1317             $OUTPUT_CONTENT_CODEREF = sub { shift; print @_ if @_; return };
1318             }
1319              
1320             sub output_response_headers {
1321 0     0 0 0 my ($self) = @_;
1322              
1323 0         0 for my $response_header ( $self->get_response_headers ) {
1324 0         0 print "$response_header\x0D\x0A";
1325             }
1326              
1327 0 0       0 if ($self->BCV < 0.53) {
1328 0 0       0 if ( not grep { /\A Content-Type: /ixms
  0         0  
1329             } $self->get_response_headers
1330             ) {
1331 0         0 my $content_type = $self->stash->{content_type};
1332 0         0 print "Content-Type: $content_type\x0D\x0A";
1333             }
1334              
1335 0         0 print "\x0D\x0A";
1336              
1337 0         0 return;
1338             }
1339              
1340 0 0       0 if ( not grep { /\A Content-Type: /ixms } $self->get_response_headers ) {
  0         0  
1341 0         0 print 'Content-Type: ' . $self->get_default_content_type . "\x0D\x0A";
1342             }
1343              
1344 0         0 print "\x0D\x0A";
1345              
1346 0         0 return;
1347             }
1348              
1349             sub get_response_headers {
1350 2     2 0 4 my ($self) = @_;
1351              
1352 2 50       7 return @{ $self->stash->{headers} } if $self->BCV < 0.53;
  0         0  
1353              
1354 2         4 return @{ $self->stash->{response_headers} }
  2         5  
1355             }
1356              
1357             {
1358             my $BUFFER_CONTENT_CODEREF;
1359              
1360             sub get_content {
1361 3     3 1 43 my ($self, $coderef, @args) = @_;
1362              
1363 3         15 my $stash = $self->stash;
1364              
1365 3         6 push @{ $stash->{contents} }, q{};
  3         9  
1366              
1367 3         13 local $stash->{output} = $BUFFER_CONTENT_CODEREF
1368 3 100       4 if @{ $stash->{contents} } == 1;
1369 3         10 my @return_values = $self->$coderef(@args);
1370              
1371 3 100       11 return pop @{ $stash->{contents} }, @return_values if wantarray;
  1         5  
1372 2         2 return pop @{ $stash->{contents} };
  2         9  
1373             }
1374              
1375             $BUFFER_CONTENT_CODEREF
1376             = sub { shift->stash->{contents}->[-1] .= join q{}, @_; return };
1377             }
1378              
1379 10     10 0 46 sub jsstr_filter { shift->jsstr_escape(@_) }
1380              
1381             sub jsstr_escape {
1382 10     10 1 17 my ($self, @values) = @_;
1383              
1384             VALUE:
1385 10         14 for my $value (@values) {
1386 10 50       19 if ( not defined $value ) {
1387 0         0 $self->warn('Use of uninitialized value');
1388              
1389 0         0 next VALUE;
1390             }
1391              
1392 10         41 $value =~ s{ (["'/\\]) }{\\$1}gxms;
1393 10         18 $value =~ s/ \x0A /\\n/gxms;
1394 10         16 $value =~ s/ \x0D /\\r/gxms;
1395 10         12 $value =~ s/ < /\\x3C/gxms;
1396 10         22 $value =~ s/ > /\\x3E/gxms;
1397             }
1398              
1399 10 100       50 return wantarray ? @values : $values[0];
1400             }
1401              
1402             sub text_filter {
1403 10     10 0 28 my ($self, @values) = @_;
1404              
1405             VALUE:
1406 10         14 for my $value ( @values ) {
1407 10 50       19 if ( not defined $value ) {
1408 0         0 $self->warn('Use of uninitialized value');
1409              
1410 0         0 next VALUE;
1411             }
1412              
1413 10         30 $value = $self->expand_tabs($value);
1414 10         25 $value = $self->html_escape($value);
1415 10         56 $value =~ s{ ( \x0D\x0A | [\x0A\x0D] ) }{
$1}gxms;
1416 10         19 $value =~ s{\A \x20 }{ }gxms;
1417 10         50 $value =~ s{ (\s) \x20 }{$1 }gxms;
1418             }
1419              
1420 10 100       49 return wantarray ? @values : $values[0];
1421             }
1422              
1423             sub expand_tabs {
1424 12     12 0 30 my ($self, @values) = @_;
1425              
1426             VALUE:
1427 12         19 for my $value (@values) {
1428 12 50       25 if ( not defined $value ) {
1429 0         0 $self->warn('Use of uninitialized value');
1430              
1431 0         0 next VALUE;
1432             }
1433              
1434 12         44 $value =~ s{( [^\x0A\x0D]+ )}{
1435 51         77 my $line = $1;
1436              
1437 51         131 while ( $line =~ / \t /gxms ) {
1438 106         130 my $offset = pos($line) - 1;
1439 106         319 substr( $line, $offset, 1 ) = q{ } x ( 8 - $offset % 8 );
1440             }
1441              
1442 51         168 $line;
1443             }egxms;
1444             }
1445              
1446 12 50       51 return wantarray ? @values : $values[0];
1447             }
1448              
1449             sub html_escape {
1450 45     45 1 71 my ($self, @values) = @_;
1451              
1452             VALUE:
1453 45         58 for my $value (@values) {
1454 45 50       82 if ( not defined $value ) {
1455 0         0 $self->warn('Use of uninitialized value');
1456              
1457 0         0 next VALUE;
1458             }
1459              
1460 45         76 $value =~ s/ & /&/gxms;
1461 45         61 $value =~ s/ " /"/gxms;
1462 45         89 $value =~ s/ ' /'/gxms;
1463 45         54 $value =~ s/ < /</gxms;
1464 45         95 $value =~ s/ > />/gxms;
1465             }
1466              
1467 45 100       303 return wantarray ? @values : $values[0];
1468             }
1469              
1470 18     18 0 44 sub word_filter { shift->html_escape(@_) }
1471              
1472             {
1473             my (%Start, %Progress, $FIND_NEXT_CODEREF);
1474              
1475             sub next {
1476 84     84 1 1189 my ($self) = @_;
1477              
1478 84         79 my ($back, $subroutine);
1479 84         504 1 while ( ( $subroutine = ( caller ++$back )[3] ) eq '(eval)' );
1480 84         372 my ($caller, $method) = $subroutine =~ / (.+) :: (.+) /xms;
1481              
1482 84   66     403 my $ident = $self->refaddr || $self;
1483              
1484 84 100 100     758 local $Start{ $ident, $method } = $caller
1485             if not $Start{ $ident, $method }
1486             or ( caller $back + 1 )[3] ne ( caller 0 )[3];
1487 84         475 local $Progress{ $ident, $method, $Start{ $ident, $method } }
1488             = $Progress{ $ident, $method, $Start{ $ident, $method } };
1489              
1490 84         304 my $next_coderef = $self->$FIND_NEXT_CODEREF(
1491             $method
1492             , $Start{ $ident, $method }
1493             , $Progress{ $ident, $method, $Start{ $ident, $method } }++
1494             );
1495              
1496 84 50       151 return if not $next_coderef;
1497              
1498 84         242 return $next_coderef->(@_);
1499             }
1500              
1501             my %Cached_next_coderefs;
1502              
1503             $FIND_NEXT_CODEREF = sub {
1504             my ($self, $method, $start, $progress) = @_;
1505              
1506             my $class = $self->blessed || $self;
1507              
1508             return $Cached_next_coderefs{$class, $method, $start}->[$progress]
1509             if $Waft::Cache
1510             and exists $Cached_next_coderefs{$class, $method, $start};
1511              
1512             my @next_classes;
1513              
1514             my @classes = ($class);
1515             while ( my $class = shift @classes ) {
1516             push @next_classes, $class;
1517              
1518 20     20   145 no strict 'refs';
  20         43  
  20         1628  
1519             unshift @classes, @{ "${class}::ISA" };
1520             }
1521              
1522             while ( $start ne shift @next_classes ) {
1523             return if @next_classes == 0;
1524             }
1525              
1526             my @next_coderefs = do {
1527 20     20   86 no strict 'refs';
  20         35  
  20         55690  
1528             grep { $_ } map { *{ "${_}::$method" }{CODE} } @next_classes;
1529             };
1530              
1531             $Cached_next_coderefs{$class, $method, $start} = \@next_coderefs;
1532              
1533             return $next_coderefs[$progress];
1534             };
1535             }
1536              
1537             sub get_page_id {
1538 0     0 0 0 my ($self, $page) = @_;
1539              
1540 0 0       0 if ( not defined $page ) {
1541 0         0 $page = $self->get_page;
1542             }
1543              
1544 0         0 my $page_id = $self->to_page_id($page);
1545              
1546 0         0 return $page_id;
1547             }
1548              
1549 0     0 0 0 sub page_id { shift->get_page_id(@_) }
1550              
1551             sub set_value {
1552 0     0 1 0 my ($self, $key, $value) = @_;
1553              
1554 0         0 $self->set_values($key, $value);
1555              
1556 0         0 return;
1557             }
1558              
1559             sub get_value {
1560 1     1 1 2 my ($self, $key, @i) = @_;
1561              
1562 1         3 return( ( $self->get_values($key, @i) )[0] );
1563             }
1564              
1565             sub add_response_header {
1566 0     0 0 0 my ($self, $response_header) = @_;
1567              
1568 0 0       0 if ($_[0]->BCV < 0.53) {
1569 0         0 ( undef, my @response_header_blocks ) = @_;
1570              
1571 0         0 my $stash = $self->stash;
1572 0         0 for my $response_header_block ( @response_header_blocks ) {
1573             my @response_header_lines
1574 0         0 = grep { length > 0
  0         0  
1575             } split /[\x0A\x0D]+/, $response_header_block;
1576 0         0 push @{ $stash->{headers} }, @response_header_lines;
  0         0  
1577             }
1578              
1579 0         0 return;
1580             }
1581              
1582 0         0 $response_header =~ s/ [\x0A\x0D]+ //gxms;
1583 0         0 push @{ $self->stash->{response_headers} }, $response_header;
  0         0  
1584              
1585 0         0 return;
1586             }
1587              
1588 0     0 1 0 sub header { shift->add_response_header(@_) }
1589              
1590 0     0 0 0 sub add_header { shift->header(@_) }
1591              
1592             sub make_url {
1593 9     9 0 17 my ($self, $page, @keys_arrayref_or_key_value_pairs) = @_;
1594              
1595 9         30 my $query_string
1596             = $self->make_query_string($page, @keys_arrayref_or_key_value_pairs);
1597              
1598 9 100       42 return $self->get_base_url if length $query_string == 0;
1599              
1600 1         2 return $self->get_base_url . '?' . $query_string;
1601             }
1602              
1603 2     2 1 24 sub url { shift->make_url(@_) }
1604              
1605             sub make_absolute_url {
1606 7     7 0 14 my ($self, @args) = @_;
1607              
1608 7         17 my $protocol = $self->cgi->protocol;
1609              
1610 7         1397 my $base_url = "$protocol://";
1611              
1612 7 100       24 if ( defined $ENV{HTTP_HOST} ) {
1613 1         3 $base_url .= $ENV{HTTP_HOST};
1614             }
1615             else {
1616 6         12 $base_url .= $ENV{SERVER_NAME};
1617              
1618 6 100 100     52 if ( $protocol eq 'http' and $ENV{SERVER_PORT} != 80
      100        
      66        
1619             or $protocol eq 'https' and $ENV{SERVER_PORT} != 443
1620             ) {
1621 2         6 $base_url .= ":$ENV{SERVER_PORT}";
1622             }
1623             }
1624              
1625 7 100 66     43 if ( defined $ENV{REQUEST_URI}
1626             and $ENV{REQUEST_URI} =~ /\A ([^?]+) /xms
1627             ) {
1628 5         11 $base_url .= $1;
1629             }
1630             else {
1631 2         7 $base_url .= $ENV{SCRIPT_NAME};
1632             }
1633              
1634 7 50       15 local $self->stash->{url} = $base_url if $self->BCV < 0.53;
1635 7         15 local $self->stash->{base_url} = $base_url;
1636              
1637 7         22 return $self->make_url(@args);
1638             }
1639              
1640 7     7 1 53 sub absolute_url { shift->make_absolute_url(@_) }
1641              
1642             sub make_query_string {
1643 9     9 0 15 my ($self, $page, @keys_arrayref_or_key_value_pairs) = @_;
1644              
1645 9 50       22 if (ref $page eq 'ARRAY') {
1646 0         0 $page = $page->[0];
1647             }
1648              
1649 9 50       24 $page = ! defined $page ? 'default.html'
    100          
1650             : $page eq 'CURRENT' ? $self->get_page
1651             : $page;
1652              
1653 9         13 my @query_string;
1654              
1655 9 100       22 if ($page ne 'default.html') {
1656 1         8 push @query_string,
1657             join( '=', ( $self->url_encode( 'p' => $page ) ) );
1658             }
1659              
1660 9         31 my $joined_values = $self->join_values(@keys_arrayref_or_key_value_pairs);
1661 9 100       20 if ( $joined_values ) {
1662 1         3 push @query_string,
1663             join( '=', ( $self->url_encode('v' => $joined_values) ) );
1664             }
1665              
1666 9         14 my $query_string = join '&', @query_string;
1667              
1668 9         22 return $query_string;
1669             }
1670              
1671             sub url_encode {
1672 2     2 1 5 my ($self, @values) = @_;
1673              
1674 2         4 my $using_utf8 = $self->get_using_utf8;
1675              
1676             VALUE:
1677 2         4 for my $value ( @values ) {
1678 4 50       9 if ( not defined $value ) {
1679 0         0 $self->warn('Use of uninitialized value');
1680              
1681 0         0 next VALUE;
1682             }
1683              
1684 4 50       9 if ( $using_utf8 ) {
1685 0         0 utf8::encode($value);
1686             }
1687              
1688 4         7 $value =~ s/ ( [^ .\w-] ) / '%' . unpack('H2', $1) /egxms;
  0         0  
1689 4         12 $value =~ tr/ /+/;
1690             }
1691              
1692 2 50       10 return wantarray ? @values : $values[0];
1693             }
1694              
1695             sub get_base_url {
1696 9     9 0 13 my ($self) = @_;
1697              
1698 9 50 33     27 return $Waft::Base_url if defined $Waft::Base_url and $self->BCV < 1.0;
1699              
1700 9 50       17 return $self->stash->{url} if $self->BCV < 0.53;
1701              
1702 9         16 return $self->stash->{base_url};
1703             }
1704              
1705             sub __forbidden__indirect {
1706 0     0   0 my ($self, @args) = @_;
1707              
1708 0         0 $self->add_response_header('Status: 403 Forbidden');
1709 0         0 $self->add_response_header('Content-Type: text/html; charset=ISO8859-1');
1710              
1711 0         0 $self->output(qq{\n});
1712 0         0 $self->output(qq{\n});
1713 0         0 $self->output(qq{403 Forbidden\n});
1714 0         0 $self->output(qq{\n});
1715 0         0 $self->output(qq{

Forbidden

\n});
1716 0         0 $self->output( q{

You don't have permission to access this page.});

1717 0         0 $self->output(qq{

\n});
1718 0         0 $self->output(qq{\n});
1719              
1720 0         0 return @args;
1721             }
1722              
1723             sub __not_found__indirect {
1724 0     0   0 my ($self, @args) = @_;
1725              
1726 0         0 $self->add_response_header('Status: 404 Not Found');
1727 0         0 $self->add_response_header('Content-Type: text/html; charset=ISO8859-1');
1728              
1729 0         0 $self->output(qq{\n});
1730 0         0 $self->output(qq{\n});
1731 0         0 $self->output(qq{404 Not Found\n});
1732 0         0 $self->output(qq{\n});
1733 0         0 $self->output(qq{

Not Found

\n});
1734 0         0 $self->output(qq{

The requested URL was not found.

\n});
1735 0         0 $self->output(qq{\n});
1736              
1737 0         0 return @args;
1738             }
1739              
1740             sub __internal_server_error__indirect {
1741 0     0   0 my ($self, @args) = @_;
1742              
1743 0         0 $self->add_response_header('Status: 500 Internal Server Error');
1744 0         0 $self->add_response_header('Content-Type: text/html; charset=ISO8859-1');
1745              
1746 0         0 $self->output(qq{\n});
1747 0         0 $self->output(qq{\n});
1748 0         0 $self->output(qq{500 Internal Server Error\n});
1749 0         0 $self->output(qq{\n});
1750 0         0 $self->output(qq{

Internal Server Error

\n});
1751 0         0 $self->output(qq{

The server encountered an internal error or\n});

1752 0         0 $self->output(qq{misconfiguration and was unable to complete\n});
1753 0         0 $self->output(qq{your request.

\n});
1754 0         0 $self->output(qq{

Please contact the server administrator\n});

1755 0         0 $self->output(qq{ and inform them of the time the error occurred,\n});
1756 0         0 $self->output(qq{and anything you might have done that may have\n});
1757 0         0 $self->output(qq{caused the error.

\n});
1758 0         0 $self->output( q{

More information about this error may be });

1759 0         0 $self->output(qq{available\n});
1760 0         0 $self->output(qq{in the server error log.

\n});
1761 0         0 $self->output(qq{\n});
1762              
1763 0         0 return @args;
1764             }
1765              
1766             {
1767             my $Defined_subs_for_under_0_99x;
1768              
1769             sub define_subs_for_under_0_99x {
1770              
1771 14 100   14 0 44 return if $Defined_subs_for_under_0_99x;
1772              
1773 13     0   88 *croak = *croak = sub { shift->die(@_) };
  0         0  
1774 13     0   69 *carp = *carp = sub { shift->warn(@_) };
  0         0  
1775              
1776             *init_base_url = *init_base_url
1777 13     1   64 = sub { shift->initialize_base_url(@_) };
  1         11  
1778             *init_page = *init_page
1779 13     1   65 = sub { shift->initialize_page(@_) };
  1         11  
1780             *init_values = *init_values
1781 13     1   57 = sub { shift->initialize_values(@_) };
  1         13  
1782             *init_action = *init_action
1783 13     1   59 = sub { shift->initialize_action(@_) };
  1         12  
1784             *init_response_headers = *init_response_headers
1785 13     1   64 = sub { shift->initialize_response_headers(@_) };
  1         11  
1786             *init_binmode = *init_binmode
1787 13     1   61 = sub { shift->initialize_binmode(@_) };
  1         14  
1788              
1789 13     0   114 *is_blessed = *is_blessed = sub { shift->blessed(@_) };
  0         0  
1790              
1791 13     0   64 *ident = *ident = sub { shift->refaddr(@_) };
  0         0  
1792              
1793             *keys_arrayref = *keys_arrayref
1794 13     1   55 = sub { [ keys %{ $_[0]->value_hashref } ] };
  1         2  
  1         4  
1795              
1796             *exists_key = *exists_key
1797 13     0   57 = sub { exists $_[0]->value_hashref->{ $_[1] } };
  0         0  
1798              
1799 13     1   57 *expand = *expand = sub { Waft->expand_tabs(@_) };
  1         3  
1800              
1801 13         24 $Defined_subs_for_under_0_99x = 1;
1802              
1803 13         23 return;
1804             }
1805              
1806             my $Defined_subs_for_under_0_52x;
1807              
1808             sub define_subs_for_under_0_52x {
1809              
1810 0 0   0 0 0 return if $Defined_subs_for_under_0_52x;
1811              
1812             *array = *array = sub {
1813 0     0   0 my ($self, $key, @values) = @_;
1814              
1815 0 0       0 if ( @values ) {
1816 0         0 my @old_values = $self->get_values($key);
1817              
1818 0         0 $self->set_values($key, @values);
1819              
1820 0         0 return @old_values;
1821             }
1822              
1823 0         0 return $self->get_values($key);
1824 0         0 };
1825              
1826             *arrayref = *arrayref = sub {
1827 0     0   0 my ($self, $key, $arrayref) = @_;
1828              
1829 0 0       0 return $self->value_hashref->{$key} = $arrayref
1830             if ref $arrayref eq 'ARRAY';
1831              
1832 0   0     0 return $self->value_hashref->{$key} ||= $arrayref;
1833 0         0 };
1834              
1835 0         0 eval q{ sub begin { return } };
1836 0         0 eval q{ sub before { return } };
1837              
1838 0     0   0 *end = *end = sub { return };
  0         0  
1839              
1840             *form_elements = *form_elements = sub {
1841 0     0   0 my ($self, @args) = @_;
1842              
1843 0 0 0     0 if (@args == 1
      0        
      0        
1844             and defined $args[0]
1845             and $args[0] eq 'ALL' || $args[0] eq 'ALLVALUES'
1846             ) {
1847 0         0 $args[0] = 'ALL_VALUES';
1848             }
1849              
1850 0         0 $self->output_waft_tags(@args);
1851              
1852 0         0 return;
1853 0         0 };
1854              
1855 0         0 *query = *query = \&cgi;
1856              
1857 0         0 *waft_tags = *waft_tags = \&get_waft_tags;
1858              
1859 0         0 *_join_values = *_join_values = \&join_values;
1860              
1861             *_load_query_param = *_load_query_param = sub {
1862 0     0   0 my ($self) = @_;
1863              
1864 0         0 $self->init_page;
1865 0         0 $self->init_action;
1866 0         0 $self->init_values;
1867              
1868 0         0 return;
1869 0         0 };
1870              
1871             *__DEFAULT = *__DEFAULT = sub {
1872 0     0   0 my ($self, @args) = @_;
1873              
1874 0         0 return { page => 'default.html', action => $self->action }, @args;
1875 0         0 };
1876              
1877 0         0 $Defined_subs_for_under_0_52x = 1;
1878              
1879 0         0 return;
1880             }
1881             }
1882              
1883             package Waft::Object;
1884              
1885             sub TIEHASH {
1886              
1887 14     14   42 bless {};
1888             }
1889              
1890             sub STORE {
1891 3 50   3   17 if (ref $_[2] eq 'ARRAY') {
1892 0 0       0 @{ $_[0]{ defined $_[1] ? $_[1] : warn_and_null() } } = @{$_[2]};
  0         0  
  0         0  
1893             }
1894             else {
1895 3 50       4 @{ $_[0]{ defined $_[1] ? $_[1] : warn_and_null() } } = ($_[2]);
  3         27  
1896             }
1897             }
1898              
1899             sub warn_and_null {
1900 0     0   0 require Carp;
1901 0         0 Carp::carp('Use of uninitialized value');
1902 0         0 q{};
1903             }
1904              
1905             sub FETCH {
1906 6 50   6   29 my $arrayref = $_[0]{ defined $_[1] ? $_[1] : warn_and_null() }
    50          
1907             or return;
1908              
1909 6         30 $arrayref->[0];
1910             }
1911              
1912 0     0   0 sub FIRSTKEY { keys %{$_[0]}; each %{$_[0]} }
  0         0  
  0         0  
  0         0  
1913              
1914 0     0   0 sub NEXTKEY { each %{$_[0]} }
  0         0  
1915              
1916 0 0   0   0 sub EXISTS { exists $_[0]{ defined $_[1] ? $_[1] : warn_and_null() } }
1917              
1918 0 0   0   0 sub DELETE { delete $_[0]{ defined $_[1] ? $_[1] : warn_and_null() } }
1919              
1920 0     0   0 sub CLEAR { %{$_[0]} = () }
  0         0  
1921              
1922             1;
1923             __END__