]> git.donarmstrong.com Git - debbugs.git/blobdiff - cgi/libravatar.cgi
Use ETags; return timestamp not is_valid
[debbugs.git] / cgi / libravatar.cgi
old mode 100644 (file)
new mode 100755 (executable)
index 83a896b..81f9c73
@@ -6,17 +6,14 @@ use strict;
 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 +26,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 "<h2>$error: $text</h2>";