-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathindex.mjs
121 lines (116 loc) · 4.07 KB
/
index.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import nodeFetch, {
Headers,
Request,
Response,
FetchError,
AbortError
} from "node-fetch";
import CookieJar from "./cookie-jar.mjs";
import Cookie from "./cookie.mjs";
import {paramError, CookieParseError} from "./errors.mjs";
const {isRedirect} = nodeFetch;
async function fetch(cookieJars, url, options) {
let cookies = "";
const addValidFromJars = jars => {
// since multiple cookie jars can be passed, filter duplicates by using a set of cookie names
const set = new Set();
jars.flatMap(jar => [...jar.cookiesValidForRequest(url)]).forEach(
cookie => {
if (set.has(cookie.name)) return;
set.add(cookie.name);
cookies += cookie.serialize() + "; ";
}
);
};
if (cookieJars) {
if (
Array.isArray(cookieJars) &&
cookieJars.every(c => c instanceof CookieJar)
)
addValidFromJars(cookieJars.filter(jar => jar.flags.includes("r")));
else if (cookieJars instanceof CookieJar)
if (cookieJars.flags.includes("r")) addValidFromJars([cookieJars]);
else
throw paramError("First", "cookieJars", "fetch", [
"CookieJar",
"[CookieJar]"
]);
}
const wantFollow =
!options || !options.redirect || options.redirect === "follow";
if (!options) {
if (cookies || wantFollow) options = {};
}
// shallow copy so we don't modify the original options object
else options = {...options};
if (
options.follow !== undefined &&
(!Number.isSafeInteger(options.follow) || options.follow < 0)
)
throw new TypeError("options.follow is not a safe positive integer");
// copy Headers as well so we don't modify it
// or, if headers is an object, construct a Headers object from it
options.headers = new Headers(options.headers);
if (cookies) {
if (options.headers.has("cookie"))
throw new Error(
"options.headers already contains a cookie header!"
);
options.headers.append("cookie", cookies.slice(0, -2));
}
if (wantFollow) options.redirect = "manual";
const result = await nodeFetch(url, options);
// I cannot use headers.get() here because it joins the cookies to a string
cookies = result.headers.raw()["set-cookie"];
if (cookies && cookieJars) {
if (Array.isArray(cookieJars)) {
cookieJars
.filter(jar => jar.flags.includes("w"))
.forEach(jar => cookies.forEach(c => jar.addCookie(c, url)));
} else if (
cookieJars instanceof CookieJar &&
cookieJars.flags.includes("w")
)
cookies.forEach(c => cookieJars.addCookie(c, url));
}
if (wantFollow && isRedirect(result.status)) {
if (options.follow !== undefined && --options.follow < 0)
throw new FetchError(
"maximum redirect reached at: " + url,
"max-redirect"
);
// change method to "GET" and remove body & content-length if response is 303 or 301/302 with POST method
if (
result.status === 303 ||
((result.status === 301 || result.status === 302) &&
typeof options.method === "string" &&
options.method.toUpperCase() === "POST")
) {
options.method = "GET";
delete options.body;
if (options.headers) {
options.headers.delete("content-length");
}
}
const location = result.headers.get("location");
options.redirect = "follow";
// delete cookie header from previous request to avoid a duplicate cookie header
options.headers.delete("cookie");
return fetch(cookieJars, location, options);
}
return result;
}
export default fetch;
export {
fetch,
CookieJar,
Cookie,
CookieParseError,
nodeFetch,
Headers,
Request,
Response,
FetchError,
AbortError,
isRedirect
};