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