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