diff --git a/lib/middleware/parameter.js b/lib/middleware/parameter.js index 0c98d0a559..d35dc65147 100644 --- a/lib/middleware/parameter.js +++ b/lib/middleware/parameter.js @@ -6,6 +6,18 @@ const config = require('@/config').value; let mercury_parser; +const resolveRelativeLink = ($, elem, attr, baseUrl) => { + const $elem = $(elem); + + if (baseUrl) { + try { + $elem.attr(attr, new URL($elem.attr(attr), baseUrl).href); + } catch (e) { + // no-empty + } + } +}; + module.exports = async (ctx, next) => { await next(); @@ -76,50 +88,46 @@ module.exports = async (ctx, next) => { $('script').remove(); - $('a').each((_, ele) => { - const $ele = $(ele); - - // absolute link - if (baseUrl) { - try { - $ele.attr('href', new URL($ele.attr('href'), baseUrl).href); - } catch (e) { - // no-empty - } - } - }); - $('img').each((_, ele) => { const $ele = $(ele); // fix lazyload if (!$ele.attr('src')) { - for (const key in ele.attribs) { - const value = ele.attribs[key].trim(); - if (['.gif', '.png', '.jpg', '.webp'].some((suffix) => value.includes(suffix))) { - $ele.attr('src', value); - break; + const lazySrc = $ele.attr('data-src') || $ele.attr('data-original'); + if (lazySrc) { + $ele.attr('src', lazySrc); + } else { + for (const key in ele.attribs) { + const value = ele.attribs[key].trim(); + if (['.gif', '.png', '.jpg', '.webp'].some((suffix) => value.includes(suffix))) { + $ele.attr('src', value); + break; + } } } } - // absolute link - if (baseUrl) { - try { - $ele.attr('src', new URL($ele.attr('src'), baseUrl).href); - } catch (e) { - // no-empty - } - } - - // referrerpolicy - $ele.attr('referrerpolicy', 'no-referrer'); - // redundant attributes ['onclick', 'onerror', 'onload'].forEach((e) => { $ele.removeAttr(e); }); }); + + // resolve relative link & fix referrer policy + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy + // https://www.w3schools.com/tags/att_href.asp + $('a, area').each((_, elem) => { + resolveRelativeLink($, elem, 'href', baseUrl); + // $(elem).attr('rel', 'noreferrer'); // currently no such a need + }); + // https://www.w3schools.com/tags/att_src.asp + $('img, video, audio, source, iframe, embed, track').each((_, elem) => { + resolveRelativeLink($, elem, 'src', baseUrl); + }); + $('img, iframe').each((_, elem) => { + $(elem).attr('referrerpolicy', 'no-referrer'); + }); + item.description = $('body').html() + '' + (config.suffix || ''); } return item; diff --git a/lib/v2/test/index.js b/lib/v2/test/index.js index ceb94229a5..5535264a0b 100644 --- a/lib/v2/test/index.js +++ b/lib/v2/test/index.js @@ -98,6 +98,21 @@ module.exports = async (ctx) => { link: `https://mock.com/DIYgod/RSSHub`, author: `DIYgod`, }); + } else if (ctx.params.id === 'multimedia') { + item.push({ + title: `Multimedia Title`, + description: ` + + + +`, + pubDate: new Date(`2019-3-1`).toUTCString(), + link: `https://mock.com/DIYgod/RSSHub`, + author: `DIYgod`, + }); } else if (ctx.params.id === 'sort') { item.push({ title: `Sort Title 0`, @@ -187,6 +202,6 @@ module.exports = async (ctx) => { link: 'https://github.com/DIYgod/RSSHub', item, allowEmpty: ctx.params.id === 'allow_empty', - description: ctx.params.id === 'complicated' ? '' : 'A test route for RSSHub', + description: ctx.params.id === 'complicated' ? '' : ctx.params.id === 'multimedia' ? '' : 'A test route for RSSHub', }; }; diff --git a/test/middleware/parameter.js b/test/middleware/parameter.js index 24234fa1cc..e8afb7df20 100644 --- a/test/middleware/parameter.js +++ b/test/middleware/parameter.js @@ -280,6 +280,22 @@ describe('complicated_description', () => { }); }); +describe('multimedia_description', () => { + it(`multimedia_description`, async () => { + const response = await request.get('/test/multimedia'); + expect(response.status).toBe(200); + const parsed = await parser.parseString(response.text); + expect(parsed.items[0].content).toBe(` + + + +`); + }); +}); + describe('sort', () => { it(`sort`, async () => { const response = await request.get('/test/sort');