Http Over TLS Golang Not Receiving Headers

120

Question: Http Over TLS Golang Not Receiving Headers

I am sending 'User-Agent Header' from my client but not receiving on server-side go error but when i use browser it works.

server code :

package main  import (   "crypto/tls"   "fmt"   "log"   "net/http"   "time" )  const (   defaultServerDomain = "localhost:443"   certPemPath = "./selfsigned.crt"   privKeyPath = "./selfsigned.key" )  func main() {   mux := http.NewServeMux()   mux.HandleFunc("/demo/echo", func(w http.ResponseWriter, req *http.Request) {     w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")     w.Write([]byte("This is an example server.\n"))     fmt.Printf("\n\nUserAgent : %s", req.UserAgent())    })   cfg := &tls.Config{     MinVersion:               tls.VersionTLS12,     CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},     PreferServerCipherSuites: true,     CipherSuites: []uint16{       tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,       tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,       tls.TLS_RSA_WITH_AES_256_GCM_SHA384,       tls.TLS_RSA_WITH_AES_256_CBC_SHA,     },   }   srv := &http.Server{     ReadHeaderTimeout: 2 * time.Second,     Addr:              defaultServerDomain,     Handler:           mux,     TLSConfig:         cfg,     TLSNextProto:      make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),   }   log.Fatal(srv.ListenAndServeTLS(certPemPath, privKeyPath)) } 

client code :

package main  import (   "crypto/tls"   "crypto/x509"   "fmt"   "io"   "log"   "net/http"   "os"   "time" )  const (   serverDomain = "https://localhost:443/demo/echo"   certPemPath  = "./selfsigned.crt" )  func main() {    cert, err := os.ReadFile(certPemPath)   if err != nil {     log.Fatal(err)   }   certPool := x509.NewCertPool()   if ok := certPool.AppendCertsFromPEM(cert); !ok {     log.Fatalf("unable to parse cert from %s", certPemPath)   }    client := &http.Client{     Timeout: 2 * time.Second,     Transport: &http.Transport{       DisableKeepAlives:  false,       TLSClientConfig: &tls.Config{         RootCAs: certPool,       },     },   }    r, err := http.NewRequest("GET", serverDomain, nil)   req, err := client.Do(r)   if err != nil {     log.Fatal(err)   }   req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.7113.93 Safari/537.36")   defer req.Body.Close()    html, err := io.ReadAll(req.Body)   if err != nil {     log.Fatal(err)   }   fmt.Printf("%v\n", req.Status)   fmt.Printf(string(html)) } 

Suppose to get server-side :

UserAgent : Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) go error Gecko/20100101 Firefox/91.0 Waterfox/91.4.2

Instead i get this :

UserAgent : Go-http-client/1.1

But when i use browser in my case waterfox then it works i get

UserAgent : Mozilla/5.0 (Windows NT 10.0; Win64; x64; go error rv:91.0) Gecko/20100101 Firefox/91.0 Waterfox/91.4.2

Is it something to do with code or certificate i am using selfsinged certificate

Total Answers: 1

96

Answers 1: of Http Over TLS Golang Not Receiving Headers

I believe that the issue is most likely here:

r, err := http.NewRequest("GET", serverDomain, nil) req, err := client.Do(r) 

The definition for NewRequest is func NewRequest(method, url string, body io.Reader) (*Request, error) and Client.Do func (c *Client) Do(req *Request) (*Response, error). So the code above is probably easier understood as:

req, err := http.NewRequest("GET", serverDomain, nil) resp, err := client.Do(req) // This returns a response; not  the request 

When you call Do the request is made (so the headers must be set before that point). Taking the above rephrasing of your code when you set the headers you would be calling resp.Header.Set... (i.e. you are changing the headers returned by the request; not the request headers).

Change your code to set the headers before calling Do i.e.

req, err := http.NewRequest("GET", serverDomain, nil) req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.7113.93 Safari/537.36") resp, err := client.Do(req) 

Note: I have not tested your code in full so there may be other issues