@@ -3,17 +3,20 @@ package proxy
33import (
44 "bufio"
55 "bytes"
6+ "context"
67 "crypto/tls"
78 "errors"
89 "fmt"
910 "io"
1011 "log/slog"
1112 "net"
1213 "net/http"
14+ _ "net/http/pprof"
1315 "net/url"
1416 "strconv"
1517 "strings"
1618 "sync/atomic"
19+ "time"
1720
1821 "github.com/coder/boundary/audit"
1922 "github.com/coder/boundary/rules"
@@ -28,26 +31,33 @@ type Server struct {
2831 httpPort int
2932 started atomic.Bool
3033
31- listener net.Listener
34+ listener net.Listener
35+ pprofServer * http.Server
36+ pprofEnabled bool
37+ pprofPort int
3238}
3339
3440// Config holds configuration for the proxy server
3541type Config struct {
36- HTTPPort int
37- RuleEngine rules.Evaluator
38- Auditor audit.Auditor
39- Logger * slog.Logger
40- TLSConfig * tls.Config
42+ HTTPPort int
43+ RuleEngine rules.Evaluator
44+ Auditor audit.Auditor
45+ Logger * slog.Logger
46+ TLSConfig * tls.Config
47+ PprofEnabled bool
48+ PprofPort int
4149}
4250
4351// NewProxyServer creates a new proxy server instance
4452func NewProxyServer (config Config ) * Server {
4553 return & Server {
46- ruleEngine : config .RuleEngine ,
47- auditor : config .Auditor ,
48- logger : config .Logger ,
49- tlsConfig : config .TLSConfig ,
50- httpPort : config .HTTPPort ,
54+ ruleEngine : config .RuleEngine ,
55+ auditor : config .Auditor ,
56+ logger : config .Logger ,
57+ tlsConfig : config .TLSConfig ,
58+ httpPort : config .HTTPPort ,
59+ pprofEnabled : config .PprofEnabled ,
60+ pprofPort : config .PprofPort ,
5161 }
5262}
5363
@@ -58,6 +68,29 @@ func (p *Server) Start() error {
5868 }
5969
6070 p .logger .Info ("Starting HTTP proxy with TLS termination" , "port" , p .httpPort )
71+
72+ // Start pprof server if enabled
73+ if p .pprofEnabled {
74+ p .pprofServer = & http.Server {
75+ Addr : fmt .Sprintf (":%d" , p .pprofPort ),
76+ Handler : http .DefaultServeMux ,
77+ }
78+
79+ ln , err := net .Listen ("tcp" , fmt .Sprintf (":%d" , p .pprofPort ))
80+ if err != nil {
81+ p .logger .Error ("failed to listen on port for pprof server" , "port" , p .pprofPort , "error" , err )
82+ return fmt .Errorf ("failed to listen on port %v for pprof server: %v" , p .pprofPort , err )
83+ }
84+
85+ go func () {
86+ p .logger .Info ("Serving pprof on existing listener" , "port" , p .pprofPort )
87+ if err := p .pprofServer .Serve (ln ); err != nil && errors .Is (err , http .ErrServerClosed ) {
88+ p .logger .Error ("pprof server error" , "error" , err )
89+ }
90+ }()
91+
92+ }
93+
6194 var err error
6295 p .listener , err = net .Listen ("tcp" , fmt .Sprintf (":%d" , p .httpPort ))
6396 if err != nil {
@@ -105,6 +138,15 @@ func (p *Server) Stop() error {
105138 return err
106139 }
107140
141+ // Close pprof server
142+ if p .pprofServer != nil {
143+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
144+ defer cancel ()
145+ if err := p .pprofServer .Shutdown (ctx ); err != nil {
146+ p .logger .Error ("Failed to shutdown pprof server" , "error" , err )
147+ }
148+ }
149+
108150 return nil
109151}
110152
0 commit comments