mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-02-17 23:45:29 -05:00
honor etags when making requests
This commit is contained in:
parent
ec26083e81
commit
782abbb86d
3 changed files with 123 additions and 94 deletions
|
@ -33,6 +33,7 @@ function get_boilerplate(name) {
|
||||||
// our own object
|
// our own object
|
||||||
'_distfiles': {},
|
'_distfiles': {},
|
||||||
'_attachments': {},
|
'_attachments': {},
|
||||||
|
'_uplinks': {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,32 +97,32 @@ Storage.prototype._read_create_package = function(name, callback) {
|
||||||
// synchronize remote package info with the local one
|
// synchronize remote package info with the local one
|
||||||
// TODO: readfile called twice
|
// TODO: readfile called twice
|
||||||
Storage.prototype.update_versions = function(name, newdata, callback) {
|
Storage.prototype.update_versions = function(name, newdata, callback) {
|
||||||
var self = this;
|
var self = this
|
||||||
self._read_create_package(name, function(err, data) {
|
self._read_create_package(name, function(err, data) {
|
||||||
if (err) return callback(err);
|
if (err) return callback(err)
|
||||||
|
|
||||||
var change = false;
|
var change = false
|
||||||
for (var ver in newdata.versions) {
|
for (var ver in newdata.versions) {
|
||||||
if (data.versions[ver] == null) {
|
if (data.versions[ver] == null) {
|
||||||
var verdata = newdata.versions[ver];
|
var verdata = newdata.versions[ver]
|
||||||
|
|
||||||
// why does anyone need to keep that in database?
|
// why does anyone need to keep that in database?
|
||||||
delete verdata.readme;
|
delete verdata.readme
|
||||||
|
|
||||||
change = true;
|
change = true
|
||||||
data.versions[ver] = verdata;
|
data.versions[ver] = verdata
|
||||||
|
|
||||||
if (verdata.dist && verdata.dist.tarball) {
|
if (verdata.dist && verdata.dist.tarball) {
|
||||||
var url = utils.parse_tarball_url(
|
var url = utils.parse_tarball_url(
|
||||||
verdata.dist.__sinopia_orig_tarball || verdata.dist.tarball
|
verdata.dist.__sinopia_orig_tarball || verdata.dist.tarball
|
||||||
);
|
)
|
||||||
|
|
||||||
// we do NOT overwrite any existing records
|
// we do NOT overwrite any existing records
|
||||||
if (url != null && data._distfiles[url.filename] == null) {
|
if (url != null && data._distfiles[url.filename] == null) {
|
||||||
data._distfiles[url.filename] = {
|
data._distfiles[url.filename] = {
|
||||||
url: verdata.dist.__sinopia_orig_tarball || verdata.dist.tarball,
|
url: verdata.dist.__sinopia_orig_tarball || verdata.dist.tarball,
|
||||||
sha: verdata.dist.shasum,
|
sha: verdata.dist.shasum,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,20 +131,30 @@ Storage.prototype.update_versions = function(name, newdata, callback) {
|
||||||
// if tag is updated to reference latter version, that's fine
|
// if tag is updated to reference latter version, that's fine
|
||||||
var need_change =
|
var need_change =
|
||||||
(data['dist-tags'][tag] == null) ||
|
(data['dist-tags'][tag] == null) ||
|
||||||
(!semver.gte(newdata['dist-tags'][tag], data['dist-tags'][tag]));
|
(!semver.gte(newdata['dist-tags'][tag], data['dist-tags'][tag]))
|
||||||
|
|
||||||
if (need_change) {
|
if (need_change) {
|
||||||
change = true;
|
change = true
|
||||||
data['dist-tags'][tag] = newdata['dist-tags'][tag];
|
data['dist-tags'][tag] = newdata['dist-tags'][tag]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var up in newdata._uplinks) {
|
||||||
|
var need_change =
|
||||||
|
!utils.is_object(data._uplinks[up]) || (newdata._uplinks[up].etag !== data._uplinks[up].etag)
|
||||||
|
|
||||||
|
if (need_change) {
|
||||||
|
change = true
|
||||||
|
data._uplinks[up] = newdata._uplinks[up]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (change) {
|
if (change) {
|
||||||
|
self.logger.debug('updating package info')
|
||||||
self._write_package(name, data, callback)
|
self._write_package(name, data, callback)
|
||||||
} else {
|
} else {
|
||||||
callback();
|
callback()
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage.prototype.add_version = function(name, version, metadata, tag, callback) {
|
Storage.prototype.add_version = function(name, version, metadata, tag, callback) {
|
||||||
|
@ -367,7 +378,7 @@ Storage.prototype.update_package = function(name, updateFn, _callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage.prototype._normalize_package = function(pkg) {
|
Storage.prototype._normalize_package = function(pkg) {
|
||||||
['versions', 'dist-tags', '_distfiles', '_attachments'].forEach(function(key) {
|
['versions', 'dist-tags', '_distfiles', '_attachments', '_uplinks'].forEach(function(key) {
|
||||||
if (!utils.is_object(pkg[key])) pkg[key] = {}
|
if (!utils.is_object(pkg[key])) pkg[key] = {}
|
||||||
});
|
});
|
||||||
if (typeof(pkg._rev) !== 'string') pkg._rev = '0-0000000000000000'
|
if (typeof(pkg._rev) !== 'string') pkg._rev = '0-0000000000000000'
|
||||||
|
|
|
@ -20,6 +20,7 @@ function Storage(config) {
|
||||||
this.uplinks = {};
|
this.uplinks = {};
|
||||||
for (var p in config.uplinks) {
|
for (var p in config.uplinks) {
|
||||||
this.uplinks[p] = new Proxy(config.uplinks[p], config);
|
this.uplinks[p] = new Proxy(config.uplinks[p], config);
|
||||||
|
this.uplinks[p].upname = p;
|
||||||
}
|
}
|
||||||
this.local = new Local(config);
|
this.local = new Local(config);
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ Storage.prototype.add_package = function(name, metadata, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async.map(uplinks, function(up, cb) {
|
async.map(uplinks, function(up, cb) {
|
||||||
up.get_package(name, function(err, res) {
|
up.get_package(name, null, function(err, res) {
|
||||||
cb(null, [err, res]);
|
cb(null, [err, res]);
|
||||||
});
|
});
|
||||||
}, function(err, results) {
|
}, function(err, results) {
|
||||||
|
@ -313,79 +314,88 @@ Storage.prototype.get_tarball = function(name, filename) {
|
||||||
// Used storages: local && uplink (proxy_access)
|
// Used storages: local && uplink (proxy_access)
|
||||||
//
|
//
|
||||||
Storage.prototype.get_package = function(name, callback) {
|
Storage.prototype.get_package = function(name, callback) {
|
||||||
var self = this;
|
var self = this
|
||||||
var uplinks = [this.local];
|
|
||||||
for (var i in this.uplinks) {
|
self.local.get_package(name, function(err, data) {
|
||||||
if (this.config.proxy_access(name, i)) {
|
if (err && (!err.status || err.status >= 500)) {
|
||||||
uplinks.push(this.uplinks[i]);
|
// report internal errors right away
|
||||||
|
return cb(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var uplinks = []
|
||||||
|
for (var i in self.uplinks) {
|
||||||
|
if (self.config.proxy_access(name, i)) {
|
||||||
|
uplinks.push(self.uplinks[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = {
|
var result = data || {
|
||||||
name: name,
|
name: name,
|
||||||
versions: {},
|
versions: {},
|
||||||
'dist-tags': {},
|
'dist-tags': {},
|
||||||
};
|
_uplinks: {},
|
||||||
var exists = false;
|
}
|
||||||
var latest;
|
var exists = !err
|
||||||
|
var latest = result['dist-tags'].latest
|
||||||
|
|
||||||
async.map(uplinks, function(up, cb) {
|
async.map(uplinks, function(up, cb) {
|
||||||
up.get_package(name, function(err, up_res) {
|
var oldetag = null
|
||||||
if (err) {
|
if (utils.is_object(result._uplinks[up.upname]))
|
||||||
if (up === self.local && (!err.status || err.status >= 500)) {
|
oldetag = result._uplinks[up.upname].etag
|
||||||
// report internal errors right away
|
|
||||||
return cb(err)
|
|
||||||
} else {
|
|
||||||
return cb()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (up === self.local) {
|
up.get_package(name, oldetag, function(err, up_res, etag) {
|
||||||
// file exists in local repo
|
if (err || !up_res) return cb()
|
||||||
exists = true
|
|
||||||
result._rev = up_res._rev
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
utils.validate_metadata(up_res, name);
|
utils.validate_metadata(up_res, name)
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
return cb();
|
return cb()
|
||||||
}
|
}
|
||||||
|
|
||||||
var this_version = up_res['dist-tags'].latest;
|
result._uplinks[up.upname] = {
|
||||||
|
etag: etag
|
||||||
|
}
|
||||||
|
|
||||||
|
var this_version = up_res['dist-tags'].latest
|
||||||
if (latest == null
|
if (latest == null
|
||||||
|| (!semver.gt(latest, this_version) && this_version)) {
|
|| (!semver.gt(latest, this_version) && this_version)) {
|
||||||
latest = this_version;
|
latest = this_version
|
||||||
var is_latest = true;
|
var is_latest = true
|
||||||
}
|
}
|
||||||
|
|
||||||
['versions', 'dist-tags'].forEach(function(key) {
|
['versions', 'dist-tags'].forEach(function(key) {
|
||||||
for (var i in up_res[key]) {
|
for (var i in up_res[key]) {
|
||||||
if (!result[key][i] || is_latest) {
|
if (!result[key][i] || is_latest) {
|
||||||
result[key][i] = up_res[key][i];
|
result[key][i] = up_res[key][i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
// if we got to this point, assume that the correct package exists
|
// if we got to this point, assume that the correct package exists
|
||||||
// on the uplink
|
// on the uplink
|
||||||
exists = true;
|
exists = true
|
||||||
cb();
|
cb()
|
||||||
});
|
})
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
if (err) return callback(err);
|
if (err) return callback(err);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
return callback(new UError({
|
return callback(new UError({
|
||||||
status: 404,
|
status: 404,
|
||||||
msg: 'no such package available'
|
msg: 'no such package available'
|
||||||
}));
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.local.update_versions(name, result, function(err) {
|
self.local.update_versions(name, result, function(err) {
|
||||||
if (err) return callback(err);
|
if (err) return callback(err)
|
||||||
callback(null, result);
|
|
||||||
});
|
var whitelist = ['_rev', 'name', 'versions', 'dist-tags']
|
||||||
});
|
for (var i in result) {
|
||||||
|
if (!~whitelist.indexOf(i)) delete result[i]
|
||||||
|
}
|
||||||
|
callback(null, result)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Storage;
|
module.exports = Storage;
|
||||||
|
|
|
@ -34,14 +34,13 @@ function Storage(config, mainconfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage.prototype.request = function(options, cb) {
|
Storage.prototype.request = function(options, cb) {
|
||||||
var self = this;
|
var self = this
|
||||||
var headers = options.headers || {};
|
var headers = options.headers || {}
|
||||||
headers.accept = headers.accept || 'application/json';
|
headers.accept = headers.accept || 'application/json'
|
||||||
headers['user-agent'] = headers['user-agent'] || this.userAgent;
|
headers['user-agent'] = headers['user-agent'] || this.userAgent
|
||||||
|
|
||||||
var method = options.method || 'GET';
|
var method = options.method || 'GET'
|
||||||
var uri = options.uri_full || (this.config.url + options.uri);
|
var uri = options.uri_full || (this.config.url + options.uri)
|
||||||
var method = options.method || 'GET';
|
|
||||||
self.logger.info({
|
self.logger.info({
|
||||||
method: method,
|
method: method,
|
||||||
headers: headers,
|
headers: headers,
|
||||||
|
@ -60,24 +59,27 @@ Storage.prototype.request = function(options, cb) {
|
||||||
body: json,
|
body: json,
|
||||||
ca: this.ca,
|
ca: this.ca,
|
||||||
}, function(err, res, body) {
|
}, function(err, res, body) {
|
||||||
|
var error
|
||||||
if (!err) {
|
if (!err) {
|
||||||
var res_length = body.length;
|
var res_length = body.length;
|
||||||
|
|
||||||
if (options.json) {
|
if (options.json && res.statusCode < 300) {
|
||||||
try {
|
try {
|
||||||
body = JSON.parse(body);
|
body = JSON.parse(body);
|
||||||
} catch(err) {
|
} catch(_err) {
|
||||||
return cb(err);
|
body = {}
|
||||||
|
err = _err
|
||||||
|
error = err.message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utils.is_object(body)) {
|
if (!err && utils.is_object(body)) {
|
||||||
if (body.error) {
|
if (body.error) {
|
||||||
var error = body.error;
|
error = body.error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var error = err.message;
|
error = err.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
var msg = '@{!status}, req: \'@{request.method} @{request.url}\'';
|
var msg = '@{!status}, req: \'@{request.method} @{request.url}\'';
|
||||||
|
@ -196,10 +198,16 @@ Storage.prototype.add_tarball = function(name, filename) {
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
Storage.prototype.get_package = function(name, callback) {
|
Storage.prototype.get_package = function(name, etag, callback) {
|
||||||
|
if (etag) {
|
||||||
|
var headers = {
|
||||||
|
'if-none-match': etag
|
||||||
|
}
|
||||||
|
}
|
||||||
this.request({
|
this.request({
|
||||||
uri: '/' + escape(name),
|
uri: '/' + escape(name),
|
||||||
json: true,
|
json: true,
|
||||||
|
headers: headers,
|
||||||
}, function(err, res, body) {
|
}, function(err, res, body) {
|
||||||
if (err) return callback(err);
|
if (err) return callback(err);
|
||||||
if (res.statusCode === 404) {
|
if (res.statusCode === 404) {
|
||||||
|
@ -211,7 +219,7 @@ Storage.prototype.get_package = function(name, callback) {
|
||||||
if (!(res.statusCode >= 200 && res.statusCode < 300)) {
|
if (!(res.statusCode >= 200 && res.statusCode < 300)) {
|
||||||
return callback(new Error('bad status code: ' + res.statusCode));
|
return callback(new Error('bad status code: ' + res.statusCode));
|
||||||
}
|
}
|
||||||
callback(null, body);
|
callback(null, body, res.headers.etag);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue