LCOV - code coverage report
Current view: top level - source/common/http - status.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 63 116 54.3 %
Date: 2024-01-05 06:35:25 Functions: 20 26 76.9 %

          Line data    Source code
       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        4340 :   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           8 :       : EnvoyStatusPayload(StatusCode::PrematureResponseError), http_code_(http_code) {}
      42             :   const Http::Code http_code_;
      43             : };
      44             : 
      45        4340 : template <typename T> void storePayload(absl::Status& status, const T& payload) {
      46        4340 :   const T* allocated = new T(payload);
      47        4340 :   const absl::string_view sv =
      48        4340 :       absl::string_view(reinterpret_cast<const char*>(allocated), sizeof(allocated));
      49        4340 :   absl::Cord cord = absl::MakeCordFromExternal(sv, [allocated]() { delete allocated; });
      50        4340 :   cord.Flatten(); // Flatten ahead of time for easier access later.
      51        4340 :   status.SetPayload(EnvoyPayloadUrl, std::move(cord));
      52        4340 : }
      53             : 
      54         751 : 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         751 :   const T* payload = nullptr;
      59         751 :   status.ForEachPayload([&payload](absl::string_view url, const absl::Cord& cord) {
      60         751 :     if (url == EnvoyPayloadUrl) {
      61         751 :       ASSERT(!payload); // Status API guarantees to have one payload with given URL
      62         751 :       auto data = cord.TryFlat();
      63         751 :       ASSERT(data.has_value()); // EnvoyPayloadUrl cords are flattened ahead of time
      64         751 :       ASSERT(data.value().length() >= sizeof(T), "Invalid payload length");
      65         751 :       payload = reinterpret_cast<const T*>(data.value().data());
      66         751 :     }
      67         751 :   });
      68         751 :   ASSERT(payload);
      69         751 :   return *payload;
      70         751 : }
      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        4325 : Status codecProtocolError(absl::string_view message) {
      91        4325 :   absl::Status status(absl::StatusCode::kInternal, message);
      92        4325 :   storePayload(status, EnvoyStatusPayload(StatusCode::CodecProtocolError));
      93        4325 :   return status;
      94        4325 : }
      95             : 
      96           0 : Status bufferFloodError(absl::string_view message) {
      97           0 :   absl::Status status(absl::StatusCode::kInternal, message);
      98           0 :   storePayload(status, EnvoyStatusPayload(StatusCode::BufferFloodError));
      99           0 :   return status;
     100           0 : }
     101             : 
     102           8 : Status prematureResponseError(absl::string_view message, Http::Code http_code) {
     103           8 :   absl::Status status(absl::StatusCode::kInternal, message);
     104           8 :   storePayload(status, PrematureResponsePayload(http_code));
     105           8 :   return status;
     106           8 : }
     107             : 
     108           7 : Status codecClientError(absl::string_view message) {
     109           7 :   absl::Status status(absl::StatusCode::kInternal, message);
     110           7 :   storePayload(status, EnvoyStatusPayload(StatusCode::CodecClientError));
     111           7 :   return status;
     112           7 : }
     113             : 
     114           0 : Status inboundFramesWithEmptyPayloadError() {
     115           0 :   absl::Status status(absl::StatusCode::kInternal,
     116           0 :                       "Too many consecutive frames with an empty payload");
     117           0 :   storePayload(status, EnvoyStatusPayload(StatusCode::InboundFramesWithEmptyPayload));
     118           0 :   return status;
     119           0 : }
     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        3970 : StatusCode getStatusCode(const Status& status) {
     129        3970 :   return status.ok() ? StatusCode::Ok : getPayload(status).status_code_;
     130        3970 : }
     131             : 
     132        1271 : bool isCodecProtocolError(const Status& status) {
     133        1271 :   return getStatusCode(status) == StatusCode::CodecProtocolError;
     134        1271 : }
     135             : 
     136         952 : bool isBufferFloodError(const Status& status) {
     137         952 :   return getStatusCode(status) == StatusCode::BufferFloodError;
     138         952 : }
     139             : 
     140          68 : bool isPrematureResponseError(const Status& status) {
     141          68 :   return getStatusCode(status) == StatusCode::PrematureResponseError;
     142          68 : }
     143             : 
     144           8 : Http::Code getPrematureResponseHttpCode(const Status& status) {
     145           8 :   const auto& payload = getPayload<PrematureResponsePayload>(status);
     146           8 :   ASSERT(payload.status_code_ == StatusCode::PrematureResponseError,
     147           8 :          "Must be PrematureResponseError");
     148           8 :   return payload.http_code_;
     149           8 : }
     150             : 
     151           0 : bool isCodecClientError(const Status& status) {
     152           0 :   return getStatusCode(status) == StatusCode::CodecClientError;
     153           0 : }
     154             : 
     155         952 : bool isInboundFramesWithEmptyPayloadError(const Status& status) {
     156         952 :   return getStatusCode(status) == StatusCode::InboundFramesWithEmptyPayload;
     157         952 : }
     158             : 
     159         727 : bool isEnvoyOverloadError(const Status& status) {
     160         727 :   return getStatusCode(status) == StatusCode::EnvoyOverloadError;
     161         727 : }
     162             : 
     163             : } // namespace Http
     164             : } // namespace Envoy

Generated by: LCOV version 1.15