Skip to content

Commit

Permalink
Merge pull request #1342 from DIYgod/master
Browse files Browse the repository at this point in the history
[pull] master from diygod:master
  • Loading branch information
pull[bot] authored Apr 7, 2024
2 parents 0b3a642 + b3a7186 commit 7caa2e5
Show file tree
Hide file tree
Showing 204 changed files with 790 additions and 319 deletions.
2 changes: 2 additions & 0 deletions lib/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import header from '@/middleware/header';
import antiHotlink from '@/middleware/anti-hotlink';
import parameter from '@/middleware/parameter';
import { jsxRenderer } from 'hono/jsx-renderer';
import { trimTrailingSlash } from 'hono/trailing-slash';

import logger from '@/utils/logger';

Expand All @@ -26,6 +27,7 @@ process.on('uncaughtException', (e) => {

const app = new Hono();

app.use(trimTrailingSlash());
app.use(compress());

app.use(
Expand Down
30 changes: 23 additions & 7 deletions lib/errors/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('httperror', () => {
it(`httperror`, async () => {
const response = await request.get('/test/httperror');
expect(response.status).toBe(503);
expect(response.text).toMatch('404 Not Found: target website might be blocking our access, you can host your own RSSHub instance for a better usability.');
expect(response.text).toMatch('FetchError: [GET] "https://httpbingo.org/status/404": 404 Not Found');
}, 20000);
});

Expand All @@ -31,10 +31,26 @@ describe('RequestInProgressError', () => {
const responses = await Promise.all([request.get('/test/slow'), request.get('/test/slow')]);
expect(new Set(responses.map((r) => r.status))).toEqual(new Set([200, 503]));
expect(new Set(responses.map((r) => r.headers['cache-control']))).toEqual(new Set([`public, max-age=${config.cache.routeExpire}`, `public, max-age=${config.requestTimeout / 1000}`]));
expect(responses.filter((r) => r.text.includes('This path is currently fetching, please come back later!'))).toHaveLength(1);
expect(responses.filter((r) => r.text.includes('RequestInProgressError: This path is currently fetching, please come back later!'))).toHaveLength(1);
});
});

describe('config-not-found-error', () => {
it(`config-not-found-error`, async () => {
const response = await request.get('/test/config-not-found-error');
expect(response.status).toBe(503);
expect(response.text).toMatch('ConfigNotFoundError: Test config not found error');
}, 20000);
});

describe('invalid-parameter-error', () => {
it(`invalid-parameter-error`, async () => {
const response = await request.get('/test/invalid-parameter-error');
expect(response.status).toBe(503);
expect(response.text).toMatch('InvalidParameterError: Test invalid parameter error');
}, 20000);
});

describe('route throws an error', () => {
it('route path error should have path mounted', async () => {
await request.get('/test/error');
Expand All @@ -47,19 +63,19 @@ describe('route throws an error', () => {
const value = $(item).find('.debug-value').html()?.trim();
switch (key) {
case 'Request Amount:':
expect(value).toBe('7');
expect(value).toBe('9');
break;
case 'Hot Routes:':
expect(value).toBe('4 /test/:id<br>');
expect(value).toBe('6 /test/:id<br>');
break;
case 'Hot Paths:':
expect(value).toBe('2 /test/error<br>2 /test/slow<br>1 /test/httperror<br>1 /thisDoesNotExist<br>1 /<br>');
expect(value).toBe('2 /test/error<br>2 /test/slow<br>1 /test/httperror<br>1 /test/config-not-found-error<br>1 /test/invalid-parameter-error<br>1 /thisDoesNotExist<br>1 /<br>');
break;
case 'Hot Error Routes:':
expect(value).toBe('3 /test/:id<br>');
expect(value).toBe('5 /test/:id<br>');
break;
case 'Hot Error Paths:':
expect(value).toBe('2 /test/error<br>1 /test/httperror<br>1 /test/slow<br>1 /thisDoesNotExist<br>');
expect(value).toBe('2 /test/error<br>1 /test/httperror<br>1 /test/slow<br>1 /test/config-not-found-error<br>1 /test/invalid-parameter-error<br>1 /thisDoesNotExist<br>');
break;
default:
}
Expand Down
46 changes: 23 additions & 23 deletions lib/errors/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import Sentry from '@sentry/node';
import logger from '@/utils/logger';
import Error from '@/views/error';

import RequestInProgressError from './request-in-progress';
import RejectError from './reject';
import NotFoundError from './not-found';
import NotFoundError from './types/not-found';

export const errorHandler: ErrorHandler = (error, ctx) => {
const requestPath = ctx.req.path;
Expand Down Expand Up @@ -38,27 +36,29 @@ export const errorHandler: ErrorHandler = (error, ctx) => {
});
}

let message = '';
if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError' || error.name === 'FetchError')) {
ctx.status(503);
message = `${error.message}: target website might be blocking our access, you can host your own RSSHub instance for a better usability.`;
} else if (error instanceof RequestInProgressError) {
ctx.header('Cache-Control', `public, max-age=${config.requestTimeout / 1000}`);
ctx.status(503);
message = error.message;
} else if (error instanceof RejectError) {
ctx.status(403);
message = error.message;
} else if (error instanceof NotFoundError) {
ctx.status(404);
message = 'wrong path';
if (ctx.req.path.endsWith('/')) {
message += ', you can try removing the trailing slash in the path';
}
} else {
ctx.status(503);
message = process.env.NODE_ENV === 'production' ? error.message : error.stack || error.message;
let errorMessage = process.env.NODE_ENV === 'production' ? error.message : error.stack || error.message;
switch (error.constructor.name) {
case 'HTTPError':
case 'RequestError':
case 'FetchError':
ctx.status(503);
break;
case 'RequestInProgressError':
ctx.header('Cache-Control', `public, max-age=${config.requestTimeout / 1000}`);
ctx.status(503);
break;
case 'RejectError':
ctx.status(403);
break;
case 'NotFoundError':
ctx.status(404);
errorMessage += 'The route does not exist or has been deleted.';
break;
default:
ctx.status(503);
break;
}
const message = `${error.name}: ${errorMessage}`;

logger.error(`Error in ${requestPath}: ${message}`);

Expand Down
3 changes: 0 additions & 3 deletions lib/errors/not-found.ts

This file was deleted.

3 changes: 0 additions & 3 deletions lib/errors/reject.ts

This file was deleted.

3 changes: 0 additions & 3 deletions lib/errors/request-in-progress.ts

This file was deleted.

5 changes: 5 additions & 0 deletions lib/errors/types/config-not-found.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class ConfigNotFoundError extends Error {
name = 'ConfigNotFoundError';
}

export default ConfigNotFoundError;
5 changes: 5 additions & 0 deletions lib/errors/types/invalid-parameter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class InvalidParameterError extends Error {
name = 'InvalidParameterError';
}

export default InvalidParameterError;
5 changes: 5 additions & 0 deletions lib/errors/types/not-found.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class NotFoundError extends Error {
name = 'NotFoundError';
}

export default NotFoundError;
5 changes: 5 additions & 0 deletions lib/errors/types/reject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class RejectError extends Error {
name = 'RejectError';
}

export default RejectError;
5 changes: 5 additions & 0 deletions lib/errors/types/request-in-progress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class RequestInProgressError extends Error {
name = 'RequestInProgressError';
}

export default RequestInProgressError;
2 changes: 1 addition & 1 deletion lib/middleware/access-control.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { MiddlewareHandler } from 'hono';
import { config } from '@/config';
import md5 from '@/utils/md5';
import RejectError from '@/errors/reject';
import RejectError from '@/errors/types/reject';

const reject = () => {
throw new RejectError('Authentication failed. Access denied.');
Expand Down
2 changes: 1 addition & 1 deletion lib/middleware/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import xxhash from 'xxhash-wasm';
import type { MiddlewareHandler } from 'hono';

import { config } from '@/config';
import RequestInProgressError from '@/errors/request-in-progress';
import RequestInProgressError from '@/errors/types/request-in-progress';
import cacheModule from '@/utils/cache/index';
import { Data } from '@/types';

Expand Down
2 changes: 1 addition & 1 deletion lib/middleware/parameter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ describe('wrong_path', () => {
const response = await app.request('/wrong');
expect(response.status).toBe(404);
expect(response.headers.get('cache-control')).toBe(`public, max-age=${config.cache.routeExpire}`);
expect(await response.text()).toMatch('wrong path');
expect(await response.text()).toMatch('The route does not exist or has been deleted.');
});
});

Expand Down
3 changes: 2 additions & 1 deletion lib/routes/12306/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import got from '@/utils/got';
import { art } from '@/utils/render';
import path from 'node:path';
import { config } from '@/config';
import InvalidParameterError from '@/errors/types/invalid-parameter';

const rootUrl = 'https://kyfw.12306.cn';

Expand Down Expand Up @@ -85,7 +86,7 @@ async function handler(ctx) {
},
});
if (response.data.data === undefined || response.data.data.length === 0) {
throw new Error('没有找到相关车次,请检查参数是否正确');
throw new InvalidParameterError('没有找到相关车次,请检查参数是否正确');
}
const data = response.data.data.result;
const map = response.data.data.map;
Expand Down
5 changes: 3 additions & 2 deletions lib/routes/163/news/rank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import iconv from 'iconv-lite';
import { parseDate } from '@/utils/parse-date';
import InvalidParameterError from '@/errors/types/invalid-parameter';

const rootUrl = 'https://news.163.com';

Expand Down Expand Up @@ -119,9 +120,9 @@ async function handler(ctx) {

const cfg = config[category];
if (!cfg) {
throw new Error('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
throw new InvalidParameterError('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
} else if ((category !== 'whole' && type === 'click' && time === 'month') || (category === 'whole' && type === 'click' && time === 'hour') || (type === 'follow' && time === 'hour')) {
throw new Error('Bad timeRange range. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
throw new InvalidParameterError('Bad timeRange range. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
}

const currentUrl = category === 'money' ? cfg.link : `${rootUrl}${cfg.link}`;
Expand Down
3 changes: 2 additions & 1 deletion lib/routes/163/news/special.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import InvalidParameterError from '@/errors/types/invalid-parameter';
import { Route } from '@/types';
import cache from '@/utils/cache';
import got from '@/utils/got';
Expand Down Expand Up @@ -43,7 +44,7 @@ export const route: Route = {

async function handler(ctx) {
if (!ctx.req.param('type')) {
throw new Error('Bad parameter. See <a href="https://docs.rsshub.app/routes/game#wang-yi-da-shen">https://docs.rsshub.app/routes/game#wang-yi-da-shen</a>');
throw new InvalidParameterError('Bad parameter. See <a href="https://docs.rsshub.app/routes/game#wang-yi-da-shen">https://docs.rsshub.app/routes/game#wang-yi-da-shen</a>');
}
const selectedType = Number.parseInt(ctx.req.param('type'));
let type;
Expand Down
3 changes: 2 additions & 1 deletion lib/routes/18comic/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';

const defaultDomain = 'jmcomic1.me';
// list of address: https://jmcomic2.bet
const allowDomain = new Set(['18comic.vip', '18comic.org', 'jmcomic.me', 'jmcomic1.me', 'jm-comic3.art', 'jm-comic.club', 'jm-comic2.ark']);

const getRootUrl = (domain) => {
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.has(domain)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}

return `https://${domain}`;
Expand Down
3 changes: 2 additions & 1 deletion lib/routes/19lou/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import timezone from '@/utils/timezone';
import { parseDate } from '@/utils/parse-date';
import iconv from 'iconv-lite';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';

const setCookie = function (cookieName, cookieValue, seconds, path, domain, secure) {
let expires = null;
Expand Down Expand Up @@ -52,7 +53,7 @@ export const route: Route = {
async function handler(ctx) {
const city = ctx.req.param('city') ?? 'www';
if (!isValidHost(city)) {
throw new Error('Invalid city');
throw new InvalidParameterError('Invalid city');
}

const rootUrl = `https://${city}.19lou.com`;
Expand Down
3 changes: 2 additions & 1 deletion lib/routes/4gamers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import got from '@/utils/got';
import path from 'node:path';
import { art } from '@/utils/render';
import { parseDate } from '@/utils/parse-date';
import InvalidParameterError from '@/errors/types/invalid-parameter';

const getCategories = (tryGet) =>
tryGet('4gamers:categories', async () => {
Expand Down Expand Up @@ -48,7 +49,7 @@ const parseItem = async (item) => {
case 'ImageGroupSection':
return renderImages(section.items);
default:
throw new Error(`Unhandled section type: ${section['@type']} on ${item.link}`);
throw new InvalidParameterError(`Unhandled section type: ${section['@type']} on ${item.link}`);
}
})
.join('')
Expand Down
3 changes: 2 additions & 1 deletion lib/routes/591/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { load } from 'cheerio';
import got from '@/utils/got';
import { art } from '@/utils/render';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';

const cookieJar = new CookieJar();

Expand Down Expand Up @@ -133,7 +134,7 @@ async function handler(ctx) {
const country = ctx.req.param('country') ?? 'tw';

if (!isValidHost(country) && country !== 'tw') {
throw new Error('Invalid country codes. Only "tw" is supported now.');
throw new InvalidParameterError('Invalid country codes. Only "tw" is supported now.');
}

/** @type {House[]} */
Expand Down
3 changes: 2 additions & 1 deletion lib/routes/91porn/utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const allowDomain = new Set(['91porn.com', 'www.91porn.com', '0122.91p30.com', 'www.91zuixindizhi.com', 'w1218.91p46.com']);

const domainValidation = (domain) => {
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.has(domain)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
};

Expand Down
7 changes: 4 additions & 3 deletions lib/routes/acfun/article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import cache from '@/utils/cache';
import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import InvalidParameterError from '@/errors/types/invalid-parameter';

const baseUrl = 'https://www.acfun.cn';
const categoryMap = {
Expand Down Expand Up @@ -66,13 +67,13 @@ export const route: Route = {
async function handler(ctx) {
const { categoryId, sortType = 'createTime', timeRange = 'all' } = ctx.req.param();
if (!categoryMap[categoryId]) {
throw new Error(`Invalid category Id: ${categoryId}`);
throw new InvalidParameterError(`Invalid category Id: ${categoryId}`);
}
if (!sortTypeEnum.has(sortType)) {
throw new Error(`Invalid sort type: ${sortType}`);
throw new InvalidParameterError(`Invalid sort type: ${sortType}`);
}
if (!timeRangeEnum.has(timeRange)) {
throw new Error(`Invalid time range: ${timeRange}`);
throw new InvalidParameterError(`Invalid time range: ${timeRange}`);
}

const url = `${baseUrl}/v/list${categoryId}/index.htm`;
Expand Down
3 changes: 2 additions & 1 deletion lib/routes/aip/journal-pupp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import { puppeteerGet, renderDesc } from './utils';
import { config } from '@/config';
import { isValidHost } from '@/utils/valid-host';
import puppeteer from '@/utils/puppeteer';
import InvalidParameterError from '@/errors/types/invalid-parameter';

const handler = async (ctx) => {
const pub = ctx.req.param('pub');
const jrn = ctx.req.param('jrn');
const host = `https://pubs.aip.org`;
const jrnlUrl = `${host}/${pub}/${jrn}/issue`;
if (!isValidHost(pub)) {
throw new Error('Invalid pub');
throw new InvalidParameterError('Invalid pub');
}

// use Puppeteer due to the obstacle by cloudflare challenge
Expand Down
3 changes: 2 additions & 1 deletion lib/routes/aisixiang/thinktank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';

import { rootUrl, ossUrl, ProcessFeed } from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';

export const route: Route = {
path: '/thinktank/:id/:type?',
Expand Down Expand Up @@ -43,7 +44,7 @@ async function handler(ctx) {
.toArray()
.filter((h) => (type ? $(h).text() === type : true));
if (!targetList) {
throw new Error(`Not found ${type} in ${id}: ${currentUrl}`);
throw new InvalidParameterError(`Not found ${type} in ${id}: ${currentUrl}`);
}

for (const l of targetList) {
Expand Down
Loading

0 comments on commit 7caa2e5

Please sign in to comment.