Skip to content

Commit 3a20869

Browse files
authored
Follow 3xx redirects (#510)
Also fix an unreleased contentType bug from #508
1 parent b5bfe4d commit 3a20869

File tree

2 files changed

+47
-31
lines changed

2 files changed

+47
-31
lines changed

bin/loaders/index.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ async function load(pathToSpec, { auth }) {
2727

2828
async function loadSpec(pathToSpec, { auth, log = true }) {
2929
if (log === true) {
30-
console.log(yellow(`🤞 Loading spec from ${bold(pathToSpec)}…`)); // only log if not writing to stdout
30+
console.log(yellow(`🔭 Loading spec from ${bold(pathToSpec)}…`)); // only log if not writing to stdout
3131
}
3232

33+
const contentType = mime.getType(pathToSpec);
3334
const rawSpec = await load(pathToSpec, { auth });
3435

35-
switch (mime.getType(pathToSpec)) {
36+
switch (contentType) {
3637
case "text/yaml": {
3738
try {
3839
return yaml.load(rawSpec);
@@ -49,7 +50,7 @@ async function loadSpec(pathToSpec, { auth, log = true }) {
4950
}
5051
}
5152
default: {
52-
throw new Error(`Unknown format: "${contentType}". Only YAML or JSON supported.`);
53+
throw new Error(`Unknown format${contentType ? `: "${contentType}"` : ""}. Only YAML or JSON supported.`);
5354
}
5455
}
5556
}

bin/loaders/loadFromHttp.js

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,54 @@
1-
const url = require("url");
1+
const http = require("http");
2+
const https = require("https");
3+
const { parse } = require("url");
24

3-
function loadFromHttp(pathToSpec, { auth }) {
4-
const { protocol } = url.parse(pathToSpec);
5-
6-
if (protocol !== "http:" && protocol !== "https:") {
7-
throw new Error(`Unsupported protocol: "${protocol}". URL must start with "http://" or "https://".`);
8-
}
5+
// config
6+
const MAX_REDIRECT_COUNT = 10;
97

10-
const fetch = require(protocol === "https:" ? "https" : "http");
8+
function fetch(url, opts, { redirectCount = 0 } = {}) {
119
return new Promise((resolve, reject) => {
12-
const req = fetch.request(
13-
pathToSpec,
14-
{
15-
method: "GET",
16-
auth,
17-
},
18-
(res) => {
19-
let rawData = "";
20-
res.setEncoding("utf8");
21-
res.on("data", (chunk) => {
22-
rawData += chunk;
23-
});
24-
res.on("end", () => {
25-
if (res.statusCode >= 200 && res.statusCode < 300) {
26-
resolve(rawData);
27-
} else {
28-
reject(rawData || `${res.statusCode} ${res.statusMessage}`);
10+
const { protocol } = parse(url);
11+
12+
if (protocol !== "http:" && protocol !== "https:") {
13+
throw new Error(`Unsupported protocol: "${protocol}". URL must start with "http://" or "https://".`);
14+
}
15+
16+
const fetchMethod = protocol === "https:" ? https : http;
17+
const req = fetchMethod.request(url, opts, (res) => {
18+
let rawData = "";
19+
res.setEncoding("utf8");
20+
res.on("data", (chunk) => {
21+
rawData += chunk;
22+
});
23+
res.on("end", () => {
24+
// 2xx: OK
25+
if (res.statusCode >= 200 && res.statusCode < 300) {
26+
return resolve(rawData);
27+
}
28+
29+
// 3xx: follow redirect (if given)
30+
if (res.statusCode >= 300 && res.headers.location) {
31+
redirectCount += 1;
32+
if (redirectCount >= MAX_REDIRECT_COUNT) {
33+
reject(`Max redirects exceeded`);
34+
return;
2935
}
30-
});
31-
}
32-
);
36+
console.log(`🚥 Redirecting to ${res.headers.location}…`);
37+
return fetch(res.headers.location, opts).then(resolve);
38+
}
39+
40+
// everything else: throw
41+
return reject(rawData || `${res.statusCode} ${res.statusMessage}`);
42+
});
43+
});
3344
req.on("error", (err) => {
3445
reject(err);
3546
});
3647
req.end();
3748
});
3849
}
50+
51+
function loadFromHttp(pathToSpec, { auth }) {
52+
return fetch(pathToSpec, { method: "GET", auth });
53+
}
3954
module.exports = loadFromHttp;

0 commit comments

Comments
 (0)