snail007/goproxy · error
http decoder data line err:%s
Error message
http decoder data line err:%s
What it means
After reading the request head, NewHTTPRequest looks for the first newline ('\n') to delimit the HTTP request line. If no newline exists in the received bytes, it throws "http decoder data line err:%s" with the first 50 bytes of the buffer, closes the connection, and returns. This means the data received does not look like an HTTP request head at all.
Source
Thrown at utils/structs.go:257
func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *BasicAuth) (req HTTPRequest, err error) {
buf := make([]byte, bufSize)
len := 0
req = HTTPRequest{
conn: inConn,
}
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()View on GitHub (pinned to e6d6a821db)
Solutions
- Check the client proxy configuration: a plain-HTTP proxy port must receive plain HTTP; remove https:// from the proxy URL if the proxy is not TLS-enabled (use http:// for http_proxy/https_proxy unless the proxy itself speaks TLS).
- Inspect the 50-byte hexdump in the error: bytes starting 0x16 0x03 indicate a TLS ClientHello hitting a plain port — reconfigure the client or wrap the proxy in TLS.
- If requests are merely fragmented, this simple single-Read parser is the limitation; buffer with a bufio.Reader and read until \r\n\r\n instead of one Read() call.
- Ensure the client actually sends a complete request line terminated by CRLF (check for custom clients or modified HTTP stacks).
Example fix
// before
len, err = (*inConn).Read(buf[:])
...
index := bytes.IndexByte(req.HeadBuf, '\n')
// after
reader := bufio.NewReader(*inConn)
headBuf, err := reader.ReadBytes('\n') // accumulates until line end
if err != nil { ... }
req.HeadBuf = headBuf Defensive patterns
Strategy: validation
Validate before calling
func looksLikeHTTP(firstBytes []byte) bool {
methods := []string{"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH", "CONNECT", "TRACE"}
s := string(firstBytes)
for _, m := range methods {
if strings.HasPrefix(s, m+" ") {
return true
}
}
return false
}
// call before proxying: if the sniffed bytes start with 0x16 0x03, the client
// is speaking TLS to a plain port — reject with a clear message instead. Type guard
func isTLSClientHello(b []byte) bool {
return len(b) >= 3 && b[0] == 0x16 && b[1] == 0x03
} Try / catch
_, err := utils.NewHTTPRequest(conn, bufSize, isAuth, auth)
if err != nil && strings.HasPrefix(err.Error(), "http decoder data line err") {
log.Printf("non-HTTP data on proxy port (TLS to plain port?): %.20s", err.Error())
} Prevention
- Use http:// (not https://) in http_proxy/https_proxy env vars unless the proxy itself terminates TLS.
- Sniff the first bytes on accept and reject TLS handshakes with a clear log message.
- Point port scanners/health checks away from the proxy port or expect this error from them.
- Prefer a buffered read-until-CRLF parser over a single Read() if clients may fragment requests.
When it happens
Trigger: Calling NewHTTPRequest when the client sends a partial request line without CRLF, sends raw TLS handshake bytes (\x16\x03...) to a plaintext HTTP proxy port, sends binary/garbage data, or the read returns only part of the first line in one packet.
Common situations: Client configured to use HTTPS on the proxy port of a plain-HTTP proxy (https_proxy pointing at a non-TLS proxy); tools like curl with `-k` sending TLS to the wrong port; a client that crashed mid-write; non-HTTP protocols pointed at the proxy.
Related errors
- http decoder data 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/83a05650353533c3.
Report an issue: GitHub.