Skip to content

Commit 1d3469f

Browse files
Fized graceful shutdown, better pretty print for copied bytes
1 parent da31d1b commit 1d3469f

File tree

3 files changed

+63
-53
lines changed

3 files changed

+63
-53
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ You can download the binary for your platform from [Releases](https://github.com
9797
Example:
9898

9999
```shell
100-
HPTS_RELEASE=v1.8.1; wget -v https://github.com/shadowy-pycoder/go-http-proxy-to-socks/releases/download/$HPTS_RELEASE/gohpts-$HPTS_RELEASE-linux-amd64.tar.gz -O gohpts && tar xvzf gohpts && mv -f gohpts-$HPTS_RELEASE-linux-amd64 gohpts && ./gohpts -h
100+
HPTS_RELEASE=v1.8.2; wget -v https://github.com/shadowy-pycoder/go-http-proxy-to-socks/releases/download/$HPTS_RELEASE/gohpts-$HPTS_RELEASE-linux-amd64.tar.gz -O gohpts && tar xvzf gohpts && mv -f gohpts-$HPTS_RELEASE-linux-amd64 gohpts && ./gohpts -h
101101
```
102102

103103
Alternatively, you can install it using `go install` command (requires Go [1.24](https://go.dev/doc/install) or later):

gohpts.go

Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ const (
4444
hopTimeout time.Duration = 3 * time.Second
4545
flushTimeout time.Duration = 10 * time.Millisecond
4646
availProxyUpdateInterval time.Duration = 30 * time.Second
47-
kbSize int64 = 1000
4847
rrIndexMax uint32 = 1_000_000
4948
maxBodySize int64 = 2 << 15
5049
)
@@ -120,6 +119,7 @@ type proxyapp struct {
120119
nocolor bool
121120
body bool
122121
json bool
122+
closeConn chan bool
123123

124124
mu sync.RWMutex
125125
availProxyList []proxyEntry
@@ -459,6 +459,18 @@ func (p *proxyapp) colorizeTunnel(req, resp layers.Layer, sniffheader *[]string,
459459
return nil
460460
}
461461

462+
// https://stackoverflow.com/a/1094933/1333724
463+
func prettifyBytes(b int64) string {
464+
bf := float64(b)
465+
for _, unit := range []string{"", "K", "M", "G", "T", "P", "E", "Z"} {
466+
if bf < 1000.0 {
467+
return fmt.Sprintf("%3.1f%sB", bf, unit)
468+
}
469+
bf /= 1000.0
470+
}
471+
return fmt.Sprintf("%.1fYB", bf)
472+
}
473+
462474
func copyHeader(dst, src http.Header) {
463475
for k, vv := range src {
464476
for _, v := range vv {
@@ -851,12 +863,7 @@ func (p *proxyapp) handleForward(w http.ResponseWriter, r *http.Request) {
851863
close(done)
852864
return
853865
}
854-
var written string
855-
if n < kbSize {
856-
written = fmt.Sprintf("%dB", n)
857-
} else {
858-
written = fmt.Sprintf("%dKB", n/kbSize)
859-
}
866+
written := prettifyBytes(n)
860867
if chunked {
861868
written = fmt.Sprintf("%s - chunked", written)
862869
}
@@ -1023,51 +1030,57 @@ func dispatch(data []byte) (layers.Layer, error) {
10231030

10241031
func (p *proxyapp) copyWithTimeout(dst net.Conn, src net.Conn, msgChan chan<- layers.Layer) (written int64, err error) {
10251032
buf := make([]byte, 32*1024)
1033+
readLoop:
10261034
for {
1027-
er := src.SetReadDeadline(time.Now().Add(readTimeout))
1028-
if er != nil {
1029-
err = er
1030-
break
1031-
}
1032-
nr, er := src.Read(buf)
1033-
if nr > 0 {
1034-
er := dst.SetWriteDeadline(time.Now().Add(writeTimeout))
1035+
select {
1036+
case <-p.closeConn:
1037+
break readLoop
1038+
default:
1039+
er := src.SetReadDeadline(time.Now().Add(readTimeout))
10351040
if er != nil {
10361041
err = er
1037-
break
1042+
break readLoop
10381043
}
1039-
if p.sniff {
1040-
l, err := dispatch(buf[0:nr])
1041-
if err == nil {
1042-
msgChan <- l
1044+
nr, er := src.Read(buf)
1045+
if nr > 0 {
1046+
er := dst.SetWriteDeadline(time.Now().Add(writeTimeout))
1047+
if er != nil {
1048+
err = er
1049+
break readLoop
10431050
}
1044-
}
1045-
nw, ew := dst.Write(buf[0:nr])
1046-
if nw < 0 || nr < nw {
1047-
nw = 0
1048-
if ew == nil {
1049-
ew = errInvalidWrite
1051+
if p.sniff {
1052+
l, err := dispatch(buf[0:nr])
1053+
if err == nil {
1054+
msgChan <- l
1055+
}
10501056
}
1051-
}
1052-
written += int64(nw)
1053-
if ew != nil {
1054-
if ne, ok := ew.(net.Error); ok && ne.Timeout() {
1055-
err = ne
1056-
break
1057+
nw, ew := dst.Write(buf[0:nr])
1058+
if nw < 0 || nr < nw {
1059+
nw = 0
1060+
if ew == nil {
1061+
ew = errInvalidWrite
1062+
}
1063+
}
1064+
written += int64(nw)
1065+
if ew != nil {
1066+
if ne, ok := ew.(net.Error); ok && ne.Timeout() {
1067+
err = ne
1068+
break readLoop
1069+
}
1070+
}
1071+
if nr != nw {
1072+
err = io.ErrShortWrite
1073+
break readLoop
10571074
}
10581075
}
1059-
if nr != nw {
1060-
err = io.ErrShortWrite
1061-
break
1062-
}
1063-
}
1064-
if er != nil {
1065-
if ne, ok := err.(net.Error); ok && ne.Timeout() {
1066-
err = er
1067-
break
1068-
}
1069-
if er == io.EOF {
1070-
break
1076+
if er != nil {
1077+
if ne, ok := err.(net.Error); ok && ne.Timeout() {
1078+
err = er
1079+
break readLoop
1080+
}
1081+
if er == io.EOF {
1082+
break readLoop
1083+
}
10711084
}
10721085
}
10731086
}
@@ -1083,13 +1096,7 @@ func (p *proxyapp) transfer(wg *sync.WaitGroup, dst net.Conn, src net.Conn, dest
10831096
if err != nil {
10841097
p.logger.Error().Err(err).Msgf("Error during copy from %s to %s: %v", srcName, destName, err)
10851098
}
1086-
var written string
1087-
if n < kbSize {
1088-
written = fmt.Sprintf("%dB", n)
1089-
} else {
1090-
written = fmt.Sprintf("%dKB", n/kbSize)
1091-
}
1092-
p.logger.Debug().Msgf("copied %s from %s to %s", written, srcName, destName)
1099+
p.logger.Debug().Msgf("copied %s from %s to %s", prettifyBytes(n), srcName, destName)
10931100
}
10941101

10951102
func parseProxyAuth(auth string) (username, password string, ok bool) {
@@ -1242,6 +1249,7 @@ func (p *proxyapp) clearRedirectRules(output string) error {
12421249
func (p *proxyapp) Run() {
12431250
done := make(chan bool)
12441251
quit := make(chan os.Signal, 1)
1252+
p.closeConn = make(chan bool)
12451253
signal.Notify(quit, os.Interrupt)
12461254
var tproxyServer *tproxyServer
12471255
if p.tproxyAddr != "" {
@@ -1276,6 +1284,7 @@ func (p *proxyapp) Run() {
12761284
p.logger.Error().Err(err).Msg("Failed clearing iptables rules")
12771285
}
12781286
}
1287+
close(p.closeConn)
12791288
if tproxyServer != nil {
12801289
p.logger.Info().Msg("[tproxy] Server is shutting down...")
12811290
tproxyServer.Shutdown()
@@ -1317,6 +1326,7 @@ func (p *proxyapp) Run() {
13171326
p.logger.Error().Err(err).Msg("Failed clearing iptables rules")
13181327
}
13191328
}
1329+
close(p.closeConn)
13201330
p.logger.Info().Msg("[tproxy] Server is shutting down...")
13211331
tproxyServer.Shutdown()
13221332
close(done)

version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
package gohpts
22

3-
const Version string = "gohpts v1.8.1"
3+
const Version string = "gohpts v1.8.2"

0 commit comments

Comments
 (0)