Template
Modelo do encurtador em Next.js
Gerado a partir de deploy-templates/nextjs (dado.cloud 57aa2a2).
This commit is contained in:
+34
-7
@@ -26,6 +26,37 @@ function passouDoLimite(ip: string): boolean {
|
||||
|
||||
const erro = (status: number, mensagem: string) => Response.json({ erro: mensagem }, { status, headers: CORS });
|
||||
|
||||
const CORPO_INVALIDO = 'Corpo inválido. Envie JSON no formato {"url": "https://..."}.';
|
||||
// Um pedido de encurtar link cabe com folga em 10 KB; mais que isso é recusado
|
||||
// sem ler o resto (o app é público: ninguém deve conseguir mandar megabytes).
|
||||
const TAMANHO_MAXIMO_CORPO = 10 * 1024;
|
||||
|
||||
/** Lê o corpo em pedaços e para assim que passar do limite (não confia só no Content-Length). */
|
||||
async function lerJsonLimitado(request: Request): Promise<{ url?: unknown } | null> {
|
||||
const declarado = request.headers.get('content-length');
|
||||
if (declarado !== null && !(/^\d+$/.test(declarado) && Number(declarado) <= TAMANHO_MAXIMO_CORPO)) return null;
|
||||
if (!request.body) return null;
|
||||
const leitor = request.body.getReader();
|
||||
const pedacos: Uint8Array[] = [];
|
||||
let total = 0;
|
||||
for (;;) {
|
||||
const { done, value } = await leitor.read();
|
||||
if (done) break;
|
||||
total += value.byteLength;
|
||||
if (total > TAMANHO_MAXIMO_CORPO) {
|
||||
await leitor.cancel();
|
||||
return null;
|
||||
}
|
||||
pedacos.push(value);
|
||||
}
|
||||
try {
|
||||
const dados: unknown = JSON.parse(Buffer.concat(pedacos).toString('utf8'));
|
||||
return dados && typeof dados === 'object' && !Array.isArray(dados) ? (dados as { url?: unknown }) : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function OPTIONS() {
|
||||
return new Response(null, { status: 204, headers: CORS });
|
||||
}
|
||||
@@ -42,14 +73,10 @@ export async function POST(request: Request) {
|
||||
const ip = request.headers.get('cf-connecting-ip') ?? request.headers.get('x-forwarded-for')?.split(',')[0].trim() ?? '?';
|
||||
if (passouDoLimite(ip)) return erro(429, 'Muitos links em pouco tempo. Espere alguns minutos e tente de novo.');
|
||||
|
||||
let corpo: { url?: unknown } | null;
|
||||
const corpo = await lerJsonLimitado(request);
|
||||
if (!corpo) return erro(400, CORPO_INVALIDO);
|
||||
try {
|
||||
corpo = await request.json();
|
||||
} catch {
|
||||
return erro(400, 'Corpo inválido. Envie JSON no formato {"url": "https://..."}.');
|
||||
}
|
||||
try {
|
||||
const link = criarLink(corpo?.url);
|
||||
const link = criarLink(corpo.url);
|
||||
return Response.json(paraJson(link, enderecoBase(request.headers)), { status: 201, headers: CORS });
|
||||
} catch (e) {
|
||||
if (e instanceof ErroDeValidacao) return erro(400, e.message);
|
||||
|
||||
Reference in New Issue
Block a user