|
|
|
@ -39,86 +39,54 @@ std::unique_ptr<XdsBootstrap> XdsBootstrap::ReadFromFile(grpc_error** error) { |
|
|
|
|
grpc_slice contents; |
|
|
|
|
*error = grpc_load_file(path.get(), /*add_null_terminator=*/true, &contents); |
|
|
|
|
if (*error != GRPC_ERROR_NONE) return nullptr; |
|
|
|
|
return grpc_core::MakeUnique<XdsBootstrap>(contents, error); |
|
|
|
|
Json json = Json::Parse(StringViewFromSlice(contents), error); |
|
|
|
|
grpc_slice_unref_internal(contents); |
|
|
|
|
if (*error != GRPC_ERROR_NONE) return nullptr; |
|
|
|
|
return grpc_core::MakeUnique<XdsBootstrap>(std::move(json), error); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
XdsBootstrap::XdsBootstrap(grpc_slice contents, grpc_error** error) |
|
|
|
|
: contents_(contents) { |
|
|
|
|
tree_ = grpc_json_parse_string_with_len( |
|
|
|
|
reinterpret_cast<char*>(GPR_SLICE_START_PTR(contents_)), |
|
|
|
|
GPR_SLICE_LENGTH(contents_)); |
|
|
|
|
if (tree_ == nullptr) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"failed to parse bootstrap file JSON"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (tree_->type != GRPC_JSON_OBJECT || tree_->key != nullptr) { |
|
|
|
|
XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) { |
|
|
|
|
if (json.type() != Json::Type::OBJECT) { |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"malformed JSON in bootstrap file"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list; |
|
|
|
|
bool seen_xds_servers = false; |
|
|
|
|
bool seen_node = false; |
|
|
|
|
for (grpc_json* child = tree_->child; child != nullptr; child = child->next) { |
|
|
|
|
if (child->key == nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null")); |
|
|
|
|
} else if (strcmp(child->key, "xds_servers") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_ARRAY) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"xds_servers\" field is not an array")); |
|
|
|
|
} |
|
|
|
|
if (seen_xds_servers) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"duplicate \"xds_servers\" field")); |
|
|
|
|
} |
|
|
|
|
seen_xds_servers = true; |
|
|
|
|
grpc_error* parse_error = ParseXdsServerList(child); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} else if (strcmp(child->key, "node") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_OBJECT) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"node\" field is not an object")); |
|
|
|
|
} |
|
|
|
|
if (seen_node) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"node\" field")); |
|
|
|
|
} |
|
|
|
|
seen_node = true; |
|
|
|
|
grpc_error* parse_error = ParseNode(child); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!seen_xds_servers) { |
|
|
|
|
auto it = json.mutable_object()->find("xds_servers"); |
|
|
|
|
if (it == json.mutable_object()->end()) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"xds_servers\" field not present")); |
|
|
|
|
} else if (it->second.type() != Json::Type::ARRAY) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"xds_servers\" field is not an array")); |
|
|
|
|
} else { |
|
|
|
|
grpc_error* parse_error = ParseXdsServerList(&it->second); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
it = json.mutable_object()->find("node"); |
|
|
|
|
if (it != json.mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::OBJECT) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"node\" field is not an object")); |
|
|
|
|
} else { |
|
|
|
|
grpc_error* parse_error = ParseNode(&it->second); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*error = GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing xds bootstrap file", |
|
|
|
|
&error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
XdsBootstrap::~XdsBootstrap() { |
|
|
|
|
grpc_json_destroy(tree_); |
|
|
|
|
grpc_slice_unref_internal(contents_); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* XdsBootstrap::ParseXdsServerList(grpc_json* json) { |
|
|
|
|
grpc_error* XdsBootstrap::ParseXdsServerList(Json* json) { |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list; |
|
|
|
|
size_t idx = 0; |
|
|
|
|
for (grpc_json *child = json->child; child != nullptr; |
|
|
|
|
child = child->next, ++idx) { |
|
|
|
|
if (child->key != nullptr) { |
|
|
|
|
char* msg; |
|
|
|
|
gpr_asprintf(&msg, "array element %" PRIuPTR " key is not null", idx); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); |
|
|
|
|
} |
|
|
|
|
if (child->type != GRPC_JSON_OBJECT) { |
|
|
|
|
for (Json& child : *json->mutable_array()) { |
|
|
|
|
if (child.type() != Json::Type::OBJECT) { |
|
|
|
|
char* msg; |
|
|
|
|
gpr_asprintf(&msg, "array element %" PRIuPTR " is not an object", idx); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); |
|
|
|
|
} else { |
|
|
|
|
grpc_error* parse_error = ParseXdsServer(child, idx); |
|
|
|
|
grpc_error* parse_error = ParseXdsServer(&child, idx); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -126,42 +94,29 @@ grpc_error* XdsBootstrap::ParseXdsServerList(grpc_json* json) { |
|
|
|
|
&error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* XdsBootstrap::ParseXdsServer(grpc_json* json, size_t idx) { |
|
|
|
|
grpc_error* XdsBootstrap::ParseXdsServer(Json* json, size_t idx) { |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list; |
|
|
|
|
servers_.emplace_back(); |
|
|
|
|
XdsServer& server = servers_[servers_.size() - 1]; |
|
|
|
|
bool seen_channel_creds = false; |
|
|
|
|
for (grpc_json* child = json->child; child != nullptr; child = child->next) { |
|
|
|
|
if (child->key == nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null")); |
|
|
|
|
} else if (strcmp(child->key, "server_uri") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"server_uri\" field is not a string")); |
|
|
|
|
} |
|
|
|
|
if (server.server_uri != nullptr) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"duplicate \"server_uri\" field")); |
|
|
|
|
} |
|
|
|
|
server.server_uri = child->value; |
|
|
|
|
} else if (strcmp(child->key, "channel_creds") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_ARRAY) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"channel_creds\" field is not an array")); |
|
|
|
|
} |
|
|
|
|
if (seen_channel_creds) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"duplicate \"channel_creds\" field")); |
|
|
|
|
} |
|
|
|
|
seen_channel_creds = true; |
|
|
|
|
grpc_error* parse_error = ParseChannelCredsArray(child, &server); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (server.server_uri == nullptr) { |
|
|
|
|
auto it = json->mutable_object()->find("server_uri"); |
|
|
|
|
if (it == json->mutable_object()->end()) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"server_uri\" field not present")); |
|
|
|
|
} else if (it->second.type() != Json::Type::STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"server_uri\" field is not a string")); |
|
|
|
|
} else { |
|
|
|
|
server.server_uri = std::move(*it->second.mutable_string_value()); |
|
|
|
|
} |
|
|
|
|
it = json->mutable_object()->find("channel_creds"); |
|
|
|
|
if (it != json->mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::ARRAY) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"channel_creds\" field is not an array")); |
|
|
|
|
} else { |
|
|
|
|
grpc_error* parse_error = ParseChannelCredsArray(&it->second, &server); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
|
|
|
|
|
// string is not static in this case.
|
|
|
|
@ -176,23 +131,17 @@ grpc_error* XdsBootstrap::ParseXdsServer(grpc_json* json, size_t idx) { |
|
|
|
|
return error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* XdsBootstrap::ParseChannelCredsArray(grpc_json* json, |
|
|
|
|
grpc_error* XdsBootstrap::ParseChannelCredsArray(Json* json, |
|
|
|
|
XdsServer* server) { |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list; |
|
|
|
|
size_t idx = 0; |
|
|
|
|
for (grpc_json *child = json->child; child != nullptr; |
|
|
|
|
child = child->next, ++idx) { |
|
|
|
|
if (child->key != nullptr) { |
|
|
|
|
for (size_t i = 0; i < json->mutable_array()->size(); ++i) { |
|
|
|
|
Json& child = json->mutable_array()->at(i); |
|
|
|
|
if (child.type() != Json::Type::OBJECT) { |
|
|
|
|
char* msg; |
|
|
|
|
gpr_asprintf(&msg, "array element %" PRIuPTR " key is not null", idx); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); |
|
|
|
|
} |
|
|
|
|
if (child->type != GRPC_JSON_OBJECT) { |
|
|
|
|
char* msg; |
|
|
|
|
gpr_asprintf(&msg, "array element %" PRIuPTR " is not an object", idx); |
|
|
|
|
gpr_asprintf(&msg, "array element %" PRIuPTR " is not an object", i); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); |
|
|
|
|
} else { |
|
|
|
|
grpc_error* parse_error = ParseChannelCreds(child, idx, server); |
|
|
|
|
grpc_error* parse_error = ParseChannelCreds(&child, i, server); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -200,38 +149,31 @@ grpc_error* XdsBootstrap::ParseChannelCredsArray(grpc_json* json, |
|
|
|
|
&error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* XdsBootstrap::ParseChannelCreds(grpc_json* json, size_t idx, |
|
|
|
|
grpc_error* XdsBootstrap::ParseChannelCreds(Json* json, size_t idx, |
|
|
|
|
XdsServer* server) { |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list; |
|
|
|
|
ChannelCreds channel_creds; |
|
|
|
|
for (grpc_json* child = json->child; child != nullptr; child = child->next) { |
|
|
|
|
if (child->key == nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null")); |
|
|
|
|
} else if (strcmp(child->key, "type") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"type\" field is not a string")); |
|
|
|
|
} |
|
|
|
|
if (channel_creds.type != nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"type\" field")); |
|
|
|
|
} |
|
|
|
|
channel_creds.type = child->value; |
|
|
|
|
} else if (strcmp(child->key, "config") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_OBJECT) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"config\" field is not an object")); |
|
|
|
|
} |
|
|
|
|
if (channel_creds.config != nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"config\" field")); |
|
|
|
|
} |
|
|
|
|
channel_creds.config = child; |
|
|
|
|
auto it = json->mutable_object()->find("type"); |
|
|
|
|
if (it == json->mutable_object()->end()) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("\"type\" field not present")); |
|
|
|
|
} else if (it->second.type() != Json::Type::STRING) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("\"type\" field is not a string")); |
|
|
|
|
} else { |
|
|
|
|
channel_creds.type = std::move(*it->second.mutable_string_value()); |
|
|
|
|
} |
|
|
|
|
it = json->mutable_object()->find("config"); |
|
|
|
|
if (it != json->mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::OBJECT) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"config\" field is not an object")); |
|
|
|
|
} else { |
|
|
|
|
channel_creds.config = std::move(it->second); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (channel_creds.type != nullptr) { |
|
|
|
|
server->channel_creds.push_back(channel_creds); |
|
|
|
|
if (!channel_creds.type.empty()) { |
|
|
|
|
server->channel_creds.emplace_back(std::move(channel_creds)); |
|
|
|
|
} |
|
|
|
|
// Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
|
|
|
|
|
// string is not static in this case.
|
|
|
|
@ -246,242 +188,81 @@ grpc_error* XdsBootstrap::ParseChannelCreds(grpc_json* json, size_t idx, |
|
|
|
|
return error; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* XdsBootstrap::ParseNode(grpc_json* json) { |
|
|
|
|
grpc_error* XdsBootstrap::ParseNode(Json* json) { |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list; |
|
|
|
|
node_ = grpc_core::MakeUnique<Node>(); |
|
|
|
|
bool seen_metadata = false; |
|
|
|
|
bool seen_locality = false; |
|
|
|
|
for (grpc_json* child = json->child; child != nullptr; child = child->next) { |
|
|
|
|
if (child->key == nullptr) { |
|
|
|
|
auto it = json->mutable_object()->find("id"); |
|
|
|
|
if (it != json->mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::STRING) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null")); |
|
|
|
|
} else if (strcmp(child->key, "id") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"id\" field is not a string")); |
|
|
|
|
} |
|
|
|
|
if (node_->id != nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"id\" field")); |
|
|
|
|
} |
|
|
|
|
node_->id = child->value; |
|
|
|
|
} else if (strcmp(child->key, "cluster") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"cluster\" field is not a string")); |
|
|
|
|
} |
|
|
|
|
if (node_->cluster != nullptr) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"duplicate \"cluster\" field")); |
|
|
|
|
} |
|
|
|
|
node_->cluster = child->value; |
|
|
|
|
} else if (strcmp(child->key, "locality") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_OBJECT) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"locality\" field is not an object")); |
|
|
|
|
} |
|
|
|
|
if (seen_locality) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"duplicate \"locality\" field")); |
|
|
|
|
} |
|
|
|
|
seen_locality = true; |
|
|
|
|
grpc_error* parse_error = ParseLocality(child); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} else if (strcmp(child->key, "metadata") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_OBJECT) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"metadata\" field is not an object")); |
|
|
|
|
} |
|
|
|
|
if (seen_metadata) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"duplicate \"metadata\" field")); |
|
|
|
|
} |
|
|
|
|
seen_metadata = true; |
|
|
|
|
InlinedVector<grpc_error*, 1> parse_errors = |
|
|
|
|
ParseMetadataStruct(child, &node_->metadata); |
|
|
|
|
if (!parse_errors.empty()) { |
|
|
|
|
grpc_error* parse_error = GRPC_ERROR_CREATE_FROM_VECTOR( |
|
|
|
|
"errors parsing \"metadata\" object", &parse_errors); |
|
|
|
|
error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("\"id\" field is not a string")); |
|
|
|
|
} else { |
|
|
|
|
node_->id = std::move(*it->second.mutable_string_value()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"node\" object", |
|
|
|
|
&error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* XdsBootstrap::ParseLocality(grpc_json* json) { |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list; |
|
|
|
|
node_->locality_region = nullptr; |
|
|
|
|
node_->locality_zone = nullptr; |
|
|
|
|
node_->locality_subzone = nullptr; |
|
|
|
|
for (grpc_json* child = json->child; child != nullptr; child = child->next) { |
|
|
|
|
if (child->key == nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null")); |
|
|
|
|
} else if (strcmp(child->key, "region") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"region\" field is not a string")); |
|
|
|
|
} |
|
|
|
|
if (node_->locality_region != nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"region\" field")); |
|
|
|
|
} |
|
|
|
|
node_->locality_region = child->value; |
|
|
|
|
} else if (strcmp(child->key, "zone") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"zone\" field is not a string")); |
|
|
|
|
} |
|
|
|
|
if (node_->locality_zone != nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("duplicate \"zone\" field")); |
|
|
|
|
} |
|
|
|
|
node_->locality_zone = child->value; |
|
|
|
|
} else if (strcmp(child->key, "subzone") == 0) { |
|
|
|
|
if (child->type != GRPC_JSON_STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"subzone\" field is not a string")); |
|
|
|
|
} |
|
|
|
|
if (node_->locality_subzone != nullptr) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"duplicate \"subzone\" field")); |
|
|
|
|
} |
|
|
|
|
node_->locality_subzone = child->value; |
|
|
|
|
it = json->mutable_object()->find("cluster"); |
|
|
|
|
if (it != json->mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"cluster\" field is not a string")); |
|
|
|
|
} else { |
|
|
|
|
node_->cluster = std::move(*it->second.mutable_string_value()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"locality\" object", |
|
|
|
|
&error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
InlinedVector<grpc_error*, 1> XdsBootstrap::ParseMetadataStruct( |
|
|
|
|
grpc_json* json, |
|
|
|
|
std::map<const char*, XdsBootstrap::MetadataValue, StringLess>* result) { |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list; |
|
|
|
|
for (grpc_json* child = json->child; child != nullptr; child = child->next) { |
|
|
|
|
if (child->key == nullptr) { |
|
|
|
|
error_list.push_back( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("JSON key is null")); |
|
|
|
|
continue; |
|
|
|
|
it = json->mutable_object()->find("locality"); |
|
|
|
|
if (it != json->mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::OBJECT) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"locality\" field is not an object")); |
|
|
|
|
} else { |
|
|
|
|
grpc_error* parse_error = ParseLocality(&it->second); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
if (result->find(child->key) != result->end()) { |
|
|
|
|
char* msg; |
|
|
|
|
gpr_asprintf(&msg, "duplicate metadata key \"%s\"", child->key); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); |
|
|
|
|
gpr_free(msg); |
|
|
|
|
} |
|
|
|
|
it = json->mutable_object()->find("metadata"); |
|
|
|
|
if (it != json->mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::OBJECT) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"metadata\" field is not an object")); |
|
|
|
|
} else { |
|
|
|
|
node_->metadata = std::move(it->second); |
|
|
|
|
} |
|
|
|
|
MetadataValue& value = (*result)[child->key]; |
|
|
|
|
grpc_error* parse_error = ParseMetadataValue(child, 0, &value); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
return error_list; |
|
|
|
|
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"node\" object", |
|
|
|
|
&error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
InlinedVector<grpc_error*, 1> XdsBootstrap::ParseMetadataList( |
|
|
|
|
grpc_json* json, std::vector<MetadataValue>* result) { |
|
|
|
|
grpc_error* XdsBootstrap::ParseLocality(Json* json) { |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list; |
|
|
|
|
size_t idx = 0; |
|
|
|
|
for (grpc_json *child = json->child; child != nullptr; |
|
|
|
|
child = child->next, ++idx) { |
|
|
|
|
if (child->key != nullptr) { |
|
|
|
|
char* msg; |
|
|
|
|
gpr_asprintf(&msg, "JSON key is non-null for index %" PRIuPTR, idx); |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg)); |
|
|
|
|
gpr_free(msg); |
|
|
|
|
auto it = json->mutable_object()->find("region"); |
|
|
|
|
if (it != json->mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"region\" field is not a string")); |
|
|
|
|
} else { |
|
|
|
|
node_->locality_region = std::move(*it->second.mutable_string_value()); |
|
|
|
|
} |
|
|
|
|
result->emplace_back(); |
|
|
|
|
grpc_error* parse_error = ParseMetadataValue(child, idx, &result->back()); |
|
|
|
|
if (parse_error != GRPC_ERROR_NONE) error_list.push_back(parse_error); |
|
|
|
|
} |
|
|
|
|
return error_list; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_error* XdsBootstrap::ParseMetadataValue(grpc_json* json, size_t idx, |
|
|
|
|
MetadataValue* result) { |
|
|
|
|
grpc_error* error = GRPC_ERROR_NONE; |
|
|
|
|
auto context_func = [json, idx]() { |
|
|
|
|
char* context; |
|
|
|
|
if (json->key != nullptr) { |
|
|
|
|
gpr_asprintf(&context, "key \"%s\"", json->key); |
|
|
|
|
it = json->mutable_object()->find("zone"); |
|
|
|
|
if (it != json->mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"zone\" field is not a string")); |
|
|
|
|
} else { |
|
|
|
|
gpr_asprintf(&context, "index %" PRIuPTR, idx); |
|
|
|
|
node_->locality_zone = std::move(*it->second.mutable_string_value()); |
|
|
|
|
} |
|
|
|
|
return context; |
|
|
|
|
}; |
|
|
|
|
switch (json->type) { |
|
|
|
|
case GRPC_JSON_STRING: |
|
|
|
|
result->type = MetadataValue::Type::STRING; |
|
|
|
|
result->string_value = json->value; |
|
|
|
|
break; |
|
|
|
|
case GRPC_JSON_NUMBER: |
|
|
|
|
result->type = MetadataValue::Type::DOUBLE; |
|
|
|
|
errno = 0; // To distinguish error.
|
|
|
|
|
result->double_value = strtod(json->value, nullptr); |
|
|
|
|
if (errno != 0) { |
|
|
|
|
char* context = context_func(); |
|
|
|
|
char* msg; |
|
|
|
|
gpr_asprintf(&msg, "error parsing numeric value for %s: \"%s\"", |
|
|
|
|
context, json->value); |
|
|
|
|
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); |
|
|
|
|
gpr_free(context); |
|
|
|
|
gpr_free(msg); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case GRPC_JSON_TRUE: |
|
|
|
|
result->type = MetadataValue::Type::BOOL; |
|
|
|
|
result->bool_value = true; |
|
|
|
|
break; |
|
|
|
|
case GRPC_JSON_FALSE: |
|
|
|
|
result->type = MetadataValue::Type::BOOL; |
|
|
|
|
result->bool_value = false; |
|
|
|
|
break; |
|
|
|
|
case GRPC_JSON_NULL: |
|
|
|
|
result->type = MetadataValue::Type::MD_NULL; |
|
|
|
|
break; |
|
|
|
|
case GRPC_JSON_ARRAY: { |
|
|
|
|
result->type = MetadataValue::Type::LIST; |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list = |
|
|
|
|
ParseMetadataList(json, &result->list_value); |
|
|
|
|
if (!error_list.empty()) { |
|
|
|
|
// Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
|
|
|
|
|
// string is not static in this case.
|
|
|
|
|
char* context = context_func(); |
|
|
|
|
char* msg; |
|
|
|
|
gpr_asprintf(&msg, "errors parsing struct for %s", context); |
|
|
|
|
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); |
|
|
|
|
gpr_free(context); |
|
|
|
|
gpr_free(msg); |
|
|
|
|
for (size_t i = 0; i < error_list.size(); ++i) { |
|
|
|
|
error = grpc_error_add_child(error, error_list[i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
case GRPC_JSON_OBJECT: { |
|
|
|
|
result->type = MetadataValue::Type::STRUCT; |
|
|
|
|
InlinedVector<grpc_error*, 1> error_list = |
|
|
|
|
ParseMetadataStruct(json, &result->struct_value); |
|
|
|
|
if (!error_list.empty()) { |
|
|
|
|
// Can't use GRPC_ERROR_CREATE_FROM_VECTOR() here, because the error
|
|
|
|
|
// string is not static in this case.
|
|
|
|
|
char* context = context_func(); |
|
|
|
|
char* msg; |
|
|
|
|
gpr_asprintf(&msg, "errors parsing struct for %s", context); |
|
|
|
|
error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(msg); |
|
|
|
|
gpr_free(context); |
|
|
|
|
gpr_free(msg); |
|
|
|
|
for (size_t i = 0; i < error_list.size(); ++i) { |
|
|
|
|
error = grpc_error_add_child(error, error_list[i]); |
|
|
|
|
GRPC_ERROR_UNREF(error_list[i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
it = json->mutable_object()->find("subzone"); |
|
|
|
|
if (it != json->mutable_object()->end()) { |
|
|
|
|
if (it->second.type() != Json::Type::STRING) { |
|
|
|
|
error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"\"subzone\" field is not a string")); |
|
|
|
|
} else { |
|
|
|
|
node_->locality_subzone = std::move(*it->second.mutable_string_value()); |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
return error; |
|
|
|
|
return GRPC_ERROR_CREATE_FROM_VECTOR("errors parsing \"locality\" object", |
|
|
|
|
&error_list); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // namespace grpc_core
|
|
|
|
|