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