roguish

[Solved] SecurityError #2122 Redirected CDN Video File

We recently encountered SecurityError #2122 when trying to capture BitmapData from a video file. Crossdomain.xml files were being requested as required for using BitmapData.draw on content loaded into a SWF. Everything had been working well until we tried using a video hosted by Vimeo using their Pro service that allows you to use them as a CDN — they deliver video files and you play them in your own player.

[For an excellent background description about this redirect problem, read the posts linked below]

We determined that the media file returned to FlashPlayer was coming from a different domain than the domain we were requesting the video from. We considered detecting the domain of the redirected media file and following up our media file request with a Security.loadPolicyFile call using the new domain.

We found a few blog posts (Jesse Warden and Steven Sacks, links at bottom) that addressed similar issues. It turns out that loading images from Facebook and applying smoothing presents a similar problems due to redirects.

We looked for a *blessed* solution in the docs from Adobe. We read the following in the Adobe documentation for NetStream:
“Be careful with checkPolicyFile if you are downloading a file from a URL that uses server-side HTTP redirects. The application tries to retrieve policy files that correspond to the initial URL that you specify in NetStream.play(). If the final file comes from a different URL because of HTTP redirects, the initially downloaded policy files might not be applicable to the file’s final URL, which is the URL that matters in security decisions.”
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/NetStream.html#checkPolicyFile

As mentioned by commenters on the Warden post, the return string when a SecurityError happens in the release Flash Player is inconsistent. We found that the latest release Flash Player distributed with Chrome does not return a string including the redirected source file url (config as of this writing: Mac OSX 10.9.4, Chrome browser 38.0.2125.111, installed Flash Player 15.0.0.189). Perhaps other system configurations would not return the needed info either. We needed a solution that would work in all scenarios.

We looked through the returned values with NetStream/NetConnection events (NetDataEvent and NetStatusEvent) and couldn’t determine the redirected URL. We tried making additional requests for the media file with Loader and URLLoader just to see if the redirected URL would be detected.

After all our Flash-only solutions didn’t solve the problem, we created a redirect detection PHP script to detect the domain of the delivered media file. This works great:

Our PHP script:

1
2
3
4
5
6
7
8
9
10
11
<?php
$url=$_GET['pathToMedia'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$a = curl_exec($ch);
$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
echo $url;
?>

The Flash side of things looks something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public function redirectTest()
{
	var tURLRequest : URLRequest = new URLRequest( "redirectDetect.php" );
	var tVariables : URLVariables = new URLVariables();
	tVariables.pathToMedia = "http://video.file.that.will.be.redirected";
	tURLRequest.data = tVariables;
	var tURLLoader : URLLoader = new URLLoader();
	tURLLoader.addEventListener( Event.COMPLETE, onCompleteURLRedirect );
	tURLLoader.load( tURLRequest );
}
 
private function onCompleteURLRedirect( event : Event ) : void {
	var tURI : com.adobe.net.URI = new URI( ( event.target as URLLoader ).data ); // the URL of the returned video
	var tMediaRedirectedURL : String = tURI.scheme + "://" + tURI.authority + "/crossdomain.xml";
	Security.loadPolicyFile( tMediaRedirectedURL );		
	( event.target as URLLoader ).removeEventListener( Event.COMPLETE, onCompleteURLRedirect );
 
	// debug: to verify the crossdomain file that was loaded, we launch it in a separate window
	var tURLRequest : URLRequest = new URLRequest( tMediaRedirectedURL );
	navigateToURL( tURLRequest, "_blank" );
}

We had some concern that the PHP request might trigger an additional download of the video file, but observing the network traffic confirmed that wasn’t the case.

Possible Limitations:

  • Needs some testing under various conditions. Tested with just Vimeo so far.
  • Not sure what would happen if the SWF and redirectDetect.php files were hosted in different domains. That might cause crossdomain issues.
  • Not sure what impact this may have on the metrics for content requests of the media file.
  • Will only work if subsequent calls to retrieve the video (within a
    few seconds of one another) return the video from the same redirected
    domain. If the CDN happens to return a different domain for the PHP
    request and the actual request to play the media, this won’t work.

Resources we referenced and used:

[UPDATE: 03/09/2015]A reader pointed me towards this post with another idea for capturing BitmapData: gamespoweredby.com/blog/2014/11/netstream-playnull-bitmapdata-workaround
Also, the latest Flash Player now allows BitmapData capture from StageVideo. That’s another avenue to explore.