Skip to content

Commit a75662a

Browse files
Chris CloseCL0SeY
Chris Close
authored andcommitted
Retrieve and respond on index using etags and handling 304's
1 parent 5ce0e97 commit a75662a

File tree

5 files changed

+42
-16
lines changed

5 files changed

+42
-16
lines changed

lib/api.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,20 @@ api.configure = function(config) {
2323
// GET /package
2424
api.get(new RegExp('^/([^/]+)$'), function(req, res, match) {
2525
var name = match[1];
26-
Package.getIndex(name, function(err, data) {
26+
Package.getIndex(name, function(err, data, etag) {
27+
if (req.headers['if-none-match'] === etag) {
28+
res.statusCode = 304;
29+
res.end();
30+
return;
31+
}
32+
2733
if (err) {
2834
logger.error('[500] Error: ', err);
2935
res.statusCode = 500;
3036
res.end();
3137
return;
3238
}
39+
res.setHeader('ETag', etag);
3340
res.end(JSON.stringify(data));
3441
});
3542
});
@@ -52,6 +59,7 @@ api.get(new RegExp('^/([^/]+)/(.+)/([^/]+)$'), function(req, res, match) {
5259
res.end();
5360
return;
5461
}
62+
5563
res.setHeader('Content-type', 'application/octet-stream');
5664
fs.createReadStream(fullpath).pipe(res);
5765
});

lib/cache.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ Cache.prototype.filename = function() {
6969
return cacheName;
7070
};
7171

72-
Cache.prototype.complete = function(itemHash, taskHash, cacheFilePath) {
72+
Cache.prototype.complete = function(itemHash, taskHash, cacheFilePath, etag) {
7373
if (arguments.length < 3) {
7474
throw new Error('Invalid call to Cache.complete()');
7575
}
@@ -83,7 +83,7 @@ Cache.prototype.complete = function(itemHash, taskHash, cacheFilePath) {
8383

8484
// make pluggable: update the cache with the INPUT item stats
8585

86-
this.data[itemHash].taskResults[taskHash] = { path: cacheFilePath };
86+
this.data[itemHash].taskResults[taskHash] = { path: cacheFilePath, etag: etag };
8787
// console.log('Complete', itemHash, taskHash);
8888
this.save();
8989
};
@@ -113,7 +113,7 @@ Cache.prototype.lookup = function(itemHash, taskHash) {
113113
!cacheMeta.taskResults[taskHash].path) {
114114
return false;
115115
}
116-
return cacheMeta.taskResults[taskHash].path;
116+
return cacheMeta.taskResults[taskHash];
117117
};
118118

119119
Cache.hash = Cache.prototype.hash = function(method, str) {

lib/package.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,18 +88,15 @@ Package.getIndex = function(pname, onDone) {
8888
logger.log('[OK] Reusing cached result for ' + uri);
8989
});
9090

91-
r.getReadablePath(function(err, fullpath) {
91+
r.getReadablePath(function(err, fullpath, etag) {
9292
if (err) {
9393
return onDone(err);
9494
}
9595

9696
r.removeAllListeners('fetch-error');
9797
r.removeAllListeners('fetch-cached');
9898

99-
return onDone(err,
100-
Package._rewriteLocation(
101-
JSON.parse(fs.readFileSync(fullpath))
102-
));
99+
return onDone(err, Package._rewriteLocation(JSON.parse(fs.readFileSync(fullpath))), etag);
103100
});
104101
};
105102

lib/resource.js

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ Resource.configure = function(opts) {
7777

7878
Resource.prototype.exists = function() {
7979
// logger.log('exists', this.url, 'GET', Cache.lookup(this.url, 'GET'));
80+
return this.lookup().path;
81+
};
82+
83+
Resource.prototype.lookup = function() {
8084
return Cache.lookup(this.url, 'GET');
8185
};
8286

@@ -107,7 +111,7 @@ Resource.prototype.getReadablePath = function(onDone) {
107111
self.emit('fetch-cached');
108112
// is the index up to date?
109113
// yes: return readable stream
110-
return onDone(null, self.exists());
114+
return onDone(null, self.exists(), self.lookup().etag);
111115
}
112116
}
113117

@@ -118,12 +122,12 @@ Resource.prototype.getReadablePath = function(onDone) {
118122
var Package = require('./package.js');
119123
return Package.getIndex(self.getPackageName(), function(err, data) {
120124
if (err) {
121-
return onDone(err, null);
125+
return onDone(err, null, null);
122126
}
123127
expectedHash = verify.getSha(self.basename, data);
124128
verify.check(self.exists(), function(err, actualHash) {
125129
if (err) {
126-
return onDone(err, null);
130+
return onDone(err, null, null);
127131
}
128132
if (actualHash === expectedHash) {
129133
return onDone(null, self.exists()); // return readable stream if file is good
@@ -149,9 +153,9 @@ Resource.prototype.getReadablePath = function(onDone) {
149153
}
150154
// return readable path
151155
if (self.err) {
152-
return onDone(self.err, null);
156+
return onDone(self.err, null, null);
153157
}
154-
onDone(self.err, self.exists());
158+
onDone(self.err, self.exists(), self.lookup().etag);
155159
});
156160

157161
// are we blocking? => nothing more to do so return
@@ -198,6 +202,7 @@ Resource.prototype.retry = function() {
198202

199203
Resource.prototype._afterFetch = function(err, readableStream) {
200204
var self = this;
205+
201206
clearTimeout(self.fetchTimer);
202207
// queue returned:
203208

@@ -209,6 +214,17 @@ Resource.prototype._afterFetch = function(err, readableStream) {
209214
}
210215
// resource fetch OK,
211216

217+
if (readableStream.statusCode === 304) {
218+
// We can rely on the data already in the cache.
219+
// No more operations required.
220+
logger.log('304 - ' + self.url);
221+
lastUpdated[self.url] = new Date();
222+
guard.release(self.url);
223+
return;
224+
}
225+
226+
self.etag = readableStream.headers['etag'];
227+
212228
// write to disk
213229
var cachename = Cache.filename(),
214230
out = fs.createWriteStream(cachename, {flags: 'w'});
@@ -234,7 +250,7 @@ Resource.prototype._afterFetch = function(err, readableStream) {
234250
return self.retry();
235251
}
236252
// mark as OK, return all pending callback
237-
Cache.complete(self.url, 'GET', cachename);
253+
Cache.complete(self.url, 'GET', cachename, self.etag);
238254
// set last updated
239255
lastUpdated[self.url] = new Date();
240256
guard.release(self.url);
@@ -319,6 +335,11 @@ Resource.prototype._fetchTask = function(onDone) {
319335
opts.strictSSL = false;
320336
}
321337

338+
if (self.lookup() && self.lookup().etag) {
339+
opts.headers = opts.headers || {};
340+
opts.headers['if-none-match'] = self.lookup().etag;
341+
}
342+
322343
logger.log('[GET] ' + this.url);
323344

324345
req = request.get(opts);

util/ls.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Object.keys(meta).forEach(function(uri) {
1919
files.splice(index, 1);
2020
}
2121

22-
console.log('Cache check', uri, cache.lookup(uri, 'GET'));
22+
console.log('Cache check', uri, cache.lookup(uri, 'GET').path);
2323

2424
});
2525

0 commit comments

Comments
 (0)