Coverage Report

Created: 2024-09-19 09:45

/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