Skip to content

Commit

Permalink
Ensure a unique eTag for meta.js
Browse files Browse the repository at this point in the history
* Go exclusively off of HTTP/1.1 eTag and ignore `last-modified`... supported since ~1996.
* HTTP/1.0 should produce 429's in this configuration

NOTES:
* Some of the documentation out there on the web is a bit iffy compared to actual implementation in browsers... but does match RFC'd specs.
* Edge case found with oujs - Meta View ... so this is why this is happening
* This transfers the load to the CPU instead of the bandwidth and is required to get things near, if not, 100%

Applies to OpenUserJS#432 and post OpenUserJS#1070
  • Loading branch information
Martii committed Apr 20, 2017
1 parent 466da78 commit 8d0f9d7
Showing 1 changed file with 42 additions and 44 deletions.
86 changes: 42 additions & 44 deletions controllers/scriptStorage.js
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,6 @@ exports.sendScript = function (aReq, aRes, aNext) {
let rAnyLocalHost = new RegExp('^(?:openuserjs\.org|oujs\.org' +
(isDev ? '|localhost:' + (process.env.PORT || 8080) : '') + ')');

var lastModified = null;
var eTag = null;
var maxAge = 1 * 60 * 60 * 24; // nth day(s) in seconds
var now = null;
Expand Down Expand Up @@ -590,24 +589,15 @@ exports.sendScript = function (aReq, aRes, aNext) {
}

// Set up server to client caching
lastModified = moment(
(!/\.min(\.user)?\.js$/.test(aReq._parsedUrl.pathname)
? aScript.updated
: mtimeUglifyJS2 > aScript.updated ? mtimeUglifyJS2 : aScript.updated)
).utc().format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT';

// Create a based representation of the hex sha512sum
eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + '"';

// NOTE: HTTP/1.1 Caching
aRes.set('Cache-Control', 'public, max-age=' + maxAge +
', no-cache, no-transform, must-revalidate');

// NOTE: HTTP/1.0 Caching
aRes.set('Last-Modified', lastModified);

// If already client-side... NOTE: HTTP/1.0 and/or HTTP/1.1 Caching
if (aReq.get('if-modified-since') === lastModified || aReq.get('if-none-match') === eTag) {
// If already client-side... NOTE: HTTP/1.1 Caching
if (aReq.get('if-none-match') === eTag) {
aRes.status(304).send(); // Not Modified
return;
}
Expand Down Expand Up @@ -751,35 +741,32 @@ exports.sendMeta = function (aReq, aRes, aNext) {

var eTag = null;
var maxAge = 1 * 60 * 60 * 24; // nth day(s) in seconds
var lastModified = null;

var metadataBlocks = '';

if (!aScript) {
aNext();
return;
}

lastModified = aScript.updated;

// Create a based representation of the hex sha512sum
eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + '"';

script = modelParser.parseScript(aScript);
meta = script.meta; // NOTE: Watchpoint

// NOTE: HTTP/1.1 Caching
aRes.set('Cache-Control', 'public, max-age=' + maxAge +
', no-cache, no-transform, must-revalidate');

// NOTE: HTTP/1.0 Caching
aRes.set('Last-Modified', lastModified);

// If already client-side... NOTE: HTTP/1.0 and/or HTTP/1.1 Caching
if (aReq.get('if-modified-since') === lastModified || aReq.get('if-none-match') === eTag) {
aRes.status(304).send(); // Not Modified
return;
}
script = modelParser.parseScript(aScript);
meta = script.meta; // NOTE: Watchpoint

if (/\.json$/.test(aReq.params.scriptname)) {
// Create a based representation of the hex sha512sum
eTag = '"' + Base62.encode(parseInt('0x' + aScript.hash, 16)) + '"';

// If already client-side... NOTE: HTTP/1.1 Caching
if (aReq.get('if-none-match') === eTag) {
aRes.status(304).send(); // Not Modified
return;
}

// Okay to send JSON...
aRes.set('Content-Type', 'application/json; charset=UTF-8');

// NOTE: HTTP/1.0 Caching
Expand Down Expand Up @@ -808,35 +795,46 @@ exports.sendMeta = function (aReq, aRes, aNext) {
async.parallel(tasks, asyncComplete);

} else {
aRes.set('Content-Type', 'text/javascript; charset=UTF-8');

// NOTE: HTTP/1.0 Caching
aRes.set('Expires', moment(moment() + maxAge * 1000).utc()
.format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT');

// NOTE: HTTP/1.1 Caching
aRes.set('Etag', eTag);

aRes.write('// ==UserScript==\n');
metadataBlocks += '// ==UserScript==\n';

if (meta.UserScript.version) {
aRes.write('// @version' + whitespace + meta.UserScript.version[0].value + '\n');
metadataBlocks += '// @version' + whitespace + meta.UserScript.version[0].value + '\n';
}

Object.keys(meta.UserScript.name).forEach(function (aName) {
var key = meta.UserScript.name[aName].key || 'name';
var value = meta.UserScript.name[aName].value;

aRes.write('// @' + key + whitespace + value + '\n');
metadataBlocks += '// @' + key + whitespace + value + '\n';
});

if (meta.UserScript.namespace) {
aRes.write('// @namespace' + whitespace + meta.UserScript.namespace[0].value + '\n');
metadataBlocks += '// @namespace' + whitespace + meta.UserScript.namespace[0].value + '\n';
}

aRes.write('// ==/UserScript==\n');
metadataBlocks += '// ==/UserScript==\n';

aRes.end();
// Calculate unique eTag here...
eTag = '"' + Base62.encode(
parseInt('0x' + crypto.createHash('sha512').update(metadataBlocks).digest('hex'), 16)) + '"';

// If already client-side... NOTE: HTTP/1.1 Caching
if (aReq.get('if-none-match') === eTag) {
aRes.status(304).send(); // Not Modified
return;
}

// Okay to send metadataBlocks
aRes.set('Content-Type', 'text/javascript; charset=UTF-8');

// NOTE: HTTP/1.0 Caching
aRes.set('Expires', moment(moment() + maxAge * 1000).utc()
.format('ddd, DD MMM YYYY HH:mm:ss') + ' GMT');

// NOTE: HTTP/1.1 Caching
aRes.set('Etag', eTag);

aRes.end(metadataBlocks);
}
});
};
Expand Down

0 comments on commit 8d0f9d7

Please sign in to comment.