The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Plack::App::CGIBin::Streaming::Request - a helper module for Plack::App::CGIBin::Streaming

SYNOPSIS

 my $r=Plack::App::CGIBin::Streaming::Request->new(
     env => $env,               # set the PSGI environment
     responder => $responder,   # set the responder (streaming protocol)
     max_buffer => 20000,
     parse_headers => 1,
     content_type => 'text/html; charset=utf-8',
     filter_before => sub {...},
     filter_after => sub {...},
     on_status_output => sub {...},
     on_flush => sub {...},
     on_finalize => sub {...},
 );

 $r->writer=$writer;            # set the writer (streaming protocol)

 $r->notes->{key}=$value;
 $r->status=404;
 $r->content_type='text/html; charset=iso-8859-15';
 $r->parse_headers=1;

 $r->print_header(key=>$value, ...);
 $r->print_content(@content);
 $r->flush;
 warn "It's too late to set the HTTP status" if $r->status_written;

 $r->finalize;

 $r->env;                       # access the PSGI environment

DESCRIPTION

Every object of this class represents an HTTP request in the Plack::App::CGIBin::Streaming environment.

An Plack::App::CGIBin::Streaming application creates the object. It is then accessible by the actual CGI script.

To write a normal CGI script you don't need to know about this module.

Methods

The methods of this module can be categorized into several groups:

  • public methods to be used by CGI scripts

  • methods or parameters mainly passed to the constructor

  • methods to be used by the Plack::App::CGIBin::Streaming system

  • private stuff

Public Methods

$r->status($status)

represents the current HTTP status of the request. You can assign new values at any time. However, to have any effect on the HTTP response it must be called before status_written becomes true.

$r->status_written

returns false if print_header, status or content_type affect the HTTP response seen by the client.

$r->content_type($type)

represents the current Content-Type of the request. You can assign new values at any time. However, to have any effect on the HTTP response it must be called before status_written becomes true.

$r->print_header($headername, $headervalue, ...)

sets HTTP headers.

Both, headername and headervalue, must not contain wide characters.

$r->print_content($content, ...)

prints to the response body. This output is buffered up to the first flush call. The buffer is automatically flushed when its size exceeds max_buffer bytes.

The printed content must not contain wide characters.

In the Plack::App::CGIBin::Streaming environment, this method is automatically called when you print to STDOUT. To be UTF8-safe, best if you push the utf8 PerlIO layer and use print.

 binmode STDOUT, ':utf8';
$r->flush

flushes the currently buffered output. The first flush operation also sends out the HTTP headers and the response status.

If nothing is currently buffered, flush returns immediately. It won't send out only the HTTP headers. If you really want to do that, use $r->_status_out.

$r->notes

returns a hash reference where you can store data that is to be thrown away when the request is finished. (similar to $r->pnotes in modperl)

$r->env

returns the PSGI environment hash of the request.

Constructor Parameters

All of these parameters are also accessible as lvalue methods on the object. If called with a value, the value is assigned to the parameter. In any case the parameter value is returned and in lvalue context can be assigned to.

So,

 $r->flag=$val

and

 $r->flag($val)

is the same, except that former is probably a bit faster. You could even

 $r->flag($dummy)=$val

However, that does not make much sense.

status
content_type
env
notes

These methods are implemented as constructor parameters. That's why they are mentioned here. They are documented already above.

Default values for status and content_type are 200 and text/plain. They can be changed by means of the request_params parameter in the *.psgi file like:

 Plack::App::CGIBin::Streaming->new(
     root=>...,
     request_params=>[
         status=>404,
         content_type=>'text/html; charset=utf-8',
         ...
     ]
 )->to_app;

The default content type can also be set by assigning to $Plack::App::CGIBin::Streaming::Request::DEFAULT_CONTEN_TYPE.

max_buffer

The max. amount of data buffered by print_content. For best performance, you need to find a trade-off between RAM consumption and buffering.

A HTTP/1.1 server like Starman will use chunked transfer encoding if at the time the HTTP header fields are sent the content length is not determined. This usually shows worse performance than sending the whole response in one go.

If your response body is shorter that max_buffer bytes and you never call flush, the request object will figure out the content length for you and send the response in one chunk.

The default value for max_buffer is 8000. This is enough for most AJAX responses but probably far too low for HTML pages.

Usually the value is set as configuration parameter in the *.psgi file like

 Plack::App::CGIBin::Streaming->new(
     root=>...,
     request_params=>[
         max_buffers=>50000,
         ...
     ]
 )->to_app;

Though, you can set it at any time. It will affect all subsequent print_content calls.

parse_headers

to have any effect this option must be set before the first print_content call. Usually it is set as configuration parameter in the *.psgi file like

 Plack::App::CGIBin::Streaming->new(
     root=>...,
     request_params=>[
         parse_headers=>1,
         ...
     ]
 )->to_app;

If set, the request object parses the data stream passed to print_content for HTTP header fields. When the header block is parsed, the parameter is automatically reset to false to prevent further parsing. This means the value changes over the lifetime of the request.

If set, you can send your response including HTTP headers like this:

 print STDOUT <<'EOF';
 Status: 404
 X-reason: the device is currently not mounted

 <html>
 ...
 </html>
 EOF
filter_before
filter_after

These 2 parameters can be used to filter the print output. Both are assigned coderefs like

 Plack::App::CGIBin::Streaming->new(
     root=>...,
     request_params=>[
         filter_before=>sub {
             my ($request, $list);
             ...
         },
         filter_after=>sub {
             my ($request, $list);
             ...
         },
         ...
     ]
 )->to_app;

The coderefs are called with 2 parameters. The first one is the request object, the 2nd one is an array of strings to be printed.

filter_before is called before actually printing. If you need to modify the output, that's the place to do it. Just modify the $list.

filter_after is called after the printing. It can be used for example to flush after the <head> section is put out.

There is no filter queue. If you need to implement that, best if you daisy-chain the filters like:

 sub insert_before_filter {
     my $app=shift;
     my $filter=shift;

     unless ($app->request_params) {
         $app->request_params=[filter_before=$filter];
         return;
     }
     my $list=$app->request_params;
     for (my $i=0; $i<@$list; $i+=2) {
         if ($list->[$i] eq 'filter_before') {
             my $old_filter=$list->[$i+1];
             $list->[$i+1]=sub {
                 my ($r, $data)=@_;
                 $filter->($r, $data);
                 $old_filter->($r, $data);
             }
             return;
         }
     }
     push @$list, filter_before=>$filter;
     return;
 }

Alternatively, you can implement a new module that inherits from this one and pass the name as request_class to the app constructor like:

 Plack::App::CGIBin::Streaming->new(
     root=>...,
     request_class=>'My::Request::Class',
 )->to_app;

To remove a filter just assign an empty subroutine:

 $r->filter_before=sub {};

This can also be done from within a filter when you know you are done.

on_status_output
on_flush
on_finalize

These parameters are also coderefs. All of them are called with one parameter, the request object.

on_status_output is called just before the HTTP status and the HTTP header fields are sent to the client. It can be used to inspect the headers one last time and to perhaps append another one.

There is one use case in particular where you might want to this hook. Proxy servers like nginx usually also buffer your response body. But they allow to turn that off by means of a HTTP output header.

 Plack::App::CGIBin::Streaming->new(
     root=>...,
     request_params=>[
         on_status_out=>sub {
             my $r=$_[0];

             $r->print_header('X-Accel-Buffering', 'no')
                 if $r->status==200 and $r->content_type=~m!^text/html!i;
         },
         ...
     ]
 )->to_app;

on_flush is called after every flush operation.

on_finalize is called before the request is finished. Actually, it's the first step of the finalize operation. At this stage you are still able to print stuff. So, it's a good place to add a footer or similar.

suppress_flush

In Perl, there is a number of operations that implicitly preform flush operations on file handles, like system.

If you want complete control over when flush is issued, set this to a true value. It does not affect $r->flush calls or implicit flushes caused by overflowing the output buffer (see max_buffer). This flag only affects flushes caused by the PerlIO layer. So, if true, output is buffered even if $| (autoflush) is true for the file handle.

Note, this requires the Plack::App::CGIBin::Streaming::IO PerlIO layer to be pushed onto the file handle. In the Plack::App::CGIBin::Streaming environment, this is usually the case for STDOUT.

Methods mainly used by the Plack::App::CGIBin::Streaming system

responder
writer

Here the responder and write callbacks are stored that implement the PSGI streaming protocol.

finalize

This method is called by Plack::App::CGIBin::Streaming after the compiled CGI script returns. It prints out the remaining buffers and it makes the request object almost unusable. So, even if you by accident save the request object in a closure or similar, you cannot print to it. This is achieved by reblessing the object into another class and scraping out the guts of the object.

The only methods allowed on the reblessed object are flush, finalize and DESTROY.

Internal Methods

_buffer
_buflen
_headers
_header_buffer

these are just internal variables

_status_out

this method is called to put out the HTTP status and header fields.

AUTHOR

Torsten Förtsch <torsten.foertsch@gmx.net>

COPYRIGHT

Copyright 2014 Binary.com

LICENSE

This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). A copy of the full license is provided by the LICENSE file in this distribution and can be obtained at

http://www.perlfoundation.org/artistic_license_2_0

SEE ALSO