to_app alias
[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
efeeb257 186Please note that the object needs to implement C<getline>, not just
187C<read>.
188
189Starting from version 5.90060, when using an L<IO::Handle> object, you
190may want to use L<Plack::Middleware::XSendfile>, to delegate the
191actual serving to the frontend server. To do so, you need to pass to
192C<body> an IO object with a C<path> method. This can be achieved in
193two ways.
194
195Either using L<Plack::Util>:
196
197 my $fh = IO::File->new($file, 'r');
198 Plack::Util::set_io_path($fh, $file);
199
200Or using L<IO::File::WithPath>
201
202 my $fh = IO::File::WithPath->new($file, 'r');
203
204And then passing the filehandle to body and setting headers, if needed.
205
206 $c->response->body($fh);
207 $c->response->headers->content_type('text/plain');
208 $c->response->headers->content_length(-s $file);
209 $c->response->headers->last_modified((stat($file))[9]);
210
211L<Plack::Middleware::XSendfile> can be loaded in the application so:
212
213 __PACKAGE__->config(
214 psgi_middleware => [
215 'XSendfile',
216 # other middlewares here...
217 ],
218 );
219
220B<Beware> that loading the middleware without configuring the
221webserver to set the request header C<X-Sendfile-Type> to a supported
222type (C<X-Accel-Redirect> for nginx, C<X-Sendfile> for Apache and
223Lighttpd), could lead to the disclosure of private paths to malicious
224clients setting that header.
225
226Nginx needs the additional X-Accel-Mapping header to be set in the
227webserver configuration, so the middleware will replace the absolute
228path of the IO object with the internal nginx path. This is also
229useful to prevent a buggy app to server random files from the
230filesystem, as it's an internal redirect.
231
232An nginx configuration for FastCGI could look so:
233
234 server {
235 server_name example.com;
236 root /my/app/root;
237 location /private/repo/ {
238 internal;
239 alias /my/app/repo/;
240 }
241 location /private/staging/ {
242 internal;
243 alias /my/app/staging/;
244 }
245 location @proxy {
246 include /etc/nginx/fastcgi_params;
247 fastcgi_param SCRIPT_NAME '';
248 fastcgi_param PATH_INFO $fastcgi_script_name;
249 fastcgi_param HTTP_X_SENDFILE_TYPE X-Accel-Redirect;
250 fastcgi_param HTTP_X_ACCEL_MAPPING /my/app=/private;
251 fastcgi_pass unix:/my/app/run/app.sock;
252 }
253 }
254
255In the example above, passing filehandles with a local path matching
256/my/app/staging or /my/app/repo will be served by nginx. Passing paths
257with other locations will lead to an internal server error.
258
259Setting the body to a filehandle without the C<path> method bypasses
260the middleware completely.
261
262For Apache and Lighttpd, the mapping doesn't apply and setting the
263X-Sendfile-Type is enough.
264
02570318 265=head2 $res->has_body
266
267Predicate which returns true when a body has been set.
268
aa9e8261 269=head2 $res->code
270
271Alias for $res->status.
272
b5ecfcf0 273=head2 $res->content_encoding
b5176d9e 274
910410b8 275Shortcut for $res->headers->content_encoding.
b5176d9e 276
b5ecfcf0 277=head2 $res->content_length
b5176d9e 278
910410b8 279Shortcut for $res->headers->content_length.
b5176d9e 280
b5ecfcf0 281=head2 $res->content_type
b5176d9e 282
910410b8 283Shortcut for $res->headers->content_type.
b5176d9e 284
87e9f9ab 285This value is typically set by your view or plugin. For example,
286L<Catalyst::Plugin::Static::Simple> will guess the mime type based on the file
287it found, while L<Catalyst::View::TT> defaults to C<text/html>.
288
b5ecfcf0 289=head2 $res->cookies
fc7ec1d9 290
910410b8 291Returns a reference to a hash containing cookies to be set. The keys of the
292hash are the cookies' names, and their corresponding values are hash
7e743798 293references used to construct a L<CGI::Simple::Cookie> object.
fc7ec1d9 294
295 $c->response->cookies->{foo} = { value => '123' };
296
7e743798 297The keys of the hash reference on the right correspond to the L<CGI::Simple::Cookie>
910410b8 298parameters of the same name, except they are used without a leading dash.
299Possible parameters are:
ac965e92 300
b0ad47c1 301=over
ac965e92 302
71453caf 303=item value
ac965e92 304
71453caf 305=item expires
ac965e92 306
71453caf 307=item domain
ac965e92 308
71453caf 309=item path
310
311=item secure
312
b21bc468 313=item httponly
314
71453caf 315=back
ac965e92 316
b5ecfcf0 317=head2 $res->header
fbcc39ad 318
910410b8 319Shortcut for $res->headers->header.
fbcc39ad 320
b5ecfcf0 321=head2 $res->headers
fc7ec1d9 322
910410b8 323Returns an L<HTTP::Headers> object, which can be used to set headers.
fc7ec1d9 324
325 $c->response->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
326
b5ecfcf0 327=head2 $res->output
fc7ec1d9 328
910410b8 329Alias for $res->body.
fc7ec1d9 330
b5ecfcf0 331=head2 $res->redirect( $url, $status )
fc7ec1d9 332
2f381252 333Causes the response to redirect to the specified URL. The default status is
334C<302>.
fc7ec1d9 335
73a52566 336 $c->response->redirect( 'http://slashdot.org' );
337 $c->response->redirect( 'http://slashdot.org', 307 );
338
2f381252 339This is a convenience method that sets the Location header to the
340redirect destination, and then sets the response status. You will
ee24f3a8 341want to C< return > or C<< $c->detach() >> to interrupt the normal
2f381252 342processing flow if you want the redirect to occur straight away.
343
824a5eb0 344B<Note:> do not give a relative URL as $url, i.e: one that is not fully
345qualified (= C<http://...>, etc.) or that starts with a slash
346(= C</path/here>). While it may work, it is not guaranteed to do the right
347thing and is not a standard behaviour. You may opt to use uri_for() or
348uri_for_action() instead.
349
73a52566 350=cut
351
352sub redirect {
353 my $self = shift;
fbcc39ad 354
355 if (@_) {
73a52566 356 my $location = shift;
f1bbebac 357 my $status = shift || 302;
73a52566 358
359 $self->location($location);
360 $self->status($status);
361 }
362
363 return $self->location;
364}
fc7ec1d9 365
059c085b 366=head2 $res->location
367
368Sets or returns the HTTP 'Location'.
369
b5ecfcf0 370=head2 $res->status
fc7ec1d9 371
910410b8 372Sets or returns the HTTP status.
fc7ec1d9 373
374 $c->response->status(404);
aa9e8261 375
376$res->code is an alias for this, to match HTTP::Response->code.
b0ad47c1 377
b5ecfcf0 378=head2 $res->write( $data )
fbcc39ad 379
380Writes $data to the output stream.
381
e37f92f5 382=head2 $res->write_fh
383
384Returns a PSGI $writer object that has two methods, write and close. You can
385close over this object for asynchronous and nonblocking applications. For
386example (assuming you are using a supporting server, like L<Twiggy>
387
388 package AsyncExample::Controller::Root;
389
390 use Moose;
391
392 BEGIN { extends 'Catalyst::Controller' }
393
394 sub prepare_cb {
395 my $write_fh = pop;
396 return sub {
397 my $message = shift;
398 $write_fh->write("Finishing: $message\n");
399 $write_fh->close;
400 };
401 }
402
403 sub anyevent :Local :Args(0) {
404 my ($self, $c) = @_;
405 my $cb = $self->prepare_cb($c->res->write_fh);
406
407 my $watcher;
408 $watcher = AnyEvent->timer(
409 after => 5,
410 cb => sub {
411 $cb->(scalar localtime);
412 undef $watcher; # cancel circular-ref
413 });
414 }
415
e4cc83b2 416=head2 $res->print( @data )
417
418Prints @data to the output stream, separated by $,. This lets you pass
419the response object to functions that want to write to an L<IO::Handle>.
420
8738b8fe 421=head2 $self->finalize_headers($c)
422
423Writes headers to response if not already written
424
e67f0874 425=head2 from_psgi_response
426
427Given a PSGI response (either three element ARRAY reference OR coderef expecting
428a $responder) set the response from it.
429
430Properly supports streaming and delayed response and / or async IO if running
431under an expected event loop.
432
433Example:
434
435 package MyApp::Web::Controller::Test;
436
437 use base 'Catalyst::Controller';
438 use Plack::App::Directory;
439
440
441 my $app = Plack::App::Directory->new({ root => "/path/to/htdocs" })
442 ->to_app;
443
444 sub myaction :Local Args {
445 my ($self, $c) = @_;
faa1bcff 446 $c->res->from_psgi_response($app->($c->req->env));
e67f0874 447 }
448
449Please note this does not attempt to map or nest your PSGI application under
450the Controller and Action namespace or path.
451
faa02805 452=head2 DEMOLISH
453
454Ensures that the response is flushed and closed at the end of the
455request.
456
457=head2 meta
458
459Provided by Moose
460
e4cc83b2 461=cut
462
463sub print {
464 my $self = shift;
465 my $data = shift;
466
467 defined $self->write($data) or return;
468
469 for (@_) {
470 defined $self->write($,) or return;
471 defined $self->write($_) or return;
472 }
fe3083a8 473 defined $self->write($\) or return;
b0ad47c1 474
e4cc83b2 475 return 1;
476}
477
910410b8 478=head1 AUTHORS
fc7ec1d9 479
2f381252 480Catalyst Contributors, see Catalyst.pm
fc7ec1d9 481
482=head1 COPYRIGHT
483
b0ad47c1 484This library is free software. You can redistribute it and/or modify
61b1e958 485it under the same terms as Perl itself.
fc7ec1d9 486
487=cut
488
e5ecd5bc 489__PACKAGE__->meta->make_immutable;
490
fc7ec1d9 4911;