From 27c566f1ac6d587b9d2d72a279e71a14c4763454 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Mon, 25 Nov 2024 10:08:05 +0000 Subject: [PATCH] REST API: Remove trailing slashes when preloading requests and there is a query string. Follow-up to [51648], see #51636. Props antonvlasenko, swissspidy, spacedmonkey. Fixes #57048. git-svn-id: https://develop.svn.wordpress.org/trunk@59457 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/rest-api.php | 9 +++++++ tests/phpunit/tests/rest-api.php | 46 +++++++++++++++++++++----------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index 401a3b9f17..c990f11ada 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -2935,6 +2935,7 @@ function rest_preload_api_request( $memo, $path ) { } } + // Remove trailing slashes at the end of the REST API path (query part). $path = untrailingslashit( $path ); if ( empty( $path ) ) { $path = '/'; @@ -2945,6 +2946,14 @@ function rest_preload_api_request( $memo, $path ) { return $memo; } + if ( isset( $path_parts['path'] ) && '/' !== $path_parts['path'] ) { + // Remove trailing slashes from the "path" part of the REST API path. + $path_parts['path'] = untrailingslashit( $path_parts['path'] ); + $path = str_contains( $path, '?' ) ? + $path_parts['path'] . '?' . ( $path_parts['query'] ?? '' ) : + $path_parts['path']; + } + $request = new WP_REST_Request( $method, $path_parts['path'] ); if ( ! empty( $path_parts['query'] ) ) { parse_str( $path_parts['query'], $query_params ); diff --git a/tests/phpunit/tests/rest-api.php b/tests/phpunit/tests/rest-api.php index 7b0ee18f68..472e6a9b9d 100644 --- a/tests/phpunit/tests/rest-api.php +++ b/tests/phpunit/tests/rest-api.php @@ -960,30 +960,46 @@ class Tests_REST_API extends WP_UnitTestCase { } /** + * @dataProvider data_rest_preload_api_request_removes_trailing_slashes + * * @ticket 51636 + * @ticket 57048 + * + * @param string $preload_path The path to preload. + * @param array|string $expected_preload_path Expected path after preloading. */ - public function test_rest_preload_api_request_removes_trailing_slashes() { + public function test_rest_preload_api_request_removes_trailing_slashes( $preload_path, $expected_preload_path ) { $rest_server = $GLOBALS['wp_rest_server']; $GLOBALS['wp_rest_server'] = null; - $preload_paths = array( - '/wp/v2/types//', - array( '/wp/v2/media///', 'OPTIONS' ), - '////', - ); - - $preload_data = array_reduce( - $preload_paths, - 'rest_preload_api_request', - array() - ); - - $this->assertSame( array_keys( $preload_data ), array( '/wp/v2/types', 'OPTIONS', '/' ) ); - $this->assertArrayHasKey( '/wp/v2/media', $preload_data['OPTIONS'] ); + $actual_preload_path = rest_preload_api_request( array(), $preload_path ); + if ( '' !== $preload_path ) { + $actual_preload_path = key( $actual_preload_path ); + } + $this->assertSame( $expected_preload_path, $actual_preload_path ); $GLOBALS['wp_rest_server'] = $rest_server; } + /** + * Data provider. + * + * @return array + */ + public static function data_rest_preload_api_request_removes_trailing_slashes() { + return array( + 'no query part' => array( '/wp/v2/types//', '/wp/v2/types' ), + 'no query part, more slashes' => array( '/wp/v2/media///', '/wp/v2/media' ), + 'only slashes' => array( '////', '/' ), + 'empty path' => array( '', array() ), + 'no query parameters' => array( '/wp/v2/types//?////', '/wp/v2/types?' ), + 'no query parameters, with slashes' => array( '/wp/v2/types//?fields////', '/wp/v2/types?fields' ), + 'query parameters with no values' => array( '/wp/v2/types//?fields=////', '/wp/v2/types?fields=' ), + 'single query parameter' => array( '/wp/v2/types//?_fields=foo,bar////', '/wp/v2/types?_fields=foo,bar' ), + 'multiple query parameters' => array( '/wp/v2/types////?_fields=foo,bar&limit=1000////', '/wp/v2/types?_fields=foo,bar&limit=1000' ), + ); + } + /** * @ticket 40614 */