Skip to content

Instantly share code, notes, and snippets.

@kwmiebach
Forked from sivel/ContentMD5-ReqDotMD5.pm
Last active May 6, 2017 10:02
Show Gist options
  • Save kwmiebach/2f03baaae7e4f86f9573f1f30818d36f to your computer and use it in GitHub Desktop.
Save kwmiebach/2f03baaae7e4f86f9573f1f30818d36f to your computer and use it in GitHub Desktop.
NGINX Perl Module to Output Content-MD5 HTTP Header

NGINX module to generate base64 content-md5 header

Can add a content-md5 header on the fly or read the pregenerated value from a file.

Links

Link to the original version: https://gist.github.com/sivel/1870822

Rackspace blog with comments: https://blog.rackspace.com/add-the-content-md5-http-header-to-nginx

This version, with modifications: https://gist.github.com/kwmiebach/2f03baaae7e4f86f9573f1f30818d36f

NGINX perl module http://nginx.org/en/docs/http/ngx_http_perl_module.html

apache2.4 ContentDigest directive: https://httpd.apache.org/docs/2.4/mod/core.html#contentdigest

RFC1864: https://tools.ietf.org/html/rfc1864

Installation

1) You need NGINX with perl module.

You can use the debian nginx package : https://packages.debian.org/stable/nginx-extras

sudo apt install nginx-extras

Or compile nginx yourself with perl module.

2) Install one of the script versions

Choose one of the scripts, there are versions with or without checking of pregenerated md5.

Only the version ContentM5.md generates a base64 encoded value, which is what RFC1864 requires. It is designed to generate exactly the same value as the apache2 'ContentDigest On' directive from apache2 core: https://httpd.apache.org/docs/2.4/mod/core.html#contentdigest

To avoid confusion the other versions have been edited to generate a header with the custom name "Content-MD5-Hex".

Place the perl script in a perl library that nginx finds, and name it ContentMD5.pm

Example:

sudo mkdir -p /usr/share/nginx/perl/lib
cd /usr/share/nginx/perl/lib
sudo curl -O https://gist.githubusercontent.com/kwmiebach/2f03baaae7e4f86f9573f1f30818d36f/raw/ContentMD5.pm
ls

3) Configure NGINX Vhost

See the vhost examples below. Restart nginx afterwards:

servic nginx restart

Author and Copyright

Author: Matt Martz matt@sivel.net modifications by kwmiebach

License: http://www.nginx.org/LICENSE

# nginx Embedded Perl module for adding a Content-MD5 HTTP header
#
# THIS VERSION GENERATES A BASE64 ENCODED VALUE AS REQUIRED BY RFC1864
#
# This perl module, will output an MD5 of a requested file using the
# Content-MD5 HTTP header, calculating the MD5 BASE64 hash on the fly.
#
# Author: Matt Martz <matt@sivel.net>
# Link to the original version: https://gist.github.com/sivel/1870822
# This version, with modifications:
# https://gist.github.com/kwmiebach/2f03baaae7e4f86f9573f1f30818d36f
# License: http://www.nginx.org/LICENSE
package ContentMD5;
use nginx;
use Digest::MD5;
sub handler {
my $r = shift;
my $filename = $r->filename;
return DECLINED unless -f $filename;
my $content_length = -s $filename;
my $md5;
open( FILE, $filename ) or return DECLINED;
my $ctx = Digest::MD5->new;
$ctx->addfile( *FILE );
# see http://search.cpan.org/dist/Digest-MD5/MD5.pm
$md5 = $ctx->b64digest.'==';
close( FILE );
$r->header_out( "Content-MD5", $md5 ) unless ! $md5;
return DECLINED;
}
1;
__END__
# nginx Embedded Perl module for adding a Content-MD5 HTTP header
#
# THIS VERSION GENERATES A HEX ENCODED VALUE BUT RFC1864 REQUIRES BASE64
#
# This perl module, will output an MD5 of a requested file using the
# Content-MD5 HTTP header, by either pulling it from a file of the
# same name with .md5 appended to the end, if it exists, or will
# calculate the MD5 hex hash on the fly
#
# Author: Matt Martz <matt@sivel.net>
# Link to the original version: https://gist.github.com/sivel/1870822
# This version, with modifications:
# https://gist.github.com/kwmiebach/2f03baaae7e4f86f9573f1f30818d36f
# License: http://www.nginx.org/LICENSE
package ContentMD5;
use nginx;
use Digest::MD5;
sub handler {
my $r = shift;
my $filename = $r->filename;
return DECLINED unless -f $filename;
my $content_length = -s $filename;
my $md5;
if ( -f "$filename.md5" ) {
open( MD5FILE, "$filename.md5" ) or return DECLINED;
$md5 = <MD5FILE>;
close( MD5FILE );
$md5 =~ s/^\s+//;
$md5 =~ s/\s+$//;
$md5 =~ s/\ .*//;
} else {
open( FILE, $filename ) or return DECLINED;
my $ctx = Digest::MD5->new;
$ctx->addfile( *FILE );
$md5 = $ctx->hexdigest;
close( FILE );
}
$r->header_out( "Content-MD5-Hex", $md5 ) unless ! $md5;
return DECLINED;
}
1;
__END__
# nginx Embedded Perl module for adding a Content-MD5 HTTP header
#
# THIS VERSION GENERATES A HEX ENCODED VALUE BUT RFC1864 REQUIRES BASE64
#
# This perl module, will output an MD5 of a requested file using the
# Content-MD5 HTTP header, by pulling the hex hash FROM A FILE of the
# same name with .md5 appended to the end, if it exists.
#
# Author: Matt Martz <matt@sivel.net>
# Link to the original version: https://gist.github.com/sivel/1870822
# This version, with modifications:
# https://gist.github.com/kwmiebach/2f03baaae7e4f86f9573f1f30818d36f
# License: http://www.nginx.org/LICENSE
package ContentMD5;
use nginx;
sub handler {
my $r = shift;
my $filename = $r->filename;
return DECLINED unless ( -f $filename && -f "$filename.md5" );
my $content_length = -s $filename;
open( MD5FILE, "$filename.md5" ) or return DECLINED;
my $md5 = <MD5FILE>;
close( MD5FILE );
$md5 =~ s/^\s+//;
$md5 =~ s/\s+$//;
$md5 =~ s/\ .*//;
$r->header_out( "Content-MD5-Hex", $md5 ) unless ! $md5;
return DECLINED;
}
1;
__END__
# nginx Embedded Perl module for adding a Content-MD5 HTTP header
#
# THIS VERSION GENERATES A HEX ENCODED VALUE BUT RFC1864 REQUIRES BASE64
#
# This perl module, will output an MD5 of a requested file using the
# Content-MD5 HTTP header, calculating the MD5 hex hash on the fly.
#
# Author: Matt Martz <matt@sivel.net>
# Link to the original version: https://gist.github.com/sivel/1870822
# This version, with modifications:
# https://gist.github.com/kwmiebach/2f03baaae7e4f86f9573f1f30818d36f
# License: http://www.nginx.org/LICENSE
package ContentMD5;
use nginx;
use Digest::MD5;
sub handler {
my $r = shift;
my $filename = $r->filename;
return DECLINED unless -f $filename;
my $content_length = -s $filename;
my $md5;
open( FILE, $filename ) or return DECLINED;
my $ctx = Digest::MD5->new;
$ctx->addfile( *FILE );
$md5 = $ctx->hexdigest;
close( FILE );
$r->header_out( "Content-MD5-Hex", $md5 ) unless ! $md5;
return DECLINED;
}
1;
__END__
# nginx sample configuration for adding a Content-MD5 HTTP header
# using the Embedded Perl module
#
# Author: Matt Martz <matt@sivel.net>
# Link to the original version: https://gist.github.com/sivel/1870822
# This version, with modifications:
# https://gist.github.com/kwmiebach/2f03baaae7e4f86f9573f1f30818d36f
http {
perl_modules perl/lib;
perl_require ContentMD5.pm;
server {
location / {
root /var/www;
index index.html
}
location /download {
perl ContentMD5::handler;
}
}
}
# nginx sample configuration for adding a Content-MD5 HTTP header
# using the Embedded Perl module
#
# Author: Matt Martz <matt@sivel.net>
# Link to the original version: https://gist.github.com/sivel/1870822
# This version, with modifications:
# https://gist.github.com/kwmiebach/2f03baaae7e4f86f9573f1f30818d36f
# A simple vhost example
# put ContentMD5.pm into one of:
# /usr/share/nginx/perl/lib /etc/perl
# /usr/local/lib/x86_64-linux-gnu/perl/5.20.2
# /usr/local/share/perl/5.20.2 /usr/lib/x86_64-linux-gnu/perl5/5.20
# /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.20 /usr/share/perl/5.20
# /usr/local/lib/site_perl
perl_modules perl/lib;
perl_require ContentMD5.pm;
server {
server_name _;
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/images;
location / {
index index.html;
autoindex on;
perl ContentMD5::handler;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment