2025-08-20 14:31:11 +02:00
|
|
|
// timer.go contains methods for storing, retrieving and checking
|
|
|
|
|
// timer in a request context.
|
|
|
|
|
package server
|
2021-04-26 17:52:50 +06:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"net/http"
|
|
|
|
|
"time"
|
|
|
|
|
|
2021-09-30 20:23:30 +06:00
|
|
|
"github.com/imgproxy/imgproxy/v3/ierrors"
|
2021-04-26 17:52:50 +06:00
|
|
|
)
|
|
|
|
|
|
2025-08-20 14:31:11 +02:00
|
|
|
// timerSinceCtxKey represents a context key for start time.
|
2024-10-02 23:43:24 +03:00
|
|
|
type timerSinceCtxKey struct{}
|
2021-04-26 17:52:50 +06:00
|
|
|
|
2025-08-20 14:31:11 +02:00
|
|
|
// startRequestTimer starts a new request timer.
|
2025-09-30 13:24:23 +02:00
|
|
|
func startRequestTimer(r *http.Request, timeout time.Duration) (*http.Request, context.CancelFunc) {
|
2022-01-14 00:18:48 +06:00
|
|
|
ctx := r.Context()
|
|
|
|
|
ctx = context.WithValue(ctx, timerSinceCtxKey{}, time.Now())
|
2025-09-30 13:24:23 +02:00
|
|
|
ctx, cancel := context.WithTimeout(ctx, timeout)
|
2022-01-14 00:18:48 +06:00
|
|
|
return r.WithContext(ctx), cancel
|
2021-04-26 17:52:50 +06:00
|
|
|
}
|
|
|
|
|
|
2025-08-20 14:31:11 +02:00
|
|
|
// requestStartedAt returns the duration since the timer started in the context.
|
|
|
|
|
func requestStartedAt(ctx context.Context) time.Duration {
|
2021-04-26 17:52:50 +06:00
|
|
|
if t, ok := ctx.Value(timerSinceCtxKey{}).(time.Time); ok {
|
|
|
|
|
return time.Since(t)
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-20 14:31:11 +02:00
|
|
|
// CheckTimeout checks if the request context has timed out or cancelled and returns
|
|
|
|
|
// wrapped error.
|
2022-07-20 15:49:05 +06:00
|
|
|
func CheckTimeout(ctx context.Context) error {
|
2021-04-26 17:52:50 +06:00
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
2025-08-20 14:31:11 +02:00
|
|
|
d := requestStartedAt(ctx)
|
2021-04-26 17:52:50 +06:00
|
|
|
|
2022-07-19 18:10:18 +06:00
|
|
|
err := ctx.Err()
|
|
|
|
|
switch err {
|
|
|
|
|
case context.Canceled:
|
2025-02-17 22:11:40 +03:00
|
|
|
return newRequestCancelledError(d)
|
2022-07-19 18:10:18 +06:00
|
|
|
case context.DeadlineExceeded:
|
2025-02-17 22:11:40 +03:00
|
|
|
return newRequestTimeoutError(d)
|
2022-07-19 18:10:18 +06:00
|
|
|
default:
|
2025-08-20 14:31:11 +02:00
|
|
|
return ierrors.Wrap(err, 0, ierrors.WithCategory(categoryTimeout))
|
2021-04-26 17:52:50 +06:00
|
|
|
}
|
|
|
|
|
default:
|
2022-07-20 15:49:05 +06:00
|
|
|
return nil
|
2021-04-26 17:52:50 +06:00
|
|
|
}
|
|
|
|
|
}
|