server.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package main
  2. import (
  3. "context"
  4. "crypto/subtle"
  5. "fmt"
  6. "net/http"
  7. "time"
  8. "golang.org/x/net/netutil"
  9. )
  10. var (
  11. imgproxyIsRunningMsg = []byte("imgproxy is running")
  12. errInvalidSecret = newError(403, "Invalid secret", "Forbidden")
  13. )
  14. func buildRouter() *router {
  15. r := newRouter()
  16. r.PanicHandler = handlePanic
  17. r.GET("/health", handleHealth)
  18. r.GET("/", withCORS(withSecret(handleProcessing)))
  19. r.OPTIONS("/", withCORS(handleOptions))
  20. return r
  21. }
  22. func startServer() *http.Server {
  23. l, err := listenReuseport("tcp", conf.Bind)
  24. if err != nil {
  25. logFatal(err.Error())
  26. }
  27. l = netutil.LimitListener(l, conf.MaxClients)
  28. s := &http.Server{
  29. Handler: buildRouter(),
  30. ReadTimeout: time.Duration(conf.ReadTimeout) * time.Second,
  31. MaxHeaderBytes: 1 << 20,
  32. }
  33. if conf.KeepAliveTimeout > 0 {
  34. s.IdleTimeout = time.Duration(conf.KeepAliveTimeout) * time.Second
  35. } else {
  36. s.SetKeepAlivesEnabled(false)
  37. }
  38. initProcessingHandler()
  39. go func() {
  40. logNotice("Starting server at %s", conf.Bind)
  41. if err := s.Serve(l); err != nil && err != http.ErrServerClosed {
  42. logFatal(err.Error())
  43. }
  44. }()
  45. return s
  46. }
  47. func shutdownServer(s *http.Server) {
  48. logNotice("Shutting down the server...")
  49. ctx, close := context.WithTimeout(context.Background(), 5*time.Second)
  50. defer close()
  51. s.Shutdown(ctx)
  52. }
  53. func withCORS(h routeHandler) routeHandler {
  54. return func(reqID string, rw http.ResponseWriter, r *http.Request) {
  55. if len(conf.AllowOrigin) > 0 {
  56. rw.Header().Set("Access-Control-Allow-Origin", conf.AllowOrigin)
  57. rw.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
  58. }
  59. h(reqID, rw, r)
  60. }
  61. }
  62. func withSecret(h routeHandler) routeHandler {
  63. if len(conf.Secret) == 0 {
  64. return h
  65. }
  66. authHeader := []byte(fmt.Sprintf("Bearer %s", conf.Secret))
  67. return func(reqID string, rw http.ResponseWriter, r *http.Request) {
  68. if subtle.ConstantTimeCompare([]byte(r.Header.Get("Authorization")), authHeader) == 1 {
  69. h(reqID, rw, r)
  70. } else {
  71. panic(errInvalidSecret)
  72. }
  73. }
  74. }
  75. func handlePanic(reqID string, rw http.ResponseWriter, r *http.Request, err error) {
  76. reportError(err, r)
  77. var (
  78. ierr *imgproxyError
  79. ok bool
  80. )
  81. if ierr, ok = err.(*imgproxyError); !ok {
  82. ierr = newUnexpectedError(err.Error(), 3)
  83. }
  84. logResponse(reqID, ierr.StatusCode, ierr.Message)
  85. rw.WriteHeader(ierr.StatusCode)
  86. if conf.DevelopmentErrorsMode {
  87. rw.Write([]byte(ierr.Message))
  88. } else {
  89. rw.Write([]byte(ierr.PublicMessage))
  90. }
  91. }
  92. func handleHealth(reqID string, rw http.ResponseWriter, r *http.Request) {
  93. logResponse(reqID, 200, string(imgproxyIsRunningMsg))
  94. rw.WriteHeader(200)
  95. rw.Write(imgproxyIsRunningMsg)
  96. }
  97. func handleOptions(reqID string, rw http.ResponseWriter, r *http.Request) {
  98. logResponse(reqID, 200, "Respond with options")
  99. rw.WriteHeader(200)
  100. }