| Plack documentation | Contained in the Plack distribution. |
Plack::Response - Portable HTTP Response object for PSGI response
use Plack::Response;
sub psgi_handler {
my $env = shift;
my $res = Plack::Response->new(200);
$res->content_type('text/html');
$res->body("Hello World");
return $res->finalize;
}
Plack::Response allows you a way to create PSGI response array ref through a simple API.
$res = Plack::Response->new; $res = Plack::Response->new($status); $res = Plack::Response->new($status, $headers); $res = Plack::Response->new($status, $headers, $body);
Creates a new Plack::Response object.
$res->status(200); $status = $res->status;
Sets and gets HTTP status code. code is an alias.
$headers = $res->headers;
$res->headers([ 'Content-Type' => 'text/html' ]);
$res->headers({ 'Content-Type' => 'text/html' });
$res->headers( HTTP::Headers->new );
Sets and gets HTTP headers of the response. Setter can take either an array ref, a hash ref or HTTP::Headers object containing a list of headers.
$res->body($body_str); $res->body([ "Hello", "World" ]); $res->body($io);
Gets and sets HTTP response body. Setter can take either a string, an
array ref, or an IO::Handle-like object. content is an alias.
Note that this method doesn't automatically set Content-Length for
the response. You have to set it manually if you want, with the
content_length method (see below).
$res->header('X-Foo' => 'bar');
my $val = $res->header('X-Foo');
Shortcut for $res->headers->header.
$res->content_type('text/plain');
$res->content_length(123);
$res->content_encoding('gzip');
Shortcut for the equivalent get/set methods in $res->headers.
$res->redirect($url); $res->redirect($url, 301);
Sets redirect URL with an optional status code, which defaults to 302.
Gets and sets Location header.
$res->cookies->{foo} = 123;
$res->cookies->{foo} = { value => '123' };
Returns a hash reference containing cookies to be set in the
response. The keys of the hash are the cookies' names, and their
corresponding values are a plain string (for value with everything
else defaults) or a hash reference that can contain keys such as
value, domain, expires, path, httponly, secure.
expires can take a string or an integer (as an epoch time) and
does not convert string formats such as +3M.
$res->cookies->{foo} = {
value => 'test',
path => "/",
domain => '.example.com',
expires => time + 24 * 60 * 60,
};
$res->finalize;
Returns the status code, headers, and body of this response as a PSGI response array reference.
Tokuhiro Matsuno
Tatsuhiko Miyagawa
| Plack documentation | Contained in the Plack distribution. |
package Plack::Response; use strict; use warnings; our $VERSION = '0.9980'; $VERSION = eval $VERSION; use Plack::Util::Accessor qw(body status); use Carp (); use Scalar::Util (); use HTTP::Headers; use URI::Escape (); sub code { shift->status(@_) } sub content { shift->body(@_) } sub new { my($class, $rc, $headers, $content) = @_; my $self = bless {}, $class; $self->status($rc) if defined $rc; $self->headers($headers) if defined $headers; $self->body($content) if defined $content; $self; } sub headers { my $self = shift; if (@_) { my $headers = shift; if (ref $headers eq 'ARRAY') { Carp::carp("Odd number of headers") if @$headers % 2 != 0; $headers = HTTP::Headers->new(@$headers); } elsif (ref $headers eq 'HASH') { $headers = HTTP::Headers->new(%$headers); } return $self->{headers} = $headers; } else { return $self->{headers} ||= HTTP::Headers->new(); } } sub cookies { my $self = shift; if (@_) { $self->{cookies} = shift; } else { return $self->{cookies} ||= +{ }; } } sub header { shift->headers->header(@_) } # shortcut sub content_length { shift->headers->content_length(@_); } sub content_type { shift->headers->content_type(@_); } sub content_encoding { shift->headers->content_encoding(@_); } sub location { shift->headers->header('Location' => @_); } sub redirect { my $self = shift; if (@_) { my $url = shift; my $status = shift || 302; $self->location($url); $self->status($status); } return $self->location; } sub finalize { my $self = shift; Carp::croak "missing status" unless $self->status(); $self->_finalize_cookies(); return [ $self->status, +[ map { my $k = $_; map { ( $k => $_ ) } $self->headers->header($_); } $self->headers->header_field_names ], $self->_body, ]; } sub _body { my $self = shift; my $body = $self->body; $body = [] unless defined $body; if (!ref $body or Scalar::Util::blessed($body) && overload::Method($body, q("")) && !$body->can('getline')) { return [ $body ]; } else { return $body; } } sub _finalize_cookies { my $self = shift; while (my($name, $val) = each %{$self->cookies}) { my $cookie = $self->_bake_cookie($name, $val); $self->headers->push_header( 'Set-Cookie' => $cookie ); } } sub _bake_cookie { my($self, $name, $val) = @_; return '' unless defined $val; $val = { value => $val } unless ref $val eq 'HASH'; my @cookie = ( URI::Escape::uri_escape($name) . "=" . URI::Escape::uri_escape($val->{value}) ); push @cookie, "domain=" . $val->{domain} if $val->{domain}; push @cookie, "path=" . $val->{path} if $val->{path}; push @cookie, "expires=" . $self->_date($val->{expires}) if $val->{expires}; push @cookie, "secure" if $val->{secure}; push @cookie, "HttpOnly" if $val->{httponly}; return join "; ", @cookie; } my @MON = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ); my @WDAY = qw( Sun Mon Tue Wed Thu Fri Sat ); sub _date { my($self, $expires) = @_; if ($expires =~ /^\d+$/) { # all numbers -> epoch date # (cookies use '-' as date separator, HTTP uses ' ') my($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($expires); $year += 1900; return sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT", $WDAY[$wday], $mday, $MON[$mon], $year, $hour, $min, $sec); } return $expires; } 1; __END__