facebookarchive / react-360

Create amazing 360 and VR content using React
https://facebook.github.io/react-360
Other
8.73k stars 1.23k forks source link

Firebase / WebSockets handshake error #118

Closed steverob closed 7 years ago

steverob commented 7 years ago

Trying to use Firebase with ReactVR.

This is my code -

export default class WelcomeToVR extends React.Component {

  constructor(){
    super();

    var config = {
      apiKey: "<REDACTED>",
      authDomain: "<REDACTED>",
      databaseURL: "<REDACTED>",
      projectId: "<REDACTED>",
      storageBucket: "<REDACTED>",
      messagingSenderId: "<REDACTED>",
    };
    firebase.initializeApp(config);
  }

  componentWillMount() {
    firebase.database().ref(`viewers`).on('child_added', function(data) {
      console.log(data);
    });
  }

  render() {
    return (
      <View>
      </View>
    );
  }
};

AppRegistry.registerComponent('WelcomeToVR', () => WelcomeToVR);

This is the error I am seeing in the console -

WebSocket connection to 'wss://kastio-vr.firebaseio.com/.ws?v=5' failed: Error during WebSocket handshake: Unexpected response code: 500

WrappedWebSocket    @   VM1892:37
connect @   WebSocketModule.js:45
frame   @   ReactNativeContext.js:416
frame   @   createRootView.js:188
_frame  @   VRInstance.js:152

Would love some help here. Do I need to do anything special for WebSockets?

andrewimm commented 7 years ago

Websockets here work the exact same way they do in React Native (theoretically). I've used them for a number of implementations, and they seem fine for the most part. I'd look online and see if Firebase requires anything special when running on RN.

steverob commented 7 years ago

Thanks for replying @andrewimm. But I have gone through some of the tutorials and guides for Firebase + RN setup and I don't see anyone doing something special to get it to work.

Should I post this question on the ReactNative issues? Thanks.

andrewimm commented 7 years ago

@steverob if you go into Chrome's devtools, you can see which messages are getting sent out via the websocket. This is how I debugged it when we first implemented it. Do you mind copying the requests that are being sent out to Firebase (may need to sanitize to remove any private keys, I don't know)? That would be immensely helpful in pinpointing the issue, since Firebase seems to be unhappy with the data being sent out.

In the meantime, I'll reach out to some of my friends on the Firebase team and see if I can get any help from them.

steverob commented 7 years ago

@andrewimm appreciate your help. Would love to get this going.

Here is what I see in the network console -

2017-04-21_23-38-38_scrot

Does this help in anyway?

andrewimm commented 7 years ago

That does help. Can you also show the information getting sent from the "Frames" tab? That's where the actual payloads are shown.

steverob commented 7 years ago

okay, this is all there is in the Frames tab - 2017-04-21_23-43-30_scrot

steverob commented 7 years ago

@andrewimm a bit more info, if I setup a listen from the index.html file outside of the RN context, the WS url that's being tried is wss://s-usc1c-nss-107.firebaseio.com/.ws?v=5&ns=kastio-vr but when I do this from within the RN context, it goes for wss://kastio-vr.firebaseio.com/.ws?v=5.

That's weird. The only thing that's differing is the fact that I am using the CDN version of Firebase (3.8.0) outside of RN and NPM version (3.8.0) from inside RN.

andrewimm commented 7 years ago

This sounds pretty firebase-specific, and unfortunately a bit out of my area of expertise. When I worked on Parse, we had to intentionally fork some behaviors between web browser and RN, so I wonder if this SDK is doing the same. I'll reach out to some Firebase people and see if I can't get this sorted, thanks for being patient.

steverob commented 7 years ago

@andrewimm thanks so much for this help!

steverob commented 7 years ago

@andrewimm any updates on this? I tried with a ReactNative app and the same code, it worked just perfect. It's so weird.

steverob commented 7 years ago

@andrewimm I heard back from the Firebase people. They said Firebase redirects from the initial endpoint - wss://kastio-vr.firebaseio.com/.ws?v=5 to wss://s-usc1c-nss-107.firebaseio.com/.ws?v=5&ns=kastio-vr.

Does ReactNative handle this though? Thanks.

steverob commented 7 years ago

@Salakar Thanks. I'm trying it out now.

Just importing RNFirebase is crashing the app.

2017-04-27_18-13-26_scrot

alexduros commented 7 years ago

I faced up the same problem. @steverob this really seems to be related to react-native WebSocket implementation. As I'm new to react-vr and react-native, I am going deeper into WebSocket to see if there is some way to fix it to make WebSocket follow redirections.

alexduros commented 7 years ago

I ended with focusing on which implementation of websocket is use when firebase is bundled with react-vr.

I ended up with this call :

RCTWebSocketModule.connect(url, protocols, options, this._socketId);

https://github.com/facebook/react-native/blob/master/Libraries/WebSocket/WebSocket.js#L87

which, as far as I understand, is the poyfill from react-native which provided cross-compatible Websocket implementation but I don't see where I can fix this implementation.

On the other hand, I found this discussion https://github.com/websockets/ws/issues/812 about how websocket should follow redirections or not.

alexduros commented 7 years ago

Ok, finally figured it out.

https://github.com/facebook/react-vr/blob/master/ReactVR/js/Modules/WebSocketModule.js#L44

The current implementation of WebSocketModule passes protocols as "null" string in WebSocket creation, which make Websocket headers looks like

Sec-WebSocket-Extensions:permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: XXXXXXX
Sec-WebSocket-Protocol:null
Sec-WebSocket-Version:13

And firebase send a 500 error code with this.

I will go deeper and prepare a PR to fix that.

andrewimm commented 7 years ago

@alexduros That's awesome. Look forward to a PR.

alexduros commented 7 years ago

@andrewimm I wonder where is the best place to fix it.

Actually, I think the best is to fix Websocket library from react-native :

https://github.com/facebook/react-native/blob/master/Libraries/WebSocket/WebSocket.js#L81

    if (!Array.isArray(protocols)) {
      protocols = null; // replace null by an empty array here
    }

which will fix serialization of Sec-WebSocket-Protocol then.

But we could also consider adding a security check in WebSocketModule :

https://github.com/facebook/react-vr/blob/master/ReactVR/js/Modules/WebSocketModule.js#L45

In order to ensure we don't pass a null object as protocols parameter of WebSocket constructor.

What do you think ?

andrewimm commented 7 years ago

I think we should fix it in WebSocketModule. The expectation of the browser's WebSocket implementation is that the absence of a second argument in the constructor leads to the creation of an empty-string in the Sec header.

let's modify line 45 to be

const socket = protocols ? new WebSocket(url, protocols) : new WebSocket(url);