Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Long Polling is using the wrong hostname rather than the one specified in useEmulator #4603

Closed
aameen951 opened this issue Mar 9, 2021 · 6 comments · Fixed by #6912
Closed
Assignees

Comments

@aameen951
Copy link

[REQUIRED] Describe your environment

  • Operating System version: Windows NT 10.0; Win64; x64
  • Browser version: Chrome/88.0.4324.190
  • Firebase SDK version: 8.2.3
  • Firebase Product: database

[REQUIRED] Describe the problem

When using the emulator your are supposed to call useEmulator and pass it the hostname and the port number as follows:

// 192.168.1.16 is another compute on the local network
app.database().useEmulator('192.168.1.16', 9000);

The database SDK is then supposed to use that hostname for connecting to the database.

The SDK has two connection methods: Websockets and Long Polling.
Websocket connection is working as expected but long polling is not.

The first request in long polling is connecting to the correct hostname as specified by useEmulator and its sending the following request:

http://192.168.1.16:9000/.lp?start=t&ser=25520194&cb=1&v=5&p=1:851885969054:web:424a0562e499959d70b58f&ns=project-id-default-rtdb

and the response is something like the following:

function pLPCommand(c, a1, a2, a3, a4) {
parent.window["pLPCommand1"] && parent.window["pLPCommand1"](c, a1, a2, a3, a4);
}
function pRTLPCB(pN, data) {
parent.window["pRTLPCB1"] && parent.window["pRTLPCB1"](pN, data);
}
         pLPCommand('start','35','FR2NN15XmK');
pRTLPCB(0,[{"t":"c","d":{"t":"h","d":{"ts":1615310373486,"v":"5","h":"localhost:9000","s":"hH3sdSBSPZIjMcyS1p29r8oVNx0SKTw3"}}}]);

All following requests are using the hostname that arrived in the previous response which is 'localhost', and they are all failing because localhost refers to the wrong computer when used on the client.

This problem will only happen if you try to connect to the database from a different computer. Using the same computer it would still work because 'localhost' is referring to both the client and the database.

The fix for this could be to ignore the incoming hostname and port number if using an emulator.

Steps to reproduce:

  1. Set the host to 0.0.0.0 to listen for connections on all interfaces by setting the host in firebase.json:
"emulators": {
    "database": {
      "host": "0.0.0.0",
      "port": 9000
    },
}
  1. Run the database emulator.
  2. Connect to it using a client on another computer by calling database().useEmulator(hostname, 9000).
  3. I don't know of a way to force using long polling instead of websockets. For me, I just drop the websocket connection and the SDK will automatically attempt to connect using long polling.
  4. Look in the network tab and you will see that the first request to /.lp will succeed and following requests will fail.

Relevant Code:

This is the code that changes the hostname based on the first response:

export function repoManagerApplyEmulatorSettings(
repo: Repo,
host: string,
port: number
): void {
repo.repoInfo_ = new RepoInfo(
`${host}:${port}`,
/* secure= */ false,
repo.repoInfo_.namespace,
repo.repoInfo_.webSocketOnly,
repo.repoInfo_.nodeAdmin,
repo.repoInfo_.persistenceKey,
repo.repoInfo_.includeNamespaceInQueryParams
);
if (repo.repoInfo_.nodeAdmin) {
repo.authTokenProvider_ = new EmulatorAdminTokenProvider();
}
}

@looptheloop88 looptheloop88 added the testing-sdk testing with emulator label Mar 22, 2021
@maneesht
Copy link
Contributor

maneesht commented Nov 2, 2022

@aameen951 I believe this should be fixed in the latest version of the emulator. Can you please try it out and get back to us?

@google-oss-bot
Copy link
Contributor

Hey @aameen951. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

@aameen951
Copy link
Author

aameen951 commented Nov 17, 2022

Sorry for the late response, I wasn't able to test it at the time.
Unfortunately, it is still not fixed. The same problem described above is still happening.

The SDK I tested with is /__/firebase/9.14.0/firebase-database-compat.js.
The firebase-tools version is: 11.16.1.

To summarize the problem: when the SDK switch from WebSocket to Long Polling, the first request is made to the correct host (the one provided by useEmulator). But the response to this request is telling the SDK to switch to a different host, the one provided by firebase.json, which is not correct. The host specified in firebase.json is what the emulator should listen to, not what the client should send requests to.

As an example: if I set the host for the database emulator in firebase.json to 0.0.0.0 (to allow requests from outside my dev machine like my phone) then 0.0.0.0 is the host that the emulator should listen to. But the client on the other hand should not make requests to that host. Instead, I should be able to tell the client what the host of the emulator is using useEmulator. If the client is running in the same machine as the emulator then it's 127.0.0.1. If it is running on a device connected to my local network (like my phone) then it is the local IP address of my dev machine and so on.

@maneesht
Copy link
Contributor

Sorry for the delay. Are you able to reproduce this with the forceLongPolling function? I have my local firebase.json listening on localhost:9000, useEmulator with 127.0.0.1:9000, enabled forceLongPolling via app.database().INTERNAL.forceLongPolling(), and all requests go to 127.0.0.1:9000

@aameen951
Copy link
Author

If your firebase.json is listening on 0.0.0.0:9000, useEmulator is called with 127.0.0.1:9000 and you force long polling then the client will first send requests to 127.0.0.1:9000 (which is correct) then will switch to 0.0.0.0:9000 (which is incorrect).

@maneesht
Copy link
Contributor

maneesht commented Dec 16, 2022

Yes. I understand that. My first response comes back with 127.0.0.1:9000 and continues to respond on that same port, even when I set the firebase.json's listen value to 0.0.0.0:9000.

Edit: I was able to reproduce the issue and am looking into it. Will report back soon. Thank you for your patience.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
4 participants