src/collectors/http.ts (view raw)
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 |
import got, { type Response } from 'got';
import type { Observations, Redirecionamento, CookieObservado } from '../core/types.js';
const USER_AGENT = 'Mozilla/5.0 (compatible; Red; +https://github.com/pablomurad/red)';
export interface RespostaHttp {
resposta: Response<string>;
redirecionamentos: Redirecionamento[];
}
export async function coletarHttp(
urlSolicitada: string,
obs: Observations,
): Promise<RespostaHttp | undefined> {
const redirecionamentos: Redirecionamento[] = [];
try {
const resposta = await got(urlSolicitada, {
method: 'GET',
throwHttpErrors: false,
followRedirect: true,
maxRedirects: 10,
timeout: { request: 15000 },
headers: {
'user-agent': USER_AGENT,
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'accept-language': 'pt-BR,pt;q=0.9,en;q=0.8',
},
hooks: {
beforeRedirect: [
(options, resp) => {
redirecionamentos.push({
de: resp.url,
para: options.url?.toString() ?? '',
status: resp.statusCode,
});
},
],
},
});
obs.urlFinal = resposta.url;
obs.statusFinal = resposta.statusCode;
obs.redirecionamentos = redirecionamentos;
obs.html = typeof resposta.body === 'string' ? resposta.body : '';
obs.headers = normalizarHeaders(resposta.headers);
obs.cookies = extrairCookies(resposta.headers['set-cookie']);
inferirServidorECdn(obs);
return { resposta, redirecionamentos };
} catch (erro) {
obs.avisos.push(`Falha ao buscar a URL: ${(erro as Error).message}`);
return undefined;
}
}
function normalizarHeaders(headers: Record<string, unknown>): Record<string, string> {
const saida: Record<string, string> = {};
for (const [chave, valor] of Object.entries(headers)) {
if (valor == null) continue;
saida[chave.toLowerCase()] = Array.isArray(valor) ? valor.join(', ') : String(valor);
}
return saida;
}
function extrairCookies(setCookie: string[] | undefined): CookieObservado[] {
if (!setCookie) return [];
return setCookie.map((linha) => {
const [par, ...resto] = linha.split(';');
const nome = (par ?? '').split('=')[0]?.trim() ?? '';
return { nome, atributos: resto.map((a) => a.trim()).join('; ') || undefined };
});
}
function inferirServidorECdn(obs: Observations): void {
const h = obs.headers;
if (h['server']) obs.servidorAparente = h['server'];
if (h['cf-ray'] || /cloudflare/i.test(h['server'] ?? '')) obs.cdnAparente = 'Cloudflare';
else if (h['x-vercel-id'] || /vercel/i.test(h['server'] ?? '')) obs.cdnAparente = 'Vercel';
else if (h['x-amz-cf-id'] || /cloudfront/i.test(h['via'] ?? '')) obs.cdnAparente = 'Amazon CloudFront';
else if (h['x-fastly-request-id'] || /fastly/i.test(h['via'] ?? '')) obs.cdnAparente = 'Fastly';
else if (h['x-akamai-transformed'] || /akamai/i.test(h['server'] ?? '')) obs.cdnAparente = 'Akamai';
else if (/netlify/i.test(h['server'] ?? '') || h['x-nf-request-id']) obs.cdnAparente = 'Netlify';
}
|