update README.mkdn
[catagits/Catalyst-Runtime.git] / lib / Catalyst / Response.pm
CommitLineData
fc7ec1d9 1package Catalyst::Response;
2
059c085b 3use Moose;
6680c772 4use HTTP::Headers;
faa02805 5use Moose::Util::TypeConstraints;
b194746d 6use Scalar::Util 'blessed';
e8361cf8 7use Catalyst::Response::Writer;
6adc45cf 8use Catalyst::Utils ();
fc7ec1d9 9
eefc03e1 10use namespace::clean -except => ['meta'];
11
531f1ab6 12with 'MooseX::Emulate::Class::Accessor::Fast';
13
6adc45cf 14our $DEFAULT_ENCODE_CONTENT_TYPE_MATCH = qr{text|xml$|javascript$};
15
16has encodable_content_type => (
17 is => 'rw',
18 required => 1,
19 default => sub { $DEFAULT_ENCODE_CONTENT_TYPE_MATCH }
20);
21
faa02805 22has _response_cb => (
23 is => 'ro',
46fff667 24 isa => 'CodeRef',
faa02805 25 writer => '_set_response_cb',
26 clearer => '_clear_response_cb',
27 predicate => '_has_response_cb',
28);
29
30subtype 'Catalyst::Engine::Types::Writer',
31 as duck_type([qw(write close)]);
32
33has _writer => (
34 is => 'ro',
46fff667 35 isa => 'Catalyst::Engine::Types::Writer', #Pointless since we control how this is built
36 #writer => '_set_writer', Now that its lazy I think this is safe to remove
faa02805 37 clearer => '_clear_writer',
38 predicate => '_has_writer',
46fff667 39 lazy => 1,
40 builder => '_build_writer',
faa02805 41);
42
46fff667 43sub _build_writer {
44 my $self = shift;
45
46 ## These two lines are probably crap now...
47 $self->_context->finalize_headers unless
48 $self->finalized_headers;
49
50 my @headers;
51 $self->headers->scan(sub { push @headers, @_ });
52
53 my $writer = $self->_response_cb->([ $self->status, \@headers ]);
54 $self->_clear_response_cb;
55
56 return $writer;
57}
58
e37f92f5 59has write_fh => (
60 is=>'ro',
a3c9ab76 61 predicate=>'_has_write_fh',
eb1f4b49 62 lazy=>1,
1f2a8069 63 builder=>'_build_write_fh',
64);
65
e8361cf8 66sub _build_write_fh {
67 my $writer = $_[0]->_writer; # We need to get the finalize headers side effect...
6adc45cf 68 my $requires_encoding = $_[0]->encodable_response;
e8361cf8 69 my %fields = (
70 _writer => $writer,
688e2420 71 _context => $_[0]->_context,
e8361cf8 72 _requires_encoding => $requires_encoding,
73 );
74
75 return bless \%fields, 'Catalyst::Response::Writer';
76}
e37f92f5 77
78sub DEMOLISH {
79 my $self = shift;
a3c9ab76 80 return if $self->_has_write_fh;
e37f92f5 81 if($self->_has_writer) {
82 $self->_writer->close
83 }
84}
faa02805 85
6680c772 86has cookies => (is => 'rw', default => sub { {} });
ffb43803 87has body => (is => 'rw', default => undef);
88sub has_body { defined($_[0]->body) }
99a543ee 89
059c085b 90has location => (is => 'rw');
6680c772 91has status => (is => 'rw', default => 200);
92has finalized_headers => (is => 'rw', default => 0);
059c085b 93has headers => (
94 is => 'rw',
9c331634 95 isa => 'HTTP::Headers',
6adc45cf 96 handles => [qw(content_encoding content_length content_type content_type_charset header)],
6680c772 97 default => sub { HTTP::Headers->new() },
98 required => 1,
99 lazy => 1,
059c085b 100);
258733f1 101has _context => (
102 is => 'rw',
103 weak_ref => 1,
104 clearer => '_clear_context',
105);
fc7ec1d9 106
18adb1ed 107before [qw(status headers content_encoding content_length content_type )] => sub {
9ae060f0 108 my $self = shift;
109
18adb1ed 110 $self->_context->log->warn(
6adc45cf 111 "Useless setting a header value after finalize_headers and the response callback has been called." .
18adb1ed 112 " Since we don't support tail headers this will not work as you might expect." )
113 if ( $self->_context && $self->finalized_headers && !$self->_has_response_cb && @_ );
114};
115
116# This has to be different since the first param to ->header is the header name and presumably
117# you should be able to request the header even after finalization, just not try to change it.
118before 'header' => sub {
119 my $self = shift;
120 my $header = shift;
121
122 $self->_context->log->warn(
123 "Useless setting a header value after finalize_headers and the response callback has been called." .
124 " Since we don't support tail headers this will not work as you might expect." )
ca6d4ff6 125 if ( $self->_context && $self->finalized_headers && !$self->_has_response_cb && @_ );
9ae060f0 126};
127
059c085b 128sub output { shift->body(@_) }
129
aa9e8261 130sub code { shift->status(@_) }
131
9c4288ea 132sub write {
133 my ( $self, $buffer ) = @_;
134
135 # Finalize headers if someone manually writes output
89ba65d5 136 $self->_context->finalize_headers unless $self->finalized_headers;
9c4288ea 137
138 $buffer = q[] unless defined $buffer;
5c397774 139
6adc45cf 140 if($self->encodable_response) {
141 $buffer = $self->_context->encoding->encode( $buffer, $self->_context->_encode_check )
142 }
9c4288ea 143
144 my $len = length($buffer);
145 $self->_writer->write($buffer);
146
147 return $len;
148}
149
9c056c82 150sub unencoded_write {
151 my ( $self, $buffer ) = @_;
152
153 # Finalize headers if someone manually writes output
154 $self->_context->finalize_headers unless $self->finalized_headers;
155
156 $buffer = q[] unless defined $buffer;
157
158 my $len = length($buffer);
159 $self->_writer->write($buffer);
160
161 return $len;
162}
163
9c4288ea 164sub finalize_headers {
165 my ($self) = @_;
9c4288ea 166 return;
167}
168
e67f0874 169sub from_psgi_response {
170 my ($self, $psgi_res) = @_;
b194746d 171 if(blessed($psgi_res) && $psgi_res->can('as_psgi')) {
172 $psgi_res = $psgi_res->as_psgi;
173 }
e67f0874 174 if(ref $psgi_res eq 'ARRAY') {
175 my ($status, $headers, $body) = @$psgi_res;
176 $self->status($status);
4491e0cc 177 $self->headers(HTTP::Headers->new(@$headers));
67fd25bc 178 # Can be arrayref or filehandle...
179 if(defined $body) { # probably paranoia
180 ref $body eq 'ARRAY' ? $self->body(join('', @$body)) : $self->body($body);
181 }
e67f0874 182 } elsif(ref $psgi_res eq 'CODE') {
183 $psgi_res->(sub {
4491e0cc 184 my $response = shift;
185 my ($status, $headers, $maybe_body) = @$response;
e67f0874 186 $self->status($status);
4491e0cc 187 $self->headers(HTTP::Headers->new(@$headers));
8a3dcb98 188 if(defined $maybe_body) {
67fd25bc 189 # Can be arrayref or filehandle...
190 ref $maybe_body eq 'ARRAY' ? $self->body(join('', @$maybe_body)) : $self->body($maybe_body);
e67f0874 191 } else {
192 return $self->write_fh;
193 }
4491e0cc 194 });
195 } else {
e67f0874 196 die "You can't set a Catalyst response from that, expect a valid PSGI response";
197 }
d2000928 198
199 # Encoding compatibilty. If the response set a charset, well... we need
200 # to assume its properly encoded and NOT encode for this response. Otherwise
201 # We risk double encoding.
202 if($self->content_type_charset) {
51b34249 203 # We have to do this since for backcompat reasons having a charset doesn't always
204 # mean that the body is already encoded :(
d2000928 205 $self->_context->clear_encoding;
206 }
e67f0874 207}
208
fc7ec1d9 209=head1 NAME
210
910410b8 211Catalyst::Response - stores output responding to the current client request
fc7ec1d9 212
213=head1 SYNOPSIS
214
fbcc39ad 215 $res = $c->response;
216 $res->body;
aa9e8261 217 $res->code;
fbcc39ad 218 $res->content_encoding;
219 $res->content_length;
220 $res->content_type;
221 $res->cookies;
fbcc39ad 222 $res->header;
223 $res->headers;
224 $res->output;
225 $res->redirect;
226 $res->status;
227 $res->write;
b22c6668 228
fc7ec1d9 229=head1 DESCRIPTION
230
910410b8 231This is the Catalyst Response class, which provides methods for responding to
46372e65 232the current client request. The appropriate L<Catalyst::Engine> for your environment
233will turn the Catalyst::Response into a HTTP Response and return it to the client.
b22c6668 234
235=head1 METHODS
fc7ec1d9 236
08a2c908 237=head2 $res->body( $text | $fh | $iohandle_object )
e060fe05 238
239 $c->response->body('Catalyst rocks!');
06e1b616 240
46372e65 241Sets or returns the output (text or binary data). If you are returning a large body,
77b5811a 242you might want to use a L<IO::Handle> type of object (Something that implements the getline method
243in the same fashion), or a filehandle GLOB. These will be passed down to the PSGI
244handler you are using and might be optimized using server specific abilities (for
245example L<Twiggy> will attempt to server a real local file in a non blocking manner).
06e1b616 246
6adc45cf 247If you are using a filehandle as the body response you are responsible for
566678d0 248making sure it conforms to the L<PSGI> specification with regards to content
6adc45cf 249encoding. Unlike with scalar body values or when using the streaming interfaces
250we currently do not attempt to normalize and encode your filehandle. In general
251this means you should be sure to be sending bytes not UTF8 decoded multibyte
252characters.
253
254Most of the time when you do:
255
256 open(my $fh, '<:raw', $path);
257
258You should be fine. If you open a filehandle with a L<PerlIO> layer you probably
259are not fine. You can usually fix this by explicitly using binmode to set
260the IOLayer to :raw. Its possible future versions of L<Catalyst> will try to
261'do the right thing'.
262
490b7a80 263When using a L<IO::Handle> type of object and no content length has been
264already set in the response headers Catalyst will make a reasonable attempt
265to determine the size of the Handle. Depending on the implementation of your
266handle object, setting the content length may fail. If it is at all possible
267for you to determine the content length of your handle object,
4a178c0d 268it is recommended that you set the content length in the response headers
490b7a80 269yourself, which will be respected and sent by Catalyst in the response.
270
efeeb257 271Please note that the object needs to implement C<getline>, not just
77b5811a 272C<read>. Older versions of L<Catalyst> expected your filehandle like objects
273to do read. If you have code written for this expectation and you cannot
274change the code to meet the L<PSGI> specification, you can try the following
275middleware L<Plack::Middleware::AdaptFilehandleRead> which will attempt to
276wrap your object in an interface that so conforms.
efeeb257 277
278Starting from version 5.90060, when using an L<IO::Handle> object, you
279may want to use L<Plack::Middleware::XSendfile>, to delegate the
280actual serving to the frontend server. To do so, you need to pass to
281C<body> an IO object with a C<path> method. This can be achieved in
282two ways.
283
284Either using L<Plack::Util>:
285
286 my $fh = IO::File->new($file, 'r');
287 Plack::Util::set_io_path($fh, $file);
288
289Or using L<IO::File::WithPath>
290
291 my $fh = IO::File::WithPath->new($file, 'r');
292
293And then passing the filehandle to body and setting headers, if needed.
294
295 $c->response->body($fh);
296 $c->response->headers->content_type('text/plain');
297 $c->response->headers->content_length(-s $file);
298 $c->response->headers->last_modified((stat($file))[9]);
299
300L<Plack::Middleware::XSendfile> can be loaded in the application so:
301
302 __PACKAGE__->config(
303 psgi_middleware => [
304 'XSendfile',
305 # other middlewares here...
306 ],
307 );
308
309B<Beware> that loading the middleware without configuring the
310webserver to set the request header C<X-Sendfile-Type> to a supported
311type (C<X-Accel-Redirect> for nginx, C<X-Sendfile> for Apache and
312Lighttpd), could lead to the disclosure of private paths to malicious
313clients setting that header.
314
315Nginx needs the additional X-Accel-Mapping header to be set in the
316webserver configuration, so the middleware will replace the absolute
317path of the IO object with the internal nginx path. This is also
318useful to prevent a buggy app to server random files from the
319filesystem, as it's an internal redirect.
320
321An nginx configuration for FastCGI could look so:
322
323 server {
324 server_name example.com;
325 root /my/app/root;
326 location /private/repo/ {
327 internal;
328 alias /my/app/repo/;
329 }
330 location /private/staging/ {
331 internal;
332 alias /my/app/staging/;
333 }
334 location @proxy {
335 include /etc/nginx/fastcgi_params;
336 fastcgi_param SCRIPT_NAME '';
337 fastcgi_param PATH_INFO $fastcgi_script_name;
338 fastcgi_param HTTP_X_SENDFILE_TYPE X-Accel-Redirect;
339 fastcgi_param HTTP_X_ACCEL_MAPPING /my/app=/private;
340 fastcgi_pass unix:/my/app/run/app.sock;
341 }
342 }
343
344In the example above, passing filehandles with a local path matching
345/my/app/staging or /my/app/repo will be served by nginx. Passing paths
346with other locations will lead to an internal server error.
347
348Setting the body to a filehandle without the C<path> method bypasses
349the middleware completely.
350
351For Apache and Lighttpd, the mapping doesn't apply and setting the
352X-Sendfile-Type is enough.
353
02570318 354=head2 $res->has_body
355
356Predicate which returns true when a body has been set.
357
aa9e8261 358=head2 $res->code
359
360Alias for $res->status.
361
b5ecfcf0 362=head2 $res->content_encoding
b5176d9e 363
910410b8 364Shortcut for $res->headers->content_encoding.
b5176d9e 365
b5ecfcf0 366=head2 $res->content_length
b5176d9e 367
910410b8 368Shortcut for $res->headers->content_length.
b5176d9e 369
b5ecfcf0 370=head2 $res->content_type
b5176d9e 371
910410b8 372Shortcut for $res->headers->content_type.
b5176d9e 373
87e9f9ab 374This value is typically set by your view or plugin. For example,
375L<Catalyst::Plugin::Static::Simple> will guess the mime type based on the file
376it found, while L<Catalyst::View::TT> defaults to C<text/html>.
377
6adc45cf 378=head2 $res->content_type_charset
379
380Shortcut for $res->headers->content_type_charset;
381
b5ecfcf0 382=head2 $res->cookies
fc7ec1d9 383
910410b8 384Returns a reference to a hash containing cookies to be set. The keys of the
385hash are the cookies' names, and their corresponding values are hash
7e743798 386references used to construct a L<CGI::Simple::Cookie> object.
fc7ec1d9 387
388 $c->response->cookies->{foo} = { value => '123' };
389
7e743798 390The keys of the hash reference on the right correspond to the L<CGI::Simple::Cookie>
910410b8 391parameters of the same name, except they are used without a leading dash.
392Possible parameters are:
ac965e92 393
b0ad47c1 394=over
ac965e92 395
71453caf 396=item value
ac965e92 397
71453caf 398=item expires
ac965e92 399
71453caf 400=item domain
ac965e92 401
71453caf 402=item path
403
404=item secure
405
b21bc468 406=item httponly
407
71453caf 408=back
ac965e92 409
b5ecfcf0 410=head2 $res->header
fbcc39ad 411
910410b8 412Shortcut for $res->headers->header.
fbcc39ad 413
b5ecfcf0 414=head2 $res->headers
fc7ec1d9 415
910410b8 416Returns an L<HTTP::Headers> object, which can be used to set headers.
fc7ec1d9 417
418 $c->response->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
419
b5ecfcf0 420=head2 $res->output
fc7ec1d9 421
910410b8 422Alias for $res->body.
fc7ec1d9 423
b5ecfcf0 424=head2 $res->redirect( $url, $status )
fc7ec1d9 425
2f381252 426Causes the response to redirect to the specified URL. The default status is
427C<302>.
fc7ec1d9 428
73a52566 429 $c->response->redirect( 'http://slashdot.org' );
430 $c->response->redirect( 'http://slashdot.org', 307 );
431
2f381252 432This is a convenience method that sets the Location header to the
433redirect destination, and then sets the response status. You will
ee24f3a8 434want to C< return > or C<< $c->detach() >> to interrupt the normal
2f381252 435processing flow if you want the redirect to occur straight away.
436
824a5eb0 437B<Note:> do not give a relative URL as $url, i.e: one that is not fully
438qualified (= C<http://...>, etc.) or that starts with a slash
439(= C</path/here>). While it may work, it is not guaranteed to do the right
440thing and is not a standard behaviour. You may opt to use uri_for() or
441uri_for_action() instead.
442
00038a21 443B<Note:> If $url is an object that does ->as_string (such as L<URI>, which is
444what you get from ->uri_for) we automatically call that to stringify. This
445should ease the common case usage
446
447 return $c->res->redirect( $c->uri_for(...));
448
73a52566 449=cut
450
451sub redirect {
452 my $self = shift;
fbcc39ad 453
454 if (@_) {
73a52566 455 my $location = shift;
f1bbebac 456 my $status = shift || 302;
73a52566 457
00038a21 458 if(blessed($location) && $location->can('as_string')) {
459 $location = $location->as_string;
460 }
461
73a52566 462 $self->location($location);
463 $self->status($status);
464 }
465
466 return $self->location;
467}
fc7ec1d9 468
059c085b 469=head2 $res->location
470
471Sets or returns the HTTP 'Location'.
472
b5ecfcf0 473=head2 $res->status
fc7ec1d9 474
910410b8 475Sets or returns the HTTP status.
fc7ec1d9 476
477 $c->response->status(404);
aa9e8261 478
479$res->code is an alias for this, to match HTTP::Response->code.
b0ad47c1 480
b5ecfcf0 481=head2 $res->write( $data )
fbcc39ad 482
dd096a3a 483Writes $data to the output stream. Calling this method will finalize your
484headers and send the headers and status code response to the client (so changing
485them afterwards is a waste... be sure to set your headers correctly first).
486
487You may call this as often as you want throughout your response cycle. You may
488even set a 'body' afterward. So for example you might write your HTTP headers
489and the HEAD section of your document and then set the body from a template
490driven from a database. In some cases this can seem to the client as if you had
491a faster overall response (but note that unless your server support chunked
492body your content is likely to get queued anyway (L<Starman> and most other
493http 1.1 webservers support this).
494
495If there is an encoding set, we encode each line of the response (the default
496encoding is UTF-8).
fbcc39ad 497
e5ac67e5 498=head2 $res->unencoded_write( $data )
499
500Works just like ->write but we don't apply any content encoding to C<$data>. Use
501this if you are already encoding the $data or the data is arriving from an encoded
502storage.
503
e37f92f5 504=head2 $res->write_fh
505
e8361cf8 506Returns an instance of L<Catalyst::Response::Writer>, which is a lightweight
507decorator over the PSGI C<$writer> object (see L<PSGI.pod\Delayed-Response-and-Streaming-Body>).
508
509In addition to proxying the C<write> and C<close> method from the underlying PSGI
510writer, this proxy object knows any application wide encoding, and provides a method
511C<write_encoded> that will properly encode your written lines based upon your
512encoding settings. By default in L<Catalyst> responses are UTF-8 encoded and this
513is the encoding used if you respond via C<write_encoded>. If you want to handle
514encoding yourself, you can use the C<write> method directly.
515
516Encoding only applies to content types for which it matters. Currently the following
517content types are assumed to need encoding: text (including HTML), xml and javascript.
518
519We provide access to this object so that you can properly close over it for use in
520asynchronous and nonblocking applications. For example (assuming you are using a supporting
521server, like L<Twiggy>:
e37f92f5 522
523 package AsyncExample::Controller::Root;
524
525 use Moose;
526
527 BEGIN { extends 'Catalyst::Controller' }
528
529 sub prepare_cb {
530 my $write_fh = pop;
531 return sub {
532 my $message = shift;
533 $write_fh->write("Finishing: $message\n");
534 $write_fh->close;
535 };
536 }
537
538 sub anyevent :Local :Args(0) {
539 my ($self, $c) = @_;
540 my $cb = $self->prepare_cb($c->res->write_fh);
541
542 my $watcher;
543 $watcher = AnyEvent->timer(
544 after => 5,
545 cb => sub {
546 $cb->(scalar localtime);
547 undef $watcher; # cancel circular-ref
548 });
549 }
550
dd096a3a 551Like the 'write' method, calling this will finalize headers. Unlike 'write' when you
552can this it is assumed you are taking control of the response so the body is never
553finalized (there isn't one anyway) and you need to call the close method.
554
e4cc83b2 555=head2 $res->print( @data )
556
557Prints @data to the output stream, separated by $,. This lets you pass
558the response object to functions that want to write to an L<IO::Handle>.
559
e7ea7308 560=head2 $res->finalize_headers()
8738b8fe 561
562Writes headers to response if not already written
563
e67f0874 564=head2 from_psgi_response
565
566Given a PSGI response (either three element ARRAY reference OR coderef expecting
567a $responder) set the response from it.
568
569Properly supports streaming and delayed response and / or async IO if running
570under an expected event loop.
571
b194746d 572If passed an object, will expect that object to do a method C<as_psgi>.
573
e67f0874 574Example:
575
576 package MyApp::Web::Controller::Test;
577
578 use base 'Catalyst::Controller';
579 use Plack::App::Directory;
580
581
582 my $app = Plack::App::Directory->new({ root => "/path/to/htdocs" })
583 ->to_app;
584
585 sub myaction :Local Args {
586 my ($self, $c) = @_;
faa1bcff 587 $c->res->from_psgi_response($app->($c->req->env));
e67f0874 588 }
589
590Please note this does not attempt to map or nest your PSGI application under
aca337aa 591the Controller and Action namespace or path. You may wish to review 'PSGI Helpers'
592under L<Catalyst::Utils> for help in properly nesting applications.
593
594B<NOTE> If your external PSGI application returns a response that has a character
595set associated with the content type (such as "text/html; charset=UTF-8") we set
596$c->clear_encoding to remove any additional content type encoding processing later
597in the application (this is done to avoid double encoding issues).
e67f0874 598
6adc45cf 599=head2 encodable_content_type
600
601This is a regular expression used to determine of the current content type
602should be considered encodable. Currently we apply default encoding (usually
603UTF8) to text type contents. Here's the default regular expression:
604
605This would match content types like:
606
607 text/plain
608 text/html
609 text/xml
610 application/javascript
611 application/xml
612 application/vnd.user+xml
613
614B<NOTE>: We don't encode JSON content type responses by default since most
615of the JSON serializers that are commonly used for this task will do so
616automatically and we don't want to double encode. If you are not using a
617tool like L<JSON> to produce JSON type content, (for example you are using
618a template system, or creating the strings manually) you will need to either
619encoding the body yourself:
620
621 $c->response->body( $c->encoding->encode( $body, $c->_encode_check ) );
622
623Or you can alter the regular expression using this attribute.
624
625=head2 encodable_response
626
627Given a L<Catalyst::Response> return true if its one that can be encoded.
628
629 make sure there is an encoding set on the response
630 make sure the content type is encodable
631 make sure no content type charset has been already set to something different from the global encoding
632 make sure no content encoding is present.
633
634Note this does not inspect a body since we do allow automatic encoding on streaming
635type responses.
636
637=cut
638
639sub encodable_response {
640 my ($self) = @_;
641 return 0 unless $self->_context; # Cases like returning a HTTP Exception response you don't have a context here...
642 return 0 unless $self->_context->encoding;
643
d2000928 644 # The response is considered to have a 'manual charset' when a charset is already set on
645 # the content type of the response AND it is not the same as the one we set in encoding.
646 # If there is no charset OR we are asking for the one which is the same as the current
647 # required encoding, that is a flag that we want Catalyst to encode the response automatically.
6adc45cf 648 my $has_manual_charset = 0;
649 if(my $charset = $self->content_type_charset) {
650 $has_manual_charset = (uc($charset) ne uc($self->_context->encoding->mime_name)) ? 1:0;
651 }
652
d2000928 653 # Content type is encodable if it matches the regular expression stored in this attribute
654 my $encodable_content_type = $self->content_type =~ m/${\$self->encodable_content_type}/ ? 1:0;
655
656 # The content encoding is allowed (for charset encoding) only if its empty or is set to identity
657 my $allowed_content_encoding = (!$self->content_encoding || $self->content_encoding eq 'identity') ? 1:0;
658
659 # The content type must be an encodable type, and there must be NO manual charset and also
660 # the content encoding must be the allowed values;
6adc45cf 661 if(
d2000928 662 $encodable_content_type and
663 !$has_manual_charset and
664 $allowed_content_encoding
665 ) {
6adc45cf 666 return 1;
667 } else {
668 return 0;
669 }
670}
671
faa02805 672=head2 DEMOLISH
673
674Ensures that the response is flushed and closed at the end of the
675request.
676
677=head2 meta
678
679Provided by Moose
680
e4cc83b2 681=cut
682
683sub print {
684 my $self = shift;
685 my $data = shift;
686
687 defined $self->write($data) or return;
688
689 for (@_) {
690 defined $self->write($,) or return;
691 defined $self->write($_) or return;
692 }
fe3083a8 693 defined $self->write($\) or return;
b0ad47c1 694
e4cc83b2 695 return 1;
696}
697
910410b8 698=head1 AUTHORS
fc7ec1d9 699
2f381252 700Catalyst Contributors, see Catalyst.pm
fc7ec1d9 701
702=head1 COPYRIGHT
703
b0ad47c1 704This library is free software. You can redistribute it and/or modify
61b1e958 705it under the same terms as Perl itself.
fc7ec1d9 706
707=cut
708
e5ecd5bc 709__PACKAGE__->meta->make_immutable;
710
fc7ec1d9 7111;