Check out "Do you speak JavaScript?" - my latest video course on advanced JavaScript.
Language APIs, Popular Concepts, Design Patterns, Advanced Techniques In the Browser

Flash, nodejs sockets and cross-domain policy file

Ok, that was a long journey. I took an already build project and I had to make some changes. It's a complex system involving flex applications, nodejs and a mobile site. Before to start making changes I had to setup the project and make it work on my local machine. I spend few days doing this. At the end I successfully compile the flex application and made the necessary corrections. I uploaded the new swf file and of course it didn't work.

I got the following error:

SecurityError: 0, Error #2048: Security sandbox violation: myfile.swf cannot load data from anotherhost.com:8102

It's clear what is going on. Maybe there is no crossdomain.xml file. I checked the server, but there was such a file and it was accessible via

anotherhost.com/crossdomain.xml

Then I read the error carefully and saw that the swf file is making a request to specific port. A quick check of the server's configugration file shows me that there was something on port 80 and nodejs script listening on port 8102. Now, it's getting interesting. Of course I thought that if I make

anotherhost.com:8102/crossdomain.xml

responds with the proper policy everything should be ok. I started digging in the node's code and I found out that this is actually a small socket server. So, It seems that I can't just map route crossdomain.xml. Beside that I found the following code:

var netserver = net.createServer(function(socket){ socket.addListener("error",function(err){ socket.end && socket.end() || socket.destroy && socket.destroy(); }); var xml = '\\n\\n\\n'; xml += '\\n'; xml += '\\n'; xml += '\\n'; if(socket && socket.readyState == 'open'){ socket.write(xml); socket.end(); } }); netserver.addListener("error",function(err){}); netserver.listen(7843, '0.0.0.0');

Here was the WTF moment. I had a socket server which is running on 8102, but that script also run another small server which runs on port 7843. I searched the whole repository for 7843 and didn't find anything. Then I asked one of my colleagues and he explained everything. The flash player first requires crossdomain.xml file to be uploaded on the server according to make requests. However, before to looks for the xml it checks port 843 on the same host and if there is a policy file then it use it. A piece of the Adobe's documentation here:

Adobe has filed with IANA, the Internet Assigned Numbers Authority, to reserve port 843 for the purposes of serving socket policy files. By introducing a centralized location for socket policy files, Flash Player enables a system administrator to define what ports are available through one master policy that overrides any other policy file on the host. If Flash Player 9,0,124,0 cannot retrieve a master policy file from port 843, then it requests a socket policy file on the port where it is trying to connect. However, if a policy file is available from a service on TCP port 843, then Flash Player considers that to be the authoritative set of permissions for that system.

So, in my case the flex applications works like that

  1. request to http://anotherhost.com:843
  2. there is no cross-domain policy file
  3. request to anotherhost.com:8102
  4. there is no cross-domain policy file
  5. exception

Here is the next question. Ok, we need the policy file served on port 843, then why that little additional server runs on 7843. That's because only a user with root privileges could run nodejs script on port lower then 1000. At the end we just forward 843 to 7843 port and finally we had the xml policy file served on the right port. However this doesn't help and I guess that it is because the forwarding. At the end I solved the problem by adding the following line before to call .connect() method of the Socket object.

Security.loadPolicyFile("xmlsocket://anotherhost.com:7843");

That solved the problem. Here is the actuall xml code send to flash

  <?xml version="1.0"?>
  <!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
  <cross-domain-policy>
     <site-control permitted-cross-domain-policies="master-only"/>
     <allow-access-from domain="*" to-ports="*"/>
  </cross-domain-policy>

P.S. If you want to read more about socket policy file please go to this page.

If you enjoy this post, share it on Twitter, Facebook or LinkedIn.