Report an error when HTTP request body is incomplete.

When a download aborts prematurely, the status code is often 200 OK, even
though we probably should not proceed with any further processing of the
downloaded information.

This silent failure leads to problems like the dreaded "Error: ENOENT: no
such file or directory, open... os.json" (#7806 and others), which were
hard to diagnose properly because the failure occurred only later, when
extracting a buffer that downloaded incompletely.

The getUrlWithResuming helper should be able to retry after this error is
thrown, which will result in a more helpful warning, even if in the most
common case, i.e. MaxCDN failure, it will never actually succeed.

Note that this change will not help until Meteor 1.4.2 is officially
released and becomes the implementation used to download later releases.

Mitigates #7806.
This commit is contained in:
Ben Newman
2016-10-17 13:38:19 -04:00
parent 1ac4bbaa84
commit 30aec9f345
2 changed files with 14 additions and 1 deletions

View File

@@ -78,6 +78,11 @@
engine, instead of failing to start Mongo. engine, instead of failing to start Mongo.
[#7840](https://github.com/meteor/meteor/pull/7840). [#7840](https://github.com/meteor/meteor/pull/7840).
* Incomplete package downloads will now fail (and be retried several
times) instead of silently succeeding, which was the cause of the
dreaded `Error: ENOENT: no such file or directory, open... os.json`
error. [#7806](https://github.com/meteor/meteor/issues/7806)
## v1.4.1.2 ## v1.4.1.2
* Node has been upgraded to version 4.6.0, a recommended security release: * Node has been upgraded to version 4.6.0, a recommended security release:

View File

@@ -299,7 +299,15 @@ _.extend(exports, {
// require it until we definitely need it. // require it until we definitely need it.
Console.debug("Doing HTTP request: ", options.method || 'GET', options.url); Console.debug("Doing HTTP request: ", options.method || 'GET', options.url);
var request = require('request'); var request = require('request');
var req = request(options, callback); var req = request(options, function (error, response, body) {
const contentLength = Number(response.headers["content-length"]);
if (contentLength > 0 && body.length < contentLength) {
error = new Error(
"Expected " + contentLength + " bytes in request body " +
"but received only " + body.length);
}
return callback.call(this, error, response, body);
});
if (_.isFunction(onRequest)) { if (_.isFunction(onRequest)) {
onRequest(req); onRequest(req);