| @@ -482,18 +482,15 @@ | ||
| 482 | 482 | $removal = $this->sitemap_generator->delete_published_sitemaps(); |
| 483 | 483 | $stuck = is_array($removal['failed'] ?? null) ? $removal['failed'] : []; |
| 484 | 484 | |
| 485 | 485 | // A stale file shadows the dynamic route, so this is a real |
| 486 | - // failure rather than a tidy-up that did not matter. | |
| 486 | + // failure rather than a tidy-up that did not matter. Worded by | |
| 487 | + // the generator so this and its own rebuild paths cannot | |
| 488 | + // describe the same stuck files differently (#764). | |
| 487 | 489 | if (!empty($stuck)) { |
| 488 | 490 | return new WP_Error( |
| 489 | 491 | 'sitemap_stale_files', |
| 490 | - sprintf( | |
| 491 | - /* translators: 1: comma-separated file names, 2: absolute path to the WordPress root. */ | |
| 492 | - __('The sitemap is served by WordPress, but these files are still in the site root and your web server will keep serving them instead: %1$s. They could not be removed because %2$s is not writable.', 'thinkrank'), | |
| 493 | - implode(', ', $stuck), | |
| 494 | - untrailingslashit(ABSPATH) | |
| 495 | - ), | |
| 492 | + $this->sitemap_generator->stuck_files_message($stuck), | |
| 496 | 493 | ['status' => 500] |
| 497 | 494 | ); |
| 498 | 495 | } |
| 499 | 496 | |
| @@ -612,10 +609,11 @@ | ||
| 612 | 609 | public function validate_sitemap(WP_REST_Request $request) { |
| 613 | 610 | try { |
| 614 | 611 | $sitemap_url = $request->get_param('sitemap_url') ?? home_url('/sitemap.xml'); |
| 615 | 612 | |
| 616 | - // Validate sitemap URL | |
| 617 | - if (!filter_var($sitemap_url, FILTER_VALIDATE_URL)) { | |
| 613 | + // Validate sitemap URL. Url_Validator accepts an internationalised | |
| 614 | + // domain or a non-ASCII path (home_url() on an IDN site is one). | |
| 615 | + if (!\ThinkRank\Core\Url_Validator::is_valid($sitemap_url)) { | |
| 618 | 616 | return new WP_Error( |
| 619 | 617 | 'invalid_url', |
| 620 | 618 | 'Invalid sitemap URL provided', |
| 621 | 619 | ['status' => 400] |
| @@ -620,8 +618,14 @@ | ||
| 620 | 618 | 'Invalid sitemap URL provided', |
| 621 | 619 | ['status' => 400] |
| 622 | 620 | ); |
| 623 | 621 | } |
| 622 | + | |
| 623 | + // Everything from here on works on the ASCII form (punycode host, | |
| 624 | + // percent-encoded path). wp_http_validate_url() resolves the host | |
| 625 | + // with gethostbyname(), which cannot resolve a Unicode name, and | |
| 626 | + // the SSRF check must see exactly the URL that is fetched. | |
| 627 | + $sitemap_url = \ThinkRank\Core\Url_Validator::to_ascii((string) $sitemap_url); | |
| 624 | 628 | |
| 625 | 629 | // Block SSRF: this endpoint fetches the URL server-side, so reject |
| 626 | 630 | // loopback/link-local/private hosts and non-http(s) schemes via |
| 627 | 631 | // WordPress's own validator (same guard used in class-schema-endpoint). |