Frontend Labs
⋯

Day 65 — HTTP/2

Learning Objectives

  • Enable HTTP/2 on your TLS server (it's automatic with TLS)
  • Understand why H2 changes connection pool sizing assumptions
  • Measure latency difference between H1 and H2

Key Concepts

HTTP/1.1 vs HTTP/2:
  H1: 1 request per connection at a time (pipelining is broken in practice)
      browsers open 6 connections per origin to get parallelism
  H2: multiple requests multiplexed over 1 connection (streams)
      browser needs only 1 connection per origin
      header compression (HPACK): repeated headers cost ~10 bytes vs ~200 bytes

Why H2 changes backend pool sizing:
  H1: 100 concurrent requests → 100 backend connections
  H2: 100 concurrent requests → 1-10 backend connections (fewer, multiplexed)
  Your connection pool maxIdleConnsPerHost should be LOWER for H2 backends

H2 gotchas:
  - Requires TLS (h2c cleartext is non-standard)
  - Go's net/http enables H2 automatically over TLS
  - Check: log `r.Proto` to see "HTTP/2.0" vs "HTTP/1.1"

Exercise: H2-Enabled Server

package main

import (
    "crypto/tls"
    "fmt"
    "net/http"
    "time"
)

func main() {
    mux := http.NewServeMux()

    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        proto := r.Proto
        fmt.Fprintf(w, `{"protocol":%q,"path":%q}`, proto, r.URL.Path)
    })

    // TLS is required for H2; Go enables H2 automatically
    // To DISABLE H2: set TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler))
    srv := &http.Server{
        Addr:              ":8443",
        Handler:           mux,
        ReadHeaderTimeout: 5 * time.Second,
        // H2 enabled automatically when serving TLS
    }

    fmt.Println("H1/H2 server on :8443")
    fmt.Println("H1 test: curl --http1.1 --cacert ca.crt https://localhost:8443/")
    fmt.Println("H2 test: curl --http2 --cacert ca.crt https://localhost:8443/")

    if err := srv.ListenAndServeTLS("server.crt", "server.key"); err != nil {
        fmt.Println("ERROR:", err)
    }
}
# Compare H1 vs H2 latency (100 requests)
time curl --http1.1 --cacert ca.crt -s -o /dev/null https://localhost:8443/ &
time curl --http2 --cacert ca.crt -s -o /dev/null https://localhost:8443/

Real-World Context

Go's net/http package enables HTTP/2 automatically when you call ListenAndServeTLS. Most teams don't notice — it just works. But your WAF middleware must work correctly with H2 (it does, because the WAF sees http.Request regardless of H1 or H2 underneath).


Generated from week9.md · 8 Oct 2026 16:36