1+ using System . Security ;
12using Microsoft . AspNetCore . Mvc ;
3+ using Microsoft . Extensions . Caching . Memory ;
24using PkgDiff . Application . Interfaces ;
5+ using PkgDiff . Shared . Constants ;
36
47namespace PkgDiff . API . Controllers ;
58
69[ ApiController ]
710[ Route ( "api" ) ]
811public class SitemapController : ControllerBase
912{
13+ private const string BaseUrl = "https://pkgdiff.dev" ;
14+ private const string CacheKey = "sitemap-xml" ;
15+
16+ private static readonly string [ ] StaticPaths =
17+ {
18+ "/" ,
19+ "/packages" ,
20+ "/audit" ,
21+ "/about" ,
22+ "/contributors" ,
23+ "/terms" ,
24+ "/privacy" ,
25+ "/cookies" ,
26+ } ;
27+
1028 private readonly IAdminPackageService _adminService ;
29+ private readonly IMemoryCache _memory ;
1130 private readonly ILogger < SitemapController > _logger ;
1231
13- public SitemapController ( IAdminPackageService adminService , ILogger < SitemapController > logger )
32+ public SitemapController (
33+ IAdminPackageService adminService ,
34+ IMemoryCache memory ,
35+ ILogger < SitemapController > logger )
1436 {
1537 _adminService = adminService ;
38+ _memory = memory ;
1639 _logger = logger ;
1740 }
1841
@@ -22,76 +45,57 @@ public async Task<IActionResult> GetDynamicSitemap()
2245 {
2346 try
2447 {
25- var packages = await _adminService . GetPackagesForSitemapAsync ( ) ;
26-
27- var xml = new System . Text . StringBuilder ( ) ;
28- xml . AppendLine ( "<?xml version=\" 1.0\" encoding=\" UTF-8\" ?>" ) ;
29- xml . AppendLine ( "<urlset xmlns=\" http://www.sitemaps.org/schemas/sitemap/0.9\" >" ) ;
30-
31- xml . AppendLine ( " <url>" ) ;
32- xml . AppendLine ( " <loc>https://pkgdiff.dev/</loc>" ) ;
33- xml . AppendLine ( " <changefreq>daily</changefreq>" ) ;
34- xml . AppendLine ( " <priority>1.0</priority>" ) ;
35- xml . AppendLine ( $ " <lastmod>{ DateTime . UtcNow : yyyy-MM-dd} </lastmod>") ;
36- xml . AppendLine ( " </url>" ) ;
37-
38- xml . AppendLine ( " <url>" ) ;
39- xml . AppendLine ( " <loc>https://pkgdiff.dev/packages</loc>" ) ;
40- xml . AppendLine ( " <changefreq>daily</changefreq>" ) ;
41- xml . AppendLine ( " <priority>0.9</priority>" ) ;
42- xml . AppendLine ( $ " <lastmod>{ DateTime . UtcNow : yyyy-MM-dd} </lastmod>") ;
43- xml . AppendLine ( " </url>" ) ;
48+ if ( ! _memory . TryGetValue ( CacheKey , out string ? sitemap ) || sitemap is null )
49+ {
50+ sitemap = await BuildSitemapAsync ( ) ;
51+ _memory . Set ( CacheKey , sitemap , TimeSpan . FromHours ( 1 ) ) ;
52+ }
4453
45- xml . AppendLine ( " <url>" ) ;
46- xml . AppendLine ( " <loc>https://pkgdiff.dev/audit</loc>" ) ;
47- xml . AppendLine ( " <changefreq>monthly</changefreq>" ) ;
48- xml . AppendLine ( " <priority>0.8</priority>" ) ;
49- xml . AppendLine ( " </url>" ) ;
54+ return Content ( sitemap , "application/xml" ) ;
55+ }
56+ catch ( Exception ex )
57+ {
58+ _logger . LogError ( ex , "Error generating dynamic sitemap" ) ;
59+ return StatusCode ( 500 , new { error = "An error occurred while generating sitemap" } ) ;
60+ }
61+ }
5062
63+ private async Task < string > BuildSitemapAsync ( )
64+ {
65+ var packages = await _adminService . GetPackagesForSitemapAsync ( ) ;
5166
52- xml . AppendLine ( " <url>" ) ;
53- xml . AppendLine ( " <loc>https://pkgdiff.dev/terms</loc>" ) ;
54- xml . AppendLine ( " <changefreq>yearly</changefreq>" ) ;
55- xml . AppendLine ( " <priority>0.3</priority>" ) ;
56- xml . AppendLine ( $ " <lastmod>{ DateTime . UtcNow : yyyy-MM-dd} </lastmod>") ;
57- xml . AppendLine ( " </url>" ) ;
67+ var xml = new System . Text . StringBuilder ( ) ;
68+ xml . AppendLine ( "<?xml version=\" 1.0\" encoding=\" UTF-8\" ?>" ) ;
69+ xml . AppendLine ( "<urlset xmlns=\" http://www.sitemaps.org/schemas/sitemap/0.9\" >" ) ;
5870
59- xml . AppendLine ( " <url>" ) ;
60- xml . AppendLine ( " <loc>https://pkgdiff.dev/privacy</loc>" ) ;
61- xml . AppendLine ( " <changefreq>yearly</changefreq>" ) ;
62- xml . AppendLine ( " <priority>0.3</priority>" ) ;
63- xml . AppendLine ( $ " <lastmod>{ DateTime . UtcNow : yyyy-MM-dd} </lastmod>") ;
64- xml . AppendLine ( " </url>" ) ;
71+ foreach ( var path in StaticPaths )
72+ {
73+ AppendUrl ( xml , path , null ) ;
74+ }
6575
66- xml . AppendLine ( " <url>" ) ;
67- xml . AppendLine ( " <loc>https://pkgdiff.dev/cookies</loc>" ) ;
68- xml . AppendLine ( " <changefreq>yearly</changefreq>" ) ;
69- xml . AppendLine ( " <priority>0.3</priority>" ) ;
70- xml . AppendLine ( $ " <lastmod>{ DateTime . UtcNow : yyyy-MM-dd} </lastmod>") ;
71- xml . AppendLine ( " </url>" ) ;
76+ foreach ( var registry in RegistryNames . All )
77+ {
78+ AppendUrl ( xml , $ "/packages?registry={ registry } ", null ) ;
79+ }
7280
73- foreach ( var package in packages )
74- {
75- var encodedPackageId = Uri . EscapeDataString ( package . PackageId ) ;
76- xml . AppendLine ( " <url>" ) ;
77- xml . AppendLine ( $ " <loc>https://pkgdiff.dev/package/{ package . Registry } /{ encodedPackageId } </loc>") ;
78- xml . AppendLine ( $ " <changefreq>{ package . ChangeFreq } </changefreq>") ;
79- xml . AppendLine ( $ " <priority>{ package . Priority : 0.0} </priority>") ;
80- if ( package . LastModified . HasValue )
81- {
82- xml . AppendLine ( $ " <lastmod>{ package . LastModified . Value : yyyy-MM-dd} </lastmod>") ;
83- }
84- xml . AppendLine ( " </url>" ) ;
85- }
81+ foreach ( var package in packages )
82+ {
83+ AppendUrl ( xml , $ "/package/{ package . Registry } /{ package . PackageId } ", package . LastModified ) ;
84+ }
8685
87- xml . AppendLine ( "</urlset>" ) ;
86+ xml . AppendLine ( "</urlset>" ) ;
87+ return xml . ToString ( ) ;
88+ }
8889
89- return Content ( xml . ToString ( ) , "application/xml" ) ;
90- }
91- catch ( Exception ex )
90+ // Must match the page's canonical URL, so the path is written as is and only escaped for XML
91+ private static void AppendUrl ( System . Text . StringBuilder xml , string path , DateTime ? lastModified )
92+ {
93+ xml . AppendLine ( " <url>" ) ;
94+ xml . AppendLine ( $ " <loc>{ SecurityElement . Escape ( BaseUrl + path ) } </loc>") ;
95+ if ( lastModified . HasValue )
9296 {
93- _logger . LogError ( ex , "Error generating dynamic sitemap" ) ;
94- return StatusCode ( 500 , new { error = "An error occurred while generating sitemap" } ) ;
97+ xml . AppendLine ( $ " <lastmod>{ lastModified . Value : yyyy-MM-dd} </lastmod>") ;
9598 }
99+ xml . AppendLine ( " </url>" ) ;
96100 }
97101}
0 commit comments