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