timer.go 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. // timer.go contains methods for storing, retrieving and checking
  2. // timer in a request context.
  3. package server
  4. import (
  5. "context"
  6. "net/http"
  7. "time"
  8. "github.com/imgproxy/imgproxy/v3/config"
  9. "github.com/imgproxy/imgproxy/v3/ierrors"
  10. )
  11. // timerSinceCtxKey represents a context key for start time.
  12. type timerSinceCtxKey struct{}
  13. // startRequestTimer starts a new request timer.
  14. func startRequestTimer(r *http.Request) (*http.Request, context.CancelFunc) {
  15. ctx := r.Context()
  16. ctx = context.WithValue(ctx, timerSinceCtxKey{}, time.Now())
  17. ctx, cancel := context.WithTimeout(ctx, time.Duration(config.Timeout)*time.Second)
  18. return r.WithContext(ctx), cancel
  19. }
  20. // requestStartedAt returns the duration since the timer started in the context.
  21. func requestStartedAt(ctx context.Context) time.Duration {
  22. if t, ok := ctx.Value(timerSinceCtxKey{}).(time.Time); ok {
  23. return time.Since(t)
  24. }
  25. return 0
  26. }
  27. // CheckTimeout checks if the request context has timed out or cancelled and returns
  28. // wrapped error.
  29. func CheckTimeout(ctx context.Context) error {
  30. select {
  31. case <-ctx.Done():
  32. d := requestStartedAt(ctx)
  33. err := ctx.Err()
  34. switch err {
  35. case context.Canceled:
  36. return newRequestCancelledError(d)
  37. case context.DeadlineExceeded:
  38. return newRequestTimeoutError(d)
  39. default:
  40. return ierrors.Wrap(err, 0)
  41. }
  42. default:
  43. return nil
  44. }
  45. }