1 package Catalyst::Response;
5 use Moose::Util::TypeConstraints;
6 use Scalar::Util 'blessed';
7 use Catalyst::Response::Writer;
8 use Catalyst::Utils ();
10 use namespace::clean -except => ['meta'];
12 with 'MooseX::Emulate::Class::Accessor::Fast';
14 our $DEFAULT_ENCODE_CONTENT_TYPE_MATCH = qr{text|xml$|javascript$};
16 has encodable_content_type => (
19 default => sub { $DEFAULT_ENCODE_CONTENT_TYPE_MATCH }
25 writer => '_set_response_cb',
26 clearer => '_clear_response_cb',
27 predicate => '_has_response_cb',
30 subtype 'Catalyst::Engine::Types::Writer',
31 as duck_type([qw(write close)]);
35 isa => 'Catalyst::Engine::Types::Writer', #Pointless since we control how this is built
36 #writer => '_set_writer', Now that its lazy I think this is safe to remove
37 clearer => '_clear_writer',
38 predicate => '_has_writer',
40 builder => '_build_writer',
46 ## These two lines are probably crap now...
47 $self->_context->finalize_headers unless
48 $self->finalized_headers;
51 $self->headers->scan(sub { push @headers, @_ });
53 my $writer = $self->_response_cb->([ $self->status, \@headers ]);
54 $self->_clear_response_cb;
61 predicate=>'_has_write_fh',
63 builder=>'_build_write_fh',
67 my $writer = $_[0]->_writer; # We need to get the finalize headers side effect...
68 my $requires_encoding = $_[0]->encodable_response;
71 _context => $_[0]->_context,
72 _requires_encoding => $requires_encoding,
75 return bless \%fields, 'Catalyst::Response::Writer';
80 return if $self->_has_write_fh;
81 if($self->_has_writer) {
86 has cookies => (is => 'rw', default => sub { {} });
87 has body => (is => 'rw', default => undef);
88 sub has_body { defined($_[0]->body) }
90 has location => (is => 'rw');
91 has status => (is => 'rw', default => 200);
92 has finalized_headers => (is => 'rw', default => 0);
95 isa => 'HTTP::Headers',
96 handles => [qw(content_encoding content_length content_type content_type_charset header)],
97 default => sub { HTTP::Headers->new() },
104 clearer => '_clear_context',
107 before [qw(status headers content_encoding content_length content_type )] => sub {
110 $self->_context->log->warn(
111 "Useless setting a header value after finalize_headers and the response callback has been called." .
112 " Since we don't support tail headers this will not work as you might expect." )
113 if ( $self->_context && $self->finalized_headers && !$self->_has_response_cb && @_ );
116 # This has to be different since the first param to ->header is the header name and presumably
117 # you should be able to request the header even after finalization, just not try to change it.
118 before 'header' => sub {
122 $self->_context->log->warn(
123 "Useless setting a header value after finalize_headers and the response callback has been called." .
124 " Since we don't support tail headers this will not work as you might expect." )
125 if ( $self->_context && $self->finalized_headers && !$self->_has_response_cb && @_ );
128 sub output { shift->body(@_) }
130 sub code { shift->status(@_) }
133 my ( $self, $buffer ) = @_;
135 # Finalize headers if someone manually writes output
136 $self->_context->finalize_headers unless $self->finalized_headers;
138 $buffer = q[] unless defined $buffer;
140 if($self->encodable_response) {
141 $buffer = $self->_context->encoding->encode( $buffer, $self->_context->_encode_check )
144 my $len = length($buffer);
145 $self->_writer->write($buffer);
150 sub unencoded_write {
151 my ( $self, $buffer ) = @_;
153 # Finalize headers if someone manually writes output
154 $self->_context->finalize_headers unless $self->finalized_headers;
156 $buffer = q[] unless defined $buffer;
158 my $len = length($buffer);
159 $self->_writer->write($buffer);
164 sub finalize_headers {
169 sub from_psgi_response {
170 my ($self, $psgi_res) = @_;
171 if(blessed($psgi_res) && $psgi_res->can('as_psgi')) {
172 $psgi_res = $psgi_res->as_psgi;
174 if(ref $psgi_res eq 'ARRAY') {
175 my ($status, $headers, $body) = @$psgi_res;
176 $self->status($status);
177 $self->headers(HTTP::Headers->new(@$headers));
178 # Can be arrayref or filehandle...
179 if(defined $body) { # probably paranoia
180 ref $body eq 'ARRAY' ? $self->body(join('', @$body)) : $self->body($body);
182 } elsif(ref $psgi_res eq 'CODE') {
184 my $response = shift;
185 my ($status, $headers, $maybe_body) = @$response;
186 $self->status($status);
187 $self->headers(HTTP::Headers->new(@$headers));
188 if(defined $maybe_body) {
189 # Can be arrayref or filehandle...
190 ref $maybe_body eq 'ARRAY' ? $self->body(join('', @$maybe_body)) : $self->body($maybe_body);
192 return $self->write_fh;
196 die "You can't set a Catalyst response from that, expect a valid PSGI response";
199 return if $self->finalized_headers;
201 # Encoding compatibilty. If the response set a charset, well... we need
202 # to assume its properly encoded and NOT encode for this response. Otherwise
203 # We risk double encoding.
204 if($self->content_type_charset) {
205 # We have to do this since for backcompat reasons having a charset doesn't always
206 # mean that the body is already encoded :(
207 $self->_context->clear_encoding;
213 Catalyst::Response - stores output responding to the current client request
220 $res->content_encoding;
221 $res->content_length;
233 This is the Catalyst Response class, which provides methods for responding to
234 the current client request. The appropriate L<Catalyst::Engine> for your environment
235 will turn the Catalyst::Response into a HTTP Response and return it to the client.
239 =head2 $res->body( $text | $fh | $iohandle_object )
241 $c->response->body('Catalyst rocks!');
243 Sets or returns the output (text or binary data). If you are returning a large body,
244 you might want to use a L<IO::Handle> type of object (Something that implements the getline method
245 in the same fashion), or a filehandle GLOB. These will be passed down to the PSGI
246 handler you are using and might be optimized using server specific abilities (for
247 example L<Twiggy> will attempt to server a real local file in a non blocking manner).
249 If you are using a filehandle as the body response you are responsible for
250 making sure it conforms to the L<PSGI> specification with regards to content
251 encoding. Unlike with scalar body values or when using the streaming interfaces
252 we currently do not attempt to normalize and encode your filehandle. In general
253 this means you should be sure to be sending bytes not UTF8 decoded multibyte
256 Most of the time when you do:
258 open(my $fh, '<:raw', $path);
260 You should be fine. If you open a filehandle with a L<PerlIO> layer you probably
261 are not fine. You can usually fix this by explicitly using binmode to set
262 the IOLayer to :raw. Its possible future versions of L<Catalyst> will try to
263 'do the right thing'.
265 When using a L<IO::Handle> type of object and no content length has been
266 already set in the response headers Catalyst will make a reasonable attempt
267 to determine the size of the Handle. Depending on the implementation of your
268 handle object, setting the content length may fail. If it is at all possible
269 for you to determine the content length of your handle object,
270 it is recommended that you set the content length in the response headers
271 yourself, which will be respected and sent by Catalyst in the response.
273 Please note that the object needs to implement C<getline>, not just
274 C<read>. Older versions of L<Catalyst> expected your filehandle like objects
275 to do read. If you have code written for this expectation and you cannot
276 change the code to meet the L<PSGI> specification, you can try the following
277 middleware L<Plack::Middleware::AdaptFilehandleRead> which will attempt to
278 wrap your object in an interface that so conforms.
280 Starting from version 5.90060, when using an L<IO::Handle> object, you
281 may want to use L<Plack::Middleware::XSendfile>, to delegate the
282 actual serving to the frontend server. To do so, you need to pass to
283 C<body> an IO object with a C<path> method. This can be achieved in
286 Either using L<Plack::Util>:
288 my $fh = IO::File->new($file, 'r');
289 Plack::Util::set_io_path($fh, $file);
291 Or using L<IO::File::WithPath>
293 my $fh = IO::File::WithPath->new($file, 'r');
295 And then passing the filehandle to body and setting headers, if needed.
297 $c->response->body($fh);
298 $c->response->headers->content_type('text/plain');
299 $c->response->headers->content_length(-s $file);
300 $c->response->headers->last_modified((stat($file))[9]);
302 L<Plack::Middleware::XSendfile> can be loaded in the application so:
307 # other middlewares here...
311 B<Beware> that loading the middleware without configuring the
312 webserver to set the request header C<X-Sendfile-Type> to a supported
313 type (C<X-Accel-Redirect> for nginx, C<X-Sendfile> for Apache and
314 Lighttpd), could lead to the disclosure of private paths to malicious
315 clients setting that header.
317 Nginx needs the additional X-Accel-Mapping header to be set in the
318 webserver configuration, so the middleware will replace the absolute
319 path of the IO object with the internal nginx path. This is also
320 useful to prevent a buggy app to server random files from the
321 filesystem, as it's an internal redirect.
323 An nginx configuration for FastCGI could look so:
326 server_name example.com;
328 location /private/repo/ {
332 location /private/staging/ {
334 alias /my/app/staging/;
337 include /etc/nginx/fastcgi_params;
338 fastcgi_param SCRIPT_NAME '';
339 fastcgi_param PATH_INFO $fastcgi_script_name;
340 fastcgi_param HTTP_X_SENDFILE_TYPE X-Accel-Redirect;
341 fastcgi_param HTTP_X_ACCEL_MAPPING /my/app=/private;
342 fastcgi_pass unix:/my/app/run/app.sock;
346 In the example above, passing filehandles with a local path matching
347 /my/app/staging or /my/app/repo will be served by nginx. Passing paths
348 with other locations will lead to an internal server error.
350 Setting the body to a filehandle without the C<path> method bypasses
351 the middleware completely.
353 For Apache and Lighttpd, the mapping doesn't apply and setting the
354 X-Sendfile-Type is enough.
356 =head2 $res->has_body
358 Predicate which returns true when a body has been set.
362 Alias for $res->status.
364 =head2 $res->content_encoding
366 Shortcut for $res->headers->content_encoding.
368 =head2 $res->content_length
370 Shortcut for $res->headers->content_length.
372 =head2 $res->content_type
374 Shortcut for $res->headers->content_type.
376 This value is typically set by your view or plugin. For example,
377 L<Catalyst::Plugin::Static::Simple> will guess the mime type based on the file
378 it found, while L<Catalyst::View::TT> defaults to C<text/html>.
380 =head2 $res->content_type_charset
382 Shortcut for $res->headers->content_type_charset;
386 Returns a reference to a hash containing cookies to be set. The keys of the
387 hash are the cookies' names, and their corresponding values are hash
388 references used to construct a L<CGI::Simple::Cookie> object.
390 $c->response->cookies->{foo} = { value => '123' };
392 The keys of the hash reference on the right correspond to the L<CGI::Simple::Cookie>
393 parameters of the same name, except they are used without a leading dash.
394 Possible parameters are:
414 Shortcut for $res->headers->header.
418 Returns an L<HTTP::Headers> object, which can be used to set headers.
420 $c->response->headers->header( 'X-Catalyst' => $Catalyst::VERSION );
424 Alias for $res->body.
426 =head2 $res->redirect( $url, $status )
428 Causes the response to redirect to the specified URL. The default status is
431 $c->response->redirect( 'http://slashdot.org' );
432 $c->response->redirect( 'http://slashdot.org', 307 );
434 This is a convenience method that sets the Location header to the
435 redirect destination, and then sets the response status. You will
436 want to C< return > or C<< $c->detach() >> to interrupt the normal
437 processing flow if you want the redirect to occur straight away.
439 B<Note:> do not give a relative URL as $url, i.e: one that is not fully
440 qualified (= C<http://...>, etc.) or that starts with a slash
441 (= C</path/here>). While it may work, it is not guaranteed to do the right
442 thing and is not a standard behaviour. You may opt to use uri_for() or
443 uri_for_action() instead.
445 B<Note:> If $url is an object that does ->as_string (such as L<URI>, which is
446 what you get from ->uri_for) we automatically call that to stringify. This
447 should ease the common case usage
449 return $c->res->redirect( $c->uri_for(...));
457 my $location = shift;
458 my $status = shift || 302;
460 if(blessed($location) && $location->can('as_string')) {
461 $location = $location->as_string;
464 $self->location($location);
465 $self->status($status);
468 return $self->location;
471 =head2 $res->location
473 Sets or returns the HTTP 'Location'.
477 Sets or returns the HTTP status.
479 $c->response->status(404);
481 $res->code is an alias for this, to match HTTP::Response->code.
483 =head2 $res->write( $data )
485 Writes $data to the output stream. Calling this method will finalize your
486 headers and send the headers and status code response to the client (so changing
487 them afterwards is a waste... be sure to set your headers correctly first).
489 You may call this as often as you want throughout your response cycle. You may
490 even set a 'body' afterward. So for example you might write your HTTP headers
491 and the HEAD section of your document and then set the body from a template
492 driven from a database. In some cases this can seem to the client as if you had
493 a faster overall response (but note that unless your server support chunked
494 body your content is likely to get queued anyway (L<Starman> and most other
495 http 1.1 webservers support this).
497 If there is an encoding set, we encode each line of the response (the default
500 =head2 $res->unencoded_write( $data )
502 Works just like ->write but we don't apply any content encoding to C<$data>. Use
503 this if you are already encoding the $data or the data is arriving from an encoded
506 =head2 $res->write_fh
508 Returns an instance of L<Catalyst::Response::Writer>, which is a lightweight
509 decorator over the PSGI C<$writer> object (see L<PSGI.pod\Delayed-Response-and-Streaming-Body>).
511 In addition to proxying the C<write> and C<close> method from the underlying PSGI
512 writer, this proxy object knows any application wide encoding, and provides a method
513 C<write_encoded> that will properly encode your written lines based upon your
514 encoding settings. By default in L<Catalyst> responses are UTF-8 encoded and this
515 is the encoding used if you respond via C<write_encoded>. If you want to handle
516 encoding yourself, you can use the C<write> method directly.
518 Encoding only applies to content types for which it matters. Currently the following
519 content types are assumed to need encoding: text (including HTML), xml and javascript.
521 We provide access to this object so that you can properly close over it for use in
522 asynchronous and nonblocking applications. For example (assuming you are using a supporting
523 server, like L<Twiggy>:
525 package AsyncExample::Controller::Root;
529 BEGIN { extends 'Catalyst::Controller' }
535 $write_fh->write("Finishing: $message\n");
540 sub anyevent :Local :Args(0) {
542 my $cb = $self->prepare_cb($c->res->write_fh);
545 $watcher = AnyEvent->timer(
548 $cb->(scalar localtime);
549 undef $watcher; # cancel circular-ref
553 Like the 'write' method, calling this will finalize headers. Unlike 'write' when you
554 can this it is assumed you are taking control of the response so the body is never
555 finalized (there isn't one anyway) and you need to call the close method.
557 =head2 $res->print( @data )
559 Prints @data to the output stream, separated by $,. This lets you pass
560 the response object to functions that want to write to an L<IO::Handle>.
562 =head2 $res->finalize_headers()
564 Writes headers to response if not already written
566 =head2 from_psgi_response
568 Given a PSGI response (either three element ARRAY reference OR coderef expecting
569 a $responder) set the response from it.
571 Properly supports streaming and delayed response and / or async IO if running
572 under an expected event loop.
574 If passed an object, will expect that object to do a method C<as_psgi>.
578 package MyApp::Web::Controller::Test;
580 use base 'Catalyst::Controller';
581 use Plack::App::Directory;
584 my $app = Plack::App::Directory->new({ root => "/path/to/htdocs" })
587 sub myaction :Local Args {
589 $c->res->from_psgi_response($app->($c->req->env));
592 Please note this does not attempt to map or nest your PSGI application under
593 the Controller and Action namespace or path. You may wish to review 'PSGI Helpers'
594 under L<Catalyst::Utils> for help in properly nesting applications.
596 B<NOTE> If your external PSGI application returns a response that has a character
597 set associated with the content type (such as "text/html; charset=UTF-8") we set
598 $c->clear_encoding to remove any additional content type encoding processing later
599 in the application (this is done to avoid double encoding issues).
601 =head2 encodable_content_type
603 This is a regular expression used to determine of the current content type
604 should be considered encodable. Currently we apply default encoding (usually
605 UTF8) to text type contents. Here's the default regular expression:
607 This would match content types like:
612 application/javascript
614 application/vnd.user+xml
616 B<NOTE>: We don't encode JSON content type responses by default since most
617 of the JSON serializers that are commonly used for this task will do so
618 automatically and we don't want to double encode. If you are not using a
619 tool like L<JSON> to produce JSON type content, (for example you are using
620 a template system, or creating the strings manually) you will need to either
621 encoding the body yourself:
623 $c->response->body( $c->encoding->encode( $body, $c->_encode_check ) );
625 Or you can alter the regular expression using this attribute.
627 =head2 encodable_response
629 Given a L<Catalyst::Response> return true if its one that can be encoded.
631 make sure there is an encoding set on the response
632 make sure the content type is encodable
633 make sure no content type charset has been already set to something different from the global encoding
634 make sure no content encoding is present.
636 Note this does not inspect a body since we do allow automatic encoding on streaming
641 sub encodable_response {
643 return 0 unless $self->_context; # Cases like returning a HTTP Exception response you don't have a context here...
644 return 0 unless $self->_context->encoding;
646 # The response is considered to have a 'manual charset' when a charset is already set on
647 # the content type of the response AND it is not the same as the one we set in encoding.
648 # If there is no charset OR we are asking for the one which is the same as the current
649 # required encoding, that is a flag that we want Catalyst to encode the response automatically.
650 my $has_manual_charset = 0;
651 if(my $charset = $self->content_type_charset) {
652 $has_manual_charset = (uc($charset) ne uc($self->_context->encoding->mime_name)) ? 1:0;
655 # Content type is encodable if it matches the regular expression stored in this attribute
656 my $encodable_content_type = $self->content_type =~ m/${\$self->encodable_content_type}/ ? 1:0;
658 # The content encoding is allowed (for charset encoding) only if its empty or is set to identity
659 my $allowed_content_encoding = (!$self->content_encoding || $self->content_encoding eq 'identity') ? 1:0;
661 # The content type must be an encodable type, and there must be NO manual charset and also
662 # the content encoding must be the allowed values;
664 $encodable_content_type and
665 !$has_manual_charset and
666 $allowed_content_encoding
676 Ensures that the response is flushed and closed at the end of the
689 defined $self->write($data) or return;
692 defined $self->write($,) or return;
693 defined $self->write($_) or return;
695 defined $self->write($\) or return;
702 Catalyst Contributors, see Catalyst.pm
706 This library is free software. You can redistribute it and/or modify
707 it under the same terms as Perl itself.
711 __PACKAGE__->meta->make_immutable;