Skip to content

Commit da6165f

Browse files
authored
fix: 404 empty paginated sitemap pages (#3797)
1 parent dc83917 commit da6165f

2 files changed

Lines changed: 33 additions & 1 deletion

File tree

__tests__/sitemaps.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ describe('GET /sitemaps/posts-:page.xml', () => {
258258
'<loc>http://localhost:5002/posts/p6-p6</loc>',
259259
);
260260
});
261+
262+
it('should return 404 for paginated pages with no rows', async () => {
263+
await request(app.server).get('/sitemaps/posts-3.xml').expect(404);
264+
});
261265
});
262266

263267
describe('GET /sitemaps/posts.xml (type filtering)', () => {
@@ -1211,6 +1215,10 @@ describe('GET /sitemaps/evergreen.xml', () => {
12111215
expect(res.text).toContain('/posts/evergreen-no-author-evergreen-norep');
12121216
expect(res.text).not.toContain('/posts/evergreen-low-rep-evergreen-lowrep');
12131217
});
1218+
1219+
it('should return 404 for paginated pages with no rows', async () => {
1220+
await request(app.server).get('/sitemaps/evergreen-2.xml').expect(404);
1221+
});
12141222
});
12151223

12161224
describe('GET /sitemaps/archive-index.xml', () => {

src/routes/sitemaps.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ const buildSitemapXmlStream = async <T extends ObjectLiteral>(
230230
};
231231

232232
const getSitemapPageCount = (totalPosts: number): number =>
233-
Math.max(1, Math.ceil(totalPosts / getPaginatedSitemapLimit()));
233+
Math.ceil(totalPosts / getPaginatedSitemapLimit());
234234

235235
const getReplicaQueryCount = async (
236236
con: DataSource,
@@ -245,6 +245,20 @@ const getReplicaQueryCount = async (
245245
}
246246
};
247247

248+
const hasPaginatedSitemapPage = async (
249+
con: DataSource,
250+
buildQuery: (source: EntityManager, page: number) => SelectQueryBuilder<Post>,
251+
page: number,
252+
): Promise<boolean> => {
253+
const queryRunner = con.createQueryRunner('slave');
254+
255+
try {
256+
return !!(await buildQuery(queryRunner.manager, page).limit(1).getRawOne());
257+
} finally {
258+
await queryRunner.release();
259+
}
260+
};
261+
248262
const buildSitemapIndexEntries = (
249263
prefix: string,
250264
sitemapCount: number,
@@ -823,6 +837,10 @@ export default async function (fastify: FastifyInstance): Promise<void> {
823837

824838
const con = await createOrGetConnection();
825839

840+
if (!(await hasPaginatedSitemapPage(con, buildPostsSitemapQuery, page))) {
841+
return res.code(404).send();
842+
}
843+
826844
return res
827845
.type('application/xml')
828846
.header('cache-control', SITEMAP_CACHE_CONTROL)
@@ -849,6 +867,12 @@ export default async function (fastify: FastifyInstance): Promise<void> {
849867

850868
const con = await createOrGetConnection();
851869

870+
if (
871+
!(await hasPaginatedSitemapPage(con, buildEvergreenSitemapQuery, page))
872+
) {
873+
return res.code(404).send();
874+
}
875+
852876
return res
853877
.type('application/xml')
854878
.header('cache-control', SITEMAP_CACHE_CONTROL)

0 commit comments

Comments
 (0)