From 5df8bf60aa2184085346f9c1306648a4787abeff Mon Sep 17 00:00:00 2001 From: TimothyBlynJacobs Date: Tue, 27 Oct 2020 16:44:06 +0000 Subject: [PATCH] REST API: Support a broader range of JSON media types. Previously, we only supported `application/json` which prevented using subtypes like `application/activity+json`. This allows for the REST API to `json_decode` the body of requests using a JSON subtype `Content-Type`. Additionally, `wp_die()` now properly sends the error as JSON when a JSON subtype is specified in the `Accept` header. Props pfefferle. Fixes #49404. Built from https://develop.svn.wordpress.org/trunk@49329 git-svn-id: http://core.svn.wordpress.org/trunk@49090 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/load.php | 22 +++++++++++++++++-- .../rest-api/class-wp-rest-request.php | 20 ++++++++++++----- wp-includes/version.php | 2 +- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/wp-includes/load.php b/wp-includes/load.php index 7f4a878241..8d9161adc2 100644 --- a/wp-includes/load.php +++ b/wp-includes/load.php @@ -1595,11 +1595,11 @@ function wp_finalize_scraping_edited_file_errors( $scrape_key ) { */ function wp_is_json_request() { - if ( isset( $_SERVER['HTTP_ACCEPT'] ) && false !== strpos( $_SERVER['HTTP_ACCEPT'], 'application/json' ) ) { + if ( isset( $_SERVER['HTTP_ACCEPT'] ) && wp_is_json_media_type( $_SERVER['HTTP_ACCEPT'] ) ) { return true; } - if ( isset( $_SERVER['CONTENT_TYPE'] ) && 'application/json' === $_SERVER['CONTENT_TYPE'] ) { + if ( isset( $_SERVER['CONTENT_TYPE'] ) && wp_is_json_media_type( $_SERVER['CONTENT_TYPE'] ) ) { return true; } @@ -1635,6 +1635,24 @@ function wp_is_jsonp_request() { } +/** + * Checks whether a string is a valid JSON Media Type. + * + * @since 5.6.0 + * + * @param string $media_type A Media Type string to check. + * @return bool True if string is a valid JSON Media Type. + */ +function wp_is_json_media_type( $media_type ) { + static $cache = array(); + + if ( ! isset( $cache[ $media_type ] ) ) { + $cache[ $media_type ] = (bool) preg_match( '/(^|\s|,)application\/([\w!#\$&-\^\.\+]+\+)?json(\+oembed)?($|\s|;|,)/i', $media_type ); + } + + return $cache[ $media_type ]; +} + /** * Checks whether current request is an XML request, or is expecting an XML response. * diff --git a/wp-includes/rest-api/class-wp-rest-request.php b/wp-includes/rest-api/class-wp-rest-request.php index 937b5684cd..d65a32eae4 100644 --- a/wp-includes/rest-api/class-wp-rest-request.php +++ b/wp-includes/rest-api/class-wp-rest-request.php @@ -323,6 +323,19 @@ class WP_REST_Request implements ArrayAccess { return $data; } + /** + * Checks if the request has specified a JSON content-type. + * + * @since 5.6.0 + * + * @return bool True if the content-type header is JSON. + */ + public function is_json_content_type() { + $content_type = $this->get_content_type(); + + return isset( $content_type['value'] ) && wp_is_json_media_type( $content_type['value'] ); + } + /** * Retrieves the parameter priority order. * @@ -335,8 +348,7 @@ class WP_REST_Request implements ArrayAccess { protected function get_parameter_order() { $order = array(); - $content_type = $this->get_content_type(); - if ( isset( $content_type['value'] ) && 'application/json' === $content_type['value'] ) { + if ( $this->is_json_content_type() ) { $order[] = 'JSON'; } @@ -658,9 +670,7 @@ class WP_REST_Request implements ArrayAccess { $this->parsed_json = true; // Check that we actually got JSON. - $content_type = $this->get_content_type(); - - if ( empty( $content_type ) || 'application/json' !== $content_type['value'] ) { + if ( ! $this->is_json_content_type() ) { return true; } diff --git a/wp-includes/version.php b/wp-includes/version.php index 53464904b5..66f3a630c8 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.6-beta1-49328'; +$wp_version = '5.6-beta1-49329'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.