Make WordPress Core


Ignore:
Timestamp:
03/02/2025 10:05:08 PM (3 months ago)
Author:
TimothyBlynJacobs
Message:

REST API: Improve performance for HEAD requests.

By default, the REST API responds to HEAD rqeuests by calling the GET handler and omitting the body from the response. While convenient, this ends up performing needless work that slows down the API response time.

This commit adjusts the Core controllers to specifically handle HEAD requests by not preparing the response body.

Fixes #56481.
Props antonvlasenko, janusdev, ironprogrammer, swissspidy, spacedmonkey, mukesh27, mamaduka, timothyblynjacobs.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php

    r57686 r59899  
    7979
    8080    /**
     81     * @dataProvider data_readable_http_methods
    8182     * @covers WP_REST_Font_Collections_Controller::get_items
    82      */
    83     public function test_get_items_should_only_return_valid_collections() {
     83     * @ticket 56481
     84     *
     85     * @param string $method The HTTP method to use.
     86     */
     87    public function test_get_items_should_only_return_valid_collections( $method ) {
    8488        $this->setExpectedIncorrectUsage( 'WP_Font_Collection::load_from_json' );
    8589
     
    9397        );
    9498
    95         $request  = new WP_REST_Request( 'GET', '/wp/v2/font-collections' );
     99        $request  = new WP_REST_Request( $method, '/wp/v2/font-collections' );
    96100        $response = rest_get_server()->dispatch( $request );
    97101        $content  = $response->get_data();
     
    100104
    101105        $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
    102         $this->assertCount( 1, $content, 'The response should only contain valid collections.' );
     106        if ( 'HEAD' !== $method ) {
     107            $this->assertCount( 1, $content, 'The response should only contain valid collections.' );
     108            return null;
     109        }
     110
     111        $this->assertNull( $content, 'The response should be empty.' );
     112        $headers = $response->get_headers();
     113        $this->assertArrayHasKey( 'X-WP-Total', $headers, 'The "X-WP-Total" header should be present in the response.' );
     114        // Includes non-valid collections.
     115        $this->assertSame( 2, $headers['X-WP-Total'], 'The "X-WP-Total" header value should be equal to 1.' );
    103116    }
    104117
     
    128141
    129142    /**
     143     * @dataProvider data_readable_http_methods
     144     * @ticket 56481
     145     *
     146     * @param string $method The HTTP method to use.
     147     */
     148    public function test_get_item_should_allow_adding_headers_via_filter( $method ) {
     149        $hook_name = 'rest_prepare_font_collection';
     150        $filter    = new MockAction();
     151        $callback  = array( $filter, 'filter' );
     152        add_filter( $hook_name, $callback );
     153        $header_filter = new class() {
     154            public static function add_custom_header( $response ) {
     155                $response->header( 'X-Test-Header', 'Test' );
     156
     157                return $response;
     158            }
     159        };
     160        add_filter( $hook_name, array( $header_filter, 'add_custom_header' ) );
     161        wp_set_current_user( self::$admin_id );
     162        $request  = new WP_REST_Request( $method, '/wp/v2/font-collections/mock-col-slug' );
     163        $response = rest_get_server()->dispatch( $request );
     164        remove_filter( $hook_name, $callback );
     165        remove_filter( $hook_name, array( $header_filter, 'add_custom_header' ) );
     166
     167        $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
     168        $this->assertSame( 1, $filter->get_call_count(), 'The "' . $hook_name . '" filter was not called when it should be for GET/HEAD requests.' );
     169        $headers = $response->get_headers();
     170        $this->assertArrayHasKey( 'X-Test-Header', $headers, 'The "X-Test-Header" header should be present in the response.' );
     171        $this->assertSame( 'Test', $headers['X-Test-Header'], 'The "X-Test-Header" header value should be equal to "Test".' );
     172        if ( 'HEAD' !== $method ) {
     173            return null;
     174        }
     175        $this->assertNull( $response->get_data(), 'The server should not generate a body in response to a HEAD request.' );
     176    }
     177
     178    /**
     179     * Data provider intended to provide HTTP method names for testing GET and HEAD requests.
     180     *
     181     * @return array
     182     */
     183    public static function data_readable_http_methods() {
     184        return array(
     185            'GET request'  => array( 'GET' ),
     186            'HEAD request' => array( 'HEAD' ),
     187        );
     188    }
     189
     190    /**
     191     * @dataProvider data_readable_http_methods
    130192     * @covers WP_REST_Font_Collections_Controller::get_item
    131      */
    132     public function test_get_item_invalid_slug() {
    133         wp_set_current_user( self::$admin_id );
    134         $request  = new WP_REST_Request( 'GET', '/wp/v2/font-collections/non-existing-collection' );
     193     * @ticket 56481
     194     *
     195     * @param string $method The HTTP method to use.
     196     */
     197    public function test_get_item_invalid_slug( $method ) {
     198        wp_set_current_user( self::$admin_id );
     199        $request  = new WP_REST_Request( $method, '/wp/v2/font-collections/non-existing-collection' );
    135200        $response = rest_get_server()->dispatch( $request );
    136201        $this->assertErrorResponse( 'rest_font_collection_not_found', $response, 404 );
     
    138203
    139204    /**
     205     * @dataProvider data_readable_http_methods
    140206     * @covers WP_REST_Font_Collections_Controller::get_item
    141      */
    142     public function test_get_item_invalid_collection() {
     207     * @ticket 56481
     208     *
     209     * @param string $method The HTTP method to use.
     210     */
     211    public function test_get_item_invalid_collection( $method ) {
    143212        $this->setExpectedIncorrectUsage( 'WP_Font_Collection::load_from_json' );
    144213
     
    153222        );
    154223
    155         $request  = new WP_REST_Request( 'GET', '/wp/v2/font-collections/' . $slug );
     224        $request  = new WP_REST_Request( $method, '/wp/v2/font-collections/' . $slug );
    156225        $response = rest_get_server()->dispatch( $request );
    157226
     
    162231
    163232    /**
     233     * @dataProvider data_readable_http_methods
    164234     * @covers WP_REST_Font_Collections_Controller::get_item
    165      */
    166     public function test_get_item_invalid_id_permission() {
    167         $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/mock-col-slug' );
     235     * @ticket 56481
     236     *
     237     * @param string $method The HTTP method to use.
     238     */
     239    public function test_get_item_invalid_id_permission( $method ) {
     240        $request = new WP_REST_Request( $method, '/wp/v2/font-collections/mock-col-slug' );
    168241
    169242        wp_set_current_user( 0 );
Note: See TracChangeset for help on using the changeset viewer.