1
#pragma once
2

            
3
#include <string>
4

            
5
#include "envoy/http/header_map.h"
6

            
7
#include "source/common/singleton/const_singleton.h"
8
#include "source/common/singleton/threadsafe_singleton.h"
9

            
10
namespace Envoy {
11
namespace Http {
12

            
13
// This class allows early override of the x-envoy prefix from bootstrap config,
14
// so that servers can configure their own x-custom-string prefix.
15
//
16
// Once the HeaderValues const singleton has been created, changing the prefix
17
// is disallowed. Essentially this is write-once then read-only.
18
class PrefixValue {
19
public:
20
38777
  const char* prefix() {
21
38777
    absl::WriterMutexLock lock(&m_);
22
38777
    read_ = true;
23
38777
    return prefix_.c_str();
24
38777
  }
25

            
26
  // The char* prefix is used directly, so must be available for the interval where prefix() may be
27
  // called.
28
1
  void setPrefix(const char* prefix) {
29
1
    absl::WriterMutexLock lock(&m_);
30
    // The check for unchanged string is purely for integration tests - this
31
    // should not happen in production.
32
1
    RELEASE_ASSERT(!read_ || prefix_ == std::string(prefix),
33
1
                   "Attempting to change the header prefix after it has been used!");
34
1
    if (!read_) {
35
      prefix_ = prefix;
36
    }
37
1
  }
38

            
39
private:
40
  absl::Mutex m_;
41
  bool read_ = false;
42
  std::string prefix_ = "x-envoy";
43
};
44

            
45
/**
46
 * These are headers that are used in extension custom O(1) header registration. These headers
47
 * *must* not contain any prefix override headers, as static init order requires that HeaderValues
48
 * be instantiated for the first time after bootstrap is loaded and before the header maps are
49
 * finalized.
50
 */
51
class CustomHeaderValues {
52
public:
53
  const LowerCaseString Accept{"accept"};
54
  const LowerCaseString AcceptEncoding{"accept-encoding"};
55
  const LowerCaseString AccessControlRequestHeaders{"access-control-request-headers"};
56
  const LowerCaseString AccessControlRequestMethod{"access-control-request-method"};
57
  const LowerCaseString AccessControlAllowOrigin{"access-control-allow-origin"};
58
  const LowerCaseString AccessControlAllowHeaders{"access-control-allow-headers"};
59
  const LowerCaseString AccessControlAllowMethods{"access-control-allow-methods"};
60
  const LowerCaseString AccessControlExposeHeaders{"access-control-expose-headers"};
61
  const LowerCaseString AccessControlMaxAge{"access-control-max-age"};
62
  const LowerCaseString AccessControlAllowCredentials{"access-control-allow-credentials"};
63
  const LowerCaseString AccessControlRequestPrviateNetwork{
64
      "access-control-request-private-network"};
65
  const LowerCaseString AccessControlAllowPrviateNetwork{"access-control-allow-private-network"};
66
  const LowerCaseString Age{"age"};
67
  const LowerCaseString AltSvc{"alt-svc"};
68
  const LowerCaseString Authentication{"authentication"};
69
  const LowerCaseString Authorization{"authorization"};
70
  const LowerCaseString CacheControl{"cache-control"};
71
  const LowerCaseString CacheStatus{"cache-status"};
72
  const LowerCaseString CdnLoop{"cdn-loop"};
73
  const LowerCaseString ContentEncoding{"content-encoding"};
74
  const LowerCaseString ConnectAcceptEncoding{"connect-accept-encoding"};
75
  const LowerCaseString ConnectContentEncoding{"connect-content-encoding"};
76
  const LowerCaseString ConnectProtocolVersion{"connect-protocol-version"};
77
  const LowerCaseString ConnectTimeoutMs{"connect-timeout-ms"};
78
  const LowerCaseString Etag{"etag"};
79
  const LowerCaseString Expires{"expires"};
80
  const LowerCaseString GrpcAcceptEncoding{"grpc-accept-encoding"};
81
  const LowerCaseString GrpcEncoding{"grpc-encoding"};
82
  const LowerCaseString GrpcMessageType{"grpc-message-type"};
83
  const LowerCaseString GrpcTimeout{"grpc-timeout"};
84
  const LowerCaseString IfMatch{"if-match"};
85
  const LowerCaseString IfNoneMatch{"if-none-match"};
86
  const LowerCaseString IfModifiedSince{"if-modified-since"};
87
  const LowerCaseString IfUnmodifiedSince{"if-unmodified-since"};
88
  const LowerCaseString IfRange{"if-range"};
89
  const LowerCaseString LastModified{"last-modified"};
90
  const LowerCaseString Origin{"origin"};
91
  const LowerCaseString OtSpanContext{"x-ot-span-context"};
92
  const LowerCaseString Pragma{"pragma"};
93
  const LowerCaseString Referer{"referer"};
94
  const LowerCaseString Vary{"vary"};
95

            
96
  struct {
97
    const std::string Gzip{"gzip"};
98
    const std::string Identity{"identity"};
99
    const std::string Wildcard{"*"};
100
  } AcceptEncodingValues;
101

            
102
  struct {
103
    const std::string All{"*"};
104
  } AccessControlAllowOriginValue;
105

            
106
  struct {
107
    const std::string NoCache{"no-cache"};
108
    const std::string NoCacheMaxAge0{"no-cache, max-age=0"};
109
    const std::string NoTransform{"no-transform"};
110
    const std::string Private{"private"};
111
  } CacheControlValues;
112

            
113
  struct {
114
    const std::string Brotli{"br"};
115
    const std::string Gzip{"gzip"};
116
    const std::string Zstd{"zstd"};
117
  } ContentEncodingValues;
118

            
119
  struct {
120
    const std::string True{"true"};
121
  } CORSValues;
122

            
123
  struct {
124
    const std::string Default{"identity"};
125
  } GrpcAcceptEncodingValues;
126

            
127
  struct {
128
    const std::string AcceptEncoding{"Accept-Encoding"};
129
    const std::string Wildcard{"*"};
130
  } VaryValues;
131
};
132

            
133
using CustomHeaders = ConstSingleton<CustomHeaderValues>;
134

            
135
/**
136
 * Constant HTTP headers and values. All lower case. This group of headers can contain prefix
137
 * override headers.
138
 */
139
class HeaderValues {
140
public:
141
38671
  const char* prefix() const { return ThreadSafeSingleton<PrefixValue>::get().prefix(); }
142

            
143
  const LowerCaseString ProxyAuthenticate{"proxy-authenticate"};
144
  const LowerCaseString ProxyAuthorization{"proxy-authorization"};
145
  const LowerCaseString CapsuleProtocol{"capsule-protocol"};
146
  const LowerCaseString ClientTraceId{"x-client-trace-id"};
147
  const LowerCaseString Connection{"connection"};
148
  const LowerCaseString ContentLength{"content-length"};
149
  const LowerCaseString ContentRange{"content-range"};
150
  const LowerCaseString ContentType{"content-type"};
151
  const LowerCaseString Cookie{"cookie"};
152
  const LowerCaseString Date{"date"};
153
  const LowerCaseString EnvoyAttemptCount{absl::StrCat(prefix(), "-attempt-count")};
154
  const LowerCaseString EnvoyCluster{absl::StrCat(prefix(), "-cluster")};
155
  const LowerCaseString EnvoyDegraded{absl::StrCat(prefix(), "-degraded")};
156
  const LowerCaseString EnvoyDownstreamServiceCluster{
157
      absl::StrCat(prefix(), "-downstream-service-cluster")};
158
  const LowerCaseString EnvoyDownstreamServiceNode{
159
      absl::StrCat(prefix(), "-downstream-service-node")};
160
  const LowerCaseString EnvoyExternalAddress{absl::StrCat(prefix(), "-external-address")};
161
  const LowerCaseString EnvoyForceTrace{absl::StrCat(prefix(), "-force-trace")};
162
  const LowerCaseString EnvoyHedgeOnPerTryTimeout{
163
      absl::StrCat(prefix(), "-hedge-on-per-try-timeout")};
164
  const LowerCaseString EnvoyImmediateHealthCheckFail{
165
      absl::StrCat(prefix(), "-immediate-health-check-fail")};
166
  const LowerCaseString EnvoyIsTimeoutRetry{absl::StrCat(prefix(), "-is-timeout-retry")};
167
  const LowerCaseString EnvoyOriginalUrl{absl::StrCat(prefix(), "-original-url")};
168
  const LowerCaseString EnvoyInternalRequest{absl::StrCat(prefix(), "-internal")};
169
  // TODO(mattklein123): EnvoyIpTags should be a custom header registered with the IP tagging
170
  // filter. We need to figure out if we can remove this header from the set of headers that
171
  // participate in prefix overrides.
172
  const LowerCaseString EnvoyIpTags{absl::StrCat(prefix(), "-ip-tags")};
173
  const LowerCaseString EnvoyLocalOverloaded{absl::StrCat(prefix(), "-local-overloaded")};
174
  const LowerCaseString EnvoyMaxRetries{absl::StrCat(prefix(), "-max-retries")};
175
  const LowerCaseString EnvoyNotForwarded{absl::StrCat(prefix(), "-not-forwarded")};
176
  const LowerCaseString EnvoyOriginalDstHost{absl::StrCat(prefix(), "-original-dst-host")};
177
  const LowerCaseString EnvoyOriginalMethod{absl::StrCat(prefix(), "-original-method")};
178
  const LowerCaseString EnvoyOriginalPath{absl::StrCat(prefix(), "-original-path")};
179
  const LowerCaseString EnvoyOriginalHost{absl::StrCat(prefix(), "-original-host")};
180
  const LowerCaseString EnvoyOverloaded{absl::StrCat(prefix(), "-overloaded")};
181
  const LowerCaseString EnvoyDropOverload{absl::StrCat(prefix(), "-drop-overload")};
182
  const LowerCaseString EnvoyUnconditionalDropOverload{
183
      absl::StrCat(prefix(), "-unconditional-drop-overload")};
184
  const LowerCaseString EnvoyRateLimited{absl::StrCat(prefix(), "-ratelimited")};
185
  const LowerCaseString EnvoyRetryOn{absl::StrCat(prefix(), "-retry-on")};
186
  const LowerCaseString EnvoyRetryGrpcOn{absl::StrCat(prefix(), "-retry-grpc-on")};
187
  const LowerCaseString EnvoyRetriableStatusCodes{
188
      absl::StrCat(prefix(), "-retriable-status-codes")};
189
  const LowerCaseString EnvoyRetriableHeaderNames{
190
      absl::StrCat(prefix(), "-retriable-header-names")};
191
  const LowerCaseString EnvoyUpstreamAltStatName{absl::StrCat(prefix(), "-upstream-alt-stat-name")};
192
  const LowerCaseString EnvoyUpstreamCanary{absl::StrCat(prefix(), "-upstream-canary")};
193
  const LowerCaseString EnvoyUpstreamHostAddress{absl::StrCat(prefix(), "-upstream-host-address")};
194
  const LowerCaseString EnvoyUpstreamHostname{absl::StrCat(prefix(), "-upstream-hostname")};
195
  const LowerCaseString EnvoyUpstreamRequestTimeoutAltResponse{
196
      absl::StrCat(prefix(), "-upstream-rq-timeout-alt-response")};
197
  const LowerCaseString EnvoyUpstreamRequestTimeoutMs{
198
      absl::StrCat(prefix(), "-upstream-rq-timeout-ms")};
199
  const LowerCaseString EnvoyUpstreamRequestPerTryTimeoutMs{
200
      absl::StrCat(prefix(), "-upstream-rq-per-try-timeout-ms")};
201
  const LowerCaseString EnvoyExpectedRequestTimeoutMs{
202
      absl::StrCat(prefix(), "-expected-rq-timeout-ms")};
203
  const LowerCaseString EnvoyUpstreamServiceTime{absl::StrCat(prefix(), "-upstream-service-time")};
204
  const LowerCaseString EnvoyUpstreamHealthCheckedCluster{
205
      absl::StrCat(prefix(), "-upstream-healthchecked-cluster")};
206
  const LowerCaseString EnvoyUpstreamStreamDurationMs{
207
      absl::StrCat(prefix(), "-upstream-stream-duration-ms")};
208
  const LowerCaseString EnvoyDecoratorOperation{absl::StrCat(prefix(), "-decorator-operation")};
209
  const LowerCaseString EnvoyCompressionStatus{absl::StrCat(prefix(), "-compression-status")};
210
  const LowerCaseString Expect{"expect"};
211
  const LowerCaseString ForwardedClientCert{"x-forwarded-client-cert"};
212
  const LowerCaseString ForwardedFor{"x-forwarded-for"};
213
  const LowerCaseString ForwardedHost{"x-forwarded-host"};
214
  const LowerCaseString ForwardedPort{"x-forwarded-port"};
215
  const LowerCaseString ForwardedProto{"x-forwarded-proto"};
216
  const LowerCaseString GrpcMessage{"grpc-message"};
217
  const LowerCaseString GrpcStatus{"grpc-status"};
218
  const LowerCaseString GrpcTimeout{"grpc-timeout"};
219
  const LowerCaseString GrpcStatusDetailsBin{"grpc-status-details-bin"};
220
  const LowerCaseString Host{":authority"};
221
  const LowerCaseString HostLegacy{"host"};
222
  const LowerCaseString Http2Settings{"http2-settings"};
223
  const LowerCaseString KeepAlive{"keep-alive"};
224
  const LowerCaseString Location{"location"};
225
  const LowerCaseString Method{":method"};
226
  const LowerCaseString Path{":path"};
227
  const LowerCaseString Protocol{":protocol"};
228
  const LowerCaseString ProxyConnection{"proxy-connection"};
229
  const LowerCaseString ProxyStatus{"proxy-status"};
230
  const LowerCaseString Range{"range"};
231
  const LowerCaseString RequestId{"x-request-id"};
232
  const LowerCaseString Scheme{":scheme"};
233
  const LowerCaseString Server{"server"};
234
  const LowerCaseString SetCookie{"set-cookie"};
235
  const LowerCaseString Status{":status"};
236
  const LowerCaseString TransferEncoding{"transfer-encoding"};
237
  const LowerCaseString TE{"te"};
238
  const LowerCaseString Upgrade{"upgrade"};
239
  const LowerCaseString UserAgent{"user-agent"};
240
  const LowerCaseString Via{"via"};
241
  const LowerCaseString WWWAuthenticate{"www-authenticate"};
242
  const LowerCaseString XContentTypeOptions{"x-content-type-options"};
243
  const LowerCaseString EarlyData{"early-data"};
244

            
245
  struct {
246
    const std::string Close{"close"};
247
    const std::string Http2Settings{"http2-settings"};
248
    const std::string KeepAlive{"keep-alive"};
249
    const std::string Upgrade{"upgrade"};
250
  } ConnectionValues;
251

            
252
  struct {
253
    const std::string H2c{"h2c"};
254
    const std::string WebSocket{"websocket"};
255
    const std::string ConnectUdp{"connect-udp"};
256
  } UpgradeValues;
257

            
258
  struct {
259
    const std::string Text{"text/plain"};
260
    const std::string TextEventStream{"text/event-stream"};
261
    const std::string TextUtf8{"text/plain; charset=UTF-8"}; // TODO(jmarantz): fold this into Text
262
    const std::string Html{"text/html; charset=UTF-8"};
263
    const std::string Connect{"application/connect"};
264
    const std::string ConnectProto{"application/connect+proto"};
265
    const std::string Grpc{"application/grpc"};
266
    const std::string GrpcWeb{"application/grpc-web"};
267
    const std::string GrpcWebProto{"application/grpc-web+proto"};
268
    const std::string GrpcWebText{"application/grpc-web-text"};
269
    const std::string GrpcWebTextProto{"application/grpc-web-text+proto"};
270
    const std::string Json{"application/json"};
271
    const std::string Protobuf{"application/x-protobuf"};
272
    const std::string FormUrlEncoded{"application/x-www-form-urlencoded"};
273
    const std::string Thrift{"application/x-thrift"};
274
  } ContentTypeValues;
275

            
276
  struct {
277
    const std::string True{"true"};
278
  } EnvoyImmediateHealthCheckFailValues;
279

            
280
  struct {
281
    const std::string True{"true"};
282
  } EnvoyInternalRequestValues;
283

            
284
  struct {
285
    const std::string True{"true"};
286
  } EnvoyOverloadedValues;
287

            
288
  struct {
289
    const std::string True{"true"};
290
  } EnvoyDropOverloadValues;
291

            
292
  struct {
293
    const std::string True{"true"};
294
  } EnvoyUnconditionalDropOverloadValues;
295

            
296
  struct {
297
    const std::string True{"true"};
298
  } EnvoyRateLimitedValues;
299

            
300
  struct {
301
    const std::string _5xx{"5xx"};
302
    const std::string GatewayError{"gateway-error"};
303
    const std::string ConnectFailure{"connect-failure"};
304
    const std::string EnvoyRateLimited{"envoy-ratelimited"};
305
    const std::string RefusedStream{"refused-stream"};
306
    const std::string Retriable4xx{"retriable-4xx"};
307
    const std::string RetriableStatusCodes{"retriable-status-codes"};
308
    const std::string RetriableHeaders{"retriable-headers"};
309
    const std::string Reset{"reset"};
310
    const std::string ResetBeforeRequest{"reset-before-request"};
311
    const std::string Http3PostConnectFailure{"http3-post-connect-failure"};
312
  } EnvoyRetryOnValues;
313

            
314
  struct {
315
    const std::string Cancelled{"cancelled"};
316
    const std::string DeadlineExceeded{"deadline-exceeded"};
317
    const std::string ResourceExhausted{"resource-exhausted"};
318
    const std::string Unavailable{"unavailable"};
319
    const std::string Internal{"internal"};
320
  } EnvoyRetryOnGrpcValues;
321

            
322
  struct {
323
    const std::string _100Continue{"100-continue"};
324
  } ExpectValues;
325

            
326
  struct {
327
    const std::string Connect{"CONNECT"};
328
    const std::string Delete{"DELETE"};
329
    const std::string Get{"GET"};
330
    const std::string Head{"HEAD"};
331
    const std::string Options{"OPTIONS"};
332
    const std::string Patch{"PATCH"};
333
    const std::string Post{"POST"};
334
    const std::string Put{"PUT"};
335
    const std::string Trace{"TRACE"};
336
  } MethodValues;
337

            
338
  struct {
339
    // per https://tools.ietf.org/html/draft-kinnear-httpbis-http2-transport-02
340
    const std::string Bytestream{"bytestream"};
341
  } ProtocolValues;
342

            
343
  struct {
344
    const std::string Http{"http"};
345
    const std::string Https{"https"};
346
  } SchemeValues;
347

            
348
  struct {
349
    const std::string Brotli{"br"};
350
    const std::string Compress{"compress"};
351
    const std::string Chunked{"chunked"};
352
    const std::string Deflate{"deflate"};
353
    const std::string Gzip{"gzip"};
354
    const std::string Identity{"identity"};
355
    const std::string Zstd{"zstd"};
356
  } TransferEncodingValues;
357

            
358
  struct {
359
    const std::string EnvoyHealthChecker{"Envoy/HC"};
360
    const std::string GoBrowser{"Go-browser"};
361
  } UserAgentValues;
362

            
363
  struct {
364
    const std::string Trailers{"trailers"};
365
  } TEValues;
366

            
367
  struct {
368
    const std::string Nosniff{"nosniff"};
369
  } XContentTypeOptionValues;
370

            
371
  struct {
372
    const std::string Http10String{"HTTP/1.0"};
373
    const std::string Http11String{"HTTP/1.1"};
374
    const std::string Http2String{"HTTP/2"};
375
    const std::string Http3String{"HTTP/3"};
376
  } ProtocolStrings;
377

            
378
  struct {
379
    const std::string ContentLengthTooSmall{"ContentLengthTooSmall"};
380
    const std::string ContentTypeNotAllowed{"ContentTypeNotAllowed"};
381
    const std::string EtagNotAllowed{"EtagNotAllowed"};
382
    const std::string StatusCodeNotAllowed{"StatusCodeNotAllowed"};
383
    const std::string Compressed{"Compressed"};
384
    const std::string OriginalLengthPrefix{"OriginalLength="};
385
    const std::string Separator{";"};
386
    const std::string ValueSeparator{","};
387
  } EnvoyCompressionStatusValues;
388
};
389

            
390
using Headers = ConstSingleton<HeaderValues>;
391

            
392
} // namespace Http
393
} // namespace Envoy