-
Notifications
You must be signed in to change notification settings - Fork 3.4k
/
propagation.go
90 lines (70 loc) · 2.77 KB
/
propagation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package querylimits
import (
"context"
"encoding/json"
"net/http"
"github.com/prometheus/common/model"
"github.com/grafana/loki/v3/pkg/util/flagext"
)
// Context key type used to avoid collisions
type key int
const (
queryLimitsContextKey key = 1
HTTPHeaderQueryLimitsKey = "X-Loki-Query-Limits"
)
// NOTE: we use custom `model.Duration` instead of standard `time.Duration` because,
// to support user-friendly duration format (e.g: "1h30m45s") in JSON value.
type QueryLimits struct {
MaxQueryLength model.Duration `json:"maxQueryLength,omitempty"`
MaxQueryRange model.Duration `json:"maxQueryInterval,omitempty"`
MaxQueryLookback model.Duration `json:"maxQueryLookback,omitempty"`
MaxEntriesLimitPerQuery int `json:"maxEntriesLimitPerQuery,omitempty"`
QueryTimeout model.Duration `json:"maxQueryTime,omitempty"`
RequiredLabels []string `json:"requiredLabels,omitempty"`
RequiredNumberLabels int `json:"minimumLabelsNumber,omitempty"`
MaxQueryBytesRead flagext.ByteSize `json:"maxQueryBytesRead,omitempty"`
}
func UnmarshalQueryLimits(data []byte) (*QueryLimits, error) {
limits := &QueryLimits{}
err := json.Unmarshal(data, limits)
return limits, err
}
func MarshalQueryLimits(limits *QueryLimits) ([]byte, error) {
return json.Marshal(limits)
}
// InjectQueryLimitsHTTP adds the query limits to the request headers.
func InjectQueryLimitsHTTP(r *http.Request, limits *QueryLimits) error {
return InjectQueryLimitsHeader(&r.Header, limits)
}
// InjectQueryLimitsHeader adds the query limits to the headers.
func InjectQueryLimitsHeader(h *http.Header, limits *QueryLimits) error {
// Ensure any existing policy sets are erased
h.Del(HTTPHeaderQueryLimitsKey)
encodedLimits, err := MarshalQueryLimits(limits)
if err != nil {
return err
}
h.Add(HTTPHeaderQueryLimitsKey, string(encodedLimits))
return nil
}
// ExtractQueryLimitsHTTP retrieves the query limit policy from the HTTP header and returns it.
func ExtractQueryLimitsHTTP(r *http.Request) (*QueryLimits, error) {
headerValues := r.Header.Values(HTTPHeaderQueryLimitsKey)
// Iterate through each set header value
for _, headerValue := range headerValues {
return UnmarshalQueryLimits([]byte(headerValue))
}
return nil, nil
}
// ExtractQueryLimitsContext gets the embedded limits from the context
func ExtractQueryLimitsContext(ctx context.Context) *QueryLimits {
source, ok := ctx.Value(queryLimitsContextKey).(*QueryLimits)
if !ok {
return nil
}
return source
}
// InjectQueryLimitsContext returns a derived context containing the provided query limits
func InjectQueryLimitsContext(ctx context.Context, limits QueryLimits) context.Context {
return context.WithValue(ctx, interface{}(queryLimitsContextKey), &limits)
}