Merge pull request #36 from infindex/master
Fix to handle weird scenarios where the request urls to assets contain query string
This commit is contained in:
Коммит
7cf3731edb
|
@ -9,7 +9,8 @@ var crypto = require('crypto'),
|
|||
format = require('./compat').format,
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
und = require('underscore');
|
||||
und = require('underscore'),
|
||||
url = require('url');
|
||||
|
||||
var existsSync = fs.existsSync || path.existsSync,
|
||||
opts,
|
||||
|
@ -48,8 +49,10 @@ exports.setup = function (assets, options) {
|
|||
// * the filename is a key in our opts[family]
|
||||
// * or the file exists on the filesystem
|
||||
var prefix = escape_regex(no_url(opts.prefix)),
|
||||
req_url = url.parse(req.url),
|
||||
uri = req_url.pathname ? req_url.pathname : '',
|
||||
fmt = format('^\\/%s[a-f0-9]{10}', prefix),
|
||||
m = req.url.match(new RegExp(fmt)),
|
||||
m = uri.match(new RegExp(fmt)),
|
||||
true_path, exists;
|
||||
|
||||
if (typeof resp.local === 'function') {
|
||||
|
@ -68,15 +71,15 @@ exports.setup = function (assets, options) {
|
|||
}
|
||||
if (m && m.index === 0) {
|
||||
// extract the hash
|
||||
var hash = req.url.slice(prefix.length + 1, prefix.length + 11);
|
||||
var hash = uri.slice(prefix.length + 1, prefix.length + 11);
|
||||
// 10 first characters of md5 + 1 for slash
|
||||
var url = req.url.slice(prefix.length + 11);
|
||||
var true_path = opts.url_to_paths[url] || path.join(opts.root, url);
|
||||
var _url = uri.slice(prefix.length + 11);
|
||||
true_path = opts.url_to_paths[_url] || path.join(opts.root, _url);
|
||||
|
||||
exists = false;
|
||||
|
||||
if (opts.prefix !== '' &&
|
||||
req.url.indexOf('/' + opts.prefix) === 0) {
|
||||
uri.indexOf('/' + opts.prefix) === 0) {
|
||||
exists = true;
|
||||
} else if (assets[true_path]) {
|
||||
exists = true;
|
||||
|
@ -114,7 +117,8 @@ exports.setup = function (assets, options) {
|
|||
|
||||
if (exists === true && hash === actualHash) {
|
||||
resp.setHeader('Cache-Control', 'public, max-age=31536000');
|
||||
req.url = url;
|
||||
// append back the query string and Hash if any
|
||||
req.url = _url + (req_url.query ? '?' + req_url.query : '') + (req_url.hash ? req_url.hash : '');
|
||||
if (opts.control_headers === true) {
|
||||
resp.on('header', function () {
|
||||
// Relax other middleware... I got this one
|
||||
|
@ -194,18 +198,22 @@ var hashify = function (resource, hash) {
|
|||
};
|
||||
|
||||
var prod_or_dev_tags = function (filename, link_fmt, hash) {
|
||||
var req_url = url.parse(filename),
|
||||
uri = req_url.pathname ? req_url.pathname : '';
|
||||
if (opts.production !== true &&
|
||||
_assets[filename]) {
|
||||
return und.map(_assets[filename], function (f) {
|
||||
return format(link_fmt, hashify(f, hash));
|
||||
}).join('\n');
|
||||
_assets[uri]) {
|
||||
return und.map(_assets[uri], function (f) {
|
||||
var asset_url = url.parse(f),
|
||||
asset_uri = asset_url.pathname ? asset_url.pathname : '';
|
||||
return format(link_fmt, hashify(asset_uri + (req_url.query ? '?' + req_url.query : '') + (asset_url.hash ? asset_url.hash : ''), hash));
|
||||
}).join('\n');
|
||||
}
|
||||
return format(link_fmt, hashify(filename, hash));
|
||||
};
|
||||
|
||||
var cachify_js = exports.cachify_js = function (filename, options) {
|
||||
if (! options) options = {};
|
||||
var link_fmt = '<script src="%s"'
|
||||
var link_fmt = '<script src="%s"';
|
||||
|
||||
/**
|
||||
* indicate to a browser that the script is meant to be executed after the
|
||||
|
|
|
@ -165,6 +165,34 @@ exports.setup = nodeunit.testCase({
|
|||
test.done();
|
||||
});
|
||||
},
|
||||
"Development mode with url query string": function (test) {
|
||||
var assets = make_assets(),
|
||||
mddlwr;
|
||||
mddlwr = cachify.setup(assets, {
|
||||
root: '/tmp',
|
||||
production: false
|
||||
});
|
||||
var links = cachify.cachify_js("/js/main.min.js?triedPassive=true").split('\n');
|
||||
test.equal(links.length, assets["/js/main.min.js"].length,
|
||||
"All script tags created");
|
||||
test.equal(links[0], '<script src="/js/lib/jquery.js?triedPassive=true"></script>',
|
||||
"No hashes in all urls during development");
|
||||
test.equal(links[3], '<script src="/js/font-loader.js?triedPassive=true#with_fragment_id"></script>',
|
||||
"Fragment identifier in URL is preserved");
|
||||
test.equal(cachify.uncached_resources.indexOf("/js/font-loader.js?triedPassive=true#with_fragment_id"), -1,
|
||||
"Fragment identifiers are never sent to server, search on disk for resource by removing fragment id");
|
||||
|
||||
var files = cachify.cachify("/js/main.min.js?triedPassive=true").split('\n');
|
||||
test.equal(files.length, assets["/js/main.min.js"].length,
|
||||
"All urls created");
|
||||
test.equal(files[0], '/js/lib/jquery.js?triedPassive=true',
|
||||
"No hashes in all urls during development");
|
||||
|
||||
var hints = cachify.cachify_prefetch("/js/main.min.js?triedPassive=true").split('\n');
|
||||
test.ok(hints.length, "Multiple link tags");
|
||||
test.equal(hints[0], '<link rel="prefetch" href="/js/lib/jquery.js?triedPassive=true">');
|
||||
test.done();
|
||||
},
|
||||
"Production mode": function (test) {
|
||||
var assets = make_assets(),
|
||||
req = {
|
||||
|
@ -206,6 +234,28 @@ exports.setup = nodeunit.testCase({
|
|||
test.done();
|
||||
});
|
||||
},
|
||||
"Production mode with url query string" : function (test) {
|
||||
var assets = make_assets(),
|
||||
req = {
|
||||
url: '/d41d8cd98f/js/main.min.js?triedPassive=true'
|
||||
},
|
||||
resp = get_resp(),
|
||||
mddlwr;
|
||||
mddlwr = cachify.setup(
|
||||
assets, {
|
||||
root: '/tmp'
|
||||
});
|
||||
|
||||
mddlwr(req, resp, function () {
|
||||
test.ok(resp.state.cachify_prefetch);
|
||||
test.ok(resp.state.cachify_js);
|
||||
test.ok(resp.state.cachify_css);
|
||||
test.ok(resp.state.cachify);
|
||||
test.ok(resp.state.header > 0);
|
||||
test.equal(req.url, '/js/main.min.js?triedPassive=true');
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
"Production mode with absolute URL in prefix": function (test) {
|
||||
var assets = make_assets(),
|
||||
req = {
|
||||
|
@ -235,6 +285,29 @@ exports.setup = nodeunit.testCase({
|
|||
test.done();
|
||||
});
|
||||
},
|
||||
"Production mode with absolute URL in prefix and url query string" : function (test) {
|
||||
var assets = make_assets(),
|
||||
req = {
|
||||
url: '/v/d41d8cd98f/js/main.min.js?triedPassive=true'
|
||||
},
|
||||
resp = get_resp(),
|
||||
mddlwr;
|
||||
mddlwr = cachify.setup(
|
||||
assets, {
|
||||
root: '/tmp',
|
||||
prefix: 'http://example.com/v/'
|
||||
});
|
||||
|
||||
mddlwr(req, resp, function () {
|
||||
test.ok(resp.state.cachify_prefetch);
|
||||
test.ok(resp.state.cachify_js);
|
||||
test.ok(resp.state.cachify_css);
|
||||
test.ok(resp.state.cachify);
|
||||
test.ok(resp.state.header > 0);
|
||||
test.equal(req.url, '/js/main.min.js?triedPassive=true');
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
"Custom prefix works with non-file assets": function (test) {
|
||||
var assets = make_assets(),
|
||||
req = {
|
||||
|
@ -261,6 +334,32 @@ exports.setup = nodeunit.testCase({
|
|||
test.done();
|
||||
});
|
||||
},
|
||||
"Custom prefix with non-file assets and url query string": function (test) {
|
||||
var assets = make_assets(),
|
||||
req = {
|
||||
url: '/cachify/d41d8cd98f/other?triedPassive=true'
|
||||
},
|
||||
resp = get_resp(),
|
||||
mddlwr;
|
||||
|
||||
mddlwr = cachify.setup(
|
||||
assets, {
|
||||
prefix: 'cachify',
|
||||
root: '/tmp'
|
||||
});
|
||||
var link = cachify.cachify_js("/other", {hash: 'd41d8cd98f'});
|
||||
test.equal(link, '<script src="/cachify/d41d8cd98f/other"></script>');
|
||||
|
||||
mddlwr(req, resp, function () {
|
||||
test.ok(resp.state.cachify_prefetch);
|
||||
test.ok(resp.state.cachify_js);
|
||||
test.ok(resp.state.cachify_css);
|
||||
test.ok(resp.state.cachify);
|
||||
test.ok(resp.state.header > 0);
|
||||
test.equal(req.url, '/other?triedPassive=true');
|
||||
test.done();
|
||||
});
|
||||
},
|
||||
"Production mode, mismatched checksum, not substituted": function (test) {
|
||||
var assets = make_assets(),
|
||||
req = {
|
||||
|
|
Загрузка…
Ссылка в новой задаче