puffing-billy: HTTPS proxying does not work in headless Chrome
Thanks for the amazing gem, I didnāt even suspect that mocking JavaScript requests can be that simple š š„.
Iām opening this issue for other users that may have the same problem as I do. I donāt think that thereās anything that Puffing Billy team can do here to help right now.
Iām trying to use Puffing Billy together with headless Chrome. My configuration is following:
Capybara.register_driver :headless_chrome do |app|
Capybara::Selenium::Driver.new(
app,
browser: :chrome,
options: Selenium::WebDriver::Chrome::Options.new(
args: [
"headless",
"disable-gpu",
"proxy-server=#{Billy.proxy.host}:#{Billy.proxy.port}"
]
)
)
end
Proxying HTTP requests works perfectly fine. Proxying HTTPS requests throws a following error in Chrome console:
https://maps.googleapis.com/maps/api/js?key=AIzaSyBukfGfN2Ayd_LgVqjEGEtJneT-D-r4Zv4 - Failed to load resource: net::ERR_INSECURE_RESPONSE
When I remove the headless flag from my Capybara driver configuration, proxying HTTPS requests works fine.
Apparently this is the expected behaviour now for headless Chrome. It just doesnāt support ignoring these certificate errors. The most relevant issue that I found about it is https://bugs.chromium.org/p/chromium/issues/detail?id=721739.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 8
- Comments: 32 (15 by maintainers)
Chrome 65 is now stable.
HTTPS proxying is working well for us via an approach inspired by @Jack12816.
spec/feature/support/billy_ssl.rb:
In spec/feature/feature_helper.rb:
In spec/rails_helper.rb:
Iāve now verified that headless chrome works with proxied secure URLs using both browsermob-proxy and mitmproxy. Iāve updated my repro script, which now allows you to run a minimal reproduction against the three proxies:
https://github.com/urbanautomaton/headless_chrome_ssl_proxy/tree/proxy-comparison
By inspecting the traffic flows in wireshark I was able to see that the TLS handshake appears to complete successfully for puffing billy and headless chrome, itās just that Chrome then immediately drops the connection and retries. I donāt know why this is, or why it would only happen in headless mode.
Iāve run out of time to investigate this, but thought Iād leave the repro and details here in case someone else is interested in following up.
Thanks for the PR @Jack12816! I finally got around to switching to headless Chrome after running into some weird issues with poltergeist today. I was able to skip all of the SSL certificate stuff, because the
acceptInsecureCertsoption is working for me.Hereās the versions of everything on my MacBook:
2.5.3p1051.1.23.10.02.44.60954571.0.3578.80The specs are also passing on CI (GitLab), running in a Docker container based on Debian
jessie. My Dockerfile is based on this one. (Same versions of everything, except chromedriver was slightly updated to2.44.609551.)My
spec/rails_helper.rb:I didnāt need the
--disable-web-securityor--no-sandboxoptions on my Mac. I also read this post:I set up the the chrome user in my CI Docker image instead of using
--no-sandbox, but you might need it:options.add_argument('--no-sandbox').One thing I should mention is that I spent about an hour trying to get this to work, but then it suddenly started working and I donāt really know why.
I was printing the browser logs in one of my specs, which was really helpful:
puts page.driver.browser.manage.logs.get(:browser).When I didnāt have the
acceptInsecureCerts: trueoption, I was getting this error:After I added
acceptInsecureCerts: true, I started getting this error instead:Unfortunately I canāt remember the exact series of steps that caused the ātoo many retriesā error to disappear, and I canāt reproduce it anymore. I think it might have stopped happening after I deleted
spec/req_cache, removed the--headlessargument, and ran the tests from scratch in a real browser window. Then I added--headlessagain, and the tests were still passing and using the cached responses. I ranrm -rf spec/req_cacheone more time, and the tests were still passing and correctly caching the responses. So if you run into any problems, try removingspec/req_cacheand running without the--headlessflag.@AlanFoster I started a wireshark session on the loopback interface:
To show only the chrome <-> proxy traffic I added a display filter for
tcp.port == 8081(or whatever port the proxy was running on - I found it helpful to fix it as 8081 in the puffing billy config so I could more easily look at old traces).The most useful view I found was the traffic flow - once youāve got a recording with a request in go Statistics > Flow Graph, and select āShow: displayed packetsā to make it respect the display filter. You should then be looking at the back and forth between chrome and puffing billy.
Thatās about the limit of my wireshark expertise - good luck, hope you find out whatās going on. š
In the mean time, if you want headless firefox - that works pretty nice:
Note that unlike capybara webkit, firefox makes additional requests to see what version it is on etc, I have disabled this as part of my puffing billy set up.
Headless firefox appears to be pretty slow though, from 5 minutes on poltergeist to 20 minutes on headless firefox, and 18 minutes on normal firefox š¤
cc @ronwsmith Let me know if we should add headless firefox support to puffing billy out of the box or not š
@Aesthetikx Have you had any luck using Chrome 65, chromedriver 2.35, and using both acceptInsecureCerts + Proxy configuration? It seems to hang for me.
I havenāt had any luck with the following configuration:
I had time to implement a solution for macOS.
/cc @AlanFoster @adamniedzielski
@Jack12816 haha, yeah - i was aware of that when i was investigating it! The initial goal was to just get it working for the currently paused rspec session, then Iād automate it and post a solution. In the end i had no luck though!
Iāll stay tuned though, let me know if i can do anything to help š
Hello! I was having the same problem as you all, but with Cucumber and testing an external application, the
BillySslmodule works fine, but I had a bit of a problems with password when running thecertutilcommands, mostly when running more than one time, so, Iāve made some changes, and works like a charm! Here my code in case anyone have the same problem:Then in my env.rb file:
Thatās it, works both with or without headless and works fine in a Docker/Alpine!
Seemingly Chrome 65 with driver 2.35 will support the acceptInsecureCerts flag, https://bugs.chromium.org/p/chromium/issues/detail?id=721739#c95
@AlanFoster Thanks for trying, but each time your test suite run, a new puffing billy root CA is generated. So this wonāt work if you import it from your macOS settings dialog. I will look for a programmatic way to do this. Or to use a different certificate store for the new Chrome session. But unfortunately I didnāt found the time for this yet, so stay tuned. š