X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=cgi%2Flibravatar.cgi;h=c280ac2da6e64054b0159b766a1f2e76ed2654b1;hb=b10a87938eb116b8871081643058052564e39603;hp=83a896b7820fd9e2dbe64ac4c08e658fa18c390f;hpb=2d8fff61383d49ae0829d338513070bcb3d0610e;p=debbugs.git diff --git a/cgi/libravatar.cgi b/cgi/libravatar.cgi old mode 100644 new mode 100755 index 83a896b..c280ac2 --- a/cgi/libravatar.cgi +++ b/cgi/libravatar.cgi @@ -3,20 +3,40 @@ use warnings; use strict; +# if we're running out of git, we want to use the git base directory as the +# first INC directory. If you're not running out of git, don't do that. +use File::Basename qw(dirname); +use Cwd qw(abs_path); +our $debbugs_dir; +BEGIN { + $debbugs_dir = + abs_path(dirname(abs_path(__FILE__)) . '/../'); + # clear the taint; we'll assume that the absolute path to __FILE__ is the + # right path if there's a .git directory there + ($debbugs_dir) = $debbugs_dir =~ /([[:print:]]+)/; + if (defined $debbugs_dir and + -d $debbugs_dir . '/.git/') { + } else { + undef $debbugs_dir; + } + # if the first directory in @INC is not an absolute directory, assume that + # someone has overridden us via -I. + if ($INC[0] !~ /^\//) { + } +} +use if defined $debbugs_dir, lib => $debbugs_dir.'/lib/'; + use Debbugs::Config qw(:config); use Debbugs::CGI qw(cgi_parameters); use Debbugs::Common; -use Digest::MD5 qw(md5_hex); -use Gravatar::URL; use File::LibMagic; -use File::Temp qw(tempfile); +use Debbugs::Libravatar qw(:libravatar); use Libravatar::URL; -use LWP::UserAgent; -use HTTP::Request; - use CGI::Simple; +use Cwd qw(abs_path); +use Digest::MD5 qw(md5_hex); my $q = CGI::Simple->new(); @@ -29,138 +49,71 @@ my %param = ); # if avatar is no, serve the empty png if ($param{avatar} ne 'yes' or not defined $param{email} or not length $param{email}) { - serve_cache('',$q); + serve_cache('',$q,0); exit 0; } -# figure out what the md5sum of the e-mail is. -my $email_md5sum = md5_hex(lc($param{email})); -my $cache_location = cache_location($email_md5sum); +my ($cache_location, $timestamp) = cache_location(email => lc($param{email})); # if we've got it, and it's less than one hour old, return it. -if (cache_valid($cache_location)) { - serve_cache($cache_location,$q); +if ($timestamp) { + serve_cache($cache_location,$q,$timestamp); exit 0; } # if we don't have it, get it, and store it in the cache -$cache_location = retreive_libravatar(location => $cache_location, - email => lc($param{email}), - ); +($cache_location,$timestamp) = + retrieve_libravatar(location => $cache_location, + email => lc($param{email}), + ); if (not defined $cache_location) { # failure, serve the default image - serve_cache('',$q); + serve_cache('',$q,0); exit 0; } else { - serve_cache($cache_location,$q); + serve_cache($cache_location,$q,$timestamp); exit 0; } -sub cache_valid{ - my ($cache_location) = @_; - if (-e $cache_location) { - if (time - (stat($cache_location))[9] < 60*60) { - return 1; - } - } - return 0; -} - -sub retreive_libravatar{ - my %type_mapping = - (jpeg => 'jpg', - png => 'png', - gif => 'png', - tiff => 'png', - tif => 'png', - pjpeg => 'jpg', - jpg => 'jpg' - ); - my %param = @_; - my $cache_location = $param{location}; - $cache_location =~ s/\.[^\.]+$//; - my $uri = libravatar_url(email => $param{email}, - default => 404, - size => 80); - my $ua = LWP::UserAgent->new(agent => 'Debbugs libravatar service (not Mozilla)', - ); - $ua->from($config{maintainer}); - # if we don't get an avatar within 10 seconds, return so we don't - # block forever - $ua->timeout(10); - # if the avatar is bigger than 30K, we don't want it either - $ua->max_size(30*1024); - my $r = $ua->get($uri); - if (not $r->is_success()) { - return undef; - } - my $aborted = $r->header('Client-Aborted'); - # if we exceeded max size, I'm not sure if we'll be successfull or - # not, but regardless, there will be a Client-Aborted header. Stop - # here if that header is defined. - return undef if defined $aborted; - my $type = $r->header('Content-Type'); - # if there's no content type, or it's not one we like, we won't - # bother going further - return undef if not defined $type; - return undef if not $type =~ m{^image/([^/]+)$}; - my $dest_type = $type_mapping{$1}; - return undef if not defined $dest_type; - # undo any content encoding - $r->decode() or return undef; - # ok, now we need to convert it from whatever it is into a format - # that we actually like - my ($temp_fh,$temp_fn) = tempfile() or - return undef; - eval { - print {$temp_fh} $r->content() or - die "Unable to print to temp file"; - close ($temp_fh); - system('convert','-resize','80x80', - '-strip', - $temp_fn, - $cache_location.'.'.$dest_type) == 0 or - die "convert file failed"; - unlink($temp_fh); - }; - if ($@) { - unlink($cache_location.'.'.$dest_type) if -e $cache_location.'.'.$dest_type; - unlink($temp_fn) if -e $temp_fn; - return undef; - } - return $cache_location.'.'.$dest_type; -} - -sub cache_location { - my ($md5sum) = @_; - for my $ext (qw(.png .jpg)) { - if (-e $config{libravatar_cache_dir}.'/'.$md5sum.$ext) { - return $config{libravatar_cache_dir}.'/'.$md5sum.$ext; - } - } - return $config{libravatar_cache_dir}.'/'.$md5sum; -} sub serve_cache { - my ($cache_location,$q) = @_; + my ($cache_location,$q,$timestamp) = @_; if (not defined $cache_location or not length $cache_location) { # serve the default image $cache_location = $config{libravatar_default_image}; + if (not defined $timestamp or not $timestamp) { + $timestamp = (stat($cache_location))[9]; + } + } + if (not defined $timestamp) { + # this probably means that the default image doesn't exist + print $q->header(status => 404); + print "404: Not found\n"; + return; + } + my $etag = md5_hex($cache_location.$timestamp); + if (defined $q->http('if-none-match') + and $etag eq $q->http('if-none-match')) { + print $q->header(-status => 304); + print "304: Not modified\n"; + return; } my $fh = IO::File->new($cache_location,'r') or - error(404, "Failed to open cached image $cache_location"); + error($q,404, "Failed to open cached image $cache_location"); my $m = File::LibMagic->new() or - error(500,'Unable to create File::LibMagic object'); - my $mime_string = $m->checktype_filename($cache_location) or - error(500,'Bad file; no mime known'); + error($q,500,'Unable to create File::LibMagic object'); + my $mime_string = $m->checktype_filename(abs_path($cache_location)) or + error($q,500,'Bad file; no mime known'); print $q->header(-type => $mime_string, - -expires => '+1d', - ); - print STDOUT <$fh>; + -expires => '+1d', + -status => 200, + -etag => $etag, + ); + print <$fh>; close($fh); } sub error { - my ($error,$text) = @_; + my ($q,$error,$text) = @_; $text //= ''; print $q->header(-status => $error); print "

$error: $text

";