@@ -8,8 +8,11 @@ import (
88 "net"
99 "net/http"
1010 "net/url"
11+ "os"
12+ "os/signal"
1113 "regexp"
1214 "strings"
15+ "syscall"
1316 "time"
1417
1518 "github.com/justinas/alice"
@@ -21,6 +24,7 @@ import (
2124 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/authentication/basic"
2225 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/cookies"
2326 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
27+ proxyhttp "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/http"
2428 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
2529 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
2630 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/middleware"
@@ -102,6 +106,7 @@ type OAuthProxy struct {
102106 headersChain alice.Chain
103107 preAuthChain alice.Chain
104108 pageWriter pagewriter.Writer
109+ server proxyhttp.Server
105110}
106111
107112// NewOAuthProxy creates a new instance of OAuthProxy from the options provided
@@ -184,7 +189,7 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
184189 return nil, fmt.Errorf("could not build headers chain: %v", err)
185190 }
186191
187− return &OAuthProxy{
192+ p := &OAuthProxy{
188193 CookieName: opts.Cookie.Name,
189194 CSRFCookieName: fmt.Sprintf("%v_%v", opts.Cookie.Name, "csrf"),
190195 CookieSeed: opts.Cookie.Secret,
@@ -223,7 +228,60 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) (*OAuthPr
223228 headersChain: headersChain,
224229 preAuthChain: preAuthChain,
225230 pageWriter: pageWriter,
226− }, nil
231+ }
232+
233+ if err := p.setupServer(opts); err != nil {
234+ return nil, fmt.Errorf("error setting up server: %v", err)
235+ }
236+
237+ return p, nil
238+}
239+
240+func (p *OAuthProxy) Start() error {
241+ if p.server == nil {
242+ // We have to call setupServer before Start is called.
243+ // If this doesn't happen it's a programming error.
244+ panic("server has not been initialised")
245+ }
246+
247+ ctx, cancel := context.WithCancel(context.Background())
248+
249+ // Observe signals in background goroutine.
250+ go func() {
251+ sigint := make(chan os.Signal, 1)
252+ signal.Notify(sigint, os.Interrupt, syscall.SIGTERM)
253+ <-sigint
254+ cancel() // cancel the context
255+ }()
256+
257+ return p.server.Start(ctx)
258+}
259+
260+func (p *OAuthProxy) setupServer(opts *options.Options) error {
261+ serverOpts := proxyhttp.Opts{
262+ Handler: p,
263+ BindAddress: opts.Server.BindAddress,
264+ SecureBindAddress: opts.Server.SecureBindAddress,
265+ TLS: opts.Server.TLS,
266+ }
267+
268+ appServer, err := proxyhttp.NewServer(serverOpts)
269+ if err != nil {
270+ return fmt.Errorf("could not build app server: %v", err)
271+ }
272+
273+ metricsServer, err := proxyhttp.NewServer(proxyhttp.Opts{
274+ Handler: middleware.DefaultMetricsHandler,
275+ BindAddress: opts.MetricsServer.BindAddress,
276+ SecureBindAddress: opts.MetricsServer.BindAddress,
277+ TLS: opts.MetricsServer.TLS,
278+ })
279+ if err != nil {
280+ return fmt.Errorf("could not build metrics server: %v", err)
281+ }
282+
283+ p.server = proxyhttp.NewServerGroup(appServer, metricsServer)
284+ return nil
227285}
228286
229287// buildPreAuthChain constructs a chain that should process every request before
@@ -233,9 +291,9 @@ func buildPreAuthChain(opts *options.Options) (alice.Chain, error) {
233291 chain := alice.New(middleware.NewScope(opts.ReverseProxy))
234292
235293 if opts.ForceHTTPS {
236− _, httpsPort, err := net.SplitHostPort(opts.HTTPSAddress)
294+ _, httpsPort, err := net.SplitHostPort(opts.Server.SecureBindAddress)
237295 if err != nil {
238− return alice.Chain{}, fmt.Errorf("invalid HTTPS address %q: %v", opts.HTTPAddress, err)
296+ return alice.Chain{}, fmt.Errorf("invalid HTTPS address %q: %v", opts.Server.SecureBindAddress, err)
239297 }
240298 chain = chain.Append(middleware.NewRedirectToHTTPS(httpsPort))
241299 }