use Moose;
use HTTP::Headers;
use Moose::Util::TypeConstraints;
-use namespace::autoclean;
use Scalar::Util 'blessed';
use Catalyst::Response::Writer;
use Catalyst::Utils ();
+use namespace::clean -except => ['meta'];
+
with 'MooseX::Emulate::Class::Accessor::Fast';
our $DEFAULT_ENCODE_CONTENT_TYPE_MATCH = qr{text|xml$|javascript$};
has _response_cb => (
is => 'ro',
- isa => 'CodeRef',
+ isa => 'CodeRef',
writer => '_set_response_cb',
clearer => '_clear_response_cb',
predicate => '_has_response_cb',
clearer => '_clear_context',
);
-before [qw(status headers content_encoding content_length content_type header)] => sub {
+before [qw(status headers content_encoding content_length content_type )] => sub {
+ my $self = shift;
+
+ $self->_context->log->warn(
+ "Useless setting a header value after finalize_headers and the response callback has been called." .
+ " Since we don't support tail headers this will not work as you might expect." )
+ if ( $self->_context && $self->finalized_headers && !$self->_has_response_cb && @_ );
+};
+
+# This has to be different since the first param to ->header is the header name and presumably
+# you should be able to request the header even after finalization, just not try to change it.
+before 'header' => sub {
my $self = shift;
+ my $header = shift;
- $self->_context->log->warn(
+ $self->_context->log->warn(
"Useless setting a header value after finalize_headers and the response callback has been called." .
- " Not what you want." )
- if ( $self->finalized_headers && !$self->_has_response_cb && @_ );
+ " Since we don't support tail headers this will not work as you might expect." )
+ if ( $self->_context && $self->finalized_headers && !$self->_has_response_cb && @_ );
};
sub output { shift->body(@_) }
return $len;
}
+sub unencoded_write {
+ my ( $self, $buffer ) = @_;
+
+ # Finalize headers if someone manually writes output
+ $self->_context->finalize_headers unless $self->finalized_headers;
+
+ $buffer = q[] unless defined $buffer;
+
+ my $len = length($buffer);
+ $self->_writer->write($buffer);
+
+ return $len;
+}
+
sub finalize_headers {
my ($self) = @_;
return;
my ($status, $headers, $body) = @$psgi_res;
$self->status($status);
$self->headers(HTTP::Headers->new(@$headers));
- $self->body(join('', @$body));
+ # Can be arrayref or filehandle...
+ if(defined $body) { # probably paranoia
+ ref $body eq 'ARRAY' ? $self->body(join('', @$body)) : $self->body($body);
+ }
} elsif(ref $psgi_res eq 'CODE') {
$psgi_res->(sub {
my $response = shift;
$self->status($status);
$self->headers(HTTP::Headers->new(@$headers));
if(defined $maybe_body) {
- $self->body(join('', @$maybe_body));
+ # Can be arrayref or filehandle...
+ ref $maybe_body eq 'ARRAY' ? $self->body(join('', @$maybe_body)) : $self->body($maybe_body);
} else {
return $self->write_fh;
}
- });
+ });
} else {
die "You can't set a Catalyst response from that, expect a valid PSGI response";
}
$c->response->body('Catalyst rocks!');
Sets or returns the output (text or binary data). If you are returning a large body,
-you might want to use a L<IO::Handle> type of object (Something that implements the getline method
+you might want to use a L<IO::Handle> type of object (Something that implements the getline method
in the same fashion), or a filehandle GLOB. These will be passed down to the PSGI
handler you are using and might be optimized using server specific abilities (for
example L<Twiggy> will attempt to server a real local file in a non blocking manner).
already set in the response headers Catalyst will make a reasonable attempt
to determine the size of the Handle. Depending on the implementation of your
handle object, setting the content length may fail. If it is at all possible
-for you to determine the content length of your handle object,
+for you to determine the content length of your handle object,
it is recommended that you set the content length in the response headers
yourself, which will be respected and sent by Catalyst in the response.
and the HEAD section of your document and then set the body from a template
driven from a database. In some cases this can seem to the client as if you had
a faster overall response (but note that unless your server support chunked
-body your content is likely to get queued anyway (L<Starman> and most other
+body your content is likely to get queued anyway (L<Starman> and most other
http 1.1 webservers support this).
If there is an encoding set, we encode each line of the response (the default
encoding is UTF-8).
+=head2 $res->unencoded_write( $data )
+
+Works just like ->write but we don't apply any content encoding to C<$data>. Use
+this if you are already encoding the $data or the data is arriving from an encoded
+storage.
+
=head2 $res->write_fh
Returns an instance of L<Catalyst::Response::Writer>, which is a lightweight
Prints @data to the output stream, separated by $,. This lets you pass
the response object to functions that want to write to an L<IO::Handle>.
-=head2 $self->finalize_headers($c)
+=head2 $res->finalize_headers()
Writes headers to response if not already written
=head2 encodable_response
-Given a L<Catalyst::Response> return true if its one that can be encoded.
+Given a L<Catalyst::Response> return true if its one that can be encoded.
make sure there is an encoding set on the response
make sure the content type is encodable