File Coverage

blib/lib/Catalyst/Engine.pm
Criterion Covered Total %
statement 232 268 86.5
branch 76 102 74.5
condition 21 42 50.0
subroutine 32 39 82.0
pod 21 22 95.4
total 382 473 80.7


line stmt bran cond sub pod time code
1              
2             use Moose;
3 155     155   154400 with 'MooseX::Emulate::Class::Accessor::Fast';
  155         385773  
  155         1223  
4              
5             use CGI::Simple::Cookie;
6 155     155   913167 use Data::Dump qw/dump/;
  155         684622  
  155         4337  
7 155     155   3992 use Errno 'EWOULDBLOCK';
  155         15014  
  155         8739  
8 155     155   1443 use HTML::Entities;
  155         1503  
  155         19959  
9 155     155   2431 use HTTP::Headers;
  155         15539  
  155         9047  
10 155     155   1494 use Plack::Loader;
  155         4710  
  155         3820  
11 155     155   3669 use Catalyst::EngineLoader;
  155         16513  
  155         3662  
12 155     155   1915 use Encode 2.21 'decode_utf8', 'encode', 'decode';
  155         423  
  155         5305  
13 155     155   1973 use Plack::Request::Upload;
  155         28449  
  155         8781  
14 155     155   2242 use Hash::MultiValue;
  155         1558  
  155         4916  
15 155     155   2174 use namespace::clean -except => 'meta';
  155         6647  
  155         4868  
16 155     155   978 use utf8;
  155         475  
  155         1999  
17 155     155   62764  
  155         436  
  155         3466  
18             # Amount of data to read from input on each pass
19             our $CHUNKSIZE = 64 * 1024;
20              
21             # XXX - this is only here for compat, do not use!
22             has env => ( is => 'rw', writer => '_set_env' , weak_ref=>1);
23             my $WARN_ABOUT_ENV = 0;
24             around env => sub {
25             my ($orig, $self, @args) = @_;
26             if(@args) {
27             warn "env as a writer is deprecated, you probably need to upgrade Catalyst::Engine::PSGI"
28             unless $WARN_ABOUT_ENV++;
29             return $self->_set_env(@args);
30             }
31             return $self->$orig;
32             };
33              
34             # XXX - Only here for Engine::PSGI compat
35             my ($self, $ctx) = @_;
36             $ctx->request->prepare_connection;
37 0     0 0 0 }
38 0         0  
39             =head1 NAME
40              
41             Catalyst::Engine - The Catalyst Engine
42              
43             =head1 SYNOPSIS
44              
45             See L<Catalyst>.
46              
47             =head1 DESCRIPTION
48              
49             =head1 METHODS
50              
51              
52             =head2 $self->finalize_body($c)
53              
54             Finalize body. Prints the response output as blocking stream if it looks like
55             a filehandle, otherwise write it out all in one go. If there is no body in
56             the response, we assume you are handling it 'manually', such as for nonblocking
57             style or asynchronous streaming responses. You do this by calling L</write>
58             several times (which sends HTTP headers if needed) or you close over
59             C<< $response->write_fh >>.
60              
61             See L<Catalyst::Response/write> and L<Catalyst::Response/write_fh> for more.
62              
63             =cut
64              
65             my ( $self, $c ) = @_;
66             my $res = $c->response; # We use this all over
67              
68 918     918 1 2064 ## If we've asked for the write 'filehandle' that means the application is
69 918         19297 ## doing something custom and is expected to close the response
70             return if $res->_has_write_fh;
71              
72             my $body = $res->body; # save some typing
73 918 100       25389 if($res->_has_response_cb) {
74             ## we have not called the response callback yet, so we are safe to send
75 913         19577 ## the whole body to PSGI
76 913 100       25709  
77             my @headers;
78             $res->headers->scan(sub { push @headers, @_ });
79              
80 901         1617 # We need to figure out what kind of body we have and normalize it to something
81 901     5924   2503 # PSGI can deal with
  5924         64266  
82             if(defined $body) {
83             # Handle objects first
84             if(blessed($body)) {
85 901 100       6772 if($body->can('getline')) {
86             # Body is an IO handle that meets the PSGI spec. Nothing to normalize
87 860 100       3434 } elsif($body->can('read')) {
    100          
88 12 100       135  
    50          
89             # In the past, Catalyst only looked for ->read not ->getline. It is very possible
90             # that one might have an object that respected read but did not have getline.
91             # As a result, we need to handle this case for backcompat.
92              
93             # We will just do the old loop for now. In a future version of Catalyst this support
94             # will be removed and one will have to rewrite their custom object or use
95             # Plack::Middleware::AdaptFilehandleRead. In anycase support for this is officially
96             # deprecated and described as such as of 5.90060
97              
98             my $got;
99             do {
100             $got = read $body, my ($buffer), $CHUNKSIZE;
101 0         0 $got = 0 unless $self->write($c, $buffer );
102 0         0 } while $got > 0;
103 0         0  
104 0 0       0 close $body;
105             return;
106             } else {
107 0         0 # Looks like for backcompat reasons we need to be able to deal
108 0         0 # with stringyfiable objects.
109             $body = ["$body"];
110             }
111             } elsif(ref $body) {
112 11         49 if( (ref($body) eq 'GLOB') or (ref($body) eq 'ARRAY')) {
113             # Again, PSGI can just accept this, no transform needed. We don't officially
114             # document the body as arrayref at this time (and there's not specific test
115 6 50 33     39 # cases. we support it because it simplifies some plack compatibility logic
116             # and we might make it official at some point.
117             } else {
118             $c->log->error("${\ref($body)} is not a valid value for Response->body");
119             return;
120             }
121 0         0 } else {
  0         0  
122 0         0 # Body is defined and not an object or reference. We assume a simple value
123             # and wrap it in an array for PSGI
124             $body = [$body];
125             }
126             } else {
127 842         1967 # There's no body...
128             $body = [];
129             }
130             $res->_response_cb->([ $res->status, \@headers, $body]);
131 41         102 $res->_clear_response_cb;
132              
133 901         3075 } else {
134 901         524088 ## Now, if there's no response callback anymore, that means someone has
135             ## called ->write in order to stream 'some stuff along the way'. I think
136             ## for backcompat we still need to handle a ->body. I guess I could see
137             ## someone calling ->write to presend some stuff, and then doing the rest
138             ## via ->body, like in a template.
139              
140             ## We'll just use the old, existing code for this (or most of it)
141              
142             if(my $body = $res->body) {
143              
144             if ( blessed($body) && $body->can('read') or ref($body) eq 'GLOB' ) {
145 12 100       293  
146             ## In this case we have no choice and will fall back on the old
147 3 50 33     32 ## manual streaming stuff. Not optimal. This is deprecated as of 5.900560+
      33        
148              
149             my $got;
150             do {
151             $got = read $body, my ($buffer), $CHUNKSIZE;
152 0         0 $got = 0 unless $self->write($c, $buffer );
153 0         0 } while $got > 0;
154 0         0  
155 0 0       0 close $body;
156             }
157             else {
158 0         0  
159             # Case where body was set after calling ->write. We'd prefer not to
160             # support this, but I can see some use cases with the way most of the
161             # views work. Since body has already been encoded, we need to do
162             # an 'unencoded_write' here.
163             $self->unencoded_write( $c, $body );
164             }
165             }
166 3         16  
167             $res->_writer->close;
168             $res->_clear_writer;
169             }
170 12         272  
171 12         5346 return;
172             }
173              
174 913         2996 =head2 $self->finalize_cookies($c)
175              
176             Create CGI::Simple::Cookie objects from $c->res->cookies, and set them as
177             response headers.
178              
179             =cut
180              
181             my ( $self, $c ) = @_;
182              
183             my @cookies;
184             my $response = $c->response;
185 918     918 1 2181  
186             foreach my $name (keys %{ $response->cookies }) {
187 918         1334  
188 918         19419 my $val = $response->cookies->{$name};
189              
190 918         1789 my $cookie = (
  918         21739  
191             blessed($val)
192 8         570 ? $val
193             : CGI::Simple::Cookie->new(
194             -name => $name,
195             -value => $val->{value},
196             -expires => $val->{expires},
197             -domain => $val->{domain},
198             -path => $val->{path},
199             -secure => $val->{secure} || 0,
200             -httponly => $val->{httponly} || 0,
201             -samesite => $val->{samesite},
202             )
203             );
204             if (!defined $cookie) {
205             $c->log->warn("undef passed in '$name' cookie value - not setting cookie")
206             if $c->debug;
207 8 100 50     96 next;
      50        
208 8 100       1125 }
209 1 50       6  
210             push @cookies, $cookie->as_string;
211 1         3 }
212              
213             for my $cookie (@cookies) {
214 7         19 $response->headers->push_header( 'Set-Cookie' => $cookie );
215             }
216             }
217 918         2901  
218 7         111 =head2 $self->finalize_error($c)
219              
220             Output an appropriate error message. Called if there's an error in $c
221             after the dispatch has finished. Will output debug messages if Catalyst
222             is in debug mode, or a `please come back later` message otherwise.
223              
224             =cut
225              
226             my ($self, $i, $element) = @_;
227             my ($name, $val) = @{ $element };
228              
229             # This is fugly, but the metaclass is _HUGE_ and demands waaay too much
230             # scrolling. Suggestions for more pleasant ways to do this welcome.
231 31     31   1170 local $val->{'__MOP__'} = "Stringified: "
232 31         61 . $val->{'__MOP__'} if ref $val eq 'HASH' && exists $val->{'__MOP__'};
  31         59  
233              
234             my $text = encode_entities( dump( $val ));
235             sprintf <<"EOF", $name, $text;
236             <h2><a href="#" onclick="toggleDump('dump_$i'); return false">%s</a></h2>
237 31 50 66     117 <div id="dump_$i">
238             <pre wrap="">%s</pre>
239 31         79 </div>
240 31         47470 EOF
241             }
242              
243             my ( $self, $c ) = @_;
244              
245             $c->res->content_type('text/html; charset=utf-8');
246             my $name = ref($c)->config->{name} || join(' ', split('::', ref $c));
247              
248             # Prevent Catalyst::Plugin::Unicode::Encoding from running.
249 34     34 1 117 # This is a little nasty, but it's the best way to be clean whether or
250             # not the user has an encoding plugin.
251 34         191  
252 34   66     798 if ($c->can('encoding')) {
253             $c->{encoding} = '';
254             }
255              
256             my ( $title, $error, $infos );
257             if ( $c->debug ) {
258 34 50       205  
259 34         140 # For pretty dumps
260             $error = join '', map {
261             '<p><code class="error">'
262 34         76 . encode_entities($_)
263 34 100       119 . '</code></p>'
264             } @{ $c->error };
265             $error ||= 'No output';
266             $error = qq{<pre wrap="">$error</pre>};
267 9         61 $title = $name = "$name on Catalyst $Catalyst::VERSION";
268             $name = "<h1>$name</h1>";
269              
270 7         25 # Don't show context in the dump
  7         15  
271 7   50     144 $c->res->_clear_context;
272 7         34  
273 7         18 # Don't show body parser in the dump
274 7         15 $c->req->_clear_body;
275              
276             my @infos;
277 7         15 my $i = 0;
278             for my $dump ( $c->dump_these ) {
279             push @infos, $self->_dump_error_page_element($i, $dump);
280 7         31 $i++;
281             }
282 7         12 $infos = join "\n", @infos;
283 7         12 }
284 7         19 else {
285 28         86 $title = $name;
286 28         62 $error = '';
287             $infos = <<"";
288 7         72 <pre>
289             (en) Please come back later
290             (fr) SVP veuillez revenir plus tard
291 27         69 (de) Bitte versuchen sie es spaeter nocheinmal
292 27         54 (at) Konnten's bitt'schoen spaeter nochmal reinschauen
293 27         69 (no) Vennligst prov igjen senere
294             (dk) Venligst prov igen senere
295             (pl) Prosze sprobowac pozniej
296             (pt) Por favor volte mais tarde
297             (ru) Попробуйте еще раз позже
298             (ua) Спробуйте ще раз пізніше
299             (it) Per favore riprova più tardi
300             </pre>
301              
302             $name = '';
303             }
304             $c->res->body( <<"" );
305             <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
306             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
307             <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
308 27         51 <head>
309             <meta http-equiv="Content-Language" content="en" />
310 34         115 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
311             <title>$title</title>
312             <script type="text/javascript">
313             <!--
314             function toggleDump (dumpElement) {
315             var e = document.getElementById( dumpElement );
316             if (e.style.display == "none") {
317             e.style.display = "";
318             }
319             else {
320             e.style.display = "none";
321             }
322             }
323             -->
324             </script>
325             <style type="text/css">
326             body {
327             font-family: "Bitstream Vera Sans", "Trebuchet MS", Verdana,
328             Tahoma, Arial, helvetica, sans-serif;
329             color: #333;
330             background-color: #eee;
331             margin: 0px;
332             padding: 0px;
333             }
334             :link, :link:hover, :visited, :visited:hover {
335             color: #000;
336             }
337             div.box {
338             position: relative;
339             background-color: #ccc;
340             border: 1px solid #aaa;
341             padding: 4px;
342             margin: 10px;
343             }
344             div.error {
345             background-color: #cce;
346             border: 1px solid #755;
347             padding: 8px;
348             margin: 4px;
349             margin-bottom: 10px;
350             }
351             div.infos {
352             background-color: #eee;
353             border: 1px solid #575;
354             padding: 8px;
355             margin: 4px;
356             margin-bottom: 10px;
357             }
358             div.name {
359             background-color: #cce;
360             border: 1px solid #557;
361             padding: 8px;
362             margin: 4px;
363             }
364             code.error {
365             display: block;
366             margin: 1em 0;
367             overflow: auto;
368             }
369             div.name h1, div.error p {
370             margin: 0;
371             }
372             h2 {
373             margin-top: 0;
374             margin-bottom: 10px;
375             font-size: medium;
376             font-weight: bold;
377             text-decoration: underline;
378             }
379             h1 {
380             font-size: medium;
381             font-weight: normal;
382             }
383             /* from http://users.tkk.fi/~tkarvine/linux/doc/pre-wrap/pre-wrap-css3-mozilla-opera-ie.html */
384             /* Browser specific (not valid) styles to make preformatted text wrap */
385             pre {
386             white-space: pre-wrap; /* css-3 */
387             white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
388             white-space: -pre-wrap; /* Opera 4-6 */
389             white-space: -o-pre-wrap; /* Opera 7 */
390             word-wrap: break-word; /* Internet Explorer 5.5+ */
391             }
392             </style>
393             </head>
394             <body>
395             <div class="box">
396             <div class="error">$error</div>
397             <div class="infos">$infos</div>
398             <div class="name">$name</div>
399             </div>
400             </body>
401             </html>
402              
403             # Trick IE. Old versions of IE would display their own error page instead
404             # of ours if we'd give it less than 512 bytes.
405             $c->res->{body} .= ( ' ' x 512 );
406              
407             $c->res->{body} = Encode::encode("UTF-8", $c->res->{body});
408              
409             # Return 500
410             $c->res->status(500);
411 34         138 }
412              
413 34         175 =head2 $self->finalize_headers($c)
414              
415             Allows engines to write headers to response
416 34         181  
417             =cut
418              
419             my ($self, $ctx) = @_;
420              
421             $ctx->finalize_headers unless $ctx->response->finalized_headers;
422             return;
423             }
424              
425             =head2 $self->finalize_uploads($c)
426 0     0 1 0  
427             Clean up after uploads, deleting temp files.
428 0 0       0  
429 0         0 =cut
430              
431             my ( $self, $c ) = @_;
432              
433             # N.B. This code is theoretically entirely unneeded due to ->cleanup(1)
434             # on the HTTP::Body object.
435             my $request = $c->request;
436             foreach my $key (keys %{ $request->uploads }) {
437             my $upload = $request->uploads->{$key};
438             unlink grep { -e $_ } map { $_->tempname }
439 918     918 1 2135 (ref $upload eq 'ARRAY' ? @{$upload} : ($upload));
440             }
441              
442             }
443 918         19818  
444 918         1817 =head2 $self->prepare_body($c)
  918         21564  
445 18         444  
446 20         1264 sets up the L<Catalyst::Request> object body using L<HTTP::Body>
  20         512  
447 18 100       78  
  1         5  
448             =cut
449              
450             my ( $self, $c ) = @_;
451              
452             $c->request->prepare_body;
453             }
454              
455             =head2 $self->prepare_body_chunk($c)
456              
457             Add a chunk to the request body.
458              
459 920     920 1 2069 =cut
460              
461 920         18845 # XXX - Can this be deleted?
462             my ( $self, $c, $chunk ) = @_;
463              
464             $c->request->prepare_body_chunk($chunk);
465             }
466              
467             =head2 $self->prepare_body_parameters($c)
468              
469             Sets up parameters from body.
470              
471             =cut
472 0     0 1 0  
473             my ( $self, $c ) = @_;
474 0         0  
475             $c->request->prepare_body_parameters;
476             }
477              
478             =head2 $self->prepare_parameters($c)
479              
480             Sets up parameters from query and post parameters.
481             If parameters have already been set up will clear
482             existing parameters and set up again.
483              
484 0     0 1 0 =cut
485              
486 0         0 my ( $self, $c ) = @_;
487              
488             $c->request->_clear_parameters;
489             return $c->request->parameters;
490             }
491              
492             =head2 $self->prepare_path($c)
493              
494             abstract method, implemented by engines.
495              
496             =cut
497              
498 919     919 1 2146 my ($self, $ctx) = @_;
499              
500 919         19545 my $env = $ctx->request->env;
501 919         17490  
502             my $scheme = $ctx->request->secure ? 'https' : 'http';
503             my $host = $env->{HTTP_HOST} || $env->{SERVER_NAME};
504             my $port = $env->{SERVER_PORT} || 80;
505             my $base_path = $env->{SCRIPT_NAME} || "/";
506              
507             # set the request URI
508             my $path;
509             if (!$ctx->config->{use_request_uri_for_path}) {
510             my $path_info = $env->{PATH_INFO};
511 931     931 1 2416 if ( exists $env->{REDIRECT_URL} ) {
512             $base_path = $env->{REDIRECT_URL};
513 931         20287 $base_path =~ s/\Q$path_info\E$//;
514             }
515 931 100       17942 $path = $base_path . $path_info;
516 931   100     2997 $path =~ s{^/+}{};
517 931   100     2621 $path =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
518 931   100     3504 $path =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE
519             }
520             else {
521 931         1463 my $req_uri = $env->{REQUEST_URI};
522 931 100       2713 $req_uri =~ s/\?.*$//;
523 316         755 $path = $req_uri;
524 316 100       867 $path =~ s{^/+}{};
525 3         6 }
526 3         48  
527             # Using URI directly is way too slow, so we construct the URLs manually
528 316         662 my $uri_class = "URI::$scheme";
529 316         1422  
530 316         2264 # HTTP_HOST will include the port even if it's 80/443
531 316         814 $host =~ s/:(?:80|443)$//;
532              
533             if ($port !~ /^(?:80|443)$/ && $host !~ /:/) {
534 615         1348 $host .= ":$port";
535 615         1446 }
536 615         1078  
537 615         2609 my $query = $env->{QUERY_STRING} ? '?' . $env->{QUERY_STRING} : '';
538             my $uri = $scheme . '://' . $host . '/' . $path . $query;
539              
540             $ctx->request->uri( (bless \$uri, $uri_class)->canonical );
541 931         2177  
542             # set the base URI
543             # base must end in a slash
544 931         1742 $base_path .= '/' unless $base_path =~ m{/$};
545              
546 931 0 33     4139 my $base_uri = $scheme . '://' . $host . $base_path;
547 0         0  
548             $ctx->request->base( bless \$base_uri, $uri_class );
549              
550 931 100       2613 return;
551 931         2634 }
552              
553 931         21648 =head2 $self->prepare_request($c)
554              
555             =head2 $self->prepare_query_parameters($c)
556              
557 931 100       3636 process the query string and extract query parameters.
558              
559 931         2574 =cut
560              
561 931         18631 my ($self, $c) = @_;
562             my $env = $c->request->env;
563 931         2645 my $do_not_decode_query = $c->config->{do_not_decode_query};
564              
565             my $old_encoding;
566             if(my $new = $c->config->{default_query_encoding}) {
567             $old_encoding = $c->encoding;
568             $c->encoding($new);
569             }
570              
571             my $check = $c->config->{do_not_check_query_encoding} ? undef :$c->_encode_check;
572             my $decoder = sub {
573             my $str = shift;
574             return $str if $do_not_decode_query;
575 923     923 1 2416 return $c->_handle_param_unicode_decoding($str, $check);
576 923         20234 };
577 923         3053  
578             my $query_string = exists $env->{QUERY_STRING}
579 923         1763 ? $env->{QUERY_STRING}
580 923 100       2323 : '';
581 1         12  
582 1         7 $query_string =~ s/\A[&;]+//;
583              
584             my @unsplit_pairs = split /[&;]+/, $query_string;
585 923 50       2644 my $p = Hash::MultiValue->new();
586              
587 283     283   415 my $is_first_pair = 1;
588 283 50       554 for my $pair (@unsplit_pairs) {
589 283         735 my ($name, $value)
590 923         5101 = map { defined $_ ? $decoder->($self->unescape_uri($_)) : $_ }
591             ( split /=/, $pair, 2 )[0,1]; # slice forces two elements
592              
593             if ($is_first_pair) {
594 923 100       2882 # If the first pair has no equal sign, then it means the isindex
595             # flag is set.
596 923         1796 $c->request->query_keywords($name) unless defined $value;
597              
598 923         2474 $is_first_pair = 0;
599 923         5684 }
600              
601 923         31060 $p->add( $name => $value );
602 923         2000 }
603              
604 144 100       1986  
  288         3083  
605             $c->encoding($old_encoding) if $old_encoding;
606             $c->request->query_parameters( $c->request->_use_hash_multivalue ? $p : $p->mixed );
607 143 100       2273 }
608              
609             =head2 $self->prepare_read($c)
610 84 100       334  
611             Prepare to read by initializing the Content-Length from headers.
612 84         137  
613             =cut
614              
615 143         480 my ( $self, $c ) = @_;
616              
617             # Initialize the amount of data we think we need to read
618             $c->request->_read_length;
619 922 100       4525 }
620 922 100       23311  
621             =head2 $self->prepare_request(@arguments)
622              
623             Populate the context object from the request object.
624              
625             =cut
626              
627             my ($self, $ctx, %args) = @_;
628             $ctx->log->psgienv($args{env}) if $ctx->log->can('psgienv');
629             $ctx->request->_set_env($args{env});
630 922     922 1 2388 $self->_set_env($args{env}); # Nasty back compat!
631             $ctx->response->_set_response_cb($args{response_cb});
632             }
633 922         19751  
634             =head2 $self->prepare_uploads($c)
635              
636             =cut
637              
638             my ( $self, $c ) = @_;
639              
640             my $request = $c->request;
641             return unless $request->_body;
642              
643 932     932 1 3579 my $enc = $c->encoding;
644 932 100       2572 my $uploads = $request->_body->upload;
645 932         20279 my $parameters = $request->parameters;
646 932         23568 foreach my $name (keys %$uploads) {
647 932         19203 my $files = $uploads->{$name};
648             $name = $c->_handle_unicode_decoding($name) if $enc;
649             my @uploads;
650             for my $upload (ref $files eq 'ARRAY' ? @$files : ($files)) {
651             my $headers = HTTP::Headers->new( %{ $upload->{headers} } );
652             my $filename = $upload->{filename};
653             $filename = $c->_handle_unicode_decoding($filename) if $enc;
654              
655 918     918 1 2167 my $u = Catalyst::Request::Upload->new
656             (
657 918         19660 size => $upload->{size},
658 918 100       20434 type => scalar $headers->content_type,
659             charset => scalar $headers->content_type_charset,
660 46         194 headers => $headers,
661 46         1166 tempname => $upload->{tempname},
662 46         401 filename => $filename,
663 46         221 );
664 18         37 push @uploads, $u;
665 18 50       81 }
666 18         331 $request->uploads->{$name} = @uploads > 1 ? \@uploads : $uploads[0];
667 18 100       68  
668 20         39 # support access to the filename as a normal param
  20         122  
669 20         1597 my @filenames = map { $_->{filename} } @uploads;
670 20 50       113 # append, if there's already params with this name
671             if (exists $parameters->{$name}) {
672             if (ref $parameters->{$name} eq 'ARRAY') {
673             push @{ $parameters->{$name} }, @filenames;
674             }
675             else {
676             $parameters->{$name} = [ $parameters->{$name}, @filenames ];
677             }
678             }
679 20         384 else {
680             $parameters->{$name} = @filenames > 1 ? \@filenames : $filenames[0];
681 20         70 }
682             }
683 18 100       461 }
684              
685             =head2 $self->write($c, $buffer)
686 18         45  
  20         55  
687             Writes the buffer to the client.
688 18 100       73  
689 2 50       10 =cut
690 0         0  
  0         0  
691             my ( $self, $c, $buffer ) = @_;
692              
693 2         12 $c->response->write($buffer);
694             }
695              
696             =head2 $self->unencoded_write($c, $buffer)
697 16 100       97  
698             Writes the buffer to the client without encoding. Necessary for
699             already encoded buffers. Used when a $c->write has been done
700             followed by $c->res->body.
701              
702             =cut
703              
704             my ( $self, $c, $buffer ) = @_;
705              
706             $c->response->unencoded_write($buffer);
707             }
708              
709 0     0 1 0 =head2 $self->read($c, [$maxlength])
710              
711 0         0 Reads from the input stream by calling C<< $self->read_chunk >>.
712              
713             Maintains the read_length and read_position counters as data is read.
714              
715             =cut
716              
717             my ( $self, $c, $maxlength ) = @_;
718              
719             $c->request->read($maxlength);
720             }
721              
722             =head2 $self->read_chunk($c, \$buffer, $length)
723 3     3 1 10  
724             Each engine implements read_chunk as its preferred way of reading a chunk
725 3         69 of data. Returns the number of bytes read. A return of 0 indicates that
726             there is no more data to be read.
727              
728             =cut
729              
730             my ($self, $ctx) = (shift, shift);
731             return $ctx->request->read_chunk(@_);
732             }
733              
734             =head2 $self->run($app, $server)
735              
736             Start the engine. Builds a PSGI application and calls the
737 0     0 1 0 run method on the server passed in, which then causes the
738             engine to loop, handling requests..
739 0         0  
740             =cut
741              
742             my ($self, $app, $psgi, @args) = @_;
743             # @args left here rather than just a $options, $server for back compat with the
744             # old style scripts which send a few args, then a hashref
745              
746             # They should never actually be used in the normal case as the Plack engine is
747             # passed in got all the 'standard' args via the loader in the script already.
748              
749             # FIXME - we should stash the options in an attribute so that custom args
750             # like Gitalist's --git_dir are possible to get from the app without stupid tricks.
751 0     0 1 0 my $server = pop @args if (scalar @args && blessed $args[-1]);
752 0         0 my $options = pop @args if (scalar @args && ref($args[-1]) eq 'HASH');
753             # Back compat hack for applications with old (non Catalyst::Script) scripts to work in FCGI.
754             if (scalar @args && !ref($args[0])) {
755             if (my $listen = shift @args) {
756             $options->{listen} ||= [$listen];
757             }
758             }
759             if (! $server ) {
760             $server = Catalyst::EngineLoader->new(application_name => ref($self))->auto(%$options);
761             # We're not being called from a script, so auto detect what backend to
762             # run on. This should never happen, as mod_perl never calls ->run,
763             # instead the $app->handle method is called per request.
764 1     1 1 5 $app->log->warn("Not supplied a Plack engine, falling back to engine auto-loader (are your scripts ancient?)")
765             }
766             $app->run_options($options);
767             $server->run($psgi, $options);
768             }
769              
770             =head2 build_psgi_app ($app, @args)
771              
772             Builds and returns a PSGI application closure. (Raw, not wrapped in middleware)
773 1 50 33     8  
774 1 50 33     7 =cut
775              
776 1 50 33     6 my ($self, $app, @args) = @_;
777 0 0       0  
778 0   0     0 return sub {
779             my ($env) = @_;
780              
781 1 50       6 return sub {
782 0         0 my ($respond) = @_;
783             confess("Did not get a response callback for writer, cannot continue") unless $respond;
784             $app->handle_request(env => $env, response_cb => $respond);
785             };
786 0         0 };
787             }
788 1         6  
789 1         11 =head2 $self->unescape_uri($uri)
790              
791             Unescapes a given URI using the most efficient method available. Engines such
792             as Apache may implement this using Apache's C-based modules, for example.
793              
794             =cut
795              
796             my ( $self, $str ) = @_;
797              
798             $str =~ s/(?:%([0-9A-Fa-f]{2})|\+)/defined $1 ? chr(hex($1)) : ' '/eg;
799 133     133 1 532  
800             return $str;
801             }
802 923     923   4394  
803             =head2 $self->finalize_output
804              
805 923         126143 <obsolete>, see finalize_body
806 923 50       2490  
807 923         4935 =head2 $self->env
808 923         4433  
809 133         1058 Hash containing environment variables including many special variables inserted
810             by WWW server - like SERVER_*, REMOTE_*, HTTP_* ...
811              
812             Before accessing environment variables consider whether the same information is
813             not directly available via Catalyst objects $c->request, $c->engine ...
814              
815             BEWARE: If you really need to access some environment variable from your Catalyst
816             application you should use $c->engine->env->{VARNAME} instead of $ENV{VARNAME},
817             as in some environments the %ENV hash does not contain what you would expect.
818              
819             =head1 AUTHORS
820 283     283 1 527  
821             Catalyst Contributors, see Catalyst.pm
822 283 100       804  
  80         311  
823             =head1 COPYRIGHT
824 283         599  
825             This library is free software. You can redistribute it and/or modify it under
826             the same terms as Perl itself.
827              
828             =cut
829              
830             __PACKAGE__->meta->make_immutable;
831              
832             1;