diff --git a/src/wp-includes/rest-api/class-wp-rest-server.php b/src/wp-includes/rest-api/class-wp-rest-server.php index a984398fb1..8c7c6d31c9 100644 --- a/src/wp-includes/rest-api/class-wp-rest-server.php +++ b/src/wp-includes/rest-api/class-wp-rest-server.php @@ -321,42 +321,6 @@ class WP_REST_Server { * https://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ */ $this->send_header( 'X-Content-Type-Options', 'nosniff' ); - $expose_headers = array( 'X-WP-Total', 'X-WP-TotalPages', 'Link' ); - - /** - * Filters the list of response headers that are exposed to REST API CORS requests. - * - * @since 5.5.0 - * - * @param string[] $expose_headers The list of response headers to expose. - */ - $expose_headers = apply_filters( 'rest_exposed_cors_headers', $expose_headers ); - - $this->send_header( 'Access-Control-Expose-Headers', implode( ', ', $expose_headers ) ); - - $allow_headers = array( - 'Authorization', - 'X-WP-Nonce', - 'Content-Disposition', - 'Content-MD5', - 'Content-Type', - ); - - /** - * Filters the list of request headers that are allowed for REST API CORS requests. - * - * The allowed headers are passed to the browser to specify which - * headers can be passed to the REST API. By default, we allow the - * Content-* headers needed to upload files to the media endpoints. - * As well as the Authorization and Nonce headers for allowing authentication. - * - * @since 5.5.0 - * - * @param string[] $allow_headers The list of request headers to allow. - */ - $allow_headers = apply_filters( 'rest_allowed_cors_headers', $allow_headers ); - - $this->send_header( 'Access-Control-Allow-Headers', implode( ', ', $allow_headers ) ); /** * Filters whether to send nocache headers on a REST API request. @@ -436,6 +400,45 @@ class WP_REST_Server { $request->set_method( $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ); } + $expose_headers = array( 'X-WP-Total', 'X-WP-TotalPages', 'Link' ); + + /** + * Filters the list of response headers that are exposed to REST API CORS requests. + * + * @since 5.5.0 + * + * @param string[] $expose_headers The list of response headers to expose. + * @param WP_REST_Request The request in context. + */ + $expose_headers = apply_filters( 'rest_exposed_cors_headers', $expose_headers, $request ); + + $this->send_header( 'Access-Control-Expose-Headers', implode( ', ', $expose_headers ) ); + + $allow_headers = array( + 'Authorization', + 'X-WP-Nonce', + 'Content-Disposition', + 'Content-MD5', + 'Content-Type', + ); + + /** + * Filters the list of request headers that are allowed for REST API CORS requests. + * + * The allowed headers are passed to the browser to specify which + * headers can be passed to the REST API. By default, we allow the + * Content-* headers needed to upload files to the media endpoints. + * As well as the Authorization and Nonce headers for allowing authentication. + * + * @since 5.5.0 + * + * @param string[] $allow_headers The list of request headers to allow. + * @param WP_REST_Request The request in context. + */ + $allow_headers = apply_filters( 'rest_allowed_cors_headers', $allow_headers, $request ); + + $this->send_header( 'Access-Control-Allow-Headers', implode( ', ', $allow_headers ) ); + $result = $this->check_authentication(); if ( ! is_wp_error( $result ) ) { diff --git a/tests/phpunit/tests/rest-api/rest-server.php b/tests/phpunit/tests/rest-api/rest-server.php index bb10b20bc6..9a12c2247b 100644 --- a/tests/phpunit/tests/rest-api/rest-server.php +++ b/tests/phpunit/tests/rest-api/rest-server.php @@ -2200,6 +2200,36 @@ class Tests_REST_Server extends WP_Test_REST_TestCase { $this->assertSame( 500, rest_get_server()->status ); } + /** + * @ticket 57752 + */ + public function test_rest_exposed_cors_headers_filter_receives_request_object() { + $mock_hook = new MockAction(); + add_filter( 'rest_exposed_cors_headers', array( $mock_hook, 'filter' ), 10, 2 ); + + rest_get_server()->serve_request( '/test-exposed-cors-headers' ); + + $this->assertCount( 1, $mock_hook->get_events() ); + $this->assertCount( 2, $mock_hook->get_events()[0]['args'] ); + $this->assertInstanceOf( 'WP_REST_Request', $mock_hook->get_events()[0]['args'][1] ); + $this->assertSame( '/test-exposed-cors-headers', $mock_hook->get_events()[0]['args'][1]->get_route() ); + } + + /** + * @ticket 57752 + */ + public function test_rest_allowed_cors_headers_filter_receives_request_object() { + $mock_hook = new MockAction(); + add_filter( 'rest_allowed_cors_headers', array( $mock_hook, 'filter' ), 10, 2 ); + + rest_get_server()->serve_request( '/test-allowed-cors-headers' ); + + $this->assertCount( 1, $mock_hook->get_events() ); + $this->assertCount( 2, $mock_hook->get_events()[0]['args'] ); + $this->assertInstanceOf( 'WP_REST_Request', $mock_hook->get_events()[0]['args'][1] ); + $this->assertSame( '/test-allowed-cors-headers', $mock_hook->get_events()[0]['args'][1]->get_route() ); + } + public function _validate_as_integer_123( $value, $request, $key ) { if ( ! is_int( $value ) ) { return new WP_Error( 'some-error', 'This is not valid!' );