REST API: Add endpoint for proxying requests to external oEmbed providers.

This endpoint is a prerequisite for the media widgets work (see https://github.com/xwp/wp-core-media-widgets).

Also use the new endpoint in the media modal instead of the `parse-embed` AJAX action.

Props westonruter, timmydcrawford, swissspidy, jnylen0.
Fixes #40450.


git-svn-id: https://develop.svn.wordpress.org/trunk@40628 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
James Nylen
2017-05-11 18:18:00 +00:00
parent 33622d9179
commit d59f437268
8 changed files with 475 additions and 37 deletions

View File

@@ -9,6 +9,25 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
* @var WP_REST_Server
*/
protected $server;
protected static $editor;
protected static $subscriber;
const YOUTUBE_VIDEO_ID = 'OQSNhk5ICTI';
const INVALID_OEMBED_URL = 'https://www.notreallyanoembedprovider.com/watch?v=awesome-cat-video';
public static function wpSetUpBeforeClass( $factory ) {
self::$subscriber = $factory->user->create( array(
'role' => 'subscriber',
) );
self::$editor = $factory->user->create( array(
'role' => 'editor',
'user_email' => 'editor@example.com',
) );
}
public static function wpTearDownAfterClass() {
self::delete_user( self::$subscriber );
self::delete_user( self::$editor );
}
public function setUp() {
parent::setUp();
@@ -18,6 +37,66 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
$this->server = $wp_rest_server = new Spy_REST_Server();
do_action( 'rest_api_init', $this->server );
add_filter( 'pre_http_request', array( $this, 'mock_embed_request' ), 10, 3 );
$this->request_count = 0;
}
public function tearDown() {
parent::tearDown();
remove_filter( 'pre_http_request', array( $this, 'mock_embed_request' ), 10, 3 );
}
/**
* Count of the number of requests attempted.
*
* @var int
*/
public $request_count = 0;
/**
* Intercept oEmbed requests and mock responses.
*
* @param mixed $preempt Whether to preempt an HTTP request's return value. Default false.
* @param mixed $r HTTP request arguments.
* @param string $url The request URL.
* @return array Response data.
*/
public function mock_embed_request( $preempt, $r, $url ) {
unset( $preempt, $r );
$this->request_count += 1;
// Mock request to YouTube Embed.
if ( false !== strpos( $url, self::YOUTUBE_VIDEO_ID ) ) {
return array(
'response' => array(
'code' => 200,
),
'body' => wp_json_encode(
array(
'version' => '1.0',
'type' => 'video',
'provider_name' => 'YouTube',
'provider_url' => 'https://www.youtube.com',
'thumbnail_width' => 480,
'width' => 500,
'thumbnail_height' => 360,
'html' => '<iframe width="500" height="375" src="https://www.youtube.com/embed/' . self::YOUTUBE_VIDEO_ID . '?feature=oembed" frameborder="0" allowfullscreen></iframe>',
'author_name' => 'Yosemitebear62',
'thumbnail_url' => 'https://i.ytimg.com/vi/' . self::YOUTUBE_VIDEO_ID . '/hqdefault.jpg',
'title' => 'Yosemitebear Mountain Double Rainbow 1-8-10',
'height' => 375,
)
),
);
} else {
return array(
'response' => array(
'code' => 404,
),
);
}
}
function test_wp_oembed_ensure_format() {
@@ -86,6 +165,15 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
$this->assertArrayHasKey( 'callback', $route[0] );
$this->assertArrayHasKey( 'methods', $route[0] );
$this->assertArrayHasKey( 'args', $route[0] );
// Check proxy route registration.
$this->assertArrayHasKey( '/oembed/1.0/proxy', $filtered_routes );
$proxy_route = $filtered_routes['/oembed/1.0/proxy'];
$this->assertCount( 1, $proxy_route );
$this->assertArrayHasKey( 'callback', $proxy_route[0] );
$this->assertArrayHasKey( 'permission_callback', $proxy_route[0] );
$this->assertArrayHasKey( 'methods', $proxy_route[0] );
$this->assertArrayHasKey( 'args', $proxy_route[0] );
}
function test_request_with_wrong_method() {
@@ -348,4 +436,100 @@ class Test_oEmbed_Controller extends WP_UnitTestCase {
update_option( 'permalink_structure', '' );
}
public function test_proxy_without_permission() {
// Test without a login.
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$response = $this->server->dispatch( $request );
$this->assertEquals( 400, $response->get_status() );
// Test with a user that does not have edit_posts capability.
wp_set_current_user( self::$subscriber );
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', self::INVALID_OEMBED_URL );
$response = $this->server->dispatch( $request );
$this->assertEquals( 403, $response->get_status() );
$data = $response->get_data();
$this->assertEquals( $data['code'], 'rest_forbidden' );
}
public function test_proxy_with_invalid_oembed_provider() {
wp_set_current_user( self::$editor );
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', self::INVALID_OEMBED_URL );
$response = $this->server->dispatch( $request );
$this->assertEquals( 404, $response->get_status() );
$data = $response->get_data();
$this->assertEquals( 'oembed_invalid_url', $data['code'] );
}
public function test_proxy_with_invalid_type() {
wp_set_current_user( self::$editor );
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'type', 'xml' );
$response = $this->server->dispatch( $request );
$this->assertEquals( 400, $response->get_status() );
$data = $response->get_data();
}
public function test_proxy_with_valid_oembed_provider() {
wp_set_current_user( self::$editor );
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', 'https://www.youtube.com/watch?v=' . self::YOUTUBE_VIDEO_ID );
$response = $this->server->dispatch( $request );
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( 1, $this->request_count );
// Subsequent request is cached and so it should not cause a request.
$response = $this->server->dispatch( $request );
$this->assertEquals( 1, $this->request_count );
// Test data object.
$data = $response->get_data();
$this->assertNotEmpty( $data );
$this->assertTrue( is_object( $data ) );
$this->assertEquals( 'YouTube', $data->provider_name );
$this->assertEquals( 'https://i.ytimg.com/vi/' . self::YOUTUBE_VIDEO_ID . '/hqdefault.jpg', $data->thumbnail_url );
}
public function test_proxy_with_invalid_oembed_provider_no_discovery() {
wp_set_current_user( self::$editor );
// If discover is false for an unkown provider, no discovery request should take place.
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', self::INVALID_OEMBED_URL );
$request->set_param( 'discover', 0 );
$response = $this->server->dispatch( $request );
$this->assertEquals( 404, $response->get_status() );
$this->assertEquals( 0, $this->request_count );
}
public function test_proxy_with_invalid_oembed_provider_with_default_discover_param() {
wp_set_current_user( self::$editor );
// For an unkown provider, a discovery request should happen.
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', self::INVALID_OEMBED_URL );
$response = $this->server->dispatch( $request );
$this->assertEquals( 404, $response->get_status() );
$this->assertEquals( 1, $this->request_count );
}
public function test_proxy_with_invalid_discover_param() {
wp_set_current_user( self::$editor );
$request = new WP_REST_Request( 'GET', '/oembed/1.0/proxy' );
$request->set_param( 'url', self::INVALID_OEMBED_URL );
$request->set_param( 'discover', 'notaboolean' );
$response = $this->server->dispatch( $request );
$this->assertEquals( 400, $response->get_status() );
$data = $response->get_data();
$this->assertEquals( $data['code'], 'rest_invalid_param' );
}
}