[wp-trac] [WordPress Trac] #60585: Recursion in WP_REST_Posts_Controller schema
WordPress Trac
noreply at wordpress.org
Tue Feb 20 17:45:04 UTC 2024
#60585: Recursion in WP_REST_Posts_Controller schema
--------------------------+-----------------------------
Reporter: derrickkoo | Owner: (none)
Type: defect (bug) | Status: new
Priority: normal | Milestone: Awaiting Review
Component: REST API | Version: 6.4.3
Severity: normal | Keywords: needs-testing
Focuses: performance |
--------------------------+-----------------------------
In the schema definition for the `WP_REST_Posts_Controller` class, any
attribute which invokes a array-like callable with `$this` for its
`validate_callback` or `sanitize_callback` option will result in a
recursive instance of the `WP_REST_Posts_Controller` class to be attached
to that schema definition. Here's an example of such a callable that
causes this issue (code pasted below; see the value of
`sanitize_callback`): https://github.com/WordPress/WordPress/blame/master
/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php#L2288
{{{#!php
'slug' => array(
'description' => __( 'An alphanumeric identifier for the post
unique to its type.' ),
'type' => 'string',
'context' => array( 'view', 'edit', 'embed' ),
'arg_options' => array(
'sanitize_callback' => array( $this, 'sanitize_slug' ),
),
),
}}}
For most sites this doesn't seem to cause any issues, but on sites that
register a lot of custom meta on the `post` CPT, because each registered
meta key adds its own schema attribute, this can result in a huge
`WP_REST_Posts_Controller` object which can potentially cause an
unexpected response to `POST` requests to the `posts` endpoint. Curiously,
this doesn't seem to cause an OOM error in my testing, but instead returns
a `403` response with a generic `The link you followed has expired` error,
which sounds more like an expired nonce error than a memory error.
This can be replicated and seen in a couple of ways:
1. Using `wp shell` to instantiate the `WP_REST_Posts_Controller` class
for the `posts` endpoint and fetching its schema:
{{{#!php
wp> $controller = new WP_REST_Posts_Controller( 'post' );
wp> $controller->get_item_schema();
}}}
The output of `get_item_schema()` will return a schema object showing the
recursive instances of `WP_REST_Posts_Controller` where those callables
are defined.
2. By making a `POST` request to the `posts` endpoint, hooking into the
`rest_insert_post` action hook (see:
https://developer.wordpress.org/reference/hooks/rest_insert_this-
post_type/) and logging the `$request` argument. The
`['attributes']['args']` property will contain the full schema and show
the recursion for any schema attribute invoking a callable using `$this`.
Potential (untested) solution: instead of invoking callables using
`$this`, convert the callable methods to static methods on the
`WP_REST_Posts_Controller` class or its parent, and invoke using `[
__CLASS__, 'method_name' ]` to avoid recursion.
Tested with v6.4.3 and v5.9.9 so far.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/60585>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list