Make WordPress Core


Ignore:
Timestamp:
03/02/2025 10:05:08 PM (2 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/rest-api/wpRestTemplateRevisionsController.php

    r59630 r59899  
    427427        );
    428428    }
     429    /**
     430     * @ticket 56481
     431     */
     432    public function test_get_items_should_return_no_response_body_for_head_requests() {
     433        wp_set_current_user( self::$admin_id );
     434        $request  = new WP_REST_Request(
     435            'HEAD',
     436            '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions'
     437        );
     438        $response = rest_get_server()->dispatch( $request );
     439        $this->assertSame( 200, $response->get_status(), 'Response status is 200.' );
     440        $this->assertNull( $response->get_data(), 'The server should not generate a body in response to a HEAD request.' );
     441    }
    429442
    430443    /**
     
    432445     * @covers WP_REST_Template_Revisions_Controller::get_items_permissions_check
    433446     * @ticket 56922
     447     * @ticket 56481
    434448     *
    435449     * @param string $rest_base   Base part of the REST API endpoint to test.
    436450     * @param string $template_id Template ID to use in the test.
    437      */
    438     public function test_get_items_endpoint_should_return_unauthorized_https_status_code_for_unauthorized_request( $rest_base, $template_id ) {
     451     * @param string $method HTTP method to use.
     452     */
     453    public function test_get_items_endpoint_should_return_unauthorized_https_status_code_for_unauthorized_request( $rest_base, $template_id, $method ) {
    439454        wp_set_current_user( 0 );
    440         $request  = new WP_REST_Request( 'GET', '/wp/v2/' . $rest_base . '/' . $template_id . '/revisions' );
     455        $request  = new WP_REST_Request( $method, '/wp/v2/' . $rest_base . '/' . $template_id . '/revisions' );
    441456        $response = rest_get_server()->dispatch( $request );
    442457        $this->assertErrorResponse( 'rest_cannot_read', $response, WP_Http::UNAUTHORIZED );
     
    450465    public function data_get_items_endpoint_should_return_unauthorized_https_status_code_for_unauthorized_request() {
    451466        return array(
    452             'templates'      => array( 'templates', self::TEST_THEME . '//' . self::TEMPLATE_NAME ),
    453             'template parts' => array( 'template-parts', self::TEST_THEME . '//' . self::TEMPLATE_PART_NAME ),
     467            'templates, GET request'       => array( 'templates', self::TEST_THEME . '//' . self::TEMPLATE_NAME, 'GET' ),
     468            'templates, HEAD request'      => array( 'templates', self::TEST_THEME . '//' . self::TEMPLATE_NAME, 'HEAD' ),
     469            'template parts, GET request'  => array( 'template-parts', self::TEST_THEME . '//' . self::TEMPLATE_PART_NAME, 'GET' ),
     470            'template parts, HEAD request' => array( 'template-parts', self::TEST_THEME . '//' . self::TEMPLATE_PART_NAME, 'HEAD' ),
    454471        );
    455472    }
     
    459476     * @covers WP_REST_Template_Revisions_Controller::get_items_permissions_check
    460477     * @ticket 56922
     478     * @ticket 56481
    461479     *
    462480     * @param string $rest_base   Base part of the REST API endpoint to test.
    463481     * @param string $template_id Template ID to use in the test.
    464      */
    465     public function test_get_items_endpoint_should_return_forbidden_https_status_code_for_users_with_insufficient_permissions( $rest_base, string $template_id ) {
     482     * @param string $method HTTP method to use.
     483     */
     484    public function test_get_items_endpoint_should_return_forbidden_https_status_code_for_users_with_insufficient_permissions( $rest_base, string $template_id, $method ) {
    466485        wp_set_current_user( self::$contributor_id );
    467         $request  = new WP_REST_Request( 'GET', '/wp/v2/' . $rest_base . '/' . $template_id . '/revisions' );
     486        $request  = new WP_REST_Request( $method, '/wp/v2/' . $rest_base . '/' . $template_id . '/revisions' );
    468487        $response = rest_get_server()->dispatch( $request );
    469488        $this->assertErrorResponse( 'rest_cannot_read', $response, WP_Http::FORBIDDEN );
     
    477496    public function data_get_items_endpoint_should_return_forbidden_https_status_code_for_users_with_insufficient_permissions() {
    478497        return array(
    479             'templates'      => array( 'templates', self::TEST_THEME . '//' . self::TEMPLATE_NAME ),
    480             'template parts' => array( 'template-parts', self::TEST_THEME . '//' . self::TEMPLATE_PART_NAME ),
     498            'templates, GET request'       => array( 'templates', self::TEST_THEME . '//' . self::TEMPLATE_NAME, 'GET' ),
     499            'templates, HEAD request'      => array( 'templates', self::TEST_THEME . '//' . self::TEMPLATE_NAME, 'HEAD' ),
     500            'template parts, GET request'  => array( 'template-parts', self::TEST_THEME . '//' . self::TEMPLATE_PART_NAME, 'GET' ),
     501            'template parts, HEAD request' => array( 'template-parts', self::TEST_THEME . '//' . self::TEMPLATE_PART_NAME, 'HEAD' ),
    481502        );
    482503    }
     
    598619
    599620    /**
     621     * @ticket 56481
     622     */
     623    public function test_get_item_should_return_no_response_body_for_head_requests() {
     624        wp_set_current_user( self::$admin_id );
     625        $revisions   = wp_get_post_revisions( self::$template_post, array( 'fields' => 'ids' ) );
     626        $revision_id = array_shift( $revisions );
     627        $request     = new WP_REST_Request( 'HEAD', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions/' . $revision_id );
     628        $response    = rest_get_server()->dispatch( $request );
     629        $this->assertSame( 200, $response->get_status(), 'Response status is 200.' );
     630        $this->assertNull( $response->get_data(), 'The server should not generate a body in response to a HEAD request.' );
     631    }
     632
     633    /**
    600634     * Data provider for test_get_item_with_data_provider.
    601635     *
     
    613647     * @covers WP_REST_Template_Revisions_Controller::get_item
    614648     * @ticket 56922
     649     * @ticket 56481
    615650     *
    616651     * @param string  $parent_post_property_name  A class property name that contains the parent post object.
    617652     * @param string  $rest_base                  Base part of the REST API endpoint to test.
    618      */
    619     public function test_get_item_not_found( $parent_post_property_name, $rest_base ) {
     653     * @param string  $method                     HTTP method to use.
     654     */
     655    public function test_get_item_not_found( $parent_post_property_name, $rest_base, $method ) {
    620656        wp_set_current_user( self::$admin_id );
    621657
     
    625661        $revision_id = array_shift( $revisions );
    626662
    627         $request  = new WP_REST_Request( 'GET', '/wp/v2/' . $rest_base . '/invalid//parent/revisions/' . $revision_id );
     663        $request  = new WP_REST_Request( $method, '/wp/v2/' . $rest_base . '/invalid//parent/revisions/' . $revision_id );
    628664        $response = rest_get_server()->dispatch( $request );
    629665        $this->assertErrorResponse( 'rest_post_invalid_parent', $response, WP_Http::NOT_FOUND );
     
    637673    public function data_get_item_not_found() {
    638674        return array(
    639             'templates'      => array( 'template_post', 'templates' ),
    640             'template parts' => array( 'template_part_post', 'template-parts' ),
     675            'templates, GET request'       => array( 'template_post', 'templates', 'GET' ),
     676            'templates, HEAD request'      => array( 'template_post', 'templates', 'HEAD' ),
     677            'template parts, GET request'  => array( 'template_part_post', 'template-parts', 'GET' ),
     678            'template parts, HEAD request' => array( 'template_part_post', 'template-parts', 'HEAD' ),
    641679        );
    642680    }
     
    646684     * @covers WP_REST_Template_Revisions_Controller::get_item
    647685     * @ticket 59875
     686     * @ticket 56481
    648687     *
    649688     * @param string $parent_post_property_name        A class property name that contains the parent post object.
     
    651690     * @param string $rest_base                        Base part of the REST API endpoint to test.
    652691     * @param string $template_id                      Template ID to use in the test.
    653      */
    654     public function test_get_item_invalid_parent_id( $parent_post_property_name, $actual_parent_post_property_name, $rest_base, $template_id ) {
     692     * @param string $method HTTP method to use.
     693     */
     694    public function test_get_item_invalid_parent_id( $parent_post_property_name, $actual_parent_post_property_name, $rest_base, $template_id, $method ) {
    655695        wp_set_current_user( self::$admin_id );
    656696
     
    660700        $revision_id        = array_shift( $revisions );
    661701
    662         $request = new WP_REST_Request( 'GET', '/wp/v2/' . $rest_base . '/' . $template_id . '/revisions/' . $revision_id );
     702        $request = new WP_REST_Request( $method, '/wp/v2/' . $rest_base . '/' . $template_id . '/revisions/' . $revision_id );
    663703
    664704        $response = rest_get_server()->dispatch( $request );
     
    676716    public function data_get_item_invalid_parent_id() {
    677717        return array(
    678             'templates'      => array(
     718            'templates, GET request'       => array(
    679719                'template_post',
    680720                'template_post_2',
    681721                'templates',
    682722                self::TEST_THEME . '//' . self::TEMPLATE_NAME_2,
    683             ),
    684             'template parts' => array(
     723                'GET',
     724            ),
     725            'templates, HEAD request'      => array(
     726                'template_post',
     727                'template_post_2',
     728                'templates',
     729                self::TEST_THEME . '//' . self::TEMPLATE_NAME_2,
     730                'HEAD',
     731            ),
     732            'template parts, GET request'  => array(
    685733                'template_part_post',
    686734                'template_part_post_2',
    687735                'template-parts',
    688736                self::TEST_THEME . '//' . self::TEMPLATE_PART_NAME_2,
     737                'GET',
     738            ),
     739            'template parts, HEAD request' => array(
     740                'template_part_post',
     741                'template_part_post_2',
     742                'template-parts',
     743                self::TEST_THEME . '//' . self::TEMPLATE_PART_NAME_2,
     744                'HEAD',
    689745            ),
    690746        );
Note: See TracChangeset for help on using the changeset viewer.