git.iko.soy/typeable/oauth2-proxy
on v6.1.1 help sign in
136 lines 3.6 kB history raw
1package main
3import (
4 "context"
5 "crypto/tls"
6 "errors"
7 "net"
8 "net/http"
9 "strings"
10 "time"
12 "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
13 "github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
16// Server represents an HTTP server
17type Server struct {
18 Handler http.Handler
19 Opts *options.Options
20 stop chan struct{} // channel for waiting shutdown
23// ListenAndServe will serve traffic on HTTP or HTTPS depending on TLS options
24func (s *Server) ListenAndServe() {
25 if s.Opts.TLSKeyFile != "" || s.Opts.TLSCertFile != "" {
26 s.ServeHTTPS()
27 } else {
28 s.ServeHTTP()
29 }
32// ServeHTTP constructs a net.Listener and starts handling HTTP requests
33func (s *Server) ServeHTTP() {
34 HTTPAddress := s.Opts.HTTPAddress
35 var scheme string
37 i := strings.Index(HTTPAddress, "://")
38 if i > -1 {
39 scheme = HTTPAddress[0:i]
40 }
42 var networkType string
43 switch scheme {
44 case "", "http":
45 networkType = "tcp"
46 default:
47 networkType = scheme
48 }
50 slice := strings.SplitN(HTTPAddress, "//", 2)
51 listenAddr := slice[len(slice)-1]
53 listener, err := net.Listen(networkType, listenAddr)
54 if err != nil {
55 logger.Fatalf("FATAL: listen (%s, %s) failed - %s", networkType, listenAddr, err)
56 }
57 logger.Printf("HTTP: listening on %s", listenAddr)
58 s.serve(listener)
59 logger.Printf("HTTP: closing %s", listener.Addr())
62// ServeHTTPS constructs a net.Listener and starts handling HTTPS requests
63func (s *Server) ServeHTTPS() {
64 addr := s.Opts.HTTPSAddress
65 config := &tls.Config{
66 MinVersion: tls.VersionTLS12,
67 MaxVersion: tls.VersionTLS12,
68 }
69 if config.NextProtos == nil {
70 config.NextProtos = []string{"http/1.1"}
71 }
73 var err error
74 config.Certificates = make([]tls.Certificate, 1)
75 config.Certificates[0], err = tls.LoadX509KeyPair(s.Opts.TLSCertFile, s.Opts.TLSKeyFile)
76 if err != nil {
77 logger.Fatalf("FATAL: loading tls config (%s, %s) failed - %s", s.Opts.TLSCertFile, s.Opts.TLSKeyFile, err)
78 }
80 ln, err := net.Listen("tcp", addr)
81 if err != nil {
82 logger.Fatalf("FATAL: listen (%s) failed - %s", addr, err)
83 }
84 logger.Printf("HTTPS: listening on %s", ln.Addr())
86 tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
87 s.serve(tlsListener)
88 logger.Printf("HTTPS: closing %s", tlsListener.Addr())
91func (s *Server) serve(listener net.Listener) {
92 srv := &http.Server{Handler: s.Handler}
94 // See https://golang.org/pkg/net/http/#Server.Shutdown
95 idleConnsClosed := make(chan struct{})
96 go func() {
97 <-s.stop // wait notification for stopping server
99 // We received an interrupt signal, shut down.
100 if err := srv.Shutdown(context.Background()); err != nil {
101 // Error from closing listeners, or context timeout:
102 logger.Printf("HTTP server Shutdown: %v", err)
103 }
104 close(idleConnsClosed)
105 }()
107 err := srv.Serve(listener)
108 if err != nil && !errors.Is(err, http.ErrServerClosed) {
109 logger.Errorf("ERROR: http.Serve() - %s", err)
110 }
111 <-idleConnsClosed
114// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
115// connections. It's used by ListenAndServe and ListenAndServeTLS so
116// dead TCP connections (e.g. closing laptop mid-download) eventually
117// go away.
118type tcpKeepAliveListener struct {
119 *net.TCPListener
122func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
123 tc, err := ln.AcceptTCP()
124 if err != nil {
125 return nil, err
126 }
127 err = tc.SetKeepAlive(true)
128 if err != nil {
129 logger.Printf("Error setting Keep-Alive: %v", err)
130 }
131 err = tc.SetKeepAlivePeriod(3 * time.Minute)
132 if err != nil {
133 logger.Printf("Error setting Keep-Alive period: %v", err)
134 }
135 return tc, nil