fix(core/utils/anti-hotlink): invalid HTML output (#9669)
Signed-off-by: Rongrong <i@rong.moe>
This commit is contained in:
parent
d5e1217498
commit
616ad78c88
|
|
@ -16,7 +16,13 @@ const parseUrl = (str) => {
|
|||
return url;
|
||||
};
|
||||
const replaceUrls = (body, template) => {
|
||||
const $ = cheerio.load(body, { decodeEntities: false, xmlMode: true });
|
||||
// const $ = cheerio.load(body, { decodeEntities: false, xmlMode: true });
|
||||
// `<br><img><hr><video><source>abc</video>` => `<br><img><hr><video><source>abc</source></video></hr></img></br>`
|
||||
// so awful...
|
||||
// "In HTML, using a closing tag on an empty element is usually invalid."
|
||||
// https://developer.mozilla.org/en-US/docs/Glossary/Empty_element
|
||||
// I guess it is just a workaround to drop `<html><head></head><body>`, so this is what we exactly need:
|
||||
const $ = cheerio.load(body, null, false);
|
||||
$('img').each(function () {
|
||||
const old_src = $(this).attr('src');
|
||||
const url = parseUrl(old_src);
|
||||
|
|
@ -35,7 +41,7 @@ module.exports = async (ctx, next) => {
|
|||
const template = config.hotlink.template;
|
||||
// Assume that only description include image link
|
||||
// and here we will only check them in description.
|
||||
// Use Cherrio to load the description as html and filter all
|
||||
// Use Cheerio to load the description as html and filter all
|
||||
// image link
|
||||
if (template) {
|
||||
if (ctx.state.data) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,13 @@ afterEach(() => {
|
|||
});
|
||||
|
||||
describe('anti-hotlink', () => {
|
||||
// First-time require is really, really slow.
|
||||
// If someone merely runs this test unit instead of the whole suite and this stage does not exist,
|
||||
// the next one will sometimes time out, so we need to firstly require it once.
|
||||
it('server-require', () => {
|
||||
server = require('../../lib/index');
|
||||
});
|
||||
|
||||
it('template', async () => {
|
||||
process.env.HOTLINK_TEMPLATE = 'https://i3.wp.com/${host}${pathname}';
|
||||
server = require('../../lib/index');
|
||||
|
|
@ -23,51 +30,22 @@ describe('anti-hotlink', () => {
|
|||
const response = await request.get('/test/complicated');
|
||||
const parsed = await parser.parseString(response.text);
|
||||
expect(parsed.items[0].content).toBe(
|
||||
`<a href="https://mock.com/DIYgod/RSSHub"/>
|
||||
`<a href="https://mock.com/DIYgod/RSSHub"></a>
|
||||
<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">
|
||||
|
||||
<a href="http://mock.com/DIYgod/RSSHub"/>
|
||||
<a href="http://mock.com/DIYgod/RSSHub"></a>
|
||||
<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" data-src="/DIYgod/RSSHub0.jpg" referrerpolicy="no-referrer">
|
||||
<img data-src="/DIYgod/RSSHub.jpg" src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">
|
||||
<img data-mock="/DIYgod/RSSHub.png" src="https://i3.wp.com/mock.com/DIYgod/RSSHub.png" referrerpolicy="no-referrer">
|
||||
<img mock="/DIYgod/RSSHub.gif" src="https://i3.wp.com/mock.com/DIYgod/RSSHub.gif" referrerpolicy="no-referrer">
|
||||
<img src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub" referrerpolicy="no-referrer">
|
||||
<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer"/></img></img></img></img></img></img>`
|
||||
<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">`
|
||||
);
|
||||
expect(parsed.items[1].content).toBe(`<a href="https://mock.com/DIYgod/RSSHub"/>
|
||||
<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer"/>`);
|
||||
expect(parsed.items[1].content).toBe(`<a href="https://mock.com/DIYgod/RSSHub"></a>
|
||||
<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">`);
|
||||
});
|
||||
it('url', async () => {
|
||||
process.env.HOTLINK_TEMPLATE = '${protocol}//${host}${pathname}';
|
||||
server = require('../../lib/index');
|
||||
const request = supertest(server);
|
||||
|
||||
const response = await request.get('/test/complicated');
|
||||
const parsed = await parser.parseString(response.text);
|
||||
expect(parsed.items[0].content).toBe(
|
||||
`<a href="https://mock.com/DIYgod/RSSHub"/>
|
||||
<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">
|
||||
|
||||
<a href="http://mock.com/DIYgod/RSSHub"/>
|
||||
<img src="https://mock.com/DIYgod/RSSHub.jpg" data-src="/DIYgod/RSSHub0.jpg" referrerpolicy="no-referrer">
|
||||
<img data-src="/DIYgod/RSSHub.jpg" src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">
|
||||
<img data-mock="/DIYgod/RSSHub.png" src="https://mock.com/DIYgod/RSSHub.png" referrerpolicy="no-referrer">
|
||||
<img mock="/DIYgod/RSSHub.gif" src="https://mock.com/DIYgod/RSSHub.gif" referrerpolicy="no-referrer">
|
||||
<img src="http://mock.com/DIYgod/DIYgod/RSSHub" referrerpolicy="no-referrer">
|
||||
<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer"/></img></img></img></img></img></img>`
|
||||
);
|
||||
expect(parsed.items[1].content).toBe(`<a href="https://mock.com/DIYgod/RSSHub"/>
|
||||
<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer"/>`);
|
||||
});
|
||||
it('no-template', async () => {
|
||||
process.env.HOTLINK_TEMPLATE = '';
|
||||
server = require('../../lib/index');
|
||||
const request = supertest(server);
|
||||
|
||||
const response = await request.get('/test/complicated');
|
||||
const parsed = await parser.parseString(response.text);
|
||||
expect(parsed.items[0].content).toBe(
|
||||
`<a href="https://mock.com/DIYgod/RSSHub"></a>
|
||||
const origin1 = `<a href="https://mock.com/DIYgod/RSSHub"></a>
|
||||
<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">
|
||||
|
||||
<a href="http://mock.com/DIYgod/RSSHub"></a>
|
||||
|
|
@ -76,9 +54,28 @@ describe('anti-hotlink', () => {
|
|||
<img data-mock="/DIYgod/RSSHub.png" src="https://mock.com/DIYgod/RSSHub.png" referrerpolicy="no-referrer">
|
||||
<img mock="/DIYgod/RSSHub.gif" src="https://mock.com/DIYgod/RSSHub.gif" referrerpolicy="no-referrer">
|
||||
<img src="http://mock.com/DIYgod/DIYgod/RSSHub" referrerpolicy="no-referrer">
|
||||
<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">`
|
||||
);
|
||||
expect(parsed.items[1].content).toBe(`<a href="https://mock.com/DIYgod/RSSHub"></a>
|
||||
<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">`);
|
||||
<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">`;
|
||||
|
||||
const origin2 = `<a href="https://mock.com/DIYgod/RSSHub"></a>
|
||||
<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">`;
|
||||
|
||||
const testOrigin = async () => {
|
||||
server = require('../../lib/index');
|
||||
const request = supertest(server);
|
||||
|
||||
const response = await request.get('/test/complicated');
|
||||
const parsed = await parser.parseString(response.text);
|
||||
expect(parsed.items[0].content).toBe(origin1);
|
||||
expect(parsed.items[1].content).toBe(origin2);
|
||||
};
|
||||
|
||||
it('url', async () => {
|
||||
process.env.HOTLINK_TEMPLATE = '${protocol}//${host}${pathname}';
|
||||
await testOrigin();
|
||||
});
|
||||
|
||||
it('no-template', async () => {
|
||||
process.env.HOTLINK_TEMPLATE = '';
|
||||
await testOrigin();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue