From 1375833447092fe78c09e79ab5e9eb93f47c2eae Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Sun, 1 Jun 2025 09:04:05 +0300 Subject: [PATCH 01/10] Added removal of connection headers, small improvements --- gohpts.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/gohpts.go b/gohpts.go index b6c2173..dadf8eb 100644 --- a/gohpts.go +++ b/gohpts.go @@ -1,6 +1,7 @@ package gohpts import ( + "crypto/tls" "fmt" "io" "net" @@ -42,6 +43,18 @@ func delHopHeaders(header http.Header) { } } +// delConnectionHeaders removes hop-by-hop headers listed in the "Connection" header +// https://datatracker.ietf.org/doc/html/rfc7230#section-6.1 +func delConnectionHeaders(h http.Header) { + for _, f := range h["Connection"] { + for _, sf := range strings.Split(f, ",") { + if sf = strings.TrimSpace(sf); sf != "" { + h.Del(sf) + } + } + } +} + func appendHostToXForwardHeader(header http.Header, host string) { if prior, ok := header["X-Forwarded-For"]; ok { host = strings.Join(prior, ", ") + ", " + host @@ -78,6 +91,8 @@ func (app *app) handleForward(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) return } + req.RequestURI = "" + delConnectionHeaders(r.Header) delHopHeaders(r.Header) copyHeader(req.Header, r.Header) if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { @@ -111,6 +126,7 @@ func (app *app) handleForward(w http.ResponseWriter, r *http.Request) { } defer resp.Body.Close() + delConnectionHeaders(resp.Header) delHopHeaders(resp.Header) copyHeader(w.Header(), resp.Header) w.WriteHeader(resp.StatusCode) @@ -254,6 +270,9 @@ func New(conf *Config) *app { MaxHeaderBytes: 1 << 20, } hc := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }, CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, From 38d61a521feaa45cc44c2b589ac77b8958223ab2 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Sun, 1 Jun 2025 09:36:45 +0300 Subject: [PATCH 02/10] Moved timeouts to constants --- gohpts.go | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/gohpts.go b/gohpts.go index dadf8eb..06789ec 100644 --- a/gohpts.go +++ b/gohpts.go @@ -15,6 +15,13 @@ import ( "golang.org/x/net/proxy" ) +const ( + readTimeout time.Duration = 10 * time.Second + writeTimeout time.Duration = 10 * time.Second + timeout time.Duration = 10 * time.Second + kbSize int64 = 1000 +) + // Hop-by-hop headers // https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1 var hopHeaders = []string{ @@ -137,10 +144,10 @@ func (app *app) handleForward(w http.ResponseWriter, r *http.Request) { return } var written string - if n < 1000 { + if n < kbSize { written = fmt.Sprintf("%dB", n) } else { - written = fmt.Sprintf("%dKB", n/1000) + written = fmt.Sprintf("%dKB", n/kbSize) } app.logger.Debug().Msgf("%s - %s - %s - %d - %s", r.Proto, r.Method, r.Host, resp.StatusCode, written) } @@ -149,7 +156,7 @@ func (app *app) handleTunnel(w http.ResponseWriter, r *http.Request) { var dstConn net.Conn var err error if isLocalAddress(r.Host) { - dstConn, err = net.DialTimeout("tcp", r.Host, 10*time.Second) + dstConn, err = net.DialTimeout("tcp", r.Host, timeout) if err != nil { http.Error(w, err.Error(), http.StatusServiceUnavailable) return @@ -196,10 +203,10 @@ func (app *app) transfer(wg *sync.WaitGroup, destination io.Writer, source io.Re app.logger.Error().Err(err).Msgf("Error during copy from %s to %s: %v", srcName, destName, err) } var written string - if n < 1000 { + if n < kbSize { written = fmt.Sprintf("%dB", n) } else { - written = fmt.Sprintf("%dKB", n/1000) + written = fmt.Sprintf("%dKB", n/kbSize) } app.logger.Debug().Msgf("copied %s from %s to %s", written, srcName, destName) } @@ -250,9 +257,9 @@ func New(conf *Config) *app { User: conf.User, Password: conf.Pass, } - dialer, err := proxy.SOCKS5("tcp", conf.AddrSOCKS, &auth, nil) + dialer, err := proxy.SOCKS5("tcp", conf.AddrSOCKS, &auth, &net.Dialer{Timeout: timeout}) if err != nil { - logger.Fatal().Err(err).Msg("Unable to create SOCKS5 client") + logger.Fatal().Err(err).Msg("Unable to create SOCKS5 dialer") } socks := &http.Client{ Transport: &http.Transport{ @@ -261,12 +268,12 @@ func New(conf *Config) *app { CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, - Timeout: 10 * time.Second, + Timeout: timeout, } hs := &http.Server{ Addr: conf.AddrHTTP, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, + ReadTimeout: readTimeout, + WriteTimeout: writeTimeout, MaxHeaderBytes: 1 << 20, } hc := &http.Client{ @@ -276,7 +283,7 @@ func New(conf *Config) *app { CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, - Timeout: 10 * time.Second, + Timeout: timeout, } logger.Info().Msgf("SOCKS5 Proxy: %s", conf.AddrSOCKS) logger.Info().Msgf("HTTP Proxy: %s", conf.AddrHTTP) From a0cc10934875fb34cfc5afce0a95cb180d2634d4 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Sun, 1 Jun 2025 10:45:39 +0300 Subject: [PATCH 03/10] Bumped to v1.3.1 --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index a8a116b..44741b5 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package gohpts -const Version string = "gohpts v1.3.0" +const Version string = "gohpts v1.3.1" From 9387a10233eb4faea219375e16a52f5a714a0b76 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Sun, 1 Jun 2025 16:13:03 +0300 Subject: [PATCH 04/10] Refactoring: changed variables names --- cmd/gohpts/cli.go | 4 +-- gohpts.go | 71 ++++++++++++++++++++++++----------------------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/cmd/gohpts/cli.go b/cmd/gohpts/cli.go index fc5ace1..9c76ba9 100644 --- a/cmd/gohpts/cli.go +++ b/cmd/gohpts/cli.go @@ -85,7 +85,7 @@ func root(args []string) error { if err := flags.Parse(args); err != nil { return err } - app := gohpts.New(&conf) - app.Run() + p := gohpts.New(&conf) + p.Run() return nil } diff --git a/gohpts.go b/gohpts.go index 06789ec..e845452 100644 --- a/gohpts.go +++ b/gohpts.go @@ -82,19 +82,19 @@ func isLocalAddress(addr string) bool { return strings.HasSuffix(host, ".local") || host == "localhost" } -type app struct { - hs *http.Server - sc *http.Client - hc *http.Client - dialer proxy.Dialer - logger *zerolog.Logger +type proxyApp struct { + httpServer *http.Server + sockServer *http.Client + httpClient *http.Client + sockDialer proxy.Dialer + logger *zerolog.Logger } -func (app *app) handleForward(w http.ResponseWriter, r *http.Request) { +func (p *proxyApp) handleForward(w http.ResponseWriter, r *http.Request) { req, err := http.NewRequest(r.Method, r.URL.String(), r.Body) if err != nil { - app.logger.Error().Err(err).Msgf("Error during NewRequest() %s: %s", r.URL.String(), err) + p.logger.Error().Err(err).Msgf("Error during NewRequest() %s: %s", r.URL.String(), err) w.WriteHeader(http.StatusInternalServerError) return } @@ -107,26 +107,26 @@ func (app *app) handleForward(w http.ResponseWriter, r *http.Request) { } var resp *http.Response if isLocalAddress(r.Host) { - resp, err = app.hc.Do(req) + resp, err = p.httpClient.Do(req) if err != nil { - app.logger.Error().Err(err).Msg("Connection failed") + p.logger.Error().Err(err).Msg("Connection failed") w.WriteHeader(http.StatusServiceUnavailable) return } if resp == nil { - app.logger.Error().Err(err).Msg("Connection failed") + p.logger.Error().Err(err).Msg("Connection failed") w.WriteHeader(http.StatusServiceUnavailable) return } } else { - resp, err = app.sc.Do(req) + resp, err = p.sockServer.Do(req) if err != nil { - app.logger.Error().Err(err).Msg("Connection to SOCKS5 server failed") + p.logger.Error().Err(err).Msg("Connection to SOCKS5 server failed") w.WriteHeader(http.StatusServiceUnavailable) return } if resp == nil { - app.logger.Error().Err(err).Msg("Connection to SOCKS5 server failed") + p.logger.Error().Err(err).Msg("Connection to SOCKS5 server failed") w.WriteHeader(http.StatusServiceUnavailable) return } @@ -139,7 +139,7 @@ func (app *app) handleForward(w http.ResponseWriter, r *http.Request) { w.WriteHeader(resp.StatusCode) n, err := io.Copy(w, resp.Body) if err != nil { - app.logger.Error().Err(err).Msgf("Error during Copy() %s: %s", r.URL.String(), err) + p.logger.Error().Err(err).Msgf("Error during Copy() %s: %s", r.URL.String(), err) w.WriteHeader(http.StatusInternalServerError) return } @@ -149,10 +149,10 @@ func (app *app) handleForward(w http.ResponseWriter, r *http.Request) { } else { written = fmt.Sprintf("%dKB", n/kbSize) } - app.logger.Debug().Msgf("%s - %s - %s - %d - %s", r.Proto, r.Method, r.Host, resp.StatusCode, written) + p.logger.Debug().Msgf("%s - %s - %s - %d - %s", r.Proto, r.Method, r.Host, resp.StatusCode, written) } -func (app *app) handleTunnel(w http.ResponseWriter, r *http.Request) { +func (p *proxyApp) handleTunnel(w http.ResponseWriter, r *http.Request) { var dstConn net.Conn var err error if isLocalAddress(r.Host) { @@ -162,7 +162,7 @@ func (app *app) handleTunnel(w http.ResponseWriter, r *http.Request) { return } } else { - dstConn, err = app.dialer.Dial("tcp", r.Host) + dstConn, err = p.sockDialer.Dial("tcp", r.Host) if err != nil { http.Error(w, err.Error(), http.StatusServiceUnavailable) return @@ -186,21 +186,21 @@ func (app *app) handleTunnel(w http.ResponseWriter, r *http.Request) { dstConnStr := fmt.Sprintf("%s->%s->%s", dstConn.LocalAddr().String(), dstConn.RemoteAddr().String(), r.Host) srcConnStr := fmt.Sprintf("%s->%s", srcConn.LocalAddr().String(), srcConn.RemoteAddr().String()) - app.logger.Debug().Msgf("%s - %s - %s", r.Proto, r.Method, r.Host) - app.logger.Debug().Msgf("src: %s - dst: %s", srcConnStr, dstConnStr) + p.logger.Debug().Msgf("%s - %s - %s", r.Proto, r.Method, r.Host) + p.logger.Debug().Msgf("src: %s - dst: %s", srcConnStr, dstConnStr) var wg sync.WaitGroup wg.Add(2) - go app.transfer(&wg, dstConn, srcConn, dstConnStr, srcConnStr) - go app.transfer(&wg, srcConn, dstConn, srcConnStr, dstConnStr) + go p.transfer(&wg, dstConn, srcConn, dstConnStr, srcConnStr) + go p.transfer(&wg, srcConn, dstConn, srcConnStr, dstConnStr) wg.Wait() } -func (app *app) transfer(wg *sync.WaitGroup, destination io.Writer, source io.Reader, destName, srcName string) { +func (p *proxyApp) transfer(wg *sync.WaitGroup, destination io.Writer, source io.Reader, destName, srcName string) { defer wg.Done() n, err := io.Copy(destination, source) if err != nil { - app.logger.Error().Err(err).Msgf("Error during copy from %s to %s: %v", srcName, destName, err) + p.logger.Error().Err(err).Msgf("Error during copy from %s to %s: %v", srcName, destName, err) } var written string if n < kbSize { @@ -208,23 +208,23 @@ func (app *app) transfer(wg *sync.WaitGroup, destination io.Writer, source io.Re } else { written = fmt.Sprintf("%dKB", n/kbSize) } - app.logger.Debug().Msgf("copied %s from %s to %s", written, srcName, destName) + p.logger.Debug().Msgf("copied %s from %s to %s", written, srcName, destName) } -func (app *app) handler() http.HandlerFunc { +func (p *proxyApp) handler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodConnect { - app.handleTunnel(w, r) + p.handleTunnel(w, r) } else { - app.handleForward(w, r) + p.handleForward(w, r) } } } -func (app *app) Run() { - app.hs.Handler = app.handler() - if err := app.hs.ListenAndServe(); err != nil { - app.logger.Fatal().Err(err).Msg("Unable to start HTTP server") +func (p *proxyApp) Run() { + p.httpServer.Handler = p.handler() + if err := p.httpServer.ListenAndServe(); err != nil { + p.logger.Fatal().Err(err).Msg("Unable to start HTTP server") } } @@ -237,7 +237,7 @@ type Config struct { Pass string } -func New(conf *Config) *app { +func New(conf *Config) *proxyApp { var logger zerolog.Logger if conf.Json { logger = zerolog.New(os.Stdout).With().Timestamp().Logger() @@ -275,7 +275,10 @@ func New(conf *Config) *app { ReadTimeout: readTimeout, WriteTimeout: writeTimeout, MaxHeaderBytes: 1 << 20, + Protocols: new(http.Protocols), } + hs.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler)) + hs.Protocols.SetHTTP1(true) hc := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, @@ -287,5 +290,5 @@ func New(conf *Config) *app { } logger.Info().Msgf("SOCKS5 Proxy: %s", conf.AddrSOCKS) logger.Info().Msgf("HTTP Proxy: %s", conf.AddrHTTP) - return &app{hs: hs, sc: socks, hc: hc, dialer: dialer, logger: &logger} + return &proxyApp{httpServer: hs, sockServer: socks, httpClient: hc, sockDialer: dialer, logger: &logger} } From b34dbbddffc97fa39f7de0f992638829d6030ba8 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Sun, 1 Jun 2025 20:00:15 +0300 Subject: [PATCH 05/10] Added clearing the password prompt line --- cmd/gohpts/cli.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/gohpts/cli.go b/cmd/gohpts/cli.go index 9c76ba9..c3a01db 100644 --- a/cmd/gohpts/cli.go +++ b/cmd/gohpts/cli.go @@ -51,7 +51,7 @@ func root(args []string) error { os.Exit(1) } conf.Pass = string(bytepw) - fmt.Println() + fmt.Print("\033[2K\r") return nil }) flags.Func("l", "Address of HTTP proxy server (Default: localhost:8080)", func(flagValue string) error { From b0fb7fb496299c64c7ea53d89474638e3e5069b0 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Mon, 2 Jun 2025 14:19:26 +0300 Subject: [PATCH 06/10] Added basic support for chunked responses --- gohpts.go | 111 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 21 deletions(-) diff --git a/gohpts.go b/gohpts.go index e845452..6aaa2d5 100644 --- a/gohpts.go +++ b/gohpts.go @@ -7,6 +7,7 @@ import ( "net" "net/http" "os" + "slices" "strings" "sync" "time" @@ -19,6 +20,7 @@ const ( readTimeout time.Duration = 10 * time.Second writeTimeout time.Duration = 10 * time.Second timeout time.Duration = 10 * time.Second + flushTimeout time.Duration = 10 * time.Millisecond kbSize int64 = 1000 ) @@ -84,12 +86,40 @@ func isLocalAddress(addr string) bool { type proxyApp struct { httpServer *http.Server - sockServer *http.Client + sockClient *http.Client httpClient *http.Client sockDialer proxy.Dialer logger *zerolog.Logger } +func (p *proxyApp) doReq(w http.ResponseWriter, r *http.Request, socks bool) *http.Response { + var ( + resp *http.Response + err error + msg string + client *http.Client + ) + if socks { + client = p.sockClient + msg = "Connection to SOCKS5 server failed" + } else { + client = p.httpClient + msg = "Connection failed" + } + resp, err = client.Do(r) + if err != nil { + p.logger.Error().Err(err).Msg(msg) + w.WriteHeader(http.StatusServiceUnavailable) + return nil + } + if resp == nil { + p.logger.Error().Msg(msg) + w.WriteHeader(http.StatusServiceUnavailable) + return nil + } + return resp +} + func (p *proxyApp) handleForward(w http.ResponseWriter, r *http.Request) { req, err := http.NewRequest(r.Method, r.URL.String(), r.Body) @@ -106,33 +136,69 @@ func (p *proxyApp) handleForward(w http.ResponseWriter, r *http.Request) { appendHostToXForwardHeader(req.Header, clientIP) } var resp *http.Response + var chunked bool + p.httpClient.Timeout = timeout + p.sockClient.Timeout = timeout if isLocalAddress(r.Host) { - resp, err = p.httpClient.Do(req) - if err != nil { - p.logger.Error().Err(err).Msg("Connection failed") - w.WriteHeader(http.StatusServiceUnavailable) - return - } + resp = p.doReq(w, req, false) if resp == nil { - p.logger.Error().Err(err).Msg("Connection failed") - w.WriteHeader(http.StatusServiceUnavailable) return } - } else { - resp, err = p.sockServer.Do(req) - if err != nil { - p.logger.Error().Err(err).Msg("Connection to SOCKS5 server failed") - w.WriteHeader(http.StatusServiceUnavailable) - return + if slices.Contains(resp.TransferEncoding, "chunked") { + chunked = true + p.httpClient.Timeout = 0 + p.sockClient.Timeout = 0 + resp.Body.Close() + resp = p.doReq(w, req, false) + if resp == nil { + return + } } + } else { + resp = p.doReq(w, req, true) if resp == nil { - p.logger.Error().Err(err).Msg("Connection to SOCKS5 server failed") - w.WriteHeader(http.StatusServiceUnavailable) return } + if slices.Contains(resp.TransferEncoding, "chunked") { + chunked = true + p.httpClient.Timeout = 0 + p.sockClient.Timeout = 0 + resp.Body.Close() + resp = p.doReq(w, req, true) + if resp == nil { + return + } + } } defer resp.Body.Close() - + done := make(chan struct{}) + if chunked { + rc := http.NewResponseController(w) + go func() { + for { + select { + case <-time.Tick(flushTimeout): + err := rc.Flush() + if err != nil { + p.logger.Error().Err(err) + return + } + err = rc.SetReadDeadline(time.Now().Add(readTimeout)) + if err != nil { + p.logger.Error().Err(err) + return + } + err = rc.SetWriteDeadline(time.Now().Add(writeTimeout)) + if err != nil { + p.logger.Error().Err(err) + return + } + case <-done: + return + } + } + }() + } delConnectionHeaders(resp.Header) delHopHeaders(resp.Header) copyHeader(w.Header(), resp.Header) @@ -149,7 +215,12 @@ func (p *proxyApp) handleForward(w http.ResponseWriter, r *http.Request) { } else { written = fmt.Sprintf("%dKB", n/kbSize) } + if chunked { + written = fmt.Sprintf("%s - chunked", written) + } p.logger.Debug().Msgf("%s - %s - %s - %d - %s", r.Proto, r.Method, r.Host, resp.StatusCode, written) + done <- struct{}{} + close(done) } func (p *proxyApp) handleTunnel(w http.ResponseWriter, r *http.Request) { @@ -268,7 +339,6 @@ func New(conf *Config) *proxyApp { CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, - Timeout: timeout, } hs := &http.Server{ Addr: conf.AddrHTTP, @@ -286,9 +356,8 @@ func New(conf *Config) *proxyApp { CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, - Timeout: timeout, } logger.Info().Msgf("SOCKS5 Proxy: %s", conf.AddrSOCKS) logger.Info().Msgf("HTTP Proxy: %s", conf.AddrHTTP) - return &proxyApp{httpServer: hs, sockServer: socks, httpClient: hc, sockDialer: dialer, logger: &logger} + return &proxyApp{httpServer: hs, sockClient: socks, httpClient: hc, sockDialer: dialer, logger: &logger} } From cc727c56c305896ebaebab71b70ea18034da4168 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Mon, 2 Jun 2025 16:29:46 +0300 Subject: [PATCH 07/10] Added basic support for trailer headers --- gohpts.go | 17 +++++++++++++++++ version.go | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/gohpts.go b/gohpts.go index 6aaa2d5..e6baf53 100644 --- a/gohpts.go +++ b/gohpts.go @@ -199,6 +199,14 @@ func (p *proxyApp) handleForward(w http.ResponseWriter, r *http.Request) { } }() } + announcedTrailers := len(resp.Trailer) + if announcedTrailers > 0 { + trailerKeys := make([]string, 0, announcedTrailers) + for k := range resp.Trailer { + trailerKeys = append(trailerKeys, k) + } + w.Header().Add("Trailer", strings.Join(trailerKeys, ", ")) + } delConnectionHeaders(resp.Header) delHopHeaders(resp.Header) copyHeader(w.Header(), resp.Header) @@ -219,6 +227,15 @@ func (p *proxyApp) handleForward(w http.ResponseWriter, r *http.Request) { written = fmt.Sprintf("%s - chunked", written) } p.logger.Debug().Msgf("%s - %s - %s - %d - %s", r.Proto, r.Method, r.Host, resp.StatusCode, written) + if len(resp.Trailer) == announcedTrailers { + copyHeader(w.Header(), resp.Trailer) + } + for key, values := range resp.Trailer { + key = http.TrailerPrefix + key + for _, v := range values { + w.Header().Add(key, v) + } + } done <- struct{}{} close(done) } diff --git a/version.go b/version.go index 44741b5..6ec07b7 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package gohpts -const Version string = "gohpts v1.3.1" +const Version string = "gohpts v1.3.2" From b27dd47a0ef4095c151a09388b7473811b63df8d Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Mon, 2 Jun 2025 17:08:14 +0300 Subject: [PATCH 08/10] Removed one line --- gohpts.go | 1 - 1 file changed, 1 deletion(-) diff --git a/gohpts.go b/gohpts.go index e6baf53..8c2f843 100644 --- a/gohpts.go +++ b/gohpts.go @@ -214,7 +214,6 @@ func (p *proxyApp) handleForward(w http.ResponseWriter, r *http.Request) { n, err := io.Copy(w, resp.Body) if err != nil { p.logger.Error().Err(err).Msgf("Error during Copy() %s: %s", r.URL.String(), err) - w.WriteHeader(http.StatusInternalServerError) return } var written string From b9c5aa521d0b5f42d7145872a2d75002def85d56 Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Mon, 2 Jun 2025 18:21:33 +0300 Subject: [PATCH 09/10] Fixed closing done channel --- gohpts.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gohpts.go b/gohpts.go index 8c2f843..7b2108b 100644 --- a/gohpts.go +++ b/gohpts.go @@ -214,6 +214,8 @@ func (p *proxyApp) handleForward(w http.ResponseWriter, r *http.Request) { n, err := io.Copy(w, resp.Body) if err != nil { p.logger.Error().Err(err).Msgf("Error during Copy() %s: %s", r.URL.String(), err) + done <- struct{}{} + close(done) return } var written string From c8828d34f2d1c5dfdaaff91286105e85bc220eac Mon Sep 17 00:00:00 2001 From: shadowy-pycoder <35629483+shadowy-pycoder@users.noreply.github.com> Date: Mon, 2 Jun 2025 18:33:01 +0300 Subject: [PATCH 10/10] Bumped to v1.3.4 --- version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.go b/version.go index 6ec07b7..b2f385a 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package gohpts -const Version string = "gohpts v1.3.2" +const Version string = "gohpts v1.3.4"