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 156     156   191800 with 'MooseX::Emulate::Class::Accessor::Fast';
  156         383373  
  156         3142  
4              
5             use CGI::Simple::Cookie;
6 156     156   1133039 use Data::Dump qw/dump/;
  156         797637  
  156         5087  
7 156     156   4685 use Errno 'EWOULDBLOCK';
  156         15354  
  156         9929  
8 156     156   1560 use HTML::Entities;
  156         1547  
  156         24656  
9 156     156   2665 use HTTP::Headers;
  156         17132  
  156         14811  
10 156     156   1601 use Plack::Loader;
  156         6931  
  156         4571  
11 156     156   2201 use Catalyst::EngineLoader;
  156         17752  
  156         4320  
12 156     156   2297 use Encode 2.21 'decode_utf8', 'encode', 'decode';
  156         382  
  156         6737  
13 156     156   2372 use Plack::Request::Upload;
  156         31729  
  156         10285  
14 156     156   2482 use Hash::MultiValue;
  156         1808  
  156         4967  
15 156     156   2317 use namespace::clean -except => 'meta';
  156         7632  
  156         5929  
16 156     156   1006 use utf8;
  156         392  
  156         1814  
17 156     156   76907  
  156         473  
  156         1496  
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 920     920 1 2841 ## If we've asked for the write 'filehandle' that means the application is
69 920         23622 ## 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 920 100       30460 if($res->_has_response_cb) {
74             ## we have not called the response callback yet, so we are safe to send
75 915         23894 ## the whole body to PSGI
76 915 100       30739  
77             my @headers;
78             $res->headers->scan(sub { push @headers, @_ });
79              
80 903         2055 # We need to figure out what kind of body we have and normalize it to something
81 903     5924   3347 # PSGI can deal with
  5924         83105  
82             if(defined $body) {
83             # Handle objects first
84             if(blessed($body)) {
85 903 100       9165 if($body->can('getline')) {
86             # Body is an IO handle that meets the PSGI spec. Nothing to normalize
87 862 100       4550 } elsif($body->can('read')) {
    100          
88 12 100       235  
    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         57 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     43 # 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 844         2650 # There's no body...
128             $body = [];
129             }
130             $res->_response_cb->([ $res->status, \@headers, $body]);
131 41         112 $res->_clear_response_cb;
132              
133 903         4387 } else {
134 903         680152 ## 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       331  
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         18  
167             $res->_writer->close;
168             $res->_clear_writer;
169             }
170 12         319  
171 12         6388 return;
172             }
173              
174 915         3794 =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 920     920 1 2972  
186             foreach my $name (keys %{ $response->cookies }) {
187 920         1860  
188 920         23636 my $val = $response->cookies->{$name};
189              
190 920         2171 my $cookie = (
  920         25764  
191             blessed($val)
192 8         596 ? $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     148 next;
      50        
208 8 100       1385 }
209 1 50       6  
210             push @cookies, $cookie->as_string;
211 1         3 }
212              
213             for my $cookie (@cookies) {
214 7         28 $response->headers->push_header( 'Set-Cookie' => $cookie );
215             }
216             }
217 920         3890  
218 7         141 =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   1686 local $val->{'__MOP__'} = "Stringified: "
232 31         47 . $val->{'__MOP__'} if ref $val eq 'HASH' && exists $val->{'__MOP__'};
  31         69  
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     163 <div id="dump_$i">
238             <pre wrap="">%s</pre>
239 31         110 </div>
240 31         57960 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 125 # 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         150  
252 34   66     1064 if ($c->can('encoding')) {
253             $c->{encoding} = '';
254             }
255              
256             my ( $title, $error, $infos );
257             if ( $c->debug ) {
258 34 50       225  
259 34         166 # For pretty dumps
260             $error = join '', map {
261             '<p><code class="error">'
262 34         96 . encode_entities($_)
263 34 100       175 . '</code></p>'
264             } @{ $c->error };
265             $error ||= 'No output';
266             $error = qq{<pre wrap="">$error</pre>};
267 9         78 $title = $name = "$name on Catalyst $Catalyst::VERSION";
268             $name = "<h1>$name</h1>";
269              
270 7         33 # Don't show context in the dump
  7         23  
271 7   50     194 $c->res->_clear_context;
272 7         28  
273 7         23 # Don't show body parser in the dump
274 7         21 $c->req->_clear_body;
275              
276             my @infos;
277 7         22 my $i = 0;
278             for my $dump ( $c->dump_these ) {
279             push @infos, $self->_dump_error_page_element($i, $dump);
280 7         27 $i++;
281             }
282 7         11 $infos = join "\n", @infos;
283 7         17 }
284 7         29 else {
285 28         105 $title = $name;
286 28         72 $error = '';
287             $infos = <<"";
288 7         103 <pre>
289             (en) Please come back later
290             (fr) SVP veuillez revenir plus tard
291 27         67 (de) Bitte versuchen sie es spaeter nocheinmal
292 27         77 (at) Konnten's bitt'schoen spaeter nochmal reinschauen
293 27         131 (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         81 <head>
309             <meta http-equiv="Content-Language" content="en" />
310 34         171 <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         156 }
412              
413 34         200 =head2 $self->finalize_headers($c)
414              
415             Allows engines to write headers to response
416 34         178  
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 920     920 1 2796 (ref $upload eq 'ARRAY' ? @{$upload} : ($upload));
440             }
441              
442             }
443 920         23832  
444 920         2100 =head2 $self->prepare_body($c)
  920         26650  
445 18         532  
446 20         1678 sets up the L<Catalyst::Request> object body using L<HTTP::Body>
  20         603  
447 18 100       91  
  1         12  
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 922     922 1 2724 =cut
460              
461 922         23214 # 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 921     921 1 2855 my ($self, $ctx) = @_;
499              
500 921         23709 my $env = $ctx->request->env;
501 921         20553  
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 933     933 1 3222 if ( exists $env->{REDIRECT_URL} ) {
512             $base_path = $env->{REDIRECT_URL};
513 933         24570 $base_path =~ s/\Q$path_info\E$//;
514             }
515 933 100       21260 $path = $base_path . $path_info;
516 933   100     3915 $path =~ s{^/+}{};
517 933   100     3365 $path =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go;
518 933   100     4881 $path =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE
519             }
520             else {
521 933         1887 my $req_uri = $env->{REQUEST_URI};
522 933 100       3678 $req_uri =~ s/\?.*$//;
523 318         872 $path = $req_uri;
524 318 100       1111 $path =~ s{^/+}{};
525 3         6 }
526 3         65  
527             # Using URI directly is way too slow, so we construct the URLs manually
528 318         742 my $uri_class = "URI::$scheme";
529 318         1642  
530 318         2908 # HTTP_HOST will include the port even if it's 80/443
531 318         941 $host =~ s/:(?:80|443)$//;
532              
533             if ($port !~ /^(?:80|443)$/ && $host !~ /:/) {
534 615         1732 $host .= ":$port";
535 615         2015 }
536 615         1528  
537 615         3400 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 933         3175  
542             # set the base URI
543             # base must end in a slash
544 933         2479 $base_path .= '/' unless $base_path =~ m{/$};
545              
546 933 0 33     5532 my $base_uri = $scheme . '://' . $host . $base_path;
547 0         0  
548             $ctx->request->base( bless \$base_uri, $uri_class );
549              
550 933 100       3517 return;
551 933         3790 }
552              
553 933         26463 =head2 $self->prepare_request($c)
554              
555             =head2 $self->prepare_query_parameters($c)
556              
557 933 100       4752 process the query string and extract query parameters.
558              
559 933         3598 =cut
560              
561 933         22807 my ($self, $c) = @_;
562             my $env = $c->request->env;
563 933         3293 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 925     925 1 3154 return $c->_handle_param_unicode_decoding($str, $check);
576 925         24609 };
577 925         3696  
578             my $query_string = exists $env->{QUERY_STRING}
579 925         2106 ? $env->{QUERY_STRING}
580 925 100       3075 : '';
581 1         7  
582 1         3 $query_string =~ s/\A[&;]+//;
583              
584             my @unsplit_pairs = split /[&;]+/, $query_string;
585 925 50       3081 my $p = Hash::MultiValue->new();
586              
587 283     283   493 my $is_first_pair = 1;
588 283 50       591 for my $pair (@unsplit_pairs) {
589 283         890 my ($name, $value)
590 925         6364 = map { defined $_ ? $decoder->($self->unescape_uri($_)) : $_ }
591             ( split /=/, $pair, 2 )[0,1]; # slice forces two elements
592              
593             if ($is_first_pair) {
594 925 100       4026 # If the first pair has no equal sign, then it means the isindex
595             # flag is set.
596 925         2447 $c->request->query_keywords($name) unless defined $value;
597              
598 925         3661 $is_first_pair = 0;
599 925         8429 }
600              
601 925         42633 $p->add( $name => $value );
602 925         2878 }
603              
604 144 100       2540  
  288         3550  
605             $c->encoding($old_encoding) if $old_encoding;
606             $c->request->query_parameters( $c->request->_use_hash_multivalue ? $p : $p->mixed );
607 143 100       2522 }
608              
609             =head2 $self->prepare_read($c)
610 84 100       396  
611             Prepare to read by initializing the Content-Length from headers.
612 84         174  
613             =cut
614              
615 143         544 my ( $self, $c ) = @_;
616              
617             # Initialize the amount of data we think we need to read
618             $c->request->_read_length;
619 924 100       5923 }
620 924 100       27955  
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 924     924 1 2978 $self->_set_env($args{env}); # Nasty back compat!
631             $ctx->response->_set_response_cb($args{response_cb});
632             }
633 924         24258  
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 934     934 1 4696 my $enc = $c->encoding;
644 934 100       3488 my $uploads = $request->_body->upload;
645 934         25097 my $parameters = $request->parameters;
646 934         28691 foreach my $name (keys %$uploads) {
647 934         23518 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 920     920 1 2773 my $u = Catalyst::Request::Upload->new
656             (
657 920         23452 size => $upload->{size},
658 920 100       24434 type => scalar $headers->content_type,
659             charset => scalar $headers->content_type_charset,
660 46         170 headers => $headers,
661 46         1289 tempname => $upload->{tempname},
662 46         405 filename => $filename,
663 46         231 );
664 18         43 push @uploads, $u;
665 18 50       90 }
666 18         395 $request->uploads->{$name} = @uploads > 1 ? \@uploads : $uploads[0];
667 18 100       89  
668 20         43 # support access to the filename as a normal param
  20         134  
669 20         1934 my @filenames = map { $_->{filename} } @uploads;
670 20 50       103 # 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         437 else {
680             $parameters->{$name} = @filenames > 1 ? \@filenames : $filenames[0];
681 20         82 }
682             }
683 18 100       532 }
684              
685             =head2 $self->write($c, $buffer)
686 18         50  
  20         75  
687             Writes the buffer to the client.
688 18 100       62  
689 2 50       11 =cut
690 0         0  
  0         0  
691             my ( $self, $c, $buffer ) = @_;
692              
693 2         30 $c->response->write($buffer);
694             }
695              
696             =head2 $self->unencoded_write($c, $buffer)
697 16 100       95  
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 9  
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 6 $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     31  
774 1 50 33     9 =cut
775              
776 1 50 33     7 my ($self, $app, @args) = @_;
777 0 0       0  
778 0   0     0 return sub {
779             my ($env) = @_;
780              
781 1 50       9 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         7  
789 1         5 =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 134     134 1 560  
800             return $str;
801             }
802 925     925   6142  
803             =head2 $self->finalize_output
804              
805 925         159379 <obsolete>, see finalize_body
806 925 50       3115  
807 925         5867 =head2 $self->env
808 925         5578  
809 134         1211 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 610  
821             Catalyst Contributors, see Catalyst.pm
822 283 100       930  
  80         330  
823             =head1 COPYRIGHT
824 283         712  
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;