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

  1. 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).
  2. 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.
  3. 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.
  4. 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

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


AI-assisted analysis of snail007/goproxy@e6d6a821db (2026-09-03). Data as JSON: /api/errors/e55a795c49867fe1. Report an issue: GitHub.