Skip to content

Instantly share code, notes, and snippets.

@anazawa
Created April 4, 2013 20:51
Show Gist options
  • Save anazawa/5314251 to your computer and use it in GitHub Desktop.
Save anazawa/5314251 to your computer and use it in GitHub Desktop.
Blosxom Plug-in: static and conditional_get
package static;
use strict;
use warnings;
use Blosxom::Header;
use FindBin;
our $dir = "$FindBin::Bin/blosxom/static";
our $url = "$blosxom::url/static";
my %MIME_Types = (
".css" => "text/css",
".jpeg" => "image/jpeg",
".jpg" => "image/jpeg",
".png" => "image/png",
);
my @path;
sub start {
@path = split '/', $blosxom::path_info;
@path and $path[0] eq 'static' and shift @path;
}
sub skip {
my $file = join '/', $dir, @path;
my $header = Blosxom::Header->instance;
require HTTP::Date;
if ( !-f $file ) {
$header->status('404 Not Found')->type('text/plain');
return $blosxom::output = 'not found';
}
if ( !-r $file ) {
$header->status('403 Forbidden')->type('text/plain');
return $blosxom::output = 'forbidden';
}
my @stat = stat $file;
my $last_modified = HTTP::Date::time2str( $stat[9] );
my $if_modified_since = $ENV{HTTP_IF_MODIFIED_SINCE} || q{};
my $request_method = $ENV{REQUEST_METHOD};
$header->set( 'Last-Modified' => $last_modified );
if ( $request_method eq 'GET' or $request_method eq 'HEAD' ) {
if ( $last_modified eq $if_modified_since ) {
$header->status('304 Not Modified')->type(q{});
$blosxom::output = q{};
return 1;
}
}
my $type = _mime_type($file) || 'text/plain';
my $charset = $type =~ m{^text/} ? 'utf-8' : q{};
$header->type( $type )->charset( $charset );
$header->set( 'Content-Length' => $stat[7] );
if ( $request_method eq 'HEAD' ) {
$blosxom::output = q{};
}
elsif ( open my $fh, "< $file" ) {
binmode $fh;
while ( read $fh, my $buffer, 1024 ) {
$blosxom::output .= $buffer;
}
close $fh;
}
else {
require Carp;
Carp::croak "Can't open $file: $!";
}
1;
}
sub end {
undef @path;
}
sub _mime_type {
my $file = shift;
$file =~ /(\.[a-zA-Z0-9]+)$/ && $MIME_Types{ lc $1 };
}
1;
package conditional_get;
use strict;
use warnings;
use Blosxom::Header;
my @last_modified;
sub start {
!$blosxom::static_entries;
}
sub date {
my $time = $_[3];
push @last_modified, $time;
}
sub last {
my $header = Blosxom::Header->instance;
my $time = ( sort { $b <=> $a } @last_modified )[0];
require HTTP::Date;
if ( defined $time ) {
my $last_modified = HTTP::Date::time2str( $time );
my $if_modified_since = $ENV{HTTP_IF_MODIFIED_SINCE} || q{};
my $request_method = $ENV{REQUEST_METHOD};
$header->set( 'Last-Modified' => $last_modified );
if ( $request_method eq 'GET' or $request_method eq 'HEAD' ) {
if ( $last_modified eq $if_modified_since ) {
$header->status('304 Not Modified')->type(q{});
$blosxom::output = q{}; # truncate output
return;
}
}
}
elsif ( !$header->status ) {
$header->status('404 Not Found')->type('text/plain');
$blosxom::output = 'not found';
}
$header->set( 'Content-Length' => length $blosxom::output );
return;
}
sub end {
undef @last_modified;
}
1;
package Blosxom::Header;
use strict;
use warnings;
use parent 'CGI::Header::Props';
our $INSTANCE;
sub new {
require Carp;
Carp::croak "Private method 'new' called for $_[0]";
}
sub instance {
$INSTANCE ||= $_[0]->SUPER::new( header => $blosxom::header )->rehash;
}
sub has_instance {
$INSTANCE;
}
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment