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

[BUG] Private Network Requests Hang When Route Is Registered #12148

Open
citizensas opened this issue Feb 16, 2022 · 20 comments
Open

[BUG] Private Network Requests Hang When Route Is Registered #12148

citizensas opened this issue Feb 16, 2022 · 20 comments

Comments

@citizensas
Copy link

Context:

  • Playwright Version: 1.19.0
  • Operating System: Mac
  • Node.js version: 14.17
  • Browser: Chromium

Code Snippet

import {test} from @playwright/test';
test('hangs requests to private network', async ({page}) => {
  page.route('**', route => route.continue()); // <-- this causes the bug
});

Describe the bug
Let's say I have a website that fetches something from my local server. If I don't stub any network calls in my test, then all works like expected. But if I have a Route defined in my test, then the request to my local (private) network hangs. Even if I have a route that doesn't match any request throughout the test, it'll still fail.

await page.route('/a-url-that-is-never-called', route => route.continue());

I've created a repository that shows exactly what the issue is about.
https://github.com/citizensas/chromium-private-network-playwright

This is very similar to the #5952 issue.

@dgozman
Copy link
Contributor

dgozman commented Feb 16, 2022

I can repro this. Note: this requires some server running on the localhost. Most likely the upstream issue.

@dgozman
Copy link
Contributor

dgozman commented Feb 16, 2022

Scenario: some https site does fetch('localhost', { mode: 'no-cors' }), that hangs with interception enabled.

Investigation revealed the following protocol sequence:

  • (event) Fetch.requestPaused(id1, networkId1, GET)
  • (event) Network.requestWillBeSent(networkId1, GET)
  • (command) Fetch.continueRequest(id1)
  • (event) Network.requestWillBeSent(networkId2, OPTIONS)
  • (event) Fetch.requestPaused(id2, networkId2, OPTIONS)
  • (command) Fetch.fulfillRequest(id2)
  • (event) Fetch.requestPaused(id1, networkId1, GET)

So we get requestPaused twice for this request, because Chromium decides to restart it with cors after hitting private network.

Possible solutions:

  • retain requestWillBeSent (until loadingFinished/loadingFailed) and handle second requestPaused for any request;
  • same as above, but only for requests that had cors preflight;
  • introduce Network.willRestartRequest that will be issued instead of an extra requestWillBeSent, and treat it accordingly.

@citizensas
Copy link
Author

citizensas commented Feb 18, 2022

That's a very good observation @dgozman. I tried to workaround this issue with your first possible solution, but unfortunately that didn't work.

retain requestWillBeSent (until loadingFinished/loadingFailed) and handle second requestPaused for any request;

The problem is that after the first Fetch.continueRequest(id1) command the request stays in pending state and no further event is fired for that requestId (i.e. loadingFinished, loadingFailed, or dataReceived).

I'd like to investigate understanding why the same scenario works when the interception is disabled and why it fails when it is enabled. Do you know where can I start looking in the code?

@dgozman
Copy link
Contributor

dgozman commented Feb 18, 2022

@citizensas This is all implemented in crNetworkManager.ts file. We assume one-to-one mapping between requestWillBeSent and requestPaused which is not the case here. The proper solution will most likely be upstream in Chromium though, so I wouldn't try to patch it up in crNetworkManager right away.

@trinode
Copy link

trinode commented May 27, 2022

This appears to be happening to us too, Does anyone know if this is being worked on either here or within chromium? Are there other issues on this or other repos progressing this that I should follow instead?

@philipearnshaw
Copy link

Unfortunately, I have this issue too with Chromium.

@ducan-ne
Copy link

ducan-ne commented Jul 15, 2022

I have this issue too, quite weird behavior.
My browser is Chromium.
Wanting a workaround for this, anyone knows? 🙇‍♂️

@citizensas
Copy link
Author

citizensas commented Jul 16, 2022

I have this issue too, quite weird behavior. My browser is Chromium. Wanting a workaround for this, anyone knows? 🙇‍♂️

I have a workaround that I use. Let's say the issue happens when I try to send a request to some 127.0.0.1 on port 8080. I define this route to be intercepted and works for me. You can adjust to your specific URL if you want.

await page.route(
  (url) => url.host === '127.0.0.1:8080, 
  async (route, req) => route.fulfill({
    response: await page.request.fetch(req)
}));

@balalaiQA
Copy link

I've deployed an app for testing in private network with using valid SSL wildcard certificate and the request handling doesn't work at all with Chromium (with FF all is OK). In Inspector the request has status code 204, and in the server logs this request didn't receive any data and immediately closed the connection.

@jondcallahan
Copy link

I've tried @citizensas 's solution, but unfortunately I'm using a self-signed cert so the node process throws Error: route.fetch: unable to verify the first certificate when using that method. I am still seeing this issue in playwright 1.33.0

@bigcakes
Copy link

bigcakes commented Nov 14, 2023

Any updates on this issue? Just testing out Playwright and I believe hitting this as the symptoms/causes are the same and would completely block our usage of Playwright.

I did find this issue though and it is hard to tell which issue we are being hit by: #10376

@dgozman
Copy link
Contributor

dgozman commented Nov 14, 2023

@bigcakes If you have a repro that we can run locally, please share. That would definitely help with fixing the issue.

@bigcakes
Copy link

@dgozman Unfortunately this is a private codebase and network that I am working in, but I was able to mostly workaround it in my PoC with this hacky bit of code:

    await page.route("**", async (route, req) => {
      route.fulfill({
        //Have to catch for requests after the page has disposed
        response: await page.request.fetch(req).catch(() => { return {} as APIResponse; }),
      });
    });
    await page.route("**/mySpecificEndpoint", async (route, req) => {
      route.fulfill({
        status: 500,
      });
    });

    await page.goto("/");

@bigcakes
Copy link

@dgozman any sort of debugging I could do to help figure out this issue?

@bigcakes
Copy link

@pavelfeldman @dgozman this will likely be a blocker for many corporations in using Playwright, is there anything I could debug on my side to help get to the bottom of this in Playwright? I am happy to, just need a point in the right direction inside Playwright on how/where to debug this issue as there is no feedback when using it that it is getting hung up

@DannyOnfido
Copy link

Any resolution for this?

@citizensas
Copy link
Author

Looks like this is fixed on the newer versions of Chromium. I installed the browser with the latest Playwright version and it works. If most of the affected users confirm that the issue is indeed fixed for them too, then we can close this issue.

@aoj2
Copy link

aoj2 commented May 3, 2024

Works for me as well 🎉

@nhlatour
Copy link

nhlatour commented May 3, 2024

Same here!

@bigcakes
Copy link

bigcakes commented May 3, 2024

Confirmed this is good now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests