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
   * Indicates the connection was gracefully closed due to GOAWAY.
85
   */
86
  GoAwayGracefulClose = 7,
87
};
88

            
89
using Status = absl::Status;
90

            
91
6273157
inline Status okStatus() { return absl::OkStatus(); }
92

            
93
/**
94
 * Returns the combination of the error code name, message and any additional error attributes.
95
 */
96
std::string toString(const Status& status);
97

            
98
/**
99
 * Functions for creating error values. The error code of the returned status object matches the
100
 * name of the function.
101
 */
102
Status codecProtocolError(absl::string_view message);
103
Status bufferFloodError(absl::string_view message);
104
Status prematureResponseError(absl::string_view message, Http::Code http_code);
105
Status codecClientError(absl::string_view message);
106
Status inboundFramesWithEmptyPayloadError();
107
Status envoyOverloadError(absl::string_view message);
108
Status goAwayGracefulCloseError();
109

            
110
/**
111
 * Returns Envoy::StatusCode of the given status object.
112
 * If the status object does not contain valid Envoy::Status value the function will ASSERT.
113
 */
114
StatusCode getStatusCode(const Status& status);
115

            
116
/**
117
 * Returns true if the given status matches error code implied by the name of the function.
118
 */
119
ABSL_MUST_USE_RESULT bool isCodecProtocolError(const Status& status);
120
ABSL_MUST_USE_RESULT bool isBufferFloodError(const Status& status);
121
ABSL_MUST_USE_RESULT bool isPrematureResponseError(const Status& status);
122
ABSL_MUST_USE_RESULT bool isCodecClientError(const Status& status);
123
ABSL_MUST_USE_RESULT bool isInboundFramesWithEmptyPayloadError(const Status& status);
124
ABSL_MUST_USE_RESULT bool isEnvoyOverloadError(const Status& status);
125
ABSL_MUST_USE_RESULT bool isGoAwayGracefulCloseError(const Status& status);
126

            
127
/**
128
 * Returns Http::Code value of the PrematureResponseError status.
129
 * IsPrematureResponseError(status) must be true which is checked by ASSERT.
130
 */
131
Http::Code getPrematureResponseHttpCode(const Status& status);
132

            
133
/**
134
 * Macro that checks return value of expression that results in Status and returns from
135
 * the current function is status is not OK.
136
 *
137
 * Example usage:
138
 *   Status foo() {
139
 *     RETURN_IF_ERROR(bar());
140
 *     return okStatus();
141
 *   }
142
 */
143

            
144
#define RETURN_IF_ERROR(expr)                                                                      \
145
1817282
  do {                                                                                             \
146
1817282
    if (::Envoy::Http::Details::StatusAdapter adapter{(expr)}) {                                   \
147
1817030
    } else {                                                                                       \
148
259
      return std::move(adapter.status_);                                                           \
149
259
    }                                                                                              \
150
1817282
  } while (false)
151

            
152
namespace Details {
153
// Helper class to convert `Status` to `bool` so it can be used inside `if` statements.
154
struct StatusAdapter {
155
326
  StatusAdapter(const Status& status) : status_(status) {}
156
1816943
  StatusAdapter(Status&& status) : status_(std::move(status)) {}
157

            
158
  StatusAdapter(const StatusAdapter&) = delete;
159
  StatusAdapter& operator=(const StatusAdapter&) = delete;
160

            
161
1817263
  explicit operator bool() const { return status_.ok(); }
162

            
163
  Status status_;
164
};
165
} // namespace Details
166

            
167
} // namespace Http
168
} // namespace Envoy