proxy object for the PSGI writer
[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;
fc7ec1d9 9
531f1ab6 10with 'MooseX::Emulate::Class::Accessor::Fast';
11
faa02805 12has _response_cb => (
13 is => 'ro',
46fff667 14 isa => 'CodeRef',
faa02805 15 writer => '_set_response_cb',
16 clearer => '_clear_response_cb',
17 predicate => '_has_response_cb',
18);
19
20subtype 'Catalyst::Engine::Types::Writer',
21 as duck_type([qw(write close)]);
22
23has _writer => (
24 is => 'ro',
46fff667 25 isa => 'Catalyst::Engine::Types::Writer', #Pointless since we control how this is built
26 #writer => '_set_writer', Now that its lazy I think this is safe to remove
faa02805 27 clearer => '_clear_writer',
28 predicate => '_has_writer',
46fff667 29 lazy => 1,
30 builder => '_build_writer',
faa02805 31);
32
46fff667 33sub _build_writer {
34 my $self = shift;
35
36 ## These two lines are probably crap now...
37 $self->_context->finalize_headers unless
38 $self->finalized_headers;
39
40 my @headers;
41 $self->headers->scan(sub { push @headers, @_ });
42
43 my $writer = $self->_response_cb->([ $self->status, \@headers ]);
44 $self->_clear_response_cb;
45
46 return $writer;
47}
48
e37f92f5 49has write_fh => (
50 is=>'ro',
a3c9ab76 51 predicate=>'_has_write_fh',
eb1f4b49 52 lazy=>1,
1f2a8069 53 builder=>'_build_write_fh',
54);
55
e8361cf8 56sub _build_write_fh {
57 my $writer = $_[0]->_writer; # We need to get the finalize headers side effect...
58 my $requires_encoding = $_[0]->content_type =~ m/^text|xml$|javascript$/;
59 my %fields = (
60 _writer => $writer,
61 _encoding => $_[0]->encoding,
62 _requires_encoding => $requires_encoding,
63 );
64
65 return bless \%fields, 'Catalyst::Response::Writer';
66}
e37f92f5 67
68sub DEMOLISH {
69 my $self = shift;
a3c9ab76 70 return if $self->_has_write_fh;
e37f92f5 71 if($self->_has_writer) {
72 $self->_writer->close
73 }
74}
faa02805 75
6680c772 76has cookies => (is => 'rw', default => sub { {} });
ffb43803 77has body => (is => 'rw', default => undef);
78sub has_body { defined($_[0]->body) }
99a543ee 79
059c085b 80has location => (is => 'rw');
6680c772 81has status => (is => 'rw', default => 200);
82has finalized_headers => (is => 'rw', default => 0);
059c085b 83has headers => (
84 is => 'rw',
9c331634 85 isa => 'HTTP::Headers',
059c085b 86 handles => [qw(content_encoding content_length content_type header)],
6680c772 87 default => sub { HTTP::Headers->new() },
88 required => 1,
89 lazy => 1,
059c085b 90);
258733f1 91has _context => (
92 is => 'rw',
93 weak_ref => 1,
94 clearer => '_clear_context',
95);
fc7ec1d9 96
e8361cf8 97has encoding => (is=>'ro');
98
9ae060f0 99before [qw(status headers content_encoding content_length content_type header)] => sub {
100 my $self = shift;
101
102 $self->_context->log->warn(
103 "Useless setting a header value after finalize_headers called." .
104 " Not what you want." )
105 if ( $self->finalized_headers && @_ );
106};
107
059c085b 108sub output { shift->body(@_) }
109
aa9e8261 110sub code { shift->status(@_) }
111
9c4288ea 112sub write {
113 my ( $self, $buffer ) = @_;
114
115 # Finalize headers if someone manually writes output
89ba65d5 116 $self->_context->finalize_headers unless $self->finalized_headers;
9c4288ea 117
118 $buffer = q[] unless defined $buffer;
5c397774 119
120 $buffer = $self->_context->encoding->encode( $buffer, $self->_context->_encode_check )
121 if $self->_context->encoding && $self->content_type =~ /^text|xml$|javascript$/;
9c4288ea 122
123 my $len = length($buffer);
124 $self->_writer->write($buffer);
125
126 return $len;
127}
128
9c4288ea 129sub finalize_headers {
130 my ($self) = @_;
9c4288ea 131 return;
132}
133
e67f0874 134sub from_psgi_response {
135 my ($self, $psgi_res) = @_;
b194746d 136 if(blessed($psgi_res) && $psgi_res->can('as_psgi')) {
137 $psgi_res = $psgi_res->as_psgi;
138 }
e67f0874 139 if(ref $psgi_res eq 'ARRAY') {
140 my ($status, $headers, $body) = @$psgi_res;
141 $self->status($status);
4491e0cc 142 $self->headers(HTTP::Headers->new(@$headers));
8a3dcb98 143 $self->body($body);
e67f0874 144 } elsif(ref $psgi_res eq 'CODE') {
145 $psgi_res->(sub {
4491e0cc 146 my $response = shift;
147 my ($status, $headers, $maybe_body) = @$response;
e67f0874 148 $self->status($status);
4491e0cc 149 $self->headers(HTTP::Headers->new(@$headers));
8a3dcb98 150 if(defined $maybe_body) {
151 $self->body($maybe_body);
e67f0874 152 } else {
153 return $self->write_fh;
154 }
4491e0cc 155 });
156 } else {
e67f0874 157 die "You can't set a Catalyst response from that, expect a valid PSGI response";
158 }
159}
160
fc7ec1d9 161=head1 NAME
162
910410b8 163Catalyst::Response - stores output responding to the current client request
fc7ec1d9 164
165=head1 SYNOPSIS
166
fbcc39ad 167 $res = $c->response;
168 $res->body;
aa9e8261 169 $res->code;
fbcc39ad 170 $res->content_encoding;
171 $res->content_length;
172 $res->content_type;
173 $res->cookies;
fbcc39ad 174 $res->header;
175 $res->headers;
176 $res->output;
177 $res->redirect;
178 $res->status;
179 $res->write;
b22c6668 180
fc7ec1d9 181=head1 DESCRIPTION
182
910410b8 183This is the Catalyst Response class, which provides methods for responding to
46372e65 184the current client request. The appropriate L<Catalyst::Engine> for your environment
185will turn the Catalyst::Response into a HTTP Response and return it to the client.
b22c6668 186
187=head1 METHODS
fc7ec1d9 188
08a2c908 189=head2 $res->body( $text | $fh | $iohandle_object )
e060fe05 190
191 $c->response->body('Catalyst rocks!');
06e1b616 192
46372e65 193Sets or returns the output (text or binary data). If you are returning a large body,
2f381252 194you might want to use a L<IO::Handle> type of object (Something that implements the read method
46372e65 195in the same fashion), or a filehandle GLOB. Catalyst
196will write it piece by piece into the response.
06e1b616 197
490b7a80 198When using a L<IO::Handle> type of object and no content length has been
199already set in the response headers Catalyst will make a reasonable attempt
200to determine the size of the Handle. Depending on the implementation of your
201handle object, setting the content length may fail. If it is at all possible
202for you to determine the content length of your handle object,
4a178c0d 203it is recommended that you set the content length in the response headers
490b7a80 204yourself, which will be respected and sent by Catalyst in the response.
205
efeeb257 206Please note that the object needs to implement C<getline>, not just
207C<read>.
208
209Starting from version 5.90060, when using an L<IO::Handle> object, you
210may want to use L<Plack::Middleware::XSendfile>, to delegate the
211actual serving to the frontend server. To do so, you need to pass to
212C<body> an IO object with a C<path> method. This can be achieved in
213two ways.
214
215Either using L<Plack::Util>:
216
217 my $fh = IO::File->new($file, 'r');
218 Plack::Util::set_io_path($fh, $file);
219
220Or using L<IO::File::WithPath>
221
222 my $fh = IO::File::WithPath->new($file, 'r');
223
224And then passing the filehandle to body and setting headers, if needed.
225
226 $c->response->body($fh);
227 $c->response->headers->content_type('text/plain');
228 $c->response->headers->content_length(-s $file);
229 $c->response->headers->last_modified((stat($file))[9]);
230
231L<Plack::Middleware::XSendfile> can be loaded in the application so:
232
233 __PACKAGE__->config(
234 psgi_middleware => [
235 'XSendfile',
236 # other middlewares here...
237 ],
238 );
239
240B<Beware> that loading the middleware without configuring the
241webserver to set the request header C<X-Sendfile-Type> to a supported
242type (C<X-Accel-Redirect> for nginx, C<X-Sendfile> for Apache and
243Lighttpd), could lead to the disclosure of private paths to malicious
244clients setting that header.
245
246Nginx needs the additional X-Accel-Mapping header to be set in the
247webserver configuration, so the middleware will replace the absolute
248path of the IO object with the internal nginx path. This is also
249useful to prevent a buggy app to server random files from the
250filesystem, as it's an internal redirect.
251
252An nginx configuration for FastCGI could look so:
253
254 server {
255 server_name example.com;
256 root /my/app/root;
257 location /private/repo/ {
258 internal;
259 alias /my/app/repo/;
260 }
261 location /private/staging/ {
262 internal;
263 alias /my/app/staging/;
264 }
265 location @proxy {
266 include /etc/nginx/fastcgi_params;
267 fastcgi_param SCRIPT_NAME '';
268 fastcgi_param PATH_INFO $fastcgi_script_name;
269 fastcgi_param HTTP_X_SENDFILE_TYPE X-Accel-Redirect;
270 fastcgi_param HTTP_X_ACCEL_MAPPING /my/app=/private;
271 fastcgi_pass unix:/my/app/run/app.sock;
272 }
273 }
274
275In the example above, passing filehandles with a local path matching
276/my/app/staging or /my/app/repo will be served by nginx. Passing paths
277with other locations will lead to an internal server error.
278
279Setting the body to a filehandle without the C<path> method bypasses
280the middleware completely.
281
282For Apache and Lighttpd, the mapping doesn't apply and setting the
283X-Sendfile-Type is enough.
284
02570318 285=head2 $res->has_body
286
287Predicate which returns true when a body has been set.
288
aa9e8261 289=head2 $res->code
290
291Alias for $res->status.
292
b5ecfcf0 293=head2 $res->content_encoding
b5176d9e 294
910410b8 295Shortcut for $res->headers->content_encoding.
b5176d9e 296
b5ecfcf0 297=head2 $res->content_length
b5176d9e 298
910410b8 299Shortcut for $res->headers->content_length.
b5176d9e 300
b5ecfcf0 301=head2 $res->content_type
b5176d9e 302
910410b8 303Shortcut for $res->headers->content_type.
b5176d9e 304
87e9f9ab 305This value is typically set by your view or plugin. For example,
306L<Catalyst::Plugin::Static::Simple> will guess the mime type based on the file
307it found, while L<Catalyst::View::TT> defaults to C<text/html>.
308
b5ecfcf0 309=head2 $res->cookies
fc7ec1d9 310
910410b8 311Returns a reference to a hash containing cookies to be set. The keys of the
312hash are the cookies' names, and their corresponding values are hash
7e743798 313references used to construct a L<CGI::Simple::Cookie> object.
fc7ec1d9 314
315 $c->response->cookies->{foo} = { value => '123' };
316
7e743798 317The keys of the hash reference on the right correspond to the L<CGI::Simple::Cookie>
910410b8 318parameters of the same name, except they are used without a leading dash.
319Possible parameters are:
ac965e92 320
b0ad47c1 321=over
ac965e92 322
71453caf 323=item value
ac965e92 324
71453caf 325=item expires
ac965e92 326
71453caf 327=item domain
ac965e92 328
71453caf 329=item path
330
331=item secure
332
b21bc468 333=item httponly
334
71453caf 335=back
ac965e92 336
b5ecfcf0 337=head2 $res->header
fbcc39ad 338
910410b8 339Shortcut for $res->headers->header.
fbcc39ad 340
b5ecfcf0 341=head2 $res->headers
fc7ec1d9 342
910410b8 343Returns an L<HTTP::Headers> object, which can be used to set headers.
fc7ec1d9 344
345 $c->response->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
346
b5ecfcf0 347=head2 $res->output
fc7ec1d9 348
910410b8 349Alias for $res->body.
fc7ec1d9 350
b5ecfcf0 351=head2 $res->redirect( $url, $status )
fc7ec1d9 352
2f381252 353Causes the response to redirect to the specified URL. The default status is
354C<302>.
fc7ec1d9 355
73a52566 356 $c->response->redirect( 'http://slashdot.org' );
357 $c->response->redirect( 'http://slashdot.org', 307 );
358
2f381252 359This is a convenience method that sets the Location header to the
360redirect destination, and then sets the response status. You will
ee24f3a8 361want to C< return > or C<< $c->detach() >> to interrupt the normal
2f381252 362processing flow if you want the redirect to occur straight away.
363
824a5eb0 364B<Note:> do not give a relative URL as $url, i.e: one that is not fully
365qualified (= C<http://...>, etc.) or that starts with a slash
366(= C</path/here>). While it may work, it is not guaranteed to do the right
367thing and is not a standard behaviour. You may opt to use uri_for() or
368uri_for_action() instead.
369
00038a21 370B<Note:> If $url is an object that does ->as_string (such as L<URI>, which is
371what you get from ->uri_for) we automatically call that to stringify. This
372should ease the common case usage
373
374 return $c->res->redirect( $c->uri_for(...));
375
73a52566 376=cut
377
378sub redirect {
379 my $self = shift;
fbcc39ad 380
381 if (@_) {
73a52566 382 my $location = shift;
f1bbebac 383 my $status = shift || 302;
73a52566 384
00038a21 385 if(blessed($location) && $location->can('as_string')) {
386 $location = $location->as_string;
387 }
388
73a52566 389 $self->location($location);
390 $self->status($status);
391 }
392
393 return $self->location;
394}
fc7ec1d9 395
059c085b 396=head2 $res->location
397
398Sets or returns the HTTP 'Location'.
399
b5ecfcf0 400=head2 $res->status
fc7ec1d9 401
910410b8 402Sets or returns the HTTP status.
fc7ec1d9 403
404 $c->response->status(404);
aa9e8261 405
406$res->code is an alias for this, to match HTTP::Response->code.
b0ad47c1 407
b5ecfcf0 408=head2 $res->write( $data )
fbcc39ad 409
dd096a3a 410Writes $data to the output stream. Calling this method will finalize your
411headers and send the headers and status code response to the client (so changing
412them afterwards is a waste... be sure to set your headers correctly first).
413
414You may call this as often as you want throughout your response cycle. You may
415even set a 'body' afterward. So for example you might write your HTTP headers
416and the HEAD section of your document and then set the body from a template
417driven from a database. In some cases this can seem to the client as if you had
418a faster overall response (but note that unless your server support chunked
419body your content is likely to get queued anyway (L<Starman> and most other
420http 1.1 webservers support this).
421
422If there is an encoding set, we encode each line of the response (the default
423encoding is UTF-8).
fbcc39ad 424
e37f92f5 425=head2 $res->write_fh
426
e8361cf8 427Returns an instance of L<Catalyst::Response::Writer>, which is a lightweight
428decorator over the PSGI C<$writer> object (see L<PSGI.pod\Delayed-Response-and-Streaming-Body>).
429
430In addition to proxying the C<write> and C<close> method from the underlying PSGI
431writer, this proxy object knows any application wide encoding, and provides a method
432C<write_encoded> that will properly encode your written lines based upon your
433encoding settings. By default in L<Catalyst> responses are UTF-8 encoded and this
434is the encoding used if you respond via C<write_encoded>. If you want to handle
435encoding yourself, you can use the C<write> method directly.
436
437Encoding only applies to content types for which it matters. Currently the following
438content types are assumed to need encoding: text (including HTML), xml and javascript.
439
440We provide access to this object so that you can properly close over it for use in
441asynchronous and nonblocking applications. For example (assuming you are using a supporting
442server, like L<Twiggy>:
e37f92f5 443
444 package AsyncExample::Controller::Root;
445
446 use Moose;
447
448 BEGIN { extends 'Catalyst::Controller' }
449
450 sub prepare_cb {
451 my $write_fh = pop;
452 return sub {
453 my $message = shift;
454 $write_fh->write("Finishing: $message\n");
455 $write_fh->close;
456 };
457 }
458
459 sub anyevent :Local :Args(0) {
460 my ($self, $c) = @_;
461 my $cb = $self->prepare_cb($c->res->write_fh);
462
463 my $watcher;
464 $watcher = AnyEvent->timer(
465 after => 5,
466 cb => sub {
467 $cb->(scalar localtime);
468 undef $watcher; # cancel circular-ref
469 });
470 }
471
dd096a3a 472Like the 'write' method, calling this will finalize headers. Unlike 'write' when you
473can this it is assumed you are taking control of the response so the body is never
474finalized (there isn't one anyway) and you need to call the close method.
475
e4cc83b2 476=head2 $res->print( @data )
477
478Prints @data to the output stream, separated by $,. This lets you pass
479the response object to functions that want to write to an L<IO::Handle>.
480
8738b8fe 481=head2 $self->finalize_headers($c)
482
483Writes headers to response if not already written
484
e67f0874 485=head2 from_psgi_response
486
487Given a PSGI response (either three element ARRAY reference OR coderef expecting
488a $responder) set the response from it.
489
490Properly supports streaming and delayed response and / or async IO if running
491under an expected event loop.
492
b194746d 493If passed an object, will expect that object to do a method C<as_psgi>.
494
e67f0874 495Example:
496
497 package MyApp::Web::Controller::Test;
498
499 use base 'Catalyst::Controller';
500 use Plack::App::Directory;
501
502
503 my $app = Plack::App::Directory->new({ root => "/path/to/htdocs" })
504 ->to_app;
505
506 sub myaction :Local Args {
507 my ($self, $c) = @_;
faa1bcff 508 $c->res->from_psgi_response($app->($c->req->env));
e67f0874 509 }
510
511Please note this does not attempt to map or nest your PSGI application under
512the Controller and Action namespace or path.
513
faa02805 514=head2 DEMOLISH
515
516Ensures that the response is flushed and closed at the end of the
517request.
518
519=head2 meta
520
521Provided by Moose
522
e4cc83b2 523=cut
524
525sub print {
526 my $self = shift;
527 my $data = shift;
528
529 defined $self->write($data) or return;
530
531 for (@_) {
532 defined $self->write($,) or return;
533 defined $self->write($_) or return;
534 }
fe3083a8 535 defined $self->write($\) or return;
b0ad47c1 536
e4cc83b2 537 return 1;
538}
539
910410b8 540=head1 AUTHORS
fc7ec1d9 541
2f381252 542Catalyst Contributors, see Catalyst.pm
fc7ec1d9 543
544=head1 COPYRIGHT
545
b0ad47c1 546This library is free software. You can redistribute it and/or modify
61b1e958 547it under the same terms as Perl itself.
fc7ec1d9 548
549=cut
550
e5ecd5bc 551__PACKAGE__->meta->make_immutable;
552
fc7ec1d9 5531;