REST API: Expose current $request object to cors_header filters in WP_REST_SERVER->serve_request().

Allows headers to be more easily set on a per-response basis when more or less security is needed on a specific route.

Props bor0, rachelbaker, spacedmonkey, chaion07, oglekler, SergeyBiryukov.
Fixes #57752.



git-svn-id: https://develop.svn.wordpress.org/trunk@56096 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
K. Adam White 2023-06-28 17:37:52 +00:00
parent 9f9add35cb
commit 68be569925
2 changed files with 69 additions and 36 deletions

View File

@ -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 ) ) {

View File

@ -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!' );