snail007/goproxy · error
http decoder data err:%s
Error message
http decoder data err:%s
What it means
NewHTTPRequest splits the request line with Sscanf "%s%s" into Method and hostOrURL. If either token comes back empty — i.e. the first line does not contain two whitespace-separated tokens like "GET /path" or "CONNECT host:port" — it throws "http decoder data err:%s" with the first 50 bytes, closes the connection, and returns.
Source
Thrown at utils/structs.go:263
}
len, err = (*inConn).Read(buf[:])
if err != nil {
if err != io.EOF {
err = fmt.Errorf("http decoder read err:%s", err)
}
CloseConn(inConn)
return
}
req.HeadBuf = buf[:len]
index := bytes.IndexByte(req.HeadBuf, '\n')
if index == -1 {
err = fmt.Errorf("http decoder data line err:%s", string(req.HeadBuf)[:50])
CloseConn(inConn)
return
}
fmt.Sscanf(string(req.HeadBuf[:index]), "%s%s", &req.Method, &req.hostOrURL)
if req.Method == "" || req.hostOrURL == "" {
err = fmt.Errorf("http decoder data err:%s", string(req.HeadBuf)[:50])
CloseConn(inConn)
return
}
req.Method = strings.ToUpper(req.Method)
req.isBasicAuth = isBasicAuth
req.basicAuth = basicAuth
log.Printf("%s:%s", req.Method, req.hostOrURL)
if req.IsHTTPS() {
err = req.HTTPS()
} else {
err = req.HTTP()
}
return
}
func (req *HTTPRequest) HTTP() (err error) {
if req.isBasicAuth {
err = req.BasicAuth()View on GitHub (pinned to e6d6a821db)
Solutions
- Look at the 50-byte payload in the error to identify the sender; port scanners and health checkers are common — filter them or point health checks at a dedicated plain endpoint.
- Verify the client sends a well-formed request line: METHOD SP request-target SP HTTP-version CRLF.
- If you control the client, test with `curl -x http://proxy:port http://example.com/` to confirm a valid request line reaches the proxy.
- Consider stricter parsing: parse with http.ReadRequest(bufio.NewReader(conn)) to get standards-compliant errors instead of Sscanf.
Example fix
// before
fmt.Sscanf(string(req.HeadBuf[:index]), "%s%s", &req.Method, &req.hostOrURL)
if req.Method == "" || req.hostOrURL == "" { ... }
// after
httpReq, perr := http.ReadRequest(bufio.NewReader(bytes.NewReader(req.HeadBuf)))
if perr != nil {
err = fmt.Errorf("http decoder data err:%s", perr)
return
}
req.Method, req.hostOrURL = httpReq.Method, httpReq.URL.String() Defensive patterns
Strategy: validation
Validate before calling
// validate the request line shape before invoking the proxy pipeline
line := string(bytes.TrimRight(reqLine, "\r\n"))
parts := strings.Fields(line)
if len(parts) != 3 || !isKnownMethod(parts[0]) {
return fmt.Errorf("malformed request line %q", line)
}
// then call utils.NewHTTPRequest(...) Type guard
func isKnownMethod(m string) bool {
switch strings.ToUpper(m) {
case "GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH", "CONNECT", "TRACE":
return true
}
return false
} Try / catch
_, err := utils.NewHTTPRequest(conn, bufSize, isAuth, auth)
if err != nil {
var opErr *net.OpError
if strings.HasPrefix(err.Error(), "http decoder data err") {
log.Printf("unparseable request line from %s: %v", conn.RemoteAddr(), err)
}
_ = opErr
} Prevention
- Send health-check probes to a dedicated endpoint, not the proxy port.
- Ensure custom clients emit a full request line: METHOD SP target SP HTTP/1.1 CRLF.
- Test clients with `curl -x http://proxy:port http://example.com/` as the baseline.
- Consider stdlib http.ReadRequest for standards-compliant rejection messages.
When it happens
Trigger: Calling NewHTTPRequest when the request line has a method but no target (e.g. "GET\r\n"), an empty first line followed by headers only, or malformed request lines from non-HTTP clients that nevertheless contain a newline.
Common situations: Health checks or port scanners sending bare CRLFs or partial payloads; custom scripts sending incomplete HTTP; HTTP/2 preface ("PRI * HTTP/2.0" would actually parse, but binary-prefixed data may not); proxies in front sending garbled request lines.
Related errors
- http decoder data line err:%s
- http decoder read err:%s
- authorization data error,ERR:%s
- authorization data parse error,ERR:%s
- can not find HOST header
AI-assisted analysis of snail007/goproxy@e6d6a821db (2026-09-03).
Data as JSON: /api/errors/eadc69c51f7feb94.
Report an issue: GitHub.