Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>

This commit is contained in:
arraykeys@gmail.com
2017-10-19 14:56:40 +08:00
parent e28d5449b5
commit 3020dc5c94
12 changed files with 135 additions and 35 deletions

View File

@ -1,6 +1,9 @@
proxy更新日志 proxy更新日志
v3.3 v3.3
1.修复了socks代理模式对证书文件的判断逻辑. 1.修复了socks代理模式对证书文件的判断逻辑.
2.增强了http代理,socks代理的ssh中转模式的稳定性.
3.socks代理tls,tcp模式新增了CMD_ASSOCIATE(udp)支持.socks代理ssh模式不支持udp.
4.修复了http代理某些情况下会崩溃的bug.
v3.2 v3.2
1.内网穿透功能server端-r参数增加了协议和key设置. 1.内网穿透功能server端-r参数增加了协议和key设置.

View File

@ -423,7 +423,9 @@ server连接到bridge的时候,如果同时有多个client连接到同一个brid
`./proxy help socks` `./proxy help socks`
### TODO ### TODO
- SOCKS5增加用户名密码认证 - SOCKS5增加用户名密码认证?
- http,socks代理多个上级负载均衡?
- 欢迎加群反馈...
### 如何使用源码? ### 如何使用源码?
cd进入你的go src目录,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可. cd进入你的go src目录,然后git clone https://github.com/snail007/goproxy.git ./proxy 即可.

View File

@ -35,7 +35,7 @@ func initConfig() (err error) {
//build srvice args //build srvice args
app = kingpin.New("proxy", "happy with proxy") app = kingpin.New("proxy", "happy with proxy")
app.Author("snail").Version(APP_VERSION) app.Author("snail").Version(APP_VERSION)
debug := app.Flag("debug", "debug log output").Default("false").Bool()
//########http######### //########http#########
http := app.Command("http", "proxy on http mode") http := app.Command("http", "proxy on http mode")
httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String() httpArgs.Parent = http.Flag("parent", "parent address, such as: \"23.32.32.19:28008\"").Default("").Short('P').String()
@ -126,7 +126,13 @@ func initConfig() (err error) {
socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String() socksArgs.Direct = socks.Flag("direct", "direct domain file , one domain each line").Default("direct").Short('d').String()
//parse args //parse args
serviceName := kingpin.MustParse(app.Parse(os.Args[1:])) serviceName := kingpin.MustParse(app.Parse(os.Args[1:]))
flags := log.Ldate
if *debug {
flags |= log.Lshortfile | log.Lmicroseconds
} else {
flags |= log.Ltime
}
log.SetFlags(flags)
poster() poster()
//regist services and run service //regist services and run service
services.Regist("http", services.NewHTTP(), httpArgs) services.Regist("http", services.NewHTTP(), httpArgs)

View File

@ -6,7 +6,7 @@ fi
mkdir /tmp/proxy mkdir /tmp/proxy
cd /tmp/proxy cd /tmp/proxy
wget https://github.com/reddec/monexec/releases/download/v0.1.1/monexec_0.1.1_linux_amd64.tar.gz wget https://github.com/reddec/monexec/releases/download/v0.1.1/monexec_0.1.1_linux_amd64.tar.gz
wget https://github.com/snail007/goproxy/releases/download/v3.2/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v3.3/proxy-linux-amd64.tar.gz
# install monexec # install monexec
tar zxvf monexec_0.1.1_linux_amd64.tar.gz tar zxvf monexec_0.1.1_linux_amd64.tar.gz

View File

@ -9,7 +9,7 @@ import (
"syscall" "syscall"
) )
const APP_VERSION = "3.2" const APP_VERSION = "3.3"
func main() { func main() {
err := initConfig() err := initConfig()

View File

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
VER="3.2" VER="3.3"
RELEASE="release-${VER}" RELEASE="release-${VER}"
rm -rf .cert rm -rf .cert
mkdir .cert mkdir .cert

View File

@ -20,6 +20,7 @@ type HTTP struct {
checker utils.Checker checker utils.Checker
basicAuth utils.BasicAuth basicAuth utils.BasicAuth
sshClient *ssh.Client sshClient *ssh.Client
lockChn chan bool
} }
func NewHTTP() Service { func NewHTTP() Service {
@ -28,6 +29,7 @@ func NewHTTP() Service {
cfg: HTTPArgs{}, cfg: HTTPArgs{},
checker: utils.Checker{}, checker: utils.Checker{},
basicAuth: utils.BasicAuth{}, basicAuth: utils.BasicAuth{},
lockChn: make(chan bool, 1),
} }
} }
func (s *HTTP) CheckArgs() { func (s *HTTP) CheckArgs() {
@ -115,7 +117,9 @@ func (s *HTTP) callback(inConn net.Conn) {
log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack())) log.Printf("http(s) conn handler crashed with err : %s \nstack: %s", err, string(debug.Stack()))
} }
}() }()
req, err := utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth) var err interface{}
var req utils.HTTPRequest
req, err = utils.NewHTTPRequest(&inConn, 4096, s.IsBasicAuth(), &s.basicAuth)
if err != nil { if err != nil {
if err != io.EOF { if err != io.EOF {
log.Printf("decoder error , form %s, ERR:%s", err, inConn.RemoteAddr()) log.Printf("decoder error , form %s, ERR:%s", err, inConn.RemoteAddr())
@ -153,7 +157,7 @@ func (s *HTTP) callback(inConn net.Conn) {
utils.CloseConn(&inConn) utils.CloseConn(&inConn)
} }
} }
func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *utils.HTTPRequest) (err error) { func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *utils.HTTPRequest) (err interface{}) {
inAddr := (*inConn).RemoteAddr().String() inAddr := (*inConn).RemoteAddr().String()
inLocalAddr := (*inConn).LocalAddr().String() inLocalAddr := (*inConn).LocalAddr().String()
//防止死循环 //防止死循环
@ -208,18 +212,27 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
return return
} }
func (s *HTTP) getSSHConn(host string) (outConn net.Conn, err error) { func (s *HTTP) getSSHConn(host string) (outConn net.Conn, err interface{}) {
maxTryCount := 1 maxTryCount := 1
tryCount := 0 tryCount := 0
errchn := make(chan interface{}, 1)
RETRY: RETRY:
if tryCount >= maxTryCount { if tryCount >= maxTryCount {
return return
} }
go func() {
defer func() {
if err == nil {
errchn <- recover()
} else {
errchn <- nil
}
}()
outConn, err = s.sshClient.Dial("tcp", host) outConn, err = s.sshClient.Dial("tcp", host)
//log.Printf("s.sshClient.Dial, host:%s)", host) }()
err = <-errchn
if err != nil { if err != nil {
log.Printf("connect ssh fail, ERR: %s, retrying...", err) log.Printf("connect ssh fail, ERR: %s, retrying...", err)
s.sshClient.Close()
e := s.ConnectSSH() e := s.ConnectSSH()
if e == nil { if e == nil {
tryCount++ tryCount++
@ -232,14 +245,25 @@ RETRY:
return return
} }
func (s *HTTP) ConnectSSH() (err error) { func (s *HTTP) ConnectSSH() (err error) {
select {
case s.lockChn <- true:
default:
err = fmt.Errorf("can not connect at same time")
return
}
config := ssh.ClientConfig{ config := ssh.ClientConfig{
Timeout: time.Duration(*s.cfg.Timeout) * time.Millisecond,
User: *s.cfg.SSHUser, User: *s.cfg.SSHUser,
Auth: []ssh.AuthMethod{s.cfg.SSHAuthMethod}, Auth: []ssh.AuthMethod{s.cfg.SSHAuthMethod},
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
return nil return nil
}, },
} }
if s.sshClient != nil {
s.sshClient.Close()
}
s.sshClient, err = ssh.Dial("tcp", *s.cfg.Parent, &config) s.sshClient, err = ssh.Dial("tcp", *s.cfg.Parent, &config)
<-s.lockChn
return return
} }
func (s *HTTP) InitOutConnPool() { func (s *HTTP) InitOutConnPool() {

View File

@ -37,7 +37,7 @@ func NewSocks() Service {
func (s *Socks) CheckArgs() { func (s *Socks) CheckArgs() {
var err error var err error
if *s.cfg.LocalType == "tls" { if *s.cfg.LocalType == "tls" {
log.Println(*s.cfg.CertFile, *s.cfg.KeyFile) //log.Println(*s.cfg.CertFile, *s.cfg.KeyFile)
s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile) s.cfg.CertBytes, s.cfg.KeyBytes = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
} }
if *s.cfg.Parent != "" { if *s.cfg.Parent != "" {
@ -55,7 +55,6 @@ func (s *Socks) CheckArgs() {
if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" { if *s.cfg.SSHKeyFile == "" && *s.cfg.SSHPassword == "" {
log.Fatalf("ssh password or key required") log.Fatalf("ssh password or key required")
} }
if *s.cfg.SSHPassword != "" { if *s.cfg.SSHPassword != "" {
s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword) s.cfg.SSHAuthMethod = ssh.Password(*s.cfg.SSHPassword)
} else { } else {
@ -85,6 +84,25 @@ func (s *Socks) InitService() {
if err != nil { if err != nil {
log.Fatalf("init service fail, ERR: %s", err) log.Fatalf("init service fail, ERR: %s", err)
} }
go func() {
//循环检查ssh网络连通性
for {
conn, err := utils.ConnectHost(*s.cfg.Parent, *s.cfg.Timeout*2)
if err != nil {
if s.sshClient != nil {
s.sshClient.Close()
if s.sshClient.Conn != nil {
s.sshClient.Conn.Close()
}
}
log.Printf("ssh offline, retrying...")
s.ConnectSSH()
} else {
conn.Close()
}
time.Sleep(time.Second * 3)
}
}()
} }
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
log.Println("warn: socks udp not suppored for ssh") log.Println("warn: socks udp not suppored for ssh")
@ -133,17 +151,17 @@ func (s *Socks) UDPKey() []byte {
return s.cfg.KeyBytes[:32] return s.cfg.KeyBytes[:32]
} }
func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) { func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
newB := b rawB := b
var err error var err error
if *s.cfg.LocalType == "tls" { if *s.cfg.LocalType == "tls" {
//decode b //decode b
newB, err = goaes.Decrypt(s.UDPKey(), b) rawB, err = goaes.Decrypt(s.UDPKey(), b)
if err != nil { if err != nil {
log.Printf("decrypt udp packet fail from %s", srcAddr.String()) log.Printf("decrypt udp packet fail from %s", srcAddr.String())
return return
} }
} }
p, err := socks.ParseUDPPacket(newB) p, err := socks.ParseUDPPacket(rawB)
log.Printf("udp revecived:%v", len(p.Data())) log.Printf("udp revecived:%v", len(p.Data()))
if err != nil { if err != nil {
log.Printf("parse udp packet fail, ERR:%s", err) log.Printf("parse udp packet fail, ERR:%s", err)
@ -154,7 +172,7 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
//有上级代理,转发给上级 //有上级代理,转发给上级
if *s.cfg.ParentType == "tls" { if *s.cfg.ParentType == "tls" {
//encode b //encode b
newB, err = goaes.Encrypt(s.UDPKey(), newB) rawB, err = goaes.Encrypt(s.UDPKey(), rawB)
if err != nil { if err != nil {
log.Printf("encrypt udp data fail to %s", *s.cfg.Parent) log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
return return
@ -172,18 +190,20 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
return return
} }
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*2))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*2)))
_, err = conn.Write(newB) _, err = conn.Write(rawB)
log.Printf("udp request:%v", len(newB)) log.Printf("udp request:%v", len(rawB))
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
conn.Close()
return return
} }
//log.Printf("send udp packet to %s success", dstAddr.String()) //log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 1024) buf := make([]byte, 10*1024)
length, _, err := conn.ReadFromUDP(buf) length, _, err := conn.ReadFromUDP(buf)
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
conn.Close()
return return
} }
respBody := buf[0:length] respBody := buf[0:length]
@ -194,6 +214,7 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
respBody, err = goaes.Decrypt(s.UDPKey(), respBody) respBody, err = goaes.Decrypt(s.UDPKey(), respBody)
if err != nil { if err != nil {
log.Printf("encrypt udp data fail to %s", *s.cfg.Parent) log.Printf("encrypt udp data fail to %s", *s.cfg.Parent)
conn.Close()
return return
} }
} }
@ -201,6 +222,7 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
d, err := goaes.Encrypt(s.UDPKey(), respBody) d, err := goaes.Encrypt(s.UDPKey(), respBody)
if err != nil { if err != nil {
log.Printf("encrypt udp data fail from %s", dstAddr.String()) log.Printf("encrypt udp data fail from %s", dstAddr.String())
conn.Close()
return return
} }
s.udpSC.UDPListener.WriteToUDP(d, srcAddr) s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
@ -223,33 +245,38 @@ func (s *Socks) udpCallback(b []byte, localAddr, srcAddr *net.UDPAddr) {
log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err) log.Printf("connect to udp %s fail,ERR:%s", dstAddr.String(), err)
return return
} }
conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*2))) conn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout*3)))
_, err = conn.Write(p.Data()) _, err = conn.Write(p.Data())
log.Printf("udp send:%v", len(p.Data())) log.Printf("udp send:%v", len(p.Data()))
if err != nil { if err != nil {
log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err) log.Printf("send udp packet to %s fail,ERR:%s", dstAddr.String(), err)
conn.Close()
return return
} }
log.Printf("send udp packet to %s success", dstAddr.String()) //log.Printf("send udp packet to %s success", dstAddr.String())
buf := make([]byte, 1024) buf := make([]byte, 10*1024)
length, _, err := conn.ReadFromUDP(buf) length, _, err := conn.ReadFromUDP(buf)
if err != nil { if err != nil {
log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err) log.Printf("read udp response from %s fail ,ERR:%s", dstAddr.String(), err)
conn.Close()
return return
} }
respBody := buf[0:length] respBody := buf[0:length]
//封装来自真实服务器的数据,返回给访问者
respPacket := p.NewReply(respBody)
//log.Printf("revecived udp packet from %s", dstAddr.String()) //log.Printf("revecived udp packet from %s", dstAddr.String())
if *s.cfg.LocalType == "tls" { if *s.cfg.LocalType == "tls" {
d, err := goaes.Encrypt(s.UDPKey(), respBody) d, err := goaes.Encrypt(s.UDPKey(), respPacket)
if err != nil { if err != nil {
log.Printf("encrypt udp data fail from %s", dstAddr.String()) log.Printf("encrypt udp data fail from %s", dstAddr.String())
conn.Close()
return return
} }
s.udpSC.UDPListener.WriteToUDP(d, srcAddr) s.udpSC.UDPListener.WriteToUDP(d, srcAddr)
} else { } else {
s.udpSC.UDPListener.WriteToUDP(respBody, srcAddr) s.udpSC.UDPListener.WriteToUDP(respPacket, srcAddr)
} }
log.Printf("udp reply:%v", len(respBody)) log.Printf("udp reply:%v", len(respPacket))
} }
} }
@ -304,18 +331,18 @@ func (s *Socks) socksConnCallback(inConn net.Conn) {
} }
func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { func (s *Socks) proxyUDP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
if *s.cfg.ParentType == "ssh" { if *s.cfg.ParentType == "ssh" {
utils.CloseConn(inConn)
return return
} }
host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String()) host, _, _ := net.SplitHostPort((*inConn).LocalAddr().String())
_, port, _ := net.SplitHostPort(s.udpSC.UDPListener.LocalAddr().String()) _, port, _ := net.SplitHostPort(s.udpSC.UDPListener.LocalAddr().String())
// log.Printf("proxy udp on %s", net.JoinHostPort(host, port)) // log.Printf("proxy udp on %s", net.JoinHostPort(host, port))
request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port)) request.UDPReply(socks.REP_SUCCESS, net.JoinHostPort(host, port))
// log.Printf("%v", request.NewReply(socks.REP_SUCCESS, net.JoinHostPort(host, port)))
} }
func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) { func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, request socks.Request) {
var outConn net.Conn var outConn net.Conn
defer utils.CloseConn(&outConn) defer utils.CloseConn(&outConn)
var err error var err interface{}
useProxy := true useProxy := true
if *s.cfg.Always { if *s.cfg.Always {
outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr()) outConn, err = s.getOutConn(methodReq.Bytes(), request.Bytes(), request.Addr())
@ -370,7 +397,8 @@ func (s *Socks) proxyTCP(inConn *net.Conn, methodReq socks.MethodsRequest, reque
utils.CloseConn(inConn) utils.CloseConn(inConn)
utils.CloseConn(&outConn) utils.CloseConn(&outConn)
} }
func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err error) { func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn net.Conn, err interface{}) {
errchn := make(chan interface{}, 1)
switch *s.cfg.ParentType { switch *s.cfg.ParentType {
case "tls": case "tls":
fallthrough fallthrough
@ -413,7 +441,17 @@ func (s *Socks) getOutConn(methodBytes, reqBytes []byte, host string) (outConn n
if tryCount >= maxTryCount { if tryCount >= maxTryCount {
return return
} }
go func() {
defer func() {
if err == nil {
errchn <- recover()
} else {
errchn <- nil
}
}()
outConn, err = s.sshClient.Dial("tcp", host) outConn, err = s.sshClient.Dial("tcp", host)
}()
err = <-errchn
if err != nil { if err != nil {
log.Printf("connect ssh fail, ERR: %s, retrying...", err) log.Printf("connect ssh fail, ERR: %s, retrying...", err)
e := s.ConnectSSH() e := s.ConnectSSH()

View File

@ -64,12 +64,15 @@ func (s *TunnelServerManager) Start(args interface{}) (err error) {
CertBytes: s.cfg.CertBytes, CertBytes: s.cfg.CertBytes,
KeyBytes: s.cfg.KeyBytes, KeyBytes: s.cfg.KeyBytes,
Parent: s.cfg.Parent, Parent: s.cfg.Parent,
CertFile: s.cfg.CertFile,
KeyFile: s.cfg.KeyFile,
Local: &local, Local: &local,
IsUDP: &IsUDP, IsUDP: &IsUDP,
Remote: &remote, Remote: &remote,
Key: &KEY, Key: &KEY,
Timeout: s.cfg.Timeout, Timeout: s.cfg.Timeout,
}) })
if err != nil { if err != nil {
return return
} }

View File

@ -315,6 +315,24 @@ func Uniqueid() string {
s := fmt.Sprintf("%d", src.Int63()) s := fmt.Sprintf("%d", src.Int63())
return s[len(s)-5:len(s)-1] + fmt.Sprintf("%d", uint64(time.Now().UnixNano()))[8:] return s[len(s)-5:len(s)-1] + fmt.Sprintf("%d", uint64(time.Now().UnixNano()))[8:]
} }
func SubStr(str string, start, end int) string {
if len(str) == 0 {
return ""
}
if end >= len(str) {
end = len(str) - 1
}
return str[start:end]
}
func SubBytes(bytes []byte, start, end int) []byte {
if len(bytes) == 0 {
return []byte{}
}
if end >= len(bytes) {
end = len(bytes) - 1
}
return bytes[start:end]
}
func TlsBytes(cert, key string) (certBytes, keyBytes []byte) { func TlsBytes(cert, key string) (certBytes, keyBytes []byte) {
certBytes, err := ioutil.ReadFile(cert) certBytes, err := ioutil.ReadFile(cert)
if err != nil { if err != nil {

View File

@ -242,6 +242,12 @@ func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
func (s *UDPPacket) Header() []byte { func (s *UDPPacket) Header() []byte {
return s.header return s.header
} }
func (s *UDPPacket) NewReply(data []byte) []byte {
var buf bytes.Buffer
buf.Write(s.header)
buf.Write(data)
return buf.Bytes()
}
func (s *UDPPacket) Host() string { func (s *UDPPacket) Host() string {
return s.dstHost return s.dstHost
} }

View File

@ -256,13 +256,13 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
req.HeadBuf = buf[:len] req.HeadBuf = buf[:len]
index := bytes.IndexByte(req.HeadBuf, '\n') index := bytes.IndexByte(req.HeadBuf, '\n')
if index == -1 { if index == -1 {
err = fmt.Errorf("http decoder data line err:%s", string(req.HeadBuf)[:50]) err = fmt.Errorf("http decoder data line err:%s", SubStr(string(req.HeadBuf), 0, 50))
CloseConn(inConn) CloseConn(inConn)
return return
} }
fmt.Sscanf(string(req.HeadBuf[:index]), "%s%s", &req.Method, &req.hostOrURL) fmt.Sscanf(string(req.HeadBuf[:index]), "%s%s", &req.Method, &req.hostOrURL)
if req.Method == "" || req.hostOrURL == "" { if req.Method == "" || req.hostOrURL == "" {
err = fmt.Errorf("http decoder data err:%s", string(req.HeadBuf)[:50]) err = fmt.Errorf("http decoder data err:%s", SubStr(string(req.HeadBuf), 0, 50))
CloseConn(inConn) CloseConn(inConn)
return return
} }