From 260a88d009a78e0de89bdcbedf2154568e2ba4dd Mon Sep 17 00:00:00 2001
From: Rachel Baker <rachelbaker@git.wordpress.org>
Date: Sun, 11 Dec 2016 21:25:40 +0000
Subject: [PATCH] REST API: Allow schema sanitization_callback to be set to
 null to bypass fallback sanitization functions.

The logic in WP_REST_Request->sanitize_params() added in [39091] did not account for `null` or `false` being the sanitization_callback preventing overriding `rest_parse_request_arg()`. This fixes that oversight, allowing the built in sanitization function to be bypassed. See #38593.

Props kkoppenhaver, rachelbaker, jnylen0.
Fixes #39042.


git-svn-id: https://develop.svn.wordpress.org/trunk@39563 602fd350-edb4-49c9-b593-d223f7449a82
---
 .../rest-api/class-wp-rest-request.php        | 18 ++++++----
 tests/phpunit/tests/rest-api/rest-request.php | 36 +++++++++++++++++++
 2 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/src/wp-includes/rest-api/class-wp-rest-request.php b/src/wp-includes/rest-api/class-wp-rest-request.php
index 3c465babd0..d37ab6175d 100644
--- a/src/wp-includes/rest-api/class-wp-rest-request.php
+++ b/src/wp-includes/rest-api/class-wp-rest-request.php
@@ -818,17 +818,21 @@ class WP_REST_Request implements ArrayAccess {
 				continue;
 			}
 			foreach ( $this->params[ $type ] as $key => $value ) {
-				// if no sanitize_callback was specified, default to rest_parse_request_arg
-				// if a type was specified in the args.
-				if ( ! isset( $attributes['args'][ $key ]['sanitize_callback'] ) && ! empty( $attributes['args'][ $key ]['type'] ) ) {
-					$attributes['args'][ $key ]['sanitize_callback'] = 'rest_parse_request_arg';
+				if ( ! isset( $attributes['args'][ $key ] ) ) {
+					continue;
 				}
-				// Check if this param has a sanitize_callback added.
-				if ( ! isset( $attributes['args'][ $key ] ) || empty( $attributes['args'][ $key ]['sanitize_callback'] ) ) {
+				$param_args = $attributes['args'][ $key ];
+
+				// If the arg has a type but no sanitize_callback attribute, default to rest_parse_request_arg.
+				if ( ! array_key_exists( 'sanitize_callback', $param_args ) && ! empty( $param_args['type'] ) ) {
+					$param_args['sanitize_callback'] = 'rest_parse_request_arg';
+				}
+				// If there's still no sanitize_callback, nothing to do here.
+				if ( empty( $param_args['sanitize_callback'] ) ) {
 					continue;
 				}
 
-				$sanitized_value = call_user_func( $attributes['args'][ $key ]['sanitize_callback'], $value, $this, $key );
+				$sanitized_value = call_user_func( $param_args['sanitize_callback'], $value, $this, $key );
 
 				if ( is_wp_error( $sanitized_value ) ) {
 					$invalid_params[ $key ] = $sanitized_value->get_error_message();
diff --git a/tests/phpunit/tests/rest-api/rest-request.php b/tests/phpunit/tests/rest-api/rest-request.php
index de44844bff..dd87e2b5c0 100644
--- a/tests/phpunit/tests/rest-api/rest-request.php
+++ b/tests/phpunit/tests/rest-api/rest-request.php
@@ -342,6 +342,42 @@ class Tests_REST_Request extends WP_UnitTestCase {
 		$this->assertEquals( 'rest_invalid_param', $valid->get_error_code() );
 	}
 
+	public function test_sanitize_params_with_null_callback() {
+		$this->request->set_url_params( array(
+			'some_email' => '',
+		) );
+
+		$this->request->set_attributes( array(
+			'args' => array(
+				'some_email' => array(
+					'type'              => 'string',
+					'format'            => 'email',
+					'sanitize_callback' => null,
+				),
+			),
+		) );
+
+		$this->assertTrue( $this->request->sanitize_params() );
+	}
+
+	public function test_sanitize_params_with_false_callback() {
+		$this->request->set_url_params( array(
+			'some_uri'   => 1.23422,
+		) );
+
+		$this->request->set_attributes( array(
+			'args' => array(
+				'some_uri' => array(
+					'type'              => 'string',
+					'format'            => 'uri',
+					'sanitize_callback' => false,
+				),
+			),
+		) );
+
+		$this->assertTrue( $this->request->sanitize_params() );
+	}
+
 	public function test_has_valid_params_required_flag() {
 		$this->request->set_attributes( array(
 			'args' => array(