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