samuong / alpaca

A local HTTP proxy for command-line tools. Supports PAC scripts and NTLM authentication.
Apache License 2.0
184 stars 31 forks source link

Support HTTP/2 #6

Closed marcelocantos closed 2 years ago

samuong commented 5 years ago

Rather than write this from scratch, building this using github.com/elazarl/goproxy should be considered. One of their examples is a cascading proxy, which is basically similar to alpaca.

marksomething commented 2 years ago

Shouldn't updating to go1.6 have solved this? https://pkg.go.dev/net/http#:~:text=Starting%20with%20Go,are%20currently%20supported%3A

marksomething commented 2 years ago

I think this is a root cause behind trouble i've had connecting to Google Cloud APIs (they are GRPC).

samuong commented 2 years ago

@marksomething I took another look into this and I don't think you're running into an issue with Alpaca itself. Alpaca doesn't support HTTP/2, but it looks like it doesn't need to - clients and servers that support it can still communicate using HTTP/2, over a CONNECT tunnel established over HTTP/1.

There are there cases which I'll go over below:

  1. curl -> google
  2. curl -> alpaca -> google
  3. curl -> alpaca -> mitm -> google

For the first case, here's what it looks like when I use curl to send a HEAD request to Google with no proxy in between. As you can see from the first line, it's using HTTP/2:

[sam@sam-desktop ~]$ curl --head --noproxy '*' https://google.com
HTTP/2 301 
location: https://www.google.com/
content-type: text/html; charset=UTF-8
date: Sat, 11 Jun 2022 22:30:18 GMT
expires: Mon, 11 Jul 2022 22:30:18 GMT
cache-control: public, max-age=2592000
server: gws
content-length: 220
x-xss-protection: 0
x-frame-options: SAMEORIGIN
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"

Second, here's what it looks like when I tell curl to use my locally-running Alpaca instance as a proxy. What's happening here is that curl is sending a CONNECT request to Alpaca using HTTP/1.1. This succeeds with a 200 and establishes a tunnel through which curl and Google can communicate directly, using whatever protocol they negotiate - and as you can see on the 4th line, Google sends back a 301 response over HTTP/2.

[sam@sam-desktop ~]$ curl --head --proxy http://localhost:3128 https://google.com
HTTP/1.1 200 OK
Connection: close

HTTP/2 301 
location: https://www.google.com/
content-type: text/html; charset=UTF-8
date: Sat, 11 Jun 2022 22:30:28 GMT
expires: Mon, 11 Jul 2022 22:30:28 GMT
cache-control: public, max-age=2592000
server: gws
content-length: 220
x-xss-protection: 0
x-frame-options: SAMEORIGIN
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"

Where I think things could go wrong though is the third case, where you have a MITM proxy between Alpaca and Google, and it's forcing the client and server (curl and Google) to use HTTP/1.1 even though they both support HTTP/2.

I'm going to try to find some time later to add a test case to assert that Alpaca won't stop an HTTP/2 connection from being established, then close this issue. But if you do find an issue with Alpaca itself please let me know, and/or reopen this bug if I've already closed it by then.