Ticket #45142: 45142.3.diff
File 45142.3.diff, 15.7 KB (added by , 6 years ago) |
---|
-
src/wp-includes/class-oembed.php
diff --git a/src/wp-includes/class-oembed.php b/src/wp-includes/class-oembed.php index 359171e37d..f27c085dc5 100644
a b class WP_oEmbed { 405 405 * 406 406 * @since 2.9.0 407 407 * 408 * @param string $data The returned oEmbed HTML.409 * @param string $url URL of the content to be embedded.410 * @param array $args Optional arguments, usually passed from a shortcode.408 * @param string|false $data The returned oEmbed HTML (false if unsafe). 409 * @param string $url URL of the content to be embedded. 410 * @param array $args Optional arguments, usually passed from a shortcode. 411 411 */ 412 412 return apply_filters( 'oembed_result', $this->data2html( $data, $url ), $url, $args ); 413 413 } -
src/wp-includes/class-wp-oembed-controller.php
diff --git a/src/wp-includes/class-wp-oembed-controller.php b/src/wp-includes/class-wp-oembed-controller.php index 7ee7950b07..9efeb54ed0 100644
a b final class WP_oEmbed_Controller { 173 173 $args['height'] = $args['maxheight']; 174 174 } 175 175 176 // Short-circuit process for URLs belonging to the current site. 177 $data = get_oembed_response_data_for_url( $url, $args ); 178 179 if ( $data ) { 180 return $data; 181 } 182 176 183 $data = _wp_oembed_get_object()->get_data( $url, $args ); 177 184 178 185 if ( false === $data ) { 179 186 return new WP_Error( 'oembed_invalid_url', get_status_header_desc( 404 ), array( 'status' => 404 ) ); 180 187 } 181 188 189 /** This filter is documented in wp-includes/class-oembed.php */ 190 $data->html = apply_filters( 'oembed_result', _wp_oembed_get_object()->data2html( (object) $data, $url ), $url, $args ); 191 182 192 /** 183 193 * Filters the oEmbed TTL value (time to live). 184 194 * -
src/wp-includes/embed.php
diff --git a/src/wp-includes/embed.php b/src/wp-includes/embed.php index 176988057b..efd991104a 100644
a b function get_oembed_response_data( $post, $width ) { 555 555 return apply_filters( 'oembed_response_data', $data, $post, $width, $height ); 556 556 } 557 557 558 559 /** 560 * Retrieves the oEmbed response data for a given URL. 561 * 562 * @since 5.0.0 563 * 564 * @param string $url The URL that should be inspected for discovery `<link>` tags. 565 * @param array $args oEmbed remote get arguments. 566 * @return object|false oEmbed response data if the URL does belong to the current site. False otherwise. 567 */ 568 function get_oembed_response_data_for_url( $url, $args ) { 569 $switched_blog = false; 570 571 if ( is_multisite() ) { 572 $url_parts = wp_parse_args( wp_parse_url( $url ), array( 573 'host' => '', 574 'path' => '/', 575 ) ); 576 577 $qv = array( 'domain' => $url_parts['host'], 'path' => '/' ); 578 579 // In case of subdirectory configs, set the path. 580 if ( ! is_subdomain_install() ) { 581 $path = explode( '/', ltrim( $url_parts['path'], '/' ) ); 582 $path = reset( $path ); 583 584 if ( $path ) { 585 $qv['path'] = get_network()->path . $path . '/'; 586 } 587 } 588 589 $sites = get_sites( $qv ); 590 $site = reset( $sites ); 591 592 if ( $site && (int) $site->blog_id !== get_current_blog_id() ) { 593 switch_to_blog( $site->blog_id ); 594 $switched_blog = true; 595 } 596 } 597 598 $post_id = url_to_postid( $url ); 599 600 /** This filter is documented in wp-includes/class-wp-oembed-controller.php */ 601 $post_id = apply_filters( 'oembed_request_post_id', $post_id, $url ); 602 603 if ( ! $post_id ) { 604 if ( $switched_blog ) { 605 restore_current_blog(); 606 } 607 608 return false; 609 } 610 611 $width = isset( $args['width'] ) ? $args['width'] : 0; 612 613 $data = get_oembed_response_data( $post_id, $width ); 614 615 if ( $switched_blog ) { 616 restore_current_blog(); 617 } 618 619 return $data ? (object) $data : false; 620 } 621 622 558 623 /** 559 624 * Filters the oEmbed response data to return an iframe embed code. 560 625 * … … function the_embed_site_title() { 1071 1136 * Null if the URL does not belong to the current site. 1072 1137 */ 1073 1138 function wp_filter_pre_oembed_result( $result, $url, $args ) { 1074 $switched_blog = false; 1075 1076 if ( is_multisite() ) { 1077 $url_parts = wp_parse_args( wp_parse_url( $url ), array( 1078 'host' => '', 1079 'path' => '/', 1080 ) ); 1081 1082 $qv = array( 'domain' => $url_parts['host'], 'path' => '/' ); 1083 1084 // In case of subdirectory configs, set the path. 1085 if ( ! is_subdomain_install() ) { 1086 $path = explode( '/', ltrim( $url_parts['path'], '/' ) ); 1087 $path = reset( $path ); 1088 1089 if ( $path ) { 1090 $qv['path'] = get_network()->path . $path . '/'; 1091 } 1092 } 1093 1094 $sites = get_sites( $qv ); 1095 $site = reset( $sites ); 1096 1097 if ( $site && (int) $site->blog_id !== get_current_blog_id() ) { 1098 switch_to_blog( $site->blog_id ); 1099 $switched_blog = true; 1100 } 1101 } 1102 1103 $post_id = url_to_postid( $url ); 1104 1105 /** This filter is documented in wp-includes/class-wp-oembed-controller.php */ 1106 $post_id = apply_filters( 'oembed_request_post_id', $post_id, $url ); 1107 1108 if ( ! $post_id ) { 1109 if ( $switched_blog ) { 1110 restore_current_blog(); 1111 } 1139 $data = get_oembed_response_data_for_url( $url, $args ); 1112 1140 1113 return $result; 1141 if ( $data ) { 1142 return _wp_oembed_get_object()->data2html( $data, $url ); 1114 1143 } 1115 1144 1116 $width = isset( $args['width'] ) ? $args['width'] : 0; 1117 1118 $data = get_oembed_response_data( $post_id, $width ); 1119 $data = _wp_oembed_get_object()->data2html( (object) $data, $url ); 1120 1121 if ( $switched_blog ) { 1122 restore_current_blog(); 1123 } 1124 1125 if ( ! $data ) { 1126 return $result; 1127 } 1128 1129 return $data; 1145 return $result; 1130 1146 } -
tests/phpunit/tests/oembed/controller.php
diff --git a/tests/phpunit/tests/oembed/controller.php b/tests/phpunit/tests/oembed/controller.php index 9f9aa6dd46..cae6948354 100644
a b class Test_oEmbed_Controller extends WP_UnitTestCase { 14 14 protected static $subscriber; 15 15 const YOUTUBE_VIDEO_ID = 'OQSNhk5ICTI'; 16 16 const INVALID_OEMBED_URL = 'https://www.notreallyanoembedprovider.com/watch?v=awesome-cat-video'; 17 const UNTRUSTED_PROVIDER_URL = 'https://www.untrustedprovider.com'; 17 18 18 19 public static function wpSetUpBeforeClass( $factory ) { 19 20 self::$subscriber = $factory->user->create( array( … … class Test_oEmbed_Controller extends WP_UnitTestCase { 43 44 44 45 do_action( 'rest_api_init', $this->server ); 45 46 add_filter( 'pre_http_request', array( $this, 'mock_embed_request' ), 10, 3 ); 47 add_filter( 'oembed_result', array( $this, 'filter_oembed_result' ), 10, 3 ); 46 48 $this->request_count = 0; 49 50 $this->oembed_result_filter_count = 0; 47 51 } 48 52 49 53 public function tearDown() { 50 54 parent::tearDown(); 51 55 52 56 remove_filter( 'pre_http_request', array( $this, 'mock_embed_request' ), 10 ); 57 remove_filter( 'oembed_result', array( $this, 'filter_oembed_result' ), 10 ); 53 58 } 54 59 55 60 /** … … class Test_oEmbed_Controller extends WP_UnitTestCase { 59 64 */ 60 65 public $request_count = 0; 61 66 67 /** 68 * Count of the number of times the oembed_result filter was called. 69 * 70 * @var int 71 */ 72 public $oembed_result_filter_count = 0; 73 62 74 /** 63 75 * Intercept oEmbed requests and mock responses. 64 76 * … … class Test_oEmbed_Controller extends WP_UnitTestCase { 71 83 unset( $preempt, $r ); 72 84 73 85 $parsed_url = wp_parse_url( $url ); 74 parse_str( $parsed_url['query'], $query_params ); 86 $query = isset( $parsed_url['query'] ) ? $parsed_url['query'] : ''; 87 parse_str( $query, $query_params ); 75 88 $this->request_count += 1; 76 89 77 90 // Mock request to YouTube Embed. … … class Test_oEmbed_Controller extends WP_UnitTestCase { 80 93 'response' => array( 81 94 'code' => 200, 82 95 ), 83 'body' => wp_json_encode(96 'body' => wp_json_encode( 84 97 array( 85 98 'version' => '1.0', 86 99 'type' => 'video', … … class Test_oEmbed_Controller extends WP_UnitTestCase { 90 103 'width' => $query_params['maxwidth'], 91 104 'thumbnail_height' => $query_params['maxheight'], 92 105 'height' => $query_params['maxheight'], 93 'html' => '< iframe width="' . $query_params['maxwidth'] . '" height="' . $query_params['maxheight'] . '" src="https://www.youtube.com/embed/' . self::YOUTUBE_VIDEO_ID . '?feature=oembed" frameborder="0" allowfullscreen></iframe>',106 'html' => '<b>Unfiltered</b><iframe width="' . $query_params['maxwidth'] . '" height="' . $query_params['maxheight'] . '" src="https://www.youtube.com/embed/' . self::YOUTUBE_VIDEO_ID . '?feature=oembed" frameborder="0" allowfullscreen></iframe>', 94 107 'author_name' => 'Yosemitebear62', 95 108 'thumbnail_url' => 'https://i.ytimg.com/vi/' . self::YOUTUBE_VIDEO_ID . '/hqdefault.jpg', 96 109 'title' => 'Yosemitebear Mountain Double Rainbow 1-8-10', 97 110 ) 98 111 ), 99 112 ); 100 } else { 113 } 114 115 if ( $url === self::UNTRUSTED_PROVIDER_URL ) { 116 return array( 117 'response' => array( 118 'code' => 200, 119 ), 120 'body' => '<html><head><link rel="alternate" type="application/json+oembed" href="' . self::UNTRUSTED_PROVIDER_URL . '" /></head><body></body></html>', 121 ); 122 } 123 124 if ( ! empty( $query_params['url'] ) && false !== strpos( $query_params['url'], self::UNTRUSTED_PROVIDER_URL ) ) { 101 125 return array( 102 126 'response' => array( 103 'code' => 404, 127 'code' => 200, 128 ), 129 'body' => wp_json_encode( 130 array( 131 'version' => '1.0', 132 'type' => 'rich', 133 'provider_name' => 'Untrusted', 134 'provider_url' => self::UNTRUSTED_PROVIDER_URL, 135 'html' => '<b>Filtered</b><a href="">Unfiltered</a>', 136 'author_name' => 'Untrusted Embed Author', 137 'title' => 'Untrusted Embed', 138 ) 104 139 ), 105 140 ); 106 141 } 142 143 return array( 144 'response' => array( 145 'code' => 404, 146 ), 147 ); 148 } 149 150 /** 151 * Filters 'oembed_result' to ensure correct type. 152 * 153 * @param string|false $data The returned oEmbed HTML. 154 * @param string $url URL of the content to be embedded. 155 * @param array $args Optional arguments, usually passed from a shortcode. 156 * @return string 157 */ 158 public function filter_oembed_result( $data, $url, $args ) { 159 if ( ! is_string( $data ) && false !== $data ) { 160 $this->fail( 'Unexpected type for $data.' ); 161 } 162 $this->assertInternalType( 'string', $url ); 163 $this->assertInternalType( 'array', $args ); 164 $this->oembed_result_filter_count++; 165 return $data; 107 166 } 108 167 109 168 function test_wp_oembed_ensure_format() { … … class Test_oEmbed_Controller extends WP_UnitTestCase { 510 569 $data = $response->get_data(); 511 570 512 571 $this->assertNotEmpty( $data ); 513 $this->assert True( is_object( $data ));572 $this->assertInternalType( 'object', $data ); 514 573 $this->assertEquals( 'YouTube', $data->provider_name ); 515 574 $this->assertEquals( 'https://i.ytimg.com/vi/' . self::YOUTUBE_VIDEO_ID . '/hqdefault.jpg', $data->thumbnail_url ); 516 575 $this->assertEquals( $data->width, $request['maxwidth'] ); … … class Test_oEmbed_Controller extends WP_UnitTestCase { 552 611 $data = $response->get_data(); 553 612 $this->assertEquals( $data['code'], 'rest_invalid_param' ); 554 613 } 614 615 /** 616 * @ticket 45142 617 */ 618 function test_proxy_with_internal_url() { 619 wp_set_current_user( self::$editor ); 620 621 $user = self::factory()->user->create_and_get( array( 622 'display_name' => 'John Doe', 623 ) ); 624 $post = self::factory()->post->create_and_get( array( 625 'post_author' => $user->ID, 626 'post_title' => 'Hello World', 627 ) ); 628 629 $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' ); 630 $request->set_param( 'url', get_permalink( $post->ID ) ); 631 $request->set_param( 'maxwidth', 400 ); 632 633 $response = $this->server->dispatch( $request ); 634 $data = $response->get_data(); 635 636 $data = (array) $data; 637 638 $this->assertNotEmpty( $data ); 639 640 $this->assertArrayHasKey( 'version', $data ); 641 $this->assertArrayHasKey( 'provider_name', $data ); 642 $this->assertArrayHasKey( 'provider_url', $data ); 643 $this->assertArrayHasKey( 'author_name', $data ); 644 $this->assertArrayHasKey( 'author_url', $data ); 645 $this->assertArrayHasKey( 'title', $data ); 646 $this->assertArrayHasKey( 'type', $data ); 647 $this->assertArrayHasKey( 'width', $data ); 648 649 $this->assertEquals( '1.0', $data['version'] ); 650 $this->assertEquals( get_bloginfo( 'name' ), $data['provider_name'] ); 651 $this->assertEquals( get_home_url(), $data['provider_url'] ); 652 $this->assertEquals( $user->display_name, $data['author_name'] ); 653 $this->assertEquals( get_author_posts_url( $user->ID, $user->user_nicename ), $data['author_url'] ); 654 $this->assertEquals( $post->post_title, $data['title'] ); 655 $this->assertEquals( 'rich', $data['type'] ); 656 $this->assertTrue( $data['width'] <= $request['maxwidth'] ); 657 } 658 659 /** 660 * @ticket 45142 661 */ 662 function test_proxy_with_static_front_page_url() { 663 wp_set_current_user( self::$editor ); 664 665 $post = self::factory()->post->create_and_get( array( 666 'post_title' => 'Front page', 667 'post_type' => 'page', 668 'post_author' => 0, 669 ) ); 670 671 update_option( 'show_on_front', 'page' ); 672 update_option( 'page_on_front', $post->ID ); 673 674 $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' ); 675 $request->set_param( 'url', home_url() ); 676 $request->set_param( 'maxwidth', 400 ); 677 678 $response = $this->server->dispatch( $request ); 679 $data = $response->get_data(); 680 681 $this->assertInternalType( 'object', $data ); 682 683 $data = (array) $data; 684 685 $this->assertNotEmpty( $data ); 686 687 $this->assertArrayHasKey( 'version', $data ); 688 $this->assertArrayHasKey( 'provider_name', $data ); 689 $this->assertArrayHasKey( 'provider_url', $data ); 690 $this->assertArrayHasKey( 'author_name', $data ); 691 $this->assertArrayHasKey( 'author_url', $data ); 692 $this->assertArrayHasKey( 'title', $data ); 693 $this->assertArrayHasKey( 'type', $data ); 694 $this->assertArrayHasKey( 'width', $data ); 695 696 $this->assertEquals( '1.0', $data['version'] ); 697 $this->assertEquals( get_bloginfo( 'name' ), $data['provider_name'] ); 698 $this->assertEquals( get_home_url(), $data['provider_url'] ); 699 $this->assertEquals( get_bloginfo( 'name' ), $data['author_name'] ); 700 $this->assertEquals( get_home_url(), $data['author_url'] ); 701 $this->assertEquals( $post->post_title, $data['title'] ); 702 $this->assertEquals( 'rich', $data['type'] ); 703 $this->assertTrue( $data['width'] <= $request['maxwidth'] ); 704 705 update_option( 'show_on_front', 'posts' ); 706 } 707 708 /** 709 * @ticket 45142 710 */ 711 public function test_proxy_filters_result_of_untrusted_oembed_provider() { 712 wp_set_current_user( self::$editor ); 713 714 $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' ); 715 $request->set_param( 'url', self::UNTRUSTED_PROVIDER_URL ); 716 $request->set_param( 'maxwidth', 456 ); 717 $request->set_param( 'maxheight', 789 ); 718 $request->set_param( '_wpnonce', wp_create_nonce( 'wp_rest' ) ); 719 720 $response = $this->server->dispatch( $request ); 721 $data = $response->get_data(); 722 723 $this->assertEquals( 1, $this->oembed_result_filter_count ); 724 $this->assertInternalType( 'object', $data ); 725 $this->assertEquals( 'Untrusted', $data->provider_name ); 726 $this->assertEquals( self::UNTRUSTED_PROVIDER_URL, $data->provider_url ); 727 $this->assertEquals( 'rich', $data->type ); 728 $this->assertFalse( $data->html ); 729 } 730 731 /** 732 * @ticket 45142 733 */ 734 public function test_proxy_does_not_filter_result_of_trusted_oembed_provider() { 735 wp_set_current_user( self::$editor ); 736 737 $request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' ); 738 $request->set_param( 'url', 'https://www.youtube.com/watch?v=' . self::YOUTUBE_VIDEO_ID ); 739 $request->set_param( 'maxwidth', 456 ); 740 $request->set_param( 'maxheight', 789 ); 741 $request->set_param( '_wpnonce', wp_create_nonce( 'wp_rest' ) ); 742 743 $response = $this->server->dispatch( $request ); 744 $data = $response->get_data(); 745 746 $this->assertEquals( 1, $this->oembed_result_filter_count ); 747 $this->assertInternalType( 'object', $data ); 748 749 $this->assertStringStartsWith( '<b>Unfiltered</b>', $data->html ); 750 } 555 751 }