abort on error defaults to true
[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;
fc7ec1d9 7
531f1ab6 8with 'MooseX::Emulate::Class::Accessor::Fast';
9
faa02805 10has _response_cb => (
11 is => 'ro',
46fff667 12 isa => 'CodeRef',
faa02805 13 writer => '_set_response_cb',
14 clearer => '_clear_response_cb',
15 predicate => '_has_response_cb',
16);
17
18subtype 'Catalyst::Engine::Types::Writer',
19 as duck_type([qw(write close)]);
20
21has _writer => (
22 is => 'ro',
46fff667 23 isa => 'Catalyst::Engine::Types::Writer', #Pointless since we control how this is built
24 #writer => '_set_writer', Now that its lazy I think this is safe to remove
faa02805 25 clearer => '_clear_writer',
26 predicate => '_has_writer',
46fff667 27 lazy => 1,
28 builder => '_build_writer',
faa02805 29);
30
46fff667 31sub _build_writer {
32 my $self = shift;
33
34 ## These two lines are probably crap now...
35 $self->_context->finalize_headers unless
36 $self->finalized_headers;
37
38 my @headers;
39 $self->headers->scan(sub { push @headers, @_ });
40
41 my $writer = $self->_response_cb->([ $self->status, \@headers ]);
42 $self->_clear_response_cb;
43
44 return $writer;
45}
46
e37f92f5 47has write_fh => (
48 is=>'ro',
a3c9ab76 49 predicate=>'_has_write_fh',
eb1f4b49 50 lazy=>1,
1f2a8069 51 builder=>'_build_write_fh',
52);
53
46fff667 54sub _build_write_fh { shift ->_writer }
e37f92f5 55
56sub DEMOLISH {
57 my $self = shift;
a3c9ab76 58 return if $self->_has_write_fh;
e37f92f5 59 if($self->_has_writer) {
60 $self->_writer->close
61 }
62}
faa02805 63
6680c772 64has cookies => (is => 'rw', default => sub { {} });
ffb43803 65has body => (is => 'rw', default => undef);
66sub has_body { defined($_[0]->body) }
99a543ee 67
059c085b 68has location => (is => 'rw');
6680c772 69has status => (is => 'rw', default => 200);
70has finalized_headers => (is => 'rw', default => 0);
059c085b 71has headers => (
72 is => 'rw',
9c331634 73 isa => 'HTTP::Headers',
059c085b 74 handles => [qw(content_encoding content_length content_type header)],
6680c772 75 default => sub { HTTP::Headers->new() },
76 required => 1,
77 lazy => 1,
059c085b 78);
258733f1 79has _context => (
80 is => 'rw',
81 weak_ref => 1,
82 clearer => '_clear_context',
83);
fc7ec1d9 84
9ae060f0 85before [qw(status headers content_encoding content_length content_type header)] => sub {
86 my $self = shift;
87
88 $self->_context->log->warn(
89 "Useless setting a header value after finalize_headers called." .
90 " Not what you want." )
91 if ( $self->finalized_headers && @_ );
92};
93
059c085b 94sub output { shift->body(@_) }
95
aa9e8261 96sub code { shift->status(@_) }
97
9c4288ea 98sub write {
99 my ( $self, $buffer ) = @_;
100
101 # Finalize headers if someone manually writes output
89ba65d5 102 $self->_context->finalize_headers unless $self->finalized_headers;
9c4288ea 103
104 $buffer = q[] unless defined $buffer;
105
106 my $len = length($buffer);
107 $self->_writer->write($buffer);
108
109 return $len;
110}
111
9c4288ea 112sub finalize_headers {
113 my ($self) = @_;
9c4288ea 114 return;
115}
116
e67f0874 117sub from_psgi_response {
118 my ($self, $psgi_res) = @_;
119 if(ref $psgi_res eq 'ARRAY') {
120 my ($status, $headers, $body) = @$psgi_res;
121 $self->status($status);
4491e0cc 122 $self->headers(HTTP::Headers->new(@$headers));
8a3dcb98 123 $self->body($body);
e67f0874 124 } elsif(ref $psgi_res eq 'CODE') {
125 $psgi_res->(sub {
4491e0cc 126 my $response = shift;
127 my ($status, $headers, $maybe_body) = @$response;
e67f0874 128 $self->status($status);
4491e0cc 129 $self->headers(HTTP::Headers->new(@$headers));
8a3dcb98 130 if(defined $maybe_body) {
131 $self->body($maybe_body);
e67f0874 132 } else {
133 return $self->write_fh;
134 }
4491e0cc 135 });
136 } else {
e67f0874 137 die "You can't set a Catalyst response from that, expect a valid PSGI response";
138 }
139}
140
fc7ec1d9 141=head1 NAME
142
910410b8 143Catalyst::Response - stores output responding to the current client request
fc7ec1d9 144
145=head1 SYNOPSIS
146
fbcc39ad 147 $res = $c->response;
148 $res->body;
aa9e8261 149 $res->code;
fbcc39ad 150 $res->content_encoding;
151 $res->content_length;
152 $res->content_type;
153 $res->cookies;
fbcc39ad 154 $res->header;
155 $res->headers;
156 $res->output;
157 $res->redirect;
158 $res->status;
159 $res->write;
b22c6668 160
fc7ec1d9 161=head1 DESCRIPTION
162
910410b8 163This is the Catalyst Response class, which provides methods for responding to
46372e65 164the current client request. The appropriate L<Catalyst::Engine> for your environment
165will turn the Catalyst::Response into a HTTP Response and return it to the client.
b22c6668 166
167=head1 METHODS
fc7ec1d9 168
08a2c908 169=head2 $res->body( $text | $fh | $iohandle_object )
e060fe05 170
171 $c->response->body('Catalyst rocks!');
06e1b616 172
46372e65 173Sets or returns the output (text or binary data). If you are returning a large body,
2f381252 174you might want to use a L<IO::Handle> type of object (Something that implements the read method
46372e65 175in the same fashion), or a filehandle GLOB. Catalyst
176will write it piece by piece into the response.
06e1b616 177
490b7a80 178When using a L<IO::Handle> type of object and no content length has been
179already set in the response headers Catalyst will make a reasonable attempt
180to determine the size of the Handle. Depending on the implementation of your
181handle object, setting the content length may fail. If it is at all possible
182for you to determine the content length of your handle object,
4a178c0d 183it is recommended that you set the content length in the response headers
490b7a80 184yourself, which will be respected and sent by Catalyst in the response.
185
02570318 186=head2 $res->has_body
187
188Predicate which returns true when a body has been set.
189
aa9e8261 190=head2 $res->code
191
192Alias for $res->status.
193
b5ecfcf0 194=head2 $res->content_encoding
b5176d9e 195
910410b8 196Shortcut for $res->headers->content_encoding.
b5176d9e 197
b5ecfcf0 198=head2 $res->content_length
b5176d9e 199
910410b8 200Shortcut for $res->headers->content_length.
b5176d9e 201
b5ecfcf0 202=head2 $res->content_type
b5176d9e 203
910410b8 204Shortcut for $res->headers->content_type.
b5176d9e 205
87e9f9ab 206This value is typically set by your view or plugin. For example,
207L<Catalyst::Plugin::Static::Simple> will guess the mime type based on the file
208it found, while L<Catalyst::View::TT> defaults to C<text/html>.
209
b5ecfcf0 210=head2 $res->cookies
fc7ec1d9 211
910410b8 212Returns a reference to a hash containing cookies to be set. The keys of the
213hash are the cookies' names, and their corresponding values are hash
7e743798 214references used to construct a L<CGI::Simple::Cookie> object.
fc7ec1d9 215
216 $c->response->cookies->{foo} = { value => '123' };
217
7e743798 218The keys of the hash reference on the right correspond to the L<CGI::Simple::Cookie>
910410b8 219parameters of the same name, except they are used without a leading dash.
220Possible parameters are:
ac965e92 221
b0ad47c1 222=over
ac965e92 223
71453caf 224=item value
ac965e92 225
71453caf 226=item expires
ac965e92 227
71453caf 228=item domain
ac965e92 229
71453caf 230=item path
231
232=item secure
233
b21bc468 234=item httponly
235
71453caf 236=back
ac965e92 237
b5ecfcf0 238=head2 $res->header
fbcc39ad 239
910410b8 240Shortcut for $res->headers->header.
fbcc39ad 241
b5ecfcf0 242=head2 $res->headers
fc7ec1d9 243
910410b8 244Returns an L<HTTP::Headers> object, which can be used to set headers.
fc7ec1d9 245
246 $c->response->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
247
b5ecfcf0 248=head2 $res->output
fc7ec1d9 249
910410b8 250Alias for $res->body.
fc7ec1d9 251
b5ecfcf0 252=head2 $res->redirect( $url, $status )
fc7ec1d9 253
2f381252 254Causes the response to redirect to the specified URL. The default status is
255C<302>.
fc7ec1d9 256
73a52566 257 $c->response->redirect( 'http://slashdot.org' );
258 $c->response->redirect( 'http://slashdot.org', 307 );
259
2f381252 260This is a convenience method that sets the Location header to the
261redirect destination, and then sets the response status. You will
ee24f3a8 262want to C< return > or C<< $c->detach() >> to interrupt the normal
2f381252 263processing flow if you want the redirect to occur straight away.
264
824a5eb0 265B<Note:> do not give a relative URL as $url, i.e: one that is not fully
266qualified (= C<http://...>, etc.) or that starts with a slash
267(= C</path/here>). While it may work, it is not guaranteed to do the right
268thing and is not a standard behaviour. You may opt to use uri_for() or
269uri_for_action() instead.
270
73a52566 271=cut
272
273sub redirect {
274 my $self = shift;
fbcc39ad 275
276 if (@_) {
73a52566 277 my $location = shift;
f1bbebac 278 my $status = shift || 302;
73a52566 279
280 $self->location($location);
281 $self->status($status);
282 }
283
284 return $self->location;
285}
fc7ec1d9 286
059c085b 287=head2 $res->location
288
289Sets or returns the HTTP 'Location'.
290
b5ecfcf0 291=head2 $res->status
fc7ec1d9 292
910410b8 293Sets or returns the HTTP status.
fc7ec1d9 294
295 $c->response->status(404);
aa9e8261 296
297$res->code is an alias for this, to match HTTP::Response->code.
b0ad47c1 298
b5ecfcf0 299=head2 $res->write( $data )
fbcc39ad 300
301Writes $data to the output stream.
302
e37f92f5 303=head2 $res->write_fh
304
305Returns a PSGI $writer object that has two methods, write and close. You can
306close over this object for asynchronous and nonblocking applications. For
307example (assuming you are using a supporting server, like L<Twiggy>
308
309 package AsyncExample::Controller::Root;
310
311 use Moose;
312
313 BEGIN { extends 'Catalyst::Controller' }
314
315 sub prepare_cb {
316 my $write_fh = pop;
317 return sub {
318 my $message = shift;
319 $write_fh->write("Finishing: $message\n");
320 $write_fh->close;
321 };
322 }
323
324 sub anyevent :Local :Args(0) {
325 my ($self, $c) = @_;
326 my $cb = $self->prepare_cb($c->res->write_fh);
327
328 my $watcher;
329 $watcher = AnyEvent->timer(
330 after => 5,
331 cb => sub {
332 $cb->(scalar localtime);
333 undef $watcher; # cancel circular-ref
334 });
335 }
336
e4cc83b2 337=head2 $res->print( @data )
338
339Prints @data to the output stream, separated by $,. This lets you pass
340the response object to functions that want to write to an L<IO::Handle>.
341
8738b8fe 342=head2 $self->finalize_headers($c)
343
344Writes headers to response if not already written
345
e67f0874 346=head2 from_psgi_response
347
348Given a PSGI response (either three element ARRAY reference OR coderef expecting
349a $responder) set the response from it.
350
351Properly supports streaming and delayed response and / or async IO if running
352under an expected event loop.
353
354Example:
355
356 package MyApp::Web::Controller::Test;
357
358 use base 'Catalyst::Controller';
359 use Plack::App::Directory;
360
361
362 my $app = Plack::App::Directory->new({ root => "/path/to/htdocs" })
363 ->to_app;
364
365 sub myaction :Local Args {
366 my ($self, $c) = @_;
faa1bcff 367 $c->res->from_psgi_response($app->($c->req->env));
e67f0874 368 }
369
370Please note this does not attempt to map or nest your PSGI application under
371the Controller and Action namespace or path.
372
faa02805 373=head2 DEMOLISH
374
375Ensures that the response is flushed and closed at the end of the
376request.
377
378=head2 meta
379
380Provided by Moose
381
e4cc83b2 382=cut
383
384sub print {
385 my $self = shift;
386 my $data = shift;
387
388 defined $self->write($data) or return;
389
390 for (@_) {
391 defined $self->write($,) or return;
392 defined $self->write($_) or return;
393 }
fe3083a8 394 defined $self->write($\) or return;
b0ad47c1 395
e4cc83b2 396 return 1;
397}
398
910410b8 399=head1 AUTHORS
fc7ec1d9 400
2f381252 401Catalyst Contributors, see Catalyst.pm
fc7ec1d9 402
403=head1 COPYRIGHT
404
b0ad47c1 405This library is free software. You can redistribute it and/or modify
61b1e958 406it under the same terms as Perl itself.
fc7ec1d9 407
408=cut
409
e5ecd5bc 410__PACKAGE__->meta->make_immutable;
411
fc7ec1d9 4121;