123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- package httputil
- import (
- "crypto/tls"
- "errors"
- "fmt"
- "net"
- "net/http"
- "os"
- "os/signal"
- "strings"
- "sync"
- "syscall"
- "time"
- )
- type HTTPServer struct {
- signalling chan os.Signal
- LastError error
- Running bool
- listener signalTCPListener
- }
- func (hs *HTTPServer) Shutdown() {
- if hs.signalling != nil {
- hs.signalling <- syscall.SIGINT
- }
- }
- func (hs *HTTPServer) RunHTTPServer(laddr string, wgStatus *sync.WaitGroup) error {
- hs.Running = false
-
- originalListener, err := net.Listen("tcp", laddr)
- if err != nil {
- hs.LastError = err
- if wgStatus != nil {
- wgStatus.Done()
- }
- return err
- }
-
- sl := newSignalTCPListener(originalListener, originalListener.(*net.TCPListener), wgStatus)
- return hs.runServer(sl, wgStatus)
- }
- func (hs *HTTPServer) RunHTTPSServer(keypath string, certFile string, keyFile string,
- laddr string, wgStatus *sync.WaitGroup) error {
-
- if keypath != "" && !strings.HasSuffix(keypath, "/") {
- keypath += "/"
- }
-
- cert, err := tls.LoadX509KeyPair(keypath+certFile, keypath+keyFile)
- if err != nil {
- hs.LastError = err
- if wgStatus != nil {
- wgStatus.Done()
- }
- return err
- }
- hs.Running = false
-
- originalListener, err := net.Listen("tcp", laddr)
- if err != nil {
- hs.LastError = err
- if wgStatus != nil {
- wgStatus.Done()
- }
- return err
- }
-
- config := tls.Config{Certificates: []tls.Certificate{cert}}
- originalTLSListener := tls.NewListener(originalListener, &config)
-
- sl := newSignalTCPListener(originalTLSListener, originalListener.(*net.TCPListener), wgStatus)
- return hs.runServer(sl, wgStatus)
- }
- func (hs *HTTPServer) runServer(sl *signalTCPListener, wgStatus *sync.WaitGroup) error {
-
- server := http.Server{}
-
-
- hs.signalling = make(chan os.Signal)
- signal.Notify(hs.signalling, syscall.SIGINT)
-
-
- var wg sync.WaitGroup
- wg.Add(1)
- go func() {
- defer wg.Done()
- hs.Running = true
- server.Serve(sl)
- }()
- for true {
- signal := <-hs.signalling
- if signal == syscall.SIGINT {
-
- sl.Shutdown()
-
- wg.Wait()
- hs.Running = false
- break
- }
- }
- if wgStatus != nil {
- wgStatus.Done()
- }
- return nil
- }
- type signalTCPListener struct {
- net.Listener
- tcpListener *net.TCPListener
- Signals chan int
- wgStatus *sync.WaitGroup
- }
- const SigShutdown = 1
- var ErrSigShutdown = errors.New("Server was shut down")
- func newSignalTCPListener(l net.Listener, tl *net.TCPListener, wgStatus *sync.WaitGroup) *signalTCPListener {
- return &signalTCPListener{l, tl, make(chan int), wgStatus}
- }
- func (sl *signalTCPListener) Accept() (net.Conn, error) {
- for {
-
- sl.tcpListener.SetDeadline(time.Now().Add(time.Second))
- newConn, err := sl.Listener.Accept()
-
- if sl.wgStatus != nil {
- sl.wgStatus.Done()
- sl.wgStatus = nil
- }
-
- select {
- case sig := <-sl.Signals:
-
- if sig == SigShutdown {
- return nil, ErrSigShutdown
- }
- panic(fmt.Sprintf("Unknown signal received: %v", sig))
- default:
- netErr, ok := err.(net.Error)
-
- if (err != nil && (!ok || !(netErr.Timeout() && netErr.Temporary()))) || newConn != nil {
- return newConn, err
- }
- }
- }
- }
- func (sl *signalTCPListener) Shutdown() {
- sl.Signals <- SigShutdown
- close(sl.Signals)
- }
|