1
#include "source/extensions/request_id/uuid/config.h"
2

            
3
#include "envoy/http/header_map.h"
4
#include "envoy/tracing/tracer.h"
5

            
6
#include "source/common/common/random_generator.h"
7
#include "source/common/common/utility.h"
8
#include "source/common/stream_info/stream_id_provider_impl.h"
9

            
10
namespace Envoy {
11
namespace Extensions {
12
namespace RequestId {
13

            
14
void UUIDRequestIDExtension::set(Http::RequestHeaderMap& request_headers, bool edge_request,
15
89759
                                 bool keep_external_id) {
16
89759
  const Http::HeaderEntry* request_id_header = request_headers.RequestId();
17

            
18
  // No request ID then set new one anyway.
19
89759
  if (request_id_header == nullptr || request_id_header->value().empty()) {
20
89681
    request_headers.setRequestId(random_.uuid());
21
89681
    return;
22
89681
  }
23

            
24
  // There is request ID already set and this is not an edge request. Then this is trusted
25
  // request ID. Do nothing.
26
78
  if (!edge_request) {
27
64
    return;
28
64
  }
29

            
30
  // There is request ID already set and this is an edge request. Then this is ID may cannot
31
  // be trusted.
32

            
33
14
  if (!keep_external_id) {
34
    // If we are not keeping external request ID, then set new one anyway.
35
11
    request_headers.setRequestId(random_.uuid());
36
11
    return;
37
11
  }
38

            
39
  // If we are keeping external request ID, and `pack_trace_reason` is enabled, then clear
40
  // the trace reason in the external request ID.
41
3
  if (pack_trace_reason_) {
42
3
    setTraceReason(request_headers, Tracing::Reason::NotTraceable);
43
3
  }
44
3
}
45

            
46
void UUIDRequestIDExtension::setInResponse(Http::ResponseHeaderMap& response_headers,
47
6
                                           const Http::RequestHeaderMap& request_headers) {
48
6
  if (request_headers.RequestId()) {
49
4
    response_headers.setRequestId(request_headers.getRequestIdValue());
50
4
  }
51
6
}
52

            
53
absl::optional<absl::string_view>
54
3042
UUIDRequestIDExtension::get(const Http::RequestHeaderMap& request_headers) const {
55
3042
  if (request_headers.RequestId() == nullptr) {
56
11
    return absl::nullopt;
57
11
  }
58
3031
  return request_headers.getRequestIdValue();
59
3042
}
60

            
61
absl::optional<uint64_t>
62
1500417
UUIDRequestIDExtension::getInteger(const Http::RequestHeaderMap& request_headers) const {
63
1500417
  if (request_headers.RequestId() == nullptr) {
64
1
    return absl::nullopt;
65
1
  }
66
1500416
  const std::string uuid(request_headers.getRequestIdValue());
67
1500416
  if (uuid.length() < 8) {
68
5
    return absl::nullopt;
69
5
  }
70

            
71
1500411
  uint64_t value;
72
1500411
  if (!StringUtil::atoull(uuid.substr(0, 8).c_str(), value, 16)) {
73
6
    return absl::nullopt;
74
6
  }
75

            
76
1500405
  return value;
77
1500411
}
78

            
79
Tracing::Reason
80
1000414
UUIDRequestIDExtension::getTraceReason(const Http::RequestHeaderMap& request_headers) {
81
  // If the request ID is not present or the pack trace reason is not enabled, return
82
  // NotTraceable directly.
83
1000414
  if (!pack_trace_reason_ || request_headers.RequestId() == nullptr) {
84
3
    return Tracing::Reason::NotTraceable;
85
3
  }
86
1000411
  absl::string_view uuid = request_headers.getRequestIdValue();
87
1000411
  if (uuid.length() != Random::RandomGeneratorImpl::UUID_LENGTH) {
88
1
    return Tracing::Reason::NotTraceable;
89
1
  }
90

            
91
1000410
  switch (uuid[TRACE_BYTE_POSITION]) {
92
21
  case TRACE_FORCED:
93
21
    return Tracing::Reason::ServiceForced;
94
1000003
  case TRACE_SAMPLED:
95
1000003
    return Tracing::Reason::Sampling;
96
2
  case TRACE_CLIENT:
97
2
    return Tracing::Reason::ClientForced;
98
384
  default:
99
384
    return Tracing::Reason::NotTraceable;
100
1000410
  }
101
1000410
}
102

            
103
void UUIDRequestIDExtension::setTraceReason(Http::RequestHeaderMap& request_headers,
104
1999027
                                            Tracing::Reason reason) {
105
1999027
  if (!pack_trace_reason_ || request_headers.RequestId() == nullptr) {
106
1
    return;
107
1
  }
108
1999026
  absl::string_view uuid_view = request_headers.getRequestIdValue();
109
1999026
  if (uuid_view.length() != Random::RandomGeneratorImpl::UUID_LENGTH) {
110
3
    return;
111
3
  }
112
1999023
  std::string uuid(uuid_view);
113

            
114
1999023
  switch (reason) {
115
4
  case Tracing::Reason::ServiceForced:
116
4
    uuid[TRACE_BYTE_POSITION] = TRACE_FORCED;
117
4
    break;
118
3
  case Tracing::Reason::ClientForced:
119
3
    uuid[TRACE_BYTE_POSITION] = TRACE_CLIENT;
120
3
    break;
121
1000043
  case Tracing::Reason::Sampling:
122
1000043
    uuid[TRACE_BYTE_POSITION] = TRACE_SAMPLED;
123
1000043
    break;
124
998973
  case Tracing::Reason::NotTraceable:
125
998973
    uuid[TRACE_BYTE_POSITION] = NO_TRACE;
126
998973
    break;
127
  default:
128
    break;
129
1999023
  }
130
1999023
  request_headers.setRequestId(uuid);
131
1999023
}
132

            
133
REGISTER_FACTORY(UUIDRequestIDExtensionFactory, Server::Configuration::RequestIDExtensionFactory);
134

            
135
} // namespace RequestId
136
} // namespace Extensions
137
} // namespace Envoy