I have a working Mojolicious server that provides data with HTML5 EventSource. Works well but I would like the data to be encoded in gzip format.
Sending compressed data with a write gives a CONTENT_DECODING_FAILED in Chrome Dev tools. Using the suggested method with "hook after_render" does not seem to work with event-stream. How can I send gzip encoded data using EventSource and Mojolicious ?
use Mojolicious::Lite;
use Mojo::Redis;
use IO::Compress::Gzip 'gzip';
my $redis = Mojo::Redis->new;
get 'radar_events' => sub {
my $c = shift;
$c->render_later;
$c->inactivity_timeout(300);
$c->res->headers->content_type('text/event-stream');
$c->res->headers->cache_control('no_cache');
$c->res->headers->content_encoding('gzip');
$c->res->headers->header( 'Access-Control-Allow-Origin' => '*' );
my $id = Mojo::IOLoop->recurring(
5 => sub {
$c->delay(
sub {
my $delay = shift;
$redis->get( 'radar', $delay->begin );
},
sub {
my ( $delay, $jstring ) = @_;
my $buf = "event:rupdate\ndata: ".$jstring."\n\n";
gzip \$jstring => \my $buf;
$c->write($buf);
}
);
}
);
$c->on( finish => sub { Mojo::IOLoop->remove($id) } );
};
app->start;
I think it is not possible the way you do it. Content-Encoding is the encoding of whole body, which includes the event:rupdate\n
and data:....
messages. Also, each event message is a single line (see the specification), so you cannot transfer binary data (like compressed data) this way.
I don't know if the browser support Content-Encoding with event streams. But if they do, you would need to provide a single gzip stream, starting with the begin of the body and only ending once your are done. And since gzip buffers data to achieve better compression you would need to explicitly flush the gzip object after each event you've added.