/* * * Copyright 2015-2016 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include #include #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include #include "src/core/lib/json/json.h" #define GRPC_JSON_MAX_DEPTH 255 #define GRPC_JSON_MAX_ERRORS 16 namespace grpc_core { namespace { class JsonReader { public: static grpc_error* Parse(absl::string_view input, Json* output); private: enum class Status { GRPC_JSON_DONE, /* The parser finished successfully. */ GRPC_JSON_PARSE_ERROR, /* The parser found an error in the json stream. */ GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */ }; enum class State { GRPC_JSON_STATE_OBJECT_KEY_BEGIN, GRPC_JSON_STATE_OBJECT_KEY_STRING, GRPC_JSON_STATE_OBJECT_KEY_END, GRPC_JSON_STATE_VALUE_BEGIN, GRPC_JSON_STATE_VALUE_STRING, GRPC_JSON_STATE_STRING_ESCAPE, GRPC_JSON_STATE_STRING_ESCAPE_U1, GRPC_JSON_STATE_STRING_ESCAPE_U2, GRPC_JSON_STATE_STRING_ESCAPE_U3, GRPC_JSON_STATE_STRING_ESCAPE_U4, GRPC_JSON_STATE_VALUE_NUMBER, GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL, GRPC_JSON_STATE_VALUE_NUMBER_ZERO, GRPC_JSON_STATE_VALUE_NUMBER_DOT, GRPC_JSON_STATE_VALUE_NUMBER_E, GRPC_JSON_STATE_VALUE_NUMBER_EPM, GRPC_JSON_STATE_VALUE_TRUE_R, GRPC_JSON_STATE_VALUE_TRUE_U, GRPC_JSON_STATE_VALUE_TRUE_E, GRPC_JSON_STATE_VALUE_FALSE_A, GRPC_JSON_STATE_VALUE_FALSE_L, GRPC_JSON_STATE_VALUE_FALSE_S, GRPC_JSON_STATE_VALUE_FALSE_E, GRPC_JSON_STATE_VALUE_NULL_U, GRPC_JSON_STATE_VALUE_NULL_L1, GRPC_JSON_STATE_VALUE_NULL_L2, GRPC_JSON_STATE_VALUE_END, GRPC_JSON_STATE_END }; /* The first non-unicode value is 0x110000. But let's pick * a value high enough to start our error codes from. These * values are safe to return from the read_char function. */ static constexpr uint32_t GRPC_JSON_READ_CHAR_EOF = 0x7ffffff0; explicit JsonReader(absl::string_view input) : original_input_(reinterpret_cast(input.data())), input_(original_input_), remaining_input_(input.size()) {} Status Run(); uint32_t ReadChar(); bool IsComplete(); size_t CurrentIndex() const { return input_ - original_input_ - 1; } void StringAddChar(uint32_t c); void StringAddUtf32(uint32_t c); Json* CreateAndLinkValue(); bool StartContainer(Json::Type type); void EndContainer(); void SetKey(); void SetString(); bool SetNumber(); void SetTrue(); void SetFalse(); void SetNull(); const uint8_t* original_input_; const uint8_t* input_; size_t remaining_input_; State state_ = State::GRPC_JSON_STATE_VALUE_BEGIN; bool escaped_string_was_key_ = false; bool container_just_begun_ = false; uint16_t unicode_char_ = 0; uint16_t unicode_high_surrogate_ = 0; std::vector errors_; bool truncated_errors_ = false; Json root_value_; std::vector stack_; std::string key_; std::string string_; }; void JsonReader::StringAddChar(uint32_t c) { string_.push_back(static_cast(c)); } void JsonReader::StringAddUtf32(uint32_t c) { if (c <= 0x7f) { StringAddChar(c); } else if (c <= 0x7ff) { uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f); uint32_t b2 = 0x80 | (c & 0x3f); StringAddChar(b1); StringAddChar(b2); } else if (c <= 0xffff) { uint32_t b1 = 0xe0 | ((c >> 12) & 0x0f); uint32_t b2 = 0x80 | ((c >> 6) & 0x3f); uint32_t b3 = 0x80 | (c & 0x3f); StringAddChar(b1); StringAddChar(b2); StringAddChar(b3); } else if (c <= 0x1fffff) { uint32_t b1 = 0xf0 | ((c >> 18) & 0x07); uint32_t b2 = 0x80 | ((c >> 12) & 0x3f); uint32_t b3 = 0x80 | ((c >> 6) & 0x3f); uint32_t b4 = 0x80 | (c & 0x3f); StringAddChar(b1); StringAddChar(b2); StringAddChar(b3); StringAddChar(b4); } } uint32_t JsonReader::ReadChar() { if (remaining_input_ == 0) return GRPC_JSON_READ_CHAR_EOF; const uint32_t r = *input_++; --remaining_input_; if (r == 0) { remaining_input_ = 0; return GRPC_JSON_READ_CHAR_EOF; } return r; } Json* JsonReader::CreateAndLinkValue() { Json* value; if (stack_.empty()) { value = &root_value_; } else { Json* parent = stack_.back(); if (parent->type() == Json::Type::OBJECT) { if (parent->object_value().find(key_) != parent->object_value().end()) { if (errors_.size() == GRPC_JSON_MAX_ERRORS) { truncated_errors_ = true; } else { errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( absl::StrFormat("duplicate key \"%s\" at index %" PRIuPTR, key_, CurrentIndex()) .c_str())); } } value = &(*parent->mutable_object())[std::move(key_)]; } else { GPR_ASSERT(parent->type() == Json::Type::ARRAY); parent->mutable_array()->emplace_back(); value = &parent->mutable_array()->back(); } } return value; } bool JsonReader::StartContainer(Json::Type type) { if (stack_.size() == GRPC_JSON_MAX_DEPTH) { if (errors_.size() == GRPC_JSON_MAX_ERRORS) { truncated_errors_ = true; } else { errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( absl::StrFormat("exceeded max stack depth (%d) at index %" PRIuPTR, GRPC_JSON_MAX_DEPTH, CurrentIndex()) .c_str())); } return false; } Json* value = CreateAndLinkValue(); if (type == Json::Type::OBJECT) { *value = Json::Object(); } else { GPR_ASSERT(type == Json::Type::ARRAY); *value = Json::Array(); } stack_.push_back(value); return true; } void JsonReader::EndContainer() { GPR_ASSERT(!stack_.empty()); stack_.pop_back(); } void JsonReader::SetKey() { key_ = std::move(string_); string_.clear(); } void JsonReader::SetString() { Json* value = CreateAndLinkValue(); *value = std::move(string_); string_.clear(); } bool JsonReader::SetNumber() { Json* value = CreateAndLinkValue(); *value = Json(string_, /*is_number=*/true); string_.clear(); return true; } void JsonReader::SetTrue() { Json* value = CreateAndLinkValue(); *value = true; string_.clear(); } void JsonReader::SetFalse() { Json* value = CreateAndLinkValue(); *value = false; string_.clear(); } void JsonReader::SetNull() { CreateAndLinkValue(); } bool JsonReader::IsComplete() { return (stack_.empty() && (state_ == State::GRPC_JSON_STATE_END || state_ == State::GRPC_JSON_STATE_VALUE_END)); } /* Call this function to start parsing the input. It will return the following: * . GRPC_JSON_DONE if the input got eof, and the parsing finished * successfully. * . GRPC_JSON_PARSE_ERROR if the input was somehow invalid. * . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid * internal state. */ JsonReader::Status JsonReader::Run() { uint32_t c; /* This state-machine is a strict implementation of ECMA-404 */ while (true) { c = ReadChar(); switch (c) { /* Let's process the error case first. */ case GRPC_JSON_READ_CHAR_EOF: if (IsComplete()) { return Status::GRPC_JSON_DONE; } else { return Status::GRPC_JSON_PARSE_ERROR; } break; /* Processing whitespaces. */ case ' ': case '\t': case '\n': case '\r': switch (state_) { case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN: case State::GRPC_JSON_STATE_OBJECT_KEY_END: case State::GRPC_JSON_STATE_VALUE_BEGIN: case State::GRPC_JSON_STATE_VALUE_END: case State::GRPC_JSON_STATE_END: break; case State::GRPC_JSON_STATE_OBJECT_KEY_STRING: case State::GRPC_JSON_STATE_VALUE_STRING: if (c != ' ') return Status::GRPC_JSON_PARSE_ERROR; if (unicode_high_surrogate_ != 0) { return Status::GRPC_JSON_PARSE_ERROR; } StringAddChar(c); break; case State::GRPC_JSON_STATE_VALUE_NUMBER: case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO: case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM: if (!SetNumber()) return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_END; break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; /* Value, object or array terminations. */ case ',': case '}': case ']': switch (state_) { case State::GRPC_JSON_STATE_OBJECT_KEY_STRING: case State::GRPC_JSON_STATE_VALUE_STRING: if (unicode_high_surrogate_ != 0) { return Status::GRPC_JSON_PARSE_ERROR; } StringAddChar(c); break; case State::GRPC_JSON_STATE_VALUE_NUMBER: case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO: case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM: if (stack_.empty()) { return Status::GRPC_JSON_PARSE_ERROR; } else if (c == '}' && stack_.back()->type() != Json::Type::OBJECT) { return Status::GRPC_JSON_PARSE_ERROR; return Status::GRPC_JSON_PARSE_ERROR; } else if (c == ']' && stack_.back()->type() != Json::Type::ARRAY) { return Status::GRPC_JSON_PARSE_ERROR; } if (!SetNumber()) return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_END; /* The missing break here is intentional. */ /* fallthrough */ case State::GRPC_JSON_STATE_VALUE_END: case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN: case State::GRPC_JSON_STATE_VALUE_BEGIN: if (c == ',') { if (state_ != State::GRPC_JSON_STATE_VALUE_END) { return Status::GRPC_JSON_PARSE_ERROR; } if (!stack_.empty() && stack_.back()->type() == Json::Type::OBJECT) { state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN; } else if (!stack_.empty() && stack_.back()->type() == Json::Type::ARRAY) { state_ = State::GRPC_JSON_STATE_VALUE_BEGIN; } else { return Status::GRPC_JSON_PARSE_ERROR; } } else { if (stack_.empty()) { return Status::GRPC_JSON_PARSE_ERROR; } if (c == '}' && stack_.back()->type() != Json::Type::OBJECT) { return Status::GRPC_JSON_PARSE_ERROR; } if (c == '}' && state_ == State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN && !container_just_begun_) { return Status::GRPC_JSON_PARSE_ERROR; } if (c == ']' && stack_.back()->type() != Json::Type::ARRAY) { return Status::GRPC_JSON_PARSE_ERROR; } if (c == ']' && state_ == State::GRPC_JSON_STATE_VALUE_BEGIN && !container_just_begun_) { return Status::GRPC_JSON_PARSE_ERROR; } state_ = State::GRPC_JSON_STATE_VALUE_END; EndContainer(); if (stack_.empty()) { state_ = State::GRPC_JSON_STATE_END; } } break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; /* In-string escaping. */ case '\\': switch (state_) { case State::GRPC_JSON_STATE_OBJECT_KEY_STRING: escaped_string_was_key_ = true; state_ = State::GRPC_JSON_STATE_STRING_ESCAPE; break; case State::GRPC_JSON_STATE_VALUE_STRING: escaped_string_was_key_ = false; state_ = State::GRPC_JSON_STATE_STRING_ESCAPE; break; /* This is the \\ case. */ case State::GRPC_JSON_STATE_STRING_ESCAPE: if (unicode_high_surrogate_ != 0) return Status::GRPC_JSON_PARSE_ERROR; StringAddChar('\\'); if (escaped_string_was_key_) { state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING; } else { state_ = State::GRPC_JSON_STATE_VALUE_STRING; } break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; default: container_just_begun_ = false; switch (state_) { case State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN: if (c != '"') return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING; break; case State::GRPC_JSON_STATE_OBJECT_KEY_STRING: if (unicode_high_surrogate_ != 0) { return Status::GRPC_JSON_PARSE_ERROR; } if (c == '"') { state_ = State::GRPC_JSON_STATE_OBJECT_KEY_END; SetKey(); } else { if (c < 32) return Status::GRPC_JSON_PARSE_ERROR; StringAddChar(c); } break; case State::GRPC_JSON_STATE_VALUE_STRING: if (unicode_high_surrogate_ != 0) { return Status::GRPC_JSON_PARSE_ERROR; } if (c == '"') { state_ = State::GRPC_JSON_STATE_VALUE_END; SetString(); } else { if (c < 32) return Status::GRPC_JSON_PARSE_ERROR; StringAddChar(c); } break; case State::GRPC_JSON_STATE_OBJECT_KEY_END: if (c != ':') return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_BEGIN; break; case State::GRPC_JSON_STATE_VALUE_BEGIN: switch (c) { case 't': state_ = State::GRPC_JSON_STATE_VALUE_TRUE_R; break; case 'f': state_ = State::GRPC_JSON_STATE_VALUE_FALSE_A; break; case 'n': state_ = State::GRPC_JSON_STATE_VALUE_NULL_U; break; case '"': state_ = State::GRPC_JSON_STATE_VALUE_STRING; break; case '0': StringAddChar(c); state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': StringAddChar(c); state_ = State::GRPC_JSON_STATE_VALUE_NUMBER; break; case '{': container_just_begun_ = true; if (!StartContainer(Json::Type::OBJECT)) { return Status::GRPC_JSON_PARSE_ERROR; } state_ = State::GRPC_JSON_STATE_OBJECT_KEY_BEGIN; break; case '[': container_just_begun_ = true; if (!StartContainer(Json::Type::ARRAY)) { return Status::GRPC_JSON_PARSE_ERROR; } break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; case State::GRPC_JSON_STATE_STRING_ESCAPE: if (escaped_string_was_key_) { state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING; } else { state_ = State::GRPC_JSON_STATE_VALUE_STRING; } if (unicode_high_surrogate_ && c != 'u') { return Status::GRPC_JSON_PARSE_ERROR; } switch (c) { case '"': case '/': StringAddChar(c); break; case 'b': StringAddChar('\b'); break; case 'f': StringAddChar('\f'); break; case 'n': StringAddChar('\n'); break; case 'r': StringAddChar('\r'); break; case 't': StringAddChar('\t'); break; case 'u': state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U1; unicode_char_ = 0; break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; case State::GRPC_JSON_STATE_STRING_ESCAPE_U1: case State::GRPC_JSON_STATE_STRING_ESCAPE_U2: case State::GRPC_JSON_STATE_STRING_ESCAPE_U3: case State::GRPC_JSON_STATE_STRING_ESCAPE_U4: if ((c >= '0') && (c <= '9')) { c -= '0'; } else if ((c >= 'A') && (c <= 'F')) { c -= 'A' - 10; } else if ((c >= 'a') && (c <= 'f')) { c -= 'a' - 10; } else { return Status::GRPC_JSON_PARSE_ERROR; } unicode_char_ = static_cast(unicode_char_ << 4); unicode_char_ = static_cast(unicode_char_ | c); switch (state_) { case State::GRPC_JSON_STATE_STRING_ESCAPE_U1: state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U2; break; case State::GRPC_JSON_STATE_STRING_ESCAPE_U2: state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U3; break; case State::GRPC_JSON_STATE_STRING_ESCAPE_U3: state_ = State::GRPC_JSON_STATE_STRING_ESCAPE_U4; break; case State::GRPC_JSON_STATE_STRING_ESCAPE_U4: /* See grpc_json_writer_escape_string to have a description * of what's going on here. */ if ((unicode_char_ & 0xfc00) == 0xd800) { /* high surrogate utf-16 */ if (unicode_high_surrogate_ != 0) return Status::GRPC_JSON_PARSE_ERROR; unicode_high_surrogate_ = unicode_char_; } else if ((unicode_char_ & 0xfc00) == 0xdc00) { /* low surrogate utf-16 */ uint32_t utf32; if (unicode_high_surrogate_ == 0) return Status::GRPC_JSON_PARSE_ERROR; utf32 = 0x10000; utf32 += static_cast( (unicode_high_surrogate_ - 0xd800) * 0x400); utf32 += static_cast(unicode_char_ - 0xdc00); StringAddUtf32(utf32); unicode_high_surrogate_ = 0; } else { /* anything else */ if (unicode_high_surrogate_ != 0) return Status::GRPC_JSON_PARSE_ERROR; StringAddUtf32(unicode_char_); } if (escaped_string_was_key_) { state_ = State::GRPC_JSON_STATE_OBJECT_KEY_STRING; } else { state_ = State::GRPC_JSON_STATE_VALUE_STRING; } break; default: GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR); } break; case State::GRPC_JSON_STATE_VALUE_NUMBER: StringAddChar(c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case 'e': case 'E': state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_E; break; case '.': state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_DOT; break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; case State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL: StringAddChar(c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case 'e': case 'E': state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_E; break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; case State::GRPC_JSON_STATE_VALUE_NUMBER_ZERO: if (c != '.') return Status::GRPC_JSON_PARSE_ERROR; StringAddChar(c); state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_DOT; break; case State::GRPC_JSON_STATE_VALUE_NUMBER_DOT: StringAddChar(c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL; break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; case State::GRPC_JSON_STATE_VALUE_NUMBER_E: StringAddChar(c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '+': case '-': state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_EPM; break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; case State::GRPC_JSON_STATE_VALUE_NUMBER_EPM: StringAddChar(c); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; case State::GRPC_JSON_STATE_VALUE_TRUE_R: if (c != 'r') return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_TRUE_U; break; case State::GRPC_JSON_STATE_VALUE_TRUE_U: if (c != 'u') return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_TRUE_E; break; case State::GRPC_JSON_STATE_VALUE_TRUE_E: if (c != 'e') return Status::GRPC_JSON_PARSE_ERROR; SetTrue(); state_ = State::GRPC_JSON_STATE_VALUE_END; break; case State::GRPC_JSON_STATE_VALUE_FALSE_A: if (c != 'a') return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_FALSE_L; break; case State::GRPC_JSON_STATE_VALUE_FALSE_L: if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_FALSE_S; break; case State::GRPC_JSON_STATE_VALUE_FALSE_S: if (c != 's') return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_FALSE_E; break; case State::GRPC_JSON_STATE_VALUE_FALSE_E: if (c != 'e') return Status::GRPC_JSON_PARSE_ERROR; SetFalse(); state_ = State::GRPC_JSON_STATE_VALUE_END; break; case State::GRPC_JSON_STATE_VALUE_NULL_U: if (c != 'u') return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_NULL_L1; break; case State::GRPC_JSON_STATE_VALUE_NULL_L1: if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR; state_ = State::GRPC_JSON_STATE_VALUE_NULL_L2; break; case State::GRPC_JSON_STATE_VALUE_NULL_L2: if (c != 'l') return Status::GRPC_JSON_PARSE_ERROR; SetNull(); state_ = State::GRPC_JSON_STATE_VALUE_END; break; /* All of the VALUE_END cases are handled in the specialized case * above. */ case State::GRPC_JSON_STATE_VALUE_END: switch (c) { case ',': case '}': case ']': GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR); break; default: return Status::GRPC_JSON_PARSE_ERROR; } break; case State::GRPC_JSON_STATE_END: return Status::GRPC_JSON_PARSE_ERROR; } } } GPR_UNREACHABLE_CODE(return Status::GRPC_JSON_INTERNAL_ERROR); } grpc_error* JsonReader::Parse(absl::string_view input, Json* output) { JsonReader reader(input); Status status = reader.Run(); if (reader.truncated_errors_) { reader.errors_.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING( "too many errors encountered during JSON parsing -- fix reported " "errors and try again to see additional errors")); } if (status == Status::GRPC_JSON_INTERNAL_ERROR) { reader.errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( absl::StrCat("internal error in JSON parser at index ", reader.CurrentIndex()) .c_str())); } else if (status == Status::GRPC_JSON_PARSE_ERROR) { reader.errors_.push_back(GRPC_ERROR_CREATE_FROM_COPIED_STRING( absl::StrCat("JSON parse error at index ", reader.CurrentIndex()) .c_str())); } if (!reader.errors_.empty()) { return GRPC_ERROR_CREATE_FROM_VECTOR("JSON parsing failed", &reader.errors_); } *output = std::move(reader.root_value_); return GRPC_ERROR_NONE; } } // namespace Json Json::Parse(absl::string_view json_str, grpc_error** error) { Json value; *error = JsonReader::Parse(json_str, &value); return value; } } // namespace grpc_core