diff --git a/src/errors.ts b/src/errors.ts new file mode 100644 index 0000000..f686ce2 --- /dev/null +++ b/src/errors.ts @@ -0,0 +1,3 @@ +export class EngineParseError extends Error {} +export class InvalidParameterError extends Error {} +export class NotHtmlMimetypeError extends Error {} diff --git a/src/handlers/google.ts b/src/handlers/google.ts index e3ca526..116e02c 100644 --- a/src/handlers/google.ts +++ b/src/handlers/google.ts @@ -1,5 +1,6 @@ import { DOMWindow } from "jsdom"; import { IHandlerOutput } from "./handler.interface"; +import { EngineParseError } from "../errors"; export default async function google( window: DOMWindow @@ -9,7 +10,9 @@ export default async function google( ); if (!googleAnchors) { - throw new Error("Failed to find anchors in search result [google]"); + throw new EngineParseError( + "Failed to find anchors in search result [google]" + ); } const results = [...googleAnchors]; diff --git a/src/handlers/main.ts b/src/handlers/main.ts index 1a77b66..475d9b4 100644 --- a/src/handlers/main.ts +++ b/src/handlers/main.ts @@ -8,6 +8,8 @@ import readability from "./readability"; import google from "./google"; import { generateProxyUrl } from "../utils"; +import { InvalidParameterError, NotHtmlMimetypeError } from "../errors"; + export default async function handlePage( url: string, requestUrl: URL, @@ -15,18 +17,24 @@ export default async function handlePage( ): Promise { if (engine && engineList.indexOf(engine) === -1) { - throw new Error("Invalid engine"); + throw new InvalidParameterError("Invalid engine"); } const response = await axios.get(url); + const mime: string | undefined = ( + response.headers["content-type"]?.toString() + ); + + if (mime && mime.indexOf("text/html") === -1) { + throw new NotHtmlMimetypeError(); + } + const window = new JSDOM(response.data, { url: url }).window; [...window.document.getElementsByTagName("a")].forEach((link) => { link.href = generateProxyUrl(requestUrl, link.href, engine); }); - // maybe implement image proxy? - if (engine) { return engines[engine](window); } diff --git a/src/handlers/readability.ts b/src/handlers/readability.ts index f4388ea..191a754 100644 --- a/src/handlers/readability.ts +++ b/src/handlers/readability.ts @@ -1,6 +1,7 @@ import { Readability } from "@mozilla/readability"; import { IHandlerOutput } from "./handler.interface"; import { DOMWindow } from "jsdom"; +import { EngineParseError } from "../errors"; export default async function readability( window: DOMWindow @@ -9,7 +10,7 @@ export default async function readability( const parsed = reader.parse(); if (!parsed) { - throw new Error("Failed to parse [readability]"); + throw new EngineParseError("Failed to parse [readability]"); } return { diff --git a/src/routes/get.ts b/src/routes/get.ts index 413b1f9..8fd4f2e 100644 --- a/src/routes/get.ts +++ b/src/routes/get.ts @@ -4,6 +4,8 @@ import { GetSchema, IGetSchema } from "../types/requests"; import handlePage from "../handlers/main"; import { generateRequestUrl } from "../utils"; +import { NotHtmlMimetypeError } from "../errors"; + export default async function getRoute(fastify: FastifyInstance) { fastify.get( "/get", @@ -12,29 +14,30 @@ export default async function getRoute(fastify: FastifyInstance) { const remoteUrl = request.query.url; const engine = request.query.engine; - let format: string; + let parsed; + try { + parsed = await handlePage( + remoteUrl, + generateRequestUrl( + request.protocol, + request.hostname, + request.originalUrl + ), + engine + ); + } catch (err) { + if (err instanceof NotHtmlMimetypeError) { + return reply.redirect(301, remoteUrl); + } else { + throw err; + } + } if (request.query.format === "text") { reply.type("text/plain; charset=utf-8"); - format = "text"; - } else { - reply.type("text/html; charset=utf-8"); - format = "html"; - } - - const parsed = await handlePage( - remoteUrl, - generateRequestUrl( - request.protocol, - request.hostname, - request.originalUrl - ), - engine - ); - - if (format === "text") { return parsed.textContent; } else { + reply.type("text/html; charset=utf-8"); return reply.view("/templates/get.ejs", { parsed: parsed }); } }