400 WebSocket connection denied: origin 'file://' not allowed
that whah I got from ngrok when I am connect ionic android with my Django App through WebSocket django/channels
"Alright, the problem was somehow related to the origin header. Ionic seems to be sending a origin header containing "file://..", which was getting rejected / blocked by the websocket server." (platzhersh, http://stackoverflow.com/a/39552561)
I used
https://github.com/joewalnes/reconnecting-websocket
and
https://github.com/AngularClass/angular-websocket
same result 400 WebSocket connection denied: origin 'file://' not allowed
It looks like either the browser or our WebSocket library is rejecting your connection because it's cross-domain - for security reasons connections out from a HTML page under file:// to external resources aren't allowed. I suggest you use runserver and view the page as a http://localhost/abc/def URL instead and it will then allow the connection.
It is working on android & ios emulator not on the device.
Does that mean I can not use WebSocket django/channels library with Ionic Framework android and IOS expect if the app at the same server?
If you're using WebSockets natively you should be able to set the Origin header that you're sending (having it be file:// seems like a bad default) - you want to match the hostname. If not, there's potential we can override the autobahn security check but that would open your site up to cross-site attacks from browsers potentially.
This turns out to be a real issue with PhoneGap/Cordova apps... when running such an app on Android - and that may be the case with iOS and their MKWebView as well - the browser systematically sends file:// as the value for the Origin header (because the app runs in a web view, with all files served from the local filesystem).
I believe there's no way to control the value of that header which makes this a show stopper unless we have a mean of allowing file:// as an allowed origin on the server side.
Would there be a way to pass configuration options for the underlying Autobahn WebSocket factory via Daphne? More specifically, the allowedOrigins protocol option.
There isn't a way, mostly because we leave allowedOrigins as the default of * and let the application decide if it wants to accept things in the connect handler. Do you know if * is not good enough to match file:///?
Weirdly enough, it doesn't look like * makes it as the Daphne server returns this status code when the browser initiates the WS connection:
400 WebSocket connection denied: origin 'file://' not allowed
I had a quick look at Autobahn's code and it appears the check for matching the Origin header against the allowedOriginPatterns is here.
The allowedOrigin configuration is transformed to a list of allowedOriginPatterns here.
The above would mean an allowedOrigin configuration of ['*'] would be transformed to the following list of regex pattern: ['^.*$'], which should theoretically work...
A closer look at the code leads me to believe the following line is suspicious in Autobahn's _is_same_origin function:
if not isinstance(websocket_origin, tuple) or not len(websocket_origin) == 3:
raise ValueError("'websocket_origin' must be a 3-tuple")
It is possible that if the code upstream does not properly parse the file:// origin as a 3 elements tuple, then an exception would be thrown... I'll need to dive a little deeper into this... I'll keep you posted.
OK the culprit is right here:
if websocket_origin == 'null':
# nothing is the same as the null origin
return False
websocket_origin does have a value of 'null' when the Origin header is set to file://.
Looking at the code that checks whether the origin header is allowed or not, it appears a plausible solution would be to configure the protocol option allowNullOrigin to True:
if have_origin:
if origin_tuple == 'null' and self.factory.allowNullOrigin:
origin_is_allowed = True
else:
...
@andrewgodwin thoughts? It appears this is more an issue with Daphne than Channels but it somewhat touches on Channels as it wraps Daphne at least when bootstrapping the local development server with the runserver management command... :/
BTW I'll be happy to help on improving this, I just think I need some guidance on the best way to approach this considering both Channels and Daphne.
Yes, this would definitely be an issue to open/patch in Daphne instead. I'd say for now it's acceptable to just set allowNullOrigin to be true as long as the Origin header makes it through in websocket.connect's headers key, so the app can choose what to do.
Most helpful comment
It looks like either the browser or our WebSocket library is rejecting your connection because it's cross-domain - for security reasons connections out from a HTML page under
file://to external resources aren't allowed. I suggest you userunserverand view the page as ahttp://localhost/abc/defURL instead and it will then allow the connection.