I am sending 'User-Agent Header' from my client but not receiving on server-side 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) 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; 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
CodePudding user response:
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