/proc/self/cwd/source/common/http/status.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "source/common/http/status.h" |
2 | | |
3 | | #include "source/common/common/assert.h" |
4 | | |
5 | | #include "absl/strings/str_cat.h" |
6 | | |
7 | | namespace Envoy { |
8 | | namespace Http { |
9 | | |
10 | | namespace { |
11 | | |
12 | | constexpr absl::string_view EnvoyPayloadUrl = "Envoy"; |
13 | | |
14 | 0 | absl::string_view statusCodeToString(StatusCode code) { |
15 | 0 | switch (code) { |
16 | 0 | case StatusCode::Ok: |
17 | 0 | return "OK"; |
18 | 0 | case StatusCode::CodecProtocolError: |
19 | 0 | return "CodecProtocolError"; |
20 | 0 | case StatusCode::BufferFloodError: |
21 | 0 | return "BufferFloodError"; |
22 | 0 | case StatusCode::PrematureResponseError: |
23 | 0 | return "PrematureResponseError"; |
24 | 0 | case StatusCode::CodecClientError: |
25 | 0 | return "CodecClientError"; |
26 | 0 | case StatusCode::InboundFramesWithEmptyPayload: |
27 | 0 | return "InboundFramesWithEmptyPayloadError"; |
28 | 0 | case StatusCode::EnvoyOverloadError: |
29 | 0 | return "EnvoyOverloadError"; |
30 | 0 | } |
31 | 0 | return ""; |
32 | 0 | } |
33 | | |
34 | | struct EnvoyStatusPayload { |
35 | 81.6k | EnvoyStatusPayload(StatusCode status_code) : status_code_(status_code) {} |
36 | | const StatusCode status_code_; |
37 | | }; |
38 | | |
39 | | struct PrematureResponsePayload : public EnvoyStatusPayload { |
40 | | PrematureResponsePayload(Http::Code http_code) |
41 | 715 | : EnvoyStatusPayload(StatusCode::PrematureResponseError), http_code_(http_code) {} |
42 | | const Http::Code http_code_; |
43 | | }; |
44 | | |
45 | 81.6k | template <typename T> void storePayload(absl::Status& status, const T& payload) { |
46 | 81.6k | const T* allocated = new T(payload); |
47 | 81.6k | const absl::string_view sv = |
48 | 81.6k | absl::string_view(reinterpret_cast<const char*>(allocated), sizeof(T)); |
49 | 81.6k | absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; }); status.cc:Envoy::Http::(anonymous namespace)::storePayload<Envoy::Http::(anonymous namespace)::EnvoyStatusPayload>(absl::lts_20230802::Status&, Envoy::Http::(anonymous namespace)::EnvoyStatusPayload const&)::{lambda()#1}::operator()() const Line | Count | Source | 49 | 80.9k | absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; }); |
status.cc:Envoy::Http::(anonymous namespace)::storePayload<Envoy::Http::(anonymous namespace)::PrematureResponsePayload>(absl::lts_20230802::Status&, Envoy::Http::(anonymous namespace)::PrematureResponsePayload const&)::{lambda()#1}::operator()() const Line | Count | Source | 49 | 715 | absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; }); |
|
50 | 81.6k | cord.Flatten(); // Flatten ahead of time for easier access later. |
51 | 81.6k | status.SetPayload(EnvoyPayloadUrl, std::move(cord)); |
52 | 81.6k | } status.cc:void Envoy::Http::(anonymous namespace)::storePayload<Envoy::Http::(anonymous namespace)::EnvoyStatusPayload>(absl::lts_20230802::Status&, Envoy::Http::(anonymous namespace)::EnvoyStatusPayload const&) Line | Count | Source | 45 | 80.9k | template <typename T> void storePayload(absl::Status& status, const T& payload) { | 46 | 80.9k | const T* allocated = new T(payload); | 47 | 80.9k | const absl::string_view sv = | 48 | 80.9k | absl::string_view(reinterpret_cast<const char*>(allocated), sizeof(T)); | 49 | 80.9k | absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; }); | 50 | 80.9k | cord.Flatten(); // Flatten ahead of time for easier access later. | 51 | 80.9k | status.SetPayload(EnvoyPayloadUrl, std::move(cord)); | 52 | 80.9k | } |
status.cc:void Envoy::Http::(anonymous namespace)::storePayload<Envoy::Http::(anonymous namespace)::PrematureResponsePayload>(absl::lts_20230802::Status&, Envoy::Http::(anonymous namespace)::PrematureResponsePayload const&) Line | Count | Source | 45 | 715 | template <typename T> void storePayload(absl::Status& status, const T& payload) { | 46 | 715 | const T* allocated = new T(payload); | 47 | 715 | const absl::string_view sv = | 48 | 715 | absl::string_view(reinterpret_cast<const char*>(allocated), sizeof(T)); | 49 | 715 | absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; }); | 50 | 715 | cord.Flatten(); // Flatten ahead of time for easier access later. | 51 | 715 | status.SetPayload(EnvoyPayloadUrl, std::move(cord)); | 52 | 715 | } |
|
53 | | |
54 | 5.09k | template <typename T = EnvoyStatusPayload> const T& getPayload(const absl::Status& status) { |
55 | | // The only way to get a reference to the payload owned by the absl::Status is through the |
56 | | // ForEachPayload method. All other methods create a copy of the payload, which is not convenient |
57 | | // for peeking at the payload value. |
58 | 5.09k | const T* payload = nullptr; |
59 | 5.09k | status.ForEachPayload([&payload](absl::string_view url, const absl::Cord& cord) { |
60 | 5.09k | if (url == EnvoyPayloadUrl) { |
61 | 5.09k | ASSERT(!payload); // Status API guarantees to have one payload with given URL |
62 | 5.09k | auto data = cord.TryFlat(); |
63 | 5.09k | ASSERT(data.has_value()); // EnvoyPayloadUrl cords are flattened ahead of time |
64 | 5.09k | ASSERT(data.value().length() >= sizeof(T), "Invalid payload length"); |
65 | 5.09k | payload = reinterpret_cast<const T*>(data.value().data()); |
66 | 5.09k | } |
67 | 5.09k | }); status.cc:Envoy::Http::(anonymous namespace)::getPayload<Envoy::Http::(anonymous namespace)::EnvoyStatusPayload>(absl::lts_20230802::Status const&)::{lambda(std::__1::basic_string_view<char, std::__1::char_traits<char> >, absl::lts_20230802::Cord const&)#1}::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >, absl::lts_20230802::Cord const&) const Line | Count | Source | 59 | 5.09k | status.ForEachPayload([&payload](absl::string_view url, const absl::Cord& cord) { | 60 | 5.09k | if (url == EnvoyPayloadUrl) { | 61 | 5.09k | ASSERT(!payload); // Status API guarantees to have one payload with given URL | 62 | 5.09k | auto data = cord.TryFlat(); | 63 | 5.09k | ASSERT(data.has_value()); // EnvoyPayloadUrl cords are flattened ahead of time | 64 | 5.09k | ASSERT(data.value().length() >= sizeof(T), "Invalid payload length"); | 65 | 5.09k | payload = reinterpret_cast<const T*>(data.value().data()); | 66 | 5.09k | } | 67 | 5.09k | }); |
Unexecuted instantiation: status.cc:Envoy::Http::(anonymous namespace)::getPayload<Envoy::Http::(anonymous namespace)::PrematureResponsePayload>(absl::lts_20230802::Status const&)::{lambda(std::__1::basic_string_view<char, std::__1::char_traits<char> >, absl::lts_20230802::Cord const&)#1}::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >, absl::lts_20230802::Cord const&) const |
68 | 5.09k | ASSERT(payload); |
69 | 5.09k | return *payload; |
70 | 5.09k | } status.cc:Envoy::Http::(anonymous namespace)::EnvoyStatusPayload const& Envoy::Http::(anonymous namespace)::getPayload<Envoy::Http::(anonymous namespace)::EnvoyStatusPayload>(absl::lts_20230802::Status const&) Line | Count | Source | 54 | 5.09k | template <typename T = EnvoyStatusPayload> const T& getPayload(const absl::Status& status) { | 55 | | // The only way to get a reference to the payload owned by the absl::Status is through the | 56 | | // ForEachPayload method. All other methods create a copy of the payload, which is not convenient | 57 | | // for peeking at the payload value. | 58 | 5.09k | const T* payload = nullptr; | 59 | 5.09k | status.ForEachPayload([&payload](absl::string_view url, const absl::Cord& cord) { | 60 | 5.09k | if (url == EnvoyPayloadUrl) { | 61 | 5.09k | ASSERT(!payload); // Status API guarantees to have one payload with given URL | 62 | 5.09k | auto data = cord.TryFlat(); | 63 | 5.09k | ASSERT(data.has_value()); // EnvoyPayloadUrl cords are flattened ahead of time | 64 | 5.09k | ASSERT(data.value().length() >= sizeof(T), "Invalid payload length"); | 65 | 5.09k | payload = reinterpret_cast<const T*>(data.value().data()); | 66 | 5.09k | } | 67 | 5.09k | }); | 68 | 5.09k | ASSERT(payload); | 69 | 5.09k | return *payload; | 70 | 5.09k | } |
Unexecuted instantiation: status.cc:Envoy::Http::(anonymous namespace)::PrematureResponsePayload const& Envoy::Http::(anonymous namespace)::getPayload<Envoy::Http::(anonymous namespace)::PrematureResponsePayload>(absl::lts_20230802::Status const&) |
71 | | |
72 | | } // namespace |
73 | | |
74 | 0 | std::string toString(const Status& status) { |
75 | 0 | if (status.ok()) { |
76 | 0 | return status.ToString(); |
77 | 0 | } |
78 | 0 | std::string text; |
79 | 0 | auto status_code = getStatusCode(status); |
80 | 0 | if (status_code != StatusCode::PrematureResponseError) { |
81 | 0 | absl::StrAppend(&text, statusCodeToString(status_code), ": ", status.message()); |
82 | 0 | } else { |
83 | 0 | auto http_code = getPrematureResponseHttpCode(status); |
84 | 0 | absl::StrAppend(&text, "PrematureResponseError: HTTP code: ", http_code, ": ", |
85 | 0 | status.message()); |
86 | 0 | } |
87 | 0 | return text; |
88 | 0 | } |
89 | | |
90 | 80.6k | Status codecProtocolError(absl::string_view message) { |
91 | 80.6k | absl::Status status(absl::StatusCode::kInternal, message); |
92 | 80.6k | storePayload(status, EnvoyStatusPayload(StatusCode::CodecProtocolError)); |
93 | 80.6k | return status; |
94 | 80.6k | } |
95 | | |
96 | 72 | Status bufferFloodError(absl::string_view message) { |
97 | 72 | absl::Status status(absl::StatusCode::kInternal, message); |
98 | 72 | storePayload(status, EnvoyStatusPayload(StatusCode::BufferFloodError)); |
99 | 72 | return status; |
100 | 72 | } |
101 | | |
102 | 715 | Status prematureResponseError(absl::string_view message, Http::Code http_code) { |
103 | 715 | absl::Status status(absl::StatusCode::kInternal, message); |
104 | 715 | storePayload(status, PrematureResponsePayload(http_code)); |
105 | 715 | return status; |
106 | 715 | } |
107 | | |
108 | 47 | Status codecClientError(absl::string_view message) { |
109 | 47 | absl::Status status(absl::StatusCode::kInternal, message); |
110 | 47 | storePayload(status, EnvoyStatusPayload(StatusCode::CodecClientError)); |
111 | 47 | return status; |
112 | 47 | } |
113 | | |
114 | 119 | Status inboundFramesWithEmptyPayloadError() { |
115 | 119 | absl::Status status(absl::StatusCode::kInternal, |
116 | 119 | "Too many consecutive frames with an empty payload"); |
117 | 119 | storePayload(status, EnvoyStatusPayload(StatusCode::InboundFramesWithEmptyPayload)); |
118 | 119 | return status; |
119 | 119 | } |
120 | | |
121 | 0 | Status envoyOverloadError(absl::string_view message) { |
122 | 0 | absl::Status status(absl::StatusCode::kInternal, message); |
123 | 0 | storePayload(status, EnvoyStatusPayload(StatusCode::EnvoyOverloadError)); |
124 | 0 | return status; |
125 | 0 | } |
126 | | |
127 | | // Methods for checking and extracting error information |
128 | 977k | StatusCode getStatusCode(const Status& status) { |
129 | 977k | return status.ok() ? StatusCode::Ok : getPayload(status).status_code_; |
130 | 977k | } |
131 | | |
132 | 245k | bool isCodecProtocolError(const Status& status) { |
133 | 245k | return getStatusCode(status) == StatusCode::CodecProtocolError; |
134 | 245k | } |
135 | | |
136 | 244k | bool isBufferFloodError(const Status& status) { |
137 | 244k | return getStatusCode(status) == StatusCode::BufferFloodError; |
138 | 244k | } |
139 | | |
140 | 486 | bool isPrematureResponseError(const Status& status) { |
141 | 486 | return getStatusCode(status) == StatusCode::PrematureResponseError; |
142 | 486 | } |
143 | | |
144 | 0 | Http::Code getPrematureResponseHttpCode(const Status& status) { |
145 | 0 | const auto& payload = getPayload<PrematureResponsePayload>(status); |
146 | 0 | ASSERT(payload.status_code_ == StatusCode::PrematureResponseError, |
147 | 0 | "Must be PrematureResponseError"); |
148 | 0 | return payload.http_code_; |
149 | 0 | } |
150 | | |
151 | 0 | bool isCodecClientError(const Status& status) { |
152 | 0 | return getStatusCode(status) == StatusCode::CodecClientError; |
153 | 0 | } |
154 | | |
155 | 244k | bool isInboundFramesWithEmptyPayloadError(const Status& status) { |
156 | 244k | return getStatusCode(status) == StatusCode::InboundFramesWithEmptyPayload; |
157 | 244k | } |
158 | | |
159 | 242k | bool isEnvoyOverloadError(const Status& status) { |
160 | 242k | return getStatusCode(status) == StatusCode::EnvoyOverloadError; |
161 | 242k | } |
162 | | |
163 | | } // namespace Http |
164 | | } // namespace Envoy |