Skip to content

Instantly share code, notes, and snippets.

@jasco
Last active May 26, 2022 20:46
Show Gist options
  • Save jasco/b633467545abf242ca0673630a10ddb6 to your computer and use it in GitHub Desktop.
Save jasco/b633467545abf242ca0673630a10ddb6 to your computer and use it in GitHub Desktop.
Apache Use Stored MD5 as ETAG
#!/usr/bin/perl
use strict;
$| = 1; # Turn off I/O buffering
sub sanitize {
my $fname = $_[0];
$fname =~ s#[^-_a-zA-Z0-9./]*##g;
$fname =~ s#/\.\.+/##g;
$fname =~ s%/+$%%;
return $fname;
}
while (<STDIN>) {
local $/ = undef; # slurp mode. Makes chomp ineffective.
# Remove whitespace. Input has a newline.
$_ =~ s/^\s+|\s+$//g;
# Verify that input appears sane or reject
if (sanitize($_) ne $_) {
print "\n";
next;
}
my $fname = $_ . '.md5';
open(my $fh, $fname) or print "\n" and next;
binmode $fh;
my $content = <$fh>;
close $fh;
# Remove any extraneous whitespace
$content =~ s/\s//sg;
# Verify that content is no longer than an md5 string.
if (length($content) > 32) {
print "\n";
next;
}
print $content . "\n";
}
<VirtualHost *:443>
# ....
# This looks for a static file *.md5 along side the requested
# file and, if found, returns the .md5 file contents as the etag.
# On request, the if-none-match value is compared with the
# value from the .md5 file contents.
#
# 1. Does not handle multiple etags in an array.
# 2. Uses a separator of | in check condition, which is actually
# a valid etag character. Should use a control character to
# avoid possible conflict.
# 3. Not tested but likely not compatible with etags that include
# embedded newlines.
# 4. In VirtualHost context, REQUEST_FILENAME is REQUEST_URI.
# This likely means must assume completely unsanitized.
#
# Reference https://serverfault.com/a/693079/425597 for use
# of RewriteMap with RewriteCond
RewriteMap getmd5 "prg:/opt/bin/get_etag.pl"
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.md5 -s
RewriteRule / - [E=ETAG:"${getmd5:%{DOCUMENT_ROOT}%{REQUEST_FILENAME}}"]
Header always set ETag %{ETAG}e env=ETAG
RewriteMap getmd5 "prg:/opt/bin/get_etag.pl"
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.md5 -s
RewriteCond "%{HTTP:If-None-Match}|${getmd5:%{DOCUMENT_ROOT}%{REQUEST_FILENAME}}" ^(?:W/)?"([^|]+)"\|\1$
RewriteRule ^(.*)$ $1 [R=304,L]
</VirtualHost>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment