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

Add HTTP/2 Support in Proxy Layer #3708

Open
flotwig opened this issue Mar 14, 2019 · 39 comments · May be fixed by paulbaudrier/cypress#6, harunpehlivan/cypress#17, noahblon/cypress#19, ajesse11x/cypress#22 or anaymalpani/cypress#7
Labels
prevent-stale mark an issue so it is ignored by stale[bot] type: performance 🏃‍♀️ Performance related

Comments

@flotwig
Copy link
Contributor

flotwig commented Mar 14, 2019

The proxy layer currently doesn't really support HTTP/2. The only case in which a user can take advantage of HTTP/2 is if they are making a non-intercepted request through the https-proxy, and when #687 lands, all requests will be intercepted. When a request is intercepted, it can't be upgraded to HTTP/2.

Take this page, which loads 1000 images: https://flotwig.github.io/cypress-fetch-page/index1000.html

Loaded with HTTP/2, 1000 images load in 1362ms on my browser.

With HTTP/1.1, it takes 3896ms - three times as long.

Making our backend requests use HTTP/2 would give us a huge performance boost for making requests against servers that support it.

Obstacles:

  1. request library doesn't support HTTP/2 - we'd need to fork or figure out a different way to try to upgrade to http2
  2. need to figure out how HTTP/2 interacts with HTTP proxies
@sesam
Copy link

sesam commented Oct 15, 2020

What are the smallest next steps possible to bring this ticket forward?

I found there's https://github.com/cypress-io/cypress/tree/develop/packages/https-proxy and in there is also a test suite.
Are new tests to be added? I can see these new cases:

  • HTTP/2 from the proxy to the target
  • HTTP/2 from the browser to the proxy
  • various conversions done in the proxy code
    • target server is HTTP/1.1 only, but browser sent a HTTP/2 request
    • target server is HTTP/2 and browser sent a HTTP/3 or 1.1 or QUIC request

@flotwig
Copy link
Contributor Author

flotwig commented Oct 15, 2020

@sesam There's two systems at play here, neither of which support HTTP/2 at this time:

  1. The HTTP/1.1 proxy server that all user requests go through - the server is stood up in packages/server/lib/server.js, proxied requests are sent outgoing in packages/proxy/lib/http/request-middleware.ts
  2. The HTTP request library that is used to make outgoing requests for the proxy and for cy.visit/cy.request does not support HTTP/1.1 at all, neither does request, the underlying library which it is based upon. See packages/server/lib/request.js

I think that, for real performance gains, both (1) and (2) would have to be updated to speak HTTP/2. This could be done in two separate PRs. After that's completed, an HTTP/2 conversation inside of Cypress would look like this (similar to how HTTPS connections are handled in Cypress currently):

  1. User attempts to load example.com inside of the Cypress browser.
  2. Browser makes a request to the Cypress proxy with the header line: CONNECT example.com:443 HTTP/1.1
  3. Cypress routes this CONNECT request to the https-proxy, which establishes an HTTP/2 server to handle requests to example.com:443, and then pipes the incoming CONNECT request to this HTTP/2 server.
    • This is similar to how plain HTTPS is intercepted in Cypress today - CONNECT requests stand up an HTTPS server, which is then piped to the incoming CONNECT request.
  4. Then, inside of packages/server/lib/request.js, the outgoing HTTP request library is also updated to use HTTP/2. The requests/responses are proxied as normal via packages/proxy/lib/http.

I haven't worked directly with HTTP/2 yet, but does this make sense? There are several different places where tests would need to be added, but it sounds like your ideas for test coverage would be a good start.


Some quick notes from messing with (1):

  • Chrome supports HTTP/2 proxying using --proxy-server=https://localhost:xxx. However, since Chrome doesn't support insecure HTTP/2, the proxy server needs to be listening on HTTPS. Which is fine.
  • Firefox does not seem to support HTTP/2 proxying.

@midan888
Copy link

midan888 commented Apr 2, 2021

I would like to mention that this is not only performance issue. All projects that use http2 streams they just can't use Cypress.
Any updates on this issue ?

@flotwig
Copy link
Contributor Author

flotwig commented Apr 2, 2021

@midan888 nobody from Cypress is currently working on this issue.

@csvan
Copy link

csvan commented Dec 14, 2021

Making our backend requests use HTTP/2 would give us a huge performance boost for making requests against servers that support it.

For completeness, this is virtually all servers not running on localhost in development mode, so this feature would help a huge number of usecases.

@edikdeisling
Copy link
Contributor

I use Cypress Ccomponent tests with Vite. Vite downloads huge amount of javascript modules separetly. Due to limitations of HTTP1 tests initial load is slow.

Waiting for 1.5s at each module to get 304 Not Modified response :/
image

@homostellaris
Copy link

I'm trying to test my Sveltekit app which use FaunaDB's document streaming to update the page in real-time. It works when tested manually with the dev server but not when tested in Cypress.

@seanmcquaid
Copy link

Are there any updates on this issue at this point?? My team is trying to use Cypress to test our app that is using grpc-web services and we are currently unable to intercept requests or even make successful requests currently from our app in a Cypress test.

@cypress-bot cypress-bot bot added stage: icebox and removed stage: ready for work The issue is reproducible and in scope labels Apr 28, 2022
@gajus
Copy link

gajus commented Jun 14, 2022

Is there a way to entirely disable proxy?

@gajus
Copy link

gajus commented Jun 14, 2022

This could be solved with #22319

@breynolds3
Copy link

As a workaround, I modified resources/app/packages/server/lib/browsers/chrome.js to exclude my http/2 requests since they use a different port in order to not break the streaming support:
args.push('--proxy-bypass-list=<-loopback>;https://localhost:9000');

@flotwig flotwig removed their assignment Sep 1, 2022
@wojciak
Copy link

wojciak commented Sep 6, 2022

+1 :)

@kelseyaubrecht
Copy link

An update on this would be great to see. :) As it stands, projects using http/2 seem to have to look elsewhere.

@lmiller1990
Copy link
Contributor

@bigcakes what version of Cypress are you on? There were some incremental (not major) tweaks to things during Cypress 11, maybe some of those help?

I agree that apps making many requests (especially if you use Vite for your dev server and test against it, too) it can be a major bottleneck.

@bigcakes
Copy link

bigcakes commented Feb 2, 2023

@lmiller1990 We are on 11.2, but I am loading about 100 javascript chunks + css/images + API calls currently so the http1 limitation is fairly impactful to our initial load speed

@lmiller1990
Copy link
Contributor

Agreed, it's slow with many chunks, some of the slowness was addressed in this PR #25209 which was released in Cypress 12.3.0, if you can update to 12.3.0, that might help, it helped my app using Vite load much quicker in Cypress. Another user reported the same, see here: #22868 (comment) (this thread has a ton of info about the exact problem you are encountering).

That actual HTTP/2 improvements will be the biggest help, this is getting worked on but I am not sure on ETA.

@adam-thomas-privitar
Copy link

Perf is definitely better since 12.3.0, thank you to all contributors for that. However, it is still noticeably slower, especially in the vite use case.

HTTP2 seems like a win-win direction, but id also note the convo on #25201.

@bigcakes
Copy link

@lmiller1990 I did update us and saw ~20% test speed increase, however definitely looking forward to http2

@adam-thomas-privitar
Copy link

adam-thomas-privitar commented Feb 21, 2023

Actually, I've changed my mind on this. HTTP2 might not be the core issue at hand in many scenarios. See #25201 (comment)

@nagash77 nagash77 added the prevent-stale mark an issue so it is ignored by stale[bot] label Apr 3, 2023
@amiralav-sonrai
Copy link

+1

1 similar comment
@paulwalsh-sonrai

This comment was marked as spam.

@codingwesley

This comment was marked as spam.

@markbeaman44
Copy link

Just wondering whats happening regarding support got http2 - my current project has switched to http2, now all tests are broken and getting pressured to use another framework that supports it.

@lmiller1990
Copy link
Contributor

Hi @markbeaman44 - your app should work fine, even if you are using HTTP/2 - if you've got a minimal reproduction, I'd recommend creating a new issue and we can take a look.

This issue in relating to how Cypress internally handles requests - the idea is to use HTTP/2 for performance reasons. Apps using HTTP/2 work fine right now, they might just load bit slower when running in Cypress.

If you have an actual issue where an app using HTTP/2 is not working at all in Cypress, please share a minimal reproduction in a new issue and we can take a look. Thanks.

@breynolds3
Copy link

@lmiller1990 it doesn't work if you use a lot of streaming connections due to the lack of multiplexing with http/1.1. Originally I was able to work around it because our application used a separate port for the streaming connections (grpc). I bypassed the proxy for the streaming connections. But now we consolidated to a single port, so all of my tests are broken also.

@lmiller1990
Copy link
Contributor

lmiller1990 commented Jul 18, 2023

Right, I see, I think this makes sense. If you can post a minimal reproduction, that would be really useful -- ideally in a separate issue.

Having more "my app cannot be tested in Cypress" like use cases will greatly help with prioritizing this feature. Right now, the main reason to do this is to make Cypress faster -- performance is always good to have, but a real business use case (eg - "I want to use Cypress, but I can't) certainly helps the product team when they re-evaluate the priority on issues every other month or so. Thank you!

@markbeaman44
Copy link

Hi @lmiller1990 created a bug for it: #27333 let me know if more info is needed.

@talsi
Copy link

talsi commented Sep 7, 2023

If your tests are crashing and you don't have a clue why- it's worth reading it.

tl;dr

  1. Cypress proxies every network request and doing a lot of "side processing" along the way,
  2. Cypress proxy doesn't support HTTP/2 thus downgrading to the much slower HTTP/1.1
  3. Chromium doesn't cache static resources returned from Cypress proxy
  4. Modern web-app builds uses chuck splitting- sending very large number of requests for static resources in the first-time visit
  • given the facts mentioned above, If your tests reload the page and/or if you have more than a couple of "it" in the same spec you'll get the prefect chance for a "spontaneous crash".

  • A suggested workaround to resume using HTTP/2 and getting back Chrome to cache resources (if applicable) is to bypass Cypress proxy for chosen hostnames by launching Chrome/Edge browser with a modified value for the --proxy-bypass-list flag.

long story-
I'm working on large scale enterprise project using Angular (v15).
I actually got into this thread when I started to investigate the "Aw, snap / Out of memory" issue as our E2E automation project was crashing too often and the automation team could not take it anymore.

While I was reaching a dead-end with my investigation, something else caught my attention.
All network requests are being sent with HTTP/1.1 protocol while I was expecting to see HTTP/2.
Then I also noticed that it takes ridiculously unreasonable 15 sec or even more just to load 1 static resource.
Moreover, the resources should have been cached, so what's going on here?

I won't go into too much details, trying to make a long story short, but at some point we noticed that Firefox does cache the resources, there were no crashes at all with it and the total runtime was dramatically improved (somewhere between 2 to 3 times faster). Using Firefox is legit in our use-case however I think we can't rely on it for too long as this behavior can change in any future version / security patch of Firefox (I believe Chrome doesn't cache the resources because of some integrity issues with Cypress proxy). Determined to find a solution for the cache and HTTP/2 usage I ended up in this thread.

The workaround we currently use is to launch Chrome with a modified value for the --proxy-bypass-list flag.
The requests are being sent directly to the backend with faster HTTP/2 protocol, browser cache is working, no crashes and everything is much better than before.
This is the relevant part from cypress.config.ts:

{
  // ...
  e2e: {
    setupNodeEvents(on, config) {
      on('before:browser:launch', (browser = {} as Browser, launchOptions) => {
        if (browser.family === 'chromium' && browser.name !== 'electron') {
          const indexOf = launchOptions.args.indexOf('--proxy-bypass-list=<-loopback>');
          const proxyByPassList = [
            '<-loopback>',
            'gstatic.com',
            'google.com',
            // list of hostnames that should bypass Cypress proxy
          ];
          const proxyByPassListFlag = `--proxy-bypass-list=${proxyByPassList.join(';')}`;
          console.log(`replacing ${launchOptions.args[indexOf]} with ${proxyByPassListFlag}`);
          launchOptions.args[indexOf] = proxyByPassListFlag;
        }
        return launchOptions;
      });
    // ...
    },
  }
// ...
}

Disclaimer and notes for suggested workaround:

  • If the hostname you wish to bypass is the same as the baseUrl this can be a bit problematic since Cypress runs internal APIs on this domain under the hood. This can also be workaround quite easily depending on your setup. If for example your baseUrl is a.b.com you can change it to b.com. It will still be considered as same origin and you'll be able to bypass a.b.com. If needed, edit your hosts file so that b.com will point to a.b.com.
  • If your tests relay on cy.intercept for the same hostname you wish to bypass it will obviously won't work anymore so you'll have to choose one over the other.

[side note]
I think it's worth mentioning that it was really frustrating for me just trying to run a local build of Cypress to try out some things I thought maybe related. I feel like there are just a few small pieces missing so that newcomers will actually be able to contribute somehow without spending too much time on trying to get a working build running locally.

related issues:

@amcsi
Copy link

amcsi commented Sep 27, 2023

@talsi Thank you for your write-up, though sadly this won't help most Vite users, because there all the module resources come from the same domain and port as the base URL.

@andreizet
Copy link

is there anyone working on this yet? i'm willing to give it a try 🕵️ since it's been 5 years from when this issue was created and still no http2.

@jakwarrior
Copy link

On our end, we ended up migrating to Playwright to avoid any issues...

@jennifer-shehane
Copy link
Member

@andreizet We're not currently prioritizing this work. The last time we looked at this, the thought was to replace our cypress/request library with got library and a bit of additional work on top to handle it.

@ross-nordstrom
Copy link

+1. Just upgrade to Angular 17 and the new vite-based build system. My cypress tests frequently fail now because they stall out waiting for the 100+ chunk-xxxx.js assets to load over HTTP 1.1

@dufrenb
Copy link

dufrenb commented Jul 12, 2024

Hi, same thing here. We recently updated our angular builder from webpack to esbuild (using angular 17) and as expected the number of chunks generated is very much larger. As Cypress proxy does not support http2, our cypress pipeline is now 10min slower than before which is not acceptable.
We have more than 1000 tests running on cypress so we are looking for a workaround (a migration to playwright would take too much time and efforts).
Simply disabling the proxy does not do the trick because we extensively use cy.intercept, does anyone have an other solution ?

@yinshuxun
Copy link

Hi, same thing here. We recently updated our angular builder from webpack to esbuild (using angular 17) and as expected the number of chunks generated is very much larger. As Cypress proxy does not support http2, our cypress pipeline is now 10min slower than before which is not acceptable.嗨,这里也是一样。我们最近将 angular 构建器从 webpack 更新到 esbuild(使用 angular 17),正如预期的那样,生成的块数量非常大。由于 Cypress 代理不支持 http2,我们的 cypress 管道现在比以前慢了 10 分钟,这是不可接受的。 We have more than 1000 tests running on cypress so we are looking for a workaround (a migration to playwright would take too much time and efforts).我们在赛普拉上运行了 1000 多个测试,因此我们正在寻找解决方法(迁移到剧作家会花费太多时间和精力)。 Simply disabling the proxy does not do the trick because we extensively use cy.intercept, does anyone have an other solution ?简单地禁用代理并不能解决问题,因为我们广泛使用 cy.intercept,有人有其他解决方案吗?

Hello, do you find a way to deal with?

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