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