gimite / web-socket-js

HTML5 Web Socket implementation powered by Flash
BSD 3-Clause "New" or "Revised" License
2.73k stars 489 forks source link

The current implementation favors port 843 for socket policy files #49

Closed jvshahid closed 13 years ago

jvshahid commented 13 years ago

According to this article http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security.html#_Configuring_Socket_Policy:

...that you need to provide more explicit guidance to Flash Player from ActionScript by calling loadPolicyFile to indicate the location of a socket policy file. When you call loadPolicyFile rather than allowing Flash Player to check locations by default, Flash Player will wait as long as necessary for a response from a socket policy file server, rather than timing out after 3 seconds. This may help your application's reliability in marginal network conditions. It can thus be helpful to call loadPolicyFile even for a default socket policy file location—simply to request that Flash Player wait patiently for the socket policy file server to respond.

It looks like asking flash to load the policy file from port 843 (WebSocketMain.as:53) will make it favor that port over the destination port. This will cause a problem if port 843 is blocked by a firewall. I noticed that flash will try port 843 three time and it waits the first time for 3 sec then it waits for 6 sec for the second and third retries (On Windows it's 3, 6 and 12 seconds resp.) That's about 15-21 seconds between the time the user loads the page and a connection being established.

I'm proposing to remove that line (WebSocketMain.as:53) since flash will try port 843 anyway. Without that line, it'll try port 843 only once with a timeout of 3 seconds. This is more acceptable than the 15 seconds delay in my opinion.

Thanks,

gimite commented 13 years ago

Yeah it makes some sense. But I also have some reason to prefer the current way:

So the preference depends on how often port 843 is blocked. I don't have clear idea. I believe it's somewhat common to block everything and allow only connection to HTTP proxy, but in that case, anyway Flash socket is not available.

One option is to provide API to set policy file URL in JavaScript.

jvshahid commented 13 years ago

Yes, I was thinking about setting the policy file url through a method call in the API. That will make the library very flexible. Regarding port 843 I believe it's blocked in most corporate networks, at least this is the case for inbound traffic to my company's network. This is actually why I started investigating the reasons behind having higher load time in Firefox and IE than in Chrome.

gimite commented 13 years ago

Now you can load policy file from other port by e.g.

WebSocket.loadFlashPolicyFile("xmlsocket://example.com:80");
Vagabond commented 13 years ago

What if you WANT it to fail in 3 seconds when 843 is blocked? I guess now I know this is why things are taking forever to time out I can just comment out the line that's doing the explicit loadPolicyFile, but it'd be nice if I could force it to fail-fast without a hack.

jvshahid commented 13 years ago

Commits 0d8d903d8b3a2e0ce99a and 6640d9d806972ea1720a provide a way to override the default port. Take a look at the commit messages.

Vagabond commented 13 years ago

I have, but it doesn't address NOT setting the loadPolicyFile at all so that flash "fails fast" when 843 is blocked. I don't want to change the default port, I want to not set a port at all and fail fast if the port is blocked.

I commented out the call to loadPolicyFile for the default port, and it worked. I'm just going to do that in a local change.

gimite commented 13 years ago

Did you try this?:

WebSocket.loadFlashPolicyFile("xmlsocket://example.com:80");

(You should replace the port number with your Web Socket port)

I guess not calling Security.loadPolicyFile() is equivalent to above, because it loads policy file from the port you are connecting to by default. Note that in both cases it first tries port 843 and gives up in 3 seconds.

jvshahid commented 13 years ago

@Vagabond, I don't understand what you're trying to do here. If you're not changing the default port then I'm assuming you're policy file will be on port 843 (correct me if I'm wrong). If so why do you care about failing fast, the flash websocket implementation won't work anyway.

Vagabond commented 13 years ago

"When you call loadPolicyFile rather than allowing Flash Player to check locations by default, Flash Player will wait as long as necessary for a response from a socket policy file server, rather than timing out after 3 seconds."

Doesn't this mean that NOT calling loadPolicyFile at all will change the timeout behavior or am I reading it wrong?

jvshahid commented 13 years ago

That's partially correct, flash won't wait as necessary. As it's pointed out in the issue, it will timeout after 15-21 sec depending on the flash version and the OS. My question was, what difference does it make in your app. In my case the policy file is served on the destination port so making flash timeout after 15 seconds wasn't acceptable. I'd like to hear your answer, just present your case.

Vagabond commented 13 years ago

I run the policy server on the default port. The policy server runs on an appliance device which may or may not be firewalled, I have no way to tell or mandate whether is it or not.

I have a websocket server that falls back to long-polling if websockets don't work. If websockets aren't native, I want to try flash websockets and if those don't work I fall back to long-polling. I need this to be as fast as possible, the 15 second timeout is unacceptable. That's why I want to avoid calling loadPolicyFile at all, so it does the 3 second timeout.

gimite commented 13 years ago

I understand your situation. But Flash Player doesn't give option to "try port 843 for 3 seconds and then give up". As I mentioned in earlier post, the default behavior (without call to Security.loadPolicyFile) is:

This worked for you probably because your Web Socket server doesn't provide socket policy file (so when it fails to connect to port 843, both attempts above fail).

And again, equivalence to default behavior above should be done by:

WebSocket.loadFlashPolicyFile("xmlsocket://example.com:80");

FYI Another way to achieve your purpose (to timeout quickly) is to timeout manually i.e. use setTimeout() to fall back to long poll if ws.onopen is not called in 3 seconds.

ondrejmirtes commented 11 years ago

I'm having a problem with setting a custom port for the flash policy file. I suppose that all ports beside 80 and 443 could be blocked by corporate firewalls, so I need to setup the policy file on either of them. Also, the policy file needs to be on the same domain where the page HTML is loaded from, otherwise Flash does not make the request.

But that's a deadlock situation - ports 80 and 443 are used by the HTTP server to serve the page, so I can't use them for serving the policy file. Serving it from a different domain does not work.

What can I do to/what technology can I use to resolve this situation?

gimite commented 11 years ago

If you can modify the HTTP server, one idea is to modify the server to handle both HTTP request and socket policy file request. You can easily distinguish these two requests. Or maybe write a thin wrapper of existing HTTP server (e.g. Apache) which also handles socket policy file.

stephenbunch commented 8 years ago

Hey @gimite, I'm having trouble getting this to work.

I've got a Node server running on Heroku. The Heroku endpoint is HTTPS, but Node is listening on an HTTP port which the Heroku environment provided. So I have a few questions:

  1. Is it possible to load a policy file over HTTPS?
  2. Why is everyone so focused on creating a lightweight net server on 843 if all Flash needs to do is load an xml file from the domain in question?
  3. What exactly does the xmlsocket scheme mean, and why can't I put http or https in there?
  4. Is wss supported?

I've tried the following combinations, but I can't get any of them to work. Do either of these methods look right? I've also tried putting a crossdomain.xml file at the root, although it seems like I should be able to name this file whatever I want.

WebSocket.loadFlashPolicyFile("xmlsocket://example.com:443");
WebSocket.loadFlashPolicyFile("xmlsocket://example.com:443/crossdomain.xml");
WebSocket.loadFlashPolicyFile("example.com:443/crossdomain.xml");
WebSocket.loadFlashPolicyFile("example.com/crossdomain.xml");
WebSocket.loadFlashPolicyFile("https://example.com/crossdomain.xml");

Thanks!

gimite commented 8 years ago

Does Heroku support listening on a port with a protocol other than HTTP or HTTPS? If not, I don't think you can make web-socket-js work on Heroku, unfortunately.

Is it possible to load a policy file over HTTPS?

No.

Why is everyone so focused on creating a lightweight net server on 843 if all Flash needs to do is load an xml file from the domain in question?

Because it's its own protocol, not HTTP.

What exactly does the xmlsocket scheme mean, and why can't I put http or https in there?

That's the name of its own protocol. Only xmlsocket is allowed. http and https are not supported. That's the spec of Flash.

Is wss supported?

Yes.

stephenbunch commented 8 years ago

Ugh.. okay. Makes sense. So theoretically, in order to use web-socket-js on Heroku, I could spin up my own machine on AWS or Digital Ocean and run a small Node server that talks the xmlsocket protocol and serves the insecure version of the SWF object over HTTP. That should work, right?

gimite commented 8 years ago

I believe you need to host the web socket server in AWS too because the socket policy file and the web socket server must be in the same host. Socket policy file grants flash contents to access to the host where the policy file is located.