k6 icon indicating copy to clipboard operation
k6 copied to clipboard

Any way to force to use HTTP/1.1 protocol

Open spaiz opened this issue 6 years ago • 7 comments

Just looked over the docs and didn't find any way to force the k6 not to switch to HTTP 2

I must do it cause we have a clients that won't use HTTP 2, so when I test I want to test the same protocol.

Tnx.

spaiz avatar Mar 03 '19 14:03 spaiz

Unfortunately there's currently no way to force k6 to use HTTP/1.1 if the remote server supports HTTP/2 and the connection is over HTTPS. I think that's mostly a consequence of the way the Go standard library's HTTP client operates - it also doesn't allow us to specify the HTTP version you want to use for a particular request.

That said, I think we can potentially slightly ameliorate this in k6 by adding the option to disable HTTP/2 globally, or at maybe at a per-VU/per-group() basis. Not sure how much refactoring would be needed for the more granular approaches, but the way we can do this is by modifying the http.Transport we use to make HTTP requests in k6. If we don't execute this line: https://github.com/loadimpact/k6/blob/0b1b25949256544226cbe3641ad8024c06ef3420/js/runner.go#L171 k6 will be unable to make HTTP/2 requests. The trouble comes from the fact that this is executed once, in the beginning of initializing each VU, so it'd be somewhat difficult to get more granular than a global "don't allow any HTTP/2 requests" option...

na-- avatar Mar 05 '19 08:03 na--

Thanks for the answer.

Disallowing http/2 usage globally should be good enough. Cannot think about situation when I would like to test both protocols in the same benchmark session.

Just found in the go's doc:

Starting with Go 1.6, the http package has transparent support for the HTTP/2 protocol when using HTTPS. Programs that must disable HTTP/2 can do so by setting Transport.TLSNextProto (for clients) or Server.TLSNextProto (for servers) to a non-nil, empty map. Alternatively, the following GODEBUG environment variables are currently supported:

GODEBUG=http2client=0  # disable HTTP/2 client support
GODEBUG=http2server=0  # disable HTTP/2 server support
GODEBUG=http2debug=1   # enable verbose HTTP/2 debug logs
GODEBUG=http2debug=2   # ... even more verbose, with frame dumps

Before talking about refactoring, will the k6 see honor the GO's env variables? May be it can be a quick win...

spaiz avatar Mar 07 '19 12:03 spaiz

A quick test with GODEBUG=http2client=0 and this script:

import http from "k6/http";

export default function () {
    let resp = http.get("https://google.com/");
    console.log(resp.proto);
}

shows that we unfortunately don't honor those environment variables. I think the reason is that line I quoted above: https://github.com/loadimpact/k6/blob/0b1b25949256544226cbe3641ad8024c06ef3420/js/runner.go#L171 We use that code from the golang.org/x/net/http2 package (connected k6 issue) because we define our own http.Transport just above that line: https://github.com/loadimpact/k6/blob/0b1b25949256544226cbe3641ad8024c06ef3420/js/runner.go#L153-L171 We need to define our own http.Transport in order to have customizable TLS settings, and we need to use http2.ConfigureTransport(transport) in order for that transport to support HTTP/2 at all. But it seems that in golang.org/x/net/http2 they don't honor any of the GODEBUG values besides http2debug: https://github.com/golang/net/search?q=GODEBUG&unscoped_q=GODEBUG :disappointed: So we'll need to handle disabling HTTP/2 in k6, and unfortunately it doesn't look like there's a quick workaround.

na-- avatar Mar 07 '19 12:03 na--

Understood. Tnx for help.

Will try for to fork k6 and implement it for my usage... if it will look good will open PR.

spaiz avatar Mar 10 '19 12:03 spaiz

A proposal on how something like this (among other things) could be implemented in k6 in a backwards compatible and reasonably performant and user-friendly way: https://github.com/loadimpact/k6/issues/1045#issuecomment-501150436

na-- avatar Jun 12 '19 07:06 na--

@spaiz Did you find any solution? I am also facing same error

ERRO[0004] GoError: Get "https://": stream error: stream ID 1; HTTP_1_1_REQUIRED at github.com/loadimpact/k6/js/common.Bind.func1 (native)

ajay-sainy avatar Mar 20 '21 01:03 ajay-sainy

This is now supported since #2222, but is still not documented as can be seen in https://github.com/grafana/k6-docs/issues/664

to use it you need to set the GODEBUG env variable to http2client=0 before running k6. Effectively what didn't work in https://github.com/grafana/k6/issues/936#issuecomment-470509886 now does work.

I will leave this open both for more visibility and because I kind of doubt we will keep this working with the New HTTP API so we will likely need a different way to fix that there.

mstoykov avatar May 10 '22 09:05 mstoykov

I DO have a workaround for this... It's not great... but it works. You can proxy through fiddler classic which does not support HTTP 2 and it will downgrade all of the calls. There might be another more elegant way to use a different proxy to do the same. Also, you might be able to keep fiddler stable so that you don't slam fiddler and run it out of memory during the test, just apply a filter that will never capture anything like "~~~~". If you are running via Powershell, you can set the run to proxy through fiddler like this:

set-item env:HTTPS_PROXY localhost:8888

This will set it to proxy through the default proxy port for Fiddler Classic.

If nothing else, you could use this to ty to confirm whether this is actually the problem you're seeing or not.

Also, check out the documentation for any questions on this. This doesn't just pertain to Android, it's just some of the better documentation on using fiddler as a proxy, and figuring out desktop proxy is easy - just launch fiddler and make sure it's setup correctly - here's the documentation on the tougher case. https://docs.telerik.com/fiddler/configure-fiddler/tasks/configureforandroid

automationmaven avatar Jan 22 '23 20:01 automationmaven

Since this is now fixed by #2222, and we're unlikely to change how this works in the current HTTP API, I'll close this issue.

We're currently working on the new HTTP API (initial design document), and this feature will be addressed differently there. It's planned as part of Phase 1 of the proposal.

imiric avatar Mar 28 '23 10:03 imiric