Ticket #36356: 36356.2.diff
File 36356.2.diff, 11.5 KB (added by , 8 years ago) |
---|
-
src/wp-includes/http.php
diff --git src/wp-includes/http.php src/wp-includes/http.php index 3738b79..96c6b75 100644
function ms_allowed_http_request_hosts( $is_external, $host ) { 623 623 } 624 624 625 625 /** 626 * A wrapper for PHP's parse_url() function that handles edgecases in < PHP 5.4.7 626 * A wrapper for PHP's parse_url() function that handles consistency in the return 627 * values across PHP versions. 627 628 * 628 629 * PHP 5.4.7 expanded parse_url()'s ability to handle non-absolute url's, including 629 * schemeless and relative url's with :// in the path, this works around those 630 * limitations providing a standard output on PHP 5.2~5.4+. 630 * schemeless and relative url's with :// in the path. This function works around 631 * those limitations providing a standard output on PHP 5.2~5.4+. 632 * 633 * Secondly, across various PHP versions, schemeless URLs starting containing a ":" 634 * in the query are being handled inconsistently. This function works around those 635 * differences as well. 631 636 * 632 637 * Error suppression is used as prior to PHP 5.3.3, an E_WARNING would be generated 633 638 * when URL parsing failed. … … function ms_allowed_http_request_hosts( $is_external, $host ) { 640 645 * predefined constants to specify which one. 641 646 * Defaults to -1 (= return all parts as an array). 642 647 * @see http://php.net/manual/en/function.parse-url.php 643 * @return mixed False on failure; Array of URL components on success;644 * When a specific component has been requested: null if the component doesn't645 * exist in the given URL; a sting or - in the case of PHP_URL_PORT - integer646 * when it does;See parse_url()'s return values.648 * @return mixed False on parse failure; Array of URL components on success; 649 * When a specific component has been requested: null if the component 650 * doesn't exist in the given URL; a sting or - in the case of 651 * PHP_URL_PORT - integer when it does. See parse_url()'s return values. 647 652 */ 648 653 function wp_parse_url( $url, $component = -1 ) { 649 $parts = @parse_url( $url, $component ); 654 $to_unset = array(); 655 $url = strval( $url ); 656 657 if ( '//' === substr( $url, 0, 2 ) ) { 658 $to_unset[] = 'scheme'; 659 $url = 'placeholder:' . $url; 660 } elseif ( '/' === substr( $url, 0, 1 ) ) { 661 $to_unset[] = 'scheme'; 662 $to_unset[] = 'host'; 663 $url = 'placeholder://placeholder' . $url; 664 } 665 666 $parts = @parse_url( $url ); 650 667 651 if ( version_compare( PHP_VERSION, '5.4.7', '>=' ) ) { 652 return $parts; 668 // Remove the placeholder values. 669 foreach ( $to_unset as $key ) { 670 unset( $parts[ $key ] ); 653 671 } 654 672 655 if ( false === $parts ) { 656 // < PHP 5.4.7 compat, trouble with relative paths including a scheme break in the path. 657 if ( '/' == $url[0] && false !== strpos( $url, '://' ) ) { 658 if ( in_array( $component, array( PHP_URL_SCHEME, PHP_URL_HOST ), true ) ) { 659 return null; 660 } 661 // Since we know it's a relative path, prefix with a scheme/host placeholder and try again. 662 if ( ! $parts = @parse_url( 'placeholder://placeholder' . $url, $component ) ) { 663 return $parts; 664 } 665 // Remove the placeholder values. 666 if ( -1 === $component ) { 667 unset( $parts['scheme'], $parts['host'] ); 668 } 669 } else { 670 return $parts; 671 } 673 return _get_component_from_parsed_url_array( $parts, $component ); 674 } 675 676 /** 677 * Retrieve a specific component from a parsed URL array. 678 * 679 * @internal 680 * 681 * @since 4.7.0 682 * 683 * @param array|false $url_parts The parsed URL. Can be false if the URL failed to parse. 684 * @param int $component The specific component to retrieve. Use one of the PHP 685 * predefined constants to specify which one. 686 * Defaults to -1 (= return all parts as an array). 687 * @see http://php.net/manual/en/function.parse-url.php 688 * @return mixed False on parse failure; Array of URL components on success; 689 * When a specific component has been requested: null if the component 690 * doesn't exist in the given URL; a sting or - in the case of 691 * PHP_URL_PORT - integer when it does. See parse_url()'s return values. 692 */ 693 function _get_component_from_parsed_url_array( $url_parts, $component = -1 ) { 694 if ( -1 === $component ) { 695 return $url_parts; 672 696 } 673 697 674 // < PHP 5.4.7 compat, doesn't detect a schemeless URL's host field. 675 if ( '//' == substr( $url, 0, 2 ) ) { 676 if ( -1 === $component && ! isset( $parts['host'] ) ) { 677 $path_parts = explode( '/', substr( $parts['path'], 2 ), 2 ); 678 $parts['host'] = $path_parts[0]; 679 if ( isset( $path_parts[1] ) ) { 680 $parts['path'] = '/' . $path_parts[1]; 681 } else { 682 unset( $parts['path'] ); 683 } 684 } elseif ( PHP_URL_HOST === $component || PHP_URL_PATH === $component ) { 685 $all_parts = @parse_url( $url ); 686 if ( ! isset( $all_parts['host'] ) ) { 687 $path_parts = explode( '/', substr( $all_parts['path'], 2 ), 2 ); 688 if ( PHP_URL_PATH === $component ) { 689 if ( isset( $path_parts[1] ) ) { 690 $parts = '/' . $path_parts[1]; 691 } else { 692 $parts = null; 693 } 694 } elseif ( PHP_URL_HOST === $component ) { 695 $parts = $path_parts[0]; 696 } 697 } 698 } 698 $key = _wp_translate_php_url_constant_to_key( $component ); 699 if ( false !== $key && is_array( $url_parts ) && isset( $url_parts[ $key ] ) ) { 700 return $url_parts[ $key ]; 701 } else { 702 return null; 699 703 } 704 } 700 705 701 return $parts; 706 /** 707 * Translate a PHP_URL_* constant to the named array keys PHP uses. 708 * 709 * @internal 710 * 711 * @since 4.7.0 712 * 713 * @see http://php.net/manual/en/url.constants.php 714 * 715 * @param int $constant PHP_URL_* constant. 716 * @return string|bool The named key or false. 717 */ 718 function _wp_translate_php_url_constant_to_key( $constant ) { 719 $translation = array( 720 PHP_URL_SCHEME => 'scheme', 721 PHP_URL_HOST => 'host', 722 PHP_URL_PORT => 'port', 723 PHP_URL_USER => 'user', 724 PHP_URL_PASS => 'pass', 725 PHP_URL_PATH => 'path', 726 PHP_URL_QUERY => 'query', 727 PHP_URL_FRAGMENT => 'fragment', 728 ); 729 730 if ( isset( $translation[ $constant ] ) ) { 731 return $translation[ $constant ]; 732 } else { 733 return false; 734 } 702 735 } -
tests/phpunit/tests/http/http.php
diff --git tests/phpunit/tests/http/http.php tests/phpunit/tests/http/http.php index 607eb47..bcd0950 100644
class Tests_HTTP_HTTP extends WP_UnitTestCase { 107 107 // PHP's parse_url() calls this an invalid url, we handle it as a path 108 108 array( '/://example.com/', array( 'path' => '/://example.com/' ) ), 109 109 110 // Schemeless URL containing colons cause parse errors in PHP 7+. 111 array( 112 '//fonts.googleapis.com/css?family=Open+Sans:400&subset=latin', 113 array( 114 'host' => 'fonts.googleapis.com', 115 'path' => '/css', 116 'query' => 'family=Open+Sans:400&subset=latin', 117 ), 118 ), 119 array( 120 '//fonts.googleapis.com/css?family=Open+Sans:400', 121 array( 122 'host' => 'fonts.googleapis.com', 123 'path' => '/css', 124 'query' => 'family=Open+Sans:400', 125 ), 126 ), 127 128 // Query parameter starting with & instead of ? 129 array( 130 'http://www.test.com/path1/path2/&q=a', 131 array( 132 'scheme' => 'http', 133 'host' => 'www.test.com', 134 'path' => '/path1/path2/&q=a', 135 ), 136 ), 137 array( 138 'http://www.test.com/path1/path2/file.php&q=a', 139 array( 140 'scheme' => 'http', 141 'host' => 'www.test.com', 142 'path' => '/path1/path2/file.php&q=a', 143 ), 144 ), 145 146 array( 'filenamefound', array( 'path' => 'filenamefound' ) ), 147 148 // Empty string or non-string passed in. 149 array( '', array( 'path' => '' ) ), 150 array( 123, array( 'path' => '123' ) ), 110 151 ); 111 152 /* 112 153 Untestable edge cases in various PHP: … … class Tests_HTTP_HTTP extends WP_UnitTestCase { 117 158 118 159 /** 119 160 * @ticket 36356 120 161 */ 121 162 function test_wp_parse_url_with_default_component() { 122 163 $actual = wp_parse_url( self::FULL_TEST_URL, -1 ); 123 164 $this->assertEquals( array( … … class Tests_HTTP_HTTP extends WP_UnitTestCase { 175 216 // PHP's parse_url() calls this an invalid URL, we handle it as a path. 176 217 array( '/://example.com/', PHP_URL_PATH, '/://example.com/' ), 177 218 219 // Schemeless URL containing colons cause parse errors in PHP 7+. 220 array( '//fonts.googleapis.com/css?family=Open+Sans:400&subset=latin', PHP_URL_HOST, 'fonts.googleapis.com' ), 221 array( '//fonts.googleapis.com/css?family=Open+Sans:400&subset=latin', PHP_URL_PORT, null ), 222 array( '//fonts.googleapis.com/css?family=Open+Sans:400&subset=latin', PHP_URL_PATH, '/css' ), 223 array( '//fonts.googleapis.com/css?family=Open+Sans:400&subset=latin', PHP_URL_QUERY, 'family=Open+Sans:400&subset=latin' ), 224 array( '//fonts.googleapis.com/css?family=Open+Sans:400', PHP_URL_HOST, 'fonts.googleapis.com' ), // 25 225 array( '//fonts.googleapis.com/css?family=Open+Sans:400', PHP_URL_PORT, null ), 226 array( '//fonts.googleapis.com/css?family=Open+Sans:400', PHP_URL_PATH, '/css' ), //27 227 array( '//fonts.googleapis.com/css?family=Open+Sans:400', PHP_URL_QUERY, 'family=Open+Sans:400' ), //28 228 229 // Query parameter starting with & instead of ? 230 array( 'http://www.test.com/path1/path2/&q=a', PHP_URL_PATH, '/path1/path2/&q=a' ), 231 array( 'http://www.test.com/path1/path2/&q=a', PHP_URL_QUERY, null ), 232 array( 'http://www.test.com/path1/path2/file.php&q=a', PHP_URL_PATH, '/path1/path2/file.php&q=a' ), 233 array( 'http://www.test.com/path1/path2/file.php&q=a', PHP_URL_QUERY, null ), 234 235 // Empty string or non-string passed in. 236 array( '', PHP_URL_PATH, '' ), 237 array( '', PHP_URL_QUERY, null ), 238 array( 123, PHP_URL_PORT, null ), 239 array( 123, PHP_URL_PATH, '123' ), 178 240 ); 179 241 } 180 242 … … class Tests_HTTP_HTTP extends WP_UnitTestCase { 224 286 } 225 287 } 226 288 } 289 290 /** 291 * @ticket 36356 292 * 293 * @dataProvider get_component_from_parsed_url_array_testcases 294 */ 295 function test_get_component_from_parsed_url_array( $url, $component, $expected ) { 296 $parts = wp_parse_url( $url ); 297 $actual = _get_component_from_parsed_url_array( $parts, $component ); 298 $this->assertSame( $expected, $actual ); 299 } 300 301 function get_component_from_parsed_url_array_testcases() { 302 // 0: A URL, 1: PHP URL constant, 2: The expected result. 303 return array( 304 array( 'http://example.com/', -1, array( 'scheme' => 'http', 'host' => 'example.com', 'path' => '/' ) ), 305 array( 'http://example.com/', -1, array( 'scheme' => 'http', 'host' => 'example.com', 'path' => '/' ) ), 306 array( 'http://example.com/', PHP_URL_HOST, 'example.com' ), 307 array( 'http://example.com/', PHP_URL_USER, null ), 308 array( 'http:///example.com', -1, false ), // Malformed. 309 array( 'http:///example.com', PHP_URL_HOST, null ), // Malformed. 310 ); 311 } 312 313 /** 314 * @ticket 36356 315 * 316 * @dataProvider wp_translate_php_url_constant_to_key_testcases 317 */ 318 function test_wp_translate_php_url_constant_to_key( $input, $expected ) { 319 $actual = _wp_translate_php_url_constant_to_key( $input ); 320 $this->assertSame( $expected, $actual ); 321 } 322 323 function wp_translate_php_url_constant_to_key_testcases() { 324 // 0: PHP URL constant, 1: The expected result. 325 return array( 326 array( PHP_URL_SCHEME, 'scheme' ), 327 array( PHP_URL_HOST, 'host' ), 328 array( PHP_URL_PORT, 'port' ), 329 array( PHP_URL_USER, 'user' ), 330 array( PHP_URL_PASS, 'pass' ), 331 array( PHP_URL_PATH, 'path' ), 332 array( PHP_URL_QUERY, 'query' ), 333 array( PHP_URL_FRAGMENT, 'fragment' ), 334 335 // Test with non-PHP_URL_CONSTANT parameter. 336 array( 'something', false ), 337 array( ABSPATH, false ), 338 ); 339 } 340 227 341 }