Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 41 additions & 34 deletions packages/utils/src/internals/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,47 +385,54 @@ export async function* parseSitemap<T extends ParseSitemapOptions>(
// the loop (per-entry warnings could flood the log; individual drops are logged at debug level).
let droppedUrlEntries = 0;

for await (const item of items) {
if (item.type === 'sitemapUrl' && !visitedSitemapUrls.has(item.url)) {
if (nestedSitemapFilter && !nestedSitemapFilter(item.url)) {
logger?.debug(`Skipping sitemap ${item.url} due to nestedSitemapFilter.`);
continue;
}

// Keep only nested sitemaps matching the strategy (and using http(s)) relative to the
// parent. Raw string sources have no parent URL, so the check is skipped.
if (source.type === 'url') {
const { allowed, reason } = filterUrl(item.url, sitemapUrl!, enqueueStrategy);
if (!allowed) {
logger?.warning(`Skipping nested sitemap ${item.url} (parent ${source.url}): ${reason}.`);
try {
for await (const item of items) {
if (item.type === 'sitemapUrl' && !visitedSitemapUrls.has(item.url)) {
if (nestedSitemapFilter && !nestedSitemapFilter(item.url)) {
logger?.debug(`Skipping sitemap ${item.url} due to nestedSitemapFilter.`);
continue;
}
}

sources.push({ type: 'url', url: item.url, depth: (source.depth ?? 0) + 1 });
if (emitNestedSitemaps) {
yield { loc: item.url, originSitemapUrl: null } as any;
}
}
// Keep only nested sitemaps matching the strategy (and using http(s)) relative to the
// parent. Raw string sources have no parent URL, so the check is skipped.
if (source.type === 'url') {
const { allowed, reason } = filterUrl(item.url, sitemapUrl!, enqueueStrategy);
if (!allowed) {
logger?.warning(`Skipping nested sitemap ${item.url} (parent ${source.url}): ${reason}.`);
continue;
}
}

if (item.type === 'url') {
// Keep only URL entries that match the enqueue strategy relative to the parent (see above).
if (source.type === 'url') {
const { allowed, reason } = filterUrl(item.loc, sitemapUrl!, enqueueStrategy);
if (!allowed) {
droppedUrlEntries++;
logger?.debug(`Skipping sitemap URL ${item.loc} (parent ${source.url}): ${reason}.`);
continue;
sources.push({ type: 'url', url: item.url, depth: (source.depth ?? 0) + 1 });
if (emitNestedSitemaps) {
yield { loc: item.url, originSitemapUrl: null } as any;
}
}

yield {
...item,
originSitemapUrl:
source.type === 'url'
? source.url
: `raw://${createHash('sha256').update(source.content).digest('base64')}`,
};
if (item.type === 'url') {
// Keep only URL entries that match the enqueue strategy relative to the parent (see above).
if (source.type === 'url') {
const { allowed, reason } = filterUrl(item.loc, sitemapUrl!, enqueueStrategy);
if (!allowed) {
droppedUrlEntries++;
logger?.debug(`Skipping sitemap URL ${item.loc} (parent ${source.url}): ${reason}.`);
continue;
}
}

yield {
...item,
originSitemapUrl:
source.type === 'url'
? source.url
: `raw://${createHash('sha256').update(source.content).digest('base64')}`,
};
}
}
} catch (e) {
// Skip a malformed sitemap without losing the other ones; raw sources already report the error above.
if (source.type === 'url') {
logger?.warning(`Malformed sitemap content: ${source.url} (${e})`);
}
}

Expand Down
31 changes: 31 additions & 0 deletions test/utils/sitemap.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,21 @@ describe('Sitemap', () => {
'</sitemapindex>',
].join('\n'),
)
.get('/sitemap_parent_with_malformed_child.xml')
.reply(
200,
[
'<?xml version="1.0" encoding="UTF-8"?>',
'<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
'<sitemap>',
'<loc>http://not-exists.com/not_actual_xml.xml</loc>',
'</sitemap>',
'<sitemap>',
'<loc>http://not-exists.com/sitemap_child.xml</loc>',
'</sitemap>',
'</sitemapindex>',
].join('\n'),
)
.get('/not_actual_xml.xml')
.reply(
200,
Expand Down Expand Up @@ -393,6 +408,22 @@ describe('Sitemap', () => {
expect(sitemap.urls).toEqual([]);
});

it('keeps urls from other sitemaps when one of them is malformed', async () => {
const sitemap = await Sitemap.load(
['http://not-exists.com/not_actual_xml.xml', 'http://not-exists.com/sitemap_child.xml'],
undefined,
{ httpClient: new FetchHttpClient() },
);
expect(sitemap.urls).toHaveLength(5);
});

it('keeps urls from other nested sitemaps when one of them is malformed', async () => {
const sitemap = await Sitemap.load('http://not-exists.com/sitemap_parent_with_malformed_child.xml', undefined, {
httpClient: new FetchHttpClient(),
});
expect(sitemap.urls).toHaveLength(5);
});

it('handles CDATA in loc tags', async () => {
const sitemap = await Sitemap.load('http://not-exists.com/sitemap_cdata.xml', undefined, {
httpClient: new FetchHttpClient(),
Expand Down
Loading