Catalyst-Runtime

 view release on metacpan or  search on metacpan

lib/Catalyst/UTF8.pod  view on Meta::CPAN

This will use the alternative encoding for a single response.

B<NOTE> If you manually set the content-type character set to whatever $c->encoding->mime_name
is set to, we STILL encode, rather than assume your manual setting is a flag to override.  This
is done to support backward compatible assumptions (in particular L<Catalyst::View::TT> has set
a utf-8 character set in its default content-type for ages, even though it does not itself do any
encoding on the body response).  If you are going to handle encoding manually you may set
$c->clear_encoding for a single request response cycle, or as in the above example set an alternative
encoding.

=head2 Encoding with streaming type responses

L<Catalyst> offers two approaches to streaming your body response.  Again, you must remember
to set your content type prior to streaming, since invoking a streaming response will automatically
finalize and send your HTTP headers (and your content type MUST be one that matches the regular
expression given above.)

Also, if you are going to override $c->encoding (or invoke $c->clear_encoding), you should do
that before anything else!

The first streaming method is to use the C<write> method on the response object.  This method
allows 'inlined' streaming and is generally used with blocking style servers.

    sub stream_write :Local {
        my ($self, $c) = @_;
        $c->response->content_type('text/html');
        $c->response->write("<p>This is stream_write action ♥</p>");
    }

You may call the C<write> method as often as you need to finish streaming all your content.
L<Catalyst> will encode each line in turn as long as the content-type meets the 'encodable types'
requirement and $c->encoding is set (which it is, as long as you did not change it).

B<NOTE> If you try to change the encoding after you start the stream, this will invoke an error
response.  However since you've already started streaming this will not show up as an HTTP error
status code, but rather error information in your body response and an error in your logs.

B<NOTE> If you use ->body AFTER using ->write (for example you may do this to write your HTML
HEAD information as fast as possible) we expect the contents to body to be encoded as it
normally would be if you never called ->write.  In general unless you are doing weird custom
stuff with encoding this is likely to just already do the correct thing.

The second way to stream a response is to get the response writer object and invoke methods
on that directly:

    sub stream_write_fh :Local {
        my ($self, $c) = @_;
        $c->response->content_type('text/html');

        my $writer = $c->res->write_fh;
        $writer->write_encoded('<p>This is stream_write_fh action ♥</p>');
        $writer->close;
    }

This can be used just like the C<write> method, but typically you request this object when
you want to do a nonblocking style response since the writer object can be closed over or
sent to a model that will invoke it in a non blocking manner.  For more on using the writer
object for non blocking responses you should review the C<Catalyst> documentation and also
you can look at several articles from last years advent, in particular:

L<http://catalyst.perl.org/calendar/2013/10>, L<http://catalyst.perl.org/calendar/2013/11>,
L<http://catalyst.perl.org/calendar/2013/12>, L<http://catalyst.perl.org/calendar/2013/13>,
L<http://catalyst.perl.org/calendar/2013/14>.

The main difference this year is that previously calling ->write_fh would return the actual
L<Plack> writer object that was supplied by your Plack application handler, whereas now we wrap
that object in a lightweight decorator object that proxies the C<write> and C<close> methods
and supplies an additional C<write_encoded> method.  C<write_encoded> does the exact same thing
as C<write> except that it will first encode the string when necessary.  In general if you are
streaming encodable content such as HTML this is the method to use.  If you are streaming
binary content, you should just use the C<write> method (although if the content type is set
correctly we would skip encoding anyway, but you may as well avoid the extra noop overhead).

The last style of content response that L<Catalyst> supports is setting the body to a filehandle
like object.  In this case the object is passed down to the Plack application handler directly
and currently we do nothing to set encoding.

    sub stream_body_fh :Local {
        my ($self, $c) = @_;
        my $path = File::Spec->catfile('t', 'utf8.txt');
        open(my $fh, '<', $path) || die "trouble: $!";
        $c->response->content_type('text/html');
        $c->response->body($fh);
    }

In this example we create a filehandle to a text file that contains UTF8 encoded characters. We
pass this down without modification, which I think is correct since we don't want to double
encode.  However this may change in a future development release so please be sure to double
check the current docs and changelog.  Its possible a future release will require you to to set
a encoding on the IO layer level so that we can be sure to properly encode at body finalization.
So this is still an edge case we are writing test examples for.  But for now if you are returning
a filehandle like response, you are expected to make sure you are following the L<PSGI> specification
and return raw bytes.

=head2 Override the Encoding on Context

As already noted you may change the current encoding (or remove it) by setting an alternative
encoding on the context;

    $c->encoding(Encode::find_encoding('Shift_JIS'));

Please note that you can continue to change encoding UNTIL the headers have been finalized.  The
last setting always wins.  Trying to change encoding after header finalization is an error.

=head2 Setting the Content Encoding HTTP Header

In some cases you may set a content encoding on your response.  For example if you are encoding
your response with gzip.  In this case you are again on your own.  If we notice that the
content encoding header is set when we hit finalization, we skip automatic encoding:

    use Encode;
    use Compress::Zlib;
    use utf8;

    sub gzipped :Local {
        my ($self, $c) = @_;

        $c->res->content_type('text/plain');
        $c->res->content_type_charset('UTF-8');
        $c->res->content_encoding('gzip');

        $c->response->body(
          Compress::Zlib::memGzip(



( run in 0.592 second using v1.01-cache-2.11-cpan-39bf76dae61 )