HTTPoison & Cowboy 2 with HTTP2 support

I am writing a HTTP proxy based on Cowboy 2.7. Everything is fine except when it comes to HTTP2 support. Here is the context (sorry for the hidden parts):

$ curl --resolve www.wikipedia.org:443:192.168.178.2 https://www.wikipedia.org --cacert ca.crt -v
* Added www.wikipedia.org:443:192.168.178.2 to DNS cache
* Rebuilt URL to: https://www.wikipedia.org/
* Hostname www.wikipedia.org was found in DNS cache
*   Trying 192.168.178.2...
* TCP_NODELAY set
* Connected to www.wikipedia.org (192.168.178.2) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: ca.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Unknown (8):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS Unknown, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Client hello (1):
* TLSv1.3 (OUT), TLS Unknown, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=<hidden>; ST=None; L=None; O=None; CN=*.www.wikipedia.org
*  start date: Nov 11 12:18:32 2020 GMT
*  expire date: Nov 11 12:18:32 2021 GMT
*  subjectAltName: host "www.wikipedia.org" matched cert's "www.wikipedia.org"
*  issuer: C=<hidden>; ST=<hidden>; L=<hidden>; O=<hidden>; CN=<hidden>; emailAddress=<hidden>
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* Using Stream ID: 1 (easy handle 0x55df610ea580)
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
> GET / HTTP/2
> Host: www.wikipedia.org
> User-Agent: curl/7.58.0
> Accept: */*
> 
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* TLSv1.3 (IN), TLS Unknown, Unknown (23):
* http2 error: Invalid HTTP header field was received: frame type: 1, stream: 1, name: [Accept-Ranges], value: [bytes]
* TLSv1.3 (OUT), TLS Unknown, Unknown (23):
* HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)
* Connection #0 to host www.wikipedia.org left intact
curl: (92) HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)

where 192.168.178.2 is the IP of my proxy. I am using a self-signed CA cert for testing, the proxy generates certs for the requested domains on the fly based on the CA cert. If I force curl to use HTTP1.1 then everything is fine (i received the target website content as expected):

$ curl --resolve www.wikipedia.org:443:192.168.178.59 https://www.wikipedia.org --cacert ca.crt --http1.1 -v

Inside the Cowboy-based proxy, upon receiving a request, I use HTTPoison to make the request to the target domain and just relay the response back to client (after removing Content-Length) using the standard :cowboy_req.reply function.

My question is, did I miss anything? Maybe I have to force HTTPoison to use HTTP1.1, if so then how?

Thanks a lot!

I solved the problem. Cowboy does not seem to like capital-case header keys, e.g., Set-Cookie, Content-Length. Lowercase the headers keys before feeding the headers to Cowboy makes it happy.

1 Like