1
0

timer.go 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  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/ierrors"
  9. )
  10. // timerSinceCtxKey represents a context key for start time.
  11. type timerSinceCtxKey struct{}
  12. // startRequestTimer starts a new request timer.
  13. func startRequestTimer(r *http.Request, timeout time.Duration) (*http.Request, context.CancelFunc) {
  14. ctx := r.Context()
  15. ctx = context.WithValue(ctx, timerSinceCtxKey{}, time.Now())
  16. ctx, cancel := context.WithTimeout(ctx, timeout)
  17. return r.WithContext(ctx), cancel
  18. }
  19. // requestStartedAt returns the duration since the timer started in the context.
  20. func requestStartedAt(ctx context.Context) time.Duration {
  21. if t, ok := ctx.Value(timerSinceCtxKey{}).(time.Time); ok {
  22. return time.Since(t)
  23. }
  24. return 0
  25. }
  26. // CheckTimeout checks if the request context has timed out or cancelled and returns
  27. // wrapped error.
  28. func CheckTimeout(ctx context.Context) error {
  29. select {
  30. case <-ctx.Done():
  31. d := requestStartedAt(ctx)
  32. err := ctx.Err()
  33. switch err {
  34. case context.Canceled:
  35. return newRequestCancelledError(d)
  36. case context.DeadlineExceeded:
  37. return newRequestTimeoutError(d)
  38. default:
  39. return ierrors.Wrap(err, 0, ierrors.WithCategory(categoryTimeout))
  40. }
  41. default:
  42. return nil
  43. }
  44. }