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