server.go 1.9 KB

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