| /* |
| * |
| * 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 <grpc/support/port_platform.h> |
| |
| #include <inttypes.h> |
| #include <stdlib.h> |
| |
| #include <algorithm> |
| #include <map> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/base/attributes.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_format.h" |
| #include "absl/strings/string_view.h" |
| |
| #include <grpc/support/log.h> |
| |
| #include "src/core/lib/iomgr/error.h" |
| #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_handle 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<const uint8_t*>(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; } |
| |
| GRPC_MUST_USE_RESULT bool StringAddChar(uint32_t c); |
| GRPC_MUST_USE_RESULT bool 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<grpc_error_handle> errors_; |
| bool truncated_errors_ = false; |
| uint8_t utf8_bytes_remaining_ = 0; |
| |
| Json root_value_; |
| std::vector<Json*> stack_; |
| |
| std::string key_; |
| std::string string_; |
| }; |
| |
| bool JsonReader::StringAddChar(uint32_t c) { |
| switch (utf8_bytes_remaining_) { |
| case 0: |
| if ((c & 0x80) == 0) { |
| utf8_bytes_remaining_ = 0; |
| } else if ((c & 0xe0) == 0xc0) { |
| utf8_bytes_remaining_ = 1; |
| } else if ((c & 0xf0) == 0xe0) { |
| utf8_bytes_remaining_ = 2; |
| } else if ((c & 0xf8) == 0xf0) { |
| utf8_bytes_remaining_ = 3; |
| } else { |
| return false; |
| } |
| break; |
| case 1: |
| case 2: |
| case 3: |
| if ((c & 0xc0) != 0x80) return false; |
| --utf8_bytes_remaining_; |
| break; |
| default: |
| abort(); |
| } |
| string_.push_back(static_cast<uint8_t>(c)); |
| return true; |
| } |
| |
| bool JsonReader::StringAddUtf32(uint32_t c) { |
| if (c <= 0x7f) { |
| return StringAddChar(c); |
| } else if (c <= 0x7ff) { |
| uint32_t b1 = 0xc0 | ((c >> 6) & 0x1f); |
| uint32_t b2 = 0x80 | (c & 0x3f); |
| return 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); |
| return 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); |
| return StringAddChar(b1) && StringAddChar(b2) && StringAddChar(b3) && |
| StringAddChar(b4); |
| } else { |
| return false; |
| } |
| } |
| |
| 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_CPP_STRING( |
| absl::StrFormat("duplicate key \"%s\" at index %" PRIuPTR, key_, |
| CurrentIndex()))); |
| } |
| } |
| 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_CPP_STRING( |
| absl::StrFormat("exceeded max stack depth (%d) at index %" PRIuPTR, |
| GRPC_JSON_MAX_DEPTH, CurrentIndex()))); |
| } |
| 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: |
| switch (state_) { |
| 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: |
| break; |
| } |
| if (IsComplete()) { |
| return Status::GRPC_JSON_DONE; |
| } |
| return Status::GRPC_JSON_PARSE_ERROR; |
| |
| /* 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; |
| } |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| 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; |
| } |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| 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; |
| } 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; |
| ABSL_FALLTHROUGH_INTENDED; |
| |
| 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; |
| } |
| if (!StringAddChar('\\')) return Status::GRPC_JSON_PARSE_ERROR; |
| 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; |
| // Once the key is parsed, there should no un-matched utf8 |
| // encoded bytes. |
| if (utf8_bytes_remaining_ != 0) { |
| return Status::GRPC_JSON_PARSE_ERROR; |
| } |
| SetKey(); |
| } else { |
| if (c < 32) return Status::GRPC_JSON_PARSE_ERROR; |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| } |
| 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; |
| // Once the value is parsed, there should no un-matched utf8 |
| // encoded bytes. |
| if (utf8_bytes_remaining_ != 0) { |
| return Status::GRPC_JSON_PARSE_ERROR; |
| } |
| SetString(); |
| } else { |
| if (c < 32) return Status::GRPC_JSON_PARSE_ERROR; |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| } |
| 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': |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| 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 '-': |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| 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 '/': |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| break; |
| case 'b': |
| if (!StringAddChar('\b')) return Status::GRPC_JSON_PARSE_ERROR; |
| break; |
| case 'f': |
| if (!StringAddChar('\f')) return Status::GRPC_JSON_PARSE_ERROR; |
| break; |
| case 'n': |
| if (!StringAddChar('\n')) return Status::GRPC_JSON_PARSE_ERROR; |
| break; |
| case 'r': |
| if (!StringAddChar('\r')) return Status::GRPC_JSON_PARSE_ERROR; |
| break; |
| case 't': |
| if (!StringAddChar('\t')) return Status::GRPC_JSON_PARSE_ERROR; |
| 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<uint16_t>(unicode_char_ << 4); |
| unicode_char_ = static_cast<uint16_t>(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<uint32_t>( |
| (unicode_high_surrogate_ - 0xd800) * 0x400); |
| utf32 += static_cast<uint32_t>(unicode_char_ - 0xdc00); |
| if (!StringAddUtf32(utf32)) { |
| return Status::GRPC_JSON_PARSE_ERROR; |
| } |
| unicode_high_surrogate_ = 0; |
| } else { |
| /* anything else */ |
| if (unicode_high_surrogate_ != 0) { |
| return Status::GRPC_JSON_PARSE_ERROR; |
| } |
| if (!StringAddUtf32(unicode_char_)) { |
| return Status::GRPC_JSON_PARSE_ERROR; |
| } |
| } |
| 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: |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| 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: |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| 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; |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| state_ = State::GRPC_JSON_STATE_VALUE_NUMBER_DOT; |
| break; |
| |
| case State::GRPC_JSON_STATE_VALUE_NUMBER_DOT: |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| 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: |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| 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: |
| if (!StringAddChar(c)) return Status::GRPC_JSON_PARSE_ERROR; |
| 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_handle 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_CPP_STRING(absl::StrCat( |
| "internal error in JSON parser at index ", reader.CurrentIndex()))); |
| } else if (status == Status::GRPC_JSON_PARSE_ERROR) { |
| reader.errors_.push_back(GRPC_ERROR_CREATE_FROM_CPP_STRING( |
| absl::StrCat("JSON parse error at index ", reader.CurrentIndex()))); |
| } |
| 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_handle* error) { |
| Json value; |
| *error = JsonReader::Parse(json_str, &value); |
| return value; |
| } |
| |
| } // namespace grpc_core |