Coverage Report

Created: 2023-11-12 09:30

/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
70.1k
  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
515
      : EnvoyStatusPayload(StatusCode::PrematureResponseError), http_code_(http_code) {}
42
  const Http::Code http_code_;
43
};
44
45
70.1k
template <typename T> void storePayload(absl::Status& status, const T& payload) {
46
70.1k
  const T* allocated = new T(payload);
47
70.1k
  const absl::string_view sv =
48
70.1k
      absl::string_view(reinterpret_cast<const char*>(allocated), sizeof(allocated));
49
70.1k
  absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; });
status.cc:Envoy::Http::(anonymous namespace)::storePayload<Envoy::Http::(anonymous namespace)::EnvoyStatusPayload>(absl::Status&, Envoy::Http::(anonymous namespace)::EnvoyStatusPayload const&)::{lambda()#1}::operator()() const
Line
Count
Source
49
69.6k
  absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; });
status.cc:Envoy::Http::(anonymous namespace)::storePayload<Envoy::Http::(anonymous namespace)::PrematureResponsePayload>(absl::Status&, Envoy::Http::(anonymous namespace)::PrematureResponsePayload const&)::{lambda()#1}::operator()() const
Line
Count
Source
49
515
  absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; });
50
70.1k
  cord.Flatten(); // Flatten ahead of time for easier access later.
51
70.1k
  status.SetPayload(EnvoyPayloadUrl, std::move(cord));
52
70.1k
}
status.cc:void Envoy::Http::(anonymous namespace)::storePayload<Envoy::Http::(anonymous namespace)::EnvoyStatusPayload>(absl::Status&, Envoy::Http::(anonymous namespace)::EnvoyStatusPayload const&)
Line
Count
Source
45
69.6k
template <typename T> void storePayload(absl::Status& status, const T& payload) {
46
69.6k
  const T* allocated = new T(payload);
47
69.6k
  const absl::string_view sv =
48
69.6k
      absl::string_view(reinterpret_cast<const char*>(allocated), sizeof(allocated));
49
69.6k
  absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; });
50
69.6k
  cord.Flatten(); // Flatten ahead of time for easier access later.
51
69.6k
  status.SetPayload(EnvoyPayloadUrl, std::move(cord));
52
69.6k
}
status.cc:void Envoy::Http::(anonymous namespace)::storePayload<Envoy::Http::(anonymous namespace)::PrematureResponsePayload>(absl::Status&, Envoy::Http::(anonymous namespace)::PrematureResponsePayload const&)
Line
Count
Source
45
515
template <typename T> void storePayload(absl::Status& status, const T& payload) {
46
515
  const T* allocated = new T(payload);
47
515
  const absl::string_view sv =
48
515
      absl::string_view(reinterpret_cast<const char*>(allocated), sizeof(allocated));
49
515
  absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; });
50
515
  cord.Flatten(); // Flatten ahead of time for easier access later.
51
515
  status.SetPayload(EnvoyPayloadUrl, std::move(cord));
52
515
}
53
54
5.72k
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.72k
  const T* payload = nullptr;
59
5.72k
  status.ForEachPayload([&payload](absl::string_view url, const absl::Cord& cord) {
60
5.72k
    if (url == EnvoyPayloadUrl) {
61
5.72k
      ASSERT(!payload); // Status API guarantees to have one payload with given URL
62
5.72k
      auto data = cord.TryFlat();
63
5.72k
      ASSERT(data.has_value()); // EnvoyPayloadUrl cords are flattened ahead of time
64
5.72k
      ASSERT(data.value().length() >= sizeof(T), "Invalid payload length");
65
5.72k
      payload = reinterpret_cast<const T*>(data.value().data());
66
5.72k
    }
67
5.72k
  });
status.cc:Envoy::Http::(anonymous namespace)::getPayload<Envoy::Http::(anonymous namespace)::EnvoyStatusPayload>(absl::Status const&)::{lambda(std::__1::basic_string_view<char, std::__1::char_traits<char> >, absl::Cord const&)#1}::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >, absl::Cord const&) const
Line
Count
Source
59
5.72k
  status.ForEachPayload([&payload](absl::string_view url, const absl::Cord& cord) {
60
5.72k
    if (url == EnvoyPayloadUrl) {
61
5.72k
      ASSERT(!payload); // Status API guarantees to have one payload with given URL
62
5.72k
      auto data = cord.TryFlat();
63
5.72k
      ASSERT(data.has_value()); // EnvoyPayloadUrl cords are flattened ahead of time
64
5.72k
      ASSERT(data.value().length() >= sizeof(T), "Invalid payload length");
65
5.72k
      payload = reinterpret_cast<const T*>(data.value().data());
66
5.72k
    }
67
5.72k
  });
Unexecuted instantiation: status.cc:Envoy::Http::(anonymous namespace)::getPayload<Envoy::Http::(anonymous namespace)::PrematureResponsePayload>(absl::Status const&)::{lambda(std::__1::basic_string_view<char, std::__1::char_traits<char> >, absl::Cord const&)#1}::operator()(std::__1::basic_string_view<char, std::__1::char_traits<char> >, absl::Cord const&) const
68
5.72k
  ASSERT(payload);
69
5.72k
  return *payload;
70
5.72k
}
status.cc:Envoy::Http::(anonymous namespace)::EnvoyStatusPayload const& Envoy::Http::(anonymous namespace)::getPayload<Envoy::Http::(anonymous namespace)::EnvoyStatusPayload>(absl::Status const&)
Line
Count
Source
54
5.72k
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.72k
  const T* payload = nullptr;
59
5.72k
  status.ForEachPayload([&payload](absl::string_view url, const absl::Cord& cord) {
60
5.72k
    if (url == EnvoyPayloadUrl) {
61
5.72k
      ASSERT(!payload); // Status API guarantees to have one payload with given URL
62
5.72k
      auto data = cord.TryFlat();
63
5.72k
      ASSERT(data.has_value()); // EnvoyPayloadUrl cords are flattened ahead of time
64
5.72k
      ASSERT(data.value().length() >= sizeof(T), "Invalid payload length");
65
5.72k
      payload = reinterpret_cast<const T*>(data.value().data());
66
5.72k
    }
67
5.72k
  });
68
5.72k
  ASSERT(payload);
69
5.72k
  return *payload;
70
5.72k
}
Unexecuted instantiation: status.cc:Envoy::Http::(anonymous namespace)::PrematureResponsePayload const& Envoy::Http::(anonymous namespace)::getPayload<Envoy::Http::(anonymous namespace)::PrematureResponsePayload>(absl::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
69.3k
Status codecProtocolError(absl::string_view message) {
91
69.3k
  absl::Status status(absl::StatusCode::kInternal, message);
92
69.3k
  storePayload(status, EnvoyStatusPayload(StatusCode::CodecProtocolError));
93
69.3k
  return status;
94
69.3k
}
95
96
42
Status bufferFloodError(absl::string_view message) {
97
42
  absl::Status status(absl::StatusCode::kInternal, message);
98
42
  storePayload(status, EnvoyStatusPayload(StatusCode::BufferFloodError));
99
42
  return status;
100
42
}
101
102
515
Status prematureResponseError(absl::string_view message, Http::Code http_code) {
103
515
  absl::Status status(absl::StatusCode::kInternal, message);
104
515
  storePayload(status, PrematureResponsePayload(http_code));
105
515
  return status;
106
515
}
107
108
43
Status codecClientError(absl::string_view message) {
109
43
  absl::Status status(absl::StatusCode::kInternal, message);
110
43
  storePayload(status, EnvoyStatusPayload(StatusCode::CodecClientError));
111
43
  return status;
112
43
}
113
114
249
Status inboundFramesWithEmptyPayloadError() {
115
249
  absl::Status status(absl::StatusCode::kInternal,
116
249
                      "Too many consecutive frames with an empty payload");
117
249
  storePayload(status, EnvoyStatusPayload(StatusCode::InboundFramesWithEmptyPayload));
118
249
  return status;
119
249
}
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
862k
StatusCode getStatusCode(const Status& status) {
129
862k
  return status.ok() ? StatusCode::Ok : getPayload(status).status_code_;
130
862k
}
131
132
217k
bool isCodecProtocolError(const Status& status) {
133
217k
  return getStatusCode(status) == StatusCode::CodecProtocolError;
134
217k
}
135
136
215k
bool isBufferFloodError(const Status& status) {
137
215k
  return getStatusCode(status) == StatusCode::BufferFloodError;
138
215k
}
139
140
691
bool isPrematureResponseError(const Status& status) {
141
691
  return getStatusCode(status) == StatusCode::PrematureResponseError;
142
691
}
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
215k
bool isInboundFramesWithEmptyPayloadError(const Status& status) {
156
215k
  return getStatusCode(status) == StatusCode::InboundFramesWithEmptyPayload;
157
215k
}
158
159
213k
bool isEnvoyOverloadError(const Status& status) {
160
213k
  return getStatusCode(status) == StatusCode::EnvoyOverloadError;
161
213k
}
162
163
} // namespace Http
164
} // namespace Envoy