{"record":{"id":"eadc69c51f7feb94","repo":"snail007/goproxy","slug":"http-decoder-data-err-s","errorCode":null,"errorMessage":"http decoder data err:%s","messagePattern":"http decoder data err:(.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"utils/structs.go","lineNumber":263,"sourceCode":"\t}\n\tlen, err = (*inConn).Read(buf[:])\n\tif err != nil {\n\t\tif err != io.EOF {\n\t\t\terr = fmt.Errorf(\"http decoder read err:%s\", err)\n\t\t}\n\t\tCloseConn(inConn)\n\t\treturn\n\t}\n\treq.HeadBuf = buf[:len]\n\tindex := bytes.IndexByte(req.HeadBuf, '\\n')\n\tif index == -1 {\n\t\terr = fmt.Errorf(\"http decoder data line err:%s\", string(req.HeadBuf)[:50])\n\t\tCloseConn(inConn)\n\t\treturn\n\t}\n\tfmt.Sscanf(string(req.HeadBuf[:index]), \"%s%s\", &req.Method, &req.hostOrURL)\n\tif req.Method == \"\" || req.hostOrURL == \"\" {\n\t\terr = fmt.Errorf(\"http decoder data err:%s\", string(req.HeadBuf)[:50])\n\t\tCloseConn(inConn)\n\t\treturn\n\t}\n\treq.Method = strings.ToUpper(req.Method)\n\treq.isBasicAuth = isBasicAuth\n\treq.basicAuth = basicAuth\n\tlog.Printf(\"%s:%s\", req.Method, req.hostOrURL)\n\n\tif req.IsHTTPS() {\n\t\terr = req.HTTPS()\n\t} else {\n\t\terr = req.HTTP()\n\t}\n\treturn\n}\nfunc (req *HTTPRequest) HTTP() (err error) {\n\tif req.isBasicAuth {\n\t\terr = req.BasicAuth()","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/snail007/goproxy/blob/e6d6a821db80e7f47ee6e981a144984e1d4ddb3d/utils/structs.go#L245-L281","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nfmt.Sscanf(string(req.HeadBuf[:index]), \"%s%s\", &req.Method, &req.hostOrURL)\nif req.Method == \"\" || req.hostOrURL == \"\" { ... }\n\n// after\nhttpReq, perr := http.ReadRequest(bufio.NewReader(bytes.NewReader(req.HeadBuf)))\nif perr != nil {\n\terr = fmt.Errorf(\"http decoder data err:%s\", perr)\n\treturn\n}\nreq.Method, req.hostOrURL = httpReq.Method, httpReq.URL.String()","handlingStrategy":"validation","validationCode":"// validate the request line shape before invoking the proxy pipeline\nline := string(bytes.TrimRight(reqLine, \"\\r\\n\"))\nparts := strings.Fields(line)\nif len(parts) != 3 || !isKnownMethod(parts[0]) {\n\treturn fmt.Errorf(\"malformed request line %q\", line)\n}\n// then call utils.NewHTTPRequest(...)","typeGuard":"func isKnownMethod(m string) bool {\n\tswitch strings.ToUpper(m) {\n\tcase \"GET\", \"POST\", \"PUT\", \"DELETE\", \"HEAD\", \"OPTIONS\", \"PATCH\", \"CONNECT\", \"TRACE\":\n\t\treturn true\n\t}\n\treturn false\n}","tryCatchPattern":"_, err := utils.NewHTTPRequest(conn, bufSize, isAuth, auth)\nif err != nil {\n\tvar opErr *net.OpError\n\tif strings.HasPrefix(err.Error(), \"http decoder data err\") {\n\t\tlog.Printf(\"unparseable request line from %s: %v\", conn.RemoteAddr(), err)\n\t}\n\t_ = opErr\n}","preventionTips":["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."],"tags":["http","parsing","malformed-request","go"],"backgroundTag":"invalid-http-request","analyzedSha":"e6d6a821db80e7f47ee6e981a144984e1d4ddb3d","analyzedAt":"2026-09-03T15:32:42.750Z","contentChangedAt":"2026-09-03T15:32:42.750Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}