2015-06-07 21:51:47 -04:00
package main
import (
2020-04-05 00:12:38 +09:00
"context"
2015-06-07 21:51:47 -04:00
"crypto/tls"
2020-04-05 00:12:38 +09:00
"errors"
2015-06-07 21:51:47 -04:00
"net"
"net/http"
"strings"
"time"
2019-02-10 08:37:45 -08:00
2020-09-30 01:44:42 +09:00
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
2015-06-07 21:51:47 -04:00
)
2018-12-20 09:30:42 +00:00
// Server represents an HTTP server
2015-06-07 21:51:47 -04:00
type Server struct {
Handler http . Handler
2020-04-13 13:50:34 +01:00
Opts * options . Options
2020-04-05 00:12:38 +09:00
stop chan struct { } // channel for waiting shutdown
2015-06-07 21:51:47 -04:00
}
2018-12-20 09:30:42 +00:00
// ListenAndServe will serve traffic on HTTP or HTTPS depending on TLS options
2015-06-07 21:51:47 -04:00
func ( s * Server ) ListenAndServe ( ) {
if s . Opts . TLSKeyFile != "" || s . Opts . TLSCertFile != "" {
s . ServeHTTPS ( )
} else {
s . ServeHTTP ( )
}
}
2018-12-20 09:30:42 +00:00
// ServeHTTP constructs a net.Listener and starts handling HTTP requests
2015-06-07 21:51:47 -04:00
func ( s * Server ) ServeHTTP ( ) {
2018-11-29 14:26:41 +00:00
HTTPAddress := s . Opts . HTTPAddress
2018-12-20 09:30:42 +00:00
var scheme string
2017-04-01 15:10:33 -04:00
2018-11-29 14:26:41 +00:00
i := strings . Index ( HTTPAddress , "://" )
2017-04-01 15:10:33 -04:00
if i > - 1 {
2018-11-29 14:26:41 +00:00
scheme = HTTPAddress [ 0 : i ]
2015-06-07 21:51:47 -04:00
}
var networkType string
2017-04-01 15:10:33 -04:00
switch scheme {
2015-06-07 21:51:47 -04:00
case "" , "http" :
networkType = "tcp"
default :
2017-04-01 15:10:33 -04:00
networkType = scheme
2015-06-07 21:51:47 -04:00
}
2017-04-01 15:10:33 -04:00
2018-11-29 14:26:41 +00:00
slice := strings . SplitN ( HTTPAddress , "//" , 2 )
2017-04-01 15:10:33 -04:00
listenAddr := slice [ len ( slice ) - 1 ]
2015-06-07 21:51:47 -04:00
listener , err := net . Listen ( networkType , listenAddr )
if err != nil {
2019-02-10 08:37:45 -08:00
logger . Fatalf ( "FATAL: listen (%s, %s) failed - %s" , networkType , listenAddr , err )
2015-06-07 21:51:47 -04:00
}
2019-02-10 08:37:45 -08:00
logger . Printf ( "HTTP: listening on %s" , listenAddr )
2020-04-05 00:12:38 +09:00
s . serve ( listener )
2019-02-10 08:37:45 -08:00
logger . Printf ( "HTTP: closing %s" , listener . Addr ( ) )
2015-06-07 21:51:47 -04:00
}
2018-12-20 09:30:42 +00:00
// ServeHTTPS constructs a net.Listener and starts handling HTTPS requests
2015-06-07 21:51:47 -04:00
func ( s * Server ) ServeHTTPS ( ) {
2018-11-29 14:26:41 +00:00
addr := s . Opts . HTTPSAddress
2015-06-07 21:51:47 -04:00
config := & tls . Config {
MinVersion : tls . VersionTLS12 ,
2020-11-19 19:25:53 +09:00
MaxVersion : tls . VersionTLS13 ,
2015-06-07 21:51:47 -04:00
}
if config . NextProtos == nil {
config . NextProtos = [ ] string { "http/1.1" }
}
var err error
config . Certificates = make ( [ ] tls . Certificate , 1 )
config . Certificates [ 0 ] , err = tls . LoadX509KeyPair ( s . Opts . TLSCertFile , s . Opts . TLSKeyFile )
if err != nil {
2019-02-10 08:37:45 -08:00
logger . Fatalf ( "FATAL: loading tls config (%s, %s) failed - %s" , s . Opts . TLSCertFile , s . Opts . TLSKeyFile , err )
2015-06-07 21:51:47 -04:00
}
ln , err := net . Listen ( "tcp" , addr )
if err != nil {
2019-02-10 08:37:45 -08:00
logger . Fatalf ( "FATAL: listen (%s) failed - %s" , addr , err )
2015-06-07 21:51:47 -04:00
}
2019-02-10 08:37:45 -08:00
logger . Printf ( "HTTPS: listening on %s" , ln . Addr ( ) )
2015-06-07 21:51:47 -04:00
tlsListener := tls . NewListener ( tcpKeepAliveListener { ln . ( * net . TCPListener ) } , config )
2020-04-05 00:12:38 +09:00
s . serve ( tlsListener )
logger . Printf ( "HTTPS: closing %s" , tlsListener . Addr ( ) )
}
func ( s * Server ) serve ( listener net . Listener ) {
2015-06-07 21:51:47 -04:00
srv := & http . Server { Handler : s . Handler }
2020-04-05 00:12:38 +09:00
// See https://golang.org/pkg/net/http/#Server.Shutdown
idleConnsClosed := make ( chan struct { } )
go func ( ) {
<- s . stop // wait notification for stopping server
2015-06-07 21:51:47 -04:00
2020-04-05 00:12:38 +09:00
// We received an interrupt signal, shut down.
if err := srv . Shutdown ( context . Background ( ) ) ; err != nil {
// Error from closing listeners, or context timeout:
logger . Printf ( "HTTP server Shutdown: %v" , err )
}
close ( idleConnsClosed )
} ( )
err := srv . Serve ( listener )
if err != nil && ! errors . Is ( err , http . ErrServerClosed ) {
2020-08-10 11:44:08 +01:00
logger . Errorf ( "ERROR: http.Serve() - %s" , err )
2020-04-05 00:12:38 +09:00
}
<- idleConnsClosed
2015-06-07 21:51:47 -04:00
}
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
* net . TCPListener
}
2020-07-20 18:49:45 -07:00
func ( ln tcpKeepAliveListener ) Accept ( ) ( net . Conn , error ) {
2015-06-07 21:51:47 -04:00
tc , err := ln . AcceptTCP ( )
if err != nil {
2020-07-20 18:49:45 -07:00
return nil , err
2015-06-07 21:51:47 -04:00
}
2020-07-19 22:24:18 -07:00
err = tc . SetKeepAlive ( true )
if err != nil {
2020-07-20 18:49:45 -07:00
logger . Printf ( "Error setting Keep-Alive: %v" , err )
2020-07-19 22:24:18 -07:00
}
err = tc . SetKeepAlivePeriod ( 3 * time . Minute )
if err != nil {
2020-07-20 18:49:45 -07:00
logger . Printf ( "Error setting Keep-Alive period: %v" , err )
2020-07-19 22:24:18 -07:00
}
2015-06-07 21:51:47 -04:00
return tc , nil
}