• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2016 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/core/lib/transport/error_utils.h"
20 
21 #include <grpc/support/port_platform.h>
22 #include <grpc/support/string_util.h>
23 #include <stdint.h>
24 
25 #include <vector>
26 
27 #include "src/core/lib/transport/status_conversion.h"
28 #include "src/core/util/status_helper.h"
29 
recursively_find_error_with_field(grpc_error_handle error,grpc_core::StatusIntProperty which)30 static grpc_error_handle recursively_find_error_with_field(
31     grpc_error_handle error, grpc_core::StatusIntProperty which) {
32   intptr_t unused;
33   // If the error itself has a status code, return it.
34   if (grpc_error_get_int(error, which, &unused)) {
35     return error;
36   }
37   std::vector<absl::Status> children = grpc_core::StatusGetChildren(error);
38   for (const absl::Status& child : children) {
39     grpc_error_handle result = recursively_find_error_with_field(child, which);
40     if (!result.ok()) return result;
41   }
42   return absl::OkStatus();
43 }
44 
grpc_error_get_status(grpc_error_handle error,grpc_core::Timestamp deadline,grpc_status_code * code,std::string * message,grpc_http2_error_code * http_error,const char ** error_string)45 void grpc_error_get_status(grpc_error_handle error,
46                            grpc_core::Timestamp deadline,
47                            grpc_status_code* code, std::string* message,
48                            grpc_http2_error_code* http_error,
49                            const char** error_string) {
50   // Fast path: We expect no error.
51   if (GPR_LIKELY(error.ok())) {
52     if (code != nullptr) *code = GRPC_STATUS_OK;
53     if (message != nullptr) {
54       // Normally, we call grpc_error_get_str(
55       //   error, grpc_core::StatusStrProperty::kGrpcMessage, message).
56       // We can fastpath since we know that:
57       // 1) Error is null
58       // 2) which == grpc_core::StatusStrProperty::kGrpcMessage
59       // 3) The resulting message is statically known.
60       // 4) Said resulting message is "".
61       // This means 3 movs, instead of 10s of instructions and a strlen.
62       *message = "";
63     }
64     if (http_error != nullptr) {
65       *http_error = GRPC_HTTP2_NO_ERROR;
66     }
67     return;
68   }
69 
70   // Start with the parent error and recurse through the tree of children
71   // until we find the first one that has a status code.
72   grpc_error_handle found_error = recursively_find_error_with_field(
73       error, grpc_core::StatusIntProperty::kRpcStatus);
74   if (found_error.ok()) {
75     /// If no grpc-status exists, retry through the tree to find a http2 error
76     /// code
77     found_error = recursively_find_error_with_field(
78         error, grpc_core::StatusIntProperty::kHttp2Error);
79   }
80 
81   // If we found an error with a status code above, use that; otherwise,
82   // fall back to using the parent error.
83   if (found_error.ok()) found_error = error;
84 
85   grpc_status_code status = GRPC_STATUS_UNKNOWN;
86   intptr_t integer;
87   if (grpc_error_get_int(found_error, grpc_core::StatusIntProperty::kRpcStatus,
88                          &integer)) {
89     status = static_cast<grpc_status_code>(integer);
90   } else if (grpc_error_get_int(found_error,
91                                 grpc_core::StatusIntProperty::kHttp2Error,
92                                 &integer)) {
93     status = grpc_http2_error_to_grpc_status(
94         static_cast<grpc_http2_error_code>(integer), deadline);
95   } else {
96     status = static_cast<grpc_status_code>(found_error.code());
97   }
98   if (code != nullptr) *code = status;
99 
100   if (error_string != nullptr && status != GRPC_STATUS_OK) {
101     *error_string = gpr_strdup(grpc_core::StatusToString(error).c_str());
102   }
103 
104   if (http_error != nullptr) {
105     if (grpc_error_get_int(
106             found_error, grpc_core::StatusIntProperty::kHttp2Error, &integer)) {
107       *http_error = static_cast<grpc_http2_error_code>(integer);
108     } else if (grpc_error_get_int(found_error,
109                                   grpc_core::StatusIntProperty::kRpcStatus,
110                                   &integer)) {
111       *http_error =
112           grpc_status_to_http2_error(static_cast<grpc_status_code>(integer));
113     } else {
114       *http_error =
115           found_error.ok() ? GRPC_HTTP2_NO_ERROR : GRPC_HTTP2_INTERNAL_ERROR;
116     }
117   }
118 
119   // If the error has a status message, use it.  Otherwise, fall back to
120   // the error description.
121   if (message != nullptr) {
122     if (!grpc_error_get_str(
123             found_error, grpc_core::StatusStrProperty::kGrpcMessage, message)) {
124       if (!grpc_error_get_str(found_error,
125                               grpc_core::StatusStrProperty::kDescription,
126                               message)) {
127         *message = grpc_core::StatusToString(error);
128       }
129     }
130   }
131 }
132 
grpc_error_to_absl_status(grpc_error_handle error)133 absl::Status grpc_error_to_absl_status(grpc_error_handle error) {
134   grpc_status_code status;
135   // TODO(yashykt): This should be updated once we decide on how to use the
136   // absl::Status payload to capture all the contents of grpc_error.
137   std::string message;
138   grpc_error_get_status(error, grpc_core::Timestamp::InfFuture(), &status,
139                         &message, nullptr /* http_error */,
140                         nullptr /* error_string */);
141   return absl::Status(static_cast<absl::StatusCode>(status), message);
142 }
143 
absl_status_to_grpc_error(absl::Status status)144 grpc_error_handle absl_status_to_grpc_error(absl::Status status) {
145   // Special error checks
146   if (status.ok()) {
147     return absl::OkStatus();
148   }
149   return grpc_error_set_int(GRPC_ERROR_CREATE(status.message()),
150                             grpc_core::StatusIntProperty::kRpcStatus,
151                             static_cast<grpc_status_code>(status.code()));
152 }
153 
grpc_error_has_clear_grpc_status(grpc_error_handle error)154 bool grpc_error_has_clear_grpc_status(grpc_error_handle error) {
155   intptr_t unused;
156   if (grpc_error_get_int(error, grpc_core::StatusIntProperty::kRpcStatus,
157                          &unused)) {
158     return true;
159   }
160   std::vector<absl::Status> children = grpc_core::StatusGetChildren(error);
161   for (const absl::Status& child : children) {
162     if (grpc_error_has_clear_grpc_status(child)) {
163       return true;
164     }
165   }
166   return false;
167 }
168