- Quick tips
HTTP Crash Course
This blog post was written and self-published by one of our developers. You can also find it on Medium.
Since my internet foo failed me, and the only workable example of an H2C client I can find was in the actual go test suite, I’m going to lay out what I discovered about H2C support in golang here.
First, in case you may be wondering what H2C is, it is essentially HTTP/2 but without TLS. H2C is understandably not widely publicized as HTTP/2 with TLS is more secure and not open to some types of attacks. However, H2C isn’t without its use cases; for instance, GRPC uses H2C when you build a client with grpc.WithInsecure().
Second, is that the standard golang code supports HTTP2 but does not directly support H2C. H2C support only exists in the golang.org/x/net/http2/h2c
package. You can make your HTTP server H2C capable by wrapping your handler or mux with h2c.NewHandler()
like so.
1h2s := &http2.Server{}23handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {4 fmt.Fprintf(w, "Hello, %v, http: %v", r.URL.Path, r.TLS == nil)5})67server := &http.Server{8 Addr: "0.0.0.0:1010",9 Handler: h2c.NewHandler(handler, h2s),10}1112fmt.Printf("Listening [0.0.0.0:1010]...\n")13checkErr(server.ListenAndServe(), "while listening")
The above code allows the server to support H2C upgrade and H2C prior knowledge along with standard HTTP/2 and HTTP/1.1 that golang natively supports.
If you don’t care about supporting HTTP/1.1, then you can run this code, which only supports H2C prior knowledge.
1server := http2.Server{}23l, err := net.Listen("tcp", "0.0.0.0:1010")4checkErr(err, "while listening")56fmt.Printf("Listening [0.0.0.0:1010]...\n")7for {8 conn, err := l.Accept()9 checkErr(err, "during accept")1011 server.ServeConn(conn, &http2.ServeConnOpts{12 Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {13 fmt.Fprintf(w, "Hello, %v, http: %v", r.URL.Path, r.TLS == nil)14 }),15 })16}
Once you have a running server, you can test your server by installing curl-OpenSSL
and use curl to test your H2C enabled server.
$ brew install curl-openssl
# Add curl-openssl to the front of your path
$ export PATH="/usr/local/opt/curl-openssl/bin:$PATH"
$ curl -v --http2 http://localhost:1010
* Trying ::1:1010...
* TCP_NODELAY set
* Connected to localhost (::1) port 1010 (#0)
> GET / HTTP/1.1
> Host: localhost:1010
> User-Agent: curl/7.65.0
> Accept: */*
> Connection: Upgrade, HTTP2-Settings
> Upgrade: h2c
> HTTP2-Settings: AAMAAABkAARAAAAAAAIAAAAA
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 101 Switching Protocols
< Connection: Upgrade
< Upgrade: h2c
* Received 101
* 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
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200
< content-type: text/plain; charset=utf-8
< content-length: 20
< date: Wed, 05 Jun 2019 19:01:40 GMT
<
* Connection #0 to host localhost left intact
Hello, /, http: true
curl -v --http2-prior-knowledge http://localhost:1010
* Trying ::1:1010...
* TCP_NODELAY set
* Connected to localhost (::1) port 1010 (#0)
* 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
* Using Stream ID: 1 (easy handle 0x7fdab8007000)
> GET / HTTP/2
> Host: localhost:1010
> User-Agent: curl/7.65.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 200
< content-type: text/plain; charset=utf-8
< content-length: 20
< date: Wed, 05 Jun 2019 19:00:43 GMT
<
* Connection #0 to host localhost left intact
Hello, /, http: true
Now, Remember when I said that the golang standard library does not support H2C? While that is technically correct, there is a workaround to get the golang standard HTTP/2 client to connect to an H2C enabled server.
To do so, you have to override DialTLS
and set the super-secret AllowHTTP
flag.
1client := http.Client{2 Transport: &http2.Transport{3 // So http2.Transport doesn't complain the URL scheme isn't 'https'4 AllowHTTP: true,5 // Pretend we are dialing a TLS endpoint.6 // Note, we ignore the passed tls.Config7 DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {8 return net.Dial(network, addr)9 },10 },11}1213resp, _ := client.Get(url)14fmt.Printf("Client Proto: %d\n", resp.ProtoMajor)
Although this all looks a little wonky, it actually works really well and performs nicely in production environments.
A complete working example is available here http://github.com/thrawn01/h2c-golang-example.
Learn about our Deliverability Services
Looking to send a high volume of emails? Our email experts can supercharge your email performance. See how we've helped companies like Lyft, Shopify, Github increase their email delivery rates to an average of 97%.
Last updated on May 17, 2021
HTTP Crash Course
Golang’s Superior Cache Solution to Memcached and Redis
How we built a Lucene-inspired parser in Go
Delivering HTML Emails With Mailgun-Go
What Toasters And Distributed Systems Might Have In Common
Introducing A Cross-Platform Debugger For Go
The Official Go SDK, Available Now
Designing HTML Email Templates For Transactional Emails
5 Ideas For Better Developer-Designer Collaboration
What Is a RESTful API, How It Works, Advantages, and Examples
InboxReady x Salesforce: The Key to a Stronger Email Deliverability
Become an Email Pro With Our Templates API
Google Postmaster Tools: Understanding Sender Reputation
Navigating Your Career as a Woman in Tech
Implementing Dmarc – A Step-by-Step Guide
Email Bounces: What To Do About Them
Announcing InboxReady: The deliverability suite you need to hit the inbox
Black History Month in Tech: 7 Visionaries Who Shaped The Future
How To Create a Successful Triggered Email Program
Designing HTML Email Templates For Transactional Emails
InboxReady x Salesforce: The Key to a Stronger Email Deliverability
Implementing Dmarc – A Step-by-Step Guide
Announcing InboxReady: The deliverability suite you need to hit the inbox
Designing HTML Email Templates For Transactional Emails
Email Security Best Practices: How To Keep Your Email Program Safe
Mailgun’s Active Defense Against Log4j
Email Blasts: The Dos And Many Don’ts Of Mass Email Sending
Email's Best of 2021
5 Ideas For Better Developer-Designer Collaboration
Mailgun Joins Sinch: The Future of Customer Communications Is Here
Always be in the know and grab free email resources!
By sending this form, I agree that Mailgun may contact me and process my data in accordance with its Privacy Policy.