github.com/erda-project/erda-infra@v1.0.10-0.20240327085753-f3a249292aeb/providers/httpserver/server/server.go (about)

     1  // Copyright (c) 2021 Terminus, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package server
    16  
    17  import (
    18  	"crypto/tls"
    19  	"net"
    20  	"net/http"
    21  	"time"
    22  
    23  	"github.com/labstack/echo"
    24  )
    25  
    26  type (
    27  	// Server .
    28  	Server interface {
    29  		Use(middleware ...MiddlewareFunc)
    30  		NewRouter() RouterTx
    31  		Router() Router
    32  		Start(addr string) error
    33  		Close() error
    34  	}
    35  	// RouterTx .
    36  	RouterTx interface {
    37  		Router
    38  		Commit()
    39  	}
    40  )
    41  
    42  var (
    43  	// NotFoundHandler .
    44  	NotFoundHandler = echo.NotFoundHandler
    45  )
    46  
    47  type (
    48  	routerManager interface {
    49  		GetRouter() Router
    50  		NewRouter() RouterTx
    51  	}
    52  	server struct {
    53  		e          *echo.Echo
    54  		reloadable bool
    55  		router     routerManager
    56  		middleware []MiddlewareFunc
    57  	}
    58  )
    59  
    60  // New .
    61  func New(reloadable bool, binder echo.Binder, validator echo.Validator) Server {
    62  	s := &server{
    63  		e:          echo.New(),
    64  		reloadable: reloadable,
    65  	}
    66  	s.e.HideBanner, s.e.HidePort = true, true
    67  	s.e.Binder, s.e.Validator = binder, validator
    68  	s.e.Server.Handler, s.e.TLSServer.Handler = s, s
    69  	if reloadable {
    70  		s.router = newReloadableRouterManager(s.e)
    71  	} else {
    72  		s.router = newFixedRouterManager(s.e)
    73  	}
    74  	return s
    75  }
    76  
    77  // Start .
    78  func (s *server) Start(addr string) error {
    79  	err := s.startHTTP(addr)
    80  	if err != nil && err != http.ErrServerClosed {
    81  		return err
    82  	}
    83  	return nil
    84  }
    85  
    86  // Close .
    87  func (s *server) Close() error {
    88  	err := s.e.Server.Close()
    89  	if err != nil && err != http.ErrServerClosed {
    90  		return err
    91  	}
    92  	return nil
    93  }
    94  
    95  // ServeHTTP .
    96  func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    97  	router := s.router.GetRouter()
    98  
    99  	// Acquire context
   100  	c := router.NewContext()
   101  	// Release context
   102  	defer router.ReleaseContext(c)
   103  	c.Reset(r, w)
   104  
   105  	// Find handler
   106  	router.Find(r.Method, getPath(r), c)
   107  	h := c.Handler()
   108  	if h == nil {
   109  		h = NotFoundHandler
   110  	}
   111  	for i := len(s.middleware) - 1; i >= 0; i-- {
   112  		h = s.middleware[i](h)
   113  	}
   114  
   115  	// Execute chain
   116  	if err := h(c); err != nil {
   117  		s.e.HTTPErrorHandler(err, c)
   118  	}
   119  }
   120  
   121  func getPath(r *http.Request) string {
   122  	path := r.URL.RawPath
   123  	if path == "" {
   124  		path = r.URL.Path
   125  	}
   126  	return path
   127  }
   128  
   129  // NewRouter .
   130  func (s *server) NewRouter() RouterTx { return s.router.NewRouter() }
   131  
   132  // Router .
   133  func (s *server) Router() Router { return s.router.GetRouter() }
   134  
   135  // Use .
   136  func (s *server) Use(middleware ...MiddlewareFunc) {
   137  	s.middleware = append(s.middleware, middleware...)
   138  }
   139  
   140  // Start starts an HTTP server.
   141  func (s *server) startHTTP(address string) error {
   142  	s.e.Server.Addr = address
   143  	return s.startServer(s.e.Server)
   144  }
   145  
   146  // StartServer starts a custom http server.
   147  func (s *server) startServer(svr *http.Server) (err error) {
   148  	if svr.TLSConfig == nil {
   149  		if s.e.Listener == nil {
   150  			s.e.Listener, err = newListener(svr.Addr)
   151  			if err != nil {
   152  				return err
   153  			}
   154  		}
   155  		return svr.Serve(s.e.Listener)
   156  	}
   157  	if s.e.TLSListener == nil {
   158  		l, err := newListener(svr.Addr)
   159  		if err != nil {
   160  			return err
   161  		}
   162  		s.e.TLSListener = tls.NewListener(l, svr.TLSConfig)
   163  	}
   164  	return svr.Serve(s.e.TLSListener)
   165  }
   166  
   167  // tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
   168  // connections. It's used by ListenAndServe and ListenAndServeTLS so
   169  // dead TCP connections (e.g. closing laptop mid-download) eventually
   170  // go away.
   171  type tcpKeepAliveListener struct {
   172  	*net.TCPListener
   173  }
   174  
   175  func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
   176  	tc, err := ln.AcceptTCP()
   177  	if err != nil {
   178  		return
   179  	}
   180  	tc.SetKeepAlive(true)
   181  	tc.SetKeepAlivePeriod(3 * time.Minute)
   182  	return tc, nil
   183  }
   184  
   185  func newListener(address string) (*tcpKeepAliveListener, error) {
   186  	l, err := net.Listen("tcp", address)
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
   191  }