Line data Source code
1 : #pragma once 2 : 3 : #include <atomic> 4 : #include <string> 5 : 6 : #include "envoy/http/codes.h" 7 : 8 : #include "absl/status/status.h" 9 : #include "absl/strings/string_view.h" 10 : 11 : /** 12 : * Facility for returning rich error information. 13 : * This facility is to be used in place of exceptions, in components where 14 : * exceptions safety is not guaranteed (i.e. codecs). 15 : * 16 : * Envoy::Status is an alias of absl::Status. 17 : * IMPORTANT: `absl::Status` constructor `absl::Status::code()` and absl::Status::ToString()` 18 : * methods must not be used as they will not return correct error information. Instead the error 19 : * value creating and corresponding error checking functions defined below must be used. 20 : * TODO(yanavlasov): add clang-tidy or lint check to enforce this. 21 : * 22 : * Usage example: 23 : * 24 : * Envoy::Status Foo() { 25 : * ... 26 : * if (codec_error) { 27 : * return CodecProtocolError("Invalid protocol"); 28 : * } 29 : * return Envoy::OkStatus(); 30 : * } 31 : * 32 : * void Bar() { 33 : * auto status = Foo(); 34 : * if (status.ok()) { 35 : * ... 36 : * } else { 37 : * ASSERT(IsCodecProtocolError(status)); 38 : * ENVOY_LOG(debug, "Codec error encountered: {}", status.message()); 39 : * } 40 : * } 41 : */ 42 : 43 : namespace Envoy { 44 : namespace Http { 45 : 46 : /** 47 : * Status codes for representing classes of Envoy errors. 48 : */ 49 : enum class StatusCode : int { 50 : Ok = 0, 51 : 52 : /** 53 : * Indicates a non-recoverable protocol error that should result in connection termination. 54 : */ 55 : CodecProtocolError = 1, 56 : 57 : /** 58 : * Indicates detection of outbound frame queue flood. 59 : */ 60 : BufferFloodError = 2, 61 : 62 : /** 63 : * Indicates a response is received on a connection that did not send a request. In practice 64 : * this can only happen on HTTP/1.1 connections. 65 : */ 66 : PrematureResponseError = 3, 67 : 68 : /** 69 : * Indicates a client (local) side error which should not happen. 70 : */ 71 : CodecClientError = 4, 72 : 73 : /** 74 : * Indicates that peer sent too many consecutive DATA frames with empty payload. 75 : */ 76 : InboundFramesWithEmptyPayload = 5, 77 : 78 : /** 79 : * Indicates that Envoy is overloaded and may shed load. 80 : */ 81 : EnvoyOverloadError = 6, 82 : }; 83 : 84 : using Status = absl::Status; 85 : 86 280089 : inline Status okStatus() { return absl::OkStatus(); } 87 : 88 : /** 89 : * Returns the combination of the error code name, message and any additional error attributes. 90 : */ 91 : std::string toString(const Status& status); 92 : 93 : /** 94 : * Functions for creating error values. The error code of the returned status object matches the 95 : * name of the function. 96 : */ 97 : Status codecProtocolError(absl::string_view message); 98 : Status bufferFloodError(absl::string_view message); 99 : Status prematureResponseError(absl::string_view message, Http::Code http_code); 100 : Status codecClientError(absl::string_view message); 101 : Status inboundFramesWithEmptyPayloadError(); 102 : Status envoyOverloadError(absl::string_view message); 103 : 104 : /** 105 : * Returns Envoy::StatusCode of the given status object. 106 : * If the status object does not contain valid Envoy::Status value the function will ASSERT. 107 : */ 108 : StatusCode getStatusCode(const Status& status); 109 : 110 : /** 111 : * Returns true if the given status matches error code implied by the name of the function. 112 : */ 113 : ABSL_MUST_USE_RESULT bool isCodecProtocolError(const Status& status); 114 : ABSL_MUST_USE_RESULT bool isBufferFloodError(const Status& status); 115 : ABSL_MUST_USE_RESULT bool isPrematureResponseError(const Status& status); 116 : ABSL_MUST_USE_RESULT bool isCodecClientError(const Status& status); 117 : ABSL_MUST_USE_RESULT bool isInboundFramesWithEmptyPayloadError(const Status& status); 118 : ABSL_MUST_USE_RESULT bool isEnvoyOverloadError(const Status& status); 119 : 120 : /** 121 : * Returns Http::Code value of the PrematureResponseError status. 122 : * IsPrematureResponseError(status) must be true which is checked by ASSERT. 123 : */ 124 : Http::Code getPrematureResponseHttpCode(const Status& status); 125 : 126 : /** 127 : * Macro that checks return value of expression that results in Status and returns from 128 : * the current function is status is not OK. 129 : * 130 : * Example usage: 131 : * Status foo() { 132 : * RETURN_IF_ERROR(bar()); 133 : * return okStatus(); 134 : * } 135 : */ 136 : 137 : #define RETURN_IF_ERROR(expr) \ 138 66389 : do { \ 139 66389 : if (::Envoy::Http::Details::StatusAdapter adapter{(expr)}) { \ 140 66262 : } else { \ 141 127 : return std::move(adapter.status_); \ 142 127 : } \ 143 66389 : } while (false) 144 : 145 : namespace Details { 146 : // Helper class to convert `Status` to `bool` so it can be used inside `if` statements. 147 : struct StatusAdapter { 148 56 : StatusAdapter(const Status& status) : status_(status) {} 149 66334 : StatusAdapter(Status&& status) : status_(std::move(status)) {} 150 : 151 : StatusAdapter(const StatusAdapter&) = delete; 152 : StatusAdapter& operator=(const StatusAdapter&) = delete; 153 : 154 66390 : explicit operator bool() const { return status_.ok(); } 155 : 156 : Status status_; 157 : }; 158 : } // namespace Details 159 : 160 : } // namespace Http 161 : } // namespace Envoy