snail007/goproxy · warning
can not find HOST header
Error message
can not find HOST header
What it means
getHeader scans the parsed request head (HeadBuf split on \r\n) for a header key case-insensitively. When the requested header is absent it returns the (misleadingly static) error "can not find HOST header", regardless of which key was requested. Its callers are BasicAuth (Authorization) and getHTTPURL (host); the message text just isn't parameterized.
Source
Thrown at utils/structs.go:365
}
URL = fmt.Sprintf("http://%s%s", _host, req.hostOrURL)
return
}
func (req *HTTPRequest) getHeader(key string) (val string, err error) {
key = strings.ToUpper(key)
lines := strings.Split(string(req.HeadBuf), "\r\n")
for _, line := range lines {
line := strings.SplitN(strings.Trim(line, "\r\n "), ":", 2)
if len(line) == 2 {
k := strings.ToUpper(strings.Trim(line[0], " "))
v := strings.Trim(line[1], " ")
if key == k {
val = v
return
}
}
}
err = fmt.Errorf("can not find HOST header")
return
}
func (req *HTTPRequest) addPortIfNot() (newHost string) {
//newHost = req.Host
port := "80"
if req.IsHTTPS() {
port = "443"
}
if (!strings.HasPrefix(req.Host, "[") && strings.Index(req.Host, ":") == -1) || (strings.HasPrefix(req.Host, "[") && strings.HasSuffix(req.Host, "]")) {
//newHost = req.Host + ":" + port
//req.headBuf = []byte(strings.Replace(string(req.headBuf), req.Host, newHost, 1))
req.Host = req.Host + ":" + port
}
return
}
type OutPool struct {View on GitHub (pinned to e6d6a821db)
Solutions
- If it's the Host case, configure clients to send HTTP/1.1 requests with a Host header (curl does this by default; check for --http1.0 flags or custom sockets).
- If it's the Authorization case, respond to the 401 challenge: the client should resend with credentials (curl: `-U user:pass` / Go: req.SetBasicAuth) — preemptive auth avoids the round trip.
- Note the error message is static even for missing Authorization headers — check which header your call path needs before debugging based on the message text alone.
- Improve the error for diagnosability by including the requested key: `fmt.Errorf("can not find header %s", key)` (library-side patch).
Example fix
// before
err = fmt.Errorf("can not find HOST header")
// after
err = fmt.Errorf("can not find header %q in request: %.50s", key, string(req.HeadBuf)) Defensive patterns
Strategy: type-guard
Validate before calling
// ensure required headers are present before sending the request through the proxy
if req.URL.Path != "" && req.Host == "" {
return errors.New("relative-form target requires a Host header (use HTTP/1.1)")
}
if needsAuth && req.Header.Get("Authorization") == "" {
return errors.New("proxy requires basic auth; set Authorization preemptively")
} Type guard
func hasHeader(headBuf []byte, key string) bool {
want := strings.ToUpper(key)
for _, line := range strings.Split(string(headBuf), "\r\n") {
parts := strings.SplitN(line, ":", 2)
if len(parts) == 2 && strings.ToUpper(strings.TrimSpace(parts[0])) == want {
return true
}
}
return false
} Try / catch
_, err := utils.NewHTTPRequest(conn, bufSize, true, auth)
if err != nil && strings.Contains(err.Error(), "can not find HOST header") {
// message is static for ANY missing header — check whether it was Host or Authorization
log.Println("request missing a required header (Host or Authorization)")
// for Authorization: resend with credentials after the 401 challenge
} Prevention
- Always use HTTP/1.1 on the client so the Host header is sent (avoid --http1.0).
- Use absolute-URI request targets or ensure Host is present for path-form targets.
- Send credentials preemptively (curl -U / req.SetBasicAuth) to skip the 401 challenge round trip.
- Remember the message text is the same for any missing header — inspect the call path, not just the message.
When it happens
Trigger: Two distinct calls: (a) getHTTPURL calls getHeader("host") for a relative-form request target (path-only URL like "GET /path") when the client omitted the Host header; (b) BasicAuth calls getHeader("Authorization") when the client sent no Authorization header (in which case BasicAuth first sends 401 + WWW-Authenticate and closes, surfacing this error to the caller).
Common situations: HTTP/1.0 clients that legitimately omit Host; hand-rolled HTTP clients missing the header; requests to an absolute URL while basic auth expects an Authorization header that the client didn't send yet (first request without preemptive auth); curl in --http1.0 mode; scrapers/health checks not sending Host.
Related errors
- authorization data error,ERR:%s
- authorization data parse error,ERR:%s
- http decoder read err:%s
- http decoder data line err:%s
- http decoder data err:%s
AI-assisted analysis of snail007/goproxy@e6d6a821db (2026-09-03).
Data as JSON: /api/errors/e55a795c49867fe1.
Report an issue: GitHub.