nginx decode base64 url for use with imgproxy
i've been testing imgproxy, to handle our image serving needs, and it looks good.
our existing servers are php based, and we sign and encode our urls for images. To test out imgproxy , I wanted to simply drop it in as a replacement for our servers by sending a % of traffic.
There are many ways to do this, varnish was one, with custom code, but nginx is our go-to web server, so I had to find a way to have nginx sit in front of imgproxy and rewrite the decoded url.
I settled on using njs, the cut down version of javascript that plugs into nginx as a loadable module. Then use proxy_pass to pass the uri to javascript that will return the imgproxy compatable url, and proxy to it.
a sample url would be
http://foo.bar/images/c2lnbmF0dXJlZm9vaHR0cDovL3MzLWV1LXdlc3QtMS5hbWF6b25hd3MuY29tL215YnVja2V0b2ZwaG90b3MvcGhvdG9fb2ZfYV9jYXQ1fHx8MTIwMHgxMjAwfHx8fHx8fHw==.jpeg
it has a sig, a bucket url, and parameters like image size.
Getting nginx setup
nginx.conf
load_module modules/ngx_http_js_module.so;
js_include "imgproxyurl.js";
js_set $imgproxyurl imgproxyurl;
server {
location ~ /images/(.*) {
aio threads;
proxy_buffering off;
proxy_pass $imgproxyurl;
}
the javascript file
function imgproxyurl(r) {
var splitUrl = r.uri.split('\/');
var filePart = splitUrl[2];
var decodedUrl = Buffer.from(filePart, 'base64url'); // don't make a string, it can have binary data , base64url takes care of + /
// skip anything up to position 48, which is the bucket part of the url
var justParams = decodedUrl.slice(48).toString(); // string it after slicing the binary contents
var splitParams = justParams.split('|');
var bucketUrl = splitParams[0];
// take parameters from the url and use them to shape the imgproxy url
var imgMode = 'fit';
if (splitParams[3] != '') var imgSize = splitParams[3];
if (splitParams[6] != '') {
var imgSize = splitParams[6];
imgMode = 'fill';
}
var imgSizeParts = imgSize.split('x');
var imgH = imgSizeParts[0];
var imgW = imgSizeParts[1];
// make image format based on extension in url
var imgFormat = 'jpg';
if (r.uri.substring(r.uri.length -4, r.uri.length) === "webp") imgFormat = 'webp';
// imgproxy is running localhost, no need to encode or encrypt url, it's invisible
var newUrl = 'http://127.0.0.1:8080/donedeal/' + imgMode + '/' + imgH + '/' + imgW + '/ce/0/plain/' + bucketUrl + '@' + imgFormat;
//r.headersOut['debug-hint'] = [newUrl];
return(newUrl);
}
Comments