got-scraping
Version:
HTTP client made for scraping based on got.
1,096 lines (1,073 loc) • 32.1 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// src/index.ts
import http3 from "node:http";
import https2 from "node:https";
import { got as originalGot, Options as Options8 } from "got";
import { HeaderGenerator as HeaderGenerator2 } from "header-generator";
// src/agent/transform-headers-agent.ts
import { HeaderGenerator } from "header-generator";
import { OutgoingMessage } from "node:http";
// src/agent/wrapped-agent.ts
import "node:http";
var _WrappedAgent = class _WrappedAgent {
constructor(agent) {
__publicField(this, "agent");
this.agent = agent;
}
addRequest(request, options) {
this.agent.addRequest(request, options);
}
get keepAlive() {
return this.agent.keepAlive;
}
get maxSockets() {
return this.agent.maxSockets;
}
get options() {
return this.agent.options;
}
get defaultPort() {
return this.agent.defaultPort;
}
get protocol() {
return this.agent.protocol;
}
destroy() {
this.agent.destroy();
}
// Let's implement `HttpAgent` so we don't have to
// type `WrappedAgent as unknown as HttpAgent`
get maxFreeSockets() {
return this.agent.maxFreeSockets;
}
get maxTotalSockets() {
return this.agent.maxTotalSockets;
}
get freeSockets() {
return this.agent.freeSockets;
}
get sockets() {
return this.agent.sockets;
}
get requests() {
return this.agent.requests;
}
on(eventName, listener) {
this.agent.on(eventName, listener);
return this;
}
once(eventName, listener) {
this.agent.once(eventName, listener);
return this;
}
off(eventName, listener) {
this.agent.off(eventName, listener);
return this;
}
addListener(eventName, listener) {
this.agent.addListener(eventName, listener);
return this;
}
removeListener(eventName, listener) {
this.agent.removeListener(eventName, listener);
return this;
}
removeAllListeners(eventName) {
this.agent.removeAllListeners(eventName);
return this;
}
setMaxListeners(n) {
this.agent.setMaxListeners(n);
return this;
}
getMaxListeners() {
return this.agent.getMaxListeners();
}
// eslint-disable-next-line @typescript-eslint/ban-types
listeners(eventName) {
return this.agent.listeners(eventName);
}
// eslint-disable-next-line @typescript-eslint/ban-types
rawListeners(eventName) {
return this.agent.rawListeners(eventName);
}
emit(eventName, ...args) {
return this.agent.emit(eventName, ...args);
}
eventNames() {
return this.agent.eventNames();
}
listenerCount(eventName) {
return this.agent.listenerCount(eventName);
}
prependListener(eventName, listener) {
this.agent.prependListener(eventName, listener);
return this;
}
prependOnceListener(eventName, listener) {
this.agent.prependOnceListener(eventName, listener);
return this;
}
};
__name(_WrappedAgent, "WrappedAgent");
var WrappedAgent = _WrappedAgent;
// src/agent/transform-headers-agent.ts
var { _storeHeader } = OutgoingMessage.prototype;
var generator = new HeaderGenerator();
var _TransformHeadersAgent = class _TransformHeadersAgent extends WrappedAgent {
// Rewritten from https://github.com/nodejs/node/blob/533cafcf7e3ab72e98a2478bc69aedfdf06d3a5e/lib/_http_outgoing.js#L442-L479
/**
* Transforms the request via header normalization.
*/
transformRequest(request, { sortHeaders }) {
const headers = {};
const hasConnection = request.hasHeader("connection");
const hasContentLength = request.hasHeader("content-length");
const hasTransferEncoding = request.hasHeader("transfer-encoding");
const hasTrailer = request.hasHeader("trailer");
const keys = request.getHeaderNames();
for (const key of keys) {
if (key.toLowerCase().startsWith("x-")) {
headers[key] = request.getHeader(key);
} else {
headers[this.toPascalCase(key)] = request.getHeader(key);
}
if (sortHeaders) {
request.removeHeader(key);
}
}
const typedRequest = request;
if (!hasConnection) {
const shouldSendKeepAlive = request.shouldKeepAlive && (hasContentLength || request.useChunkedEncodingByDefault || typedRequest.agent);
if (shouldSendKeepAlive) {
headers.Connection = "keep-alive";
} else {
headers.Connection = "close";
}
}
if (!hasContentLength && !hasTransferEncoding) {
if (!hasTrailer && !typedRequest._removedContLen && typeof typedRequest._contentLength === "number") {
headers["Content-Length"] = typedRequest._contentLength;
} else if (!typedRequest._removedTE) {
headers["Transfer-Encoding"] = "chunked";
}
}
const transformedHeaders = sortHeaders ? generator.orderHeaders(headers) : headers;
for (const [key, value] of Object.entries(transformedHeaders)) {
request.setHeader(key, value);
}
}
addRequest(request, options) {
const typedRequest = request;
typedRequest._storeHeader = (...args) => {
this.transformRequest(request, { sortHeaders: true });
return _storeHeader.call(request, ...args);
};
options.secureEndpoint = options.protocol === "https:";
return super.addRequest(request, options);
}
toPascalCase(header) {
return header.split("-").map((part) => {
return part[0].toUpperCase() + part.slice(1).toLowerCase();
}).join("-");
}
};
__name(_TransformHeadersAgent, "TransformHeadersAgent");
var TransformHeadersAgent = _TransformHeadersAgent;
// src/hooks/browser-headers.ts
import "got";
import http22 from "http2-wrapper";
import "node:url";
// src/resolve-protocol.ts
import { isIPv6 as isIPv62 } from "node:net";
import tls2 from "node:tls";
import { URL as URL3 } from "node:url";
import "got";
import { auto as auto2 } from "http2-wrapper";
import QuickLRU from "quick-lru";
// src/hooks/proxy.ts
import "got";
import http2, { auto } from "http2-wrapper";
import { URL as URL2 } from "node:url";
// src/agent/h1-proxy-agent.ts
import http from "node:http";
import https from "node:https";
import { isIPv6 } from "node:net";
import tls from "node:tls";
import { URL } from "node:url";
// src/auth.ts
function buildBasicAuthHeader(url) {
if (!url.username && !url.password) {
return null;
}
const username = decodeURIComponent(url.username ?? "");
const password = decodeURIComponent(url.password ?? "");
const basic = Buffer.from(`${username}:${password}`).toString("base64");
return `Basic ${basic}`;
}
__name(buildBasicAuthHeader, "buildBasicAuthHeader");
// src/agent/h1-proxy-agent.ts
var initialize = /* @__PURE__ */ __name((self, options) => {
self.proxy = typeof options.proxy === "string" ? new URL(options.proxy) : options.proxy;
}, "initialize");
var getPort = /* @__PURE__ */ __name((url) => {
if (url.port !== "") {
return Number(url.port);
}
if (url.protocol === "http:") {
return 80;
}
if (url.protocol === "https:") {
return 443;
}
throw new Error(`Unexpected protocol: ${url.protocol}`);
}, "getPort");
var _HttpRegularProxyAgent = class _HttpRegularProxyAgent extends http.Agent {
constructor(options) {
super(options);
__publicField(this, "proxy");
initialize(this, options);
}
addRequest(request, options) {
if (options.socketPath) {
super.addRequest(request, options);
return;
}
let hostport = `${options.host}:${options.port}`;
if (isIPv6(options.host)) {
hostport = `[${options.host}]:${options.port}`;
}
const url = new URL(`${request.protocol}//${hostport}${request.path}`);
options = {
...options,
host: this.proxy.hostname,
port: getPort(this.proxy)
};
request.path = url.href;
const basic = buildBasicAuthHeader(this.proxy);
if (basic) {
request.setHeader("proxy-authorization", basic);
}
super.addRequest(request, options);
}
};
__name(_HttpRegularProxyAgent, "HttpRegularProxyAgent");
var HttpRegularProxyAgent = _HttpRegularProxyAgent;
var _HttpProxyAgent = class _HttpProxyAgent extends http.Agent {
constructor(options) {
super(options);
__publicField(this, "proxy");
initialize(this, options);
}
createConnection(options, callback) {
if (options.path) {
super.createConnection(options, callback);
return;
}
const fn = this.proxy.protocol === "https:" ? https.request : http.request;
let hostport = `${options.host}:${options.port}`;
if (isIPv6(options.host)) {
hostport = `[${options.host}]:${options.port}`;
}
const headers = {
host: hostport
};
const basic = buildBasicAuthHeader(this.proxy);
if (basic) {
headers["proxy-authorization"] = basic;
headers.authorization = basic;
}
const connectRequest = fn(this.proxy, {
method: "CONNECT",
headers,
path: hostport,
agent: false,
rejectUnauthorized: false
});
connectRequest.once("connect", (response, socket, head) => {
if (head.length > 0 || response.statusCode !== 200) {
socket.destroy();
const error = new Error(`The proxy responded with ${response.statusCode} ${response.statusMessage}: ${head.toString()}`);
callback(error);
return;
}
if (options.protocol === "https:") {
callback(void 0, tls.connect({
...options,
socket
}));
return;
}
callback(void 0, socket);
});
connectRequest.once("error", (error) => {
callback(error);
});
connectRequest.end();
}
};
__name(_HttpProxyAgent, "HttpProxyAgent");
var HttpProxyAgent = _HttpProxyAgent;
var _HttpsProxyAgent = class _HttpsProxyAgent extends https.Agent {
constructor(options) {
super(options);
__publicField(this, "proxy");
initialize(this, options);
}
createConnection(options, callback) {
HttpProxyAgent.prototype.createConnection.call(this, options, callback);
}
};
__name(_HttpsProxyAgent, "HttpsProxyAgent");
var HttpsProxyAgent = _HttpsProxyAgent;
// src/hooks/proxy.ts
var {
HttpOverHttp2,
HttpsOverHttp2,
Http2OverHttp2,
Http2OverHttps,
Http2OverHttp
} = http2.proxies;
async function proxyHook(options) {
const { context: { proxyUrl } } = options;
if (proxyUrl) {
const parsedProxy = new URL2(proxyUrl);
validateProxyProtocol(parsedProxy.protocol);
options.agent = await getAgents(parsedProxy, options.https.rejectUnauthorized);
}
}
__name(proxyHook, "proxyHook");
var _ProxyError = class _ProxyError extends Error {
};
__name(_ProxyError, "ProxyError");
var ProxyError = _ProxyError;
function validateProxyProtocol(protocol) {
const isSupported = protocol === "http:" || protocol === "https:";
if (!isSupported) {
throw new ProxyError(`Proxy URL protocol "${protocol}" is not supported. Please use HTTP or HTTPS.`);
}
}
__name(validateProxyProtocol, "validateProxyProtocol");
async function getAgents(parsedProxyUrl, rejectUnauthorized) {
const headers = {};
const basic = buildBasicAuthHeader(parsedProxyUrl);
if (basic) {
headers.authorization = basic;
headers["proxy-authorization"] = basic;
}
const wrapperOptions = {
proxyOptions: {
url: parsedProxyUrl,
headers,
// Based on the got https.rejectUnauthorized option
rejectUnauthorized
},
// The sockets won't be reused, no need to keep them
maxFreeSockets: 0,
maxEmptySessions: 0
};
const nativeOptions = {
proxy: parsedProxyUrl,
// The sockets won't be reused, no need to keep them
maxFreeSockets: 0
};
let agent;
if (parsedProxyUrl.protocol === "https:") {
let alpnProtocol = "http/1.1";
try {
const result = await auto.resolveProtocol({
host: parsedProxyUrl.hostname,
port: parsedProxyUrl.port,
rejectUnauthorized,
ALPNProtocols: ["h2", "http/1.1"],
servername: parsedProxyUrl.hostname
});
alpnProtocol = result.alpnProtocol;
} catch {
}
const proxyIsHttp2 = alpnProtocol === "h2";
if (proxyIsHttp2) {
agent = {
http: new TransformHeadersAgent(new HttpOverHttp2(wrapperOptions)),
https: new TransformHeadersAgent(new HttpsOverHttp2(wrapperOptions)),
http2: new Http2OverHttp2(wrapperOptions)
};
} else {
agent = {
http: new TransformHeadersAgent(new HttpProxyAgent(nativeOptions)),
https: new TransformHeadersAgent(new HttpsProxyAgent(nativeOptions)),
http2: new Http2OverHttps(wrapperOptions)
};
}
} else {
agent = {
http: new TransformHeadersAgent(new HttpRegularProxyAgent(nativeOptions)),
https: new TransformHeadersAgent(new HttpsProxyAgent(nativeOptions)),
http2: new Http2OverHttp(wrapperOptions)
};
}
return agent;
}
__name(getAgents, "getAgents");
// src/resolve-protocol.ts
var connect = /* @__PURE__ */ __name(async (proxyUrl, options, callback) => new Promise((resolve, reject) => {
let host = `${options.host}:${options.port}`;
if (isIPv62(options.host)) {
host = `[${options.host}]:${options.port}`;
}
void (async () => {
try {
const headers = {
host
};
const url = new URL3(proxyUrl);
const basic = buildBasicAuthHeader(url);
if (basic) {
headers.authorization = basic;
headers["proxy-authorization"] = basic;
}
const request = await auto2(url, {
method: "CONNECT",
headers,
path: host,
// TODO: this property doesn't exist according to the types
pathname: host,
rejectUnauthorized: false
});
request.end();
request.once("error", reject);
request.once("connect", (response, socket, head) => {
if (response.statusCode !== 200 || head.length > 0) {
reject(new ProxyError(`Proxy responded with ${response.statusCode} ${response.statusMessage}: ${head.length} bytes.
Below is the first 100 bytes of the proxy response body:
${head.toString("utf8", 0, 100)}`, { cause: head.toString("utf8") }));
socket.destroy();
return;
}
const tlsSocket = tls2.connect({
...options,
socket
}, callback);
resolve(tlsSocket);
});
} catch (error) {
reject(error);
}
})();
}), "connect");
var createCaches = /* @__PURE__ */ __name(() => ({
protocolCache: new QuickLRU({ maxSize: 1e3 }),
resolveAlpnQueue: /* @__PURE__ */ new Map()
}), "createCaches");
var defaults = createCaches();
var createResolveProtocol = /* @__PURE__ */ __name((proxyUrl, sessionData, timeout) => {
let { protocolCache, resolveAlpnQueue } = defaults;
if (sessionData) {
if (!sessionData.protocolCache || !sessionData.resolveAlpnQueue) {
Object.assign(sessionData, createCaches());
}
protocolCache = sessionData.protocolCache;
resolveAlpnQueue = sessionData.resolveAlpnQueue;
}
const connectWithProxy = /* @__PURE__ */ __name(async (pOptions, pCallback) => {
return connect(proxyUrl, pOptions, pCallback);
}, "connectWithProxy");
const resolveProtocol = auto2.createResolveProtocol(
protocolCache,
resolveAlpnQueue,
connectWithProxy
);
return async (...args) => resolveProtocol({
...args[0],
timeout
});
}, "createResolveProtocol");
// src/hooks/browser-headers.ts
function mergeHeaders(original, overrides) {
const fixedHeaders = /* @__PURE__ */ new Map();
for (const entry of Object.entries(original)) {
fixedHeaders.set(entry[0].toLowerCase(), entry);
}
for (const entry of Object.entries(overrides)) {
fixedHeaders.set(entry[0].toLowerCase(), entry);
}
return Object.fromEntries(fixedHeaders.values());
}
__name(mergeHeaders, "mergeHeaders");
var getResolveProtocolFunction = /* @__PURE__ */ __name((options, proxyUrl, sessionData) => {
const { resolveProtocol } = options;
if (resolveProtocol) {
return resolveProtocol;
}
if (proxyUrl) {
return createResolveProtocol(proxyUrl, sessionData, Math.min(options?.timeout?.connect ?? 6e4, options?.timeout?.request ?? 6e4));
}
return (...args) => http22.auto.resolveProtocol({
...args[0],
timeout: Math.min(options?.timeout?.connect ?? 6e4, options?.timeout?.request ?? 6e4)
});
}, "getResolveProtocolFunction");
async function browserHeadersHook(options) {
const { context } = options;
const {
headerGeneratorOptions,
useHeaderGenerator,
headerGenerator,
proxyUrl
} = context;
const sessionData = context.sessionData;
if (!useHeaderGenerator || !headerGenerator)
return;
const createHeadersPair = /* @__PURE__ */ __name(() => ({
1: headerGenerator.getHeaders({
httpVersion: "1",
...headerGeneratorOptions
}),
2: headerGenerator.getHeaders({
httpVersion: "2",
...headerGeneratorOptions
})
}), "createHeadersPair");
const url = options.url;
const resolveProtocol = getResolveProtocolFunction(options, proxyUrl, sessionData);
let alpnProtocol;
if (url.protocol === "https:") {
alpnProtocol = (await resolveProtocol({
host: url.hostname,
port: url.port || 443,
rejectUnauthorized: false,
ALPNProtocols: ["h2", "http/1.1"],
servername: url.hostname
})).alpnProtocol;
}
const httpVersion = alpnProtocol === "h2" ? "2" : "1";
let generatedHeaders;
if (sessionData) {
if (!sessionData.headers) {
sessionData.headers = createHeadersPair();
}
generatedHeaders = sessionData.headers[httpVersion];
} else {
generatedHeaders = headerGenerator.getHeaders({
httpVersion,
...headerGeneratorOptions
});
}
if (!options.decompress) {
for (const key of Object.keys(generatedHeaders)) {
if (key.toLowerCase() === "accept-encoding") {
delete generatedHeaders[key];
}
}
}
options.headers = mergeHeaders(generatedHeaders, options.headers);
}
__name(browserHeadersHook, "browserHeadersHook");
// src/hooks/custom-options.ts
import "got";
function customOptionsHook(raw, options) {
const typedRaw = raw;
const names = [
"proxyUrl",
"headerGeneratorOptions",
"useHeaderGenerator",
"insecureHTTPParser",
"sessionToken"
];
for (const name of names) {
if (name in raw) {
options.context[name] = typedRaw[name];
delete typedRaw[name];
}
}
}
__name(customOptionsHook, "customOptionsHook");
// src/hooks/fix-decompress.ts
import zlib from "node:zlib";
import "node:http";
import { PassThrough } from "node:stream";
import mimicResponse from "mimic-response";
var onResponse = /* @__PURE__ */ __name((response, propagate) => {
const encoding = response.headers["content-encoding"]?.toLowerCase();
const zlibOptions = {
flush: zlib.constants.Z_SYNC_FLUSH,
finishFlush: zlib.constants.Z_SYNC_FLUSH
};
const useDecompressor = /* @__PURE__ */ __name((decompressor) => {
delete response.headers["content-encoding"];
const result = new PassThrough({
autoDestroy: false,
destroy(error, callback) {
response.destroy();
callback(error);
}
});
decompressor.once("error", (error) => {
result.destroy(error);
});
response.pipe(decompressor).pipe(result);
propagate(mimicResponse(response, result));
}, "useDecompressor");
if (encoding === "gzip" || encoding === "x-gzip") {
useDecompressor(zlib.createGunzip(zlibOptions));
} else if (encoding === "deflate" || encoding === "x-deflate") {
let read = false;
response.once("data", (chunk) => {
read = true;
response.unshift(chunk);
const decompressor = (chunk[0] & 15) === 8 ? zlib.createInflate() : zlib.createInflateRaw();
useDecompressor(decompressor);
});
response.once("end", () => {
if (!read) {
propagate(response);
}
});
} else if (encoding === "br") {
let read = false;
response.once("data", (chunk) => {
read = true;
response.unshift(chunk);
const decompressor = zlib.createBrotliDecompress();
useDecompressor(decompressor);
});
response.once("end", () => {
if (!read) {
propagate(response);
}
});
} else {
propagate(response);
}
}, "onResponse");
var fixDecompress = /* @__PURE__ */ __name((options, next) => {
const result = next(options);
result.on("request", (request) => {
const emit = request.emit.bind(request);
request.emit = (event, ...args) => {
if (event === "response" && options.decompress) {
const response = args[0];
const emitted = request.listenerCount("response") !== 0;
onResponse(response, (fixedResponse) => {
emit("response", fixedResponse);
});
return emitted;
}
return emit(event, ...args);
};
});
return result;
}, "fixDecompress");
// src/hooks/http2.ts
import "node:url";
import "got";
import { auto as auto3 } from "http2-wrapper";
function http2Hook(options) {
const { proxyUrl, sessionData } = options.context;
if (options.http2 && options.url.protocol !== "http:") {
options.request = (url, requestOptions, callback) => {
const typedRequestOptions = requestOptions;
if (proxyUrl) {
typedRequestOptions.resolveProtocol = createResolveProtocol(
proxyUrl,
sessionData,
Math.min(options?.timeout?.connect ?? 6e4, options?.timeout?.request ?? 6e4)
);
}
return auto3(url, typedRequestOptions, callback);
};
} else {
options.request = void 0;
}
}
__name(http2Hook, "http2Hook");
// src/hooks/insecure-parser.ts
import "got";
function insecureParserHook(options) {
if (options.context.insecureHTTPParser !== void 0) {
options._unixOptions = {
// @ts-expect-error Private use
...options._unixOptions,
insecureHTTPParser: options.context.insecureHTTPParser
};
}
}
__name(insecureParserHook, "insecureParserHook");
// src/hooks/options-validation.ts
import ow from "ow";
var validationSchema = {
proxyUrl: ow.optional.string.url,
useHeaderGenerator: ow.optional.boolean,
headerGeneratorOptions: ow.optional.object,
insecureHTTPParser: ow.optional.boolean,
sessionToken: ow.optional.object
};
function optionsValidationHandler(options) {
ow(options, ow.object.partialShape(validationSchema));
}
__name(optionsValidationHandler, "optionsValidationHandler");
// src/hooks/referer.ts
import { URL as URL6 } from "node:url";
var refererHook = /* @__PURE__ */ __name((options, response) => {
const url = options.url;
const resUrl = new URL6(response.url);
const policy = response.headers["referer-policy"] || "strict-origin-when-cross-origin";
if (policy === "no-referrer") {
delete options.headers.referer;
} else if (policy === "no-referrer-when-downgrade") {
if (resUrl.protocol === "https:" && url.protocol === "http:") {
delete options.headers.referer;
} else {
options.headers.referer = `${resUrl.origin}${resUrl.pathname}${resUrl.search}`;
}
} else if (policy === "origin") {
options.headers.referer = resUrl.origin;
} else if (policy === "origin-when-cross-origin") {
if (url.origin === resUrl.origin) {
options.headers.referer = `${resUrl.origin}${resUrl.pathname}${resUrl.search}`;
} else {
options.headers.referer = resUrl.origin;
}
} else if (policy === "same-origin") {
if (url.origin === resUrl.origin) {
options.headers.referer = `${resUrl.origin}${resUrl.pathname}${resUrl.search}`;
} else {
delete options.headers.referer;
}
} else if (policy === "strict-origin") {
if (resUrl.protocol === "https:" && url.protocol === "http:") {
delete options.headers.referer;
} else {
options.headers.referer = resUrl.origin;
}
} else if (policy === "strict-origin-when-cross-origin") {
if (url.origin === resUrl.origin) {
options.headers.referer = `${resUrl.origin}${resUrl.pathname}${resUrl.search}`;
} else if (resUrl.protocol === "https:" && url.protocol === "http:") {
delete options.headers.referer;
} else {
options.headers.referer = resUrl.origin;
}
} else if (policy === "unsafe-url") {
options.headers.referer = `${resUrl.origin}${resUrl.pathname}${resUrl.search}`;
}
}, "refererHook");
// src/hooks/storage.ts
import "got";
var _Storage = class _Storage {
constructor() {
__publicField(this, "storage");
this.storage = /* @__PURE__ */ new WeakMap();
}
get(token) {
if (!token) {
return;
}
if (!this.storage.has(token)) {
this.storage.set(token, {});
}
return this.storage.get(token);
}
};
__name(_Storage, "Storage");
var Storage = _Storage;
var storage = new Storage();
var sessionDataHook = /* @__PURE__ */ __name((options) => {
options.context.sessionData = storage.get(options.context.sessionToken);
}, "sessionDataHook");
// src/hooks/tls.ts
import "got";
var supportsFirefoxFully = Number(process.versions.node.split(".")[0]) >= 17;
var SSL_OP_TLSEXT_PADDING = 1 << 4;
var SSL_OP_NO_ENCRYPT_THEN_MAC = 1 << 19;
var ecdhCurve = {
firefox: (supportsFirefoxFully ? [
"X25519",
"prime256v1",
"secp384r1",
"secp521r1",
"ffdhe2048",
"ffdhe3072"
] : [
"X25519",
"prime256v1",
"secp384r1",
"secp521r1"
]).join(":"),
chrome: [
"X25519",
"prime256v1",
"secp384r1"
].join(":"),
safari: [
"X25519",
"prime256v1",
"secp384r1",
"secp521r1"
].join(":")
};
var sigalgs = {
firefox: [
"ecdsa_secp256r1_sha256",
"ecdsa_secp384r1_sha384",
"ecdsa_secp521r1_sha512",
"rsa_pss_rsae_sha256",
"rsa_pss_rsae_sha384",
"rsa_pss_rsae_sha512",
"rsa_pkcs1_sha256",
"rsa_pkcs1_sha384",
"rsa_pkcs1_sha512",
"ECDSA+SHA1",
"rsa_pkcs1_sha1"
].join(":"),
chrome: [
"ecdsa_secp256r1_sha256",
"rsa_pss_rsae_sha256",
"rsa_pkcs1_sha256",
"ecdsa_secp384r1_sha384",
"rsa_pss_rsae_sha384",
"rsa_pkcs1_sha384",
"rsa_pss_rsae_sha512",
"rsa_pkcs1_sha512"
].join(":"),
safari: [
"ecdsa_secp256r1_sha256",
"rsa_pss_rsae_sha256",
"rsa_pkcs1_sha256",
"ecdsa_secp384r1_sha384",
"ECDSA+SHA1",
"rsa_pss_rsae_sha384",
"rsa_pkcs1_sha384",
"rsa_pss_rsae_sha512",
"rsa_pkcs1_sha512",
"RSA+SHA1"
].join(":")
};
var knownCiphers = {
chrome: [
// Chrome v92
"TLS_AES_128_GCM_SHA256",
"TLS_AES_256_GCM_SHA384",
"TLS_CHACHA20_POLY1305_SHA256",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
"ECDHE-ECDSA-CHACHA20-POLY1305",
"ECDHE-RSA-CHACHA20-POLY1305",
// Legacy:
"ECDHE-RSA-AES128-SHA",
"ECDHE-RSA-AES256-SHA",
"AES128-GCM-SHA256",
"AES256-GCM-SHA384",
"AES128-SHA",
"AES256-SHA"
].join(":"),
firefox: [
// Firefox v91
"TLS_AES_128_GCM_SHA256",
"TLS_CHACHA20_POLY1305_SHA256",
"TLS_AES_256_GCM_SHA384",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-CHACHA20-POLY1305",
"ECDHE-RSA-CHACHA20-POLY1305",
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES256-GCM-SHA384",
// Legacy:
"ECDHE-ECDSA-AES256-SHA",
"ECDHE-ECDSA-AES128-SHA",
"ECDHE-RSA-AES128-SHA",
"ECDHE-RSA-AES256-SHA",
"AES128-GCM-SHA256",
"AES256-GCM-SHA384",
"AES128-SHA",
"AES256-SHA",
"DES-CBC3-SHA"
].join(":"),
safari: [
// Safari v14
"TLS_AES_128_GCM_SHA256",
"TLS_AES_256_GCM_SHA384",
"TLS_CHACHA20_POLY1305_SHA256",
"ECDHE-ECDSA-AES256-GCM-SHA384",
"ECDHE-ECDSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-CHACHA20-POLY1305",
"ECDHE-RSA-AES256-GCM-SHA384",
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-RSA-CHACHA20-POLY1305",
// Legacy:
"ECDHE-ECDSA-AES256-SHA384",
"ECDHE-ECDSA-AES128-SHA256",
"ECDHE-ECDSA-AES256-SHA",
"ECDHE-ECDSA-AES128-SHA",
"ECDHE-RSA-AES256-SHA384",
"ECDHE-RSA-AES128-SHA256",
"ECDHE-RSA-AES256-SHA",
"ECDHE-RSA-AES128-SHA",
"AES256-GCM-SHA384",
"AES128-GCM-SHA256",
"AES256-SHA256",
"AES128-SHA256",
"AES256-SHA",
"AES128-SHA",
"ECDHE-ECDSA-DES-CBC3-SHA",
"ECDHE-RSA-DES-CBC3-SHA",
"DES-CBC3-SHA"
].join(":")
};
var minVersion = {
firefox: "TLSv1.2",
chrome: "TLSv1",
safari: "TLSv1.2"
};
var maxVersion = {
firefox: "TLSv1.3",
chrome: "TLSv1.3",
safari: "TLSv1.3"
};
var secureOptions = {
firefox: SSL_OP_TLSEXT_PADDING | SSL_OP_NO_ENCRYPT_THEN_MAC,
chrome: SSL_OP_TLSEXT_PADDING | SSL_OP_NO_ENCRYPT_THEN_MAC,
safari: SSL_OP_TLSEXT_PADDING | SSL_OP_NO_ENCRYPT_THEN_MAC
};
var requestOCSP = {
firefox: true,
chrome: true,
safari: true
};
var getUserAgent = /* @__PURE__ */ __name((headers) => {
for (const [header, value] of Object.entries(headers)) {
if (header.toLowerCase() === "user-agent") {
return value;
}
}
return void 0;
}, "getUserAgent");
var getBrowser = /* @__PURE__ */ __name((userAgent) => {
if (!userAgent) {
return;
}
let browser;
if (userAgent.includes("Firefox")) {
browser = "firefox";
} else if (userAgent.includes("Chrome")) {
browser = "chrome";
} else {
browser = "safari";
}
return browser;
}, "getBrowser");
function tlsHook(options) {
const { https: https3 } = options;
if (https3.ciphers || https3.signatureAlgorithms || https3.minVersion || https3.maxVersion) {
return;
}
const browser = getBrowser(getUserAgent(options.headers)) ?? "firefox";
https3.ciphers = knownCiphers[browser];
https3.signatureAlgorithms = sigalgs[browser];
https3.ecdhCurve = ecdhCurve[browser];
https3.minVersion = minVersion[browser];
https3.maxVersion = maxVersion[browser];
options._unixOptions = {
// @ts-expect-error Private use
...options._unixOptions,
secureOptions: secureOptions[browser],
requestOCSP: requestOCSP[browser]
};
}
__name(tlsHook, "tlsHook");
// src/index.ts
export * from "got";
var handlers = [
fixDecompress
];
var beforeRequest = [
insecureParserHook,
sessionDataHook,
http2Hook,
proxyHook,
browserHeadersHook,
tlsHook
];
var init = [
optionsValidationHandler,
customOptionsHook
];
var beforeRedirect = [
refererHook
];
var gotScraping = originalGot.extend({
handlers,
mutableDefaults: true,
// Most of the new browsers use HTTP/2
http2: true,
https: {
// In contrast to browsers, we don't usually do login operations.
// We want the content.
rejectUnauthorized: false
},
// Don't fail on 404
throwHttpErrors: false,
timeout: { request: 6e4 },
retry: { limit: 0 },
headers: {
"user-agent": void 0
},
context: {
headerGenerator: new HeaderGenerator2(),
useHeaderGenerator: true,
insecureHTTPParser: true
},
agent: {
http: new TransformHeadersAgent(http3.globalAgent),
https: new TransformHeadersAgent(https2.globalAgent)
},
hooks: {
init,
beforeRequest,
beforeRedirect
}
});
var setupDecodeURI = /* @__PURE__ */ __name(() => {
const { set } = Object.getOwnPropertyDescriptor(Options8.prototype, "url");
Object.defineProperty(Options8.prototype, "url", {
set(value) {
const originalDecodeURI = global.decodeURI;
global.decodeURI = (str) => str;
try {
return set.call(this, value);
} finally {
global.decodeURI = originalDecodeURI;
}
}
});
}, "setupDecodeURI");
setupDecodeURI();
var hooks = {
init,
beforeRequest,
beforeRedirect,
fixDecompress,
insecureParserHook,
sessionDataHook,
http2Hook,
proxyHook,
browserHeadersHook,
tlsHook,
optionsValidationHandler,
customOptionsHook,
refererHook
};
export {
TransformHeadersAgent,
gotScraping,
hooks
};
//# sourceMappingURL=index.js.map