diff --git a/index.js b/index.js index e0cd03b..22f7316 100644 --- a/index.js +++ b/index.js @@ -15,6 +15,11 @@ events.forEach(function (event) { }; }); +var InvalidUrlError = createErrorType( + "ERR_INVALID_URL", + "Invalid URL", + TypeError +); // Error types with codes var RedirectionError = createErrorType( "ERR_FR_REDIRECTION_FAILURE", @@ -409,7 +414,7 @@ RedirectableRequest.prototype._processResponse = function (response) { redirectUrl = url.resolve(currentUrl, location); } catch (cause) { - this.emit("error", new RedirectionError(cause)); + this.emit("error", new RedirectionError({ cause: cause })); return; } @@ -454,7 +459,7 @@ RedirectableRequest.prototype._processResponse = function (response) { this._performRequest(); } catch (cause) { - this.emit("error", new RedirectionError(cause)); + this.emit("error", new RedirectionError({ cause: cause })); } }; @@ -477,14 +482,18 @@ function wrap(protocols) { function request(input, options, callback) { // Parse parameters if (isString(input)) { - var urlStr = input; + var parsed; try { - input = urlToOptions(new URL(urlStr)); + parsed = urlToOptions(new URL(input)); } catch (err) { /* istanbul ignore next */ - input = url.parse(urlStr); + parsed = url.parse(input); + } + if (!isString(parsed.protocol)) { + throw new InvalidUrlError({ input }); } + input = parsed; } else if (URL && (input instanceof URL)) { input = urlToOptions(input); @@ -562,21 +571,19 @@ function removeMatchingHeaders(regex, headers) { undefined : String(lastValue).trim(); } -function createErrorType(code, defaultMessage) { - function CustomError(cause) { +function createErrorType(code, message, baseClass) { + // Create constructor + function CustomError(properties) { Error.captureStackTrace(this, this.constructor); - if (!cause) { - this.message = defaultMessage; - } - else { - this.message = defaultMessage + ": " + cause.message; - this.cause = cause; - } + Object.assign(this, properties || {}); + this.code = code; + this.message = this.cause ? message + ": " + this.cause.message : message; } - CustomError.prototype = new Error(); + + // Attach constructor and set default properties + CustomError.prototype = new (baseClass || Error)(); CustomError.prototype.constructor = CustomError; CustomError.prototype.name = "Error [" + code + "]"; - CustomError.prototype.code = code; return CustomError; } diff --git a/test/test.js b/test/test.js index 2662523..91da4c7 100644 --- a/test/test.js +++ b/test/test.js @@ -197,6 +197,20 @@ describe("follow-redirects", function () { }); }); + it("http.get with relative URL path", function () { + var error = null; + try { + http.get("/relative"); + } + catch (e) { + error = e; + } + assert(error instanceof Error); + assert(error instanceof TypeError); + assert.equal(error.code, "ERR_INVALID_URL"); + assert.equal(error.input, "/relative"); + }); + it("should return with the original status code if the response does not contain a location header", function () { app.get("/a", function (req, res) { res.status(307).end();