1
0

server.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package server
  2. import (
  3. "context"
  4. "fmt"
  5. "log/slog"
  6. "net"
  7. "net/http"
  8. "golang.org/x/net/netutil"
  9. "github.com/imgproxy/imgproxy/v3/reuseport"
  10. )
  11. const (
  12. // maxHeaderBytes represents max bytes in request header
  13. maxHeaderBytes = 1 << 20
  14. )
  15. // Server represents the HTTP server wrapper struct
  16. type Server struct {
  17. router *Router
  18. server *http.Server
  19. Addr net.Addr
  20. }
  21. // Start starts the http server. cancel is called in case server failed to start, but it happened
  22. // asynchronously. It should cancel the upstream context.
  23. func Start(cancel context.CancelFunc, router *Router) (*Server, error) {
  24. l, err := reuseport.Listen(router.config.Network, router.config.Bind, router.config.SocketReusePort)
  25. if err != nil {
  26. cancel()
  27. return nil, fmt.Errorf("can't start server: %s", err)
  28. }
  29. if router.config.MaxClients > 0 {
  30. l = netutil.LimitListener(l, router.config.MaxClients)
  31. }
  32. errLogger := slog.NewLogLogger(
  33. slog.With("source", "http_server").Handler(),
  34. slog.LevelError,
  35. )
  36. addr := l.Addr()
  37. srv := &http.Server{
  38. Handler: router,
  39. ReadTimeout: router.config.ReadRequestTimeout,
  40. MaxHeaderBytes: maxHeaderBytes,
  41. ErrorLog: errLogger,
  42. }
  43. if router.config.KeepAliveTimeout > 0 {
  44. srv.IdleTimeout = router.config.KeepAliveTimeout
  45. } else {
  46. srv.SetKeepAlivesEnabled(false)
  47. }
  48. go func() {
  49. slog.Info(fmt.Sprintf("Starting server at %s", router.config.Bind))
  50. if err := srv.Serve(l); err != nil && err != http.ErrServerClosed {
  51. slog.Error(err.Error(), "source", "http_server")
  52. }
  53. cancel()
  54. }()
  55. return &Server{
  56. router: router,
  57. server: srv,
  58. Addr: addr,
  59. }, nil
  60. }
  61. // Shutdown gracefully shuts down the server
  62. func (s *Server) Shutdown(ctx context.Context) {
  63. slog.Info("Shutting down the server...")
  64. ctx, close := context.WithTimeout(ctx, s.router.config.GracefulStopTimeout)
  65. defer close()
  66. s.server.Shutdown(ctx)
  67. }