67
67
// Echo is the top-level framework instance.
68
68
Echo struct {
69
69
common
70
+ // startupMutex is mutex to lock Echo instance access during server configuration and startup. Useful for to get
71
+ // listener address info (on which interface/port was listener binded) without having data races.
72
+ startupMutex sync.RWMutex
70
73
StdLogger * stdLog.Logger
71
74
colorer * color.Color
72
75
premiddleware []MiddlewareFunc
@@ -643,32 +646,48 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
643
646
644
647
// Start starts an HTTP server.
645
648
func (e * Echo ) Start (address string ) error {
649
+ e .startupMutex .Lock ()
646
650
e .Server .Addr = address
647
- return e .StartServer (e .Server )
651
+ if err := e .configureServer (e .Server ); err != nil {
652
+ e .startupMutex .Unlock ()
653
+ return err
654
+ }
655
+ e .startupMutex .Unlock ()
656
+ return e .serve ()
648
657
}
649
658
650
659
// StartTLS starts an HTTPS server.
651
660
// If `certFile` or `keyFile` is `string` the values are treated as file paths.
652
661
// If `certFile` or `keyFile` is `[]byte` the values are treated as the certificate or key as-is.
653
662
func (e * Echo ) StartTLS (address string , certFile , keyFile interface {}) (err error ) {
663
+ e .startupMutex .Lock ()
654
664
var cert []byte
655
665
if cert , err = filepathOrContent (certFile ); err != nil {
666
+ e .startupMutex .Unlock ()
656
667
return
657
668
}
658
669
659
670
var key []byte
660
671
if key , err = filepathOrContent (keyFile ); err != nil {
672
+ e .startupMutex .Unlock ()
661
673
return
662
674
}
663
675
664
676
s := e .TLSServer
665
677
s .TLSConfig = new (tls.Config )
666
678
s .TLSConfig .Certificates = make ([]tls.Certificate , 1 )
667
679
if s .TLSConfig .Certificates [0 ], err = tls .X509KeyPair (cert , key ); err != nil {
680
+ e .startupMutex .Unlock ()
668
681
return
669
682
}
670
683
671
- return e .startTLS (address )
684
+ e .configureTLS (address )
685
+ if err := e .configureServer (s ); err != nil {
686
+ e .startupMutex .Unlock ()
687
+ return err
688
+ }
689
+ e .startupMutex .Unlock ()
690
+ return s .Serve (e .TLSListener )
672
691
}
673
692
674
693
func filepathOrContent (fileOrContent interface {}) (content []byte , err error ) {
@@ -684,24 +703,41 @@ func filepathOrContent(fileOrContent interface{}) (content []byte, err error) {
684
703
685
704
// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
686
705
func (e * Echo ) StartAutoTLS (address string ) error {
706
+ e .startupMutex .Lock ()
687
707
s := e .TLSServer
688
708
s .TLSConfig = new (tls.Config )
689
709
s .TLSConfig .GetCertificate = e .AutoTLSManager .GetCertificate
690
710
s .TLSConfig .NextProtos = append (s .TLSConfig .NextProtos , acme .ALPNProto )
691
- return e .startTLS (address )
711
+
712
+ e .configureTLS (address )
713
+ if err := e .configureServer (s ); err != nil {
714
+ e .startupMutex .Unlock ()
715
+ return err
716
+ }
717
+ e .startupMutex .Unlock ()
718
+ return s .Serve (e .TLSListener )
692
719
}
693
720
694
- func (e * Echo ) startTLS (address string ) error {
721
+ func (e * Echo ) configureTLS (address string ) {
695
722
s := e .TLSServer
696
723
s .Addr = address
697
724
if ! e .DisableHTTP2 {
698
725
s .TLSConfig .NextProtos = append (s .TLSConfig .NextProtos , "h2" )
699
726
}
700
- return e .StartServer (e .TLSServer )
701
727
}
702
728
703
729
// StartServer starts a custom http server.
704
730
func (e * Echo ) StartServer (s * http.Server ) (err error ) {
731
+ e .startupMutex .Lock ()
732
+ if err := e .configureServer (s ); err != nil {
733
+ e .startupMutex .Unlock ()
734
+ return err
735
+ }
736
+ e .startupMutex .Unlock ()
737
+ return e .serve ()
738
+ }
739
+
740
+ func (e * Echo ) configureServer (s * http.Server ) (err error ) {
705
741
// Setup
706
742
e .colorer .SetOutput (e .Logger .Output ())
707
743
s .ErrorLog = e .StdLogger
@@ -724,7 +760,7 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
724
760
if ! e .HidePort {
725
761
e .colorer .Printf ("⇨ http server started on %s\n " , e .colorer .Green (e .Listener .Addr ()))
726
762
}
727
- return s . Serve ( e . Listener )
763
+ return nil
728
764
}
729
765
if e .TLSListener == nil {
730
766
l , err := newListener (s .Addr , e .ListenerNetwork )
@@ -736,11 +772,39 @@ func (e *Echo) StartServer(s *http.Server) (err error) {
736
772
if ! e .HidePort {
737
773
e .colorer .Printf ("⇨ https server started on %s\n " , e .colorer .Green (e .TLSListener .Addr ()))
738
774
}
739
- return s .Serve (e .TLSListener )
775
+ return nil
776
+ }
777
+
778
+ func (e * Echo ) serve () error {
779
+ if e .TLSListener != nil {
780
+ return e .Server .Serve (e .TLSListener )
781
+ }
782
+ return e .Server .Serve (e .Listener )
783
+ }
784
+
785
+ // ListenerAddr returns net.Addr for Listener
786
+ func (e * Echo ) ListenerAddr () net.Addr {
787
+ e .startupMutex .RLock ()
788
+ defer e .startupMutex .RUnlock ()
789
+ if e .Listener == nil {
790
+ return nil
791
+ }
792
+ return e .Listener .Addr ()
793
+ }
794
+
795
+ // TLSListenerAddr returns net.Addr for TLSListener
796
+ func (e * Echo ) TLSListenerAddr () net.Addr {
797
+ e .startupMutex .RLock ()
798
+ defer e .startupMutex .RUnlock ()
799
+ if e .TLSListener == nil {
800
+ return nil
801
+ }
802
+ return e .TLSListener .Addr ()
740
803
}
741
804
742
805
// StartH2CServer starts a custom http/2 server with h2c (HTTP/2 Cleartext).
743
806
func (e * Echo ) StartH2CServer (address string , h2s * http2.Server ) (err error ) {
807
+ e .startupMutex .Lock ()
744
808
// Setup
745
809
s := e .Server
746
810
s .Addr = address
@@ -758,18 +822,22 @@ func (e *Echo) StartH2CServer(address string, h2s *http2.Server) (err error) {
758
822
if e .Listener == nil {
759
823
e .Listener , err = newListener (s .Addr , e .ListenerNetwork )
760
824
if err != nil {
825
+ e .startupMutex .Unlock ()
761
826
return err
762
827
}
763
828
}
764
829
if ! e .HidePort {
765
830
e .colorer .Printf ("⇨ http server started on %s\n " , e .colorer .Green (e .Listener .Addr ()))
766
831
}
832
+ e .startupMutex .Unlock ()
767
833
return s .Serve (e .Listener )
768
834
}
769
835
770
836
// Close immediately stops the server.
771
837
// It internally calls `http.Server#Close()`.
772
838
func (e * Echo ) Close () error {
839
+ e .startupMutex .Lock ()
840
+ defer e .startupMutex .Unlock ()
773
841
if err := e .TLSServer .Close (); err != nil {
774
842
return err
775
843
}
@@ -779,6 +847,8 @@ func (e *Echo) Close() error {
779
847
// Shutdown stops the server gracefully.
780
848
// It internally calls `http.Server#Shutdown()`.
781
849
func (e * Echo ) Shutdown (ctx stdContext.Context ) error {
850
+ e .startupMutex .Lock ()
851
+ defer e .startupMutex .Unlock ()
782
852
if err := e .TLSServer .Shutdown (ctx ); err != nil {
783
853
return err
784
854
}
0 commit comments