Plack::Middleware::ConditionalGET - Middleware to enable conditional GET


Plack documentation Contained in the Plack distribution.

Index


Code Index:

NAME

Top

Plack::Middleware::ConditionalGET - Middleware to enable conditional GET

SYNOPSIS

Top

  builder {
      enable "ConditionalGET";
      ....
  };

DESCRIPTION

Top

This middleware enables conditional GET and HEAD using If-None-Match and If-Modified-Since header. The application should set either or both of Last-Modified or ETag response headers per RFC 2616. When either of the conditions is met, the response body is set to be zero length and the status is set to 304 Not Modified.

SEE ALSO

Top

Rack::ConditionalGet


Plack documentation Contained in the Plack distribution.

package Plack::Middleware::ConditionalGET;
use strict;
use parent qw( Plack::Middleware );
use Plack::Util;

sub call {
    my $self = shift;
    my $env  = shift;

    my $res = $self->app->($env);
    return $res unless $env->{REQUEST_METHOD} =~ /^(GET|HEAD)$/;

    $self->response_cb($res, sub {
        my $res = shift;
        return unless $res->[2]; # do not support streaming interface

        my $h = Plack::Util::headers($res->[1]);
        if ( $self->etag_matches($h, $env) || $self->not_modified_since($h, $env) ) {
            $res->[0] = 304;
            $h->remove($_) for qw( Content-Type Content-Length Content-Disposition );
            $res->[2] = [];
        }
    });
}

no warnings 'uninitialized';

sub etag_matches {
    my($self, $h, $env) = @_;
    $h->exists('ETag') && $h->get('ETag') eq _value($env->{HTTP_IF_NONE_MATCH});
}

sub not_modified_since {
    my($self, $h, $env) = @_;
    $h->exists('Last-Modified') && $h->get('Last-Modified') eq _value($env->{HTTP_IF_MODIFIED_SINCE});
}

sub _value {
    my $str = shift;
    # IE sends wrong formatted value(i.e. "Thu, 03 Dec 2009 01:46:32 GMT; length=17936")
    $str =~ s/;.*$//;
    return $str;
}

1;

__END__