Handling Crossdomain.xml and 302 Redirects Using NetStream

Skip Intro

When dealing with CDN’s, a lot of time you’ll get redirected. Other times, you’ll just be dealing with a server that is dynamically loading assets from other servers. In both cases, the server may return a redirect, and thus a new URL that you’ll load your media from (image, video, sound, etc.). This can cause havoc with Flash Player’s automatic loading of crossdomain.xml files for permission to access the media in Flash Player.

Short Version of What a CDN Is and What is a Redirect

A CDN stands for Content Delivery Network, and they are used everywhere nowadays. They are utilized to ensure that you can deliver images, video, etc. to millions of people consistently and quickly. The most common CDN’s are Akamai, Limelight, Castfire, and Amazon S3. A lot of times, instead of loading an image from a static location on a webserver, you’ll instead load from the CDN. The link actually has server-side logic behind it to redirect your request to next available server. The theory goes that if you have 100 servers, once you have 100 people asking for images, you’ll have distributed your server load nicely; 1 request for each server, with an optimization to load from the server closest to the person asking. You then repeat this process as more people come in. So, if you have 200 requests, each server is only handling 2 requests. A lot of times this means the web server will return a 302 HTTP status code (or a 301, or a 307, etc.). This instructs the web browser to reload the media from the new URL instead. Flash Player abstracts its handling of HTTP Status Codes. For example, a 404 (not found) or a 500 (server blew up good) both result in an IOErrorEvent for Loader for example. Redirects, however, while still loading your image or video, will NOT fetch a crossdomain.xml file for the new URL.

Why is this a problem?

When you load an image, Flash Player doesn’t care where it comes from. While you can sometimes get security errors, you’re still allowed to load an image from another domain. However, you cannot play with the pixels of that image if it’s not in your same domain. So, if I were to write a Twitter Flash app that resides on twitter.com, and it loaded a user’s Twitter icon and attempted to apply bitmap smoothing to it, I’d get a security error. This is because Twitter uses Amazon S3 to host Twitter user icons (example). Since s3.amazoneaws.com is different than twitter.com, Flash Player prevents me from accessing the pixels in that image and throws a SecurityError UNLESS a crossdomain.xml from s3.amazoneaws.com was already loaded. Now, a lot of times, Flash Player will look for a crossdomain.xml file on it’s own. In newer builds of Flash Player, you need to opt-in. This means for Loader’s load method (2nd parameter called LoaderContext), and NetStream, you need to specify that you want them to look for a crossdomain.xml file first. While this has the potential to slow down the loading of the media because it needs to load the file first, that’s ok because crossdomain.xml files are usually uber-tiny anyway. Once those files load and do allow your domain, you can play with pixels.

…except with 302 Redirects. A lot of CDN servers, when you request media, will find a new server to serve the image to you on the fly. The 2nd returned URL doesn’t cause Flash Player to reload the crossdomain.xml from the new server. So, while it may have gotten a crossdomain.xml file for the first one, it won’t for the 2nd, and your attempts to utilize BitmapData.draw on the media for example will fail at life.

My NetStream Redirect Problem

On my current project, we request progressive video from 2 sources. It either comes from an Amazon S3 server, or directly from the camera capturing the video since the video cameras have built-in flash memory with enough room. A Python web service handles where I get it from, and the Flex app doesn’t care; it just requests a URL using NetStream.play like normal. When I pause the video in our app, I take a screenshot to allow the user to save the current frame as a JPEG to their local machine. This was failing with newer videos.

It turns out, for newer videos, the server will dispatch back a 302 and route me to a specific camera server, and thus a completely different domain, to get my video. If it were older, it’d just proxy the request to Amazon S3, thus remain on the same domain. I set the checkPolicyFile to true on my NetStream once I found this to be the case, ensuring it would request a crossdomain.xml file first. However, in practice, something was wrong… it wasn’t requesting the crossdomain.xml from the camera server. Here’s the order of events as told by Charles:

  1. I issue a NetStream.play
  2. Flash Player requests “ourserver.com/crossdomain.xml” and successfullly downloads the crossdomain.xml, thus allowing me to play with the video pixels for videos on ourserver.com.
  3. Flash Player then immediately requests the FLV from “ourserver.com/media/id/flv”
  4. The server responds with a 302
  5. Flash Player then re-requests the FLV from the new URL that the 302 redirected us to which is “some.whack.ip.address/id/flv”
  6. My code that pauses the video fails with a security error because the FLV I’m attepting to copy pixels from is NOT from ourserver.com

As you can see, no request for “some.whack.ip.address/crossdomain.xml” was made. Thus, I’d have to manually request the crossdomain.xml myself. The problem is, these redirects are dynamic on the server, and it’d be a pain in the ass for them to let me know what available IP addresses their cluster has in a initial web service request.

I had forgotten Steven Sacks and I had this exact same problem loading images from Cast Fire 3 months ago. If you load a JPEG from Cast Fire from example, it’ll redirect you to some random server. If you attempt to play with the pixels of those images, it’ll fail because Flash Player doesn’t know to re-issue a crossdomain.xml request to the new server the 302 told you to go for your image. The solution we figured out was to reload the media again from the same server with the checkPolicyFile flag true on the LoaderContext since now that you know what server to use, it won’t redirect you.

The problem is, NetStream doesn’t have a LoaderContext like Loader does. So, my solution was to instead parse out the BitmapData.draw SecurityError, and attempt to load a crossdomain.xml from that parsed out URL every 2 seconds until it works, or I’ve failed 4 times. Works like a charm. Here’s a snippet of the code I used:

try
{
        var bit:BitmapData = new BitmapData(progressiveVideoPlayer.measuredWidth, progressiveVideoPlayer.measuredHeight, false, 0x000000);
        bit.draw(progressiveVideoPlayer);
}
catch(error:SecurityError)
{
        var list:Array = error.toString().split(" ");
        var swfURL:String = list[7] as String;
        var domain:String = list[10] as String;
        domain = domain.substring(0, domain.length - 1);
        var domainList:Array = domain.split("/");
        var protocol:String = domainList[0] as String;
        var address:String = domainList[2];
        var policyFileURL:String = protocol + "//" + address + "/crossdomain.xml";
        Security.loadPolicyFile(policyFileURL);
}

I attempt to draw, and if it fails with a SecurityError, I parse out the URL, load the crossdomain.xml from it, and try the same code again every 2 seconds. Works really well!

…proper handling of 302, 301, and 307’s by Flash Player with regards to crossdomain.xml files would be nice, though…

8 Responses

  1. Wow, nice work Jesse. The Flash security model never ceases to baffle and to make the web more complex. I suppose the simple answer to all this would be to proxy all your requests through a script on your server, so the Flash Player never knows where the original file came from. It’s a simple workaround but obviously means you have to pay for the extra bandwidth.

  2. Nice workaround.

    Do you know if anyone has logged this as a bug in the Adobe bug tracker? I did a quick search but couldn’t find an appropriate entry.

    I’m sure the Flash Player team will have to tackle this as CDNs (especially S3) become more commonly used by developers.

  3. Not a bad hack there jdub.

  4. lianghwa

    In flash 10.0.32 release build, the error #2122 doesn’t list the url’s anymore so this solution doesn’t work on new flash.

  5. Oh man, awesome! And also tantalisingly close to solving my own problem in a relatively straightforward way.

    Do you know if there’s any way to detect the redirect without catching a security error?

    Anyway, cheers for the post. Great stuff.

  6. Oh, forgot to say: I don’t need to play with the pixels, I just need to detect if a redirect has happened, for reporting purposes…

  7. Steven Hartland

    This only works if you have the debug version of flash player installed otherwise the error.message is just the fault code #2122. So unfortunately its not much use in its current form :(

  8. I’m having the exact same problem playing with vimeo videos. They redirect a lot. Steven is right, #2122 isn’t throwing the url anymore in the non-debug player. Hopefully there’s a workaround for this soon.