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