From 6a9b33ff933cfd562f5a746964b1e838a84a4a42 Mon Sep 17 00:00:00 2001 From: Ned Wright Date: Wed, 15 Feb 2023 19:09:38 +0000 Subject: [PATCH] Feb 15th 2023 update --- README.md | 3 +- components/CMakeLists.txt | 1 - .../nginx_attachment/nginx_attachment.cc | 94 + .../generic_rulebase/evaluators/asset_eval.cc | 12 + components/generic_rulebase/match_query.cc | 57 +- .../generic_rulebase/parameters_config.cc | 43 +- .../generic_rulebase/triggers_config.cc | 36 +- components/include/WaapEnums.h | 1 + .../include/generic_rulebase/match_query.h | 19 +- .../generic_rulebase/parameters_config.h | 7 + .../generic_rulebase/triggers_config.h | 6 +- components/include/i_service_controller.h | 3 +- components/include/nginx_attachment.h | 8 +- .../report_messaging/report_messaging.cc | 21 +- .../include/mock/mock_service_controller.h | 5 +- .../local_policy_mgmt_gen/CMakeLists.txt | 4 +- .../appsec_practice_section.cc | 571 +++ .../exceptions_section.cc | 242 ++ .../include/appsec_practice_section.h | 576 +-- .../include/exceptions_section.h | 216 +- .../include/ingress_data.h | 124 +- .../include/policy_maker_utils.h | 132 + .../include/rules_config_section.h | 305 +- .../include/settings_section.h | 64 +- .../include/snort_section.h | 34 +- .../include/triggers_section.h | 459 +-- .../include/trusted_sources_section.h | 149 +- .../local_policy_mgmt_gen/ingress_data.cc | 178 + .../local_policy_mgmt_gen.cc | 150 +- .../policy_maker_utils.cc | 579 +++ .../rules_config_section.cc | 365 ++ .../local_policy_mgmt_gen/settings_section.cc | 74 + .../local_policy_mgmt_gen/snort_section.cc | 41 + .../local_policy_mgmt_gen/triggers_section.cc | 522 +++ .../trusted_sources_section.cc | 125 + .../modules/orchestration_status.cc | 20 +- .../orchestration/orchestration_comp.cc | 47 +- .../orchestration_multitenant_ut.cc | 16 +- .../orchestration_ut/orchestration_ut.cc | 64 +- .../service_controller/service_controller.cc | 31 +- .../local_communication.cc | 8 +- .../security_apps/waap/include/i_serialize.h | 4 +- .../reputation/reputation_features_agg.cc | 26 +- .../waap/waap_clib/CMakeLists.txt | 1 + .../waap/waap_clib/DeepParser.cc | 46 +- .../waap_clib/IndicatorsFiltersManager.cc | 14 +- .../waap/waap_clib/IndicatorsFiltersManager.h | 2 + .../security_apps/waap/waap_clib/ParserBase.h | 1 + .../security_apps/waap/waap_clib/ParserGql.cc | 134 + .../security_apps/waap/waap_clib/ParserGql.h | 56 + .../waap/waap_clib/ParserJson.cc | 4 + .../waap/waap_clib/Serializator.cc | 117 +- .../waap/waap_clib/TypeIndicatorsFilter.cc | 3 +- .../waap/waap_clib/WaapAssetState.cc | 2 +- .../waap/waap_clib/WaapConfigApplication.cc | 9 + .../waap/waap_clib/WaapConfigApplication.h | 6 +- .../waap/waap_clib/WaapScanner.cc | 17 +- .../waap/waap_clib/Waf2Engine.cc | 19 +- .../security_apps/waap/waap_clib/Waf2Util.cc | 52 +- .../security_apps/waap/waap_clib/Waf2Util.h | 4 + components/utils/CMakeLists.txt | 1 + .../http_transaction_data/CMakeLists.txt | 0 .../http_transaction_data.cc | 0 .../http_transaction_data_ut/CMakeLists.txt | 0 .../http_transaction_data_ut.cc | 0 core/config/config.cc | 50 +- core/connkey/connkey.cc | 20 - core/include/general/logging_comp.h | 4 +- core/include/general/tenant_profile_pair.h | 2 +- .../services_sdk/interfaces/i_logging.h | 6 +- .../interfaces/i_tenant_manager.h | 2 + .../interfaces/mock/mock_logging.h | 2 +- .../interfaces/mock/mock_tenant_manager.h | 1 + .../services_sdk/resources/debug_flags.h | 2 + .../resources/report/report_enums.h | 2 + core/include/services_sdk/utilities/connkey.h | 15 - core/instance_awareness/instance_awareness.cc | 6 +- .../instance_awareness_ut.cc | 34 +- core/logging/CMakeLists.txt | 2 +- core/logging/cef_stream.cc | 63 +- core/logging/k8s_svc_stream.cc | 97 + core/logging/log_streams.h | 24 +- core/logging/logging.cc | 17 +- core/logging/logging_ut/logging_ut.cc | 176 +- core/logging/syslog_stream.cc | 80 +- core/report/tag_and_enum_management.cc | 7 +- core/tenant_manager/tenant_manager.cc | 77 +- external/CMakeLists.txt | 1 + external/graphqlparser/.clang-tidy | 326 ++ external/graphqlparser/.gitignore | 23 + external/graphqlparser/.travis.yml | 21 + external/graphqlparser/AstNode.h | 36 + external/graphqlparser/CMakeLists.txt | 148 + external/graphqlparser/CONTRIBUTING.md | 23 + external/graphqlparser/GraphQLParser.cpp | 76 + external/graphqlparser/GraphQLParser.h | 55 + external/graphqlparser/JsonVisitor.cpp | 161 + external/graphqlparser/JsonVisitor.h | 121 + external/graphqlparser/LICENSE | 21 + external/graphqlparser/README.clang-tidy | 7 + external/graphqlparser/README.md | 94 + external/graphqlparser/ast/.gitignore | 1 + external/graphqlparser/ast/ast.ast | 203 + external/graphqlparser/ast/ast.py | 61 + external/graphqlparser/ast/c.py | 100 + external/graphqlparser/ast/c_impl.py | 61 + external/graphqlparser/ast/c_visitor_impl.py | 39 + external/graphqlparser/ast/casing.py | 26 + external/graphqlparser/ast/cxx.py | 197 + external/graphqlparser/ast/cxx_impl.py | 61 + .../ast/cxx_json_visitor_header.py | 42 + .../ast/cxx_json_visitor_impl.py | 80 + external/graphqlparser/ast/cxx_visitor.py | 64 + external/graphqlparser/ast/js.py | 65 + external/graphqlparser/ast/license.py | 10 + external/graphqlparser/c/.gitignore | 3 + external/graphqlparser/c/GraphQLAstNode.cpp | 25 + external/graphqlparser/c/GraphQLAstNode.h | 33 + external/graphqlparser/c/GraphQLAstToJSON.cpp | 21 + external/graphqlparser/c/GraphQLAstToJSON.h | 24 + .../graphqlparser/c/GraphQLAstVisitor.cpp | 55 + external/graphqlparser/c/GraphQLAstVisitor.h | 53 + external/graphqlparser/c/GraphQLParser.cpp | 35 + external/graphqlparser/c/GraphQLParser.h | 54 + external/graphqlparser/clang-tidy-all.sh | 3 + external/graphqlparser/cmake/version.cmake | 16 + external/graphqlparser/dump_json_ast.cpp | 48 + external/graphqlparser/go/.gitignore | 1 + external/graphqlparser/go/README.md | 20 + external/graphqlparser/go/callbacks.go | 18 + external/graphqlparser/go/gotest.go | 64 + external/graphqlparser/lexer.lpp | 324 ++ external/graphqlparser/libgraphqlparser.pc.in | 11 + external/graphqlparser/parser.ypp | 693 ++++ external/graphqlparser/parsergen/lexer.cpp | 2633 +++++++++++++ external/graphqlparser/parsergen/lexer.h | 528 +++ external/graphqlparser/parsergen/location.hh | 189 + .../graphqlparser/parsergen/parser.tab.cpp | 3300 +++++++++++++++++ .../graphqlparser/parsergen/parser.tab.hpp | 646 ++++ external/graphqlparser/parsergen/position.hh | 179 + external/graphqlparser/parsergen/stack.hh | 156 + external/graphqlparser/python/.gitignore | 1 + external/graphqlparser/python/CMakeLists.txt | 14 + external/graphqlparser/python/README.md | 5 + external/graphqlparser/python/example.py | 31 + external/graphqlparser/syntaxdefs.h | 19 + external/graphqlparser/test/.gitignore | 5 + external/graphqlparser/test/BuildCAPI.c | 5 + external/graphqlparser/test/CMakeLists.txt | 25 + .../graphqlparser/test/JsonVisitorTests.cpp | 28 + external/graphqlparser/test/ParserTests.cpp | 352 ++ .../graphqlparser/test/kitchen-sink.graphql | 59 + external/graphqlparser/test/kitchen-sink.json | 1 + .../test/schema-kitchen-sink.graphql | 78 + .../test/schema-kitchen-sink.json | 1 + external/graphqlparser/test/valgrind.supp | 33 + nodes/http_transaction_handler/CMakeLists.txt | 1 + .../orchestration/package/open-appsec-ctl.sh | 10 +- .../package/orchestration_package.sh | 28 +- 159 files changed, 16474 insertions(+), 2096 deletions(-) create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/appsec_practice_section.cc create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/exceptions_section.cc create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/include/policy_maker_utils.h create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/ingress_data.cc create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/policy_maker_utils.cc create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/rules_config_section.cc create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/settings_section.cc create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/snort_section.cc create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/triggers_section.cc create mode 100644 components/security_apps/orchestration/local_policy_mgmt_gen/trusted_sources_section.cc create mode 100644 components/security_apps/waap/waap_clib/ParserGql.cc create mode 100644 components/security_apps/waap/waap_clib/ParserGql.h rename components/{ => utils}/http_transaction_data/CMakeLists.txt (100%) rename components/{ => utils}/http_transaction_data/http_transaction_data.cc (100%) rename components/{ => utils}/http_transaction_data/http_transaction_data_ut/CMakeLists.txt (100%) rename components/{ => utils}/http_transaction_data/http_transaction_data_ut/http_transaction_data_ut.cc (100%) create mode 100644 core/logging/k8s_svc_stream.cc create mode 100644 external/graphqlparser/.clang-tidy create mode 100644 external/graphqlparser/.gitignore create mode 100644 external/graphqlparser/.travis.yml create mode 100644 external/graphqlparser/AstNode.h create mode 100644 external/graphqlparser/CMakeLists.txt create mode 100644 external/graphqlparser/CONTRIBUTING.md create mode 100644 external/graphqlparser/GraphQLParser.cpp create mode 100644 external/graphqlparser/GraphQLParser.h create mode 100644 external/graphqlparser/JsonVisitor.cpp create mode 100644 external/graphqlparser/JsonVisitor.h create mode 100644 external/graphqlparser/LICENSE create mode 100644 external/graphqlparser/README.clang-tidy create mode 100644 external/graphqlparser/README.md create mode 100644 external/graphqlparser/ast/.gitignore create mode 100644 external/graphqlparser/ast/ast.ast create mode 100644 external/graphqlparser/ast/ast.py create mode 100644 external/graphqlparser/ast/c.py create mode 100644 external/graphqlparser/ast/c_impl.py create mode 100644 external/graphqlparser/ast/c_visitor_impl.py create mode 100644 external/graphqlparser/ast/casing.py create mode 100644 external/graphqlparser/ast/cxx.py create mode 100644 external/graphqlparser/ast/cxx_impl.py create mode 100644 external/graphqlparser/ast/cxx_json_visitor_header.py create mode 100644 external/graphqlparser/ast/cxx_json_visitor_impl.py create mode 100644 external/graphqlparser/ast/cxx_visitor.py create mode 100644 external/graphqlparser/ast/js.py create mode 100644 external/graphqlparser/ast/license.py create mode 100644 external/graphqlparser/c/.gitignore create mode 100644 external/graphqlparser/c/GraphQLAstNode.cpp create mode 100644 external/graphqlparser/c/GraphQLAstNode.h create mode 100644 external/graphqlparser/c/GraphQLAstToJSON.cpp create mode 100644 external/graphqlparser/c/GraphQLAstToJSON.h create mode 100644 external/graphqlparser/c/GraphQLAstVisitor.cpp create mode 100644 external/graphqlparser/c/GraphQLAstVisitor.h create mode 100644 external/graphqlparser/c/GraphQLParser.cpp create mode 100644 external/graphqlparser/c/GraphQLParser.h create mode 100755 external/graphqlparser/clang-tidy-all.sh create mode 100644 external/graphqlparser/cmake/version.cmake create mode 100644 external/graphqlparser/dump_json_ast.cpp create mode 100644 external/graphqlparser/go/.gitignore create mode 100644 external/graphqlparser/go/README.md create mode 100644 external/graphqlparser/go/callbacks.go create mode 100644 external/graphqlparser/go/gotest.go create mode 100644 external/graphqlparser/lexer.lpp create mode 100644 external/graphqlparser/libgraphqlparser.pc.in create mode 100644 external/graphqlparser/parser.ypp create mode 100644 external/graphqlparser/parsergen/lexer.cpp create mode 100644 external/graphqlparser/parsergen/lexer.h create mode 100644 external/graphqlparser/parsergen/location.hh create mode 100644 external/graphqlparser/parsergen/parser.tab.cpp create mode 100644 external/graphqlparser/parsergen/parser.tab.hpp create mode 100644 external/graphqlparser/parsergen/position.hh create mode 100644 external/graphqlparser/parsergen/stack.hh create mode 100644 external/graphqlparser/python/.gitignore create mode 100644 external/graphqlparser/python/CMakeLists.txt create mode 100644 external/graphqlparser/python/README.md create mode 100755 external/graphqlparser/python/example.py create mode 100644 external/graphqlparser/syntaxdefs.h create mode 100644 external/graphqlparser/test/.gitignore create mode 100644 external/graphqlparser/test/BuildCAPI.c create mode 100644 external/graphqlparser/test/CMakeLists.txt create mode 100644 external/graphqlparser/test/JsonVisitorTests.cpp create mode 100644 external/graphqlparser/test/ParserTests.cpp create mode 100644 external/graphqlparser/test/kitchen-sink.graphql create mode 100644 external/graphqlparser/test/kitchen-sink.json create mode 100644 external/graphqlparser/test/schema-kitchen-sink.graphql create mode 100644 external/graphqlparser/test/schema-kitchen-sink.json create mode 100644 external/graphqlparser/test/valgrind.supp diff --git a/README.md b/README.md index dd1eda4..a835ac7 100644 --- a/README.md +++ b/README.md @@ -78,12 +78,13 @@ Before compiling the services, you'll need to ensure the latest development vers * GTest * GMock * cURL +* Python2 An example of installing the packages on Alpine: ```bash $ apk update - $ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev + $ apk add boost-dev openssl-dev pcre2-dev libxml2-dev gtest-dev curl-dev python2 ``` ## Compiling and packaging the agent code diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b051072..7d8bd27 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,6 +1,5 @@ add_subdirectory(report_messaging) add_subdirectory(http_manager) -add_subdirectory(http_transaction_data) add_subdirectory(generic_rulebase) add_subdirectory(signal_handler) add_subdirectory(gradual_deployment) diff --git a/components/attachment-intakers/nginx_attachment/nginx_attachment.cc b/components/attachment-intakers/nginx_attachment/nginx_attachment.cc index d007437..801c818 100755 --- a/components/attachment-intakers/nginx_attachment/nginx_attachment.cc +++ b/components/attachment-intakers/nginx_attachment/nginx_attachment.cc @@ -149,6 +149,7 @@ public: { dbgFlow(D_NGINX_ATTACHMENT) << "Initializing NGINX attachment"; + i_env = Singleton::Consume::by(); timer = Singleton::Consume::by(); i_socket = Singleton::Consume::by(); mainloop = Singleton::Consume::by(); @@ -156,6 +157,30 @@ public: i_transaction_table = Singleton::Consume>::by(); inst_awareness = Singleton::Consume::by(); + auto agent_type = getSetting("agentType"); + bool is_nsaas_env = false; + if (agent_type.ok() && (*agent_type == "CloudNative" || *agent_type == "VirtualNSaaS")) { + is_nsaas_env = true; + } + + if (is_nsaas_env && inst_awareness->getFamilyID().ok()) { + mainloop->addOneTimeRoutine( + I_MainLoop::RoutineType::Offline, + [this] () + { + while (true) { + if (!setActiveTenantAndProfile()) { + mainloop->yield(std::chrono::seconds(2)); + } else { + break; + } + } + }, + "Setting active tenant and profile for an NGINX based security app", + false + ); + } + metric_report_interval = chrono::seconds( getConfigurationWithDefault( METRIC_PERIODIC_TIMEOUT, @@ -237,6 +262,73 @@ public: dbgInfo(D_NGINX_ATTACHMENT) << "Successfully initialized NGINX Attachment"; } + bool + setActiveTenantAndProfile() + { + string container_id = inst_awareness->getFamilyID().unpack(); + dbgTrace(D_NGINX_ATTACHMENT) << "Found a family ID: " << container_id; + + I_ShellCmd *shell_cmd = Singleton::Consume::by(); + + string cmd = + "docker inspect --format='{{.Name}}' " + container_id + + " | awk -F'cp_nginx_gaia' '{print substr($2, index($2, \" \"))}'"; + auto maybe_tenant_id = shell_cmd->getExecOutput(cmd, 1000, false); + + if (maybe_tenant_id.ok()) { + + string tenant_id = *maybe_tenant_id; + tenant_id.erase(remove(tenant_id.begin(), tenant_id.end(), '\n'), tenant_id.end()); + dbgTrace(D_NGINX_ATTACHMENT) << "The tenant ID found is :" << tenant_id; + + static string region; + if (region.empty()) { + const char *env_region = getenv("CP_NSAAS_REGION"); + if (env_region) { + region = env_region; + } else { + region = getProfileAgentSettingWithDefault("eu-west-1", "accessControl.region"); + } + dbgInfo(D_NGINX_ATTACHMENT) << "Resolved region is " << region; + } + + string profile_id = Singleton::Consume::by()->getProfileId( + tenant_id, + region + ); + + if (!profile_id.empty()) { + i_env->setActiveTenantAndProfile(tenant_id, profile_id); + dbgTrace(D_NGINX_ATTACHMENT) + << "NGINX attachment setting active context. Tenant ID: " + << tenant_id + << ", Profile ID: " + << profile_id + << ", Region: " + << region; + return true; + } else { + dbgWarning(D_NGINX_ATTACHMENT) + << "Received an empty profile ID. Tenant ID: " + << tenant_id + << ", Region: " + << region; + + return false; + } + } else { + dbgWarning(D_NGINX_ATTACHMENT) + << "Failed getting the tenant ID: " + << cmd + << ". Error :" + << maybe_tenant_id.getErr(); + + return false; + } + + return true; + } + void fini() { @@ -1714,6 +1806,7 @@ private: I_Socket *i_socket = nullptr; I_TimeGet *timer = nullptr; I_MainLoop *mainloop = nullptr; + I_Environment *i_env = nullptr; I_HttpManager *http_manager = nullptr; I_InstanceAwareness *inst_awareness = nullptr; I_TableSpecific *i_transaction_table = nullptr; @@ -1750,6 +1843,7 @@ void NginxAttachment::preload() { pimpl->preload(); + registerExpectedSetting("agentType"); registerExpectedConfiguration("HTTP manager", "Container mode"); registerExpectedConfiguration("HTTP manager", "Shared memory segment size in KB"); registerExpectedConfiguration("HTTP manager", "Nginx permission"); diff --git a/components/generic_rulebase/evaluators/asset_eval.cc b/components/generic_rulebase/evaluators/asset_eval.cc index 3207ed0..ad0e35c 100755 --- a/components/generic_rulebase/evaluators/asset_eval.cc +++ b/components/generic_rulebase/evaluators/asset_eval.cc @@ -22,6 +22,8 @@ using namespace std; +USE_DEBUG_FLAG(D_RULEBASE_CONFIG); + string AssetMatcher::ctx_key = "asset_id"; AssetMatcher::AssetMatcher(const vector ¶ms) @@ -36,5 +38,15 @@ AssetMatcher::evalVariable() const I_Environment *env = Singleton::Consume::by(); auto bc_asset_id_ctx = env->get(AssetMatcher::ctx_key); + if (bc_asset_id_ctx.ok()) { + dbgTrace(D_RULEBASE_CONFIG) + << "Asset ID: " + << asset_id + << "; Current set assetId context: " + << *bc_asset_id_ctx; + } else { + dbgTrace(D_RULEBASE_CONFIG) << "Asset ID: " << asset_id << ". Empty context"; + } + return bc_asset_id_ctx.ok() && *bc_asset_id_ctx == asset_id; } diff --git a/components/generic_rulebase/match_query.cc b/components/generic_rulebase/match_query.cc index 6e2852d..16b1582 100755 --- a/components/generic_rulebase/match_query.cc +++ b/components/generic_rulebase/match_query.cc @@ -95,6 +95,8 @@ MatchQuery::load(cereal::JSONInputArchive &archive_in) is_specific_label = false; } } + is_ignore_keyword = (key == "indicator"); + if (condition_type != Conditions::Exist) { archive_in(cereal::make_nvp("value", value)); for(const auto &val: value) { @@ -221,23 +223,34 @@ MatchQuery::getAllKeys() const } bool -MatchQuery::matchAttributes(const unordered_map> &key_value_pairs) const +MatchQuery::matchAttributes( + const unordered_map> &key_value_pairs, + set &matched_override_keywords ) const { + if (type == MatchType::Condition) { auto key_value_pair = key_value_pairs.find(key); if (key_value_pair == key_value_pairs.end()) { dbgTrace(D_RULEBASE_CONFIG) << "Ignoring irrelevant key: " << key; return false; } - return matchAttributes(key_value_pair->second); + return matchAttributes(key_value_pair->second, matched_override_keywords); } else if (type == MatchType::Operator && operator_type == Operators::And) { for (const MatchQuery &inner_match: items) { - if (!inner_match.matchAttributes(key_value_pairs)) return false; + if (!inner_match.matchAttributes(key_value_pairs, matched_override_keywords)) { + return false; + } } return true; } else if (type == MatchType::Operator && operator_type == Operators::Or) { + // With 'or' condition, evaluate matched override keywords first and add the ones that were fully matched + set inner_override_keywords; for (const MatchQuery &inner_match: items) { - if (inner_match.matchAttributes(key_value_pairs)) return true; + inner_override_keywords.clear(); + if (inner_match.matchAttributes(key_value_pairs, inner_override_keywords)) { + matched_override_keywords.insert(inner_override_keywords.begin(), inner_override_keywords.end()); + return true; + } } return false; } else { @@ -246,18 +259,39 @@ MatchQuery::matchAttributes(const unordered_map> &key_value_ return false; } +MatchQuery::MatchResult +MatchQuery::getMatch( const unordered_map> &key_value_pairs) const +{ + MatchQuery::MatchResult matches; + matches.matched_keywords = make_shared>(); + matches.is_match = matchAttributes(key_value_pairs, *matches.matched_keywords); + return matches; +} + bool -MatchQuery::matchAttributes(const set &values) const +MatchQuery::matchAttributes( + const unordered_map> &key_value_pairs) const +{ + return getMatch(key_value_pairs).is_match; +} + +bool +MatchQuery::matchAttributes( + const set &values, + set &matched_override_keywords) const { auto &type = condition_type; bool negate = type == MatchQuery::Conditions::NotEquals || type == MatchQuery::Conditions::NotIn; - bool match = isRegEx() ? matchAttributesRegEx(values) : matchAttributesString(values); + bool match = isRegEx() ? matchAttributesRegEx(values, matched_override_keywords) : matchAttributesString(values); return negate ? !match : match; } bool -MatchQuery::matchAttributesRegEx(const set &values) const +MatchQuery::matchAttributesRegEx( + const set &values, + set &matched_override_keywords) const { + bool res = false; boost::cmatch value_matcher; for (const boost::regex &val_regex : regex_values) { for (const string &requested_match_value : values) { @@ -268,11 +302,16 @@ MatchQuery::matchAttributesRegEx(const set &values) const value_matcher, val_regex)) { - return true; + res = true; + if (is_ignore_keyword) { + matched_override_keywords.insert(requested_match_value); + } else { + return res; + } } } } - return false; + return res; } bool diff --git a/components/generic_rulebase/parameters_config.cc b/components/generic_rulebase/parameters_config.cc index 897ba05..7677b86 100755 --- a/components/generic_rulebase/parameters_config.cc +++ b/components/generic_rulebase/parameters_config.cc @@ -108,19 +108,50 @@ ParameterException::load(cereal::JSONInputArchive &archive_in) } set -ParameterException::getBehavior(const unordered_map> &key_value_pairs) const +ParameterException::getBehavior( + const unordered_map> &key_value_pairs, + set &matched_override_keywords) const { set matched_behaviors; + + matched_override_keywords.clear(); dbgTrace(D_RULEBASE_CONFIG) << "Matching exception"; for (const MatchBehaviorPair &match_behavior_pair: match_queries) { - if (match_behavior_pair.match.matchAttributes(key_value_pairs)) { + MatchQuery::MatchResult match_res = match_behavior_pair.match.getMatch(key_value_pairs); + if (match_res.is_match) { dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception from a list of matches."; - matched_behaviors.insert(match_behavior_pair.behavior); + // When matching indicators with action=ignore, we expect no behavior override. + // Instead, a matched keywords list should be returned which will be later removed from score calculation + if (match_res.matched_keywords->size() > 0 && match_behavior_pair.behavior == action_ignore) { + matched_override_keywords.insert(match_res.matched_keywords->begin(), + match_res.matched_keywords->end()); + } else { + matched_behaviors.insert(match_behavior_pair.behavior); + } } } - if (match_queries.empty() && match.matchAttributes(key_value_pairs)) { - dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception."; - matched_behaviors.insert(behavior); + + if (match_queries.empty()) { + MatchQuery::MatchResult match_res = match.getMatch(key_value_pairs); + if (match_res.is_match) { + dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception."; + // When matching indicators with action=ignore, we expect no behavior override. + // Instead, a matched keywords list should be returned which will be later removed from score calculation + if (match_res.matched_keywords->size() > 0 && behavior == action_ignore) { + matched_override_keywords.insert(match_res.matched_keywords->begin(), + match_res.matched_keywords->end()); + } else { + matched_behaviors.insert(behavior); + } + } } + return matched_behaviors; } + +set +ParameterException::getBehavior(const unordered_map> &key_value_pairs) const +{ + set keywords; + return getBehavior(key_value_pairs, keywords); +} diff --git a/components/generic_rulebase/triggers_config.cc b/components/generic_rulebase/triggers_config.cc index abfbbaf..e0f43b0 100755 --- a/components/generic_rulebase/triggers_config.cc +++ b/components/generic_rulebase/triggers_config.cc @@ -124,16 +124,36 @@ setTriggersFlag(const string &key, cereal::JSONInputArchive &ar, EnumClass flag, } static void -setLogConfiguration(const ReportIS::StreamType &log_type, const string &log_server_url = "") +setLogConfiguration( + const ReportIS::StreamType &log_type, + const string &log_server_url = "", + const string &protocol = "" +) { dbgTrace(D_RULEBASE_CONFIG) << "log server url:" << log_server_url; - if (log_server_url != "") { - Singleton::Consume::by()->addStream(log_type, log_server_url); + if (log_server_url != "" && protocol != "") { + Singleton::Consume::by()->addStream(log_type, log_server_url, protocol); } else { Singleton::Consume::by()->addStream(log_type); } } +static string +parseProtocolWithDefault( + const std::string &default_value, + const std::string &key_name, + cereal::JSONInputArchive &archive_in +) +{ + string value; + try { + archive_in(cereal::make_nvp(key_name, value)); + } catch (const cereal::Exception &e) { + return default_value; + } + return value; +} + void LogTriggerConf::load(cereal::JSONInputArchive& archive_in) { @@ -142,6 +162,9 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in) parseJSONKey("verbosity", verbosity, archive_in); parseJSONKey("urlForSyslog", url_for_syslog, archive_in); parseJSONKey("urlForCef", url_for_cef, archive_in); + parseJSONKey("syslogProtocol", syslog_protocol, archive_in); + syslog_protocol = parseProtocolWithDefault("UDP", "syslogProtocol", archive_in); + cef_protocol = parseProtocolWithDefault("UDP", "cefProtocol", archive_in); setTriggersFlag("webBody", archive_in, WebLogFields::webBody, log_web_fields); setTriggersFlag("webHeaders", archive_in, WebLogFields::webHeaders, log_web_fields); @@ -197,11 +220,14 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in) case ReportIS::StreamType::JSON_LOG_FILE: setLogConfiguration(ReportIS::StreamType::JSON_LOG_FILE); break; + case ReportIS::StreamType::JSON_K8S_SVC: + setLogConfiguration(ReportIS::StreamType::JSON_K8S_SVC); + break; case ReportIS::StreamType::SYSLOG: - setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog()); + setLogConfiguration(ReportIS::StreamType::SYSLOG, getUrlForSyslog(), syslog_protocol); break; case ReportIS::StreamType::CEF: - setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef()); + setLogConfiguration(ReportIS::StreamType::CEF, getUrlForCef(), cef_protocol); break; case ReportIS::StreamType::NONE: break; case ReportIS::StreamType::COUNT: break; diff --git a/components/include/WaapEnums.h b/components/include/WaapEnums.h index 7319024..0b69ae0 100755 --- a/components/include/WaapEnums.h +++ b/components/include/WaapEnums.h @@ -48,6 +48,7 @@ enum ParamType { HTML_PARAM_TYPE, URL_PARAM_TYPE, FREE_TEXT_PARAM_TYPE, + FREE_TEXT_FRENCH_PARAM_TYPE, PIPE_PARAM_TYPE, LONG_RANDOM_TEXT_PARAM_TYPE, BASE64_PARAM_TYPE, diff --git a/components/include/generic_rulebase/match_query.h b/components/include/generic_rulebase/match_query.h index 71a6d6e..658f4a2 100755 --- a/components/include/generic_rulebase/match_query.h +++ b/components/include/generic_rulebase/match_query.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "cereal/types/string.hpp" @@ -45,6 +46,13 @@ public: Domain, NotStatic }; + struct MatchResult + { + bool is_match; + std::shared_ptr> matched_keywords; + }; + + MatchQuery(): is_specific_label(false), is_ignore_keyword(false) {} void load(cereal::JSONInputArchive &archive_in); @@ -58,6 +66,7 @@ public: const std::vector & getProtoValue() const { return ip_proto_value; } const std::vector & getItems() const { return items; } std::string getFirstValue() const { return first_value; } + MatchResult getMatch(const std::unordered_map> &key_value_pairs) const; bool matchAttributes(const std::unordered_map> &key_value_pairs) const; bool matchException(const std::string &behaviorKey, const std::string &behaviorValue) const; bool isKeyTypeIp() const; @@ -69,9 +78,14 @@ public: std::set getAllKeys() const; private: + bool matchAttributes( + const std::unordered_map> &key_value_pairs, + std::set &matched_override_keywords) const; StaticKeys getKeyByName(const std::string &key_type_name); - bool matchAttributes(const std::set &values) const; - bool matchAttributesRegEx(const std::set &values) const; + bool matchAttributes(const std::set &values, + std::set &matched_override_keywords) const; + bool matchAttributesRegEx(const std::set &values, + std::set &matched_override_keywords) const; bool matchAttributesString(const std::set &values) const; bool isRegEx() const; @@ -88,6 +102,7 @@ private: std::vector port_value; std::vector ip_proto_value; std::vector items; + bool is_ignore_keyword; }; #endif // __MATCH_QUERY_H__ diff --git a/components/include/generic_rulebase/parameters_config.h b/components/include/generic_rulebase/parameters_config.h index 8317ae3..665f8ec 100755 --- a/components/include/generic_rulebase/parameters_config.h +++ b/components/include/generic_rulebase/parameters_config.h @@ -200,6 +200,11 @@ public: std::set getBehavior(const std::unordered_map> &key_value_pairs) const; + std::set + getBehavior( + const std::unordered_map> &key_value_pairs, + std::set &matched_override_keywords) const; + static bool isGeoLocationExceptionExists() { return is_geo_location_exception_exists; } private: @@ -218,4 +223,6 @@ private: static bool is_geo_location_exception_being_loaded; }; +static const ParameterBehavior action_ignore(BehaviorKey::ACTION, BehaviorValue::IGNORE); + #endif //__PARAMETERS_CONFIG_H__ diff --git a/components/include/generic_rulebase/triggers_config.h b/components/include/generic_rulebase/triggers_config.h index 27f2e09..bea59df 100755 --- a/components/include/generic_rulebase/triggers_config.h +++ b/components/include/generic_rulebase/triggers_config.h @@ -160,8 +160,10 @@ private: std::string name; std::string verbosity; - std::string url_for_syslog = ""; - std::string url_for_cef = ""; + std::string url_for_syslog = "UDP"; + std::string url_for_cef = "UDP"; + std::string syslog_protocol = ""; + std::string cef_protocol = ""; Flags active_streams; Flags should_log_on_detect; Flags should_log_on_prevent; diff --git a/components/include/i_service_controller.h b/components/include/i_service_controller.h index 1dae9b6..b9d472b 100755 --- a/components/include/i_service_controller.h +++ b/components/include/i_service_controller.h @@ -42,7 +42,8 @@ public: const std::string &new_settings_path, const std::vector &new_data_files = {}, const std::string &tenant_id = "", - const std::string &profile_id = "" + const std::string &profile_id = "", + const bool last_iteration = false ) = 0; virtual bool isServiceInstalled(const std::string &service_name) = 0; diff --git a/components/include/nginx_attachment.h b/components/include/nginx_attachment.h index b0d0716..a87a29d 100755 --- a/components/include/nginx_attachment.h +++ b/components/include/nginx_attachment.h @@ -21,6 +21,9 @@ #include "i_http_manager.h" #include "i_static_resources_handler.h" #include "i_socket_is.h" +#include "i_environment.h" +#include "i_shell_cmd.h" +#include "i_tenant_manager.h" #include "transaction_table_metric.h" #include "nginx_attachment_metric.h" #include "nginx_intaker_metric.h" @@ -38,7 +41,10 @@ class NginxAttachment Singleton::Consume, Singleton::Consume, Singleton::Consume, - Singleton::Consume + Singleton::Consume, + Singleton::Consume, + Singleton::Consume, + Singleton::Consume { public: NginxAttachment(); diff --git a/components/report_messaging/report_messaging.cc b/components/report_messaging/report_messaging.cc index 7c45e61..528b5c2 100755 --- a/components/report_messaging/report_messaging.cc +++ b/components/report_messaging/report_messaging.cc @@ -28,15 +28,18 @@ ReportMessaging::~ReportMessaging() LogRest log_rest(report); auto messaging = Singleton::Consume::by(); - messaging->sendObjectWithPersistence( - log_rest, - I_Messaging::Method::POST, - url, - "", - true, - message_type_tag, - is_async_message - ); + try { + messaging->sendObjectWithPersistence( + log_rest, + I_Messaging::Method::POST, + url, + "", + true, + message_type_tag, + is_async_message + ); + } catch (...) { + } } ReportMessaging & diff --git a/components/security_apps/orchestration/include/mock/mock_service_controller.h b/components/security_apps/orchestration/include/mock/mock_service_controller.h index 01e31b5..9cc44ca 100755 --- a/components/security_apps/orchestration/include/mock/mock_service_controller.h +++ b/components/security_apps/orchestration/include/mock/mock_service_controller.h @@ -28,14 +28,15 @@ public: MOCK_CONST_METHOD0(getUpdatePolicyVersion, const std::string &()); - MOCK_METHOD5( + MOCK_METHOD6( updateServiceConfiguration, bool( const std::string &new_policy_path, const std::string &new_settings_path, const std::vector &new_data_files, const std::string &tenant_id, - const std::string &profile_id + const std::string &profile_id, + const bool last_iteration ) ); diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/CMakeLists.txt b/components/security_apps/orchestration/local_policy_mgmt_gen/CMakeLists.txt index 7232b08..1ecfeb7 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/CMakeLists.txt +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/CMakeLists.txt @@ -1 +1,3 @@ -add_library(local_policy_mgmt_gen local_policy_mgmt_gen.cc) +include_directories(include) + +add_library(local_policy_mgmt_gen appsec_practice_section.cc exceptions_section.cc ingress_data.cc local_policy_mgmt_gen.cc policy_maker_utils.cc rules_config_section.cc settings_section.cc snort_section.cc triggers_section.cc trusted_sources_section.cc) diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/appsec_practice_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/appsec_practice_section.cc new file mode 100644 index 0000000..7437369 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/appsec_practice_section.cc @@ -0,0 +1,571 @@ +#include "appsec_practice_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_K8S_POLICY); +// LCOV_EXCL_START Reason: no test exist +void +AppSecWebBotsURI::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots URI"; + parseAppsecJSONKey("uri", uri, archive_in); +} + +const string & +AppSecWebBotsURI::getURI() const +{ + return uri; +} + +void +AppSecPracticeAntiBot::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots"; + parseAppsecJSONKey>("injected-URIs", injected_uris, archive_in); + parseAppsecJSONKey>("validated-URIs", validated_uris, archive_in); + parseAppsecJSONKey("override-mode", override_mode, archive_in, "Inactive"); +} + +void +AppSecPracticeAntiBot::save(cereal::JSONOutputArchive &out_ar) const +{ + vector injected; + vector validated; + for (const AppSecWebBotsURI &uri : injected_uris) injected.push_back(uri.getURI()); + for (const AppSecWebBotsURI &uri : validated_uris) injected.push_back(uri.getURI()); + out_ar( + cereal::make_nvp("injected", injected), + cereal::make_nvp("validated", validated) + ); +} + +void +AppSecWebAttackProtections::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Attack Protections"; + parseAppsecJSONKey("csrf-enabled", csrf_protection, archive_in, "inactive"); + parseAppsecJSONKey("error-disclosure-enabled", error_disclosure, archive_in, "inactive"); + parseAppsecJSONKey("open-redirect-enabled", open_redirect, archive_in, "inactive"); + parseAppsecJSONKey("non-valid-http-methods", non_valid_http_methods, archive_in, false); +} + +const string +AppSecWebAttackProtections::getCsrfProtectionMode() const +{ + if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) { + dbgError(D_K8S_POLICY) + << "Failed to find a value for " + << csrf_protection + << ". Setting CSRF protection to Inactive"; + return "Inactive"; + } + return key_to_practices_val.at(csrf_protection); +} + +const string & +AppSecWebAttackProtections::getErrorDisclosureMode() const +{ + return error_disclosure; +} + +bool +AppSecWebAttackProtections::getNonValidHttpMethods() const +{ + return non_valid_http_methods; +} + +const string +AppSecWebAttackProtections::getOpenRedirectMode() const +{ + if (key_to_practices_val.find(open_redirect) == key_to_practices_val.end()) { + dbgError(D_K8S_POLICY) + << "Failed to find a value for " + << open_redirect + << ". Setting Open Redirect mode to Inactive"; + return "Inactive"; + } + return key_to_practices_val.at(open_redirect); +} + +void +AppSecPracticeWebAttacks::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec"; + parseAppsecJSONKey("protections", protections, archive_in); + if (getMode() == "Prevent") { + parseAppsecJSONKey("minimum-confidence", minimum_confidence, archive_in, "critical"); + } else { + minimum_confidence = "Transparent"; + } + parseAppsecJSONKey("override-mode", mode, archive_in, "Unset"); + parseAppsecJSONKey("max-body-size-kb", max_body_size_kb, archive_in, 1000000); + parseAppsecJSONKey("max-header-size-bytes", max_header_size_bytes, archive_in, 102400); + parseAppsecJSONKey("max-object-depth", max_object_depth, archive_in, 40); + parseAppsecJSONKey("max-url-size-bytes", max_url_size_bytes, archive_in, 32768); +} + +int +AppSecPracticeWebAttacks::getMaxBodySizeKb() const +{ + return max_body_size_kb; +} + +int +AppSecPracticeWebAttacks::getMaxHeaderSizeBytes() const +{ + return max_header_size_bytes; +} + +int +AppSecPracticeWebAttacks::getMaxObjectDepth() const +{ + return max_object_depth; +} + +int +AppSecPracticeWebAttacks::getMaxUrlSizeBytes() const +{ + return max_url_size_bytes; +} + +const string & +AppSecPracticeWebAttacks::getMinimumConfidence() const +{ + return minimum_confidence; +} + +const string & +AppSecPracticeWebAttacks::getMode(const string &default_mode) const +{ + if (mode == "Unset" || (key_to_practices_val.find(mode) == key_to_practices_val.end())) { + dbgError(D_K8S_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode; + return default_mode; + } + return key_to_practices_val.at(mode); +} + +void +AppSecPracticeSnortSignatures::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec Snort Signatures practice"; + parseAppsecJSONKey("override-mode", override_mode, archive_in, "Inactive"); + parseAppsecJSONKey>("configmap", config_map, archive_in); +} + +const string & +AppSecPracticeSnortSignatures::getOverrideMode() const +{ + return override_mode; +} + +const vector & +AppSecPracticeSnortSignatures::getConfigMap() const +{ + return config_map; +} + +void +AppSecPracticeOpenSchemaAPI::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSecPracticeOpenSchemaAPI practice"; + parseAppsecJSONKey("override-mode", override_mode, archive_in, "Inactive"); + parseAppsecJSONKey>("configmap", config_map, archive_in); +} + +const string & +AppSecPracticeOpenSchemaAPI::getOverrideMode() const +{ + return override_mode; +} + +const vector & +AppSecPracticeOpenSchemaAPI::getConfigMap() const +{ + return config_map; +} + +void +AppSecPracticeSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec"; + parseAppsecJSONKey( + "openapi-schema-validation", + openapi_schema_validation, + archive_in + ); + parseAppsecJSONKey("snort-signatures", snort_signatures, archive_in); + parseAppsecJSONKey("web-attacks", web_attacks, archive_in); + parseAppsecJSONKey("anti-bot", anti_bot, archive_in); + parseAppsecJSONKey("name", practice_name, archive_in); +} + +const AppSecPracticeOpenSchemaAPI & +AppSecPracticeSpec::getOpenSchemaValidation() const +{ + return openapi_schema_validation; +} + +const AppSecPracticeSnortSignatures & +AppSecPracticeSpec::getSnortSignatures() const +{ + return snort_signatures; +} + +const AppSecPracticeWebAttacks & +AppSecPracticeSpec::getWebAttacks() const +{ + return web_attacks; +} + +const AppSecPracticeAntiBot & +AppSecPracticeSpec::getAntiBot() const +{ + return anti_bot; +} + +const string & +AppSecPracticeSpec::getName() const +{ + return practice_name; +} + +void +PracticeAdvancedConfig::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("httpHeaderMaxSize", http_header_max_size), + cereal::make_nvp("httpIllegalMethodsAllowed", http_illegal_methods_allowed), + cereal::make_nvp("httpRequestBodyMaxSize", http_request_body_max_size), + cereal::make_nvp("jsonMaxObjectDepth", json_max_object_depth), + cereal::make_nvp("urlMaxSize", url_max_size) + ); +} + +void +TriggersInWaapSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("$triggerType", trigger_type), + cereal::make_nvp("id", id), + cereal::make_nvp("name", name), + cereal::make_nvp("log", log) + ); +} + +AppSecOverride::AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources) +{ + string source_ident = parsed_trusted_sources.getSourceIdent(); + map behavior = {{"httpSourceId", source_ident}}; + parsed_behavior.push_back(behavior); + parsed_match = {{"operator", "BASIC"}, {"tag", "sourceip"}, {"value", "0.0.0.0/0"}}; +} + +void +AppSecOverride::save(cereal::JSONOutputArchive &out_ar) const +{ + string parameter_type = "TrustedSource"; + out_ar( + cereal::make_nvp("parsedBehavior", parsed_behavior), + cereal::make_nvp("parsedMatch", parsed_match) + ); +} + +WebAppSection::WebAppSection( + const string &_application_urls, + const string &_asset_id, + const string &_asset_name, + const string &_rule_id, + const string &_rule_name, + const string &_practice_id, + const string &_practice_name, + const AppSecPracticeSpec &parsed_appsec_spec, + const LogTriggerSection &parsed_log_trigger, + const string &default_mode, + const AppSecTrustedSources &parsed_trusted_sources) + : + application_urls(_application_urls), + asset_id(_asset_id), + asset_name(_asset_name), + rule_id(_rule_id), + rule_name(_rule_name), + practice_id(_practice_id), + practice_name(_practice_name), + context("practiceId(" + practice_id +")"), + web_attack_mitigation_severity(parsed_appsec_spec.getWebAttacks().getMinimumConfidence()), + web_attack_mitigation_mode(parsed_appsec_spec.getWebAttacks().getMode(default_mode)), + practice_advanced_config(parsed_appsec_spec), + anti_bots(parsed_appsec_spec.getAntiBot()), + trusted_sources({parsed_trusted_sources}) +{ + web_attack_mitigation = true; + web_attack_mitigation_action = + web_attack_mitigation_severity == "critical" ? "low" : + web_attack_mitigation_severity == "high" ? "balanced" : + web_attack_mitigation_severity == "medium" ? "high" : + "Error"; + + triggers.push_back(TriggersInWaapSection(parsed_log_trigger)); + for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) { + overrides.push_back(AppSecOverride(source_ident)); + } +} + +void +WebAppSection::save(cereal::JSONOutputArchive &out_ar) const +{ + string disabled_str = "Disabled"; + string detect_str = "Detect"; + vector empty_list; + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("webAttackMitigation", web_attack_mitigation), + cereal::make_nvp("webAttackMitigationSeverity", web_attack_mitigation_severity), + cereal::make_nvp("webAttackMitigationAction", web_attack_mitigation_action), + cereal::make_nvp("webAttackMitigationMode", web_attack_mitigation_mode), + cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config), + cereal::make_nvp("csrfProtection", disabled_str), + cereal::make_nvp("openRedirect", disabled_str), + cereal::make_nvp("errorDisclosure", disabled_str), + cereal::make_nvp("practiceId", practice_id), + cereal::make_nvp("practiceName", practice_name), + cereal::make_nvp("assetId", asset_id), + cereal::make_nvp("assetName", asset_name), + cereal::make_nvp("ruleId", rule_id), + cereal::make_nvp("ruleName", rule_name), + cereal::make_nvp("triggers", triggers), + cereal::make_nvp("applicationUrls", application_urls), + cereal::make_nvp("overrides", overrides), + cereal::make_nvp("trustedSources", trusted_sources), + cereal::make_nvp("waapParameters", empty_list), + cereal::make_nvp("botProtection", false), + cereal::make_nvp("antiBot", anti_bots), + cereal::make_nvp("botProtection_v2", detect_str) + ); +} + +const string & +WebAppSection::getPracticeId() const +{ + return practice_id; +} + +bool +WebAppSection::operator<(const WebAppSection &other) const +{ + return getPracticeId() < other.getPracticeId(); +} + +void +WebAPISection::save(cereal::JSONOutputArchive &out_ar) const +{ + string disabled_str = "Disabled"; + vector empty_list; + out_ar( + cereal::make_nvp("application_urls", application_urls), + cereal::make_nvp("asset_id", asset_id), + cereal::make_nvp("asset_name", asset_name), + cereal::make_nvp("context", context), + cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config), + cereal::make_nvp("practice_id", practice_id), + cereal::make_nvp("practice_name", practice_name), + cereal::make_nvp("ruleId", rule_id), + cereal::make_nvp("ruleName", rule_name), + cereal::make_nvp("schemaValidation", false), + cereal::make_nvp("schemaValidation_v2", disabled_str), + cereal::make_nvp("web_attack_mitigation", web_attack_mitigation), + cereal::make_nvp("web_attack_mitigation_action", web_attack_mitigation_action), + cereal::make_nvp("web_attack_mitigation_severity", web_attack_mitigation_severity), + cereal::make_nvp("web_attack_mitigation_mode", web_attack_mitigation_mode), + cereal::make_nvp("oas", empty_list), + cereal::make_nvp("trustedSources", empty_list), + cereal::make_nvp("triggers", empty_list), + cereal::make_nvp("waapParameters", empty_list), + cereal::make_nvp("overrides", empty_list) + ); +} + +const string & +WebAPISection::getPracticeId() const +{ + return practice_id; +} + +void +AppSecRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("WebAPISecurity", webAPIPractices), + cereal::make_nvp("WebApplicationSecurity", webApplicationPractices) + ); +} + +void +AppSecWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar(cereal::make_nvp("WAAP", app_sec_rulebase)); +} + +void +ParsedRule::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec ParsedRule"; + parseAppsecJSONKey>("exceptions", exceptions, archive_in); + parseAppsecJSONKey>("triggers", log_triggers, archive_in); + parseAppsecJSONKey>("practices", practices, archive_in); + parseAppsecJSONKey("mode", mode, archive_in); + parseAppsecJSONKey("custom-response", custom_response, archive_in); + parseAppsecJSONKey("source-identifiers", source_identifiers, archive_in); + parseAppsecJSONKey("trusted-sources", trusted_sources, archive_in); + try { + archive_in(cereal::make_nvp("host", host)); + } catch (const cereal::Exception &e) + {} // The default ParsedRule does not hold a host, so no error handling +} + +const vector & +ParsedRule::getExceptions() const +{ + return exceptions; +} + +const vector & +ParsedRule::getLogTriggers() const +{ + return log_triggers; +} + +const vector & +ParsedRule::getPractices() const +{ + return practices; +} + +const string & +ParsedRule::getHost() const +{ + return host; +} + +const string & +ParsedRule::getMode() const +{ + return mode; +} + +void +ParsedRule::setHost(const string &_host) +{ + host = _host; +} + +void +ParsedRule::setMode(const string &_mode) +{ + mode = _mode; +} + +const string & +ParsedRule::getCustomResponse() const +{ + return custom_response; +} + +const string & +ParsedRule::getSourceIdentifiers() const +{ + return source_identifiers; +} + +const string & +ParsedRule::getTrustedSources() const +{ + return trusted_sources; +} + +void +AppsecPolicySpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec policy spec"; + parseAppsecJSONKey("default", default_rule, archive_in); + auto default_mode_annot = + Singleton::Consume::by()->get("default mode annotation"); + if (default_mode_annot.ok() && !default_mode_annot.unpack().empty() && default_rule.getMode().empty()) { + default_rule.setMode(default_mode_annot.unpack()); + } + default_rule.setHost("*"); + parseAppsecJSONKey>("specific-rules", specific_rules, archive_in); + specific_rules.push_front(default_rule); +} + +const ParsedRule & +AppsecPolicySpec::getDefaultRule() const +{ + return default_rule; +} + +const list & +AppsecPolicySpec::getSpecificRules() const +{ + return specific_rules; +} + +void +AppsecLinuxPolicy::serialize(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading Appsec Linux Policy"; + parseAppsecJSONKey("policies", policies, archive_in); + parseAppsecJSONKey>("practices", practices, archive_in); + parseAppsecJSONKey>("log-triggers", log_triggers, archive_in); + parseAppsecJSONKey>("custom-responses", custom_responses, archive_in); + parseAppsecJSONKey>("exceptions", exceptions, archive_in); + parseAppsecJSONKey>("trusted-sources", trusted_sources, archive_in); + parseAppsecJSONKey>( + "source-identifier", + sources_identifier, + archive_in + ); +} + +const AppsecPolicySpec & +AppsecLinuxPolicy::getAppsecPolicySpec() const +{ + return policies; +} + +const vector & +AppsecLinuxPolicy::getAppSecPracticeSpecs() const +{ + return practices; +} + +const vector & +AppsecLinuxPolicy::getAppsecTriggerSpecs() const +{ + return log_triggers; +} + +const vector & +AppsecLinuxPolicy::getAppSecCustomResponseSpecs() const +{ + return custom_responses; +} + +const vector & +AppsecLinuxPolicy::getAppsecExceptionSpecs() const +{ + return exceptions; +} + +const vector & +AppsecLinuxPolicy::getAppsecTrustedSourceSpecs() const +{ + return trusted_sources; +} + +const vector & +AppsecLinuxPolicy::getAppsecSourceIdentifierSpecs() const +{ + return sources_identifier; +} + +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/exceptions_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/exceptions_section.cc new file mode 100644 index 0000000..4c17c96 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/exceptions_section.cc @@ -0,0 +1,242 @@ +#include "exceptions_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_K8S_POLICY); + +// LCOV_EXCL_START Reason: no test exist +void +AppsecExceptionSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec exception spec"; + parseAppsecJSONKey("name", name, archive_in); + parseAppsecJSONKey("action", action, archive_in); + parseAppsecJSONKey>("countryCode", country_code, archive_in); + parseAppsecJSONKey>("countryName", country_name, archive_in); + parseAppsecJSONKey>("hostName", host_name, archive_in); + parseAppsecJSONKey>("paramName", param_name, archive_in); + parseAppsecJSONKey>("paramValue", param_value, archive_in); + parseAppsecJSONKey>("protectionName", protection_name, archive_in); + parseAppsecJSONKey>("sourceIdentifier", source_identifier, archive_in); + parseAppsecJSONKey>("sourceIp", source_ip, archive_in); + parseAppsecJSONKey>("url", url, archive_in); +} + +const string & +AppsecExceptionSpec::getName() const +{ + return name; +} + +const string & +AppsecExceptionSpec::getAction() const +{ + return action; +} + +const vector & +AppsecExceptionSpec::getCountryCode() const +{ + return country_code; +} + +const vector & +AppsecExceptionSpec::getCountryName() const +{ + return country_name; +} + +const vector & +AppsecExceptionSpec::getHostName() const +{ + return host_name; +} + +const vector & +AppsecExceptionSpec::getParamName() const +{ + return param_name; +} + +const vector & +AppsecExceptionSpec::getParamValue() const +{ + return param_value; +} + +const vector & +AppsecExceptionSpec::getProtectionName() const +{ + return protection_name; +} + +const vector & +AppsecExceptionSpec::getSourceIdentifier() const +{ + return source_identifier; +} + +const vector & +AppsecExceptionSpec::getSourceIp() const +{ + return source_ip; +} + +const vector & +AppsecExceptionSpec::getUrl() const +{ + return url; +} + +ExceptionMatch::ExceptionMatch(const AppsecExceptionSpec &parsed_exception) + : + match_type(MatchType::Operator), + op("and") +{ + if (!parsed_exception.getCountryCode().empty()) { + items.push_back(ExceptionMatch("countryCode", parsed_exception.getCountryCode())); + } + if (!parsed_exception.getCountryName().empty()) { + items.push_back(ExceptionMatch("countryName", parsed_exception.getCountryName())); + } + if (!parsed_exception.getHostName().empty()) { + items.push_back(ExceptionMatch("hostName", parsed_exception.getHostName())); + } + if (!parsed_exception.getParamName().empty()) { + items.push_back(ExceptionMatch("paramName", parsed_exception.getParamName())); + } + if (!parsed_exception.getParamValue().empty()) { + items.push_back(ExceptionMatch("paramValue", parsed_exception.getParamValue())); + } + if (!parsed_exception.getProtectionName().empty()) { + items.push_back(ExceptionMatch("protectionName", parsed_exception.getProtectionName())); + } + if (!parsed_exception.getSourceIdentifier().empty()) { + items.push_back(ExceptionMatch("sourceIdentifier", parsed_exception.getSourceIdentifier())); + } + if (!parsed_exception.getSourceIp().empty()) { + items.push_back(ExceptionMatch("sourceIp", parsed_exception.getSourceIp())); + } + if (!parsed_exception.getUrl().empty()) { + items.push_back(ExceptionMatch("url", parsed_exception.getUrl())); + } +} + +void +ExceptionMatch::save(cereal::JSONOutputArchive &out_ar) const +{ + switch (match_type) { + case (MatchType::Condition): { + string type_str = "condition"; + out_ar( + cereal::make_nvp("key", key), + cereal::make_nvp("op", op), + cereal::make_nvp("type", type_str), + cereal::make_nvp("value", value) + ); + break; + } + case (MatchType::Operator): { + string type_str = "operator"; + out_ar( + cereal::make_nvp("op", op), + cereal::make_nvp("type", type_str), + cereal::make_nvp("items", items) + ); + break; + } + default: { + dbgError(D_K8S_POLICY) << "No match for exception match type: " << static_cast(match_type); + } + } +} + +ExceptionBehavior::ExceptionBehavior( + const string &_key, + const string &_value) + : + key(_key), + value(_value) +{ + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_K8S_POLICY) << "Failed to generate exception behavior UUID. Error: " << e.what(); + } +} + +void +ExceptionBehavior::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("key", key), + cereal::make_nvp("value", value), + cereal::make_nvp("id", id) + ); +} + +const string +ExceptionBehavior::getBehaviorId() const +{ + return id; +} + +void +InnerException::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("behavior", behavior), + cereal::make_nvp("match", match) + ); +} + +const string +InnerException::getBehaviorId() const +{ + return behavior.getBehaviorId(); +} + +bool +InnerException::operator<(const InnerException &other) const +{ + return getBehaviorId() < other.getBehaviorId(); +} + +ExceptionsRulebase::ExceptionsRulebase( + vector _exceptions) + : + exceptions(_exceptions) +{ + string context_id_str = ""; + for (const InnerException & exception : exceptions) { + string curr_id = "parameterId(" + exception.getBehaviorId() + "), "; + context_id_str += curr_id; + } + context_id_str = context_id_str.substr(0, context_id_str.size() - 2); + context = "Any(" + context_id_str + ")"; +} + +void +ExceptionsRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("exceptions", exceptions) + ); +} + +void +ExceptionsWrapper::Exception::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar(cereal::make_nvp("exception", exception)); +} + +void +ExceptionsWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulebase", exception_rulebase) + ); +} + +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/appsec_practice_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/appsec_practice_section.h index 980fdce..c4f230e 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/appsec_practice_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/appsec_practice_section.h @@ -14,7 +14,9 @@ #ifndef __APPSEC_PRACTICE_SECTION_H__ #define __APPSEC_PRACTICE_SECTION_H__ +#include #include +#include #include #include #include @@ -28,67 +30,24 @@ #include "trusted_sources_section.h" USE_DEBUG_FLAG(D_K8S_POLICY); + // LCOV_EXCL_START Reason: no test exist class AppSecWebBotsURI { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots URI"; - parseAppsecJSONKey("uri", uri, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string & getURI() const { return uri; } + const std::string & getURI() const; private: std::string uri; }; -std::ostream & -operator<<(std::ostream &os, const AppSecWebBotsURI &obj) -{ - os << obj.getURI(); - return os; -} - -std::ostream & -operator<<(std::ostream &os, const std::vector &obj) -{ - os << "[" << std::endl; - makeSeparatedStr(obj, ","); - os << std::endl << "]"; - return os; -} - class AppSecPracticeAntiBot { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Bots"; - parseAppsecJSONKey>("injected-URIs", injected_uris, archive_in); - parseAppsecJSONKey>("validated-URIs", validated_uris, archive_in); - parseAppsecJSONKey("override-mode", override_mode, archive_in, "Inactive"); - } - - void - save(cereal::JSONOutputArchive &out_ar) const - { - std::vector injected; - std::vector validated; - for (const AppSecWebBotsURI &uri : getInjectedURIs()) injected.push_back(uri.getURI()); - for (const AppSecWebBotsURI &uri : getValidatedURIs()) injected.push_back(uri.getURI()); - out_ar( - cereal::make_nvp("injected", injected), - cereal::make_nvp("validated", validated) - ); - } - - const std::vector & getInjectedURIs() const { return injected_uris; } - const std::vector & getValidatedURIs() const { return validated_uris; } - const std::string & getOverrideMode() const { return override_mode; } + void load(cereal::JSONInputArchive &archive_in); + void save(cereal::JSONOutputArchive &out_ar) const; private: std::string override_mode; @@ -96,61 +55,15 @@ private: std::vector validated_uris; }; -std::ostream & -operator<<(std::ostream &os, const AppSecPracticeAntiBot &obj) -{ - os - << "injected-URIs: " - << obj.getInjectedURIs() - << " validated-URIs: " - << obj.getValidatedURIs() - << ", override_mode: " - << obj.getOverrideMode(); - return os; -} - class AppSecWebAttackProtections { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec Web Attack Protections"; - parseAppsecJSONKey("csrf-protection", csrf_protection, archive_in, "Inactive"); - parseAppsecJSONKey("error-disclosure", error_disclosure, archive_in, "Inactive"); - parseAppsecJSONKey("open-redirect", open_redirect, archive_in, "Inactive"); - parseAppsecJSONKey("non-valid-http-methods", non_valid_http_methods, archive_in, false); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string - getCsrfProtectionMode() const - { - if (key_to_practices_val.find(csrf_protection) == key_to_practices_val.end()) { - dbgError(D_K8S_POLICY) - << "Failed to find a value for " - << csrf_protection - << ". Setting CSRF protection to Inactive"; - return "Inactive"; - } - return key_to_practices_val.at(csrf_protection); - } - - const std::string & getErrorDisclosureMode() const { return error_disclosure; } - - bool getNonValidHttpMethods() const { return non_valid_http_methods; } - - const std::string - getOpenRedirectMode() const - { - if (key_to_practices_val.find(open_redirect) == key_to_practices_val.end()) { - dbgError(D_K8S_POLICY) - << "Failed to find a value for " - << open_redirect - << ". Setting Open Redirect mode to Inactive"; - return "Inactive"; - } - return key_to_practices_val.at(open_redirect); - } + const std::string getCsrfProtectionMode() const; + const std::string & getErrorDisclosureMode() const; + bool getNonValidHttpMethods() const; + const std::string getOpenRedirectMode() const; private: std::string csrf_protection; @@ -159,53 +72,18 @@ private: bool non_valid_http_methods; }; -std::ostream & -operator<<(std::ostream &os, const AppSecWebAttackProtections &obj) -{ - os - << " csrf-protection: " - << obj.getCsrfProtectionMode() - << " error-disclosure: " - << obj.getErrorDisclosureMode() - << " non-valid-http-methods: " - << obj.getNonValidHttpMethods() - << " open-redirect: " - << obj.getOpenRedirectMode(); - return os; -} - class AppSecPracticeWebAttacks { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec"; - parseAppsecJSONKey("protections", protections, archive_in); - parseAppsecJSONKey("minimum-confidence", minimum_confidence, archive_in, "critical"); - parseAppsecJSONKey("override-mode", mode, archive_in, "Unset"); - parseAppsecJSONKey("max-body-size-kb", max_body_size_kb, archive_in, 1000000); - parseAppsecJSONKey("max-header-size-bytes", max_header_size_bytes, archive_in, 102400); - parseAppsecJSONKey("max-object-depth", max_object_depth, archive_in, 40); - parseAppsecJSONKey("max-url-size-bytes", max_url_size_bytes, archive_in, 32768); - } + void load(cereal::JSONInputArchive &archive_in); - int getMaxBodySizeKb() const { return max_body_size_kb; } - int getMaxHeaderSizeBytes() const { return max_header_size_bytes; } - int getMaxObjectDepth() const { return max_object_depth; } - int getMaxUrlSizeBytes() const { return max_url_size_bytes; } - const std::string & getMinimumConfidence() const { return minimum_confidence; } - const AppSecWebAttackProtections & getprotections() const { return protections; } - - const std::string & - getMode(const std::string &default_mode = "Inactive") const - { - if (mode == "Unset" || (key_to_practices_val.find(mode) == key_to_practices_val.end())) { - dbgError(D_K8S_POLICY) << "Couldn't find a value for key: " << mode << ". Returning " << default_mode; - return default_mode; - } - return key_to_practices_val.at(mode); - } + int getMaxBodySizeKb() const; + int getMaxHeaderSizeBytes() const; + int getMaxObjectDepth() const; + int getMaxUrlSizeBytes() const; + const std::string & getMinimumConfidence() const; + const AppSecWebAttackProtections & getprotections() const; + const std::string & getMode(const std::string &default_mode = "Inactive") const; private: int max_body_size_kb; @@ -217,114 +95,42 @@ private: AppSecWebAttackProtections protections; }; -std::ostream & -operator<<(std::ostream &os, const AppSecPracticeWebAttacks &obj) -{ - os - << "mode: " - << obj.getMode() - << " max-body-size-kb: " - << obj.getMaxBodySizeKb() - << " max-header-size-bytes: " - << obj.getMaxHeaderSizeBytes() - << " max-object-depth: " - << obj.getMaxObjectDepth() - << " max-url-size-bytes: " - << obj.getMaxUrlSizeBytes() - << " minimum-confidence: " - << obj.getMinimumConfidence() - << " protections: " - << obj.getprotections(); - return os; -} - class AppSecPracticeSnortSignatures { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec Snort Signatures practice"; - parseAppsecJSONKey("override-mode", override_mode, archive_in, "Inactive"); - parseAppsecJSONKey>("configmap", config_map, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string & getOverrideMode() const { return override_mode; } - - const std::vector & getConfigMap() const { return config_map; } + const std::string & getOverrideMode() const; + const std::vector & getConfigMap() const; private: std::string override_mode; std::vector config_map; }; -std::ostream & -operator<<(std::ostream &os, const AppSecPracticeSnortSignatures &obj) -{ - os - << "override mode: " - << obj.getOverrideMode() - << ". Config map: [" << std::endl - << makeSeparatedStr(obj.getConfigMap(), ",") - << std::endl << "]"; - return os; -} - class AppSecPracticeOpenSchemaAPI { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSecPracticeOpenSchemaAPI practice"; - parseAppsecJSONKey("override-mode", override_mode, archive_in, "Inactive"); - parseAppsecJSONKey>("configmap", config_map, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string & getOverrideMode() const { return override_mode; } - - const std::vector & getConfigMap() const { return config_map; } + const std::string & getOverrideMode() const; + const std::vector & getConfigMap() const; private: std::string override_mode; std::vector config_map; }; -std::ostream & -operator<<(std::ostream &os, const AppSecPracticeOpenSchemaAPI &obj) -{ - os - << "override mode: " - << obj.getOverrideMode() - << ". Config map: [" << std::endl - << makeSeparatedStr(obj.getConfigMap(), ",") - << std::endl << "]"; - return os; -} - class AppSecPracticeSpec { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec practice spec"; - parseAppsecJSONKey( - "openapi-schema-validation", - openapi_schema_validation, - archive_in - ); - parseAppsecJSONKey("snort-signatures", snort_signatures, archive_in); - parseAppsecJSONKey("web-attacks", web_attacks, archive_in); - parseAppsecJSONKey("anti-bot", anti_bot, archive_in); - parseAppsecJSONKey("name", practice_name, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const { return openapi_schema_validation; } - const AppSecPracticeSnortSignatures & getSnortSignatures() const { return snort_signatures; } - const AppSecPracticeWebAttacks & getWebAttacks() const { return web_attacks; } - const AppSecPracticeAntiBot & getAntiBot() const { return anti_bot; } - const std::string & getName() const { return practice_name; } + const AppSecPracticeOpenSchemaAPI & getOpenSchemaValidation() const; + const AppSecPracticeSnortSignatures & getSnortSignatures() const; + const AppSecPracticeWebAttacks & getWebAttacks() const; + const AppSecPracticeAntiBot & getAntiBot() const; + const std::string & getName() const; private: AppSecPracticeOpenSchemaAPI openapi_schema_validation; @@ -334,24 +140,11 @@ private: std::string practice_name; }; -std::ostream & -operator<<(std::ostream &os, const AppSecPracticeSpec &obj) -{ - os - << "Open Schema API:" << std::endl - << obj.getOpenSchemaValidation() - << std::endl << "Snort Signatures:" << std::endl - << obj.getOpenSchemaValidation() - << std::endl << "Web Attacks:" << std::endl - << obj.getWebAttacks() - << std::endl << "Web Bots:" << std::endl - << obj.getAntiBot(); - return os; -} - class PracticeAdvancedConfig { public: + PracticeAdvancedConfig() {} + PracticeAdvancedConfig(const AppSecPracticeSpec &parsed_appsec_spec) : http_header_max_size(parsed_appsec_spec.getWebAttacks().getMaxHeaderSizeBytes()), @@ -361,19 +154,7 @@ public: url_max_size(parsed_appsec_spec.getWebAttacks().getMaxUrlSizeBytes()) {} - void - save(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("httpHeaderMaxSize", http_header_max_size), - cereal::make_nvp("httpIllegalMethodsAllowed", http_illegal_methods_allowed), - cereal::make_nvp("httpRequestBodyMaxSize", http_request_body_max_size), - cereal::make_nvp("jsonMaxObjectDepth", json_max_object_depth), - cereal::make_nvp("urlMaxSize", url_max_size) - ); - } - - void setIllegalMethodsAllowed(int val) { http_illegal_methods_allowed = val; }; + void save(cereal::JSONOutputArchive &out_ar) const; private: int http_header_max_size; @@ -394,16 +175,7 @@ public: log(log_section) {} - void - save(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("$triggerType", trigger_type), - cereal::make_nvp("id", id), - cereal::make_nvp("name", name), - cereal::make_nvp("log", log) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: std::string trigger_type; @@ -415,23 +187,10 @@ private: class AppSecOverride { public: - AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources) - { - std::string source_ident = parsed_trusted_sources.getSourceIdent(); - std::map behavior = {{"httpSourceId", source_ident}}; - parsed_behavior.push_back(behavior); - parsed_match = {{"operator", "BASIC"}, {"tag", "sourceip"}, {"value", "0.0.0.0/0"}}; - } + AppSecOverride(const SourcesIdentifiers &parsed_trusted_sources); + + void save(cereal::JSONOutputArchive &out_ar) const; - void - save(cereal::JSONOutputArchive &out_ar) const - { - std::string parameter_type = "TrustedSource"; - out_ar( - cereal::make_nvp("parsedBehavior", parsed_behavior), - cereal::make_nvp("parsedMatch", parsed_match) - ); - } private: std::vector> parsed_behavior; std::map parsed_match; @@ -440,6 +199,8 @@ private: class WebAppSection { public: + WebAppSection() {} + WebAppSection( const std::string &_application_urls, const std::string &_asset_id, @@ -451,75 +212,12 @@ public: const AppSecPracticeSpec &parsed_appsec_spec, const LogTriggerSection &parsed_log_trigger, const std::string &default_mode, - const AppSecTrustedSources &parsed_trusted_sources) - : - application_urls(_application_urls), - asset_id(_asset_id), - asset_name(_asset_name), - rule_id(_rule_id), - rule_name(_rule_name), - practice_id(_practice_id), - practice_name(_practice_name), - context("practiceId(" + practice_id +")"), - web_attack_mitigation_severity(parsed_appsec_spec.getWebAttacks().getMinimumConfidence()), - web_attack_mitigation_mode(parsed_appsec_spec.getWebAttacks().getMode(default_mode)), - practice_advanced_config(parsed_appsec_spec), - anti_bots(parsed_appsec_spec.getAntiBot()), - trusted_sources({parsed_trusted_sources}) - { - web_attack_mitigation = true; - web_attack_mitigation_action = - web_attack_mitigation_severity == "critical" ? "low" : - web_attack_mitigation_severity == "high" ? "balanced" : - web_attack_mitigation_severity == "medium" ? "high" : - "Error"; + const AppSecTrustedSources &parsed_trusted_sources + ); - triggers.push_back(TriggersInWaapSection(parsed_log_trigger)); - for (const SourcesIdentifiers &source_ident : parsed_trusted_sources.getSourcesIdentifiers()) { - overrides.push_back(AppSecOverride(source_ident)); - } - } - - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - std::string disabled_str = "Disabled"; - std::string detect_str = "Detect"; - std::vector empty_list; - out_ar( - cereal::make_nvp("context", context), - cereal::make_nvp("webAttackMitigation", web_attack_mitigation), - cereal::make_nvp("webAttackMitigationSeverity", web_attack_mitigation_severity), - cereal::make_nvp("webAttackMitigationAction", web_attack_mitigation_action), - cereal::make_nvp("webAttackMitigationMode", web_attack_mitigation_mode), - cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config), - cereal::make_nvp("csrfProtection", disabled_str), - cereal::make_nvp("openRedirect", disabled_str), - cereal::make_nvp("errorDisclosure", disabled_str), - cereal::make_nvp("practiceId", practice_id), - cereal::make_nvp("practiceName", practice_name), - cereal::make_nvp("assetId", asset_id), - cereal::make_nvp("assetName", asset_name), - cereal::make_nvp("ruleId", rule_id), - cereal::make_nvp("ruleName", rule_name), - cereal::make_nvp("triggers", triggers), - cereal::make_nvp("applicationUrls", application_urls), - cereal::make_nvp("overrides", overrides), - cereal::make_nvp("trustedSources", trusted_sources), - cereal::make_nvp("waapParameters", empty_list), - cereal::make_nvp("botProtection", false), - cereal::make_nvp("antiBot", anti_bots), - cereal::make_nvp("botProtection_v2", detect_str) - ); - } - - const std::string & getPracticeId() const { return practice_id; } - - bool - operator<(const WebAppSection &other) const - { - return getPracticeId() < other.getPracticeId(); - } + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getPracticeId() const; + bool operator<(const WebAppSection &other) const; private: std::string application_urls; @@ -573,36 +271,9 @@ public: practice_advanced_config(parsed_appsec_spec) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - std::string disabled_str = "Disabled"; - std::vector empty_list; - out_ar( - cereal::make_nvp("application_urls", application_urls), - cereal::make_nvp("asset_id", asset_id), - cereal::make_nvp("asset_name", asset_name), - cereal::make_nvp("context", context), - cereal::make_nvp("practiceAdvancedConfig", practice_advanced_config), - cereal::make_nvp("practice_id", practice_id), - cereal::make_nvp("practice_name", practice_name), - cereal::make_nvp("ruleId", rule_id), - cereal::make_nvp("ruleName", rule_name), - cereal::make_nvp("schemaValidation", false), - cereal::make_nvp("schemaValidation_v2", disabled_str), - cereal::make_nvp("web_attack_mitigation", web_attack_mitigation), - cereal::make_nvp("web_attack_mitigation_action", web_attack_mitigation_action), - cereal::make_nvp("web_attack_mitigation_severity", web_attack_mitigation_severity), - cereal::make_nvp("web_attack_mitigation_mode", web_attack_mitigation_mode), - cereal::make_nvp("oas", empty_list), - cereal::make_nvp("trustedSources", empty_list), - cereal::make_nvp("triggers", empty_list), - cereal::make_nvp("waapParameters", empty_list), - cereal::make_nvp("overrides", empty_list) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; - const std::string & getPracticeId() const { return practice_id; } + const std::string & getPracticeId() const; private: std::string application_urls; @@ -630,14 +301,7 @@ public: webApplicationPractices(_webApplicationPractices), webAPIPractices(_webAPIPractices) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("WebAPISecurity", webAPIPractices), - cereal::make_nvp("WebApplicationSecurity", webApplicationPractices) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: std::vector webApplicationPractices; @@ -652,54 +316,27 @@ public: app_sec_rulebase(_app_sec) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar(cereal::make_nvp("WAAP", app_sec_rulebase)); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: AppSecRulebase app_sec_rulebase; }; - class ParsedRule { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec ParsedRule"; - parseAppsecJSONKey>("exceptions", exceptions, archive_in); - parseAppsecJSONKey>("triggers", log_triggers, archive_in); - parseAppsecJSONKey>("practices", practices, archive_in); - parseAppsecJSONKey("mode", mode, archive_in); - parseAppsecJSONKey("custom-response", custom_response, archive_in); - parseAppsecJSONKey("source-identifiers", source_identifiers, archive_in); - parseAppsecJSONKey("trusted-sources", trusted_sources, archive_in); - try { - archive_in(cereal::make_nvp("host", host)); - } catch (const cereal::Exception &e) - {} // The default ParsedRule does not hold a host, so no error handling - } + void load(cereal::JSONInputArchive &archive_in); - const std::vector & getExceptions() const { return exceptions; } - - const std::vector & getLogTriggers() const { return log_triggers; } - - const std::vector & getPractices() const { return practices; } - - const std::string & getHost() const { return host; } - - const std::string & getMode() const { return mode; } - - void setMode(const std::string &_mode) { mode = _mode; }; - - const std::string & getCustomResponse() const { return custom_response; } - - const std::string & getSourceIdentifiers() const { return source_identifiers; } - - const std::string & getTrustedSources() const { return trusted_sources; } + const std::vector & getExceptions() const; + const std::vector & getLogTriggers() const; + const std::vector & getPractices() const; + const std::string & getHost() const; + const std::string & getMode() const; + void setHost(const std::string &_host); + void setMode(const std::string &_mode); + const std::string & getCustomResponse() const; + const std::string & getSourceIdentifiers() const; + const std::string & getTrustedSources() const; private: std::vector exceptions; @@ -712,88 +349,32 @@ private: std::string trusted_sources; }; -std::ostream & -operator<<(std::ostream &os, const ParsedRule &obj) -{ - os - << "host: " - << obj.getHost() - << std::endl << "log trigger: " - << makeSeparatedStr(obj.getLogTriggers(), ",") - << std::endl << "mode: " - << obj.getMode() - << std::endl << "practices: " - << makeSeparatedStr(obj.getPractices(), ",") - << std::endl << "web responce: " - << obj.getCustomResponse() - << std::endl << " Exceptions: [" << std::endl - << makeSeparatedStr(obj.getExceptions(), ",") - << std::endl << "]"; - return os; -} - class AppsecPolicySpec : Singleton::Consume { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec policy spec"; - parseAppsecJSONKey("default", default_rule, archive_in); - auto default_mode_annot = - Singleton::Consume::by()->get("default mode annotation"); - if (default_mode_annot.ok() && !default_mode_annot.unpack().empty() && default_rule.getMode().empty()) { - default_rule.setMode(default_mode_annot.unpack()); - } - parseAppsecJSONKey>("specific-rules", specific_rules, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const ParsedRule & getDefaultRule() const { return default_rule; } - - const std::vector & getSpecificRules() const { return specific_rules; } + const ParsedRule & getDefaultRule() const; + const std::list & getSpecificRules() const; private: ParsedRule default_rule; - std::vector specific_rules; + std::list specific_rules; }; class AppsecLinuxPolicy : Singleton::Consume { public: void - serialize(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec policy spec"; - parseAppsecJSONKey("policies", policies, archive_in); - parseAppsecJSONKey>("practices", practices, archive_in); - parseAppsecJSONKey>("logtriggers", log_triggers, archive_in); - parseAppsecJSONKey>("customresponses", custom_responses, archive_in); - parseAppsecJSONKey>("exceptions", exceptions, archive_in); - parseAppsecJSONKey>("trustedsources", trusted_sources, archive_in); - parseAppsecJSONKey>( - "sourceidentifiers", - sources_identifier, - archive_in - ); - } + serialize(cereal::JSONInputArchive &archive_in); - const AppsecPolicySpec & getAppsecPolicySpec() const { return policies; } - - const std::vector & getAppSecPracticeSpecs() const { return practices; } - - const std::vector & getAppsecTriggerSpecs() const { return log_triggers; } - - const std::vector & getAppSecCustomResponseSpecs() const { return custom_responses; } - - const std::vector & getAppsecExceptionSpecs() const { return exceptions; } - - const std::vector & getAppsecTrustedSourceSpecs() const { return trusted_sources; } - - const std::vector & - getAppsecSourceIdentifierSpecs() const - { - return sources_identifier; - } + const AppsecPolicySpec & getAppsecPolicySpec() const; + const std::vector & getAppSecPracticeSpecs() const; + const std::vector & getAppsecTriggerSpecs() const; + const std::vector & getAppSecCustomResponseSpecs() const; + const std::vector & getAppsecExceptionSpecs() const; + const std::vector & getAppsecTrustedSourceSpecs() const; + const std::vector & getAppsecSourceIdentifierSpecs() const; private: AppsecPolicySpec policies; @@ -805,16 +386,5 @@ private: std::vector sources_identifier; }; -std::ostream & -operator<<(std::ostream &os, const AppsecPolicySpec &obj) -{ - os - << "Default Rule: " - << obj.getDefaultRule() - << std::endl <<"Specific Rules: [" << std::endl - << makeSeparatedStr(obj.getSpecificRules(), ",") - << std::endl << "]"; - return os; -} // LCOV_EXCL_STOP #endif // __APPSEC_PRACTICE_SECTION_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/exceptions_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/exceptions_section.h index 69b3196..900e3bd 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/exceptions_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/exceptions_section.h @@ -30,34 +30,22 @@ USE_DEBUG_FLAG(D_K8S_POLICY); class AppsecExceptionSpec { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec exception spec"; - parseAppsecJSONKey("action", action, archive_in); - parseAppsecJSONKey>("countryCode", country_code, archive_in); - parseAppsecJSONKey>("countryName", country_name, archive_in); - parseAppsecJSONKey>("hostName", host_name, archive_in); - parseAppsecJSONKey>("paramName", param_name, archive_in); - parseAppsecJSONKey>("paramValue", param_value, archive_in); - parseAppsecJSONKey>("protectionName", protection_name, archive_in); - parseAppsecJSONKey>("sourceIdentifier", source_identifier, archive_in); - parseAppsecJSONKey>("sourceIp", source_ip, archive_in); - parseAppsecJSONKey>("url", url, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string & getAction() const { return action; } - const std::vector & getCountryCode() const { return country_code; } - const std::vector & getCountryName() const { return country_name; } - const std::vector & getHostName() const { return host_name; } - const std::vector & getParamName() const { return param_name; } - const std::vector & getParamValue() const { return param_value; } - const std::vector & getProtectionName() const { return protection_name; } - const std::vector & getSourceIdentifier() const { return source_identifier; } - const std::vector & getSourceIp() const { return source_ip; } - const std::vector & getUrl() const { return url; } + const std::string & getName() const; + const std::string & getAction() const; + const std::vector & getCountryCode() const; + const std::vector & getCountryName() const; + const std::vector & getHostName() const; + const std::vector & getParamName() const; + const std::vector & getParamValue() const; + const std::vector & getProtectionName() const; + const std::vector & getSourceIdentifier() const; + const std::vector & getSourceIp() const; + const std::vector & getUrl() const; private: + std::string name; std::string action; std::vector country_code; std::vector country_name; @@ -70,71 +58,11 @@ private: std::vector url; }; -std::ostream & -operator<<(std::ostream &os, const AppsecExceptionSpec &obj) -{ - os - << "action: " - << makeSeparatedStr(obj.getAction(), ",") - << "countryCode: " - << makeSeparatedStr(obj.getCountryCode(), ",") - << "countryName: " - << makeSeparatedStr(obj.getCountryName(), ",") - << "hostName: " - << makeSeparatedStr(obj.getHostName(), ",") - << "paramName: " - << makeSeparatedStr(obj.getParamName(), ",") - << "paramValue: " - << makeSeparatedStr(obj.getParamValue(), ",") - << "protectionName: " - << makeSeparatedStr(obj.getProtectionName(), ",") - << "sourceIdentifier: " - << makeSeparatedStr(obj.getSourceIdentifier(), ",") - << "sourceIp: " - << makeSeparatedStr(obj.getSourceIp(), ",") - << "url: " - << makeSeparatedStr(obj.getUrl(), ","); - - return os; -} - class ExceptionMatch { public: - ExceptionMatch(const AppsecExceptionSpec &parsed_exception) - : - match_type(MatchType::Operator), - op("and") - { - if (!parsed_exception.getCountryCode().empty()) { - items.push_back(ExceptionMatch("countryCode", parsed_exception.getCountryCode())); - } - if (!parsed_exception.getCountryName().empty()) { - items.push_back(ExceptionMatch("countryName", parsed_exception.getCountryName())); - } - if (!parsed_exception.getHostName().empty()) { - items.push_back(ExceptionMatch("hostName", parsed_exception.getHostName())); - } - if (!parsed_exception.getParamName().empty()) { - items.push_back(ExceptionMatch("paramName", parsed_exception.getParamName())); - } - if (!parsed_exception.getParamValue().empty()) { - items.push_back(ExceptionMatch("paramValue", parsed_exception.getParamValue())); - } - if (!parsed_exception.getProtectionName().empty()) { - items.push_back(ExceptionMatch("protectionName", parsed_exception.getProtectionName())); - } - if (!parsed_exception.getSourceIdentifier().empty()) { - items.push_back(ExceptionMatch("sourceIdentifier", parsed_exception.getSourceIdentifier())); - } - if (!parsed_exception.getSourceIp().empty()) { - items.push_back(ExceptionMatch("sourceIp", parsed_exception.getSourceIp())); - } - if (!parsed_exception.getUrl().empty()) { - items.push_back(ExceptionMatch("url", parsed_exception.getUrl())); - } - } - + ExceptionMatch() {} + ExceptionMatch(const AppsecExceptionSpec &parsed_exception); ExceptionMatch(const std::string &_key, const std::vector &_value) : match_type(MatchType::Condition), @@ -143,34 +71,7 @@ public: value(_value) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - switch (match_type) { - case (MatchType::Condition): { - std::string type_str = "condition"; - out_ar( - cereal::make_nvp("key", key), - cereal::make_nvp("op", op), - cereal::make_nvp("type", type_str), - cereal::make_nvp("value", value) - ); - break; - } - case (MatchType::Operator): { - std::string type_str = "operator"; - out_ar( - cereal::make_nvp("op", op), - cereal::make_nvp("type", type_str), - cereal::make_nvp("items", items) - ); - break; - } - default: { - dbgError(D_K8S_POLICY) << "No match for exception match type: " << static_cast(match_type); - } - } - } + void save(cereal::JSONOutputArchive &out_ar) const; private: MatchType match_type; @@ -183,31 +84,14 @@ private: class ExceptionBehavior { public: + ExceptionBehavior() {} ExceptionBehavior( const std::string &_key, - const std::string &_value) - : - key(_key), - value(_value) - { - try { - id = to_string(boost::uuids::random_generator()()); - } catch (const boost::uuids::entropy_error &e) { - dbgWarning(D_K8S_POLICY) << "Failed to generate exception behavior UUID. Error: " << e.what(); - } - } + const std::string &_value + ); - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("key", key), - cereal::make_nvp("value", value), - cereal::make_nvp("id", id) - ); - } - - const std::string getBehaviorId() const { return id; } + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string getBehaviorId() const; private: std::string key; @@ -218,6 +102,7 @@ private: class InnerException { public: + InnerException() {} InnerException( ExceptionBehavior _behavior, ExceptionMatch _match) @@ -225,22 +110,9 @@ public: behavior(_behavior), match(_match) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("behavior", behavior), - cereal::make_nvp("match", match) - ); - } - - const std::string getBehaviorId() const { return behavior.getBehaviorId(); } - - bool - operator<(const InnerException &other) const - { - return getBehaviorId() < other.getBehaviorId(); - } + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string getBehaviorId() const; + bool operator<(const InnerException &other) const; private: ExceptionBehavior behavior; @@ -250,28 +122,8 @@ private: class ExceptionsRulebase { public: - ExceptionsRulebase( - std::vector _exceptions) - : - exceptions(_exceptions) - { - std::string context_id_str = ""; - for (const InnerException exception : exceptions) { - std::string curr_id = "parameterId(" + exception.getBehaviorId() + "), "; - context_id_str += curr_id; - } - context_id_str = context_id_str.substr(0, context_id_str.size() - 2); - context = "Any(" + context_id_str + ")"; - } - - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("context", context), - cereal::make_nvp("exceptions", exceptions) - ); - } + ExceptionsRulebase(std::vector _exceptions); + void save(cereal::JSONOutputArchive &out_ar) const; private: std::string context; @@ -286,11 +138,7 @@ public: public: Exception(const std::vector &_exception) : exception(_exception) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar(cereal::make_nvp("exception", exception)); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: std::vector exception; @@ -298,13 +146,7 @@ public: ExceptionsWrapper(const std::vector &_exception) : exception_rulebase(Exception(_exception)) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("rulebase", exception_rulebase) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: Exception exception_rulebase; diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/ingress_data.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/ingress_data.h index 1dcece2..dd18eff 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/ingress_data.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/ingress_data.h @@ -21,26 +21,21 @@ #include "debug.h" #include "rest.h" #include "cereal/archives/json.hpp" +#include + +#include "k8s_policy_common.h" USE_DEBUG_FLAG(D_K8S_POLICY); // LCOV_EXCL_START Reason: no test exist class IngressMetadata { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "IngressMetadata load"; - parseAppsecJSONKey("name", name, archive_in); - parseAppsecJSONKey("resourceVersion", resourceVersion, archive_in); - parseAppsecJSONKey("namespace", namespace_name, archive_in); - parseAppsecJSONKey>("annotations", annotations, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string & getName() const { return name; } - const std::string & getResourceVersion() const { return resourceVersion; } - const std::string & getNamespace() const { return namespace_name; } - const std::map & getAnnotations() const { return annotations; } + const std::string & getName() const; + const std::string & getResourceVersion() const; + const std::string & getNamespace() const; + const std::map & getAnnotations() const; private: std::string name; @@ -53,19 +48,15 @@ class IngressRulePath { public: void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path"; - parseAppsecJSONKey("path", path, archive_in); - } + load(cereal::JSONInputArchive &archive_in); - const std::string & getPath() const { return path; } + const std::string & getPath() const; private: std::string path; }; -std::ostream & +inline std::ostream & operator<<(std::ostream &os, const IngressRulePath &obj) { os << obj.getPath(); @@ -75,14 +66,9 @@ operator<<(std::ostream &os, const IngressRulePath &obj) class IngressRulePathsWrapper { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path wrapper"; - parseAppsecJSONKey>("paths", paths, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const std::vector & getRulePaths() const { return paths; } + const std::vector & getRulePaths() const; private: std::vector paths; @@ -91,23 +77,17 @@ private: class IngressDefinedRule { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule"; - parseAppsecJSONKey("host", host, archive_in); - parseAppsecJSONKey("http", paths_wrapper, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string & getHost() const { return host; } - const IngressRulePathsWrapper & getPathsWrapper() const { return paths_wrapper; } + const std::string & getHost() const; + const IngressRulePathsWrapper & getPathsWrapper() const; private: std::string host; IngressRulePathsWrapper paths_wrapper; }; -std::ostream & +inline std::ostream & operator<<(std::ostream &os, const IngressDefinedRule &obj) { os @@ -123,13 +103,9 @@ class DefaultBackend { public: void - load(cereal::JSONInputArchive &) - { - dbgTrace(D_K8S_POLICY) << "Loading Default Backend"; - is_exists = true; - } + load(cereal::JSONInputArchive &); - bool isExists() const { return is_exists; } + bool isExists() const; private: bool is_exists = false; @@ -139,17 +115,11 @@ class IngressSpec { public: void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading single ingress spec"; - parseAppsecJSONKey("ingressClassName", ingress_class_name, archive_in); - parseAppsecJSONKey>("rules", rules, archive_in); - parseAppsecJSONKey("defaultBackend", default_backend, archive_in); - } + load(cereal::JSONInputArchive &archive_in); - const std::string & getIngressClassName() const { return ingress_class_name; } - const std::vector & getRules() const { return rules; } - bool isDefaultBackendExists() const { return default_backend.isExists(); } + const std::string & getIngressClassName() const; + const std::vector & getRules() const; + bool isDefaultBackendExists() const; private: std::string ingress_class_name; @@ -157,31 +127,14 @@ private: DefaultBackend default_backend; }; -std::ostream & -operator<<(std::ostream &os, const IngressSpec &obj) -{ - os - << "Ingress Spec - ingressClassName: " - << obj.getIngressClassName() - << ", rules: [" << std::endl - << makeSeparatedStr(obj.getRules(), ",") - << std::endl << "]"; - return os; -} - class SingleIngressData { public: void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading single ingress data"; - parseAppsecJSONKey("metadata", metadata, archive_in); - parseAppsecJSONKey("spec", spec, archive_in); - } + load(cereal::JSONInputArchive &archive_in); - const IngressMetadata & getMetadata() const { return metadata; } - const IngressSpec & getSpec() const { return spec; } + const IngressMetadata & getMetadata() const; + const IngressSpec & getSpec() const; private: IngressMetadata metadata; @@ -192,29 +145,10 @@ private: class IngressData : public ClientRest { public: - bool - loadJson(const std::string &json) - { - std::string modified_json = json; - modified_json.pop_back(); - std::stringstream in; - in.str(modified_json); - dbgTrace(D_K8S_POLICY) << "Loading ingress data"; - try { - cereal::JSONInputArchive in_ar(in); - in_ar( - cereal::make_nvp("apiVersion", apiVersion), - cereal::make_nvp("items", items) - ); - } catch (cereal::Exception &e) { - dbgError(D_K8S_POLICY) << "Failed to load ingress data JSON. Error: " << e.what(); - return false; - } - return true; - } + bool loadJson(const std::string &json); - const std::string & getapiVersion() const { return apiVersion; } - const std::vector & getItems() const { return items; } + const std::string & getapiVersion() const; + const std::vector & getItems() const; private: std::string apiVersion; diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/policy_maker_utils.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/policy_maker_utils.h new file mode 100644 index 0000000..b86d057 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/policy_maker_utils.h @@ -0,0 +1,132 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (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. + +#ifndef __POLICY_MAKER_UTILS_H__ +#define __POLICY_MAKER_UTILS_H__ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "debug.h" +#include "common.h" +#include "maybe_res.h" +#include "appsec_practice_section.h" +#include "ingress_data.h" +#include "settings_section.h" +#include "triggers_section.h" +#include "k8s_policy_common.h" +#include "exceptions_section.h" +#include "rules_config_section.h" +#include "trusted_sources_section.h" + +USE_DEBUG_FLAG(D_NGINX_POLICY); + +enum class AnnotationTypes { + PRACTICE, + TRIGGER, + EXCEPTION, + WEB_USER_RES, + SOURCE_IDENTIFIERS, + TRUSTED_SOURCES, + COUNT +}; + +// LCOV_EXCL_START Reason: no test exist +class SecurityAppsWrapper +{ +public: + SecurityAppsWrapper( + const AppSecWrapper &_waap, + const TriggersWrapper &_trrigers, + const RulesConfigWrapper &_rules, + const ExceptionsWrapper &_exceptions, + const std::string &_policy_version) + : + waap(_waap), + trrigers(_trrigers), + rules(_rules), + exceptions(_exceptions), + policy_version(_policy_version) {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + AppSecWrapper waap; + TriggersWrapper trrigers; + RulesConfigWrapper rules; + ExceptionsWrapper exceptions; + std::string policy_version; +}; + +class PolicyWrapper +{ +public: + PolicyWrapper( + const SettingsWrapper &_settings, + const SecurityAppsWrapper &_security_apps) + : + settings(_settings), + security_apps(_security_apps) {} + + void save(cereal::JSONOutputArchive &out_ar) const; + +private: + SettingsWrapper settings; + SecurityAppsWrapper security_apps; +}; +// LCOV_EXCL_STOP +class PolicyMakerUtils +{ +public: + void clearElementsMaps(); + + bool startsWith(const std::string &str, const std::string &prefix); + + bool endsWith(const std::string &str, const std::string &suffix); + + std::tuple splitHostName(const std::string &host_name); + + std::string dumpPolicyToFile(const PolicyWrapper &policy, const std::string &policy_path) const; + + PolicyWrapper combineElementsToPolicy(const std::string &policy_version); + + void createPolicyElementsByRule( + const ParsedRule &rule, + const ParsedRule &default_rule, + const AppsecLinuxPolicy &policy, + const std::string &policy_name + ); + + void createPolicyElements( + const std::vector &rules, + const ParsedRule &default_rule, + const AppsecLinuxPolicy &policy, + const std::string &policy_name + ); + +private: + std::map log_triggers; + std::map web_user_res_triggers; + std::map inner_exceptions; + std::map web_apps; + std::map rules_config; +}; + +#endif // __POLICY_MAKER_UTILS_H__ diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/rules_config_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/rules_config_section.h index 39a2e85..86ec66b 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/rules_config_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/rules_config_section.h @@ -30,100 +30,24 @@ USE_DEBUG_FLAG(D_K8S_POLICY); class AssetUrlParser { public: + AssetUrlParser() {} + + static AssetUrlParser parse(const std::string &uri); std::string query_string, asset_uri, protocol, asset_url, port; - - AssetUrlParser() - {} - - AssetUrlParser(const std::string &asset) - { - parse(asset); - } - -private: - static AssetUrlParser - parse(const std::string &uri) - { - AssetUrlParser result; - - using iterator_t = std::string::const_iterator; - - if (uri.length() == 0) return result; - - iterator_t uri_end = uri.end(); - - // get query start - iterator_t query_start = std::find(uri.begin(), uri_end, '?'); - - // protocol - iterator_t protocol_start = uri.begin(); - iterator_t protocol_end = std::find(protocol_start, uri_end, ':'); //"://"); - - if (protocol_end != uri_end) { - std::string http_protocol = &*(protocol_end); - if ((http_protocol.length() > 3) && (http_protocol.substr(0, 3) == "://")) { - result.protocol = std::string(protocol_start, protocol_end); - protocol_end += 3; // :// - } else { - protocol_end = uri.begin(); // no protocol - } - } else { - protocol_end = uri.begin(); // no protocol - } - - // URL - iterator_t host_start = protocol_end; - iterator_t path_start = std::find(host_start, uri_end, '/'); - - iterator_t host_end = std::find(protocol_end, (path_start != uri_end) ? path_start : query_start, ':'); - - result.asset_url = std::string(host_start, host_end); - - // port - if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) { // we have a port - host_end++; - iterator_t portEnd = (path_start != uri_end) ? path_start : query_start; - result.port = std::string(host_end, portEnd); - } - - // URI - if (path_start != uri_end) result.asset_uri = std::string(path_start, query_start); - - // query - if (query_start != uri_end) result.query_string = std::string(query_start, uri.end()); - - return result; - } // Parse -}; // uri +}; class PracticeSection { public: - PracticeSection(const std::string &_id, const std::string &_type, const std::string &_practice_name) - { - auto maybe_type = string_to_practice_type.find(_type); - if (maybe_type == string_to_practice_type.end()) { - dbgError(D_K8S_POLICY) << "Illegal pracrtice type: " << _type; - return; - } + PracticeSection( + const std::string &_id, + const std::string &_type, + const std::string &_practice_name); - type = _type; - name = _practice_name; - id = _id; - } + void save(cereal::JSONOutputArchive &out_ar) const; - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("practiceId", id), - cereal::make_nvp("practiceName", name), - cereal::make_nvp("practiceType", type) - ); - } - - const std::string & getPracticeId() const { return id; } - const std::string & getPracticeName() const { return name; } + const std::string & getPracticeId() const; + const std::string & getPracticeName() const; private: std::string id; @@ -134,30 +58,10 @@ private: class ParametersSection { public: - ParametersSection( - const std::string &_id, - const std::string &_name) - : - name(_name), - id(_id) - { - if (_id.empty() && _name.empty()) { - dbgError(D_K8S_POLICY) << "Illegal Parameter values. Name and ID are empty"; - return; - } - } + ParametersSection(const std::string &_id, const std::string &_name); - const std::string & getId() const { return id; } - - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("parameterId", id), - cereal::make_nvp("parameterName", name), - cereal::make_nvp("parameterType", type) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getId() const; private: std::string name; @@ -171,35 +75,12 @@ public: RulesTriggerSection( const std::string &_name, const std::string &_id, - const std::string &_type) - : - name(_name), - id(_id) - { - if (_name.empty() && _id.empty()) { - dbgError(D_K8S_POLICY) << "Illegal values for trigger. Name and ID are empty"; - return; - } - auto maybe_type = string_to_trigger_type.find(_type); - if (maybe_type == string_to_trigger_type.end()) { - dbgError(D_K8S_POLICY) << "Illegal trigger type in rule: " << _type; - return; - } - type = _type; - } + const std::string &_type); - const std::string & getId() const { return id; } - const std::string & getName() const { return id; } + void save(cereal::JSONOutputArchive &out_ar) const; - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("triggerId", id), - cereal::make_nvp("triggerName", name), - cereal::make_nvp("triggerType", type) - ); - } + const std::string & getId() const; + const std::string & getName() const; private: std::string name; @@ -219,84 +100,19 @@ public: const std::string &_uri, std::vector _practices, std::vector _parameters, - std::vector _triggers) - : - name(_name), - practices(_practices), - parameters(_parameters), - triggers(_triggers) - { - try { - id = _url+_uri; - bool any = _name == "Any" && _url == "Any" && _uri == "Any"; - if (_uri != "/") { - context = any ? "All()" : "Any(" - "All(" - "Any(" - "EqualHost(" + _url + ")" - ")," - "EqualListeningPort(80)" + - std::string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") + - ")," - "All(" - "Any(" - "EqualHost(" + _url + ")" - ")," - "EqualListeningPort(443)" + - std::string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") + - ")" - ")"; - } else { - context = any ? "All()" : "Any(" - "All(" - "Any(" - "EqualHost(" + _url + ")" - ")," - "EqualListeningPort(80)" - ")," - "All(" - "Any(" - "EqualHost(" + _url + ")" - ")," - "EqualListeningPort(443)" - ")" - ")"; - } - } catch (const boost::uuids::entropy_error &e) { - dbgWarning(D_K8S_POLICY) << "Failed to generate rule UUID. Error: " << e.what(); - } - } + std::vector _triggers); - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - std::string empty_str = ""; - out_ar( - cereal::make_nvp("assetId", id), - cereal::make_nvp("assetName", name), - cereal::make_nvp("ruleId", id), - cereal::make_nvp("ruleName", name), - cereal::make_nvp("context", context), - cereal::make_nvp("priority", 1), - cereal::make_nvp("isCleanup", false), - cereal::make_nvp("parameters", parameters), - cereal::make_nvp("practices", practices), - cereal::make_nvp("triggers", triggers), - cereal::make_nvp("zoneId", empty_str), - cereal::make_nvp("zoneName", empty_str) - ); - } - - const std::string & getRuleId() const { return id; } - const std::string & getAssetName() const { return name; } - const std::string & getRuleName() const { return name; } - const std::string & getAsstId() const { return id; } - const std::string & getPracticeId() const { return practices[0].getPracticeId(); } - const std::string & getPracticeName() const { return practices[0].getPracticeName(); } - const std::vector & getPractice() const { return practices; } - const std::vector & getParameters() const { return parameters; } - const std::vector & getTriggers() const { return triggers; } + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getRuleId() const; + const std::string & getAssetName() const; + const std::string & getRuleName() const; + const std::string & getAssetId() const; + const std::string & getPracticeId() const; + const std::string & getPracticeName() const; + const std::vector & getPractice() const; + const std::vector & getParameters() const; + const std::vector & getTriggers() const; private: std::string context; @@ -313,60 +129,13 @@ public: class RulesConfig { public: - RulesConfig(const std::vector &_rules_config) - : - rules_config(_rules_config) - { - sort(rules_config.begin(), rules_config.end(), sortBySpecific); - } + RulesConfig(const std::vector &_rules_config); - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("rulesConfig", rules_config) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: - static bool - sortBySpecific(const RulesConfigRulebase &first, const RulesConfigRulebase &second) - { - return sortBySpecificAux(first.getAssetName(), second.getAssetName()); - } - - static bool - sortBySpecificAux(const std::string &first, const std::string &second) - { - if (first.empty()) return false; - if (second.empty()) return true; - - AssetUrlParser first_parsed = AssetUrlParser(first); - AssetUrlParser second_parsed = AssetUrlParser(second); - - // sort by URL - if (first_parsed.asset_url == "*" && second_parsed.asset_url != "*") return false; - if (second_parsed.asset_url == "*" && first_parsed.asset_url != "*") return true; - - // sort by port - if (first_parsed.port == "*" && second_parsed.port != "*") return false; - if (second_parsed.port == "*" && first_parsed.port != "*") return true; - - // sort by URI - if (first_parsed.asset_uri == "*" && second_parsed.asset_uri != "*") return false; - if (second_parsed.asset_uri == "*" && first_parsed.asset_uri != "*") return true; - - if (first_parsed.asset_uri.empty()) return false; - if (second_parsed.asset_uri.empty()) return true; - - if (second_parsed.asset_uri.find(first_parsed.asset_uri) != std::string::npos) return false; - if (first_parsed.asset_uri.find(second_parsed.asset_uri) != std::string::npos) return true; - - if (first_parsed.asset_url.empty()) return false; - if (second_parsed.asset_url.empty()) return false; - - return second < first; - } + static bool sortBySpecific(const RulesConfigRulebase &first, const RulesConfigRulebase &second); + static bool sortBySpecificAux(const std::string &first, const std::string &second); std::vector rules_config; }; @@ -376,13 +145,7 @@ public: rules_config_rulebase(RulesConfig(_rules_config)) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("rulebase", rules_config_rulebase) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: RulesConfig rules_config_rulebase; diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/settings_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/settings_section.h index ce403b7..aa79afb 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/settings_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/settings_section.h @@ -28,31 +28,10 @@ USE_DEBUG_FLAG(D_K8S_POLICY); class AgentSettingsSection { public: - AgentSettingsSection( - const std::string &_key, - const std::string &_value) - : - key(_key), - value(_value) - { - try { - id = to_string(boost::uuids::random_generator()()); - } catch (const boost::uuids::entropy_error &e) { - dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what(); - } - } + AgentSettingsSection(const std::string &_key, const std::string &_value); - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("id", id), - cereal::make_nvp("key", key), - cereal::make_nvp("value", value) - ); - } - - const std::string & getSettingId() const { return id; } + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getSettingId() const; private: std::string id; @@ -65,20 +44,7 @@ class SettingsRulebase public: SettingsRulebase(std::vector _agentSettings) : agentSettings(_agentSettings) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - std::string profile_type = "Kubernetes"; - std::string upgrade_mode = "automatic"; - out_ar( - cereal::make_nvp("agentSettings", agentSettings), - cereal::make_nvp("agentType", profile_type), - cereal::make_nvp("allowOnlyDefinedApplications", false), - cereal::make_nvp("anyFog", true), - cereal::make_nvp("maxNumberOfAgents", 10), - cereal::make_nvp("upgradeMode", upgrade_mode) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: std::vector agentSettings; @@ -87,27 +53,9 @@ private: class SettingsWrapper { public: - SettingsWrapper(SettingsRulebase _agent) : agent(_agent) - { - try { - id = to_string(boost::uuids::random_generator()()); - } catch (const boost::uuids::entropy_error &e) { - dbgWarning(D_K8S_POLICY) << "Failed to generate Settings Wrapper UUID. Error: " << e.what(); - } - } + SettingsWrapper(SettingsRulebase _agent); - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("profileType", profileType), - cereal::make_nvp("tokenType", isToken), - cereal::make_nvp("tokenType", tokenType), - cereal::make_nvp("name", name), - cereal::make_nvp("id", id), - cereal::make_nvp("agent", agent) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: std::string profileType = "agent"; diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/snort_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/snort_section.h index 073b644..5d176fe 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/snort_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/snort_section.h @@ -27,24 +27,9 @@ USE_DEBUG_FLAG(D_K8S_POLICY); class AgentSettingsSection { public: - AgentSettingsSection(std::string _key, std::string _value) : key(_key), value(_value) - { - try { - id = to_string(boost::uuids::random_generator()()); - } catch (const boost::uuids::entropy_error &e) { - dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what(); - } - } + AgentSettingsSection(std::string _key, std::string _value); - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("id", id), - cereal::make_nvp("key", key), - cereal::make_nvp("value", value) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: std::string id; @@ -57,20 +42,7 @@ class IpsSnortSigsRulebase public: IpsSnortSigsRulebase(std::vector _agentSettings) : agentSettings(_agentSettings) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - std::string profile_type = "KubernetesProfile"; - std::string upgrade_mode = "automatic"; - out_ar( - cereal::make_nvp("agentSettings", agentSettings), - cereal::make_nvp("agentType", profile_type), - cereal::make_nvp("allowOnlyDefinedApplications", false), - cereal::make_nvp("anyFog", true), - cereal::make_nvp("maxNumberOfAgents", 10), - cereal::make_nvp("upgradeMode", upgrade_mode) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: std::vector agentSettings; diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/triggers_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/triggers_section.h index 4c65538..d9f500d 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/triggers_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/triggers_section.h @@ -52,76 +52,14 @@ public: const std::string &_cefIpAddress, int _syslogPortNum, const std::string &_syslogIpAddress, - bool _beautify_logs) - : - name(_name), - verbosity(_verbosity), - extendloggingMinSeverity(_extendloggingMinSeverity), - extendlogging(_extendlogging), - logToAgent(_logToAgent), - logToCef(_logToCef), - logToCloud(_logToCloud), - logToSyslog(_logToSyslog), - responseBody(_responseBody), - tpDetect(_tpDetect), - tpPrevent(_tpPrevent), - webBody(_webBody), - webHeaders(_webHeaders), - webRequests(_webRequests), - webUrlPath(_webUrlPath), - webUrlQuery(_webUrlQuery), - cefPortNum (_cefPortNum), - cefIpAddress (_cefIpAddress), - syslogPortNum (_syslogPortNum), - syslogIpAddress (_syslogIpAddress), - beautify_logs(_beautify_logs) - { - try { - id = to_string(boost::uuids::random_generator()()); - context = "triggerId(" + id + ")"; - } catch (const boost::uuids::entropy_error &e) { - dbgWarning(D_K8S_POLICY) << "Failed to generate log trigger UUID. Error: " << e.what(); - } - } + bool _beautify_logs + ); - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - std::string trigger_type = "log"; - std::string urlForSyslog = syslogIpAddress + ":" + std::to_string(syslogPortNum); - std::string urlForCef = cefIpAddress + ":" + std::to_string(cefPortNum); - out_ar( - cereal::make_nvp("context", context), - cereal::make_nvp("triggerName", name), - cereal::make_nvp("triggerType", trigger_type), - cereal::make_nvp("verbosity", verbosity), - cereal::make_nvp("acAllow", false), - cereal::make_nvp("acDrop", false), - cereal::make_nvp("complianceViolations", false), - cereal::make_nvp("complianceWarnings", false), - cereal::make_nvp("extendloggingMinSeverity", extendloggingMinSeverity), - cereal::make_nvp("extendlogging", extendlogging), - cereal::make_nvp("logToAgent", logToAgent), - cereal::make_nvp("logToCef", logToCef), - cereal::make_nvp("logToCloud", logToCloud), - cereal::make_nvp("logToSyslog", logToSyslog), - cereal::make_nvp("responseBody", responseBody), - cereal::make_nvp("responseCode", false), - cereal::make_nvp("tpDetect", tpDetect), - cereal::make_nvp("tpPrevent", tpPrevent), - cereal::make_nvp("webBody", webBody), - cereal::make_nvp("webHeaders", webHeaders), - cereal::make_nvp("webRequests", webRequests), - cereal::make_nvp("webUrlPath", webUrlPath), - cereal::make_nvp("webUrlQuery", webUrlQuery), - cereal::make_nvp("urlForSyslog", urlForSyslog), - cereal::make_nvp("urlForCef", urlForCef), - cereal::make_nvp("formatLoggingOutput", beautify_logs) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; - const std::string & getTriggerId() const { return id; } - const std::string & getTriggerName() const { return name; } + const std::string & getTriggerId() const; + const std::string & getTriggerName() const; + bool operator<(const LogTriggerSection &other) const; private: std::string id; @@ -152,43 +90,22 @@ private: class WebUserResponseTriggerSection { public: + WebUserResponseTriggerSection() {} + WebUserResponseTriggerSection( const std::string &_name, const std::string &_details_level, const std::string &_response_body, int _response_code, - const std::string &_response_title) - : - name(_name), - context(), - details_level(_details_level), - response_body(_response_body), - response_title(_response_title), - response_code(_response_code) - { - try { - id = to_string(boost::uuids::random_generator()()); - context = "triggerId(" + id + ")"; - } catch (const boost::uuids::entropy_error &e) { - dbgWarning(D_K8S_POLICY) << "Failed to generate webUserResponse trigger UUID. Error: " << e.what(); - } - } + const std::string &_response_title + ); - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("context", context), - cereal::make_nvp("triggerName", name), - cereal::make_nvp("details level", details_level), - cereal::make_nvp("response body", response_body), - cereal::make_nvp("response code", response_code), - cereal::make_nvp("response title", response_title) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; - const std::string & getTriggerId() const { return id; } - const std::string & getTriggerName() const { return name; } + const std::string & getTriggerId() const; + const std::string & getTriggerName() const; + + bool operator<(const WebUserResponseTriggerSection &other) const; private: std::string id; @@ -203,34 +120,13 @@ private: class AppSecCustomResponseSpec { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec web user response spec"; - parseAppsecJSONKey("http-response-code", httpResponseCode, archive_in, 403); - parseAppsecJSONKey("mode", mode, archive_in, "block-page"); - parseAppsecJSONKey("name", name, archive_in); - if (mode == "block-page") { - parseAppsecJSONKey( - "message-body", - messageBody, - archive_in, - "Openappsec's Application Security has detected an attack and blocked it." - ); - parseAppsecJSONKey( - "message-title", - messageTitle, - archive_in, - "Attack blocked by web application protection" - ); - } - } + void load(cereal::JSONInputArchive &archive_in); - int getHttpResponseCode() const { return httpResponseCode; } - const std::string & getMessageBody() const { return messageBody; } - const std::string & getMessageTitle() const { return messageTitle; } - const std::string & getMode() const { return mode; } - const std::string & getName() const { return name; } + int getHttpResponseCode() const; + const std::string & getMessageBody() const; + const std::string & getMessageTitle() const; + const std::string & getMode() const; + const std::string & getName() const; private: int httpResponseCode; @@ -240,21 +136,6 @@ private: std::string name; }; -std::ostream & -operator<<(std::ostream &os, const AppSecCustomResponseSpec &obj) -{ - os - << "mode: " - << obj.getMode() - << "," << std::endl << "message-title: " - << obj.getMessageTitle() - << "," << std::endl << "message-body: " - << obj.getMessageBody() - << "," << std::endl << "http-response-code: " - << obj.getHttpResponseCode(); - return os; -} - class TriggersRulebase { public: @@ -266,14 +147,7 @@ public: webUserResponseTriggers(_webUserResponseTriggers) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("log", logTriggers), - cereal::make_nvp("webUserResponse", webUserResponseTriggers) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: std::vector logTriggers; @@ -283,49 +157,24 @@ private: class AppsecTriggerAccessControlLogging { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Access Control Logging"; - parseAppsecJSONKey("allow-events", allow_events, archive_in, false); - parseAppsecJSONKey("drop-events", drop_events, archive_in, false); - } + void load(cereal::JSONInputArchive &archive_in); - bool isAllowEvents() const { return allow_events; } - bool isDropEvents() const { return drop_events; } + bool isAllowEvents() const; + bool isDropEvents() const; private: bool allow_events = false; bool drop_events = false; }; -std::ostream & -operator<<(std::ostream &os, const AppsecTriggerAccessControlLogging &obj) -{ - os - << "AppSec Trigger - Access Control Logging: " - << "isAllowEvents: " - << obj.isAllowEvents() - << " , isDropEvents: " - << obj.isDropEvents(); - return os; -} - class AppsecTriggerAdditionalSuspiciousEventsLogging : public ClientRest { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging"; - parseAppsecJSONKey("enabled", enabled, archive_in, true); - parseAppsecJSONKey("response-body", response_body, archive_in, false); - parseAppsecJSONKey("minimum-severity", minimum_severity, archive_in, "high"); - } + void load(cereal::JSONInputArchive &archive_in); - bool isEnabled() const { return enabled; } - bool isResponseBody() const { return response_body; } - const std::string & getMinimumSeverity() const { return minimum_severity; } + bool isEnabled() const; + bool isResponseBody() const; + const std::string & getMinimumSeverity() const; private: bool enabled = true; @@ -333,37 +182,15 @@ private: std::string minimum_severity = "high"; }; -std::ostream & -operator<<(std::ostream &os, const AppsecTriggerAdditionalSuspiciousEventsLogging &obj) -{ - os - << "AppsecTriggerAdditionalSuspiciousEventsLogging: " - << "Enabled: " - << obj.isEnabled() - << " response_body: " - << obj.isResponseBody() - << " minimum_severity: " - << obj.getMinimumSeverity(); - return os; -} - class AppsecTriggerLogging : public ClientRest { public: void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Logging"; - parseAppsecJSONKey("all-web-requests", all_web_requests, archive_in, false); - parseAppsecJSONKey("detect-events", detect_events, archive_in, false); - parseAppsecJSONKey("prevent-events", prevent_events, archive_in, true); - } + load(cereal::JSONInputArchive &archive_in); - bool isAllWebRequests() const { return all_web_requests; } - - bool isDetectEvents() const { return detect_events; } - - bool isPreventEvents() const { return prevent_events; } + bool isAllWebRequests() const; + bool isDetectEvents() const; + bool isPreventEvents() const; private: bool all_web_requests = false; @@ -371,37 +198,15 @@ private: bool prevent_events = true; }; -std::ostream & -operator<<(std::ostream &os, const AppsecTriggerLogging &obj) -{ - os - << "AppsecTriggerLogging: " - << "all_web_requests: " - << obj.isAllWebRequests() - << ", detect_events: " - << obj.isDetectEvents() - << ", prevent_events: " - << obj.isPreventEvents(); - return os; -} - class AppsecTriggerExtendedLogging : public ClientRest { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Extended Logging"; - parseAppsecJSONKey("http-headers", http_headers, archive_in, false); - parseAppsecJSONKey("request-body", request_body, archive_in, false); - parseAppsecJSONKey("url-path", url_path, archive_in, false); - parseAppsecJSONKey("url-query", url_query, archive_in, false); - } + void load(cereal::JSONInputArchive &archive_in); - bool isHttpHeaders() const { return http_headers; } - bool isRequestBody() const { return request_body; } - bool isUrlPath() const { return url_path; } - bool isUrlQuery() const { return url_query; } + bool isHttpHeaders() const; + bool isRequestBody() const; + bool isUrlPath() const; + bool isUrlQuery() const; private: bool http_headers = false; @@ -410,36 +215,14 @@ private: bool url_query = false; }; -std::ostream & -operator<<(std::ostream &os, const AppsecTriggerExtendedLogging &obj) -{ - os - << "AppsecTriggerExtendedLogging: " - << "http_headers: " - << obj.isHttpHeaders() - << ", request_body: " - << obj.isRequestBody() - << ", url_path: " - << obj.isUrlPath() - << ", url_query: " - << obj.isUrlQuery(); - return os; -} - class LoggingService { public: - void - load(cereal::JSONInputArchive &archive_in) - { - parseAppsecJSONKey("address", address, archive_in); - parseAppsecJSONKey("proto", proto, archive_in); - parseAppsecJSONKey("port", port, archive_in, 514); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string & getAddress() const { return address; } - const std::string & getProto() const { return proto; } - int getPort() const { return port; } + const std::string & getAddress() const; + const std::string & getProto() const; + int getPort() const; private: std::string address; @@ -452,13 +235,8 @@ class StdoutLogging public: StdoutLogging() : format("json") {} - void - load(cereal::JSONInputArchive &archive_in) - { - parseAppsecJSONKey("format", format, archive_in, "json"); - } - - const std::string & getFormat() const { return format; } + void load(cereal::JSONInputArchive &archive_in); + const std::string & getFormat() const; private: std::string format; @@ -467,35 +245,22 @@ private: class AppsecTriggerLogDestination : public ClientRest { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger LogDestination"; - // TBD: support "file" - parseAppsecJSONKey("cloud", cloud, archive_in, false); + void load(cereal::JSONInputArchive &archive_in); - StdoutLogging stdout_log; - parseAppsecJSONKey("stdout", stdout_log, archive_in); - agent_local = !(stdout_log.getFormat().empty()); - beautify_logs = stdout_log.getFormat() == "json-formatted"; - parseAppsecJSONKey("syslog-service", syslog_service, archive_in); - parseAppsecJSONKey("cef-service", cef_service, archive_in); - } + int getCefServerUdpPort() const; + int getSyslogServerUdpPort() const; + bool isAgentLocal() const; + bool shouldBeautifyLogs() const; - int getCefServerUdpPort() const { return getCefServiceData().getPort(); } - int getSyslogServerUdpPort() const { return getSyslogServiceData().getPort(); } - bool isAgentLocal() const { return agent_local; } - bool shouldBeautifyLogs() const { return beautify_logs; } - - bool getCloud() const { return cloud; } - bool isCefNeeded() const { return !getCefServiceData().getAddress().empty(); } - bool isSyslogNeeded() const { return !getSyslogServiceData().getAddress().empty(); } - const std::string & getSyslogServerIpv4Address() const { return getSyslogServiceData().getAddress(); } - const std::string & getCefServerIpv4Address() const { return getCefServiceData().getAddress(); } + bool getCloud() const; + bool isCefNeeded() const; + bool isSyslogNeeded() const; + const std::string & getSyslogServerIpv4Address() const; + const std::string & getCefServerIpv4Address() const; private: - const LoggingService & getSyslogServiceData() const { return syslog_service; } - const LoggingService & getCefServiceData() const { return cef_service; } + const LoggingService & getSyslogServiceData() const; + const LoggingService & getCefServiceData() const; bool cloud = false; bool agent_local = true; @@ -504,90 +269,17 @@ private: LoggingService cef_service; }; -std::ostream & -operator<<(std::ostream &os, const AppsecTriggerLogDestination &obj) -{ - os - << "AppSec Trigger Log Destination:" << std::endl - << "agent_local: " - << obj.isAgentLocal() - << ", beautify_logs: " - << obj.shouldBeautifyLogs() - << ", cef_server_udp_port: " - << obj.getCefServerUdpPort() - << ", syslog_server_udp_port: " - << obj.getSyslogServerUdpPort() - << ", cef_service: " - << obj.isCefNeeded() - << ", cloud: " - << obj.getCloud() - << ", syslog: " - << obj.isSyslogNeeded() - << ", syslog_server_ipv4_address: " - << obj.getSyslogServerIpv4Address() - << ", cef_server_ipv4_address: " - << obj.getCefServerIpv4Address(); - return os; -} - class AppsecTriggerSpec { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading AppSec trigger spec"; - parseAppsecJSONKey( - "access-control-logging", - access_control_logging, - archive_in - ); - parseAppsecJSONKey( - "additional-suspicious-events-logging", - additional_suspicious_events_logging, - archive_in - ); - parseAppsecJSONKey("appsec-logging", appsec_logging, archive_in); - parseAppsecJSONKey("extended-logging", extended_logging, archive_in); - parseAppsecJSONKey("log-destination", log_destination, archive_in); - parseAppsecJSONKey("name", name, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const AppsecTriggerAccessControlLogging & - getAppsecTriggerAccessControlLogging() const - { - return access_control_logging; - } - - const std::string & - getName() const - { - return name; - } - - const AppsecTriggerAdditionalSuspiciousEventsLogging & - getAppsecTriggerAdditionalSuspiciousEventsLogging() const - { - return additional_suspicious_events_logging; - } - - const AppsecTriggerLogging & - getAppsecTriggerLogging() const - { - return appsec_logging; - } - - const AppsecTriggerExtendedLogging & - getAppsecTriggerExtendedLogging() const - { - return extended_logging; - } - - const AppsecTriggerLogDestination & - getAppsecTriggerLogDestination() const - { - return log_destination; - } + const AppsecTriggerAccessControlLogging & getAppsecTriggerAccessControlLogging() const; + const std::string & getName() const; + const AppsecTriggerAdditionalSuspiciousEventsLogging & getAppsecTriggerAdditionalSuspiciousEventsLogging() const; + const AppsecTriggerLogging & getAppsecTriggerLogging() const; + const AppsecTriggerExtendedLogging & getAppsecTriggerExtendedLogging() const; + const AppsecTriggerLogDestination & getAppsecTriggerLogDestination() const; private: AppsecTriggerAccessControlLogging access_control_logging; @@ -598,36 +290,13 @@ private: std::string name; }; -std::ostream & -operator<<(std::ostream &os, const AppsecTriggerSpec &obj) -{ - os - << "AppSec Access Control Logging:" << std::endl - << obj.getAppsecTriggerAccessControlLogging() - << std::endl << "AppSec Additional Suspocious Events Logging:" << std::endl - << obj.getAppsecTriggerAdditionalSuspiciousEventsLogging() - << std::endl << "AppSec Trigger Logging:" << std::endl - << obj.getAppsecTriggerLogging() - << std::endl << "Appsec Trigger Extended Logging:" << std::endl - << obj.getAppsecTriggerExtendedLogging() - << std::endl << "AppSec Trigger Log Destination:" << std::endl - << obj.getAppsecTriggerLogDestination(); - return os; -} - class TriggersWrapper { public: TriggersWrapper(const TriggersRulebase &_triggers) : triggers_rulebase(_triggers) {} - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("rulebase", triggers_rulebase) - ); - } + void save(cereal::JSONOutputArchive &out_ar) const; private: TriggersRulebase triggers_rulebase; diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/include/trusted_sources_section.h b/components/security_apps/orchestration/local_policy_mgmt_gen/include/trusted_sources_section.h index 0ba5eee..48a17f0 100755 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/include/trusted_sources_section.h +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/include/trusted_sources_section.h @@ -29,51 +29,18 @@ USE_DEBUG_FLAG(D_K8S_POLICY); class TrustedSourcesSpec { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec"; - parseAppsecJSONKey("minNumOfSources", min_num_of_sources, archive_in, 3); - parseAppsecJSONKey>("sourcesIdentifiers", sources_identifiers, archive_in); - parseAppsecJSONKey("name", name, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - int - getMinNumOfSources() const - { - return min_num_of_sources; - } - - const std::vector & - getSourcesIdentifiers() const - { - return sources_identifiers; - } - - const std::string & - getName() const - { - return name; - } + int getMinNumOfSources() const; + const std::vector & getSourcesIdentifiers() const; + const std::string & getName() const; private: - int min_num_of_sources; + int min_num_of_sources = 0; std::string name; std::vector sources_identifiers; }; -std::ostream & -operator<<(std::ostream &os, const TrustedSourcesSpec &obj) -{ - os - << "Min number of sources: " - << obj.getMinNumOfSources() - << ", SourceIdentifiers: [" - << makeSeparatedStr(obj.getSourcesIdentifiers(), ",") - << "]"; - return os; -} - class SourcesIdentifiers { public: @@ -83,20 +50,8 @@ public: value(_value) {} - void - save(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("sourceIdentifier", source_identifier), - cereal::make_nvp("value", value) - ); - } - - const std::string & - getSourceIdent() const - { - return source_identifier; - } + void save(cereal::JSONOutputArchive &out_ar) const; + const std::string & getSourceIdent() const; private: std::string source_identifier; @@ -106,25 +61,10 @@ private: class SourceIdentifierSpec { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec"; - parseAppsecJSONKey("sourceIdentifier", source_identifier, archive_in); - parseAppsecJSONKey>("value", value, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string & - getSourceIdentifier() const - { - return source_identifier; - } - - const std::vector & - getValues() const - { - return value; - } + const std::string & getSourceIdentifier() const; + const std::vector & getValues() const; private: std::string source_identifier; @@ -134,43 +74,16 @@ private: class SourceIdentifierSpecWrapper { public: - void - load(cereal::JSONInputArchive &archive_in) - { - dbgTrace(D_K8S_POLICY) << "Loading Source Identifier Spec Wrapper"; - parseAppsecJSONKey>("identifiers", identifiers, archive_in); - parseAppsecJSONKey("name", name, archive_in); - } + void load(cereal::JSONInputArchive &archive_in); - const std::string & - getName() const - { - return name; - } - - const std::vector & - getIdentifiers() const - { - return identifiers; - } + const std::string & getName() const; + const std::vector & getIdentifiers() const; private: std::string name; std::vector identifiers; }; -std::ostream & -operator<<(std::ostream &os, const SourceIdentifierSpec &obj) -{ - os - << "sourceIdentifier: " - << obj.getSourceIdentifier() - << ", values: [" - << makeSeparatedStr(obj.getValues(), ",") - << "]"; - return os; -} - class AppSecTrustedSources { public: @@ -180,42 +93,16 @@ public: AppSecTrustedSources( const std::string &_name, int _num_of_sources, - const std::vector &_sources_identifiers) - : - name(_name), - num_of_sources(_num_of_sources), - sources_identifiers(_sources_identifiers) - { - try { - id = to_string(boost::uuids::random_generator()()); - } catch (const boost::uuids::entropy_error &e) { - dbgWarning(D_K8S_POLICY) << "Failed to generate Trusted Sources ID. Error: " << e.what(); - } - } + const std::vector &_sources_identifiers + ); - void - save(cereal::JSONOutputArchive &out_ar) const - { - std::string parameter_type = "TrustedSource"; - out_ar( - cereal::make_nvp("id", id), - cereal::make_nvp("name", name), - cereal::make_nvp("numOfSources", num_of_sources), - cereal::make_nvp("sourcesIdentifiers", sources_identifiers), - cereal::make_nvp("parameterType", parameter_type) - ); - } - - const std::vector & - getSourcesIdentifiers() const - { - return sources_identifiers; - } + void save(cereal::JSONOutputArchive &out_ar) const; + const std::vector & getSourcesIdentifiers() const; private: std::string id; std::string name; - int num_of_sources; + int num_of_sources = 0; std::vector sources_identifiers; }; // LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/ingress_data.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/ingress_data.cc new file mode 100644 index 0000000..82cbb5b --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/ingress_data.cc @@ -0,0 +1,178 @@ +#include "ingress_data.h" + +using namespace std; + +USE_DEBUG_FLAG(D_K8S_POLICY); +// LCOV_EXCL_START Reason: no test exist +void +IngressMetadata::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "IngressMetadata load"; + parseAppsecJSONKey("name", name, archive_in); + parseAppsecJSONKey("resourceVersion", resourceVersion, archive_in); + parseAppsecJSONKey("namespace", namespace_name, archive_in); + parseAppsecJSONKey>("annotations", annotations, archive_in); +} + +const string & +IngressMetadata::getName() const +{ + return name; +} + +const string & +IngressMetadata::getResourceVersion() const +{ + return resourceVersion; +} + +const string & +IngressMetadata::getNamespace() const +{ + return namespace_name; +} + +const map & +IngressMetadata::getAnnotations() const +{ + return annotations; +} + +void +IngressRulePath::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path"; + parseAppsecJSONKey("path", path, archive_in); +} + +const string & +IngressRulePath::getPath() const +{ + return path; +} + +void +IngressRulePathsWrapper::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule path wrapper"; + parseAppsecJSONKey>("paths", paths, archive_in); +} + +const vector & +IngressRulePathsWrapper::getRulePaths() const +{ + return paths; +} + +void +IngressDefinedRule::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading ingress defined rule"; + parseAppsecJSONKey("host", host, archive_in); + parseAppsecJSONKey("http", paths_wrapper, archive_in); +} + +const string & +IngressDefinedRule::getHost() const +{ + return host; +} + +const IngressRulePathsWrapper & +IngressDefinedRule::getPathsWrapper() const +{ + return paths_wrapper; +} + +void +DefaultBackend::load(cereal::JSONInputArchive &) +{ + dbgTrace(D_K8S_POLICY) << "Loading Default Backend"; + is_exists = true; +} + +bool +DefaultBackend::isExists() const +{ + return is_exists; +} + +void +IngressSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading single ingress spec"; + parseAppsecJSONKey("ingressClassName", ingress_class_name, archive_in); + parseAppsecJSONKey>("rules", rules, archive_in); + parseAppsecJSONKey("defaultBackend", default_backend, archive_in); +} + +const string & +IngressSpec::getIngressClassName() const +{ + return ingress_class_name; +} + +const vector & +IngressSpec::getRules() const +{ + return rules; +} +bool +IngressSpec::isDefaultBackendExists() const +{ + return default_backend.isExists(); +} + +void +SingleIngressData::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading single ingress data"; + parseAppsecJSONKey("metadata", metadata, archive_in); + parseAppsecJSONKey("spec", spec, archive_in); +} + +const IngressMetadata & +SingleIngressData::getMetadata() const +{ + return metadata; +} + +const IngressSpec & +SingleIngressData::getSpec() const +{ + return spec; +} + +bool +IngressData::loadJson(const string &json) +{ + string modified_json = json; + modified_json.pop_back(); + stringstream in; + in.str(modified_json); + dbgTrace(D_K8S_POLICY) << "Loading ingress data"; + try { + cereal::JSONInputArchive in_ar(in); + in_ar( + cereal::make_nvp("apiVersion", apiVersion), + cereal::make_nvp("items", items) + ); + } catch (cereal::Exception &e) { + dbgError(D_K8S_POLICY) << "Failed to load ingress data JSON. Error: " << e.what(); + return false; + } + return true; +} + +const string & +IngressData::getapiVersion() const +{ + return apiVersion; +} + +const vector & +IngressData::getItems() const +{ + return items; +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/local_policy_mgmt_gen.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/local_policy_mgmt_gen.cc index 5bf13ba..a9224e3 100644 --- a/components/security_apps/orchestration/local_policy_mgmt_gen/local_policy_mgmt_gen.cc +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/local_policy_mgmt_gen.cc @@ -44,6 +44,7 @@ #include "include/exceptions_section.h" #include "include/rules_config_section.h" #include "include/trusted_sources_section.h" +#include "include/policy_maker_utils.h" using namespace std; @@ -56,62 +57,6 @@ const static string syslog_key = "syslog"; const static string mode_key = "mode"; const static string local_mgmt_policy_path = "/conf/local_policy.yaml"; // LCOV_EXCL_START Reason: no test exist -class SecurityAppsWrapper -{ -public: - SecurityAppsWrapper( - const AppSecWrapper &_waap, - const TriggersWrapper &_trrigers, - const RulesConfigWrapper &_rules, - const ExceptionsWrapper &_exceptions, - const string &_policy_version) - : - waap(_waap), - trrigers(_trrigers), - rules(_rules), - exceptions(_exceptions), - policy_version(_policy_version) {} - - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - out_ar( - cereal::make_nvp("waap", waap), - cereal::make_nvp("triggers", trrigers), - cereal::make_nvp("rules", rules), - cereal::make_nvp("exceptions", exceptions), - cereal::make_nvp("version", policy_version) - ); - } - -private: - AppSecWrapper waap; - TriggersWrapper trrigers; - RulesConfigWrapper rules; - ExceptionsWrapper exceptions; - string policy_version; -}; - -class K8sPolicyWrapper -{ -public: - K8sPolicyWrapper( - const SettingsWrapper &_settings, - const SecurityAppsWrapper &_security_apps) - : - settings(_settings), - security_apps(_security_apps) {} - - void - serialize(cereal::JSONOutputArchive &out_ar) const - { - security_apps.serialize(out_ar); - } - -private: - SettingsWrapper settings; - SecurityAppsWrapper security_apps; -}; class NamespaceMetadata { @@ -120,16 +65,16 @@ public: load(cereal::JSONInputArchive &archive_in) { dbgInfo(D_K8S_POLICY) << "NamespaceMetadata load"; - parseAppsecJSONKey("name", name, archive_in); - parseAppsecJSONKey("uid", uid, archive_in); + parseAppsecJSONKey("name", name, archive_in); + parseAppsecJSONKey("uid", uid, archive_in); } - const std::string & getName() const { return name; } - const std::string & getUID() const { return uid; } + const string & getName() const { return name; } + const string & getUID() const { return uid; } private: - std::string name; - std::string uid; + string name; + string uid; }; class SingleNamespaceData @@ -151,12 +96,12 @@ class NamespaceData : public ClientRest { public: bool - loadJson(const std::string &json) + loadJson(const string &json) { dbgTrace(D_K8S_POLICY) << "Loading namespace data"; - std::string modified_json = json; + string modified_json = json; modified_json.pop_back(); - std::stringstream in; + stringstream in; in.str(modified_json); try { cereal::JSONInputArchive in_ar(in); @@ -170,10 +115,10 @@ public: return true; } - const std::vector & getItems() const { return items; } + const vector & getItems() const { return items; } private: - std::vector items; + vector items; }; class LocalPolicyMgmtGenerator::Impl @@ -289,7 +234,7 @@ public: return appsec_policy; }); - vector specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules(); + list specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules(); ParsedRule default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule(); string asset; @@ -461,7 +406,7 @@ public: ); string port = "80"; string full_url = asset_name == "Any" ? "" : url + uri + ":" + port; - string asset_id = rules_config.getAsstId(); + string asset_id = rules_config.getAssetId(); string practice_id = rules_config.getPracticeId(); if (!generated_apps.count(full_url)) { @@ -483,7 +428,7 @@ public: parsed_rules.push_back(rules_config); generated_apps.insert(full_url); } - } + } //end specific rules string exception_name; if (!default_rule.getExceptions().empty()) { @@ -563,9 +508,9 @@ public: ); SettingsWrapper profiles_section = createProfilesSection(); - K8sPolicyWrapper k8s_policy = K8sPolicyWrapper(profiles_section, security_app_section); + PolicyWrapper policy_wrapper = PolicyWrapper(profiles_section, security_app_section); - return dumpPolicyToFile(k8s_policy); + return dumpPolicyToFile(policy_wrapper); } LocalPolicyEnv getEnvType() const { return env_type;} @@ -608,14 +553,6 @@ public: dbgTrace(D_K8S_POLICY) << "Ingress items ammount: " << ingress.getItems().size(); // TBD: break to methods : INXT-31445 for (const SingleIngressData &item : ingress.getItems()) { - dbgTrace(D_K8S_POLICY) - << "Metadata name is: " - << item.getMetadata().getName() - << ", Namespace is: " - << item.getMetadata().getNamespace() - << ", Spec: " - << item.getSpec(); - set> specific_assets_from_ingress; for (const IngressDefinedRule &rule : item.getSpec().getRules()) { string url = rule.getHost(); @@ -670,9 +607,8 @@ public: } AppsecSpecParser appsec_policy = maybe_appsec_policy.unpack(); - dbgTrace(D_K8S_POLICY) << "Succeessfully retrieved AppSec policy: " << appsec_policy.getSpec(); - vector specific_rules = appsec_policy.getSpec().getSpecificRules(); + list specific_rules = appsec_policy.getSpec().getSpecificRules(); ParsedRule default_rule = appsec_policy.getSpec().getDefaultRule(); for (const ParsedRule &parsed_rule : specific_rules) { @@ -799,10 +735,6 @@ public: AppsecSpecParser appsec_practice = maybe_appsec_practice.unpack(); practice_map.emplace(practice_annotation_name, appsec_practice.getSpec()); - dbgTrace(D_K8S_POLICY) - << "Successfully retrieved AppSec practice" - << practice_annotation_name - << appsec_practice.getSpec(); } string log_trigger_id; @@ -830,7 +762,7 @@ public: ); string port = "80"; string full_url = asset_name == "Any" ? "" : url + "/" + uri + ":" + port; - string asset_id = rules_config.getAsstId(); + string asset_id = rules_config.getAssetId(); string practice_id = rules_config.getPracticeId(); if (!generated_apps.count(full_url)) { @@ -917,10 +849,6 @@ public: AppsecSpecParser appsec_practice = maybe_appsec_practice.unpack(); practice_map.emplace(practice_name, appsec_practice.getSpec()); - dbgTrace(D_K8S_POLICY) - << "Successfully retrieved AppSec practice" - << practice_name - << appsec_practice.getSpec(); } if (item.getSpec().isDefaultBackendExists()) { @@ -978,7 +906,7 @@ public: parsed_rules.push_back(default_rule_config); } - string asset_id = default_rule_config.getAsstId(); + string asset_id = default_rule_config.getAssetId(); string practice_id = default_rule_config.getPracticeId(); if (!generated_apps.count(asset.first + asset.second)) { @@ -1035,7 +963,7 @@ public: ); SettingsWrapper profiles_section = createProfilesSection(); - K8sPolicyWrapper k8s_policy = K8sPolicyWrapper(profiles_section, security_app_section); + PolicyWrapper k8s_policy = PolicyWrapper(profiles_section, security_app_section); return dumpPolicyToFile(k8s_policy); } @@ -1238,7 +1166,7 @@ private: env_value.begin(), env_value.end(), env_value.begin(), - [](unsigned char c) { return std::tolower(c); } + [](unsigned char c) { return tolower(c); } ); return env_value == "true"; } @@ -1283,12 +1211,12 @@ private: } const string - dumpPolicyToFile(const K8sPolicyWrapper &k8s_policy) const + dumpPolicyToFile(const PolicyWrapper &policy) const { stringstream ss; { cereal::JSONOutputArchive ar(ss); - k8s_policy.serialize(ar); + policy.save(ar); } string policy_str = ss.str(); ofstream policy_file(local_appsec_policy_path); @@ -1300,12 +1228,18 @@ private: string readFileContent(const string&file_path) { - ifstream file(file_path); - stringstream buffer; - - buffer << file.rdbuf(); - - return buffer.str(); + try { + ifstream file(file_path); + stringstream buffer; + buffer << file.rdbuf(); + return buffer.str(); + } catch (ifstream::failure &f) { + dbgWarning(D_ORCHESTRATOR) + << "Cannot read the file" + << " File: " << file_path + << " Error: " << f.what(); + return ""; + } } string @@ -1436,12 +1370,6 @@ private: return false; } - dbgTrace(D_K8S_POLICY) - << "Successfuly retrieved AppSec exceptions for " - << trigger_annotation_name - << ":\n" - << *maybe_appsec_trigger_spec; - LogTriggerSection log_triggers_section = createLogTriggersSection(trigger_annotation_name, false, "", *maybe_appsec_trigger_spec); log_triggers_map.emplace(trigger_annotation_name, log_triggers_section); @@ -1688,12 +1616,6 @@ private: ) ); } - - dbgTrace(D_K8S_POLICY) - << "Successfuly retrieved AppSec web user response for: " - << web_user_res_annotation_name - << ":\n" - << appsec_web_user_res_spec; } return true; } diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/policy_maker_utils.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/policy_maker_utils.cc new file mode 100644 index 0000000..36927ba --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/policy_maker_utils.cc @@ -0,0 +1,579 @@ +#include "policy_maker_utils.h" + +using namespace std; + +USE_DEBUG_FLAG(D_NGINX_POLICY); + +// LCOV_EXCL_START Reason: no test exist + +void +SecurityAppsWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("waap", waap), + cereal::make_nvp("triggers", trrigers), + cereal::make_nvp("rules", rules), + cereal::make_nvp("exceptions", exceptions), + cereal::make_nvp("version", policy_version) + ); +} + +void +PolicyWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + security_apps.save(out_ar); +} + +void +PolicyMakerUtils::clearElementsMaps() +{ + log_triggers.clear(); + web_user_res_triggers.clear(); + inner_exceptions.clear(); + web_apps.clear(); + rules_config.clear(); +} + +bool +PolicyMakerUtils::startsWith(const string &str, const string &prefix) +{ + return str.rfind(prefix, 0) == 0; +} + +bool +PolicyMakerUtils::endsWith(const string &str, const string &suffix) +{ + return str.size() >= suffix.size() && + str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; +} + +tuple +PolicyMakerUtils::splitHostName(const string &host_name) +{ + string url = host_name; + string uri; + string port; + if (startsWith(url, "http://")) { + url = url.substr(7, url.length() - 1); + port = "80"; + } else if (startsWith(url, "https://")) { + url = url.substr(8, url.length() - 1); + port = "443"; + } + + if (url.find("/") != string::npos) { + uri = url.substr(url.find("/")); + url = url.substr(0, url.find("/")); + } else { + uri = ""; + } + + if (url.find(":") != string::npos) { + port = url.substr(url.find(":") + 1, url.length() - 1); + url = url.substr(0, url.find(":")); + } + + if (host_name == "*") { + url = "Any"; + uri = "Any"; + } + return make_tuple(url, port, uri); +} + +string +PolicyMakerUtils::dumpPolicyToFile(const PolicyWrapper &policy, const string &policy_path) const +{ + stringstream ss; + { + cereal::JSONOutputArchive ar(ss); + policy.save(ar); + } + string policy_str = ss.str(); + dbgTrace(D_NGINX_POLICY) << "policy: " << policy_str; + try { + ofstream policy_file(policy_path); + policy_file << policy_str; + policy_file.close(); + } catch (const ofstream::failure &e) { + dbgDebug(D_NGINX_POLICY) << "Error while writing new policy to " << policy_path << ", Error: " << e.what(); + return ""; + } + return policy_str; +} + +map +extractAnnotationsNames( + const ParsedRule &parsed_rule, + const ParsedRule &default_rule, + const string &policy_name) +{ + map rule_annotation; + string practice_annotation_name; + // TBD: support multiple practices + if (!parsed_rule.getPractices().empty() && !parsed_rule.getPractices()[0].empty()) { + practice_annotation_name = parsed_rule.getPractices()[0]; + } else if (!default_rule.getPractices().empty() && !default_rule.getPractices()[0].empty()) { + practice_annotation_name = default_rule.getPractices()[0]; + } + + if (!practice_annotation_name.empty()) { + rule_annotation[AnnotationTypes::PRACTICE] = policy_name + "/" + practice_annotation_name; + } + + string trigger_annotation_name; + // TBD: support multiple triggers + if (!parsed_rule.getLogTriggers().empty() && !parsed_rule.getLogTriggers()[0].empty()) { + trigger_annotation_name = parsed_rule.getLogTriggers()[0]; + } else if (!default_rule.getLogTriggers().empty() && !default_rule.getLogTriggers()[0].empty()) { + trigger_annotation_name = default_rule.getLogTriggers()[0]; + } + + if (!trigger_annotation_name.empty()) { + rule_annotation[AnnotationTypes::TRIGGER] = policy_name + "/" + trigger_annotation_name; + } + + string exception_annotation_name; + // TBD: support multiple exceptions + if (!parsed_rule.getExceptions().empty() && !parsed_rule.getExceptions()[0].empty()) { + exception_annotation_name = parsed_rule.getExceptions()[0]; + } else if (!default_rule.getExceptions().empty() && !default_rule.getExceptions()[0].empty()) { + exception_annotation_name = default_rule.getExceptions()[0]; + } + + if (!exception_annotation_name.empty()) { + rule_annotation[AnnotationTypes::EXCEPTION] = policy_name + "/" + exception_annotation_name; + } + + string web_user_res_annotation_name = + parsed_rule.getCustomResponse().empty() ? + default_rule.getCustomResponse() : + parsed_rule.getCustomResponse(); + + if (!web_user_res_annotation_name.empty()) { + rule_annotation[AnnotationTypes::WEB_USER_RES] = policy_name + "/" + web_user_res_annotation_name; + } + + string source_identifiers_annotation_name = + parsed_rule.getSourceIdentifiers().empty() ? + default_rule.getSourceIdentifiers() : + parsed_rule.getSourceIdentifiers(); + + if (!source_identifiers_annotation_name.empty()) { + rule_annotation[AnnotationTypes::SOURCE_IDENTIFIERS] = policy_name + "/" + source_identifiers_annotation_name; + } + + string trusted_sources_annotation_name = + parsed_rule.getTrustedSources ().empty() ? + default_rule.getTrustedSources() : + parsed_rule.getTrustedSources(); + + if (!trusted_sources_annotation_name.empty()) { + rule_annotation[AnnotationTypes::TRUSTED_SOURCES] = policy_name + "/" + trusted_sources_annotation_name; + } + return rule_annotation; +} + +template +container_it +extractElement(container_it begin, container_it end, const string &element_name) +{ + dbgTrace(D_NGINX_POLICY) << "Tryting to find element: " << element_name; + string clean_element_name = element_name.substr(element_name.find("/") + 1); + for (container_it it = begin; it < end; it++) { + if (clean_element_name == it->getName()) { + dbgTrace(D_NGINX_POLICY) << "Element with name " << clean_element_name << " was found"; + return it; + } + } + dbgTrace(D_NGINX_POLICY) << "Element with name " << clean_element_name << " was not found"; + return end; +} + +template +vector +convertMapToVector(map map) +{ + vector vec; + vec.reserve(map.size()); + if (map.empty()) { + return vec; + } + for (const auto &m : map) { + if (!m.first.empty()) vec.push_back(m.second); + } + return vec; +} + +AppSecPracticeSpec +getAppsecPracticeSpec(const string &practice_annotation_name, const AppsecLinuxPolicy &policy) +{ + auto practices_vec = policy.getAppSecPracticeSpecs(); + auto practice_it = extractElement(practices_vec.begin(), practices_vec.end(), practice_annotation_name); + + if (practice_it == practices_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec practice"; + return AppSecPracticeSpec(); + } + return *practice_it; +} + +AppsecTriggerSpec +getAppsecTriggerSpec(const string &trigger_annotation_name, const AppsecLinuxPolicy &policy) +{ + auto triggers_vec = policy.getAppsecTriggerSpecs(); + auto trigger_it = extractElement(triggers_vec.begin(), triggers_vec.end(), trigger_annotation_name); + + if (trigger_it == triggers_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec trigger"; + return AppsecTriggerSpec(); + } + return *trigger_it; +} + +AppsecExceptionSpec +getAppsecExceptionSpec(const string &exception_annotation_name, const AppsecLinuxPolicy &policy) +{ + auto exceptions_vec = policy.getAppsecExceptionSpecs(); + auto exception_it = extractElement(exceptions_vec.begin(), exceptions_vec.end(), exception_annotation_name); + + if (exception_it == exceptions_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec exception"; + return AppsecExceptionSpec(); + } + return *exception_it; +} + +AppSecCustomResponseSpec +getAppsecCustomResponseSpec(const string &custom_response_annotation_name, const AppsecLinuxPolicy &policy) +{ + auto custom_response_vec = policy.getAppSecCustomResponseSpecs(); + auto custom_response_it = extractElement( + custom_response_vec.begin(), + custom_response_vec.end(), + custom_response_annotation_name); + + if (custom_response_it == custom_response_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec custom response"; + return AppSecCustomResponseSpec(); + } + return *custom_response_it; +} + +SourceIdentifierSpecWrapper +getAppsecSourceIdentifierSpecs(const string &source_identifiers_annotation_name, const AppsecLinuxPolicy &policy) +{ + auto source_identifiers_vec = policy.getAppsecSourceIdentifierSpecs(); + auto source_identifier_it = extractElement( + source_identifiers_vec.begin(), + source_identifiers_vec.end(), + source_identifiers_annotation_name); + + if (source_identifier_it == source_identifiers_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec source identifier"; + return SourceIdentifierSpecWrapper(); + } + return *source_identifier_it; +} + +TrustedSourcesSpec +getAppsecTrustedSourceSpecs(const string &trusted_sources_annotation_name, const AppsecLinuxPolicy &policy) +{ + auto trusted_sources_vec = policy.getAppsecTrustedSourceSpecs(); + auto trusted_sources_it = extractElement( + trusted_sources_vec.begin(), + trusted_sources_vec.end(), + trusted_sources_annotation_name); + + if (trusted_sources_it == trusted_sources_vec.end()) { + dbgTrace(D_NGINX_POLICY) << "Failed to retrieve AppSec trusted source"; + return TrustedSourcesSpec(); + } + return *trusted_sources_it; +} + +LogTriggerSection +createLogTriggerSection( + const string &trigger_annotation_name, + const AppsecLinuxPolicy &policy) +{ + AppsecTriggerSpec trigger_spec = getAppsecTriggerSpec(trigger_annotation_name, policy); + + string verbosity = "Standard"; + string extendLoggingMinSeverity = + trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().getMinimumSeverity(); + bool tpDetect = trigger_spec.getAppsecTriggerLogging().isDetectEvents(); + bool tpPrevent = trigger_spec.getAppsecTriggerLogging().isPreventEvents(); + bool webRequests = trigger_spec.getAppsecTriggerLogging().isAllWebRequests(); + bool webUrlPath = trigger_spec.getAppsecTriggerExtendedLogging().isUrlPath(); + bool webUrlQuery = trigger_spec.getAppsecTriggerExtendedLogging().isUrlQuery(); + bool webHeaders = trigger_spec.getAppsecTriggerExtendedLogging().isHttpHeaders(); + bool webBody = trigger_spec.getAppsecTriggerExtendedLogging().isRequestBody(); + bool logToCloud = trigger_spec.getAppsecTriggerLogDestination().getCloud(); + bool logToAgent = trigger_spec.getAppsecTriggerLogDestination().isAgentLocal(); + bool beautify_logs = trigger_spec.getAppsecTriggerLogDestination().shouldBeautifyLogs(); + bool logToCef = trigger_spec.getAppsecTriggerLogDestination().isCefNeeded(); + bool logToSyslog = trigger_spec.getAppsecTriggerLogDestination().isSyslogNeeded(); + bool responseBody = trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().isResponseBody(); + bool extendLogging = trigger_spec.getAppsecTriggerAdditionalSuspiciousEventsLogging().isEnabled(); + int cefPortNum = logToCef ? trigger_spec.getAppsecTriggerLogDestination().getCefServerUdpPort() : 0; + string cefIpAddress = + logToCef ? trigger_spec.getAppsecTriggerLogDestination().getCefServerIpv4Address() : ""; + int syslogPortNum = + logToSyslog ? + trigger_spec.getAppsecTriggerLogDestination().getSyslogServerUdpPort() : + 514; + string syslogIpAddress = + logToSyslog ? + trigger_spec.getAppsecTriggerLogDestination().getSyslogServerIpv4Address() : + ""; + + LogTriggerSection log( + trigger_annotation_name, + verbosity, + extendLoggingMinSeverity, + extendLogging, + logToAgent, + logToCef, + logToCloud, + logToSyslog, + responseBody, + tpDetect, + tpPrevent, + webBody, + webHeaders, + webRequests, + webUrlPath, + webUrlQuery, + cefPortNum, + cefIpAddress, + syslogPortNum, + syslogIpAddress, + beautify_logs + ); + return log; +} + +WebUserResponseTriggerSection +createWebUserResponseTriggerSection( + const string &web_user_res_annotation_name, + const AppsecLinuxPolicy &policy) +{ + AppSecCustomResponseSpec web_user_res_spec = getAppsecCustomResponseSpec(web_user_res_annotation_name, policy); + string mode = web_user_res_spec.getMode(); + string response_body = web_user_res_spec.getMessageBody(); + string response_title = web_user_res_spec.getMessageTitle(); + int response_code = web_user_res_spec.getHttpResponseCode(); + + WebUserResponseTriggerSection web_user_res( + web_user_res_annotation_name, + mode, + response_body, + response_code, + response_title + ); + + return web_user_res; +} + +InnerException +createExceptionSection( + const string &exception_annotation_name, + const AppsecLinuxPolicy &policy) +{ + AppsecExceptionSpec exception_spec = getAppsecExceptionSpec(exception_annotation_name, policy); + ExceptionMatch exception_match(exception_spec); + string behavior = + exception_spec.getAction() == "skip" ? + "ignore" : + exception_spec.getAction(); + ExceptionBehavior exception_behavior("action", behavior); + InnerException inner_exception(exception_behavior, exception_match); + return inner_exception; +} + +RulesConfigRulebase +createMultiRulesSections( + const string &url, + const string &uri, + const string &practice_id, + const string &practice_name, + const string &practice_type, + const string &log_trigger_name, + const string &log_trigger_id, + const string &log_trigger_type, + const string &web_user_res_vec_name, + const string &web_user_res_vec_id, + const string &web_user_res_vec_type, + const string &asset_name, + const string &exception_name, + const string &exception_id) +{ + PracticeSection practice = PracticeSection(practice_id, practice_type, practice_name); + ParametersSection exception_param = ParametersSection(exception_id, exception_name); + + vector triggers; + if (!log_trigger_id.empty()) { + triggers.push_back(RulesTriggerSection(log_trigger_name, log_trigger_id, log_trigger_type)); + } + if (!web_user_res_vec_id.empty()) { + triggers.push_back(RulesTriggerSection( + web_user_res_vec_name, + web_user_res_vec_id, + web_user_res_vec_type) + ); + } + + RulesConfigRulebase rules_config = RulesConfigRulebase( + asset_name, + url, + uri, + {practice}, + {exception_param}, + triggers + ); + return rules_config; +} + +SettingsWrapper +createProfilesSection() +{ + string agent_settings_key = "agent.test.policy"; + string agent_settings_value = "local policy"; + AgentSettingsSection agent_setting_1 = AgentSettingsSection(agent_settings_key, agent_settings_value); + + SettingsRulebase settings_rulebase_1 = SettingsRulebase({agent_setting_1}); + return SettingsWrapper(settings_rulebase_1); +} + +PolicyWrapper +PolicyMakerUtils::combineElementsToPolicy(const string &policy_version) +{ + TriggersWrapper triggers_section( + TriggersRulebase( + convertMapToVector(log_triggers), convertMapToVector(web_user_res_triggers) + ) + ); + ExceptionsWrapper exceptions_section({ + ExceptionsRulebase(convertMapToVector(inner_exceptions)) + }); + + AppSecWrapper appses_section(AppSecRulebase(convertMapToVector(web_apps), {})); + RulesConfigWrapper rules_config_section(convertMapToVector(rules_config)); + SecurityAppsWrapper security_app_section = SecurityAppsWrapper( + appses_section, + triggers_section, + rules_config_section, + exceptions_section, + policy_version + ); + + SettingsWrapper profiles_section = createProfilesSection(); + PolicyWrapper policy_wrapper = PolicyWrapper(profiles_section, security_app_section); + + return policy_wrapper; +} + +void +PolicyMakerUtils::createPolicyElementsByRule( + const ParsedRule &rule, + const ParsedRule &default_rule, + const AppsecLinuxPolicy &policy, + const string &policy_name) +{ + map rule_annotations = extractAnnotationsNames(rule, default_rule, policy_name); + if ( + !rule_annotations[AnnotationTypes::TRIGGER].empty() && + !log_triggers.count(rule_annotations[AnnotationTypes::TRIGGER]) + ) { + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]] = + createLogTriggerSection( + rule_annotations[AnnotationTypes::TRIGGER], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::WEB_USER_RES].empty() && + !web_user_res_triggers.count(rule_annotations[AnnotationTypes::WEB_USER_RES]) + ) { + web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]] = + createWebUserResponseTriggerSection( + rule_annotations[AnnotationTypes::WEB_USER_RES], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::EXCEPTION].empty() && + !inner_exceptions.count(rule_annotations[AnnotationTypes::EXCEPTION]) + ) { + inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]] = + createExceptionSection( + rule_annotations[AnnotationTypes::EXCEPTION], + policy + ); + } + + if ( + !rule_annotations[AnnotationTypes::PRACTICE].empty() && + !web_apps.count(rule_annotations[AnnotationTypes::PRACTICE]) + ) { + string practice_id = ""; + try { + practice_id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + //TBD: return Maybe as part of future error handling + } + tuple splited_host_name = splitHostName(rule.getHost()); + string full_url = rule.getHost() == "*" + ? "Any" + : rule.getHost(); + + + RulesConfigRulebase rule_config = createMultiRulesSections( + std::get<0>(splited_host_name), + std::get<2>(splited_host_name), + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + "WebApplication", + rule_annotations[AnnotationTypes::TRIGGER], + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]].getTriggerId(), + "log", + rule_annotations[AnnotationTypes::WEB_USER_RES], + web_user_res_triggers[rule_annotations[AnnotationTypes::WEB_USER_RES]].getTriggerId(), + "WebUserResponse", + full_url, + rule_annotations[AnnotationTypes::EXCEPTION], + inner_exceptions[rule_annotations[AnnotationTypes::EXCEPTION]].getBehaviorId() + ); + rules_config[rule_config.getAssetName()] = rule_config; + + WebAppSection web_app = WebAppSection( + full_url == "Any" ? "" : full_url, + rule_config.getAssetId(), + rule_config.getAssetName(), + rule_config.getAssetId(), + rule_config.getAssetName(), + practice_id, + rule_annotations[AnnotationTypes::PRACTICE], + getAppsecPracticeSpec(rule_annotations[AnnotationTypes::PRACTICE], policy), + log_triggers[rule_annotations[AnnotationTypes::TRIGGER]], + rule.getMode(), + AppSecTrustedSources() + ); + web_apps[rule_annotations[AnnotationTypes::PRACTICE]] = web_app; + } +} + +void +PolicyMakerUtils::createPolicyElements( + const vector &rules, + const ParsedRule &default_rule, + const AppsecLinuxPolicy &policy, + const string &policy_name) +{ + for (const ParsedRule &rule : rules) { + createPolicyElementsByRule(rule, default_rule, policy, policy_name); + } +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/rules_config_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/rules_config_section.cc new file mode 100644 index 0000000..8efe031 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/rules_config_section.cc @@ -0,0 +1,365 @@ +#include "rules_config_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_K8S_POLICY); + +// LCOV_EXCL_START Reason: no test exist +AssetUrlParser +AssetUrlParser::parse(const string &uri) +{ + AssetUrlParser result; + + using iterator_t = string::const_iterator; + + if (uri.length() == 0) return result; + + iterator_t uri_end = uri.end(); + + // get query start + iterator_t query_start = find(uri.begin(), uri_end, '?'); + + // protocol + iterator_t protocol_start = uri.begin(); + iterator_t protocol_end = find(protocol_start, uri_end, ':'); //"://"); + + if (protocol_end != uri_end) { + string http_protocol = &*(protocol_end); + if ((http_protocol.length() > 3) && (http_protocol.substr(0, 3) == "://")) { + result.protocol = string(protocol_start, protocol_end); + protocol_end += 3; // :// + } else { + protocol_end = uri.begin(); // no protocol + } + } else { + protocol_end = uri.begin(); // no protocol + } + + // URL + iterator_t host_start = protocol_end; + iterator_t path_start = find(host_start, uri_end, '/'); + + iterator_t host_end = find(protocol_end, (path_start != uri_end) ? path_start : query_start, ':'); + + result.asset_url = string(host_start, host_end); + + // port + if ((host_end != uri_end) && ((&*(host_end))[0] == ':')) { // we have a port + host_end++; + iterator_t portEnd = (path_start != uri_end) ? path_start : query_start; + result.port = string(host_end, portEnd); + } + + // URI + if (path_start != uri_end) result.asset_uri = string(path_start, query_start); + + // query + if (query_start != uri_end) result.query_string = string(query_start, uri.end()); + + return result; +} // Parse + +PracticeSection::PracticeSection( + const string &_id, + const string &_type, + const string &_practice_name +) +{ + auto maybe_type = string_to_practice_type.find(_type); + if (maybe_type == string_to_practice_type.end()) { + dbgError(D_K8S_POLICY) << "Illegal pracrtice type: " << _type; + return; + } + + type = _type; + name = _practice_name; + id = _id; +} + +void +PracticeSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("practiceId", id), + cereal::make_nvp("practiceName", name), + cereal::make_nvp("practiceType", type) + ); +} + +const string & +PracticeSection::getPracticeId() const +{ + return id; +} + +const string & +PracticeSection::getPracticeName() const +{ + return name; +} + +ParametersSection::ParametersSection( + const string &_id, + const string &_name) + : + name(_name), + id(_id) +{ + if (_id.empty() && _name.empty()) { + dbgError(D_K8S_POLICY) << "Illegal Parameter values. Name and ID are empty"; + return; + } +} + +void +ParametersSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("parameterId", id), + cereal::make_nvp("parameterName", name), + cereal::make_nvp("parameterType", type) + ); +} + +const string & +ParametersSection::getId() const +{ + return id; +} + +RulesTriggerSection::RulesTriggerSection( + const string &_name, + const string &_id, + const string &_type) + : + name(_name), + id(_id) +{ + if (_name.empty() && _id.empty()) { + dbgError(D_K8S_POLICY) << "Illegal values for trigger. Name and ID are empty"; + return; + } + auto maybe_type = string_to_trigger_type.find(_type); + if (maybe_type == string_to_trigger_type.end()) { + dbgError(D_K8S_POLICY) << "Illegal trigger type in rule: " << _type; + return; + } + type = _type; +} + +void +RulesTriggerSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("triggerId", id), + cereal::make_nvp("triggerName", name), + cereal::make_nvp("triggerType", type) + ); +} + +const string & +RulesTriggerSection::getId() const +{ + return id; +} + +const string & +RulesTriggerSection::getName() const +{ + return id; +} + +RulesConfigRulebase::RulesConfigRulebase( + const string &_name, + const string &_url, + const string &_uri, + vector _practices, + vector _parameters, + vector _triggers) + : + name(_name), + practices(_practices), + parameters(_parameters), + triggers(_triggers) +{ + try { + bool any = _name == "Any" && _url == "Any" && _uri == "Any"; + id = any ? "Any" : _url+_uri; + if (_uri != "/") { + context = any ? "All()" : "Any(" + "All(" + "Any(" + "EqualHost(" + _url + ")" + ")," + "EqualListeningPort(80)" + + string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") + + ")," + "All(" + "Any(" + "EqualHost(" + _url + ")" + ")," + "EqualListeningPort(443)" + + string(_uri.empty() ? "" : ",BeginWithUri(" + _uri + ")") + + ")" + ")"; + } else { + context = any ? "All()" : "Any(" + "All(" + "Any(" + "EqualHost(" + _url + ")" + ")," + "EqualListeningPort(80)" + ")," + "All(" + "Any(" + "EqualHost(" + _url + ")" + ")," + "EqualListeningPort(443)" + ")" + ")"; + } + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_K8S_POLICY) << "Failed to generate rule UUID. Error: " << e.what(); + } +} + +void +RulesConfigRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + string empty_str = ""; + out_ar( + cereal::make_nvp("assetId", id), + cereal::make_nvp("assetName", name), + cereal::make_nvp("ruleId", id), + cereal::make_nvp("ruleName", name), + cereal::make_nvp("context", context), + cereal::make_nvp("priority", 1), + cereal::make_nvp("isCleanup", false), + cereal::make_nvp("parameters", parameters), + cereal::make_nvp("practices", practices), + cereal::make_nvp("triggers", triggers), + cereal::make_nvp("zoneId", empty_str), + cereal::make_nvp("zoneName", empty_str) + ); +} + +const string & +RulesConfigRulebase::getRuleId() const +{ + return id; +} + +const string & +RulesConfigRulebase::getAssetName() const +{ + return name; +} + +const string & +RulesConfigRulebase::getRuleName() const +{ + return name; +} + +const string & +RulesConfigRulebase::getAssetId() const +{ + return id; +} + +const string & +RulesConfigRulebase::getPracticeId() const +{ + return practices[0].getPracticeId(); +} + +const string & +RulesConfigRulebase::getPracticeName() const +{ + return practices[0].getPracticeName(); +} + +const vector & +RulesConfigRulebase::getPractice() const +{ + return practices; +} + +const vector & +RulesConfigRulebase::getParameters() const +{ + return parameters; +} + +const vector & +RulesConfigRulebase::getTriggers() const +{ + return triggers; +} + +RulesConfigWrapper::RulesConfig::RulesConfig(const vector &_rules_config) + : + rules_config(_rules_config) +{ + sort(rules_config.begin(), rules_config.end(), sortBySpecific); +} + +void +RulesConfigWrapper::RulesConfig::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulesConfig", rules_config) + ); +} + +bool +RulesConfigWrapper::RulesConfig::sortBySpecific( + const RulesConfigRulebase &first, + const RulesConfigRulebase &second +) +{ + return sortBySpecificAux(first.getAssetName(), second.getAssetName()); +} + +bool +RulesConfigWrapper::RulesConfig::sortBySpecificAux(const string &first, const string &second) +{ + if (first.empty()) return false; + if (second.empty()) return true; + + AssetUrlParser first_parsed = AssetUrlParser::parse(first); + AssetUrlParser second_parsed = AssetUrlParser::parse(second); + + // sort by URL + if (first_parsed.asset_url == "Any" && second_parsed.asset_url != "Any") return false; + if (second_parsed.asset_url == "Any" && first_parsed.asset_url != "Any") return true; + + // sort by port + if (first_parsed.port == "*" && second_parsed.port != "*") return false; + if (second_parsed.port == "*" && first_parsed.port != "*") return true; + + // sort by URI + if (first_parsed.asset_uri == "*" && second_parsed.asset_uri != "*") return false; + if (second_parsed.asset_uri == "*" && first_parsed.asset_uri != "*") return true; + + if (first_parsed.asset_uri.empty()) return false; + if (second_parsed.asset_uri.empty()) return true; + + if (second_parsed.asset_uri.find(first_parsed.asset_uri) != string::npos) return false; + if (first_parsed.asset_uri.find(second_parsed.asset_uri) != string::npos) return true; + + if (first_parsed.asset_url.empty()) return false; + if (second_parsed.asset_url.empty()) return false; + + return second < first; +} + +void +RulesConfigWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulebase", rules_config_rulebase) + ); +} + +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/settings_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/settings_section.cc new file mode 100644 index 0000000..1dfedf4 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/settings_section.cc @@ -0,0 +1,74 @@ +#include "settings_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_K8S_POLICY); +// LCOV_EXCL_START Reason: no test exist + +AgentSettingsSection::AgentSettingsSection( + const string &_key, + const string &_value) + : + key(_key), + value(_value) +{ + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what(); + } +} + +void +AgentSettingsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("key", key), + cereal::make_nvp("value", value) + ); +} + +const string & +AgentSettingsSection::getSettingId() const +{ + return id; +} + +void +SettingsRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + string profile_type = "Kubernetes"; + string upgrade_mode = "automatic"; + out_ar( + cereal::make_nvp("agentSettings", agentSettings), + cereal::make_nvp("agentType", profile_type), + cereal::make_nvp("allowOnlyDefinedApplications", false), + cereal::make_nvp("anyFog", true), + cereal::make_nvp("maxNumberOfAgents", 10), + cereal::make_nvp("upgradeMode", upgrade_mode) + ); +} + +SettingsWrapper::SettingsWrapper(SettingsRulebase _agent) : agent(_agent) +{ + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_K8S_POLICY) << "Failed to generate Settings Wrapper UUID. Error: " << e.what(); + } +} + +void +SettingsWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("profileType", profileType), + cereal::make_nvp("tokenType", isToken), + cereal::make_nvp("tokenType", tokenType), + cereal::make_nvp("name", name), + cereal::make_nvp("id", id), + cereal::make_nvp("agent", agent) + ); +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/snort_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/snort_section.cc new file mode 100644 index 0000000..ae95987 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/snort_section.cc @@ -0,0 +1,41 @@ +#include "snort_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_K8S_POLICY); +// LCOV_EXCL_START Reason: no test exist + +AgentSettingsSection::AgentSettingsSection(string _key, string _value) : key(_key), value(_value) +{ + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_K8S_POLICY) << "Failed to generate agent setting UUID. Error: " << e.what(); + } +} + +void +AgentSettingsSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("key", key), + cereal::make_nvp("value", value) + ); +} + +void +IpsSnortSigsRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + string profile_type = "KubernetesProfile"; + string upgrade_mode = "automatic"; + out_ar( + cereal::make_nvp("agentSettings", agentSettings), + cereal::make_nvp("agentType", profile_type), + cereal::make_nvp("allowOnlyDefinedApplications", false), + cereal::make_nvp("anyFog", true), + cereal::make_nvp("maxNumberOfAgents", 10), + cereal::make_nvp("upgradeMode", upgrade_mode) + ); +} +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/triggers_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/triggers_section.cc new file mode 100644 index 0000000..91e2076 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/triggers_section.cc @@ -0,0 +1,522 @@ +#include "triggers_section.h" + +using namespace std; + +USE_DEBUG_FLAG(D_K8S_POLICY); +// LCOV_EXCL_START Reason: no test exist + +LogTriggerSection::LogTriggerSection( + const string &_name, + const string &_verbosity, + const string &_extendloggingMinSeverity, + bool _extendlogging, + bool _logToAgent, + bool _logToCef, + bool _logToCloud, + bool _logToSyslog, + bool _responseBody, + bool _tpDetect, + bool _tpPrevent, + bool _webBody, + bool _webHeaders, + bool _webRequests, + bool _webUrlPath, + bool _webUrlQuery, + int _cefPortNum, + const string &_cefIpAddress, + int _syslogPortNum, + const string &_syslogIpAddress, + bool _beautify_logs) + : + name(_name), + verbosity(_verbosity), + extendloggingMinSeverity(_extendloggingMinSeverity), + extendlogging(_extendlogging), + logToAgent(_logToAgent), + logToCef(_logToCef), + logToCloud(_logToCloud), + logToSyslog(_logToSyslog), + responseBody(_responseBody), + tpDetect(_tpDetect), + tpPrevent(_tpPrevent), + webBody(_webBody), + webHeaders(_webHeaders), + webRequests(_webRequests), + webUrlPath(_webUrlPath), + webUrlQuery(_webUrlQuery), + cefPortNum (_cefPortNum), + cefIpAddress (_cefIpAddress), + syslogPortNum (_syslogPortNum), + syslogIpAddress (_syslogIpAddress), + beautify_logs(_beautify_logs) +{ + try { + id = to_string(boost::uuids::random_generator()()); + context = "triggerId(" + id + ")"; + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_K8S_POLICY) << "Failed to generate log trigger UUID. Error: " << e.what(); + } +} + +void +LogTriggerSection::save(cereal::JSONOutputArchive &out_ar) const +{ + string trigger_type = "log"; + string urlForSyslog = syslogIpAddress + ":" + to_string(syslogPortNum); + string urlForCef = cefIpAddress + ":" + to_string(cefPortNum); + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("triggerName", name), + cereal::make_nvp("triggerType", trigger_type), + cereal::make_nvp("verbosity", verbosity), + cereal::make_nvp("acAllow", false), + cereal::make_nvp("acDrop", false), + cereal::make_nvp("complianceViolations", false), + cereal::make_nvp("complianceWarnings", false), + cereal::make_nvp("extendloggingMinSeverity", extendloggingMinSeverity), + cereal::make_nvp("extendlogging", extendlogging), + cereal::make_nvp("logToAgent", logToAgent), + cereal::make_nvp("logToCef", logToCef), + cereal::make_nvp("logToCloud", logToCloud), + cereal::make_nvp("logToSyslog", logToSyslog), + cereal::make_nvp("responseBody", responseBody), + cereal::make_nvp("responseCode", false), + cereal::make_nvp("tpDetect", tpDetect), + cereal::make_nvp("tpPrevent", tpPrevent), + cereal::make_nvp("webBody", webBody), + cereal::make_nvp("webHeaders", webHeaders), + cereal::make_nvp("webRequests", webRequests), + cereal::make_nvp("webUrlPath", webUrlPath), + cereal::make_nvp("webUrlQuery", webUrlQuery), + cereal::make_nvp("urlForSyslog", urlForSyslog), + cereal::make_nvp("urlForCef", urlForCef), + cereal::make_nvp("formatLoggingOutput", beautify_logs) + ); +} + +const string & +LogTriggerSection::getTriggerId() const +{ + return id; +} + +const string & +LogTriggerSection::getTriggerName() const +{ + return name; +} + +bool +LogTriggerSection::operator<(const LogTriggerSection &other) const +{ + return getTriggerName() < other.getTriggerName(); +} + +WebUserResponseTriggerSection::WebUserResponseTriggerSection( + const string &_name, + const string &_details_level, + const string &_response_body, + int _response_code, + const string &_response_title) + : + name(_name), + context(), + details_level(_details_level), + response_body(_response_body), + response_title(_response_title), + response_code(_response_code) +{ + try { + id = to_string(boost::uuids::random_generator()()); + context = "triggerId(" + id + ")"; + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_K8S_POLICY) << "Failed to generate webUserResponse trigger UUID. Error: " << e.what(); + } +} + +void +WebUserResponseTriggerSection::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("context", context), + cereal::make_nvp("triggerName", name), + cereal::make_nvp("details level", details_level), + cereal::make_nvp("response body", response_body), + cereal::make_nvp("response code", response_code), + cereal::make_nvp("response title", response_title) + ); +} + +const string & +WebUserResponseTriggerSection::getTriggerId() const +{ + return id; +} + +const string & +WebUserResponseTriggerSection::getTriggerName() const +{ + return name; +} + +bool +WebUserResponseTriggerSection::operator<(const WebUserResponseTriggerSection &other) const +{ + return getTriggerName() < other.getTriggerName(); +} + +void +AppSecCustomResponseSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec web user response spec"; + parseAppsecJSONKey("http-response-code", httpResponseCode, archive_in, 403); + parseAppsecJSONKey("mode", mode, archive_in, "block-page"); + parseAppsecJSONKey("name", name, archive_in); + if (mode == "block-page") { + parseAppsecJSONKey( + "message-body", + messageBody, + archive_in, + "Openappsec's Application Security has detected an attack and blocked it." + ); + parseAppsecJSONKey( + "message-title", + messageTitle, + archive_in, + "Attack blocked by web application protection" + ); + } +} + +int +AppSecCustomResponseSpec::getHttpResponseCode() const +{ + return httpResponseCode; +} + +const string & +AppSecCustomResponseSpec::getMessageBody() const +{ + return messageBody; +} + +const string & +AppSecCustomResponseSpec::getMessageTitle() const +{ + return messageTitle; +} + +const string & +AppSecCustomResponseSpec::getMode() const +{ + return mode; +} + +const string & +AppSecCustomResponseSpec::getName() const +{ + return name; +} + +void +TriggersRulebase::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("log", logTriggers), + cereal::make_nvp("webUserResponse", webUserResponseTriggers) + ); +} + +void +AppsecTriggerAccessControlLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Access Control Logging"; + parseAppsecJSONKey("allow-events", allow_events, archive_in, false); + parseAppsecJSONKey("drop-events", drop_events, archive_in, false); +} + +bool +AppsecTriggerAccessControlLogging::isAllowEvents() const +{ + return allow_events; +} + +bool +AppsecTriggerAccessControlLogging::isDropEvents() const +{ + return drop_events; +} + +void +AppsecTriggerAdditionalSuspiciousEventsLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger - Additional Suspicious Events Logging"; + parseAppsecJSONKey("enabled", enabled, archive_in, true); + parseAppsecJSONKey("response-body", response_body, archive_in, false); + parseAppsecJSONKey("minimum-severity", minimum_severity, archive_in, "high"); +} + +bool +AppsecTriggerAdditionalSuspiciousEventsLogging::isEnabled() const +{ + return enabled; +} + +bool +AppsecTriggerAdditionalSuspiciousEventsLogging::isResponseBody() const +{ + return response_body; +} + +const string & +AppsecTriggerAdditionalSuspiciousEventsLogging::getMinimumSeverity() const +{ + return minimum_severity; +} + +void +AppsecTriggerLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Logging"; + parseAppsecJSONKey("all-web-requests", all_web_requests, archive_in, false); + parseAppsecJSONKey("detect-events", detect_events, archive_in, false); + parseAppsecJSONKey("prevent-events", prevent_events, archive_in, true); +} + +bool +AppsecTriggerLogging::isAllWebRequests() const +{ + return all_web_requests; +} + +bool +AppsecTriggerLogging::isDetectEvents() const +{ + return detect_events; +} + +bool +AppsecTriggerLogging::isPreventEvents() const +{ + return prevent_events; +} + +void +AppsecTriggerExtendedLogging::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger Extended Logging"; + parseAppsecJSONKey("http-headers", http_headers, archive_in, false); + parseAppsecJSONKey("request-body", request_body, archive_in, false); + parseAppsecJSONKey("url-path", url_path, archive_in, false); + parseAppsecJSONKey("url-query", url_query, archive_in, false); +} + +bool +AppsecTriggerExtendedLogging::isHttpHeaders() const +{ + return http_headers; +} + +bool +AppsecTriggerExtendedLogging::isRequestBody() const +{ + return request_body; +} + +bool +AppsecTriggerExtendedLogging::isUrlPath() const +{ + return url_path; +} + +bool +AppsecTriggerExtendedLogging::isUrlQuery() const +{ + return url_query; +} + +void +LoggingService::load(cereal::JSONInputArchive &archive_in) +{ + parseAppsecJSONKey("address", address, archive_in); + parseAppsecJSONKey("proto", proto, archive_in); + parseAppsecJSONKey("port", port, archive_in, 514); +} + +const string & +LoggingService::getAddress() const +{ + return address; +} + +const string & +LoggingService::getProto() const +{ + return proto; +} + +int +LoggingService::getPort() const +{ + return port; +} + + +void +StdoutLogging::load(cereal::JSONInputArchive &archive_in) +{ + parseAppsecJSONKey("format", format, archive_in, "json"); +} + +const string & +StdoutLogging::getFormat() const +{ + return format; +} + +void +AppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec Trigger LogDestination"; + // TBD: support "file" + parseAppsecJSONKey("cloud", cloud, archive_in, false); + + StdoutLogging stdout_log; + parseAppsecJSONKey("stdout", stdout_log, archive_in); + agent_local = !(stdout_log.getFormat().empty()); + beautify_logs = stdout_log.getFormat() == "json-formatted"; + parseAppsecJSONKey("syslog-service", syslog_service, archive_in); + parseAppsecJSONKey("cef-service", cef_service, archive_in); +} + +int +AppsecTriggerLogDestination::getCefServerUdpPort() const +{ + return getCefServiceData().getPort(); +} + +int +AppsecTriggerLogDestination::getSyslogServerUdpPort() const +{ + return getSyslogServiceData().getPort(); +} + +bool +AppsecTriggerLogDestination::isAgentLocal() const +{ + return agent_local; +} + +bool +AppsecTriggerLogDestination::shouldBeautifyLogs() const +{ + return beautify_logs; +} + +bool +AppsecTriggerLogDestination::getCloud() const +{ + return cloud; +} + +bool +AppsecTriggerLogDestination::isCefNeeded() const +{ + return !getCefServiceData().getAddress().empty(); +} + +bool +AppsecTriggerLogDestination::isSyslogNeeded() const +{ + return !getSyslogServiceData().getAddress().empty(); +} + +const +string & AppsecTriggerLogDestination::getSyslogServerIpv4Address() const +{ + return getSyslogServiceData().getAddress(); +} + +const string & +AppsecTriggerLogDestination::getCefServerIpv4Address() const +{ + return getCefServiceData().getAddress(); +} + +const LoggingService & +AppsecTriggerLogDestination::getSyslogServiceData() const +{ + return syslog_service; +} + +const LoggingService & +AppsecTriggerLogDestination::getCefServiceData() const +{ + return cef_service; +} + +void +AppsecTriggerSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading AppSec trigger spec"; + parseAppsecJSONKey( + "access-control-logging", + access_control_logging, + archive_in + ); + parseAppsecJSONKey( + "additional-suspicious-events-logging", + additional_suspicious_events_logging, + archive_in + ); + parseAppsecJSONKey("appsec-logging", appsec_logging, archive_in); + parseAppsecJSONKey("extended-logging", extended_logging, archive_in); + parseAppsecJSONKey("log-destination", log_destination, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +const AppsecTriggerAccessControlLogging & +AppsecTriggerSpec::getAppsecTriggerAccessControlLogging() const +{ + return access_control_logging; +} + +const string & +AppsecTriggerSpec::getName() const +{ + return name; +} + +const AppsecTriggerAdditionalSuspiciousEventsLogging & +AppsecTriggerSpec::getAppsecTriggerAdditionalSuspiciousEventsLogging() const +{ + return additional_suspicious_events_logging; +} + +const AppsecTriggerLogging & +AppsecTriggerSpec::getAppsecTriggerLogging() const +{ + return appsec_logging; +} + +const AppsecTriggerExtendedLogging & +AppsecTriggerSpec::getAppsecTriggerExtendedLogging() const +{ + return extended_logging; +} + +const AppsecTriggerLogDestination & +AppsecTriggerSpec::getAppsecTriggerLogDestination() const +{ + return log_destination; +} + +void +TriggersWrapper::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("rulebase", triggers_rulebase) + ); +} + +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/local_policy_mgmt_gen/trusted_sources_section.cc b/components/security_apps/orchestration/local_policy_mgmt_gen/trusted_sources_section.cc new file mode 100644 index 0000000..e553023 --- /dev/null +++ b/components/security_apps/orchestration/local_policy_mgmt_gen/trusted_sources_section.cc @@ -0,0 +1,125 @@ +#include "policy_maker_utils.h" + +using namespace std; + +USE_DEBUG_FLAG(D_K8S_POLICY); +// LCOV_EXCL_START Reason: no test exist + +void +TrustedSourcesSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec"; + parseAppsecJSONKey("minNumOfSources", min_num_of_sources, archive_in, 3); + parseAppsecJSONKey>("sourcesIdentifiers", sources_identifiers, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +int +TrustedSourcesSpec::getMinNumOfSources() const +{ + return min_num_of_sources; +} + +const vector & +TrustedSourcesSpec::getSourcesIdentifiers() const +{ + return sources_identifiers; +} + +const string & +TrustedSourcesSpec::getName() const +{ + return name; +} + +void +SourcesIdentifiers::save(cereal::JSONOutputArchive &out_ar) const +{ + out_ar( + cereal::make_nvp("sourceIdentifier", source_identifier), + cereal::make_nvp("value", value) + ); +} + +const string & +SourcesIdentifiers::getSourceIdent() const +{ + return source_identifier; +} + +void +SourceIdentifierSpec::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading trusted sources spec"; + parseAppsecJSONKey("sourceIdentifier", source_identifier, archive_in); + parseAppsecJSONKey>("value", value, archive_in); +} + +const string & +SourceIdentifierSpec::getSourceIdentifier() const +{ + return source_identifier; +} + +const vector & +SourceIdentifierSpec::getValues() const +{ + return value; +} + +void +SourceIdentifierSpecWrapper::load(cereal::JSONInputArchive &archive_in) +{ + dbgTrace(D_K8S_POLICY) << "Loading Source Identifier Spec Wrapper"; + parseAppsecJSONKey>("identifiers", identifiers, archive_in); + parseAppsecJSONKey("name", name, archive_in); +} + +const string & +SourceIdentifierSpecWrapper::getName() const +{ + return name; +} + +const vector & +SourceIdentifierSpecWrapper::getIdentifiers() const +{ + return identifiers; +} + +AppSecTrustedSources::AppSecTrustedSources( + const string &_name, + int _num_of_sources, + const vector &_sources_identifiers) + : + name(_name), + num_of_sources(_num_of_sources), + sources_identifiers(_sources_identifiers) +{ + try { + id = to_string(boost::uuids::random_generator()()); + } catch (const boost::uuids::entropy_error &e) { + dbgWarning(D_K8S_POLICY) << "Failed to generate Trusted Sources ID. Error: " << e.what(); + } +} + +void +AppSecTrustedSources::save(cereal::JSONOutputArchive &out_ar) const +{ + string parameter_type = "TrustedSource"; + out_ar( + cereal::make_nvp("id", id), + cereal::make_nvp("name", name), + cereal::make_nvp("numOfSources", num_of_sources), + cereal::make_nvp("sourcesIdentifiers", sources_identifiers), + cereal::make_nvp("parameterType", parameter_type) + ); +} + +const vector & +AppSecTrustedSources::getSourcesIdentifiers() const +{ + return sources_identifiers; +} + +// LCOV_EXCL_STOP diff --git a/components/security_apps/orchestration/modules/orchestration_status.cc b/components/security_apps/orchestration/modules/orchestration_status.cc index d0f3039..6a08d93 100755 --- a/components/security_apps/orchestration/modules/orchestration_status.cc +++ b/components/security_apps/orchestration/modules/orchestration_status.cc @@ -389,17 +389,17 @@ public: void writeStatusToFile() { - auto orchestrations_status_path = getConfigurationWithDefault( - filesystem_prefix + "/conf/orchestrations_status.json", + auto orchestration_status_path = getConfigurationWithDefault( + filesystem_prefix + "/conf/orchestration_status.json", "orchestration", "Orchestration status path" ); auto write_result = - orchestration_tools->objectToJsonFile(status, orchestrations_status_path); + orchestration_tools->objectToJsonFile(status, orchestration_status_path); if (!write_result) { - dbgWarning(D_ORCHESTRATOR) << "Failed to write Orchestration status. File: " << orchestrations_status_path; + dbgWarning(D_ORCHESTRATOR) << "Failed to write Orchestration status. File: " << orchestration_status_path; } - dbgTrace(D_ORCHESTRATOR) << "Orchestration status file has been updated. File: " << orchestrations_status_path; + dbgTrace(D_ORCHESTRATOR) << "Orchestration status file has been updated. File: " << orchestration_status_path; } void @@ -440,10 +440,10 @@ public: { time = Singleton::Consume::by(); orchestration_tools = Singleton::Consume::by(); + filesystem_prefix = getFilesystemPathConfig(); initValues(); loadFromFile(); - filesystem_prefix = getFilesystemPathConfig(); dbgTrace(D_ORCHESTRATOR) << "Initializing Orchestration status, file system path prefix: " << filesystem_prefix; @@ -473,13 +473,13 @@ private: void loadFromFile() { - auto orchestrations_status_path = getConfigurationWithDefault( - filesystem_prefix + "/conf/orchestrations_status.json", + auto orchestration_status_path = getConfigurationWithDefault( + filesystem_prefix + "/conf/orchestration_status.json", "orchestration", "Orchestration status path" ); Maybe maybe_status_file = - orchestration_tools->jsonFileToObject(orchestrations_status_path); + orchestration_tools->jsonFileToObject(orchestration_status_path); if (!maybe_status_file.ok()) { dbgTrace(D_ORCHESTRATOR) << "Failed to load Orchestration status, start with clear status." @@ -489,7 +489,7 @@ private: status = maybe_status_file.unpack(); - dbgInfo(D_ORCHESTRATOR) << "Orchestration status loaded from file." << " File: " << orchestrations_status_path; + dbgInfo(D_ORCHESTRATOR) << "Orchestration status loaded from file." << " File: " << orchestration_status_path; } const string & getLastUpdateAttempt() const override { return status.getLastUpdateAttempt(); } diff --git a/components/security_apps/orchestration/orchestration_comp.cc b/components/security_apps/orchestration/orchestration_comp.cc index a30094f..95f5859 100755 --- a/components/security_apps/orchestration/orchestration_comp.cc +++ b/components/security_apps/orchestration/orchestration_comp.cc @@ -124,6 +124,29 @@ private: map field_types_status; }; +class setAgentUninstall : public ServerRest +{ +public: + void + doCall() override + { + dbgTrace(D_ORCHESTRATOR) << "Send 'agent uninstall process started' log to fog"; + setConfiguration(false, "Logging", "Enable bulk of logs"); + LogGen log ( + "Agent started uninstall process", + Audience::INTERNAL, + Severity::INFO, + Priority::URGENT, + LogField("issuingEngine", "agentUninstallProvider"), + Tags::ORCHESTRATOR + ); + notify_uninstall_to_fog = true; + } + +private: + S2C_PARAM(bool, notify_uninstall_to_fog); +}; + class OrchestrationComp::Impl { public: @@ -144,6 +167,7 @@ public: auto rest = Singleton::Consume::by(); rest->addRestCall(RestAction::SHOW, "orchestration-status"); rest->addRestCall(RestAction::ADD, "proxy"); + rest->addRestCall(RestAction::SET, "agent-uninstall"); // Main loop of the Orchestration. Singleton::Consume::by()->addOneTimeRoutine( I_MainLoop::RoutineType::RealTime, @@ -982,7 +1006,7 @@ private: const Maybe> &updated_policy_tenants, const vector &new_data_files) { - dbgFlow(D_ORCHESTRATOR) << "Hanlding virtual files"; + dbgFlow(D_ORCHESTRATOR) << "Handling virtual files"; if (!updated_policy_tenants.ok()) return; // Sorting files by tenant id; @@ -1053,26 +1077,31 @@ private: } } - for (const auto downloade_files: sorted_files) { - auto files = downloade_files.second; + for (auto it = sorted_files.begin(); it != sorted_files.end(); it++) { + const auto &downloaded_files = *it; + auto files = downloaded_files.second; string policy_file = files[0]; string setting_file = ""; if (files.size() > 1) { setting_file = files[1]; auto handled_settings = updateSettingsFile( setting_file, - downloade_files.first.getTenantId(), - downloade_files.first.getPfofileId() + downloaded_files.first.getTenantId(), + downloaded_files.first.getProfileId() ); if (handled_settings.ok()) setting_file = *handled_settings; } + bool last_iteration = false; + if (next(it) == sorted_files.end()) last_iteration = true; + Singleton::Consume::by()->updateServiceConfiguration( policy_file, setting_file, new_data_files, - downloade_files.first.getTenantId(), - downloade_files.first.getPfofileId() + downloaded_files.first.getTenantId(), + downloaded_files.first.getProfileId(), + last_iteration ); } } @@ -1087,9 +1116,9 @@ private: "Conf dir" ) + (tenant_id != "" ? "tenant_" + tenant_id + "_profile_" + profile_id + "_" : ""); - dbgTrace(D_ORCHESTRATOR) << "The settings directory is " << conf_dir; auto orchestration_tools = Singleton::Consume::by(); string settings_file_path = conf_dir + "settings.json"; + dbgTrace(D_ORCHESTRATOR) << "The settings directory is " << settings_file_path; if (!orchestration_tools->copyFile(new_settings_file, settings_file_path)) { dbgWarning(D_ORCHESTRATOR) << "Failed to update the settings."; return genError("Failed to update the settings"); @@ -1278,7 +1307,7 @@ private: int sleep_interval = policy.getErrorSleepInterval(); Maybe start_state(genError("Not running yet.")); while (!(start_state = start()).ok()) { - dbgError(D_ORCHESTRATOR) << "Failed to start the Orchestration. Error: " << start_state.getErr(); + dbgDebug(D_ORCHESTRATOR) << "Orchestration not started yet. Status: " << start_state.getErr(); health_check_status_listener.setStatus( HealthCheckStatus::UNHEALTHY, OrchestrationStatusFieldType::REGISTRATION, diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc index f5f1ed9..eca3c5a 100644 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_multitenant_ut.cc @@ -65,7 +65,12 @@ public: EXPECT_CALL(rest, mockRestCall(RestAction::SHOW, "orchestration-status", _)).WillOnce( WithArg<2>(Invoke(this, &OrchestrationMultitenancyTest::setRestStatus))); - + + EXPECT_CALL( + rest, + mockRestCall(RestAction::SET, "agent-uninstall", _) + ).WillOnce(Return(true)); + doEncrypt(); orchestration_comp.init(); } @@ -417,7 +422,8 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource) "/etc/cp/conf/settings.json", expected_data_types, "", - "" + "", + false ) ).WillOnce(Return(true)); @@ -428,7 +434,8 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource) "/etc/cp/conf/tenant_1236_profile_2611_settings.json", expected_data_types, "1236", - "2611" + "2611", + false ) ).WillOnce(Return(true)); @@ -439,7 +446,8 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource) "/etc/cp/conf/tenant_1235_profile_2311_settings.json", expected_data_types, "1235", - "2311" + "2311", + true ) ).WillOnce(Return(true)); diff --git a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc index 2973116..daf9d2a 100755 --- a/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc +++ b/components/security_apps/orchestration/orchestration_ut/orchestration_ut.cc @@ -79,6 +79,11 @@ public: WithArg<2>(Invoke(this, &OrchestrationTest::setRestStatus)) ); + EXPECT_CALL( + rest, + mockRestCall(RestAction::SET, "agent-uninstall", _) + ).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandlerAgentUninstall))); + string message_body; EXPECT_CALL(mock_message, mockSendPersistentMessage( false, @@ -101,6 +106,12 @@ public: return true; } + bool + restHandlerAgentUninstall(const unique_ptr &p) + { + agent_uninstall = p->getRest(); + return true; + } void doEncrypt() @@ -249,6 +260,7 @@ public: } unique_ptr rest_handler; + unique_ptr agent_uninstall; unique_ptr declare_variable; StrictMock mock_ml; NiceMock mock_time_get; @@ -295,8 +307,36 @@ private: I_MainLoop::Routine status_routine; }; -TEST_F(OrchestrationTest, doNothing) +TEST_F(OrchestrationTest, testAgentUninstallRest) { + EXPECT_CALL( + rest, + mockRestCall(RestAction::ADD, "proxy", _) + ).WillOnce(WithArg<2>(Invoke(this, &OrchestrationTest::restHandler))); + + init(); + + Report report; + EXPECT_CALL(mock_log, sendLog(_)).WillRepeatedly(SaveArg<0>(&report)); + + stringstream ss("{}"); + Maybe maybe_res = agent_uninstall->performRestCall(ss); + EXPECT_TRUE(maybe_res.ok()); + EXPECT_EQ(maybe_res.unpack(), + "{\n" + " \"notify_uninstall_to_fog\": true\n" + "}" + ); + + stringstream report_ss; + { + cereal::JSONOutputArchive ar(report_ss); + report.serialize(ar); + } + + string report_str = report_ss.str(); + EXPECT_THAT(report_str, HasSubstr("\"eventName\": \"Agent started uninstall process\"")); + EXPECT_THAT(report_str, HasSubstr("\"issuingEngine\": \"agentUninstallProvider\"")); } TEST_F(OrchestrationTest, register_config) @@ -530,12 +570,12 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate) vector expected_data_types = {}; EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "") + updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) ).WillOnce(Return(true)); EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "") + updateServiceConfiguration(new_policy_path, "", expected_data_types, "", "", _) ).WillOnce(Return(true)); EXPECT_CALL( @@ -633,7 +673,7 @@ TEST_F(OrchestrationTest, startOrchestrationPoliceWithFailures) vector expected_data_types = {}; EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "") + updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) ).Times(2).WillRepeatedly(Return(true)); EXPECT_CALL(mock_message, setActiveFog(host_address, 443, true, MessageTypeTag::GENERIC)).WillOnce(Return(true)); @@ -753,7 +793,7 @@ TEST_F(OrchestrationTest, loadOrchestrationPolicyFromBackup) vector expected_data_types = {}; EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "") + updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) ).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true)); @@ -887,7 +927,7 @@ TEST_F(OrchestrationTest, manifestUpdate) vector expected_data_types = {}; EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "") + updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) ).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true)); @@ -1037,7 +1077,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate) vector expected_data_types = {}; EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "") + updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) ).Times(2).WillRepeatedly(Return(true)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true)); @@ -1118,7 +1158,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate) EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "")).WillOnce(Return(false) + updateServiceConfiguration(string("policy path"), "", expected_data_types, "", "", _)).WillOnce(Return(false) ); EXPECT_CALL(mock_ml, yield(A())) @@ -1183,7 +1223,7 @@ TEST_F(OrchestrationTest, failedDownloadSettings) vector expected_data_types = {}; EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "") + updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) ).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true)); @@ -1401,7 +1441,7 @@ TEST_P(OrchestrationTest, orchestrationFirstRun) vector expected_data_types = {}; EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "") + updateServiceConfiguration(policy_file_path, setting_file_path, expected_data_types, "", "", _) ).WillOnce(Return(true)); EXPECT_CALL(mock_ml, yield(A())) @@ -1582,13 +1622,13 @@ TEST_F(OrchestrationTest, dataUpdate) vector expected_empty_data_types = {}; ExpectationSet expectation_set = EXPECT_CALL( mock_service_controller, - updateServiceConfiguration(policy_file_path, setting_file_path, expected_empty_data_types, "", "") + updateServiceConfiguration(policy_file_path, setting_file_path, expected_empty_data_types, "", "", _) ).WillOnce(Return(true)); vector expected_ips_data_types = { "ips" }; EXPECT_CALL( mock_service_controller, - updateServiceConfiguration("", "", expected_ips_data_types, "", "") + updateServiceConfiguration("", "", expected_ips_data_types, "", "", _) ).After(expectation_set).WillOnce(Return(true)); EXPECT_CALL(mock_orchestration_tools, doesDirectoryExist("/etc/cp/conf/data")).WillOnce(Return(true)); diff --git a/components/security_apps/orchestration/service_controller/service_controller.cc b/components/security_apps/orchestration/service_controller/service_controller.cc index b181aba..d880d9e 100755 --- a/components/security_apps/orchestration/service_controller/service_controller.cc +++ b/components/security_apps/orchestration/service_controller/service_controller.cc @@ -272,7 +272,8 @@ public: const string &new_settings_path, const vector &new_data_files, const string &tenant_id, - const string &profile_id + const string &profile_id, + const bool last_iteration ) override; bool isServiceInstalled(const string &service_name) override; @@ -325,6 +326,7 @@ private: map services_reconf_names; map services_reconf_ids; string filesystem_prefix; + bool is_multi_tenant_env = false; }; class GetServicesPorts : public ServerRest @@ -412,6 +414,11 @@ ServiceController::Impl::init() filesystem_prefix = getFilesystemPathConfig(); loadRegisteredServicesFromFile(); + + auto agent_type = getSetting("agentType"); + if (agent_type.ok() && (*agent_type == "CloudNative" || *agent_type == "VirtualNSaaS")) { + is_multi_tenant_env = true; + } } void @@ -592,7 +599,8 @@ ServiceController::Impl::updateServiceConfiguration( const string &new_settings_path, const vector &new_data_files, const string &tenant_id, - const string &profile_id) + const string &profile_id, + const bool last_iteration) { dbgFlow(D_ORCHESTRATOR) << "new_policy_path: " @@ -746,7 +754,10 @@ ServiceController::Impl::updateServiceConfiguration( } } - was_policy_updated &= sendSignalForServices(nano_services_to_update, version_value); + // In a multi-tenant env, we send the signal to the services only on the last iteration + was_policy_updated &= (is_multi_tenant_env && !last_iteration) ? + true : + sendSignalForServices(nano_services_to_update, version_value); dbgTrace(D_ORCHESTRATOR) << "was_policy_updated: " << (was_policy_updated ? "true" : "false"); @@ -965,6 +976,11 @@ ServiceController::Impl::updateReconfStatus(int id, ReconfStatus status) dbgError(D_ORCHESTRATOR) << "Service reconfiguration monitor received illegal id :" << id; return; } + dbgTrace(D_ORCHESTRATOR) + << "Updating reconf status for reconfiguration ID " + << id + << ". Status: " + << static_cast(status); services_reconf_status[id] = status; } @@ -975,6 +991,15 @@ ServiceController::Impl::startReconfStatus( const string &service_name, const string &service_id) { + dbgTrace(D_ORCHESTRATOR) + << "Starting reconf status. Configuration ID: " + << id + << ", service name: " + << service_name + << ", service ID: " + << service_id + << ", status: " + << static_cast(status); services_reconf_status.emplace(id, status); services_reconf_names.emplace(id, service_name); services_reconf_ids.emplace(id, service_id); diff --git a/components/security_apps/orchestration/update_communication/local_communication.cc b/components/security_apps/orchestration/update_communication/local_communication.cc index bf739e6..77cab09 100755 --- a/components/security_apps/orchestration/update_communication/local_communication.cc +++ b/components/security_apps/orchestration/update_communication/local_communication.cc @@ -122,9 +122,9 @@ LocalCommunication::getUpdate(CheckUpdateRequest &request) } Maybe -LocalCommunication::downloadAttributeFile(const GetResourceFile &resourse_file) +LocalCommunication::downloadAttributeFile(const GetResourceFile &resource_file) { - auto file_name = resourse_file.getFileName(); + auto file_name = resource_file.getFileName(); I_OrchestrationTools *orchestration_tools = Singleton::Consume::by(); if (file_name.compare("policy") == 0) { @@ -163,8 +163,8 @@ LocalCommunication::downloadAttributeFile(const GetResourceFile &resourse_file) )); } - dbgError(D_ORCHESTRATOR) << "Unknown resourse file name " << file_name; - return genError("Failed to detect resourse file name " + file_name); + dbgError(D_ORCHESTRATOR) << "Unknown resource file name " << file_name; + return genError("Failed to detect resource file name " + file_name); } void diff --git a/components/security_apps/waap/include/i_serialize.h b/components/security_apps/waap/include/i_serialize.h index 6c45808..d47e07d 100755 --- a/components/security_apps/waap/include/i_serialize.h +++ b/components/security_apps/waap/include/i_serialize.h @@ -191,7 +191,7 @@ protected: dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i; mainloop->yield(true); } - dbgError(D_WAAP) << "Failed to send object, reached maximum attempts: " << + dbgError(D_WAAP) << "Failed to send object to " << uri << ", reached maximum attempts: " << max_send_obj_retries; return false; } @@ -245,7 +245,7 @@ protected: dbgWarning(D_WAAP) << "Failed to send object. Attempt: " << i; mainloop->yield(true); } - dbgError(D_WAAP) << "Failed to send object, reached maximum attempts: " << + dbgError(D_WAAP) << "Failed to send object to " << uri << ", reached maximum attempts: " << max_send_obj_retries; return false; } diff --git a/components/security_apps/waap/reputation/reputation_features_agg.cc b/components/security_apps/waap/reputation/reputation_features_agg.cc index daed4af..747ddf4 100755 --- a/components/security_apps/waap/reputation/reputation_features_agg.cc +++ b/components/security_apps/waap/reputation/reputation_features_agg.cc @@ -129,17 +129,29 @@ SourceReputationFeaturesAgg::addHeaders(const ReputationFeaturesEntry &entry) } const auto &referer_header_itr = headers.find("referer"); - if (referer_header_itr == headers.cend()) { + if (referer_header_itr == headers.cend() || referer_header_itr->second.empty()) { m_referer_count.na++; } else { const string &uri = referer_header_itr->second; - size_t scheme_end_pos = uri.find("://") + 3; - size_t authority_end_pos = uri.find("/", scheme_end_pos + 1); - string authority = uri.substr(scheme_end_pos + 1, authority_end_pos); - if (authority.find(entry.getHost()) != string::npos) { - m_referer_count.external_host++; + size_t scheme_end_pos = uri.find("://"); + if (scheme_end_pos != string::npos) { + string authority; + scheme_end_pos = scheme_end_pos + 3; + size_t authority_end_pos = uri.find("/", scheme_end_pos); + if (authority_end_pos == string::npos) { + authority = uri.substr(scheme_end_pos); + } else { + authority = uri.substr(scheme_end_pos, authority_end_pos - scheme_end_pos); + } + + if (authority.find(entry.getHost()) != string::npos) { + m_referer_count.internal_host++; + } else { + m_referer_count.external_host++; + } } else { - m_referer_count.internal_host++; + m_referer_count.external_host++; + dbgTrace(D_WAAP_REPUTATION) << "No scheme found in referer header: " << uri; } } diff --git a/components/security_apps/waap/waap_clib/CMakeLists.txt b/components/security_apps/waap/waap_clib/CMakeLists.txt index c1f1ff3..ae1196f 100755 --- a/components/security_apps/waap/waap_clib/CMakeLists.txt +++ b/components/security_apps/waap/waap_clib/CMakeLists.txt @@ -82,6 +82,7 @@ add_library(waap_clib SyncLearningNotification.cc LogGenWrapper.cc WaapSampleValue.cc + ParserGql.cc ) add_definitions("-Wno-unused-function") diff --git a/components/security_apps/waap/waap_clib/DeepParser.cc b/components/security_apps/waap/waap_clib/DeepParser.cc index 6861201..331c2e4 100755 --- a/components/security_apps/waap/waap_clib/DeepParser.cc +++ b/components/security_apps/waap/waap_clib/DeepParser.cc @@ -17,6 +17,7 @@ #include "ParserUrlEncode.h" #include "PHPSerializedDataParser.h" #include "ParserJson.h" +#include "ParserGql.h" #include "ParserConfluence.h" #include "ParserXML.h" #include "ParserHTML.h" @@ -231,26 +232,30 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i bool base64ParamFound = false; dbgTrace(D_WAAP_DEEP_PARSER) << " ===Processing potential base64==="; - std::string base64_decoded_val, base64_key; + std::string decoded_val, key; base64_variants base64_status = Waap::Util::b64Test (cur_val, - base64_key, - base64_decoded_val); + key, + decoded_val); - dbgTrace(D_WAAP_DEEP_PARSER) << " status = " << base64_status - << " key = " << base64_key - << " value = " << base64_decoded_val; + dbgTrace(D_WAAP_DEEP_PARSER) + << " status = " + << base64_status + << " key = " + << key + << " value = " + << decoded_val; switch (base64_status) { case SINGLE_B64_CHUNK_CONVERT: - cur_val = base64_decoded_val; + cur_val = decoded_val; base64ParamFound = true; break; case KEY_VALUE_B64_PAIR: // going deep with new pair in case value is not empty - if (base64_decoded_val.size() > 0) { - cur_val = base64_decoded_val; + if (decoded_val.size() > 0) { + cur_val = decoded_val; base64ParamFound = true; - rc = onKv(base64_key.c_str(), base64_key.size(), cur_val.data(), cur_val.size(), flags); + rc = onKv(key.c_str(), key.size(), cur_val.data(), cur_val.size(), flags); dbgTrace(D_WAAP_DEEP_PARSER) << " rc = " << rc; if (rc != CONTINUE_PARSING) { return rc; @@ -323,6 +328,7 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i } } + // Parse buffer // Note: API report does not include output of "PIPE" and similar extracted stuff. @@ -365,6 +371,21 @@ int DeepParser::onKv(const char* k, size_t k_len, const char* v, size_t v_len, i return rc; } + if (Waap::Util::detectJSONasParameter(cur_val, key, decoded_val)) { + dbgTrace(D_WAAP_DEEP_PARSER) + << " detectJSONasParameter was true: key = " + << key + << " value = " + << decoded_val; + + rc = onKv(key.c_str(), key.size(), decoded_val.data(), decoded_val.size(), flags); + + dbgTrace(D_WAAP_DEEP_PARSER) << " After processing potential JSON rc = " << rc; + if (rc != CONTINUE_PARSING) { + return rc; + } + } + m_depth--; // Send key/value pair to the Signature scanner @@ -878,6 +899,11 @@ void DeepParser::createInternalParser(const char *k, size_t k_len, std::string& dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse phpSerializedData"; m_parsersDeque.push_front(std::make_shared>(*this)); } + else if (isPotentialGqlQuery && cur_val.size() > 0 && !validateJson(cur_val.data(), cur_val.size())) { + // Graphql value detected + dbgTrace(D_WAAP_DEEP_PARSER) << "Starting to parse graphql"; + m_parsersDeque.push_front(std::make_shared>(*this)); + } else if (cur_val.length() > 0 && (cur_val[0] == '[' || cur_val[0] == '{')) { boost::smatch confulence_match; diff --git a/components/security_apps/waap/waap_clib/IndicatorsFiltersManager.cc b/components/security_apps/waap/waap_clib/IndicatorsFiltersManager.cc index 4327044..27b0acc 100755 --- a/components/security_apps/waap/waap_clib/IndicatorsFiltersManager.cc +++ b/components/security_apps/waap/waap_clib/IndicatorsFiltersManager.cc @@ -25,7 +25,8 @@ IndicatorsFiltersManager::IndicatorsFiltersManager(const std::string& remotePath : SerializeToFileBase(pWaapAssetState->getWaapDataDir() + "/6.data"), m_ignoreSources(pWaapAssetState->getWaapDataDir(), remotePath, assetId), - m_tuning(remotePath) + m_tuning(remotePath), + m_matchedOverrideKeywords() { restore(); m_keywordsFreqFilter = std::make_unique( @@ -88,6 +89,12 @@ bool IndicatorsFiltersManager::shouldFilterKeyword(const std::string &key, const shouldFilter |= m_keywordsFreqFilter->shouldFilterKeyword(type, keyword); } } + if (m_matchedOverrideKeywords.size() > 0 && + m_matchedOverrideKeywords.find(keyword) != m_matchedOverrideKeywords.end()) + { + dbgTrace(D_WAAP_OVERRIDE) << "Filtering keyword '" << keyword << "' due to override"; + shouldFilter = true; + } return shouldFilter; } @@ -315,3 +322,8 @@ void IndicatorsFiltersManager::pushSample( } m_typeFilter->registerKeywords(key, sample, pTransaction); } + +std::set & IndicatorsFiltersManager::getMatchedOverrideKeywords(void) +{ + return m_matchedOverrideKeywords; +} diff --git a/components/security_apps/waap/waap_clib/IndicatorsFiltersManager.h b/components/security_apps/waap/waap_clib/IndicatorsFiltersManager.h index 073430f..e83733f 100755 --- a/components/security_apps/waap/waap_clib/IndicatorsFiltersManager.h +++ b/components/security_apps/waap/waap_clib/IndicatorsFiltersManager.h @@ -42,6 +42,7 @@ public: virtual bool shouldFilterKeyword(const std::string &key, const std::string &keyword) const; virtual void filterKeywords(const std::string &key, Waap::Keywords::KeywordsSet& keywords, std::vector& filteredKeywords); + std::set &getMatchedOverrideKeywords(void); void pushSample(const std::string& key, const std::string& sample, IWaf2Transaction* pTransaction); @@ -67,4 +68,5 @@ private: std::shared_ptr m_trustedSrcParams; ScannerDetector m_ignoreSources; TuningDecision m_tuning; + std::set m_matchedOverrideKeywords; }; diff --git a/components/security_apps/waap/waap_clib/ParserBase.h b/components/security_apps/waap/waap_clib/ParserBase.h index d64679b..d49b3cd 100755 --- a/components/security_apps/waap/waap_clib/ParserBase.h +++ b/components/security_apps/waap/waap_clib/ParserBase.h @@ -43,6 +43,7 @@ struct IParserReceiver2 { virtual void onEndMap() = 0; virtual void onStartArray() = 0; virtual void onEndArray() = 0; + virtual void onEndOfData() = 0; }; // Interface for receiver classes that can accept not only full key/value pairs, but also partial content diff --git a/components/security_apps/waap/waap_clib/ParserGql.cc b/components/security_apps/waap/waap_clib/ParserGql.cc new file mode 100644 index 0000000..294cfba --- /dev/null +++ b/components/security_apps/waap/waap_clib/ParserGql.cc @@ -0,0 +1,134 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (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 "ParserGql.h" +#include "graphqlparser/AstNode.h" +#include "graphqlparser/AstVisitor.h" +#include "graphqlparser/GraphQLParser.h" +#include "debug.h" + +USE_DEBUG_FLAG(D_WAAP_PARSER_GQL); + +const std::string ParserGql::m_parserName = "gqlParser"; + +ParserGql::ParserGql(IParserReceiver& receiver) : + m_receiver(receiver), + m_error(false), + m_curNameValues(0) +{ + dbgFlow(D_WAAP_PARSER_GQL); +} + +ParserGql::~ParserGql() { + dbgFlow(D_WAAP_PARSER_GQL); +} + +size_t ParserGql::push(const char* buf, size_t len) { + dbgTrace(D_WAAP_PARSER_GQL) << "buf='" << std::string(buf, len) << "'"; + if (len > 0) { + dbgTrace(D_WAAP_PARSER_GQL) << "appending " << len << " bytes ..."; + m_buffer.append(buf, len); + return len; + } + + const char *errorstr = nullptr; + dbgTrace(D_WAAP_PARSER_GQL) << "parsing ..."; + std::unique_ptr ast = facebook::graphql::parseString(m_buffer.c_str(), &errorstr); + if (!ast) { + dbgTrace(D_WAAP_PARSER_GQL) << "GraphQL parser failed: " << errorstr; + m_error = true; + return 0; + } + + // Walk over AST and call the visitXXX callbacks + ast->accept(this); + + // Handle corner case of last name visited without value: don't forget to output that name too + if (m_curNameValues == 0 && !m_curNodeName.empty()) { + dbgTrace(D_WAAP_PARSER_GQL) << "handle last name: '" << m_curNodeName << "'"; + if (m_receiver.onKv(m_curNodeName.data(), m_curNodeName.size(), "", 0, BUFFERED_RECEIVER_F_BOTH) != 0) { + m_error = true; + } + } + + return len; +} + +void ParserGql::finish() { + push(NULL, 0); +} + +const std::string & +ParserGql::name() const { + return m_parserName; +} + +bool ParserGql::error() const { + return m_error; +} + +bool ParserGql::visitValue(const char *value) +{ + dbgTrace(D_WAAP_PARSER_GQL) << "'" << value << "'"; + m_curNameValues++; + return m_receiver.onKv(m_curNodeName.data(), m_curNodeName.size(), value, strlen(value), BUFFERED_RECEIVER_F_BOTH); +} + +bool ParserGql::visitName(const facebook::graphql::ast::Name &node) +{ + dbgTrace(D_WAAP_PARSER_GQL) << node.getValue() << "'"; + bool ret = true; + if (m_curNameValues == 0 && !m_curNodeName.empty()) { + ret = m_receiver.onKv(m_curNodeName.data(), m_curNodeName.size(), "", 0, BUFFERED_RECEIVER_F_BOTH); + } + // wait for next name + m_curNodeName = std::string(node.getValue()); + m_curNameValues = 0; + return ret; +} + +bool ParserGql::visitIntValue(const facebook::graphql::ast::IntValue &node) +{ + dbgFlow(D_WAAP_PARSER_GQL); + return visitValue(node.getValue()); +} + +bool ParserGql::visitFloatValue(const facebook::graphql::ast::FloatValue &node) +{ + dbgFlow(D_WAAP_PARSER_GQL); + return visitValue(node.getValue()); +} + +bool ParserGql::visitStringValue(const facebook::graphql::ast::StringValue &node) +{ + dbgFlow(D_WAAP_PARSER_GQL); + return visitValue(node.getValue()); +} + +bool ParserGql::visitBooleanValue(const facebook::graphql::ast::BooleanValue &node) +{ + dbgFlow(D_WAAP_PARSER_GQL); + return visitValue(node.getValue() ? "true" : "false"); +} + +bool ParserGql::visitNullValue(const facebook::graphql::ast::NullValue &node) +{ + dbgFlow(D_WAAP_PARSER_GQL); + return visitValue("null"); +} + +bool ParserGql::visitEnumValue(const facebook::graphql::ast::EnumValue &node) +{ + dbgFlow(D_WAAP_PARSER_GQL); + return visitValue(node.getValue()); +} diff --git a/components/security_apps/waap/waap_clib/ParserGql.h b/components/security_apps/waap/waap_clib/ParserGql.h new file mode 100644 index 0000000..0215e1c --- /dev/null +++ b/components/security_apps/waap/waap_clib/ParserGql.h @@ -0,0 +1,56 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (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. + +#ifndef __PARSER_GQL_H +#define __PARSER_GQL_H + +#include +#include + +#include "ParserBase.h" +#include "graphqlparser/Ast.h" +#include "graphqlparser/AstNode.h" +#include "graphqlparser/AstVisitor.h" +#include "KeyStack.h" + +class ParserGql : public ParserBase, public facebook::graphql::ast::visitor::AstVisitor { +public: + ParserGql(IParserReceiver &receiver); + virtual ~ParserGql(); + size_t push(const char *data, size_t data_len); + void finish(); + virtual const std::string &name() const; + bool error() const; + virtual size_t depth() { return 0; } +private: + IParserReceiver &m_receiver; + bool m_error; + std::string m_buffer; + std::string m_curNodeName; + int m_curNameValues; + + bool visitValue(const char *value); + + // Callbacks from the parser + bool visitName(const facebook::graphql::ast::Name &node) override; + bool visitIntValue(const facebook::graphql::ast::IntValue &node) override; + bool visitFloatValue(const facebook::graphql::ast::FloatValue &node) override; + bool visitStringValue(const facebook::graphql::ast::StringValue &node) override; + bool visitBooleanValue(const facebook::graphql::ast::BooleanValue &node) override; + bool visitNullValue(const facebook::graphql::ast::NullValue &node) override; + bool visitEnumValue(const facebook::graphql::ast::EnumValue &node) override; +public: + static const std::string m_parserName; +}; + +#endif // __PARSER_JQL_H diff --git a/components/security_apps/waap/waap_clib/ParserJson.cc b/components/security_apps/waap/waap_clib/ParserJson.cc index e565d84..91e1190 100755 --- a/components/security_apps/waap/waap_clib/ParserJson.cc +++ b/components/security_apps/waap/waap_clib/ParserJson.cc @@ -270,6 +270,10 @@ size_t ParserJson::push(const char* buf, size_t len) { m_state = s_error; } + if (m_receiver2) { + m_receiver2->onEndOfData(); + } + return 0; } diff --git a/components/security_apps/waap/waap_clib/Serializator.cc b/components/security_apps/waap/waap_clib/Serializator.cc index 58cd83c..fd96b27 100755 --- a/components/security_apps/waap/waap_clib/Serializator.cc +++ b/components/security_apps/waap/waap_clib/Serializator.cc @@ -44,18 +44,19 @@ static const string defaultSharedStorageHost = "appsec-shared-storage-svc"; #define LEARNING_HOST_ENV_NAME "LEARNING_HOST" static bool -isGZipped(const std::string &stream) +isGZipped(const string &stream) { if (stream.size() < 2) return false; auto unsinged_stream = reinterpret_cast(stream.data()); return unsinged_stream[0] == 0x1f && unsinged_stream[1] == 0x8b; } -bool RestGetFile::loadJson(const std::string& json) +bool RestGetFile::loadJson(const string& json) { + string json_str; - std::string json_str = json; - if (isGZipped(json_str) == 0) + json_str = json; + if (!isGZipped(json_str)) { return ClientRest::loadJson(json_str); } @@ -66,7 +67,7 @@ bool RestGetFile::loadJson(const std::string& json) reinterpret_cast(json_str.c_str())); if (res.ok){ - json_str = std::string((const char *)res.output, res.num_output_bytes); + json_str = string((const char *)res.output, res.num_output_bytes); if (res.output) free(res.output); res.output = nullptr; res.num_output_bytes = 0; @@ -76,12 +77,12 @@ bool RestGetFile::loadJson(const std::string& json) return ClientRest::loadJson(json_str); } -Maybe RestGetFile::genJson() const +Maybe RestGetFile::genJson() const { - Maybe json = ClientRest::genJson(); + Maybe json = ClientRest::genJson(); if (json.ok()) { - std::string data = json.unpack(); + string data = json.unpack(); auto compression_stream = initCompressionStream(); CompressionResult res = compressData( compression_stream, @@ -94,7 +95,7 @@ Maybe RestGetFile::genJson() const dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "Failed to gzip data"; return genError("Failed to compress data"); } - data = std::string((const char *)res.output, res.num_output_bytes); + data = string((const char *)res.output, res.num_output_bytes); json = data; @@ -104,7 +105,7 @@ Maybe RestGetFile::genJson() const } return json; } -SerializeToFilePeriodically::SerializeToFilePeriodically(std::chrono::seconds pollingIntervals, std::string filePath) : +SerializeToFilePeriodically::SerializeToFilePeriodically(ch::seconds pollingIntervals, string filePath) : SerializeToFileBase(filePath), m_lastSerialization(0), m_interval(pollingIntervals) @@ -140,7 +141,7 @@ void SerializeToFilePeriodically::backupWorker() } } -void SerializeToFilePeriodically::setInterval(std::chrono::seconds newInterval) +void SerializeToFilePeriodically::setInterval(ch::seconds newInterval) { if (m_interval != newInterval) { @@ -150,7 +151,7 @@ void SerializeToFilePeriodically::setInterval(std::chrono::seconds newInterval) } } -SerializeToFileBase::SerializeToFileBase(std::string fileName) : m_filePath(fileName) +SerializeToFileBase::SerializeToFileBase(string fileName) : m_filePath(fileName) { dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "SerializeToFileBase::SerializeToFileBase() fname='" << m_filePath << "'"; @@ -163,12 +164,12 @@ SerializeToFileBase::~SerializeToFileBase() void SerializeToFileBase::saveData() { - std::fstream filestream; + fstream filestream; dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "saving to file: " << m_filePath; - filestream.open(m_filePath, std::fstream::out); + filestream.open(m_filePath, fstream::out); - std::stringstream ss; + stringstream ss; if (filestream.is_open() == false) { dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to open file: " << m_filePath << " Error: " @@ -182,12 +183,12 @@ void SerializeToFileBase::saveData() filestream.close(); } -void SerializeToFileBase::loadFromFile(std::string filePath) +void SerializeToFileBase::loadFromFile(string filePath) { dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "loadFromFile() file: " << filePath; - std::fstream filestream; + fstream filestream; - filestream.open(filePath, std::fstream::in); + filestream.open(filePath, fstream::in); if (filestream.is_open() == false) { dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to open file: " << filePath << " Error: " << @@ -200,14 +201,14 @@ void SerializeToFileBase::loadFromFile(std::string filePath) // try to strip the unique ID from the path and load the file from the parent directory // that might exist in previous run where instance awareness didn't exits. I_InstanceAwareness* instanceAwareness = Singleton::Consume::by(); - Maybe id = instanceAwareness->getUniqueID(); + Maybe id = instanceAwareness->getUniqueID(); if (!id.ok()) { return; } - std::string idStr = "/" + id.unpack() + "/"; + string idStr = "/" + id.unpack() + "/"; size_t idPosition = filePath.find(idStr); - if (idPosition != std::string::npos) + if (idPosition != string::npos) { filePath.erase(idPosition, idStr.length() - 1); dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "retry to load file from : " << filePath; @@ -219,12 +220,12 @@ void SerializeToFileBase::loadFromFile(std::string filePath) dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "loading from file: " << filePath; int length; - filestream.seekg(0, std::ios::end); // go to the end + filestream.seekg(0, ios::end); // go to the end length = filestream.tellg(); // report location (this is the length) dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "file length: " << length; assert(length >= 0); // length -1 really happens if filePath is a directory (!) char* buffer = new char[length]; // allocate memory for a buffer of appropriate dimension - filestream.seekg(0, std::ios::beg); // go back to the beginning + filestream.seekg(0, ios::beg); // go back to the beginning if (!filestream.read(buffer, length)) // read the whole file into the buffer { filestream.close(); @@ -234,18 +235,18 @@ void SerializeToFileBase::loadFromFile(std::string filePath) } filestream.close(); - std::string dataObfuscated(buffer, length); + string dataObfuscated(buffer, length); delete[] buffer; - std::stringstream ss(dataObfuscated); + stringstream ss(dataObfuscated); try { deserialize(ss); } - catch (std::runtime_error & e) { + catch (runtime_error & e) { dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to deserialize file: " << m_filePath << ", error: " << e.what(); } @@ -263,7 +264,7 @@ RemoteFilesList::RemoteFilesList() : files(), filesPathsList() // parses xml instead of json // extracts a file list in -bool RemoteFilesList::loadJson(const std::string& xml) +bool RemoteFilesList::loadJson(const string& xml) { xmlDocPtr doc; // the resulting document tree dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "XML input: " << xml; @@ -293,22 +294,22 @@ bool RemoteFilesList::loadJson(const std::string& xml) { dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the Contents element"; xmlNodePtr contents_node = node->children; - std::string file; - std::string lastModified; + string file; + string lastModified; while (contents_node != NULL) { if (xmlStrEqual(key_name, contents_node->name) == 1) { dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the Key element"; xmlChar* xml_file = xmlNodeGetContent(contents_node); - file = std::string(reinterpret_cast(xml_file)); + file = string(reinterpret_cast(xml_file)); xmlFree(xml_file); } if (xmlStrEqual(last_modified_name, contents_node->name) == 1) { dbgTrace(D_WAAP_CONFIDENCE_CALCULATOR) << "Found the LastModified element"; xmlChar* xml_file = xmlNodeGetContent(contents_node); - lastModified = std::string(reinterpret_cast(xml_file)); + lastModified = string(reinterpret_cast(xml_file)); xmlFree(xml_file); } if (!file.empty() && !lastModified.empty()) @@ -333,24 +334,24 @@ bool RemoteFilesList::loadJson(const std::string& xml) return true; } -const std::vector& RemoteFilesList::getFilesList() const +const vector& RemoteFilesList::getFilesList() const { return filesPathsList; } -const std::vector& RemoteFilesList::getFilesMetadataList() const +const vector& RemoteFilesList::getFilesMetadataList() const { return files.get(); } SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase( - std::chrono::minutes interval, - std::chrono::seconds waitForSync, - const std::string& filePath, - const std::string& remotePath, - const std::string& assetId, - const std::string& owner) + ch::minutes interval, + ch::seconds waitForSync, + const string& filePath, + const string& remotePath, + const string& assetId, + const string& owner) : SerializeToFileBase(filePath), m_remotePath(remotePath), @@ -400,7 +401,7 @@ SerializeToLocalAndRemoteSyncBase::SerializeToLocalAndRemoteSyncBase( if (parts[0].empty()) { offset = 1; } - std::string type = ""; + string type = ""; for (size_t i = offset + 2; i < parts.size(); i++) { type += type.empty() ? parts[i] : "/" + parts[i]; @@ -417,7 +418,7 @@ bool SerializeToLocalAndRemoteSyncBase::isBase() return m_remotePath == ""; } -std::string SerializeToLocalAndRemoteSyncBase::getUri() +string SerializeToLocalAndRemoteSyncBase::getUri() { static const string hybridModeUri = "/api"; static const string onlineModeUri = "/storage/waap"; @@ -437,24 +438,24 @@ SerializeToLocalAndRemoteSyncBase::~SerializeToLocalAndRemoteSyncBase() } -std::string SerializeToLocalAndRemoteSyncBase::getWindowId() +string SerializeToLocalAndRemoteSyncBase::getWindowId() { - return "window_" + std::to_string(m_daysCount) + "_" + std::to_string(m_windowsCount); + return "window_" + to_string(m_daysCount) + "_" + to_string(m_windowsCount); } -std::string SerializeToLocalAndRemoteSyncBase::getPostDataUrl() +string SerializeToLocalAndRemoteSyncBase::getPostDataUrl() { - std::string agentId = Singleton::Consume::by()->getAgentId(); + string agentId = Singleton::Consume::by()->getAgentId(); if (Singleton::exists()) { I_InstanceAwareness* instance = Singleton::Consume::by(); - Maybe uniqueId = instance->getUniqueID(); + Maybe uniqueId = instance->getUniqueID(); if (uniqueId.ok()) { agentId += "/" + uniqueId.unpack(); } } - std::string windowId = getWindowId(); + string windowId = getWindowId(); return getUri() + "/" + m_remotePath + "/" + windowId + "/" + agentId + "/data.data"; } void SerializeToLocalAndRemoteSyncBase::setRemoteSyncEnabled(bool enabled) @@ -462,7 +463,7 @@ void SerializeToLocalAndRemoteSyncBase::setRemoteSyncEnabled(bool enabled) m_remoteSyncEnabled = enabled; } -void SerializeToLocalAndRemoteSyncBase::setInterval(std::chrono::seconds newInterval) +void SerializeToLocalAndRemoteSyncBase::setInterval(ch::seconds newInterval) { dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "setInterval: from " << m_interval.count() << " to " << newInterval.count() << " seconds. assetId='" << m_assetId << "', owner='" << m_owner << "'"; @@ -495,7 +496,7 @@ void SerializeToLocalAndRemoteSyncBase::setInterval(std::chrono::seconds newInte size_t slicesCount = m_interval / assetSyncTimeSliceLength; size_t sliceIndex = 0; if (slicesCount != 0 && m_assetId != "") { - sliceIndex = std::hash{}(m_assetId) % slicesCount; + sliceIndex = hash{}(m_assetId) % slicesCount; } ch::seconds sliceOffset = assetSyncTimeSliceLength * sliceIndex; @@ -572,7 +573,7 @@ bool SerializeToLocalAndRemoteSyncBase::localSyncAndProcess() return true; } -std::chrono::seconds SerializeToLocalAndRemoteSyncBase::getIntervalDuration() const +ch::seconds SerializeToLocalAndRemoteSyncBase::getIntervalDuration() const { return m_interval; } @@ -581,14 +582,14 @@ void SerializeToLocalAndRemoteSyncBase::updateStateFromRemoteService() { for (int i = 0; i < remoteSyncMaxPollingAttempts; i++) { - m_pMainLoop->yield(std::chrono::seconds(60)); + m_pMainLoop->yield(ch::seconds(60)); RemoteFilesList remoteFiles = getRemoteProcessedFilesList(); if (remoteFiles.getFilesMetadataList().empty()) { dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "no files generated by the remote service were found"; continue; } - std::string lastModified = remoteFiles.getFilesMetadataList().begin()->modified; + string lastModified = remoteFiles.getFilesMetadataList().begin()->modified; if (lastModified != m_lastProcessedModified) { m_lastProcessedModified = lastModified; @@ -618,7 +619,7 @@ void SerializeToLocalAndRemoteSyncBase::syncWorker() << "Did not synchronize the data. Remote URL: " << m_remotePath << " is enabled: " - << std::to_string(m_remoteSyncEnabled); + << to_string(m_remoteSyncEnabled); processData(); saveData(); return; @@ -659,7 +660,7 @@ void SerializeToLocalAndRemoteSyncBase::syncWorker() Flags conn_flags; conn_flags.setFlag(MessageConnConfig::EXTERNAL); - std::string tenant_header = "X-Tenant-Id: " + agentDetails->getTenantId(); + string tenant_header = "X-Tenant-Id: " + agentDetails->getTenantId(); bool ok = messaging->sendNoReplyObject(syncObj, I_Messaging::Method::POST, getLearningHost(), @@ -735,7 +736,7 @@ RemoteFilesList SerializeToLocalAndRemoteSyncBase::getProcessedFilesList() if (!processedFilesList.getFilesList().empty()) { - const std::vector& filesMD = processedFilesList.getFilesMetadataList(); + const vector& filesMD = processedFilesList.getFilesMetadataList(); if (filesMD.size() > 1) { dbgWarning(D_WAAP_CONFIDENCE_CALCULATOR) << "got more than 1 expected processed file"; } @@ -764,7 +765,7 @@ RemoteFilesList SerializeToLocalAndRemoteSyncBase::getProcessedFilesList() return processedFilesList; } // backward compatibility - try to get backup file with the buggy prefix tenantID/assetID/instanceID/ - std::string bcRemotePath = m_remotePath; + string bcRemotePath = m_remotePath; size_t pos = bcRemotePath.find('/'); pos = bcRemotePath.find('/', pos + 1); if (!Singleton::exists()) @@ -774,14 +775,14 @@ RemoteFilesList SerializeToLocalAndRemoteSyncBase::getProcessedFilesList() return processedFilesList; } I_InstanceAwareness* instanceAwareness = Singleton::Consume::by(); - Maybe id = instanceAwareness->getUniqueID(); + Maybe id = instanceAwareness->getUniqueID(); if (!id.ok()) { dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "failed to get instance id err: " << id.getErr() << ". can't check backward compatibility"; return processedFilesList; } - std::string idStr = id.unpack(); + string idStr = id.unpack(); bcRemotePath.insert(pos + 1, idStr + "/"); dbgDebug(D_WAAP_CONFIDENCE_CALCULATOR) << "List of files is empty - trying to get the file from " << bcRemotePath; diff --git a/components/security_apps/waap/waap_clib/TypeIndicatorsFilter.cc b/components/security_apps/waap/waap_clib/TypeIndicatorsFilter.cc index 70fcb7c..273878c 100755 --- a/components/security_apps/waap/waap_clib/TypeIndicatorsFilter.cc +++ b/components/security_apps/waap/waap_clib/TypeIndicatorsFilter.cc @@ -65,7 +65,8 @@ bool TypeIndicatorFilter::shouldFilterKeyword(const std::string &key, const std: key.compare(key.size() - htmlParam.size(), htmlParam.size(), htmlParam) == 0); for (auto keyType : keyTypes) { - if (keyType == "free_text" && !isHtmlInput) + static const std::string free_text = "free_text"; + if (!keyType.compare(0, free_text.size(), free_text) && !isHtmlInput) { return true; } diff --git a/components/security_apps/waap/waap_clib/WaapAssetState.cc b/components/security_apps/waap/waap_clib/WaapAssetState.cc index 8822505..74a889a 100755 --- a/components/security_apps/waap/waap_clib/WaapAssetState.cc +++ b/components/security_apps/waap/waap_clib/WaapAssetState.cc @@ -1993,7 +1993,7 @@ void WaapAssetState::filterKeywordsByParameters( } else { - dbgTrace(D_WAAP_ASSET_STATE) << "No keywords need to be filter for this parameter"; + dbgTrace(D_WAAP_ASSET_STATE) << "No keywords need to be filtered for this parameter"; } } diff --git a/components/security_apps/waap/waap_clib/WaapConfigApplication.cc b/components/security_apps/waap/waap_clib/WaapConfigApplication.cc index 3f499b4..9a26df6 100755 --- a/components/security_apps/waap/waap_clib/WaapConfigApplication.cc +++ b/components/security_apps/waap/waap_clib/WaapConfigApplication.cc @@ -23,6 +23,15 @@ set WaapConfigApplication::assets_ids{}; set WaapConfigApplication::assets_ids_aggregation{}; bool WaapConfigApplication::getWaapSiteConfig(WaapConfigApplication& ngenSiteConfig) { + auto maybe_tenant_id = Singleton::Consume::by()->get( + "ActiveTenantId" + ); + auto maybe_profile_id = Singleton::Consume::by()->get( + "ActiveProfileId" + ); + string tenant_id = (maybe_tenant_id.ok() ? *maybe_tenant_id : "not found"); + string profile_id = (maybe_profile_id.ok() ? *maybe_profile_id : "not found"); + dbgTrace(D_WAAP) << "Tenant ID: " << tenant_id << ", Profile ID: " << profile_id; auto &maybe_ngen_config = getConfiguration( "WAAP", "WebApplicationSecurity" diff --git a/components/security_apps/waap/waap_clib/WaapConfigApplication.h b/components/security_apps/waap/waap_clib/WaapConfigApplication.h index f6149d1..b866abe 100755 --- a/components/security_apps/waap/waap_clib/WaapConfigApplication.h +++ b/components/security_apps/waap/waap_clib/WaapConfigApplication.h @@ -19,9 +19,13 @@ #include "WaapConfigBase.h" #include "log_generator.h" +#include "i_environment.h" #include "debug.h" -class WaapConfigApplication : public WaapConfigBase +class WaapConfigApplication + : + public WaapConfigBase, + Singleton::Consume { public: WaapConfigApplication(); diff --git a/components/security_apps/waap/waap_clib/WaapScanner.cc b/components/security_apps/waap/waap_clib/WaapScanner.cc index 4529194..886f55c 100755 --- a/components/security_apps/waap/waap_clib/WaapScanner.cc +++ b/components/security_apps/waap/waap_clib/WaapScanner.cc @@ -31,6 +31,7 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN std::string param_name = IndicatorsFiltersManager::generateKey(res.location, res.param_name, m_transaction); dbgTrace(D_WAAP_SCANNER) << "filter processing for parameter: " << param_name; m_transaction->getAssetState()->logIndicatorsInFilters(param_name, keywordsSet, m_transaction); + m_transaction->getAssetState()->filterKeywords(param_name, keywordsSet, res.filtered_keywords); if (m_transaction->getSiteConfig() != nullptr) { @@ -41,6 +42,7 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN } m_transaction->getAssetState()->filterKeywordsByParameters(res.param_name, keywordsSet); + // The keywords are only removed in production, they are still used while building scores if (!m_transaction->get_ignoreScore()) { m_transaction->getAssetState()->removeKeywords(keywordsSet); @@ -66,6 +68,7 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN std::sort(res.keyword_matches.begin(), res.keyword_matches.end()); std::string keywords_string; + std::vector strippedKeywords; for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) { // Add spaces between the items, but not before the first one if (pKeyword != keywordsSet.begin()) { @@ -75,15 +78,21 @@ double Waap::Scanner::getScoreData(Waf2ScanResult& res, const std::string &poolN std::string k = *pKeyword; stripSpaces(k); keywords_string += k; + strippedKeywords.push_back(k); } std::vector newKeywords; for (auto pKeyword = keywordsSet.begin(); pKeyword != keywordsSet.end(); ++pKeyword) { std::string k = *pKeyword; stripSpaces(k); - // if keyword_string.count(key) < 2: new_keywords.append(key) if (countSubstrings(keywords_string, k) < 2) { newKeywords.push_back(k); + } else { + if ((std::count(strippedKeywords.begin(), strippedKeywords.end(), k) > 1) ) { + if ((std::count(newKeywords.begin(), newKeywords.end(), k) < 1)) { + newKeywords.push_back(k); + } + } } } @@ -127,6 +136,10 @@ bool Waap::Scanner::suspiciousHit(Waf2ScanResult& res, DeepParser &dp, res.location = location; res.param_name = param_name; // remember the param name (analyzer needs it for reporting) + // call shouldIgnoreOverride prior to score calculation, so that matched override keywords will be filtered + // when an ignore override action is detected + bool ignoreOverride = m_transaction->shouldIgnoreOverride(res); + // Select scores pool by location std::string poolName = Waap::Scores::getScorePoolNameByLocation(location); @@ -145,7 +158,7 @@ bool Waap::Scanner::suspiciousHit(Waf2ScanResult& res, DeepParser &dp, ); } - if (isKeyCspReport(key, res, dp) || m_transaction->shouldIgnoreOverride(res)) { + if (isKeyCspReport(key, res, dp) || ignoreOverride) { dbgTrace(D_WAAP_SCANNER) << "Ignoring parameter key/value " << res.param_name << " due to ignore action in override"; m_bIgnoreOverride = true; diff --git a/components/security_apps/waap/waap_clib/Waf2Engine.cc b/components/security_apps/waap/waap_clib/Waf2Engine.cc index 3d07a8e..598bfaa 100755 --- a/components/security_apps/waap/waap_clib/Waf2Engine.cc +++ b/components/security_apps/waap/waap_clib/Waf2Engine.cc @@ -67,8 +67,6 @@ using namespace ReportIS; // Score threshold below which the match won't be considered #define SCORE_THRESHOLD (1.4f) -static const ParameterBehavior action_ignore(BehaviorKey::ACTION, BehaviorValue::IGNORE); - void Waf2Transaction::learnScore(ScoreBuilderData& data, const std::string &poolName) { m_pWaapAssetState->scoreBuilder.analyzeFalseTruePositive(data, poolName, !m_ignoreScore); @@ -1372,7 +1370,7 @@ Waf2Transaction::checkShouldInject() std::string uri = m_uriPath; std::string low_method = m_methodStr; std::transform(low_method.begin(), low_method.end(), low_method.begin(), ::tolower); - + auto csrfPolicy = m_siteConfig ? m_siteConfig->get_CsrfPolicy() : NULL; bool csrf = false; dbgTrace(D_WAAP) << "Waf2Transaction::checkShouldInject(): received the relevant Application configuration " @@ -1384,7 +1382,7 @@ Waf2Transaction::checkShouldInject() { dbgTrace(D_WAAP) << "Waf2Transaction::checkShouldInject(): Should not inject CSRF scripts."; } - + if(csrf) { dbgTrace(D_WAAP) << "Waf2Transaction::checkShouldInject(): Should inject CSRF script"; m_responseInjectReasons.setCsrf(true); @@ -1554,6 +1552,8 @@ void Waf2Transaction::appendCommonLogFields(LogGen& waapLog, const std::string& incidentType) const { auto env = Singleton::Consume::by(); + auto active_id = env->get("ActiveTenantId"); + if (active_id.ok()) waapLog.addToOrigin(LogField("tenantId", *active_id)); auto proxy_ip = env->get(HttpTransactionData::proxy_ip_ctx); if (proxy_ip.ok() && m_remote_addr != proxy_ip.unpack()) { @@ -2155,7 +2155,7 @@ Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) { auto exceptions = getConfiguration("rulebase", "exception"); if (!exceptions.ok()) return false; - dbgTrace(D_WAAP) << "matching exceptions"; + dbgTrace(D_WAAP_OVERRIDE) << "matching exceptions"; std::unordered_map> exceptions_dict; @@ -2184,11 +2184,16 @@ Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) { exceptions_dict["url"].insert(getUriStr()); exceptions_dict["hostName"].insert(m_hostStr); + for (auto &keyword : res.keyword_matches) { + exceptions_dict["indicator"].insert(keyword); + } + // calling behavior and check if there is a behavior that match to this specific param name. - auto behaviors = exceptions.unpack().getBehavior(exceptions_dict); + auto behaviors = exceptions.unpack().getBehavior(exceptions_dict, + getAssetState()->m_filtersMngr->getMatchedOverrideKeywords()); for (auto const &behavior : behaviors) { if (behavior == action_ignore) { - dbgTrace(D_WAAP) << "matched exceptions for " << res.param_name << " should ignore."; + dbgTrace(D_WAAP_OVERRIDE) << "matched exceptions for " << res.param_name << " should ignore."; std::string overrideId = behavior.getId(); if (!overrideId.empty()) { m_matchedOverrideIds.insert(overrideId); diff --git a/components/security_apps/waap/waap_clib/Waf2Util.cc b/components/security_apps/waap/waap_clib/Waf2Util.cc index 13a4bab..7d1b3ca 100755 --- a/components/security_apps/waap/waap_clib/Waf2Util.cc +++ b/components/security_apps/waap/waap_clib/Waf2Util.cc @@ -41,6 +41,7 @@ using namespace std; USE_DEBUG_FLAG(D_WAAP); USE_DEBUG_FLAG(D_WAAP_EVASIONS); USE_DEBUG_FLAG(D_WAAP_BASE64); +USE_DEBUG_FLAG(D_WAAP_JSON); #define MIN_HEX_LENGTH 6 #define charToDigit(c) (c - '0') @@ -1144,6 +1145,8 @@ namespace Util { #define B64_TRAILERCHAR '=' static bool err = false; +// based on malicious JSON "{1:\x00}" +static const int minimal_legal_json_size = 8; static const SingleRegex invalid_hex_evasion_re( "%([g-zG-Z][0-9a-zA-Z]|[0-9a-zA-Z][g-zG-Z])", @@ -1161,11 +1164,15 @@ static const SingleRegex csp_report_policy_re( "csp_report_policy" ); static const SingleRegex base64_key_value_detector_re( - "^[^<>;&\\?|=\\s]+={1}\\s*.+", + "^[^<>{};,&\\?|=\\s]+={1}\\s*.+", err, "base64_key_value"); +static const SingleRegex json_key_value_detector_re( + "^[^<>{};,&\\?|=\\s]+={.+:.+}\\z", + err, + "json_key_value"); static const SingleRegex base64_key_detector_re( - "^[^<>;&\\?|=\\s]+={1}", + "^[^<>{};,&\\?|=\\s]+={1}", err, "base64_key"); static const SingleRegex base64_prefix_detector_re( @@ -1173,6 +1180,44 @@ static const SingleRegex base64_prefix_detector_re( err, "base64_prefix"); +// looks for combination ={*:*} +//used to allow parsing param=JSON to reduce false positives +bool detectJSONasParameter(const string &string_buffer, + string &key, + string &value) +{ + key.clear(); + value.clear(); + bool is_json_candidate_detected = json_key_value_detector_re.hasMatch(string_buffer); + + if (is_json_candidate_detected) { + dbgTrace(D_WAAP_JSON) << "===JSONdetect===: json_key_value_detector_re test passed - looking for key"; + string::const_iterator it = string_buffer.begin(); + for (; it != string_buffer.end(); ++it) { + if (*it != '{') { + continue; + } + // candidate should have size 8 or more - minimum for JSON with attack + if ((string_buffer.end() - it) < minimal_legal_json_size) { + dbgTrace(D_WAAP_JSON) + << "===JSONdetect===: candidate is shorter then the length" + "of the shortest known json attack which is: " << minimal_legal_json_size; + return false; + } + + key = std::string(string_buffer.begin(), it-1); + value = std::string(it, string_buffer.end()); + break; + } + } + dbgTrace(D_WAAP_JSON) + << "===JSONdetect===: key = '" + << key + << "', value = '" + << value <<"'"; + return is_json_candidate_detected; +} + static void b64TestChunk(const string &s, string::const_iterator chunkStart, string::const_iterator chunkEnd, @@ -2115,6 +2160,8 @@ string convertParamTypeToStr(ParamType type) return "urls"; case FREE_TEXT_PARAM_TYPE: return "free_text"; + case FREE_TEXT_FRENCH_PARAM_TYPE: + return "free_text_french"; case PIPE_PARAM_TYPE: return "pipes"; case LONG_RANDOM_TEXT_PARAM_TYPE: @@ -2148,6 +2195,7 @@ ParamType convertTypeStrToEnum(const string& typeStr) {"administration_config", ParamType::ADMINISTRATOR_CONFIG_PARAM_TYPE}, {"base64", ParamType::BASE64_PARAM_TYPE }, {"free_text", ParamType::FREE_TEXT_PARAM_TYPE}, + {"free_text_french", ParamType::FREE_TEXT_FRENCH_PARAM_TYPE}, {"html_input", ParamType::HTML_PARAM_TYPE}, {"long_random_text", ParamType::LONG_RANDOM_TEXT_PARAM_TYPE}, {"pipes", ParamType::PIPE_PARAM_TYPE}, diff --git a/components/security_apps/waap/waap_clib/Waf2Util.h b/components/security_apps/waap/waap_clib/Waf2Util.h index 009d1bf..c11eb01 100755 --- a/components/security_apps/waap/waap_clib/Waf2Util.h +++ b/components/security_apps/waap/waap_clib/Waf2Util.h @@ -858,6 +858,10 @@ namespace Util { std::string::const_iterator e, std::string &repl); + bool detectJSONasParameter(const std::string &s, + std::string &key, + std::string &value); + void b64Decode( const std::string &s, RegexSubCallback_f cb, diff --git a/components/utils/CMakeLists.txt b/components/utils/CMakeLists.txt index 3863672..48eed04 100644 --- a/components/utils/CMakeLists.txt +++ b/components/utils/CMakeLists.txt @@ -1,2 +1,3 @@ +add_subdirectory(http_transaction_data) add_subdirectory(ip_utilities) add_subdirectory(pm) diff --git a/components/http_transaction_data/CMakeLists.txt b/components/utils/http_transaction_data/CMakeLists.txt similarity index 100% rename from components/http_transaction_data/CMakeLists.txt rename to components/utils/http_transaction_data/CMakeLists.txt diff --git a/components/http_transaction_data/http_transaction_data.cc b/components/utils/http_transaction_data/http_transaction_data.cc similarity index 100% rename from components/http_transaction_data/http_transaction_data.cc rename to components/utils/http_transaction_data/http_transaction_data.cc diff --git a/components/http_transaction_data/http_transaction_data_ut/CMakeLists.txt b/components/utils/http_transaction_data/http_transaction_data_ut/CMakeLists.txt similarity index 100% rename from components/http_transaction_data/http_transaction_data_ut/CMakeLists.txt rename to components/utils/http_transaction_data/http_transaction_data_ut/CMakeLists.txt diff --git a/components/http_transaction_data/http_transaction_data_ut/http_transaction_data_ut.cc b/components/utils/http_transaction_data/http_transaction_data_ut/http_transaction_data_ut.cc similarity index 100% rename from components/http_transaction_data/http_transaction_data_ut/http_transaction_data_ut.cc rename to components/utils/http_transaction_data/http_transaction_data_ut/http_transaction_data_ut.cc diff --git a/core/config/config.cc b/core/config/config.cc index 513c5cd..decc78a 100644 --- a/core/config/config.cc +++ b/core/config/config.cc @@ -14,6 +14,7 @@ #include "config.h" #include "config_component.h" +#include #include #include #include @@ -66,11 +67,24 @@ public: void doCall() override { - auto i_config = Singleton::Consume::from(); + static const map status_map { + {I_Config::AsyncLoadConfigStatus::Success, "Success"}, + {I_Config::AsyncLoadConfigStatus::InProgress, "In Progress"}, + {I_Config::AsyncLoadConfigStatus::Error, "Error"} + }; + auto i_config = Singleton::Consume::from(); I_Config::AsyncLoadConfigStatus load_config_staus = i_config->reloadConfiguration(policy_version, true, id); - finished = load_config_staus == I_Config::AsyncLoadConfigStatus::InProgress; + + finished = load_config_staus != I_Config::AsyncLoadConfigStatus::InProgress; error = load_config_staus == I_Config::AsyncLoadConfigStatus::Error; + + if (error) { + dbgWarning(D_CONFIG) << "Configuration reload status: " << status_map.at(load_config_staus); + } else { + dbgDebug(D_CONFIG) << "Configuration reload status: " << status_map.at(load_config_staus); + } + if (!finished) { error_message = "Reload already in progress - can't start another one"; } @@ -669,8 +683,8 @@ ConfigComponent::Impl::clearOldTenants() bool ConfigComponent::Impl::areTenantAndProfileActive(const TenantProfilePair &tenant_profile) const { - return (tenant_profile.getTenantId() == default_tenant_id && tenant_profile.getPfofileId() == default_profile_id) - || tenant_mananger->areTenantAndProfileActive(tenant_profile.getTenantId(), tenant_profile.getPfofileId()); + return (tenant_profile.getTenantId() == default_tenant_id && tenant_profile.getProfileId() == default_profile_id) + || tenant_mananger->areTenantAndProfileActive(tenant_profile.getTenantId(), tenant_profile.getProfileId()); } void @@ -723,12 +737,21 @@ ConfigComponent::Impl::loadConfiguration(vector> &f string curr_profile = default_profile_id; try { (*archive)(cereal::make_nvp("tenantID", curr_tenant)); + dbgTrace(D_CONFIG) << "Found a tenant ID in the file: " << curr_tenant; + } catch (cereal::Exception &e) {} + try { (*archive)(cereal::make_nvp("profileID", curr_profile)); - } catch (cereal::Exception &e) { - } + dbgTrace(D_CONFIG) << "Found a profile ID in the file " << curr_profile; + } catch (cereal::Exception &e) {} + + dbgTrace(D_CONFIG) + << "Loading configuration for tenant: " + << curr_tenant + << " and profile: " + << curr_profile + << ", for the archive: " + << (*archive).getNodeName(); - dbgTrace(D_CONFIG) << - "Loading configuration for tenant: " << curr_tenant << " and profile: " << curr_profile; TenantProfilePair tenant_profile(curr_tenant, curr_profile); for (auto &config : expected_configs) { auto loaded = config->loadConfiguration(*archive); @@ -800,6 +823,7 @@ ConfigComponent::Impl::commitFailure(const string &error) bool ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_async) { + dbgFlow(D_CONFIG) << "Reloading configuration"; auto env = Singleton::Consume::by(); env->registerValue("New Policy Version", version); auto cleanup = make_scope_exit([env] () { env->unregisterKey("New Policy Version"); } ); @@ -812,6 +836,8 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as const auto &active_tenants = tenant_mananger ? tenant_mananger->fetchAllActiveTenants() : vector(); + dbgTrace(D_CONFIG) << "Number of active tenants found while reloading configuration: " << active_tenants.size(); + for (const auto &config_file : expected_configuration_files) { for (const auto &type : config_file.second) { if (type == ConfigFileType::RawData) continue; @@ -835,7 +861,9 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as const vector &profile_ids = tenant_mananger ? tenant_mananger->fetchProfileIds(tenant) : vector(); for (auto &profile_id : profile_ids) { - string settings_path = config_directory_path + "tenant_" + tenant + "_" + profile_id + "_settings.json"; + string settings_path = + config_directory_path + "tenant_" + tenant + "_profile_"+ profile_id + "_settings.json"; + dbgTrace(D_CONFIG) << "Inserting a settings path: " << settings_path; files.emplace(settings_path, make_shared(settings_path)); } } @@ -843,10 +871,10 @@ ConfigComponent::Impl::reloadConfigurationImpl(const string &version, bool is_as vector> archives; for (const auto &file : files) { if (file.second->is_open()) { - dbgDebug(D_CONFIG) << "Succesfully opened configuration file. File: " << file.first; + dbgTrace(D_CONFIG) << "Succesfully opened configuration file. File: " << file.first; archives.push_back(make_shared(*file.second)); } else { - dbgDebug(D_CONFIG) << "Could not open configuration file. Path: " << file.first; + dbgTrace(D_CONFIG) << "Could not open configuration file. Path: " << file.first; } } diff --git a/core/connkey/connkey.cc b/core/connkey/connkey.cc index f888cf1..ab4e04c 100755 --- a/core/connkey/connkey.cc +++ b/core/connkey/connkey.cc @@ -161,26 +161,6 @@ IPAddr::createIPAddr(const string &ip_text) bool IPAddr::isValidIPAddr(const string &ip_text) { return createIPAddr(ip_text).ok(); } -IPAddressConfig::IPAddressConfig(const string &ip_string) -{ - auto maybe_address = IPAddr::createIPAddr(ip_string); - if (maybe_address.ok()) address = maybe_address.unpack(); -} - -void -IPAddressConfig::load(cereal::JSONInputArchive &ar) -{ - string ip_string; - ar(cereal::make_nvp("IPAddress", ip_string)); - auto ip_address = IPAddr::createIPAddr(ip_string); - if (!ip_address.ok()) { - throw Config::ConfigException( - "Failed to create an IP address from " + ip_string + ": " + ip_address.getErr() - ); - } - address = ip_address.unpack(); -} - const string ConnKey::network_key = "NetworkKey"; template diff --git a/core/include/general/logging_comp.h b/core/include/general/logging_comp.h index bb268c9..a7b78b5 100644 --- a/core/include/general/logging_comp.h +++ b/core/include/general/logging_comp.h @@ -24,6 +24,7 @@ #include "i_socket_is.h" #include "component.h" #include "i_agent_details.h" +#include "i_shell_cmd.h" class LoggingComp : @@ -35,7 +36,8 @@ class LoggingComp Singleton::Consume, Singleton::Consume, Singleton::Consume, - Singleton::Consume + Singleton::Consume, + Singleton::Consume { public: LoggingComp(); diff --git a/core/include/general/tenant_profile_pair.h b/core/include/general/tenant_profile_pair.h index 25bd29e..c44f728 100644 --- a/core/include/general/tenant_profile_pair.h +++ b/core/include/general/tenant_profile_pair.h @@ -79,7 +79,7 @@ public: } std::string - getPfofileId() const + getProfileId() const { return profile_id; } diff --git a/core/include/services_sdk/interfaces/i_logging.h b/core/include/services_sdk/interfaces/i_logging.h index fcdb244..3112c0d 100644 --- a/core/include/services_sdk/interfaces/i_logging.h +++ b/core/include/services_sdk/interfaces/i_logging.h @@ -25,7 +25,11 @@ public: using GeneralModifier = std::function; virtual bool addStream(ReportIS::StreamType type) = 0; - virtual bool addStream(ReportIS::StreamType type, const std::string &log_server_url) = 0; + virtual bool addStream( + ReportIS::StreamType type, + const std::string &log_server_url, + const std::string &protocol + ) = 0; virtual bool delStream(ReportIS::StreamType type) = 0; virtual void sendLog(const Report &msg) = 0; diff --git a/core/include/services_sdk/interfaces/i_tenant_manager.h b/core/include/services_sdk/interfaces/i_tenant_manager.h index c0d7fa5..d7b0175 100644 --- a/core/include/services_sdk/interfaces/i_tenant_manager.h +++ b/core/include/services_sdk/interfaces/i_tenant_manager.h @@ -41,6 +41,8 @@ public: virtual std::chrono::microseconds getTimeoutVal() const = 0; + virtual std::string getProfileId(const std::string &tenant_id, const std::string ®ion) const = 0; + private: friend class LoadNewTenants; friend class LoadNewTenantsAndProfiles; diff --git a/core/include/services_sdk/interfaces/mock/mock_logging.h b/core/include/services_sdk/interfaces/mock/mock_logging.h index b2170d7..6f7c2e5 100755 --- a/core/include/services_sdk/interfaces/mock/mock_logging.h +++ b/core/include/services_sdk/interfaces/mock/mock_logging.h @@ -10,7 +10,7 @@ class MockLogging : public Singleton::Provide::From for IPAddr namespace std { diff --git a/core/instance_awareness/instance_awareness.cc b/core/instance_awareness/instance_awareness.cc index b2d76d5..289a1a6 100644 --- a/core/instance_awareness/instance_awareness.cc +++ b/core/instance_awareness/instance_awareness.cc @@ -33,7 +33,7 @@ public: Maybe instance_id = checkIfValueIsConfigured("id"); if (instance_id.ok()) return instance_id; - return genError("Instance Awareness isn't active"); + return genError("Instance Awareness isn't active, Error: " + instance_id.getErr()); } Maybe @@ -42,14 +42,14 @@ public: Maybe family_id = checkIfValueIsConfigured("family"); if (family_id.ok()) return family_id; - return genError("Family ID isn't active"); + return genError("Family ID isn't active, Error: " + family_id.getErr()); } Maybe getUniqueID() override { Maybe instance_id(getInstanceID()); - if (!instance_id.ok()) return genError("Instance Awareness isn't active"); + if (!instance_id.ok()) return genError("Can't get instance ID, Error: " + instance_id.getErr()); Maybe family_id(getFamilyID()); if (!family_id.ok()) return *instance_id; diff --git a/core/instance_awareness/instance_awareness_ut/instance_awareness_ut.cc b/core/instance_awareness/instance_awareness_ut/instance_awareness_ut.cc index 8732252..f1d63d6 100644 --- a/core/instance_awareness/instance_awareness_ut/instance_awareness_ut.cc +++ b/core/instance_awareness/instance_awareness_ut/instance_awareness_ut.cc @@ -43,9 +43,12 @@ TEST_F(InstanceAwarenessTest, emptyInit) init(args); - EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active")); - EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active")); - EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active")); + EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Flag not found")); + EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Flag not found")); + EXPECT_THAT( + getUniqueID(), + IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Flag not found") + ); } TEST_F(InstanceAwarenessTest, badFamilyID) @@ -55,7 +58,7 @@ TEST_F(InstanceAwarenessTest, badFamilyID) init(args); EXPECT_THAT(getInstanceID(), IsValue("9")); - EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active")); + EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Illegal flag: family")); EXPECT_THAT(getUniqueID(), IsValue("9")); } @@ -65,9 +68,12 @@ TEST_F(InstanceAwarenessTest, badInstanceID) init(args); - EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active")); + EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Illegal flag: id")); EXPECT_THAT(getFamilyID(), IsValue("073b8744b4c5")); - EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active")); + EXPECT_THAT( + getUniqueID(), + IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Illegal flag: id") + ); } TEST_F(InstanceAwarenessTest, emptyInstanceID) @@ -76,9 +82,12 @@ TEST_F(InstanceAwarenessTest, emptyInstanceID) init(args); - EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active")); + EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Flag not found")); EXPECT_THAT(getFamilyID(), IsValue("073b8744b4c5")); - EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active")); + EXPECT_THAT( + getUniqueID(), + IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Flag not found") + ); } TEST_F(InstanceAwarenessTest, noInstanceID) @@ -87,9 +96,12 @@ TEST_F(InstanceAwarenessTest, noInstanceID) init(args); - EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active")); + EXPECT_THAT(getInstanceID(), IsError("Instance Awareness isn't active, Error: Flag not found")); EXPECT_THAT(getFamilyID(), IsValue("073b8744b4c5")); - EXPECT_THAT(getUniqueID(), IsError("Instance Awareness isn't active")); + EXPECT_THAT( + getUniqueID(), + IsError("Can't get instance ID, Error: Instance Awareness isn't active, Error: Flag not found") + ); } TEST_F(InstanceAwarenessTest, init) @@ -111,7 +123,7 @@ TEST_F(InstanceAwarenessTest, initIDOnly) EXPECT_THAT(getUniqueID(), IsValue("9")); EXPECT_THAT(getInstanceID(), IsValue("9")); - EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active")); + EXPECT_THAT(getFamilyID(), IsError("Family ID isn't active, Error: Flag not found")); } TEST_F(InstanceAwarenessTest, defaultValues) diff --git a/core/logging/CMakeLists.txt b/core/logging/CMakeLists.txt index b34275e..f8f26a0 100644 --- a/core/logging/CMakeLists.txt +++ b/core/logging/CMakeLists.txt @@ -1,3 +1,3 @@ -add_library(logging logging.cc log_generator.cc debug_stream.cc file_stream.cc fog_stream.cc syslog_stream.cc cef_stream.cc) +add_library(logging logging.cc log_generator.cc debug_stream.cc file_stream.cc fog_stream.cc syslog_stream.cc cef_stream.cc k8s_svc_stream.cc) add_subdirectory(logging_ut) diff --git a/core/logging/cef_stream.cc b/core/logging/cef_stream.cc index 60d2273..e115308 100755 --- a/core/logging/cef_stream.cc +++ b/core/logging/cef_stream.cc @@ -11,6 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include "logging_comp.h" #include "log_streams.h" @@ -19,11 +21,16 @@ using namespace cereal; USE_DEBUG_FLAG(D_REPORT); -CefStream::CefStream(const string &_ip_address, int _port) +static string lookup_cmd = "nslookup "; +static string line_selection_cmd = "| grep Address | sed -n 2p"; +static string parsing_cmd = "| cut -f2 -d' ' | tr -d '\n'"; + +CefStream::CefStream(const string &_address, int _port, I_Socket::SocketType _protocol) : i_socket(Singleton::Consume::by()), - ip_address(_ip_address), - port(_port) + address(_address), + port(_port), + protocol(_protocol) { connect(); if (!socket.ok()) { @@ -65,17 +72,57 @@ CefStream::sendLog(const Report &log) void CefStream::connect() { - auto cef_ip_address = getProfileAgentSettingWithDefault(ip_address, "agent.config.log.cefServer.IP"); + auto cef_address = getProfileAgentSettingWithDefault(address, "agent.config.log.cefServer.IP"); auto cef_port = getProfileAgentSettingWithDefault(port, "agent.config.log.cefServer.port"); - if (cef_ip_address.empty()) { - dbgWarning(D_REPORT) << "Cannot connect to CEF server, IP is not configured."; + if (cef_address.empty()) { + dbgWarning(D_REPORT) << "Cannot connect to CEF server, IP/Domain is not configured."; return; } + + struct in_addr addr; + if (inet_pton(AF_INET, cef_address.data(), &addr) != 1) { + I_ShellCmd *shell_cmd = Singleton::Consume::by(); + string host_cmd = lookup_cmd + cef_address + line_selection_cmd + parsing_cmd; + Maybe res = shell_cmd->getExecOutput(host_cmd, 500); + if (!res.ok()) { + dbgWarning(D_REPORT) + << "Failed to execute domain lookup command. " + << "CEF Domain: " + << cef_address + << "Error: " + << res.getErr(); + return; + } + + if (res.unpack().empty()) { + dbgWarning(D_REPORT) + << "Got en empty ip address from lookup command. " + << "CEF Domain: " + << cef_address + << "Got bad ip address: " + << res.unpack(); + return; + } + + dbgDebug(D_REPORT) << "CEF Domain lookup result: " << res.unpack(); + if (inet_pton(AF_INET, res.unpack().data(), &addr) != 1) { + dbgWarning(D_REPORT) + << "Got a faulty ip address from lookup command. " + << "CEF Domain: " + << cef_address + << "Got bad ip address: " + << res.unpack(); + return; + } + + cef_address = res.unpack(); + } + socket = i_socket->genSocket( - I_Socket::SocketType::UDP, + protocol, false, false, - cef_ip_address + ":" + to_string(cef_port) + cef_address + ":" + to_string(cef_port) ); } diff --git a/core/logging/k8s_svc_stream.cc b/core/logging/k8s_svc_stream.cc new file mode 100644 index 0000000..8ad9daf --- /dev/null +++ b/core/logging/k8s_svc_stream.cc @@ -0,0 +1,97 @@ +// Copyright (C) 2022 Check Point Software Technologies Ltd. All rights reserved. + +// Licensed under the Apache License, Version 2.0 (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 "log_streams.h" +#include "logging_comp.h" + +using namespace std; + +const static string default_host = "open-appsec-tuning-svc"; +const static string default_bulk_uri = "/api/v1/agents/events/bulk"; +const static string default_log_uri = "/api/v1/agents/events"; + +USE_DEBUG_FLAG(D_REPORT); + +K8sSvcStream::K8sSvcStream() + : + i_msg(Singleton::Consume::by()) +{ +} + +K8sSvcStream::~K8sSvcStream() +{ +} + +string +K8sSvcStream::genHeader() +{ + return "X-Tenant-Id: " + Singleton::Consume::by()->getTenantId(); +} + +void +K8sSvcStream::sendLog(const Report &log) +{ + auto svc_host = getConfigurationWithDefault(default_host, "Logging", "K8sSvc Log host"); + auto K8sSvc_log_uri = getConfigurationWithDefault(default_log_uri, "Logging", "K8sSvc Log URI"); + LogRest rest(log); + Flags conn_flags; + conn_flags.setFlag(MessageConnConfig::EXTERNAL); + + bool ok = i_msg->sendNoReplyObject( + rest, + I_Messaging::Method::POST, + svc_host, + 80, + conn_flags, + K8sSvc_log_uri, + genHeader(), + nullptr, + MessageTypeTag::LOG + ); + + if (!ok) { + dbgWarning(D_REPORT) << "failed to send log"; + } +} + +void +K8sSvcStream::sendLog(const LogBulkRest &logs, bool persistence_only) +{ + dbgFlow(D_REPORT) << "send bulk logs"; + + if (persistence_only) { + dbgWarning(D_REPORT) << "Skipping logs due to persistence only setting"; + return; + } + + auto svc_host = getConfigurationWithDefault(default_host, "Logging", "K8sSvc Log host"); + auto K8sSvc_log_uri = getConfigurationWithDefault(default_bulk_uri, "Logging", "K8sSvc Bulk Log URI"); + Flags conn_flags; + conn_flags.setFlag(MessageConnConfig::EXTERNAL); + + bool ok = i_msg->sendNoReplyObject( + logs, + I_Messaging::Method::POST, + svc_host, + 80, + conn_flags, + K8sSvc_log_uri, + genHeader(), + nullptr, + MessageTypeTag::LOG + ); + + if (!ok) { + dbgWarning(D_REPORT) << "failed to send bulk logs"; + } +} diff --git a/core/logging/log_streams.h b/core/logging/log_streams.h index a62a48d..d620dc0 100755 --- a/core/logging/log_streams.h +++ b/core/logging/log_streams.h @@ -80,10 +80,24 @@ private: I_Messaging *i_msg = nullptr; }; +class K8sSvcStream : public Stream +{ +public: + K8sSvcStream(); + ~K8sSvcStream(); + + void sendLog(const Report &log) override; + void sendLog(const LogBulkRest &logs, bool persistance_only) override; + +private: + std::string genHeader(); + I_Messaging *i_msg = nullptr; +}; + class SyslogStream : public Stream { public: - SyslogStream(const std::string &_ip_address, int _port); + SyslogStream(const std::string &_address, int _port, I_Socket::SocketType protocol); ~SyslogStream(); void sendLog(const Report &log) override; @@ -93,8 +107,9 @@ private: I_Socket *i_socket = nullptr; I_MainLoop *mainloop = nullptr; - std::string ip_address; + std::string address; int port; + I_Socket::SocketType protocol = I_Socket::SocketType::UDP; I_MainLoop::RoutineID log_send_routine = -1; Maybe socket = genError("Not set yet"); }; @@ -102,7 +117,7 @@ private: class CefStream : public Stream { public: - CefStream(const std::string &_ip_address, int _port); + CefStream(const std::string &_address, int _port, I_Socket::SocketType _protocol); ~CefStream(); void sendLog(const Report &log) override; @@ -111,8 +126,9 @@ private: void connect(); I_Socket *i_socket = nullptr; - std::string ip_address; + std::string address; int port; + I_Socket::SocketType protocol = I_Socket::SocketType::UDP; Maybe socket = genError("Not set yet"); }; diff --git a/core/logging/logging.cc b/core/logging/logging.cc index 0473e81..68d6fd9 100755 --- a/core/logging/logging.cc +++ b/core/logging/logging.cc @@ -111,7 +111,11 @@ public: } bool - addStream(ReportIS::StreamType type, const string &log_server_url) override + addStream( + ReportIS::StreamType type, + const string &log_server_url, + const string &_protocol + ) override { string log_type = TagAndEnumManagement::convertToString(type); if (streams_preperation.find(type) != streams_preperation.end()) { @@ -124,8 +128,9 @@ public: string ip = log_server_url.substr(0, log_server_url.find(':')); string port = log_server_url.substr(log_server_url.find(':') + 1, log_server_url.length()); int port_num = stoi(port); + auto protocol = (_protocol == "TCP") ? I_Socket::SocketType::TCP : I_Socket::SocketType::UDP; - streams_preperation[type] = makeStream(type, ip, port_num); + streams_preperation[type] = makeStream(type, ip, port_num, protocol); dbgInfo(D_REPORT) << "Successfully added log stream. Stream type: " << log_type @@ -265,6 +270,7 @@ private: case StreamType::JSON_DEBUG: return make_shared(); case StreamType::JSON_FOG: return make_shared(); case StreamType::JSON_LOG_FILE: return make_shared(); + case StreamType::JSON_K8S_SVC: return make_shared(); case StreamType::SYSLOG: return nullptr; case StreamType::CEF: return nullptr; case StreamType::NONE: return nullptr; @@ -275,12 +281,11 @@ private: } shared_ptr - makeStream(StreamType type, const string &ip, int port) + makeStream(StreamType type, const string &ip, int port, I_Socket::SocketType protocol) { switch (type) { - case StreamType::SYSLOG: - return make_shared(ip, port); - case StreamType::CEF: return make_shared(ip, port); + case StreamType::SYSLOG: return make_shared(ip, port, protocol); + case StreamType::CEF: return make_shared(ip, port, protocol); default: dbgWarning(D_REPORT) << "Invalid stream type with url"; return NULL; diff --git a/core/logging/logging_ut/logging_ut.cc b/core/logging/logging_ut/logging_ut.cc index 61c0385..d28637d 100755 --- a/core/logging/logging_ut/logging_ut.cc +++ b/core/logging/logging_ut/logging_ut.cc @@ -21,6 +21,7 @@ #include "mock/mock_encryptor.h" #include "mock/mock_agent_details.h" #include "metric/all_metric_event.h" +#include "mock/mock_shell_cmd.h" #include "version.h" using namespace testing; @@ -33,6 +34,7 @@ class TestEnd {}; static bool should_fail = false; static bool should_load_file_stream = false; +static bool should_load_k8s_stream = false; class fakeConfig : Singleton::Consume { @@ -57,19 +59,45 @@ public: } void - load(cereal::JSONInputArchive &) + load(cereal::JSONInputArchive &ar) { if (should_fail) throw cereal::Exception("Should fail load"); if (should_load_file_stream) { Singleton::Consume::by()->addStream(ReportIS::StreamType::JSON_LOG_FILE); return; } + if (should_load_k8s_stream) { + Singleton::Consume::by()->addStream(ReportIS::StreamType::JSON_K8S_SVC); + return; + } Singleton::Consume::by()->addStream(ReportIS::StreamType::JSON_DEBUG); Singleton::Consume::by()->addStream(ReportIS::StreamType::JSON_FOG); - Singleton::Consume::by()->addStream(ReportIS::StreamType::CEF, "1.3.3.0:123"); - Singleton::Consume::by()->addStream(ReportIS::StreamType::SYSLOG, "1.2.3.4:567"); - } + bool is_domain; + ar(cereal::make_nvp("IsDomain", is_domain)); + if (is_domain) { + Singleton::Consume::by()->addStream( + ReportIS::StreamType::CEF, + "www.youtube.com:123", + "UDP" + ); + Singleton::Consume::by()->addStream( + ReportIS::StreamType::SYSLOG, + "www.google.com:567", + "UDP" + ); + } else { + Singleton::Consume::by()->addStream( + ReportIS::StreamType::CEF, + "1.3.3.0:123", "UDP" + ); + Singleton::Consume::by()->addStream( + ReportIS::StreamType::SYSLOG, + "1.2.3.4:567", + "UDP" + ); + } + } }; class LogTest : public testing::TestWithParam @@ -81,8 +109,10 @@ public: i_agent_details(Singleton::Consume::from(agent_details)), logger(Singleton::Consume::from(log_comp)) { + is_domain = false; should_fail = false; should_load_file_stream = false; + should_load_k8s_stream = false; env.preload(); log_comp.preload(); env.init(); @@ -143,8 +173,10 @@ public: ~LogTest() { + is_domain = false; should_fail = false; should_load_file_stream = false; + should_load_k8s_stream = false; env.fini(); log_comp.fini(); Debug::setUnitTestFlag(D_REPORT, Debug::DebugLevel::INFO); @@ -208,15 +240,23 @@ public: } bool - loadFakeConfiguration(const bool &enable_bulk, const string &log_file_name = "", int bulks_size = -1) + loadFakeConfiguration( + bool enable_bulk, + bool domain = false, + const string &log_file_name = "", + int bulks_size = -1) { string is_enable_bulks = enable_bulk ? "true" : "false"; + string is_domain = domain ? "true" : "false"; fakeConfig::preload(); output_filename = log_file_name == "" ? file.fname : log_file_name; stringstream str_stream; str_stream - << "{\"fake config\": [{}], \"Logging\": {\"Log file name\": [{\"value\": \"" + << "{\"fake config\": [{\"IsDomain\": " + << is_domain + << "}]," + << "\"Logging\": {\"Log file name\": [{\"value\": \"" << output_filename << "\"}]," << "\"Enable bulk of logs\": [{\"value\": " @@ -247,6 +287,8 @@ public: ConfigComponent config; vector capture_syslog_cef_data; I_MainLoop::Routine sysog_routine = nullptr; + StrictMock mock_shell_cmd; + bool is_domain; private: string body; @@ -259,6 +301,16 @@ TEST_F(LogTest, load_policy) EXPECT_TRUE(loadFakeConfiguration(false)); } +TEST_F(LogTest, loadPolicyDomain) +{ + is_domain = true; + string result = "172.28.1.6"; + EXPECT_CALL(mock_shell_cmd, getExecOutput(_, _, _)).WillRepeatedly(Return(result)); + EXPECT_TRUE(loadFakeConfiguration(false, true)); + string failed_str = "Failed to connect to the CEF server"; + EXPECT_THAT(getMessages(), Not(HasSubstr(failed_str))); +} + TEST_F(LogTest, loadPolicyFailure) { should_fail = true; @@ -690,9 +742,117 @@ TEST_F(LogTest, FogBulkLogs) EXPECT_EQ(local_body, str1); } +TEST_F(LogTest, OfflineK8sSvcTest) +{ + i_agent_details->setOrchestrationMode(OrchestrationMode::HYBRID); + should_load_k8s_stream = true; + loadFakeConfiguration(false); + Tags tag1 = Tags::POLICY_INSTALLATION; + Tags tag2 = Tags::ACCESS_CONTROL; + string local_body; + string res("[{\"id\": 1, \"code\": 400, \"message\": \"yes\"}]"); + EXPECT_CALL( + mock_fog_msg, + sendMessage(_, _, _, "open-appsec-tuning-svc", _, _, "/api/v1/agents/events", _, _, MessageTypeTag::LOG) + ).WillRepeatedly(DoAll(SaveArg<1>(&local_body), Return(res))); + + string str1( + "{\n" + " \"log\": {\n" + " \"eventTime\": \"0:0:0\",\n" + " \"eventName\": \"Install policy\",\n" + " \"eventSeverity\": \"Info\",\n" + " \"eventPriority\": \"Low\",\n" + " \"eventType\": \"Event Driven\",\n" + " \"eventLevel\": \"Log\",\n" + " \"eventLogLevel\": \"info\",\n" + " \"eventAudience\": \"Internal\",\n" + " \"eventAudienceTeam\": \"\",\n" + " \"eventFrequency\": 0,\n" + " \"eventTags\": [\n" + " \"Access Control\",\n" + " \"Policy Installation\"\n" + " ],\n" + " \"eventSource\": {\n" + " \"agentId\": \"Unknown\",\n" + " \"eventTraceId\": \"\",\n" + " \"eventSpanId\": \"\",\n" + " \"issuingEngineVersion\": \"\",\n" + " \"serviceName\": \"Unnamed Nano Service\"\n" + " },\n" + " \"eventData\": {\n" + " \"logIndex\": 1\n" + " }\n" + " }\n" + "}" + ); + + LogGen("Install policy", Audience::INTERNAL, Severity::INFO, Priority::LOW, tag1, tag2); + EXPECT_EQ(local_body, str1); +} + +TEST_F(LogTest, OfflineK8sSvcBulkLogs) +{ + i_agent_details->setOrchestrationMode(OrchestrationMode::HYBRID); + should_load_k8s_stream = true; + loadFakeConfiguration(true); + string local_body; + string res("[{\"id\": 1, \"code\": 400, \"message\": \"yes\"}]"); + EXPECT_CALL( + mock_fog_msg, + sendMessage(_, _, _, "open-appsec-tuning-svc", _, _, "/api/v1/agents/events/bulk", _, _, MessageTypeTag::LOG) + ).WillRepeatedly(DoAll(SaveArg<1>(&local_body), Return(res))); + + Tags tag1 = Tags::POLICY_INSTALLATION; + Tags tag2 = Tags::ACCESS_CONTROL; + + + string str1( + "{\n" + " \"logs\": [\n" + " {\n" + " \"id\": 1,\n" + " \"log\": {\n" + " \"eventTime\": \"0:0:0\",\n" + " \"eventName\": \"Install policy\",\n" + " \"eventSeverity\": \"Info\",\n" + " \"eventPriority\": \"Low\",\n" + " \"eventType\": \"Event Driven\",\n" + " \"eventLevel\": \"Log\",\n" + " \"eventLogLevel\": \"info\",\n" + " \"eventAudience\": \"Internal\",\n" + " \"eventAudienceTeam\": \"\",\n" + " \"eventFrequency\": 0,\n" + " \"eventTags\": [\n" + " \"Access Control\",\n" + " \"Policy Installation\"\n" + " ],\n" + " \"eventSource\": {\n" + " \"agentId\": \"Unknown\",\n" + " \"eventTraceId\": \"\",\n" + " \"eventSpanId\": \"\",\n" + " \"issuingEngineVersion\": \"\",\n" + " \"serviceName\": \"Unnamed Nano Service\"\n" + " },\n" + " \"eventData\": {\n" + " \"logIndex\": 1\n" + " }\n" + " }\n" + " }\n" + " ]\n" + "}" + ); + { + LogGen("Install policy", Audience::INTERNAL, Severity::INFO, Priority::LOW, tag1, tag2); + } + bulk_routine(); + + EXPECT_EQ(local_body, str1); +} + TEST_P(LogTest, metrics_check) { - loadFakeConfiguration(true, "", 3); + loadFakeConfiguration(true, false, "", 3); Tags tag1 = Tags::POLICY_INSTALLATION; Tags tag2 = Tags::ACCESS_CONTROL; @@ -837,7 +997,7 @@ TEST_F(LogTest, ShouldRetryAfterFailedWriteToFile) EXPECT_TRUE(logger->delStream(ReportIS::StreamType::JSON_LOG_FILE)); static const string invalid_file_path = "/proc/gibberish"; - loadFakeConfiguration(false, invalid_file_path, -1); + loadFakeConfiguration(false, false, invalid_file_path, -1); LogGen( "Install policy", diff --git a/core/logging/syslog_stream.cc b/core/logging/syslog_stream.cc index db885bf..b452cef 100755 --- a/core/logging/syslog_stream.cc +++ b/core/logging/syslog_stream.cc @@ -11,6 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include + #include "log_streams.h" #include "logging_comp.h" @@ -18,12 +20,17 @@ using namespace std; USE_DEBUG_FLAG(D_REPORT); -SyslogStream::SyslogStream(const string &_ip_address, int _port) +static string lookup_cmd = "nslookup "; +static string line_selection_cmd = "| grep Address | sed -n 2p"; +static string parsing_cmd = "| cut -f2 -d' ' | tr -d '\n'"; + +SyslogStream::SyslogStream(const string &_address, int _port, I_Socket::SocketType _protocol) : i_socket(Singleton::Consume::by()), mainloop(Singleton::Consume::by()), - ip_address(_ip_address), - port(_port) + address(_address), + port(_port), + protocol(_protocol) { connect(); if (!socket.ok()) { @@ -43,21 +50,21 @@ SyslogStream::~SyslogStream() void SyslogStream::sendLog(const Report &log) { - if (!socket.ok()) { - connect(); - if (!socket.ok()) { - dbgWarning(D_REPORT) << "Failed to connect to the syslog server, Log will not be sent."; - return; - } - dbgTrace(D_REPORT) << "Successfully connect to the syslog server"; - } - string syslog_report = log.getSyslog(); vector data(syslog_report.begin(), syslog_report.end()); mainloop->addOneTimeRoutine( I_MainLoop::RoutineType::Offline, [this, data] () { + if (!socket.ok()) { + connect(); + if (!socket.ok()) { + dbgWarning(D_REPORT) << "Failed to connect to the syslog server, Log will not be sent."; + return; + } + dbgTrace(D_REPORT) << "Successfully connect to the syslog server"; + } + int tries = 1; for (; tries <=3; tries++) { if (i_socket->writeData(socket.unpack(), data)) { @@ -75,18 +82,57 @@ SyslogStream::sendLog(const Report &log) void SyslogStream::connect() { - auto syslog_ip_address = getProfileAgentSettingWithDefault(ip_address, "agent.config.log.syslogServer.IP"); + auto syslog_address = getProfileAgentSettingWithDefault(address, "agent.config.log.syslogServer.IP"); auto syslog_port = getProfileAgentSettingWithDefault(port, "agent.config.log.syslogServer.port"); - if (syslog_ip_address.empty()) { - dbgWarning(D_REPORT) << "Cannot connect to Syslog server, IP is not configured."; + if (syslog_address.empty()) { + dbgWarning(D_REPORT) << "Cannot connect to Syslog server, Address IP/Domain not configured."; return; } + struct in_addr addr; + if (inet_pton(AF_INET, syslog_address.data(), &addr) != 1) { + I_ShellCmd *shell_cmd = Singleton::Consume::by(); + string host_cmd = lookup_cmd + syslog_address + line_selection_cmd + parsing_cmd; + Maybe res = shell_cmd->getExecOutput(host_cmd, 500); + if (!res.ok()) { + dbgWarning(D_REPORT) + << "Failed to execute domain lookup command. " + << "SYSLOG Domain: " + << syslog_address + << "Error: " + << res.getErr(); + return; + } + + if (res.unpack().empty()) { + dbgWarning(D_REPORT) + << "Got en empty ip address from lookup command. " + << "SYSLOG Domain: " + << syslog_address + << "Got bad ip address: " + << res.unpack(); + return; + } + + dbgDebug(D_REPORT) << "SYSLOG Domain lookup result: " << res.unpack(); + if (inet_pton(AF_INET, res.unpack().data(), &addr) != 1) { + dbgWarning(D_REPORT) + << "Got a faulty ip address from lookup command. " + << "SYSLOG Domain: " + << syslog_address + << "Got bad ip address: " + << res.unpack(); + return; + } + + syslog_address = res.unpack(); + } + socket = i_socket->genSocket( - I_Socket::SocketType::UDP, + protocol, false, false, - syslog_ip_address + ":" + to_string(syslog_port) + syslog_address + ":" + to_string(syslog_port) ); } diff --git a/core/report/tag_and_enum_management.cc b/core/report/tag_and_enum_management.cc index c99aa0a..931d13e 100755 --- a/core/report/tag_and_enum_management.cc +++ b/core/report/tag_and_enum_management.cc @@ -98,7 +98,8 @@ TagAndEnumManagement::convertStringToTag(const string &tag) {"Reverse Proxy", ReportIS::Tags::REVERSE_PROXY}, {"Http Geo Filter", ReportIS::Tags::HTTP_GEO_FILTER}, {"File Upload", ReportIS::Tags::FILE_UPLOAD}, - {"Identity Awareness", ReportIS::Tags::IDENTITY_AWARENESS} + {"Identity Awareness", ReportIS::Tags::IDENTITY_AWARENESS}, + {"Rate Limit", ReportIS::Tags::RATE_LIMIT} }; auto report_is_tag = strings_to_tags.find(tag); @@ -135,6 +136,7 @@ TagAndEnumManagement::convertToString(const StreamType &stream_type) case StreamType::JSON_DEBUG: return "JSON Debug stream"; case StreamType::JSON_FOG: return "JSON FOG stream"; case StreamType::JSON_LOG_FILE: return "JSON File stream"; + case StreamType::JSON_K8S_SVC: return "JSON K8S service stream"; case StreamType::SYSLOG: return "Syslog stream"; case StreamType::CEF: return "CEF stream"; @@ -307,7 +309,8 @@ EnumArray TagAndEnumManagement::tags_translation_arr { "Reverse Proxy", "Http Geo Filter", "File Upload", - "Identity Awareness" + "Identity Awareness", + "Rate Limit" }; EnumArray TagAndEnumManagement::audience_team_translation { diff --git a/core/tenant_manager/tenant_manager.cc b/core/tenant_manager/tenant_manager.cc index 95a45e7..8da40aa 100644 --- a/core/tenant_manager/tenant_manager.cc +++ b/core/tenant_manager/tenant_manager.cc @@ -49,6 +49,8 @@ public: chrono::microseconds getTimeoutVal() const override; + string getProfileId(const string &tenant_id, const string ®ion) const override; + void addInstance(const string &tenant_id, const string &profile_id, const string &instace_id) { @@ -183,7 +185,7 @@ TenantManager::Impl::init() auto rest = Singleton::Consume::by(); rest->addRestCall(RestAction::SET, "tenant-id"); rest->addRestCall(RestAction::SHOW, "active-tenants"); - rest->addRestCall(RestAction::SHOW, "profile-ids"); + rest->addRestCall(RestAction::SHOW, "profile-ids"); } if (type == TenantManagerType::CLIENT) { @@ -307,14 +309,14 @@ TenantManager::Impl::getAllTenants() const } vector -TenantManager::Impl::getProfileIds(const string &tenant_id) const +TenantManager::Impl::getProfileIds(const string &_tenant_id) const { - dbgFlow(D_TENANT_MANAGER) << "Tenant Manager is a client. Requesting the active tenants"; + dbgFlow(D_TENANT_MANAGER) << "Tenant Manager is a client. Requesting the active profiles"; - GetProfileIds profile_id(tenant_id); + GetProfileIds tenant_id(_tenant_id); auto res = i_messaging->sendObject( - profile_id, + tenant_id, I_Messaging::Method::POST, "127.0.0.1", 7777, @@ -324,7 +326,7 @@ TenantManager::Impl::getProfileIds(const string &tenant_id) const if (!res) { i_messaging->sendObject( - profile_id, + tenant_id, I_Messaging::Method::POST, "127.0.0.1", 7778, @@ -333,7 +335,53 @@ TenantManager::Impl::getProfileIds(const string &tenant_id) const ); } - return profile_id.profile_ids.get(); + return tenant_id.profile_ids.get(); +} + +string +TenantManager::Impl::getProfileId(const string &tenant_id, const string ®ion) const +{ + if (region.empty()) { + dbgWarning(D_TENANT_MANAGER) << "Can't find the profile ID. Region is empty"; + return ""; + } + + vector profile_ids = fetchProfileIds(tenant_id); + + dbgTrace(D_TENANT_MANAGER) << "Fetched " << profile_ids.size() << " profiles"; + + auto i_env = Singleton::Consume::by(); + auto unset_tenant_on_exit = make_scope_exit([&]() { i_env->unsetActiveTenantAndProfile(); }); + for (const string &profile_id : profile_ids) { + dbgDebug(D_TENANT_MANAGER) + << "Checking if the profile ID: " + << profile_id + << " corresponds to the tenant ID: " + << tenant_id + << " and the region " + << region; + + i_env->setActiveTenantAndProfile(tenant_id, profile_id); + + auto maybe_region = getSetting("region"); + if (maybe_region.ok() && region == maybe_region.unpack()) { + dbgDebug(D_TENANT_MANAGER) << "The region corresponds to profile ID " << profile_id; + return profile_id; + } else { + if (maybe_region.ok()) { + dbgTrace(D_TENANT_MANAGER) + << "The region does not corresponds to profile ID " + << profile_id + << " region " + << *maybe_region; + } else { + dbgDebug(D_TENANT_MANAGER) << "Failed to get region for profile ID " << profile_id; + } + } + } + + dbgWarning(D_TENANT_MANAGER) << "Found no profile ID for tenant " << tenant_id << " and region " << region; + return ""; } void @@ -351,7 +399,16 @@ TenantManager::Impl::areTenantAndProfileActive(const string &tenant_id, const st void TenantManager::Impl::addActiveTenantAndProfile(const string &tenant_id, const string &profile_id) { + if (tenant_id.empty() || profile_id.empty()) { + dbgWarning(D_TENANT_MANAGER) << "Tenant ID and Profile ID should not be empty."; + return; + } auto tenant_profile = TenantProfilePair(tenant_id, profile_id); + dbgTrace(D_TENANT_MANAGER) + << "Adding an active tenant and profile. Tenant ID: " + << tenant_id + << ", Profile ID: " + << profile_id; active_tenants.createEntry(tenant_profile); if (type == TenantManagerType::CLIENT) { sendTenantAndProfile(tenant_id, profile_id); @@ -410,7 +467,8 @@ TenantManager::Impl::fetchAllProfileIds(const string &tenant_id) const for (auto iter = begin(active_tenants); iter != end(active_tenants); iter++) { if (iter->first.getTenantId() == tenant_id) { - tenant_profile_ids.push_back(iter->first.getPfofileId()); + dbgTrace(D_TENANT_MANAGER) << "Returning a fetched profile ID: " << iter->first.getProfileId(); + tenant_profile_ids.push_back(iter->first.getProfileId()); } } return tenant_profile_ids; @@ -419,7 +477,7 @@ TenantManager::Impl::fetchAllProfileIds(const string &tenant_id) const vector TenantManager::Impl::fetchProfileIds(const string &tenant_id) const { - dbgFlow(D_TENANT_MANAGER) << "Fetching all profile ids for tenant " << tenant_id; + dbgFlow(D_TENANT_MANAGER) << "Fetching all profile IDs for tenant " << tenant_id; return (type == TenantManagerType::CLIENT) ? getProfileIds(tenant_id) : fetchAllProfileIds(tenant_id); } @@ -462,4 +520,5 @@ TenantManager::preload() { registerExpectedConfiguration("Tenant Manager", "Tenant timeout"); registerExpectedConfiguration("Tenant Manager", "Tenant manager type"); + registerExpectedSetting("region"); } diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 8f67e96..1cd077d 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -1,2 +1,3 @@ +add_subdirectory(graphqlparser) add_subdirectory(yajl) add_subdirectory(yq) diff --git a/external/graphqlparser/.clang-tidy b/external/graphqlparser/.clang-tidy new file mode 100644 index 0000000..c54e3df --- /dev/null +++ b/external/graphqlparser/.clang-tidy @@ -0,0 +1,326 @@ +--- +Checks: 'clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,cppcoreguidelines*,modernize*,performance*,readability*,google*,-cppcoreguidelines-pro-type-cstyle-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-readability-implicit-bool*,-cppcoreguidelines-pro-bounds-array-to-pointer-decay' +WarningsAsErrors: '' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +CheckOptions: + - key: cert-oop11-cpp.UseCERTSemantics + value: '1' + - key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader + value: '' + - key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle + value: '0' + - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays + value: '0' + - key: google-readability-braces-around-statements.ShortStatementLines + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-use-auto.RemoveStars + value: '0' + - key: modernize-use-emplace.ContainersWithPushBack + value: '::std::vector;::std::list;::std::deque' + - key: modernize-use-emplace.SmartPointers + value: '::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr' + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + - key: performance-faster-string-find.StringLikeClasses + value: 'std::basic_string' + - key: performance-for-range-copy.WarnOnAllAutoCopies + value: '0' + - key: performance-unnecessary-value-param.IncludeStyle + value: llvm + - key: readability-braces-around-statements.ShortStatementLines + value: '0' + - key: readability-function-size.BranchThreshold + value: '4294967295' + - key: readability-function-size.LineThreshold + value: '4294967295' + - key: readability-function-size.StatementThreshold + value: '800' + - key: readability-identifier-naming.AbstractClassCase + value: aNy_CasE + - key: readability-identifier-naming.AbstractClassPrefix + value: '' + - key: readability-identifier-naming.AbstractClassSuffix + value: '' + - key: readability-identifier-naming.ClassCase + value: aNy_CasE + - key: readability-identifier-naming.ClassConstantCase + value: aNy_CasE + - key: readability-identifier-naming.ClassConstantPrefix + value: '' + - key: readability-identifier-naming.ClassConstantSuffix + value: '' + - key: readability-identifier-naming.ClassMemberCase + value: aNy_CasE + - key: readability-identifier-naming.ClassMemberPrefix + value: '' + - key: readability-identifier-naming.ClassMemberSuffix + value: '' + - key: readability-identifier-naming.ClassMethodCase + value: aNy_CasE + - key: readability-identifier-naming.ClassMethodPrefix + value: '' + - key: readability-identifier-naming.ClassMethodSuffix + value: '' + - key: readability-identifier-naming.ClassPrefix + value: '' + - key: readability-identifier-naming.ClassSuffix + value: '' + - key: readability-identifier-naming.ConstantCase + value: aNy_CasE + - key: readability-identifier-naming.ConstantMemberCase + value: aNy_CasE + - key: readability-identifier-naming.ConstantMemberPrefix + value: '' + - key: readability-identifier-naming.ConstantMemberSuffix + value: '' + - key: readability-identifier-naming.ConstantParameterCase + value: aNy_CasE + - key: readability-identifier-naming.ConstantParameterPrefix + value: '' + - key: readability-identifier-naming.ConstantParameterSuffix + value: '' + - key: readability-identifier-naming.ConstantPrefix + value: '' + - key: readability-identifier-naming.ConstantSuffix + value: '' + - key: readability-identifier-naming.ConstexprFunctionCase + value: aNy_CasE + - key: readability-identifier-naming.ConstexprFunctionPrefix + value: '' + - key: readability-identifier-naming.ConstexprFunctionSuffix + value: '' + - key: readability-identifier-naming.ConstexprMethodCase + value: aNy_CasE + - key: readability-identifier-naming.ConstexprMethodPrefix + value: '' + - key: readability-identifier-naming.ConstexprMethodSuffix + value: '' + - key: readability-identifier-naming.ConstexprVariableCase + value: aNy_CasE + - key: readability-identifier-naming.ConstexprVariablePrefix + value: '' + - key: readability-identifier-naming.ConstexprVariableSuffix + value: '' + - key: readability-identifier-naming.EnumCase + value: aNy_CasE + - key: readability-identifier-naming.EnumConstantCase + value: aNy_CasE + - key: readability-identifier-naming.EnumConstantPrefix + value: '' + - key: readability-identifier-naming.EnumConstantSuffix + value: '' + - key: readability-identifier-naming.EnumPrefix + value: '' + - key: readability-identifier-naming.EnumSuffix + value: '' + - key: readability-identifier-naming.FunctionCase + value: aNy_CasE + - key: readability-identifier-naming.FunctionPrefix + value: '' + - key: readability-identifier-naming.FunctionSuffix + value: '' + - key: readability-identifier-naming.GlobalConstantCase + value: aNy_CasE + - key: readability-identifier-naming.GlobalConstantPrefix + value: '' + - key: readability-identifier-naming.GlobalConstantSuffix + value: '' + - key: readability-identifier-naming.GlobalFunctionCase + value: aNy_CasE + - key: readability-identifier-naming.GlobalFunctionPrefix + value: '' + - key: readability-identifier-naming.GlobalFunctionSuffix + value: '' + - key: readability-identifier-naming.GlobalVariableCase + value: aNy_CasE + - key: readability-identifier-naming.GlobalVariablePrefix + value: '' + - key: readability-identifier-naming.GlobalVariableSuffix + value: '' + - key: readability-identifier-naming.IgnoreFailedSplit + value: '0' + - key: readability-identifier-naming.InlineNamespaceCase + value: aNy_CasE + - key: readability-identifier-naming.InlineNamespacePrefix + value: '' + - key: readability-identifier-naming.InlineNamespaceSuffix + value: '' + - key: readability-identifier-naming.LocalConstantCase + value: aNy_CasE + - key: readability-identifier-naming.LocalConstantPrefix + value: '' + - key: readability-identifier-naming.LocalConstantSuffix + value: '' + - key: readability-identifier-naming.LocalVariableCase + value: aNy_CasE + - key: readability-identifier-naming.LocalVariablePrefix + value: '' + - key: readability-identifier-naming.LocalVariableSuffix + value: '' + - key: readability-identifier-naming.MacroDefinitionCase + value: aNy_CasE + - key: readability-identifier-naming.MacroDefinitionPrefix + value: '' + - key: readability-identifier-naming.MacroDefinitionSuffix + value: '' + - key: readability-identifier-naming.MemberCase + value: aNy_CasE + - key: readability-identifier-naming.MemberPrefix + value: '' + - key: readability-identifier-naming.MemberSuffix + value: '' + - key: readability-identifier-naming.MethodCase + value: aNy_CasE + - key: readability-identifier-naming.MethodPrefix + value: '' + - key: readability-identifier-naming.MethodSuffix + value: '' + - key: readability-identifier-naming.NamespaceCase + value: aNy_CasE + - key: readability-identifier-naming.NamespacePrefix + value: '' + - key: readability-identifier-naming.NamespaceSuffix + value: '' + - key: readability-identifier-naming.ParameterCase + value: aNy_CasE + - key: readability-identifier-naming.ParameterPackCase + value: aNy_CasE + - key: readability-identifier-naming.ParameterPackPrefix + value: '' + - key: readability-identifier-naming.ParameterPackSuffix + value: '' + - key: readability-identifier-naming.ParameterPrefix + value: '' + - key: readability-identifier-naming.ParameterSuffix + value: '' + - key: readability-identifier-naming.PrivateMemberCase + value: aNy_CasE + - key: readability-identifier-naming.PrivateMemberPrefix + value: '' + - key: readability-identifier-naming.PrivateMemberSuffix + value: '' + - key: readability-identifier-naming.PrivateMethodCase + value: aNy_CasE + - key: readability-identifier-naming.PrivateMethodPrefix + value: '' + - key: readability-identifier-naming.PrivateMethodSuffix + value: '' + - key: readability-identifier-naming.ProtectedMemberCase + value: aNy_CasE + - key: readability-identifier-naming.ProtectedMemberPrefix + value: '' + - key: readability-identifier-naming.ProtectedMemberSuffix + value: '' + - key: readability-identifier-naming.ProtectedMethodCase + value: aNy_CasE + - key: readability-identifier-naming.ProtectedMethodPrefix + value: '' + - key: readability-identifier-naming.ProtectedMethodSuffix + value: '' + - key: readability-identifier-naming.PublicMemberCase + value: aNy_CasE + - key: readability-identifier-naming.PublicMemberPrefix + value: '' + - key: readability-identifier-naming.PublicMemberSuffix + value: '' + - key: readability-identifier-naming.PublicMethodCase + value: aNy_CasE + - key: readability-identifier-naming.PublicMethodPrefix + value: '' + - key: readability-identifier-naming.PublicMethodSuffix + value: '' + - key: readability-identifier-naming.StaticConstantCase + value: aNy_CasE + - key: readability-identifier-naming.StaticConstantPrefix + value: '' + - key: readability-identifier-naming.StaticConstantSuffix + value: '' + - key: readability-identifier-naming.StaticVariableCase + value: aNy_CasE + - key: readability-identifier-naming.StaticVariablePrefix + value: '' + - key: readability-identifier-naming.StaticVariableSuffix + value: '' + - key: readability-identifier-naming.StructCase + value: aNy_CasE + - key: readability-identifier-naming.StructPrefix + value: '' + - key: readability-identifier-naming.StructSuffix + value: '' + - key: readability-identifier-naming.TemplateParameterCase + value: aNy_CasE + - key: readability-identifier-naming.TemplateParameterPrefix + value: '' + - key: readability-identifier-naming.TemplateParameterSuffix + value: '' + - key: readability-identifier-naming.TemplateTemplateParameterCase + value: aNy_CasE + - key: readability-identifier-naming.TemplateTemplateParameterPrefix + value: '' + - key: readability-identifier-naming.TemplateTemplateParameterSuffix + value: '' + - key: readability-identifier-naming.TypeAliasCase + value: aNy_CasE + - key: readability-identifier-naming.TypeAliasPrefix + value: '' + - key: readability-identifier-naming.TypeAliasSuffix + value: '' + - key: readability-identifier-naming.TypeTemplateParameterCase + value: aNy_CasE + - key: readability-identifier-naming.TypeTemplateParameterPrefix + value: '' + - key: readability-identifier-naming.TypeTemplateParameterSuffix + value: '' + - key: readability-identifier-naming.TypedefCase + value: aNy_CasE + - key: readability-identifier-naming.TypedefPrefix + value: '' + - key: readability-identifier-naming.TypedefSuffix + value: '' + - key: readability-identifier-naming.UnionCase + value: aNy_CasE + - key: readability-identifier-naming.UnionPrefix + value: '' + - key: readability-identifier-naming.UnionSuffix + value: '' + - key: readability-identifier-naming.ValueTemplateParameterCase + value: aNy_CasE + - key: readability-identifier-naming.ValueTemplateParameterPrefix + value: '' + - key: readability-identifier-naming.ValueTemplateParameterSuffix + value: '' + - key: readability-identifier-naming.VariableCase + value: aNy_CasE + - key: readability-identifier-naming.VariablePrefix + value: '' + - key: readability-identifier-naming.VariableSuffix + value: '' + - key: readability-identifier-naming.VirtualMethodCase + value: aNy_CasE + - key: readability-identifier-naming.VirtualMethodPrefix + value: '' + - key: readability-identifier-naming.VirtualMethodSuffix + value: '' + - key: readability-simplify-boolean-expr.ChainedConditionalAssignment + value: '0' + - key: readability-simplify-boolean-expr.ChainedConditionalReturn + value: '0' +... + diff --git a/external/graphqlparser/.gitignore b/external/graphqlparser/.gitignore new file mode 100644 index 0000000..a00499c --- /dev/null +++ b/external/graphqlparser/.gitignore @@ -0,0 +1,23 @@ +bison.tab.cpp +bison.tab.hpp +*.o +parser.output +dump_json_ast +Ast.h +Ast.cpp +AstVisitor.h +*.dSYM +CMakeCache.txt +CMakeFiles +CMakeScripts +Makefile +cmake_install.cmake +*.a +*.dylib +*.so +GraphQLParser.py +install_manifest.txt +build/ +libgraphqlparser.pc +JsonVisitor.cpp.inc +JsonVisitor.h.inc diff --git a/external/graphqlparser/.travis.yml b/external/graphqlparser/.travis.yml new file mode 100644 index 0000000..ef9c576 --- /dev/null +++ b/external/graphqlparser/.travis.yml @@ -0,0 +1,21 @@ +language: cpp + +compiler: + - clang + - gcc + + +addons: + apt: + packages: + - valgrind + +before_install: + # Versions of g++ prior to 4.8 don't have very good C++11 support. + - wget https://codeload.github.com/google/googletest/zip/release-1.8.0 + && cd test + && unzip ../release-1.8.0 + && cd .. + && rm release-1.8.0 + +script: mkdir build && cd build && cmake .. -Dtest=ON -DCMAKE_BUILD_TYPE=Debug && make && test/runTests && make memcheck diff --git a/external/graphqlparser/AstNode.h b/external/graphqlparser/AstNode.h new file mode 100644 index 0000000..ebc2df5 --- /dev/null +++ b/external/graphqlparser/AstNode.h @@ -0,0 +1,36 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include "location.hh" + +namespace facebook { +namespace graphql { +namespace ast { + +namespace visitor { +class AstVisitor; +} + +class Node { + yy::location location_; +public: + explicit Node(const yy::location &location) + : location_(location) {} + + virtual ~Node() {} + + const yy::location &getLocation() const + { return location_; } + + virtual void accept(visitor::AstVisitor *visitor) const = 0; +}; + +} +} +} diff --git a/external/graphqlparser/CMakeLists.txt b/external/graphqlparser/CMakeLists.txt new file mode 100644 index 0000000..ede39fb --- /dev/null +++ b/external/graphqlparser/CMakeLists.txt @@ -0,0 +1,148 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +PROJECT(libgraphqlparser C CXX) + +SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}") + +INCLUDE(version) + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") + +FIND_PACKAGE(PythonInterp 2 REQUIRED) +IF (NOT PYTHON_VERSION_MAJOR EQUAL 2) + MESSAGE(FATAL_ERROR "Python 2 is required.") +ENDIF() + +FIND_PROGRAM(CTYPESGEN_FOUND ctypesgen.py) + +FIND_PACKAGE(BISON 3) +FIND_PACKAGE(FLEX) +IF (BISON_FOUND) + BISON_TARGET(graphqlparser_bison parser.ypp ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.cpp) + SET(BISON_LOCATION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/location.hh) +ELSE() + SET(BISON_graphqlparser_bison_OUTPUT_SOURCE ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.cpp) + SET(BISON_graphqlparser_bison_OUTPUT_HEADER ${CMAKE_CURRENT_BINARY_DIR}/parser.tab.hpp) + SET(BISON_graphqlparser_bison_OUTPUTS + ${BISON_graphqlparser_bison_OUTPUT_SOURCE} + ${BISON_graphqlparser_bison_OUTPUT_HEADER} + ${CMAKE_CURRENT_BINARY_DIR}/location.hh + ${CMAKE_CURRENT_BINARY_DIR}/position.hh + ${CMAKE_CURRENT_BINARY_DIR}/stack.hh) + SET(BISON_LOCATION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/location.hh) + FILE(COPY + ${CMAKE_CURRENT_SOURCE_DIR}/parsergen/parser.tab.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/parsergen/parser.tab.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/parsergen/location.hh + ${CMAKE_CURRENT_SOURCE_DIR}/parsergen/position.hh + ${CMAKE_CURRENT_SOURCE_DIR}/parsergen/stack.hh + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +ENDIF() + +IF(FLEX_FOUND) + FLEX_TARGET(GraphQLScanner lexer.lpp ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp COMPILE_FLAGS "--header-file=${CMAKE_CURRENT_BINARY_DIR}/lexer.h") + IF (BISON_FOUND) + ADD_FLEX_BISON_DEPENDENCY(GraphQLScanner graphqlparser_bison) + ENDIF() +ELSE() + SET(FLEX_GraphQLScanner_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp) + FILE(COPY + ${CMAKE_CURRENT_SOURCE_DIR}/parsergen/lexer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/parsergen/lexer.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +ENDIF() + +FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/c) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) + +ADD_LIBRARY(graphqlparser + JsonVisitor.cpp + ${CMAKE_CURRENT_BINARY_DIR}/Ast.h + ${CMAKE_CURRENT_BINARY_DIR}/Ast.cpp + ${CMAKE_CURRENT_BINARY_DIR}/AstVisitor.h + ${CMAKE_CURRENT_BINARY_DIR}/c/GraphQLAst.h + ${CMAKE_CURRENT_BINARY_DIR}/c/GraphQLAst.cpp + ${CMAKE_CURRENT_BINARY_DIR}/c/GraphQLAstForEachConcreteType.h + ${CMAKE_CURRENT_BINARY_DIR}/JsonVisitor.h.inc + ${CMAKE_CURRENT_BINARY_DIR}/JsonVisitor.cpp.inc + ${BISON_graphqlparser_bison_OUTPUTS} + ${FLEX_GraphQLScanner_OUTPUTS} + c/GraphQLAstNode.cpp + c/GraphQLAstToJSON.cpp + c/GraphQLAstVisitor.h + c/GraphQLAstVisitor.cpp + c/GraphQLParser.cpp + GraphQLParser.cpp) + +# Enable this and remove CMAKE_CXX_FLAGS fiddle above when we are able +# to upgrade to CMake 2.8.12. Blocker seems to be Travis CI being on +# Ubuntu Precise; Trusty has 2.8.12. +# TARGET_COMPILE_OPTIONS(graphqlparser PUBLIC -std=gnu++11) + +ADD_EXECUTABLE(dump_json_ast dump_json_ast.cpp) +TARGET_LINK_LIBRARIES(dump_json_ast graphqlparser) + +FUNCTION(GENERATE_AST_FILE FILE_TYPE FILE_RELATIVE_PATH) + ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${FILE_RELATIVE_PATH} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/ast/ast.py ${FILE_TYPE} ${CMAKE_CURRENT_SOURCE_DIR}/ast/ast.ast > ${CMAKE_CURRENT_BINARY_DIR}/${FILE_RELATIVE_PATH} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ast/ast.ast ${CMAKE_CURRENT_SOURCE_DIR}/ast/ast.py ${CMAKE_CURRENT_SOURCE_DIR}/ast/${FILE_TYPE}.py) +ENDFUNCTION(GENERATE_AST_FILE) + +GENERATE_AST_FILE(cxx Ast.h) + +GENERATE_AST_FILE(cxx_visitor AstVisitor.h) + +GENERATE_AST_FILE(cxx_impl Ast.cpp) + +GENERATE_AST_FILE(c c/GraphQLAst.h) + +GENERATE_AST_FILE(c_impl c/GraphQLAst.cpp) + +GENERATE_AST_FILE(c_visitor_impl c/GraphQLAstForEachConcreteType.h) + +GENERATE_AST_FILE(cxx_json_visitor_header JsonVisitor.h.inc) + +GENERATE_AST_FILE(cxx_json_visitor_impl JsonVisitor.cpp.inc) + +ADD_SUBDIRECTORY(python) + +OPTION(test "Build tests." OFF) + +INSTALL(DIRECTORY c ${CMAKE_CURRENT_BINARY_DIR}/c DESTINATION include/graphqlparser + FILES_MATCHING PATTERN "*.h" + PATTERN "build" EXCLUDE) + +INSTALL(FILES + ${CMAKE_CURRENT_BINARY_DIR}/Ast.h + AstNode.h + ${CMAKE_CURRENT_BINARY_DIR}/AstVisitor.h + GraphQLParser.h + JsonVisitor.h + ${BISON_LOCATION_HEADER} + DESTINATION include/graphqlparser) +INSTALL(TARGETS graphqlparser + LIBRARY DESTINATION lib) + +if (UNIX) + # generate pkgconfig file + include(FindPkgConfig QUIET) + if(PKG_CONFIG_FOUND) + # generate .pc and install + configure_file("libgraphqlparser.pc.in" "libgraphqlparser.pc" @ONLY) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libgraphqlparser.pc" + DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig") + endif() +endif() + +IF (test) + ADD_SUBDIRECTORY(test) + + if(UNIX) + # setup valgrind + ADD_CUSTOM_TARGET(memcheck + valgrind --leak-check=full --suppressions=./test/valgrind.supp --dsymutil=yes --error-exitcode=1 ./test/runTests >/dev/null + ) + endif() + +ENDIF() diff --git a/external/graphqlparser/CONTRIBUTING.md b/external/graphqlparser/CONTRIBUTING.md new file mode 100644 index 0000000..34cf598 --- /dev/null +++ b/external/graphqlparser/CONTRIBUTING.md @@ -0,0 +1,23 @@ +# Contributing to libgraphqlparser + +Please see the Code of Conduct featured at https://github.com/graphql/foundation + +## Pull Requests +We actively welcome your pull requests. + +1. Fork the repo and create your branch from `master`. +2. If you've added code that should be tested, add tests +3. If you've changed APIs, update the documentation. +4. Ensure the test suite passes. +5. Make sure your code lints. + +## Issues +We use GitHub issues to track public bugs. Please ensure your description is +clear and has sufficient instructions to be able to reproduce the issue. + +If you find a security bug, please contact the project administrators, +and do not file a public issue. + +## License +By contributing to libgraphqlparser, you agree that your contributions +will be licensed under the LICENSE file in the project root directory. diff --git a/external/graphqlparser/GraphQLParser.cpp b/external/graphqlparser/GraphQLParser.cpp new file mode 100644 index 0000000..ab4341a --- /dev/null +++ b/external/graphqlparser/GraphQLParser.cpp @@ -0,0 +1,76 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "GraphQLParser.h" + +#include "AstNode.h" + +#include "parser.tab.hpp" +#include "lexer.h" +#include "syntaxdefs.h" + +namespace facebook { +namespace graphql { + +// Given properly-configured yylex, run the parser and return the +// result. +static std::unique_ptr doParse(const char **outError, yyscan_t scanner, bool enableSchema) { + Node *outAST = nullptr; + yy::GraphQLParserImpl parser(enableSchema, &outAST, outError, scanner); + int failure = parser.parse(); + if (failure) { + delete outAST; + } + return !failure ? std::unique_ptr(outAST) : nullptr; +} + +static std::unique_ptr parseStringImpl(const char *text, const char **error, bool enableSchema) { + yyscan_t scanner; + struct LexerExtra extra; + yylex_init_extra(&extra, &scanner); + YY_BUFFER_STATE buffer = yy_scan_string(text, scanner); + yy_switch_to_buffer(buffer, scanner); + + auto result = doParse(error, scanner, enableSchema); + yylex_destroy(scanner); + return result; +} + +std::unique_ptr parseString(const char *text, const char **error) { + return parseStringImpl(text, error, false); +} + +std::unique_ptr parseStringWithExperimentalSchemaSupport( + const char *text, const char **error) { + return parseStringImpl(text, error, true); +} + +static std::unique_ptr parseFileImpl( + FILE *file, const char **error, bool enableSchema) { + yyscan_t scanner; + struct LexerExtra extra; + yylex_init_extra(&extra, &scanner); + yyset_in(file, scanner); + + auto result = doParse(error, scanner, enableSchema); + yylex_destroy(scanner); + + return result; +} + +std::unique_ptr parseFile(FILE *file, const char **error) { + return parseFileImpl(file, error, false); +} + +std::unique_ptr parseFileWithExperimentalSchemaSupport( + FILE *file, const char **error) { + return parseFileImpl(file, error, true); +} + + +} // namespace graphql +} // namespace facebook diff --git a/external/graphqlparser/GraphQLParser.h b/external/graphqlparser/GraphQLParser.h new file mode 100644 index 0000000..f3f88a3 --- /dev/null +++ b/external/graphqlparser/GraphQLParser.h @@ -0,0 +1,55 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +/** + * The purpose of this file is to provide a nice interface to parsing + * GraphQL, rather than the old-fashioned interface provided by bison + * and flex. + */ + +#pragma once + +#include +#include + +namespace facebook { +namespace graphql { + +namespace ast { + class Node; +} + +/** + * Parse the given GraphQL source string, returning an AST. Returns + * nullptr on error and, if error is not null, places a string + * describing what went wrong in error that must be freed with free(3). + */ +std::unique_ptr parseString(const char *text, const char **error); + +/** + * Like parseString, but enables support for the experimental type + * definition syntax from https://github.com/facebook/graphql/pull/90 . + */ +std::unique_ptr parseStringWithExperimentalSchemaSupport( + const char *text, const char **error); + +/** + * Read and parse GraphQL source from the given file, returning an + * AST. Returns nullptr on error and, if error is not null, places an + * error string in error that must be freed with free(3). + */ +std::unique_ptr parseFile(FILE *file, const char **error); + +/** + * Like parseFile, but enables support for the experimental type + * definition syntax from https://github.com/facebook/graphql/pull/90 . + */ +std::unique_ptr parseFileWithExperimentalSchemaSupport( + FILE *file, const char **error); + +} +} diff --git a/external/graphqlparser/JsonVisitor.cpp b/external/graphqlparser/JsonVisitor.cpp new file mode 100644 index 0000000..a37fb13 --- /dev/null +++ b/external/graphqlparser/JsonVisitor.cpp @@ -0,0 +1,161 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "position.hh" +#include "JsonVisitor.h" + +#include +#include + +namespace facebook { +namespace graphql { +namespace ast { +namespace visitor { + +static std::string escape(const char *s) { + static char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + std::string result; + while (unsigned char ch = *s++) { + if (ch >= '\0' && ch <= '\x1f') { + result.push_back('\\'); + result.push_back('u'); + result.push_back('0'); + result.push_back('0'); + result.push_back(ch >= 16 ? '1' : '0'); + result.push_back(hex[ch % 16]); + } else if (ch == '"') { + result.push_back('\\'); + result.push_back('"'); + } else if (ch == '\\') { + result.push_back('\\'); + result.push_back('\\'); + } else { + result.push_back(ch); + } + } + return result; +} + +JsonVisitor::NodeFieldPrinter::NodeFieldPrinter( + JsonVisitor &visitor, + const char *nodeKind, + const Node &node) + : visitor_(visitor) +{ + if (!visitor_.printed_.empty()) { + nextChild_ = visitor_.printed_.back().begin(); + } + // NOTE: If you're an Emacs user and this file's use of C++11 raw + // strings doesn't highlight correctly in c++-mode, try upgrading to + // Emacs 26 if you can. + out_ << R"({"kind":")" << nodeKind << R"(","loc":)"; + printLocation(out_, node.getLocation()); +} + +std::string JsonVisitor::NodeFieldPrinter::finishPrinting() { + assert(!out_.str().empty()); + out_ << '}'; + auto result(out_.str()); +#ifndef NDEBUG + out_.str(""); +#endif + return result; + +} + +void JsonVisitor::NodeFieldPrinter::printFieldSeparator() +{ + out_ << ','; +} + +void JsonVisitor::NodeFieldPrinter::printSingularPrimitiveField( + const char *fieldName, + const char *value) { + printFieldSeparator(); + out_ << '"' << fieldName << R"(":)"; + out_ << '"' << escape(value) << '"'; +} + +void JsonVisitor::NodeFieldPrinter::printSingularBooleanField( + const char *fieldName, + bool value) { + printFieldSeparator(); + out_ << '"' << fieldName << R"(":)"; + out_ << (value ? "true" : "false"); +} + +void JsonVisitor::NodeFieldPrinter::printSingularObjectField(const char *fieldName) { + printFieldSeparator(); + out_ << '"' << fieldName << R"(":)"; + assert(!visitor_.printed_.empty()); + out_ << *nextChild_++; +} + +void JsonVisitor::NodeFieldPrinter::printNullableSingularObjectField( + const char *fieldName, + const void *value) { + printFieldSeparator(); + out_ << '"' << fieldName << R"(":)"; + if (value != nullptr) { + assert(!visitor_.printed_.empty()); + out_ << *nextChild_++; + } else { + out_ << "null"; + } +} + +// Method invariant: printed_ contains strings for this node's children. +void JsonVisitor::NodeFieldPrinter::printLocation( + std::ostringstream &out, + const yy::location &location) +{ + out << R"({"start": {"line": )" << location.begin.line + << R"(,"column":)" << location.begin.column + << R"(}, "end": {"line":)" << location.end.line + << R"(,"column":)" << location.end.column + << "}}"; +} + +void JsonVisitor::NodeFieldPrinter::printChildList( + std::ostringstream &out, + const std::vector::const_iterator &childIterator, + size_t numChildren) { + out << '['; + for (size_t ii = 0; ii < numChildren; ++ii) { + if (ii != 0) { + out << ','; + } + out << *(childIterator + ii); + } + out << ']'; +} + +JsonVisitor::JsonVisitor() { + printed_.emplace_back(); +} + +void JsonVisitor::visitNode() { + printed_.emplace_back(); +} + +void JsonVisitor::endVisitNode(std::string &&str) { + printed_.pop_back(); + printed_.back().emplace_back(std::move(str)); +} + +std::string JsonVisitor::getResult() const { + assert(printed_.size() == 1); + assert(printed_[0].size() == 1); + return printed_[0][0]; +} + +#include "JsonVisitor.cpp.inc" + +} // namespace visitor +} // namespace ast +} // namespace graphql +} // namespace facebook diff --git a/external/graphqlparser/JsonVisitor.h b/external/graphqlparser/JsonVisitor.h new file mode 100644 index 0000000..46e93fe --- /dev/null +++ b/external/graphqlparser/JsonVisitor.h @@ -0,0 +1,121 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include "AstNode.h" +#include "AstVisitor.h" + +#include +#include + +namespace facebook { +namespace graphql { +namespace ast { +namespace visitor { + +/** + * Produces a JSON string describing the visited AST, in a format that + * would be a valid graphql-js AST when parsed. + */ +class JsonVisitor : public AstVisitor { + private: + using ChildrenList = std::vector; + // Stack of lists of printed children. + // Postvisit method precondition: printed.back() contains strings + // for this node's children. + // Postvisit method postcondition: *(printed.rbegin() - 1) has had this + std::vector printed_; + + // Interface to print fields for each kind of node. + // Note that, because of the post-order traversal for printing, + // field values need not be passed explicitly; they are grabbed from + // the passed-in visitor! + class NodeFieldPrinter { + private: + JsonVisitor &visitor_; + ChildrenList::const_iterator nextChild_; + std::ostringstream out_; + + void printFieldSeparator(); + + // Prints a non-null array of n children from the given + // iterator. Does not update the iterator. + void printChildList( + std::ostringstream &out, + const std::vector::const_iterator &childIterator, + size_t numChildren); + + void printLocation(std::ostringstream &out, const yy::location &location); + + public: + // Begin printing the fields for a node of the given kind at the + // given location. + NodeFieldPrinter( + JsonVisitor &visitor, + const char *nodeKind, + const Node &node); + + std::string finishPrinting(); + + void printSingularPrimitiveField(const char *fieldName, const char *value); + void printSingularBooleanField(const char *fieldName, bool value); + void printSingularObjectField(const char *fieldName); + void printNullableSingularObjectField(const char *fieldName, const void *value); + + template + void printPluralField( + const char *fieldName, + const std::vector> &value) { + printFieldSeparator(); + out_ << '"' << fieldName << "\":"; + printChildList(out_, nextChild_, value.size()); + nextChild_ += value.size(); + } + + template + void printNullablePluralField( + const char *fieldName, + const std::vector> *value) { + printFieldSeparator(); + out_ << '"' << fieldName << "\":"; + if (value == nullptr) { + out_ << "null"; + } else { + printChildList(out_, nextChild_, value->size()); + nextChild_ += value->size(); + } + } + }; + + // Must be called at the start of all visit methods for node types + // that have children. Maintains printed_. + void visitNode(); + + // Must be called at the end of all visit methods for node types + // that have children, passing the text for this node. Maintains + // printed_. + void endVisitNode(std::string &&str); + + // Prints one of the many FooValue types that is prepresented with a + // single string. + template + void endVisitValueRepresentedAsString(const char *valueKind, const ValueNode &value); + +public: + JsonVisitor(); + ~JsonVisitor() {} + + std::string getResult() const; + + #include "JsonVisitor.h.inc" +}; + +} +} +} +} diff --git a/external/graphqlparser/LICENSE b/external/graphqlparser/LICENSE new file mode 100644 index 0000000..7bbf892 --- /dev/null +++ b/external/graphqlparser/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) GraphQL Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/external/graphqlparser/README.clang-tidy b/external/graphqlparser/README.clang-tidy new file mode 100644 index 0000000..60825d9 --- /dev/null +++ b/external/graphqlparser/README.clang-tidy @@ -0,0 +1,7 @@ +* readability-implicit-bool is disabled because I disagree with it. + +* cppcoreguidelines-pro-type-reinterpret-cast is disabled because we use it + to implement our C API. + +* cppcoreguidelines-pro-bounds-array-to-pointer-decay is disabled + because it fires a false positive on every use of assert(). \ No newline at end of file diff --git a/external/graphqlparser/README.md b/external/graphqlparser/README.md new file mode 100644 index 0000000..7a7742a --- /dev/null +++ b/external/graphqlparser/README.md @@ -0,0 +1,94 @@ +# libgraphqlparser + +libgraphqlparser is a parser for +[GraphQL](http://graphql.org/), a query language for describing data +requirements on complex application data models, implemented in C++11. +It can be used on its own in C++ code (or in C code via the pure C API +defined in the `c` subdirectory), or you can use it as the basis for an +extension module for your favorite programming language instead of writing +your own parser from scratch. + +## Example + +The provided `dump_json_ast` is a simple program that reads GraphQL +text on stdin and prints a JSON representation of the AST to stdout. + +The `python` subdirectory contains an example Python binding for the +pure C API. + +## Requirements + +libgraphqlparser requires a C++ compiler that supports C++11. It +also requires Mac OS X or Linux. + +To run tests, first, compile and install the library as described above. Then, +please download googletest from +https://github.com/google/googletest/archive/release-1.8.0.zip +and unzip it in the `test` subdirectory. In consequence, a folder +`googletest-release-1.8.0` should be contained in `test`. Next, within the +`test` folder, run `cmake .` and `make` to generate the `runTests` binary. +To execute the tests run `./test/runTests` from the main folder. + +## Building libgraphqlparser + +libgraphqlparser is built with [CMake](http://www.cmake.org/). If a +sufficiently-recent version of [Flex](http://flex.sourceforge.net/) and [Bison](http://www.gnu.org/software/bison/) are installed on your +system, it will use them; otherwise, it will rely on the checked-in +`parser.tab.{c,h}pp` and `lexer.{h,cpp}`. + +To build libgraphqlparser from source: + +``` +$ # inside the project root: +$ cmake . +$ make +``` + +Then, to install it on your system: + +``` +$ make install +``` + +## How libgraphqlparser works + +libgraphqlparser uses flex and bison to generate a C++ parser for +GraphQL. These tools work well but have idiosyncratic interfaces by +modern standards, so GraphQLParser.h provides a simple interface to +parse GraphQL. + +In order to make it simpler to write code based around the GraphQL +AST, libgraphqlparser includes an extremely simple code generation +framework in the `ast/` subdirectory. This framework is used to build +the AST classes themselves, as well as a visitor over the AST. It may +be easier to understand the output of the generation steps directly +(i.e., Ast.h, Ast.cpp, and AstVisitor.h) rather than trying to read +the generation scripts. Simply building libgraphqlparser will cause +these files to be generated. + +libgraphqlparser also uses the AST generation framework to build a +pure C API in the `c` subdirectory. This API can be used from C code, +and it should also simplify the task of creating bindings to other +programming languages. + +## License + +libgraphqlparser is MIT-licensed. + +## Related Projects + +- [graphql-parser (Ruby interface)](https://github.com/Shopify/graphql-parser) +- [py-graphqlparser (Python interface)](https://github.com/elastic-coders/py-graphqlparser) +- [graphql_parser (Elixir interface)](https://github.com/aarvay/graphql_parser) +- [graphql-parser-php (PHP interface)](https://github.com/dosten/graphql-parser-php) +- [graphql-libgraphqlparser (Ruby interface)](https://github.com/rmosolgo/graphql-libgraphqlparser-ruby) + +## Contributing to this repo + +This repository is managed by EasyCLA. Project participants must sign the free ([GraphQL Specification Membership agreement](https://preview-spec-membership.graphql.org) before making a contribution. You only need to do this one time, and it can be signed by [individual contributors](http://individual-spec-membership.graphql.org/) or their [employers](http://corporate-spec-membership.graphql.org/). + +To initiate the signature process please open a PR against this repo. The EasyCLA bot will block the merge if we still need a membership agreement from you. + +You can find [detailed information here](https://github.com/graphql/graphql-wg/tree/main/membership). If you have issues, please email [operations@graphql.org](mailto:operations@graphql.org). + +If your company benefits from GraphQL and you would like to provide essential financial support for the systems and people that power our community, please also consider membership in the [GraphQL Foundation](https://foundation.graphql.org/join). diff --git a/external/graphqlparser/ast/.gitignore b/external/graphqlparser/ast/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/external/graphqlparser/ast/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/external/graphqlparser/ast/ast.ast b/external/graphqlparser/ast/ast.ast new file mode 100644 index 0000000..a095d38 --- /dev/null +++ b/external/graphqlparser/ast/ast.ast @@ -0,0 +1,203 @@ +# Copyright 2019-present, GraphQL Foundation + +# Mini-language for AST definition. +# All AST nodes extend AstNode. +# All AST nodes are visitible. +# All AST fields have a getter and a setter and are a constructor argument. +# We have concrete types (code T) and unions (code U). +# S for singular field, P for plural, ? for nullable. +# O for option in a union. +# Scalar type ontology: string, boolean + +# Definitions other than OperationDefinition and FragmentDefinition +# are experimental additions for schema parsing. (We don't support +# nested unions in the AST mini-language, so I've flattened and elided +# TypeSystemDefinition and TypeDefinition.) +U Definition +O OperationDefinition +O FragmentDefinition +O SchemaDefinition +O ScalarTypeDefinition +O ObjectTypeDefinition +O InterfaceTypeDefinition +O UnionTypeDefinition +O EnumTypeDefinition +O InputObjectTypeDefinition +O TypeExtensionDefinition +O DirectiveDefinition + + +T Document +P Definition definitions + +T OperationDefinition +S OperationKind operation +S? Name name +P? VariableDefinition variableDefinitions +P? Directive directives +S SelectionSet selectionSet + +T VariableDefinition +S Variable variable +S Type type +S? Value defaultValue + +T SelectionSet +P Selection selections + +U Selection +O Field +O FragmentSpread +O InlineFragment + +T Field +S? Name alias +S Name name +P? Argument arguments +P? Directive directives +S? SelectionSet selectionSet + +T Argument +S Name name +S Value value + +T FragmentSpread +S Name name +P? Directive directives + +T InlineFragment +S? NamedType typeCondition +P? Directive directives +S SelectionSet selectionSet + +T FragmentDefinition +S Name name +S NamedType typeCondition +P? Directive directives +S SelectionSet selectionSet + +U Value +O Variable +O IntValue +O FloatValue +O StringValue +O BooleanValue +O NullValue +O EnumValue +O ListValue +O ObjectValue + +T Variable +S Name name + +T IntValue +S string value + +T FloatValue +S string value + +T StringValue +S string value + +T BooleanValue +S boolean value + +T NullValue + +T EnumValue +S string value + +T ListValue +P Value values + +T ObjectValue +P ObjectField fields + +T ObjectField +S Name name +S Value value + +T Directive +S Name name +P? Argument arguments + +U Type +O NamedType +O ListType +O NonNullType + +T NamedType +S Name name + +T ListType +S Type type + +T NonNullType +# JS version prohibits nesting nonnull in nonnull, we can't because we +# can't support multiple unions. Fix? +S Type type + +T Name +S string value + +T SchemaDefinition +P? Directive directives +P OperationTypeDefinition operationTypes + +T OperationTypeDefinition +S OperationKind operation +S NamedType type + +T ScalarTypeDefinition +S Name name +P? Directive directives + +T ObjectTypeDefinition +S Name name +P? NamedType interfaces +P? Directive directives +P FieldDefinition fields + +T FieldDefinition +S Name name +P? InputValueDefinition arguments +S Type type +P? Directive directives + +T InputValueDefinition +S Name name +S Type type +S? Value defaultValue +P? Directive directives + +T InterfaceTypeDefinition +S Name name +P? Directive directives +P FieldDefinition fields + +T UnionTypeDefinition +S Name name +P? Directive directives +P NamedType types + +T EnumTypeDefinition +S Name name +P? Directive directives +P EnumValueDefinition values + +T EnumValueDefinition +S Name name +P? Directive directives + +T InputObjectTypeDefinition +S Name name +P? Directive directives +P InputValueDefinition fields + +T TypeExtensionDefinition +S ObjectTypeDefinition definition + +T DirectiveDefinition +S Name name +P? InputValueDefinition arguments +P Name locations diff --git a/external/graphqlparser/ast/ast.py b/external/graphqlparser/ast/ast.py new file mode 100644 index 0000000..8ddb8bf --- /dev/null +++ b/external/graphqlparser/ast/ast.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from importlib import import_module + +def load_lang(lang): + return import_module(lang).Printer() + + +def print_ast(lang_module, input_file): + lang_module.start_file() + line = input_file.readline() + while line: + line = line.strip() + if line.startswith('#') or not line: + line = input_file.readline() + continue + + code, rest = line.split(None, 1) + if code[0] == 'T': + lang_module.start_type(rest) + field_line = input_file.readline().strip() + while field_line: + if field_line.startswith('#'): + field_line = input_file.readline().strip() + continue + field_kind, field_type, field_name = field_line.split() + nullable = len(field_kind) > 1 and field_kind[1] == '?' + if field_kind[0] == 'S': + plural = False + elif field_kind[0] == 'P': + plural = True + else: + raise Error('Unknown field kind: ' + field_kind) + lang_module.field(field_type, field_name, nullable, plural) + field_line = input_file.readline().strip() + lang_module.end_type(rest) + elif code[0] == 'U': + lang_module.start_union(rest) + field_line = input_file.readline().strip() + while field_line: + option_code, option_type = field_line.split() + if option_code != 'O': + raise Error('Unknown code in union: ' + option_code) + lang_module.union_option(option_type) + field_line = input_file.readline().strip() + lang_module.end_union(rest) + line = input_file.readline() + + lang_module.end_file() +if __name__ == '__main__': + import sys + lang = sys.argv[1] + filename = sys.argv[2] + + lang_module = load_lang(lang) + + print_ast(lang_module, open(filename, 'r')) diff --git a/external/graphqlparser/ast/c.py b/external/graphqlparser/ast/c.py new file mode 100644 index 0000000..3a60ebf --- /dev/null +++ b/external/graphqlparser/ast/c.py @@ -0,0 +1,100 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import snake + +from license import C_LICENSE_COMMENT + +def struct_name(type): + return 'GraphQLAst' + type + + +def return_type(type): + if type == 'OperationKind' or type == 'string': + return 'const char *' + + if type == 'boolean': + return 'int' + + return 'const struct %s *' % struct_name(type) + + +def field_prototype(owning_type, type, name, nullable, plural): + st_name = struct_name(owning_type) + if plural: + return 'int %s_get_%s_size(const struct %s *node)' % ( + st_name, snake(name), st_name) + else: + ret_type = return_type(type) + return '%s %s_get_%s(const struct %s *node)' % ( + ret_type, st_name, snake(name), st_name) + + +class Printer(object): + '''Printer for the pure C interface to the AST. + + Merely a set of wrappers around the C++ interface; makes it possible + to use the AST from C code and simplifies the task of writing + bindings for other langugages. + + The mapping is as follows: + + - For each concrete type, you get an opaque C struct type, + accessible only by pointer. + + - For each singular field of a concrete type, you get an accessor + function, returning said field in the obvious way. + + - For each plural field of a concrete type, you get an accessor + function telling you its size. For access to elements of a plural + field, you can use the visitor API. + + - For each union type, you get nothing specific (REVIEW), but you + can use the visitor API to work around this entirely. + + ''' + + def __init__(self): + self._current_type = None + + def start_file(self): + print C_LICENSE_COMMENT + '''/** @generated */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +''' + + def end_file(self): + print ''' + +#ifdef __cplusplus +} +#endif +''' + + def start_type(self, name): + # Forward declarations for AST nodes. + st_name = struct_name(name) + print 'struct ' + st_name + ';' + self._current_type = name + + def field(self, type, name, nullable, plural): + print field_prototype(self._current_type, type, name, nullable, plural) + ';' + + def end_type(self, name): + print + + def start_union(self, name): + print 'struct ' + struct_name(name) + ';' + + def union_option(self, option): + pass + + def end_union(self, name): + print diff --git a/external/graphqlparser/ast/c_impl.py b/external/graphqlparser/ast/c_impl.py new file mode 100644 index 0000000..f82299d --- /dev/null +++ b/external/graphqlparser/ast/c_impl.py @@ -0,0 +1,61 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from c import field_prototype, return_type, struct_name +from casing import title +from license import C_LICENSE_COMMENT + +class Printer(object): + '''Printer for the implementation of the pure C interface to the AST. + ''' + + def __init__(self): + self._current_type = None + + def start_file(self): + print C_LICENSE_COMMENT + '''/** @generated */ + +#include "GraphQLAst.h" +#include "../Ast.h" + +using namespace facebook::graphql::ast; // NOLINT +''' + + def end_file(self): + pass + + def start_type(self, name): + self._current_type = name + + def field(self, type, name, nullable, plural): + print field_prototype(self._current_type, type, name, nullable, plural) + ' {' + print ' const auto *realNode = reinterpret_cast(node);' % self._current_type + title_name = title(name) + call_get = 'realNode->get%s()' % title_name + if plural: + if nullable: + print ' return %s ? %s->size() : 0;' % (call_get, call_get) + else: + print ' return %s.size();' % call_get + else: + if type in ['string', 'OperationKind', 'boolean']: + print ' return %s;' % call_get + else: + fmt = ' return reinterpret_cast(%s%s);' + print fmt % (struct_name(type), '' if nullable else '&', call_get) + + print '}' + + def end_type(self, name): + pass + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/external/graphqlparser/ast/c_visitor_impl.py b/external/graphqlparser/ast/c_visitor_impl.py new file mode 100644 index 0000000..cab7062 --- /dev/null +++ b/external/graphqlparser/ast/c_visitor_impl.py @@ -0,0 +1,39 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import snake +from license import C_LICENSE_COMMENT + +class Printer(object): + '''Printer for a simple list of types to be visited by the C visitor. + ''' + + def __init__(self): + self._types = [] + + def start_file(self): + print C_LICENSE_COMMENT + '/** @generated */' + print '#define FOR_EACH_CONCRETE_TYPE(MACRO) \\' + + def start_type(self, name): + self._types.append(name) + + def field(self, type, name, nullable, plural): + pass + + def end_type(self, name): + pass + + def end_file(self): + print ' \\\n'.join('MACRO(%s, %s)' % (name, snake(name)) for name in self._types) + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/external/graphqlparser/ast/casing.py b/external/graphqlparser/ast/casing.py new file mode 100644 index 0000000..ca299c7 --- /dev/null +++ b/external/graphqlparser/ast/casing.py @@ -0,0 +1,26 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +def title(s): + '''Capitalize the first character of s.''' + return s[0].capitalize() + s[1:] + + +def camel(s): + '''Lowercase the first character of s.''' + return s[0].lower() + s[1:] + + +def snake(s): + '''Convert from title or camelCase to snake_case.''' + if len(s) < 2: + return s.lower() + out = s[0].lower() + for c in s[1:]: + if c.isupper(): + out += '_' + c = c.lower() + out += c + return out diff --git a/external/graphqlparser/ast/cxx.py b/external/graphqlparser/ast/cxx.py new file mode 100644 index 0000000..3706cad --- /dev/null +++ b/external/graphqlparser/ast/cxx.py @@ -0,0 +1,197 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +import cStringIO as StringIO + +from casing import title +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + self._type_name = None + # Map concrete type to base class + self._bases = {} + # HACK: Defer everything we print so that forward declarations for + # all classes come first. Avoids having to do 2 passes over the + # input file. + self._deferredOutput = StringIO.StringIO() + + self._fields = [] + + def start_file(self): + print C_LICENSE_COMMENT + '''/** @generated */ +#pragma once + +#include "AstNode.h" + +#include +#include +#include +#include + +namespace facebook { +namespace graphql { +namespace ast { + +// The parser uses strdup to move from yytext to the heap, so we need +// to use free instead of delete. +struct CDeleter { + void operator()(const char *p) const { free((void *)p); } +}; +''' + + def end_file(self): + print + print self._deferredOutput.getvalue() + print '}' + print '}' + print '}' + + def _base_class(self, type): + return self._bases.get(type, 'Node') + + def start_type(self, name): + self._type_name = name + base = self._base_class(name) + # non-deferred! + print 'class %s;' % name + print >> self._deferredOutput, 'class %s : public %s {' % (name, base) + self._fields = [] + + def field(self, type, name, nullable, plural): + if type == 'OperationKind': + type = 'string' + self._fields.append((type, name, nullable, plural)) + + def end_type(self, name): + self._print_fields() + print >> self._deferredOutput, ' public:' + self._print_constructor() + print >> self._deferredOutput + self._print_destructor_prototype() + print >> self._deferredOutput + self._print_noncopyable() + print >> self._deferredOutput + self._print_getters() + print >> self._deferredOutput, ' void accept(visitor::AstVisitor *visitor) const override;' + print >> self._deferredOutput, '};' + print >> self._deferredOutput + print >> self._deferredOutput + self._type_name = None + self._fields = [] + + def _storage_type(self, type): + if type == 'string': + return 'std::unique_ptr' + elif type == 'boolean': + return 'bool' + else: + return 'std::unique_ptr<%s>' % type + + def _print_fields(self): + for (type, name, nullable, plural) in self._fields: + storage_type = self._storage_type(type) + if plural: + storage_type = 'std::unique_ptr>' % storage_type + print >> self._deferredOutput, ' %s %s_;' % (storage_type, name) + + def _ctor_singular_type(self, type): + if type == 'string': + return 'const char *' + elif type == 'boolean': + return 'bool' + else: + return '%s *' % type + + def _ctor_plural_type(self, type): + return 'std::vector<%s> *' % self._storage_type(type) + + def _print_constructor(self): + print >> self._deferredOutput, ' explicit %s(' % self._type_name + print >> self._deferredOutput, ' const yy::location &location%s' % (',' if self._fields else '') + def ctor_arg(type, name, plural): + if plural: + ctor_type = self._ctor_plural_type(type) + else: + ctor_type = self._ctor_singular_type(type) + return ' %s %s' % (ctor_type, name) + print >> self._deferredOutput, ',\n'.join(ctor_arg(type, name, plural) + for (type, name, nullable, plural) in self._fields) + print >> self._deferredOutput, ' )' + def ctor_init(type, name, plural): + # Strings are const char *, just pass. + # Vectors are passed by pointer and we take ownership. + # Node types are passed in by pointer and we take ownership. + value = name + return ' %s_(%s)' % (name, value) + print >> self._deferredOutput, ' : %s(location)%s' % (self._base_class(self._type_name), ',' if self._fields else '') + print >> self._deferredOutput, ',\n'.join(ctor_init(type, name, plural) + for (type, name, nullable, plural) + in self._fields) + print >> self._deferredOutput, ' {}' + + def _getter_type(self, type, nullable, plural): + if plural and nullable: + return 'const std::vector<%s>*' % self._storage_type(type) + elif plural: + return 'const std::vector<%s>&' % self._storage_type(type) + + if type == 'string': + assert not nullable + return 'const char *' + elif type == 'boolean': + assert not nullable + return 'bool' + elif nullable: + return 'const %s*' % type + else: + return 'const %s&' % type + + def _getter_value_to_return(self, raw_value, type, nullable, plural): + if plural and nullable: + return raw_value + '.get()' + elif plural: + return '*%s' % raw_value + elif type == 'boolean': + return raw_value + elif nullable or type == 'string': + return '%s.get()' % raw_value + else: + return '*%s' % raw_value + + def _print_getters(self): + for (type, name, nullable, plural) in self._fields: + print >> self._deferredOutput, ' %s get%s() const' % ( + self._getter_type(type, nullable, plural), + title(name)) + print >> self._deferredOutput, ' { return %s; }' % ( + self._getter_value_to_return(name + '_', type, nullable, plural)) + print >> self._deferredOutput + + def _print_destructor_prototype(self): + print >> self._deferredOutput, ' ~%s() {}' % self._type_name + + def _print_noncopyable(self): + print >> self._deferredOutput, ' %s(const %s&) = delete;' % ( + self._type_name, self._type_name) + print >> self._deferredOutput, ' %s& operator=(const %s&) = delete;' % ( + self._type_name, self._type_name) + + def start_union(self, name): + self._type_name = name + # non-deferred! + print 'class %s;' % name + print >> self._deferredOutput, 'class %s : public Node {' % name + print >> self._deferredOutput, ' public:' + self._print_constructor() + print >> self._deferredOutput, '};' + print >> self._deferredOutput + + def union_option(self, type): + assert type not in self._bases, '%s cannot appear in more than one union!' % type + self._bases[type] = self._type_name + + def end_union(self, name): + pass diff --git a/external/graphqlparser/ast/cxx_impl.py b/external/graphqlparser/ast/cxx_impl.py new file mode 100644 index 0000000..ab161c6 --- /dev/null +++ b/external/graphqlparser/ast/cxx_impl.py @@ -0,0 +1,61 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + pass + + def start_file(self): + print C_LICENSE_COMMENT + '''/** @generated */ + +#include "Ast.h" +#include "AstVisitor.h" + +namespace facebook { +namespace graphql { +namespace ast { +''' + + def end_file(self): + print '} // namespace ast' + print '} // namespace graphql' + print '} // namespace facebook' + + def start_type(self, name): + print '''void %s::accept(visitor::AstVisitor *visitor) const { + if (visitor->visit%s(*this)) { +''' % (name, name) + + def field(self, type, name, nullable, plural): + if type in ['OperationKind', 'string', 'boolean']: + return + + if plural: + accept = '{ for (const auto &x : *%s_) { x->accept(visitor); } }' % name + if nullable: + accept = 'if (%s_) %s' % (name, accept) + print ' ' + accept + else: + accept = '%s_->accept(visitor);' % name + if nullable: + accept = 'if (%s_) { %s }' % (name, accept) + print ' ' + accept + + def end_type(self, name): + print ''' } + visitor->endVisit%s(*this); +} +''' % name + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/external/graphqlparser/ast/cxx_json_visitor_header.py b/external/graphqlparser/ast/cxx_json_visitor_header.py new file mode 100644 index 0000000..fca744f --- /dev/null +++ b/external/graphqlparser/ast/cxx_json_visitor_header.py @@ -0,0 +1,42 @@ +# Copyright 2019-present, GraphQL Foundation +# All rights reserved. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import title +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + self._anyFieldIsANode = False + + def start_file(self): + print C_LICENSE_COMMENT + '/** @generated */' + + def end_file(self): + pass + + def start_type(self, name): + self._anyFieldIsANode = False + + def end_type(self, name): + titleName = title(name) + if self._anyFieldIsANode: + print 'bool visit%s(const %s &node) override;' % (titleName, titleName) + print 'void endVisit%s(const %s &node) override;' % (titleName, titleName) + print + + def field(self, type, name, nullable, plural): + if (not self._anyFieldIsANode and + type not in ('OperationKind', 'string', 'boolean')): + self._anyFieldIsANode = True + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/external/graphqlparser/ast/cxx_json_visitor_impl.py b/external/graphqlparser/ast/cxx_json_visitor_impl.py new file mode 100644 index 0000000..0df2bac --- /dev/null +++ b/external/graphqlparser/ast/cxx_json_visitor_impl.py @@ -0,0 +1,80 @@ +# Copyright 2019-present, GraphQL Foundation +# All rights reserved. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import title +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + self._fields = [] + + def start_file(self): + print C_LICENSE_COMMENT + '/** @generated */' + + def end_file(self): + pass + + def start_type(self, name): + self._fields = [] + + def field(self, type, name, nullable, plural): + if type == 'OperationKind': + type = 'string' + self._fields.append((type, name, nullable, plural)) + + def end_type(self, name): + titleName = title(name) + anyFieldIsANode = any(type not in ('string, boolean') + for (type, _, _ ,_) in self._fields) + if anyFieldIsANode: + print '''bool JsonVisitor::visit%s(const %s &node) { + visitNode(); + return true; +} +''' % (titleName, titleName) + print '''void JsonVisitor::endVisit%(tn)s(const %(tn)s &node) { + NodeFieldPrinter fields(*this, "%(tn)s", node);''' % {'tn': titleName} + + for (type, fieldName, nullable, plural) in self._fields: + funcName = None + if type == 'string': + assert not plural, 'plural string fields not supported yet' + funcName = 'printSingularPrimitiveField' + elif type == 'boolean': + assert not plural, 'plural boolean fields not supported yet' + funcName = 'printSingularBooleanField' + elif not nullable and not plural: + # Special case: singular object fields don't need the value passed. + print ' fields.printSingularObjectField("%s");' % fieldName + continue + else: + nullable_str = 'Nullable' if nullable else '' + plural_str = 'Plural' if plural else 'SingularObject' + funcName = 'print%s%sField' % (nullable_str, plural_str) + + assert funcName is not None + print ' fields.%s("%s", node.get%s());' % ( + funcName, fieldName, title(fieldName)) + + if anyFieldIsANode: + print ''' + endVisitNode(fields.finishPrinting()); +} +''' + else: + print ''' + printed_.back().emplace_back(fields.finishPrinting()); +} +''' + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/external/graphqlparser/ast/cxx_visitor.py b/external/graphqlparser/ast/cxx_visitor.py new file mode 100644 index 0000000..f1b7029 --- /dev/null +++ b/external/graphqlparser/ast/cxx_visitor.py @@ -0,0 +1,64 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from casing import camel, title +from license import C_LICENSE_COMMENT + +class Printer(object): + def __init__(self): + pass + + def start_file(self): + print C_LICENSE_COMMENT + '''/** @generated */ + +#pragma once + +#include "Ast.h" + +namespace facebook { +namespace graphql { +namespace ast { +namespace visitor { + +class AstVisitor { +public: + virtual ~AstVisitor() {} +''' + + def end_file(self): + print '};' # end AstVisitor + print + print '}' + print '}' + print '}' + print '}' + + def start_type(self, name): + titleName = title(name) + camelName = camel(titleName) + print ' virtual bool visit%s(const %s &%s) { return true; }' % ( + titleName, + titleName, + camelName) + print ' virtual void endVisit%s(const %s &%s) { }' % ( + titleName, + titleName, + camelName) + print + + def end_type(self, name): + pass + + def field(self, type, name, nullable, plural): + pass + + def start_union(self, name): + pass + + def union_option(self, option): + pass + + def end_union(self, name): + pass diff --git a/external/graphqlparser/ast/js.py b/external/graphqlparser/ast/js.py new file mode 100644 index 0000000..0b0dd26 --- /dev/null +++ b/external/graphqlparser/ast/js.py @@ -0,0 +1,65 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + + +class Printer(object): + def __init__(self): + pass + + def start_file(self): + print '''/* @flow */ +/* @generated */ +/* jshint ignore:start */ + +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +type Node = { + kind: string; + start?: ?number; + end?: ?number; +}; + +type OperationKind = 'query' | 'mutation' | 'subscription';''' + + def end_file(self): + pass + + def start_type(self, name): + print + print 'type %s = Node & {' % name + kind = name + if kind == 'GenericType': + kind = 'Type' + print ' kind: \'%s\';' % kind + + def end_type(self, name): + print '}' + + def _js_type(self, type, plural): + if plural: + type = 'Array<%s>' % type + return type + + def field(self, type, name, nullable, plural): + nullable_char = '?' if nullable else '' + js_type = self._js_type(type, plural) + print ' %(name)s%(nullable_char)s: %(nullable_char)s%(js_type)s;' % locals() + + def start_union(self, name): + print ('type %s = ' % name), + self._current_options = [] + + def union_option(self, type): + self._current_options.append(type) + + def end_union(self, name): + print '\n | '.join(self._current_options) + print + self._current_options = None diff --git a/external/graphqlparser/ast/license.py b/external/graphqlparser/ast/license.py new file mode 100644 index 0000000..8dbd5da --- /dev/null +++ b/external/graphqlparser/ast/license.py @@ -0,0 +1,10 @@ +# Copyright 2019-present GraphQL Foundation +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +C_LICENSE_COMMENT = '''/** + * Copyright 2019-present GraphQL Foundation + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +''' diff --git a/external/graphqlparser/c/.gitignore b/external/graphqlparser/c/.gitignore new file mode 100644 index 0000000..02f06d2 --- /dev/null +++ b/external/graphqlparser/c/.gitignore @@ -0,0 +1,3 @@ +GraphQLAst.h +GraphQLAst.cpp +GraphQLAstForEachConcreteType.h diff --git a/external/graphqlparser/c/GraphQLAstNode.cpp b/external/graphqlparser/c/GraphQLAstNode.cpp new file mode 100644 index 0000000..4d12056 --- /dev/null +++ b/external/graphqlparser/c/GraphQLAstNode.cpp @@ -0,0 +1,25 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "GraphQLAstNode.h" +#include "../AstNode.h" + +using facebook::graphql::ast::Node; + +void graphql_node_get_location(const struct GraphQLAstNode *node, + struct GraphQLAstLocation *location) { + const auto *realNode = reinterpret_cast(node); + const auto &loc = realNode->getLocation(); + location->beginLine = loc.begin.line; + location->beginColumn = loc.begin.column; + location->endLine = loc.end.line; + location->endColumn = loc.end.column; +} + +void graphql_node_free(struct GraphQLAstNode *node) { + delete reinterpret_cast(node); +} diff --git a/external/graphqlparser/c/GraphQLAstNode.h b/external/graphqlparser/c/GraphQLAstNode.h new file mode 100644 index 0000000..3948603 --- /dev/null +++ b/external/graphqlparser/c/GraphQLAstNode.h @@ -0,0 +1,33 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Opaque type representing a generic AST node. */ +struct GraphQLAstNode; + +/* A location in the AST. */ +struct GraphQLAstLocation { + unsigned int beginLine; + unsigned int beginColumn; + unsigned int endLine; + unsigned int endColumn; +}; + +/* Fills location with location information for the given node. */ +void graphql_node_get_location(const struct GraphQLAstNode *node, + struct GraphQLAstLocation *location); + +void graphql_node_free(struct GraphQLAstNode *node); + +#ifdef __cplusplus +} +#endif diff --git a/external/graphqlparser/c/GraphQLAstToJSON.cpp b/external/graphqlparser/c/GraphQLAstToJSON.cpp new file mode 100644 index 0000000..180f038 --- /dev/null +++ b/external/graphqlparser/c/GraphQLAstToJSON.cpp @@ -0,0 +1,21 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "GraphQLAstToJSON.h" + +#include + +#include "../JsonVisitor.h" +#include "../AstNode.h" + + +const char *graphql_ast_to_json(const struct GraphQLAstNode *node) +{ + facebook::graphql::ast::visitor::JsonVisitor visitor; + reinterpret_cast(node)->accept(&visitor); + return strdup(visitor.getResult().c_str()); +} diff --git a/external/graphqlparser/c/GraphQLAstToJSON.h b/external/graphqlparser/c/GraphQLAstToJSON.h new file mode 100644 index 0000000..63d9481 --- /dev/null +++ b/external/graphqlparser/c/GraphQLAstToJSON.h @@ -0,0 +1,24 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +struct GraphQLAstNode; + +/** + * Serialize the given AST to JSON. The returned C string must be + * freed with free(). + */ +const char *graphql_ast_to_json(const struct GraphQLAstNode *node); + +#ifdef __cplusplus +} +#endif diff --git a/external/graphqlparser/c/GraphQLAstVisitor.cpp b/external/graphqlparser/c/GraphQLAstVisitor.cpp new file mode 100644 index 0000000..1765133 --- /dev/null +++ b/external/graphqlparser/c/GraphQLAstVisitor.cpp @@ -0,0 +1,55 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "c/GraphQLAstVisitor.h" +#include "AstVisitor.h" + +using namespace facebook::graphql::ast; // NOLINT + +#include "c/GraphQLAstForEachConcreteType.h" + +#define DECLARE_VISIT(type, snake_type) \ + bool visit##type(const type &node) override; \ + void endVisit##type(const type &node) override; + +class CVisitorBridge : public visitor::AstVisitor { + const struct GraphQLAstVisitorCallbacks *callbacks_; + void *userData_; +public: + explicit CVisitorBridge(const struct GraphQLAstVisitorCallbacks *callbacks, + void *userData) + : callbacks_(callbacks), userData_(userData) {} + + FOR_EACH_CONCRETE_TYPE(DECLARE_VISIT) +}; + +#define IMPLEMENT_VISIT(type, snake_type) \ + bool CVisitorBridge::visit##type(const type &node) { \ + if (callbacks_->visit_##snake_type) { \ + return callbacks_->visit_##snake_type( \ + (const struct GraphQLAst##type *)&node, userData_); \ + } \ + return true; \ + } \ + void CVisitorBridge::endVisit##type(const type &node) { \ + if (callbacks_->end_visit_##snake_type) { \ + callbacks_->end_visit_##snake_type( \ + (const struct GraphQLAst##type *)&node, userData_); \ + } \ + } + +FOR_EACH_CONCRETE_TYPE(IMPLEMENT_VISIT) + +void graphql_node_visit(const struct GraphQLAstNode *node, + const struct GraphQLAstVisitorCallbacks *callbacks, + void *userData) +{ + CVisitorBridge visitor(callbacks, userData); + if (node) { + reinterpret_cast(node)->accept(&visitor); + } +} diff --git a/external/graphqlparser/c/GraphQLAstVisitor.h b/external/graphqlparser/c/GraphQLAstVisitor.h new file mode 100644 index 0000000..1fcceac --- /dev/null +++ b/external/graphqlparser/c/GraphQLAstVisitor.h @@ -0,0 +1,53 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include "c/GraphQLAst.h" +#include "c/GraphQLAstForEachConcreteType.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define TYPEDEFS(type, snake_type) \ + typedef int (*visit_##snake_type##_func)(const struct GraphQLAst##type *snake_type, void *user_data); \ + typedef void (*end_visit_##snake_type##_func)(const struct GraphQLAst##type *snake_type, void *user_data); + +FOR_EACH_CONCRETE_TYPE(TYPEDEFS) + +#define FUNC_MEMBER(type, snake_type) \ + visit_##snake_type##_func visit_##snake_type; \ + end_visit_##snake_type##_func end_visit_##snake_type; +/** + * Functions to be called when particular AST nodes are encountered. + * visit_* functions are called in pre-order, and may return non-zero to + * continue recursing into children (if any), or zero to skip them. end_visit_* + * functions are called in post-order. Any particular function may be set to + * NULL to indicate that the caller is not interested in the corresponding type + * of AST node. (NULL visit_* functions act as though they simply returned + * non-zero.) + */ +struct GraphQLAstVisitorCallbacks { + FOR_EACH_CONCRETE_TYPE(FUNC_MEMBER) +}; + +struct GraphQLAstNode; + +/** + * Walk the AST rooted at the given node, issuing callbacks from the given + * callbacks struct as appropriate. userData will be passed as the userData + * argument to each callback. + */ +void graphql_node_visit(const struct GraphQLAstNode *node, + const struct GraphQLAstVisitorCallbacks *callbacks, + void *userData); + +#ifdef __cplusplus +} +#endif + diff --git a/external/graphqlparser/c/GraphQLParser.cpp b/external/graphqlparser/c/GraphQLParser.cpp new file mode 100644 index 0000000..738f648 --- /dev/null +++ b/external/graphqlparser/c/GraphQLParser.cpp @@ -0,0 +1,35 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "GraphQLParser.h" +#include "../GraphQLParser.h" +#include "../AstNode.h" + +#include + +struct GraphQLAstNode *graphql_parse_string(const char *text, const char **error) { + return reinterpret_cast(facebook::graphql::parseString(text, error).release()); +} + +struct GraphQLAstNode *graphql_parse_string_with_experimental_schema_support( + const char *text, const char **error) { + return reinterpret_cast(facebook::graphql::parseStringWithExperimentalSchemaSupport( + text, error).release()); +} + +struct GraphQLAstNode *graphql_parse_file(FILE *file, const char **error) { + return reinterpret_cast(facebook::graphql::parseFile(file, error).release()); +} + +struct GraphQLAstNode *graphql_parse_file_with_experimental_schema_support( + FILE *file, const char **error) { + return reinterpret_cast(facebook::graphql::parseFileWithExperimentalSchemaSupport(file, error).release()); +} + +void graphql_error_free(const char *error) { + std::free((void *)(error)); // NOLINT +} diff --git a/external/graphqlparser/c/GraphQLParser.h b/external/graphqlparser/c/GraphQLParser.h new file mode 100644 index 0000000..6254984 --- /dev/null +++ b/external/graphqlparser/c/GraphQLParser.h @@ -0,0 +1,54 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * This file provides C wrappers for ../GraphQLParser.h. + */ + +struct GraphQLAstNode; + +/** + * Parse the given GraphQL source string, returning an AST. Returns + * NULL on error. Return value must be freed with + * graphql_node_free(). If NULL is returned and error is not NULL, an + * error message is placed in error and must be freed with + * graphql_error_free(). + */ +struct GraphQLAstNode *graphql_parse_string( + const char *text, const char **error); + +struct GraphQLAstNode *graphql_parse_string_with_experimental_schema_support( + const char *text, const char **error); + +/** + * Read and parse GraphQL source from the given file, returning an + * AST. Returns nullptr on error. Return value must be freed with + * graphql_node_free(). If NULL is returned and error is not NULL, an + * error message is placed in error and must be freed with + * graphql_error_free(). + */ +struct GraphQLAstNode *graphql_parse_file(FILE *file, const char **error); + +struct GraphQLAstNode *graphql_parse_file_with_experimental_schema_support( + FILE *file, const char **error); + +/** + * Frees an error. + */ +void graphql_error_free(const char *error); + +#ifdef __cplusplus +} +#endif diff --git a/external/graphqlparser/clang-tidy-all.sh b/external/graphqlparser/clang-tidy-all.sh new file mode 100755 index 0000000..bb86897 --- /dev/null +++ b/external/graphqlparser/clang-tidy-all.sh @@ -0,0 +1,3 @@ +#!/bin/sh +# Copyright 2019-present, GraphQL Foundation +find . -name '*.cpp' | grep -v lexer | grep -v googletest | grep -v tab.cpp | xargs clang-tidy -p build diff --git a/external/graphqlparser/cmake/version.cmake b/external/graphqlparser/cmake/version.cmake new file mode 100644 index 0000000..d5fad1a --- /dev/null +++ b/external/graphqlparser/cmake/version.cmake @@ -0,0 +1,16 @@ +# Copyright 2019-present, GraphQL Foundation + +find_package(Git QUIET) + +# default version string +set(LIBGRAPHQLPARSER_VERSION "0.0-dev") + +if(GIT_EXECUTABLE AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE LIBGRAPHQLPARSER_VERSION + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(SUBSTRING ${LIBGRAPHQLPARSER_VERSION} 1 -1 LIBGRAPHQLPARSER_VERSION) +endif() diff --git a/external/graphqlparser/dump_json_ast.cpp b/external/graphqlparser/dump_json_ast.cpp new file mode 100644 index 0000000..8d1d1a0 --- /dev/null +++ b/external/graphqlparser/dump_json_ast.cpp @@ -0,0 +1,48 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "AstNode.h" +#include "GraphQLParser.h" +#include "c/GraphQLAstToJSON.h" + +#include +#include +#include + + +using std::cout; +using std::cerr; +using std::endl; +using std::fopen; +using std::fclose; +using std::free; + + +int main(int argc, char **argv) { + const char *error; + FILE * in; + if (argc > 1) { + in = fopen(argv[1], "r"); // NOLINT + } else { + in = stdin; + } + auto AST = facebook::graphql::parseFile(in, &error); + if (argc > 1) { + fclose(in); + } + if (!AST) { + cerr << "Parser failed with error: " << error << endl; + free((void *)error); // NOLINT + return 1; + } + + const char *json = graphql_ast_to_json(reinterpret_cast(AST.get())); + puts(json); + free((void *)json); // NOLINT + + return 0; +} diff --git a/external/graphqlparser/go/.gitignore b/external/graphqlparser/go/.gitignore new file mode 100644 index 0000000..4023f20 --- /dev/null +++ b/external/graphqlparser/go/.gitignore @@ -0,0 +1 @@ +go diff --git a/external/graphqlparser/go/README.md b/external/graphqlparser/go/README.md new file mode 100644 index 0000000..39456be --- /dev/null +++ b/external/graphqlparser/go/README.md @@ -0,0 +1,20 @@ +# About +This directory contains an example using the libgraphqlparser C library from [Go](https://golang.org/project/). + +For an overview of binding to C libraries in Go, please see the [cgo documentation](https://github.com/golang/go/wiki/cgo). +Specifically, please read the overview of [Function pointer callbacks](https://github.com/golang/go/wiki/cgo#function-pointer-callbacks) in Go and C. + +## Building and Running + +To build with Go, please ensure that you have `pkg-config` installed for your +system. + +Assuming pkg-config has been installed, it should be possible to then build +using Go in the normal fashion: +```sh +$ cd libgraphqlparser/go +$ go build +$ ./go +field : myfield +Example error: 1.18-19: syntax error, unexpected on, expecting ( or @ or { +``` diff --git a/external/graphqlparser/go/callbacks.go b/external/graphqlparser/go/callbacks.go new file mode 100644 index 0000000..be5b8c0 --- /dev/null +++ b/external/graphqlparser/go/callbacks.go @@ -0,0 +1,18 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package main + +/* +struct GraphQLAstField; + +int printField(struct GraphQLAstField *field, void *unused); + +int printField_cgo(struct GraphQLAstField *field, void *unused) { + return printField(field, unused); +} +*/ +import "C" diff --git a/external/graphqlparser/go/gotest.go b/external/graphqlparser/go/gotest.go new file mode 100644 index 0000000..5949d2c --- /dev/null +++ b/external/graphqlparser/go/gotest.go @@ -0,0 +1,64 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +package main + +/* +#cgo pkg-config: libgraphqlparser + +#include "c/GraphQLAst.h" +#include "c/GraphQLAstNode.h" +#include "c/GraphQLAstVisitor.h" +#include "c/GraphQLParser.h" +#include + +int printField_cgo(struct GraphQLAstField *field, void *unused); +*/ +import "C" + +import "errors" +import "fmt" +import "unsafe" + +//export printField +func printField(field *C.struct_GraphQLAstField, unused unsafe.Pointer) int { + fmt.Printf("field : %s\n", C.GoString(C.GraphQLAstName_get_value(C.GraphQLAstField_get_name(field)))) + return 0 +} + +func parse(query string) (*C.struct_GraphQLAstNode, error) { + graphql := C.CString(query) + cError := (*C.char)(nil) + ast := C.graphql_parse_string(graphql, &cError) + C.free(unsafe.Pointer(graphql)) + + if ast == nil { + err := errors.New(C.GoString(cError)) + C.graphql_error_free(cError) + return nil, err + } + return ast, nil +} + +func main() { + ast, err := parse("query myquery { myfield }") + if err != nil { + fmt.Printf("BUG: unexpected parse error: %s", err) + return + } + visitor_callbacks := C.struct_GraphQLAstVisitorCallbacks{visit_field: (C.visit_field_func)(C.printField_cgo)} + C.graphql_node_visit(ast, &visitor_callbacks, nil) + + C.graphql_node_free(ast) + + ast2, err2 := parse("query errorQuery on oops { myfield }") + if err2 != nil { + fmt.Printf("Example error: %s\n", err2) + } + if ast2 != nil { + fmt.Printf("BUG: we should have got a null AST back, but we got %s\n", ast2) + } +} diff --git a/external/graphqlparser/lexer.lpp b/external/graphqlparser/lexer.lpp new file mode 100644 index 0000000..90e339c --- /dev/null +++ b/external/graphqlparser/lexer.lpp @@ -0,0 +1,324 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +%{ +#include +#include +#include +#include +#include +#include +#include +#include "location.hh" +#include "position.hh" +#include "parser.tab.hpp" +#include "syntaxdefs.h" + +// Keep track of token lengths. +#define YY_USER_ACTION yyextra->loc.columns(yyleng); + +static void escape(char c, char *buf); + +static std::string clean_up_block_string(const std::string &str); + +%} + +%option bison-bridge bison-locations +%option noyywrap batch noinput nounput +%option reentrant +%option extra-type="struct LexerExtra *" + +%x STRING_STATE +%x BLOCK_STRING_STATE +%x C_COMMENT_STATE +%x LINE_COMMENT_STATE + +FLOAT -?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)? +INTEGER -?(0|[1-9][0-9]*) +IDENTIFIER [_A-Za-z][_0-9A-Za-z]* +VARIABLE $[_0-9A-Za-z]+ +BOM \xef\xbb\xbf +CRLF \r\n +BADCHAR [\x00-\x08\x0b\x0c\x0e-\x1f] +GOODCHAR [^\x00-\x08\x0b\x0c\x0e-\x1f] +STRINGCHAR [^\x00-\x1f\\\x22] + +blank [ \t,] +newline [\n\r] +notnewline [^\n\r] + +%% + +%{ + yyextra->loc.step(); +%} + +{ + \" { + BEGIN(INITIAL); + yylval->str = yyextra->str.c_str(); + *yylloc = yyextra->loc; + return yy::GraphQLParserImpl::token::TOK_STRING; + } + + {newline} { + throw make_error(yyextra->loc, "Unterminated string"); + } + + <> { + throw make_error(yyextra->loc, "Unterminated string at EOF"); + } + + {STRINGCHAR}+ { + char *p = yytext; + while (*p) { + yyextra->str.push_back(*p++); + } + } + + \\\" { yyextra->str.push_back('"'); } + \\\\ { yyextra->str.push_back('\\'); } + \\\/ { yyextra->str.push_back('/'); } + \\n { yyextra->str.push_back('\n'); } + \\t { yyextra->str.push_back('\t'); } + \\r { yyextra->str.push_back('\r'); } + \\b { yyextra->str.push_back('\b'); } + \\f { yyextra->str.push_back('\f'); } + + \\u[0-9A-Fa-f]{4} { + int ch; + sscanf(yytext + 2, "%x", &ch); + yyextra->str.push_back(ch); + } + + \\u { throw make_error(yyextra->loc, "bad Unicode escape sequence"); } + \\. { throw make_error(yyextra->loc, std::string("bad escape sequence \\") + yytext[1]); } + +} + +{ + <> { + throw make_error(yyextra->loc, "Unterminated block string at EOF"); + } + + {BADCHAR} { + throw make_error(yyextra->loc, std::string("Invalid character ") + yytext[0]); + } + + {GOODCHAR} { + /* Can't use {GOODCHAR}+ because that would be a better match for + """ than the explicit rule! */ + yyextra->str.push_back(*yytext); + } + + \\\"\"\" { + yyextra->str.append(3, '"'); + } + + \"\"\" { + BEGIN(INITIAL); + yyextra->str = clean_up_block_string(yyextra->str); + yylval->str = yyextra->str.c_str(); + *yylloc = yyextra->loc; + return yy::GraphQLParserImpl::token::TOK_STRING; + } +} + +{ + {CRLF} { yyextra->loc.lines(yyleng / 2); yyextra->loc.step(); BEGIN(INITIAL); } + {newline} { yyextra->loc.lines(yyleng); yyextra->loc.step(); BEGIN(INITIAL); } + {notnewline}+ /* eat comment character */ +} + +{ + {blank}+ { yyextra->loc.step(); } + {BOM}+ { yyextra->loc.step(); yyextra->loc.step(); yyextra->loc.step(); } + {CRLF}+ { yyextra->loc.lines(yyleng / 2); yyextra->loc.step(); } + {newline}+ { yyextra->loc.lines(yyleng); yyextra->loc.step(); } + + # {yyextra->loc.step(); BEGIN(LINE_COMMENT_STATE); } + + directive { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_DIRECTIVE; } + enum { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_ENUM; } + extend { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_EXTEND; } + false { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_FALSE; } + fragment { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_FRAGMENT; } + implements { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_IMPLEMENTS; } + input { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_INPUT; } + interface { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_INTERFACE; } + mutation { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_MUTATION; } + null { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_NULL; } + on { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_ON; } + query { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_QUERY; } + scalar { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_SCALAR; } + schema { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_SCHEMA; } + subscription { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_SUBSCRIPTION; } + true { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_TRUE; } + type { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_TYPE; } + union { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_UNION; } + + {INTEGER} { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_INTEGER; } + {FLOAT} { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_FLOAT; } + {IDENTIFIER} { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_IDENTIFIER; } + {VARIABLE} { yylval->str = yytext + 1; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_VARIABLE; } + + "!" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_BANG; } + "(" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_LPAREN; } + ")" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_RPAREN; } + "..." { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_ELLIPSIS; } + ":" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_COLON; } + "=" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_EQUAL; } + "@" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_AT; } + "[" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_LBRACKET; } + "]" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_RBRACKET; } + "{" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_LBRACE; } + "|" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_PIPE; } + "}" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_RBRACE; } + + + <> { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_EOF; } + + \"\"\" { + BEGIN(BLOCK_STRING_STATE); + yyextra->str.clear(); + } + + \" { + BEGIN(STRING_STATE); + yyextra->str.clear(); + } +} + +. { + char buf[6]; + escape(yytext[0], buf); + throw make_error( + yyextra->loc, + std::string("unrecognized character ") + buf); +} + +%% + +static void escape(char c, char *buf) { + if (std::isgraph(c)) { + *buf = c; + buf[1] = '\0'; + } else { + buf[0] = '\\'; + buf[2] = '\0'; + switch (c) { + case '\a': + buf[1] = 'a'; + break; + case '\b': + buf[1] = 'b'; + break; + case '\f': + buf[1] = 'f'; + break; + case '\n': + buf[1] = 'n'; + break; + case '\r': + buf[1] = 'r'; + break; + case '\t': + buf[1] = 't'; + break; + case '\v': + buf[1] = 'v'; + break; + default: + buf[1] = 'x'; + std::snprintf(buf + 2, 3, "%x", ((int)c & 0xFF)); + break; + } + } +} + +static std::vector splitLines(const std::string &str) { + std::vector lines; + auto it = str.begin(); + while (it != str.end()) { + static char terminators[2] = {'\r', '\n'}; + auto nextIt = std::find_first_of(it, str.end(), terminators, terminators + sizeof(terminators)); + lines.emplace_back(str.data() + (it - str.begin()), nextIt - it); + if (nextIt != str.end()) { + auto advancedIt = nextIt + 1; + if (advancedIt != str.end()) { + if (*nextIt == '\r' && *advancedIt == '\n') { + ++advancedIt; + } + } + nextIt = std::move(advancedIt); + } + it = std::move(nextIt); + } + return lines; +} + +static int count_leading_whitespace(const std::string &str) { + auto pos = str.find_first_not_of(" \t", 0, strlen(" \t")); + if (pos == std::string::npos) { + return str.length(); + } + return pos; +} + +static bool is_all_whitespace(const std::string &str) { + return count_leading_whitespace(str) == str.length(); +} + +static std::string clean_up_block_string(const std::string &str) { + auto lines = splitLines(str); + bool first = true; + int commonIndent = INT_MAX; + for (const auto &line : lines) { + if (first) { + first = false; + continue; + } + const auto indent = count_leading_whitespace(line); + if (indent < line.length()) { + if (indent < commonIndent) { + commonIndent = indent; + } + } + } + if (commonIndent != INT_MAX) { + first = true; + for (auto &line : lines) { + if (first) { + first = false; + continue; + } + line.erase(0, commonIndent); + } + } + + const auto firstNonBlankIt = std::find_if(lines.begin(), lines.end(), [](const std::string &line) { + return !is_all_whitespace(line); + }); + lines.erase(lines.begin(), firstNonBlankIt); + + const auto firstNonBlankReverseIt = std::find_if(lines.rbegin(), lines.rend(), [](const std::string &line) { + return !is_all_whitespace(line); + }); + lines.erase(lines.end() - (firstNonBlankReverseIt - lines.rbegin()), lines.end()); + + std::string formatted; + first = true; + for (const auto &line: lines) { + if (first) { + first = false; + } else { + formatted.push_back('\n'); + } + formatted.append(line); + } + return formatted; +} diff --git a/external/graphqlparser/libgraphqlparser.pc.in b/external/graphqlparser/libgraphqlparser.pc.in new file mode 100644 index 0000000..c5720e6 --- /dev/null +++ b/external/graphqlparser/libgraphqlparser.pc.in @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include/graphqlparser + +Name: @CMAKE_PROJECT_NAME@ +Description: facebook graphql parsing library +Version: @LIBGRAPHQLPARSER_VERSION@ +Libs: -L${libdir} -lgraphqlparser +Libs.private: +Cflags: -I${includedir} diff --git a/external/graphqlparser/parser.ypp b/external/graphqlparser/parser.ypp new file mode 100644 index 0000000..fa81321 --- /dev/null +++ b/external/graphqlparser/parser.ypp @@ -0,0 +1,693 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +%require "3" + +%skeleton "lalr1.cc" + +%defines +%define parser_class_name {GraphQLParserImpl} + +%define api.token.prefix {TOK_} + +%define parse.error verbose + +%code requires +{ +#include +#include +#include +#include +#include + +#include "Ast.h" + +using facebook::graphql::ast::Node; +using facebook::graphql::ast::Name; +using facebook::graphql::ast::Definition; +using facebook::graphql::ast::Document; +using facebook::graphql::ast::OperationDefinition; +using facebook::graphql::ast::VariableDefinition; +using facebook::graphql::ast::Variable; +using facebook::graphql::ast::SelectionSet; +using facebook::graphql::ast::Selection; +using facebook::graphql::ast::Field; +using facebook::graphql::ast::Argument; +using facebook::graphql::ast::FragmentSpread; +using facebook::graphql::ast::InlineFragment; +using facebook::graphql::ast::FragmentDefinition; +using facebook::graphql::ast::Value; +using facebook::graphql::ast::IntValue; +using facebook::graphql::ast::FloatValue; +using facebook::graphql::ast::StringValue; +using facebook::graphql::ast::BooleanValue; +using facebook::graphql::ast::NullValue; +using facebook::graphql::ast::EnumValue; +using facebook::graphql::ast::ListValue; +using facebook::graphql::ast::ObjectValue; +using facebook::graphql::ast::ObjectField; +using facebook::graphql::ast::Directive; +using facebook::graphql::ast::Type; +using facebook::graphql::ast::NamedType; +using facebook::graphql::ast::ListType; +using facebook::graphql::ast::NonNullType; + +// Experimental schema support. +using facebook::graphql::ast::SchemaDefinition; +using facebook::graphql::ast::ScalarTypeDefinition; +using facebook::graphql::ast::ObjectTypeDefinition; +using facebook::graphql::ast::InterfaceTypeDefinition; +using facebook::graphql::ast::UnionTypeDefinition; +using facebook::graphql::ast::EnumTypeDefinition; +using facebook::graphql::ast::InputObjectTypeDefinition; +using facebook::graphql::ast::TypeExtensionDefinition; +using facebook::graphql::ast::DirectiveDefinition; +using facebook::graphql::ast::SchemaDefinition; +using facebook::graphql::ast::OperationTypeDefinition; +using facebook::graphql::ast::ScalarTypeDefinition; +using facebook::graphql::ast::ObjectTypeDefinition; +using facebook::graphql::ast::FieldDefinition; +using facebook::graphql::ast::InputValueDefinition; +using facebook::graphql::ast::InterfaceTypeDefinition; +using facebook::graphql::ast::UnionTypeDefinition; +using facebook::graphql::ast::EnumTypeDefinition; +using facebook::graphql::ast::EnumValueDefinition; +using facebook::graphql::ast::InputObjectTypeDefinition; +using facebook::graphql::ast::TypeExtensionDefinition; +using facebook::graphql::ast::DirectiveDefinition; + +union yystype { \ + const char *str; \ + const char *heapStr; \ + Name *name; \ + Definition *definition; \ + Document *document; \ + OperationDefinition *operationDefinition; \ + VariableDefinition *variableDefinition; \ + Variable *variable; \ + SelectionSet *selectionSet; \ + Selection *selection; \ + Field *field; \ + Argument *argument; \ + FragmentSpread *fragmentSpread; \ + InlineFragment *inlineFragment; \ + FragmentDefinition *fragmentDefinition; \ + Value *value; \ + IntValue *intValue; \ + FloatValue *floatValue; \ + StringValue *stringValue; \ + BooleanValue *booleanValue; \ + NullValue *nullValue; \ + EnumValue *enumValue; \ + ListValue *arrayValue; \ + ObjectValue *objectValue; \ + ObjectField *objectField; \ + Directive *directive; \ + Type *type; \ + NamedType *namedType; \ + ListType *listType; \ + NonNullType *nonNullType; \ + \ + std::vector> *definitionList; \ + std::vector> *variableDefinitionList; \ + std::vector> *selectionList; \ + std::vector> *fieldList; \ + std::vector> *argumentList; \ + std::vector> *valueList; \ + std::vector> *objectFieldList; \ + std::vector> *directiveList; \ + \ + SchemaDefinition *schemaDefinition; \ + ScalarTypeDefinition *scalarTypeDefinition; \ + ObjectTypeDefinition *objectTypeDefinition; \ + InterfaceTypeDefinition *interfaceTypeDefinition; \ + UnionTypeDefinition *unionTypeDefinition; \ + EnumTypeDefinition *enumTypeDefinition; \ + InputObjectTypeDefinition *inputObjectTypeDefinition; \ + TypeExtensionDefinition *typeExtensionDefinition; \ + DirectiveDefinition *directiveDefinition; \ + OperationTypeDefinition *operationTypeDefinition; \ + InputValueDefinition *inputValueDefinition; \ + FieldDefinition *fieldDefinition; \ + EnumValueDefinition *enumValueDefinition; \ + \ + std::vector> *operationTypeDefinitionList; \ + std::vector> *typeNameList; \ + std::vector> *inputValueDefinitionList; \ + std::vector> *fieldDefinitionList; \ + std::vector> *nameList; \ + std::vector> *enumValueDefinitionList; \ +}; + +#define YYSTYPE union yystype +#define YYLTYPE yy::location + +} + +%lex-param { void *scanner } +%parse-param { bool enableSchema } { Node **outAST } { const char **outError } { void *scanner } + +%locations + +%code +{ +#include "lexer.h" +#include "syntaxdefs.h" +} + +%token EOF 0 +%token DIRECTIVE "directive" +%token ENUM "enum" +%token EXTEND "extend" +%token FALSE "false" +%token FRAGMENT "fragment" +%token IMPLEMENTS "implements" +%token INPUT "input" +%token INTERFACE "interface" +%token MUTATION "mutation" +%token NULL "null" +%token QUERY "query" +%token ON "on" +%token SCALAR "scalar" +%token SCHEMA "schema" +%token SUBSCRIPTION "subscription" +%token TRUE "true" +%token TYPE "type" +%token UNION "union" +%token BANG "!" +%token LPAREN "(" +%token RPAREN ")" +%token ELLIPSIS "..." +%token COLON ":" +%token EQUAL "=" +%token AT "@" +%token LBRACKET "[" +%token RBRACKET "]" +%token LBRACE "{" +%token PIPE "|" +%token RBRACE "}" + +%token VARIABLE +%token INTEGER +%token FLOAT +%token STRING +%token IDENTIFIER + +%type variable +%type int_value +%type float_value +%type string_value + +%type start +%type document +%type fragment_name +%type name +%type name_opt + +%type definition_list +%type definition +%type schema_gate + +%type operation_definition +%type variable_definitions +%type variable_definition_list +%type variable_definition +%type default_value_opt +%type default_value +%type selection_set +%type selection_set_opt +%type selection_list +%type selection +%type field +%type arguments_opt +%type arguments +%type argument_list +%type argument + +%type fragment_spread +%type inline_fragment +%type fragment_definition +%type type_condition + +%type value +%type value_const +%type boolean_value +%type null_value +%type enum_value +%type list_value +%type list_value_const +%type value_list +%type value_const_list +%type object_value +%type object_value_const +%type object_field_list +%type object_field_const_list +%type object_field +%type object_field_const + + +%type directives +%type directives_opt +%type directive_list +%type directive + +%type type +%type type_name +%type list_type +%type non_null_type + +%type operation_type + +%type schema_definition; +%type scalar_type_definition; +%type object_type_definition; +%type interface_type_definition; +%type union_type_definition; +%type enum_type_definition; +%type input_object_type_definition; +%type type_extension_definition; +%type directive_definition; +%type operation_type_definition; +%type operation_type_definition_list; +%type type_name_list; +%type implements_interfaces_opt; +%type union_members; +%type field_definition; +%type field_definition_list; +%type arguments_definition_opt; +%type arguments_definition; +%type input_value_definition_list; +%type input_value_definition; +%type enum_value_definition; +%type directive_locations; +%type enum_value_definition_list; + +%destructor { } +%destructor { free((void *)$$); } +%destructor { } /* we steal it and put it in outAST, don't free! */ +%destructor { delete $$; } <*> + +%printer { yyoutput << $$; } + +%% + +start: document { *outAST = $1; } + ; + +/* All of the non-identifier tokens are to accommodate various flavors + of name that don't include those tokens. */ +fragment_name: DIRECTIVE { $$ = new Name(@1, strdup($1)); } + | ENUM { $$ = new Name(@1, strdup($1)); } + | EXTEND { $$ = new Name(@1, strdup($1)); } + | FALSE { $$ = new Name(@1, strdup($1)); } + | FRAGMENT { $$ = new Name(@1, strdup($1)); } + | IDENTIFIER { $$ = new Name(@1, strdup($1)); } + | IMPLEMENTS { $$ = new Name(@1, strdup($1)); } + | INPUT { $$ = new Name(@1, strdup($1)); } + | INTERFACE { $$ = new Name(@1, strdup($1)); } + | MUTATION { $$ = new Name(@1, strdup($1)); } + | NULL { $$ = new Name(@1, strdup($1)); } + | QUERY { $$ = new Name(@1, strdup($1)); } + | SCALAR { $$ = new Name(@1, strdup($1)); } + | SCHEMA { $$ = new Name(@1, strdup($1)); } + | SUBSCRIPTION { $$ = new Name(@1, strdup($1)); } + | TRUE { $$ = new Name(@1, strdup($1)); } + | TYPE { $$ = new Name(@1, strdup($1)); } + | UNION { $$ = new Name(@1, strdup($1)); } + ; + +name: fragment_name + | ON { $$ = new Name(@1, strdup($1)); } + ; + +name_opt: + %empty {$$ = nullptr;} + | name + ; + +/* 2.2 Document */ + +document: definition_list { $$ = new Document(@$, $1); } + ; + +definition_list:definition { $$ = new std::vector>(); $$->emplace_back($1); } + | definition_list definition { $1->emplace_back($2); $$ = $1; } + ; + +definition: operation_definition { $$ = static_cast($1); } + | fragment_definition { $$ = static_cast($1); } + | schema_gate { + if (!enableSchema) { + error(@$, "schema support disabled"); + // %destructor doesn't work with YYERROR. See + // https://www.gnu.org/software/bison/manual/html_node/Destructor-Decl.html + delete $$; + YYERROR; + } + $$ = static_cast($1); + } + ; + +schema_gate: schema_definition { $$ = static_cast($1); } + | scalar_type_definition { $$ = static_cast($1); } + | object_type_definition { $$ = static_cast($1); } + | interface_type_definition { $$ = static_cast($1); } + | union_type_definition { $$ = static_cast($1); } + | enum_type_definition { $$ = static_cast($1); } + | input_object_type_definition { $$ = static_cast($1); } + | type_extension_definition { $$ = static_cast($1); } + | directive_definition { $$ = static_cast($1); } + ; + + +/* 2.2.1 Operations */ +operation_definition: + selection_set { $$ = new OperationDefinition(@$, strdup("query"), nullptr, nullptr, nullptr, $1); } + | operation_type name_opt selection_set { $$ = new OperationDefinition(@$, $1, $2, nullptr, nullptr, $3); } + | operation_type name_opt variable_definitions selection_set { $$ = new OperationDefinition(@$, $1, $2, $3, nullptr, $4); } + | operation_type name_opt directives selection_set { $$ = new OperationDefinition(@$, $1, $2, nullptr, $3, $4); } + | operation_type name_opt variable_definitions directives selection_set { $$ = new OperationDefinition(@$, $1, $2, $3, $4, $5); } + ; + +operation_type: QUERY { $$ = strdup($1); } + | MUTATION { $$ = strdup($1); } + | SUBSCRIPTION { $$ = strdup($1); } + ; + +variable_definitions: + "(" variable_definition_list ")" { $$ = $2; } + ; + +variable_definition_list: + variable_definition { $$ = new std::vector>(); $$->emplace_back($1); } + | variable_definition_list variable_definition { $1->emplace_back($2); $$ = $1; } + ; + +variable: VARIABLE { $$ = new Variable(@$, new Name(@1, strdup($1))); } + ; + +variable_definition: + variable ":" type default_value_opt { $$ = new VariableDefinition(@$, $1, $3, $4); } + ; + +default_value_opt: + %empty { $$ = nullptr; } + | default_value + ; + +default_value: "=" value_const { $$ = $2; } + ; + +selection_set: + "{" selection_list "}" { $$ = new SelectionSet(@$, $2); } + ; + +selection_set_opt: + %empty { $$ = nullptr; } + | selection_set + ; +selection_list: selection { $$ = new std::vector>(); $$->emplace_back($1); } + | selection_list selection { $1->emplace_back($2); $$ = $1; } + ; + +selection: field { $$ = static_cast($1); } + | fragment_spread { $$ = static_cast($1); } + | inline_fragment { $$ = static_cast($1); } + ; + +field: name arguments_opt directives_opt selection_set_opt { $$ = new Field(@$, nullptr, $1, $2, $3, $4); } + | name ":" name arguments_opt directives_opt selection_set_opt { $$ = new Field(@$, $1, $3, $4, $5, $6); } + ; + +arguments: "(" argument_list ")" { $$ = $2; } + ; + +arguments_opt: %empty { $$ = nullptr; } + | arguments { $$ = $1; } + ; + +argument_list: argument { $$ = new std::vector>(); $$->emplace_back($1); } + | argument_list argument { $1->emplace_back($2); $$ = $1; } + ; + +argument: name ":" value { $$ = new Argument(@$, $1, $3); } + ; + +/* 2.2.6 Fragments */ +fragment_spread: + "..." fragment_name directives_opt { $$ = new FragmentSpread(@$, $2, $3); } + ; + +inline_fragment: + "..." "on" type_condition directives_opt selection_set { $$ = new InlineFragment(@$, $3, $4, $5); } + | "..." directives_opt selection_set { $$ = new InlineFragment(@$, nullptr, $2, $3); } + ; + +fragment_definition: + "fragment" fragment_name "on" type_condition directives_opt selection_set { $$ = new FragmentDefinition(@$, $2, $4, $5, $6); } + ; + +type_condition: type_name + ; + +/* 2.2.7 Input Values */ +value: variable { $$ = static_cast($1); } + | int_value { $$ = static_cast($1); } + | float_value { $$ = static_cast($1); } + | string_value { $$ = static_cast($1); } + | boolean_value { $$ = static_cast($1); } + | null_value { $$ = static_cast($1); } + | enum_value { $$ = static_cast($1); } + | list_value { $$ = static_cast($1); } + | object_value { $$ = static_cast($1); } + ; + +int_value: INTEGER { $$ = new IntValue(@$, strdup($1)); } + ; + +float_value: FLOAT { $$ = new FloatValue(@$, strdup($1)); } + ; + +string_value: STRING { $$ = new StringValue(@$, strdup($1)); } + ; + +value_const: int_value { $$ = static_cast($1); } + | float_value { $$ = static_cast($1); } + | string_value { $$ = static_cast($1); } + | boolean_value { $$ = static_cast($1); } + | null_value { $$ = static_cast($1); } + | enum_value { $$ = static_cast($1); } + | list_value_const { $$ = static_cast($1); } + | object_value_const { $$ = static_cast($1); } + ; + +boolean_value: TRUE { $$ = new BooleanValue(@$, true); } + | FALSE { $$ = new BooleanValue(@$, false); } + ; + +null_value: NULL { $$ = new NullValue(@$); } + ; + +enum_value: DIRECTIVE { $$ = new EnumValue(@$, strdup($1)); } + | ENUM { $$ = new EnumValue(@$, strdup($1)); } + | EXTEND { $$ = new EnumValue(@$, strdup($1)); } + | FRAGMENT { $$ = new EnumValue(@$, strdup($1)); } + | IDENTIFIER { $$ = new EnumValue(@$, strdup($1)); } + | IMPLEMENTS { $$ = new EnumValue(@$, strdup($1)); } + | INPUT { $$ = new EnumValue(@$, strdup($1)); } + | INTERFACE { $$ = new EnumValue(@$, strdup($1)); } + | MUTATION { $$ = new EnumValue(@$, strdup($1)); } + | ON { $$ = new EnumValue(@$, strdup($1)); } + | QUERY { $$ = new EnumValue(@$, strdup($1)); } + | SCALAR { $$ = new EnumValue(@$, strdup($1)); } + | SCHEMA { $$ = new EnumValue(@$, strdup($1)); } + | SUBSCRIPTION { $$ = new EnumValue(@$, strdup($1)); } + | TYPE { $$ = new EnumValue(@$, strdup($1)); } + | UNION { $$ = new EnumValue(@$, strdup($1)); } + ; + +/* 2.2.7.6 List Value */ + +/* REVIEW: the empty case is inefficient; consider implementing + ListValue manually. Don't forget to also do list_value_const. */ +list_value: "[" "]" { $$ = new ListValue(@$, new std::vector>()); } + | "[" value_list "]" { $$ = new ListValue(@$, $2); } + ; + +value_list: value { $$ = new std::vector>(); $$->emplace_back($1); } + | value_list value { $1->emplace_back($2); $$ = $1; } + ; + +list_value_const: + "[" "]" { $$ = new ListValue(@$, new std::vector>()); } + | "[" value_const_list "]" { $$ = new ListValue(@$, $2); } + ; + +value_const_list: + value_const { $$ = new std::vector>(); $$->emplace_back($1); } + | value_const_list value_const { $1->emplace_back($2); $$ = $1; } + ; + +/* 2.2.7.7 Object Value */ +/* REVIEW: Inefficient, like ListValue. */ +object_value: "{" "}" { $$ = new ObjectValue(@$, new std::vector>()); } + | "{" object_field_list "}" { $$ = new ObjectValue(@$, $2); } + ; + +object_field_list: + object_field { $$ = new std::vector>(); $$->emplace_back($1); } + | object_field_list object_field { $1->emplace_back($2); $$ = $1; } + ; + +object_field: name ":" value { $$ = new ObjectField(@$, $1, $3); } + ; + +object_value_const: + "{" "}" { $$ = new ObjectValue(@$, new std::vector>()); } + | "{" object_field_const_list "}" { $$ = new ObjectValue(@$, $2); } + ; + +object_field_const_list: + object_field_const { $$ = new std::vector>(); $$->emplace_back($1); } + | object_field_const_list object_field_const { $1->emplace_back($2); $$ = $1; } + ; + +object_field_const: name ":" value_const { $$ = new ObjectField(@$, $1, $3); } + ; + +/* 2.2.10 Directives */ + +directives: directive_list + ; + +directives_opt: %empty { $$ = nullptr; } + | directives + ; + +directive_list: directive { $$ = new std::vector>(); $$->emplace_back($1); } + | directive_list directive { $1->emplace_back($2); $$ = $1; } + ; + +directive: "@" name arguments_opt { $$ = new Directive(@$, $2, $3); } + ; + +/* 2.2.9 Types */ + +type: type_name { $$ = static_cast($1); } + | list_type { $$ = static_cast($1); } + | non_null_type { $$ = static_cast($1); } + ; + +type_name: name { $$ = new NamedType(@$, $1); } + ; + +list_type: "[" type "]" { $$ = new ListType(@$, $2); } + ; + +non_null_type: type_name "!" { $$ = new NonNullType(@$, $1); } + | list_type "!" { $$ = new NonNullType(@$, $1); } + ; + +/* Experimental schema parsing support. */ + +schema_definition: SCHEMA directives_opt "{" operation_type_definition_list "}" { $$ = new SchemaDefinition(@$, $2, $4); } + ; + +operation_type_definition_list: + operation_type_definition { $$ = new std::vector>(); $$->emplace_back($1); } + | operation_type_definition_list operation_type_definition { $1->emplace_back($2); $$ = $1; } + ; + +operation_type_definition: + operation_type ":" type_name { $$ = new OperationTypeDefinition(@$, $1, $3); } + ; + +scalar_type_definition: SCALAR name directives_opt { $$ = new ScalarTypeDefinition(@$, $2, $3); } + ; + +object_type_definition: TYPE name implements_interfaces_opt directives_opt "{" field_definition_list "}" { $$ = new ObjectTypeDefinition(@$, $2, $3, $4, $6); } + ; + +implements_interfaces_opt: %empty { $$ = nullptr; } + | IMPLEMENTS type_name_list { $$ = $2; } + ; + +type_name_list: type_name { $$ = new std::vector>(); $$->emplace_back($1); } + | type_name_list type_name { $1->emplace_back($2); $$ = $1; } + ; + +field_definition: name arguments_definition_opt ":" type directives_opt { $$ = new FieldDefinition(@$, $1, $2, $4, $5); } + ; + +field_definition_list: + field_definition { $$ = new std::vector>(); $$->emplace_back($1); } + | field_definition_list field_definition { $1->emplace_back($2); $$ = $1; } + ; + +arguments_definition_opt: %empty { $$ = nullptr; } + | arguments_definition { $$ = $1; } + ; + +arguments_definition: "(" input_value_definition_list ")" { $$ = $2; } + ; + +input_value_definition_list: input_value_definition { $$ = new std::vector>(); $$->emplace_back($1); } + | input_value_definition_list input_value_definition { $1->emplace_back($2); $$ = $1; } + ; + +input_value_definition: name ":" type default_value_opt directives_opt { $$ = new InputValueDefinition(@$, $1, $3, $4, $5); } + +interface_type_definition: INTERFACE name directives_opt "{" field_definition_list "}" { $$ = new InterfaceTypeDefinition(@$, $2, $3, $5); } + ; + +union_type_definition: UNION name directives_opt "=" union_members { $$ = new UnionTypeDefinition(@$, $2, $3, $5); } + ; + +union_members: type_name { $$ = new std::vector>(); $$->emplace_back($1); } + | union_members "|" type_name { $1->emplace_back($3); $$ = $1; } + ; + +enum_type_definition: ENUM name directives_opt "{" enum_value_definition_list "}" { $$ = new EnumTypeDefinition(@$, $2, $3, $5); } + ; + +enum_value_definition: name directives_opt { $$ = new EnumValueDefinition(@$, $1, $2); } + ; + +enum_value_definition_list: + enum_value_definition { $$ = new std::vector>(); $$->emplace_back($1); } + | enum_value_definition_list enum_value_definition { $1->emplace_back($2); $$ = $1; } + ; + +input_object_type_definition: INPUT name directives_opt "{" input_value_definition_list "}" { $$ = new InputObjectTypeDefinition(@$, $2, $3, $5); } + ; + +type_extension_definition: EXTEND object_type_definition { $$ = new TypeExtensionDefinition(@$, $2); } + ; + +directive_definition: DIRECTIVE "@" name arguments_definition_opt ON directive_locations { $$ = new DirectiveDefinition(@$, $3, $4, $6); } + ; + +directive_locations: + name { $$ = new std::vector>(); $$->emplace_back($1); } + | directive_locations "|" name { $1->emplace_back($3); $$ = $1; } + ; + +%% + +void yy::GraphQLParserImpl::error(const yy::location &loc, const std::string &str) { + std::ostringstream out; + out << loc << ": " << str; + if (outError) { + *outError = strdup(out.str().c_str()); + } +} + +/* Workaround for syntax_error ctor being marked inline, which causes link + errors if used from lexer.lpp. */ +yy::GraphQLParserImpl::syntax_error make_error(const yy::location &loc, const std::string &str) { + return yy::GraphQLParserImpl::syntax_error(loc, str); +} diff --git a/external/graphqlparser/parsergen/lexer.cpp b/external/graphqlparser/parsergen/lexer.cpp new file mode 100644 index 0000000..6edcd43 --- /dev/null +++ b/external/graphqlparser/parsergen/lexer.cpp @@ -0,0 +1,2633 @@ +#line 1 "lexer.cpp" + +#line 3 "lexer.cpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yyget_lval +#define yyget_lval_ALREADY_DEFINED +#else +#define yyget_lval yyget_lval +#endif + +#ifdef yyset_lval +#define yyset_lval_ALREADY_DEFINED +#else +#define yyset_lval yyset_lval +#endif + +#ifdef yyget_lloc +#define yyget_lloc_ALREADY_DEFINED +#else +#define yyget_lloc yyget_lloc +#endif + +#ifdef yyset_lloc +#define yyset_lloc_ALREADY_DEFINED +#else +#define yyset_lloc yyset_lloc +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin , yyscanner ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +static void yyensure_buffer_stack ( yyscan_t yyscanner ); +static void yy_load_buffer_state ( yyscan_t yyscanner ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP +typedef flex_uint8_t YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); +static int yy_get_next_buffer ( yyscan_t yyscanner ); +static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; +#define YY_NUM_RULES 64 +#define YY_END_OF_BUFFER 65 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[196] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 65, 63, 22, 25, 25, 49, 62, 26, 63, 50, + 51, 63, 63, 45, 45, 53, 54, 55, 47, 56, + 57, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 58, 59, 60, 63, 2, 2, 3, 1, + 63, 15, 16, 16, 16, 64, 21, 20, 20, 22, + 25, 24, 0, 48, 45, 45, 0, 0, 0, 45, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 37, 47, 47, 47, 47, 47, 47, 0, 3, 14, + 4, 6, 5, 10, 11, 7, 9, 8, 13, 0, + + 0, 21, 19, 25, 61, 52, 46, 0, 46, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 23, 0, 18, 0, + 47, 28, 47, 47, 47, 47, 47, 47, 47, 36, + 47, 47, 47, 47, 42, 43, 47, 0, 0, 17, + 47, 47, 30, 47, 47, 33, 47, 47, 38, 47, + 47, 47, 44, 0, 47, 29, 47, 47, 47, 47, + 39, 40, 47, 12, 47, 47, 47, 47, 47, 47, + 47, 31, 47, 47, 35, 47, 27, 47, 34, 47, + 32, 47, 47, 41, 0 + + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5, 6, 7, 8, 9, 10, 10, 10, 11, + 12, 10, 13, 5, 14, 15, 16, 17, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 19, 10, 10, + 20, 10, 10, 21, 22, 22, 22, 22, 23, 22, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 25, 26, 27, 10, 24, 10, 28, 29, 30, 31, + + 32, 33, 34, 35, 36, 24, 24, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 24, 48, + 49, 24, 50, 51, 52, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 53, 10, 10, 10, + 54, 10, 10, 10, 10, 10, 10, 10, 10, 10, + + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 55, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10 + } ; + +static const YY_CHAR yy_meta[56] = + { 0, + 1, 1, 2, 3, 4, 4, 1, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, + 4, 5, 5, 6, 4, 1, 4, 5, 5, 5, + 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, + 4, 4, 4, 4, 4 + } ; + +static const flex_int16_t yy_base[209] = + { 0, + 0, 0, 55, 62, 60, 67, 0, 0, 67, 69, + 288, 289, 73, 73, 76, 289, 280, 289, 0, 289, + 289, 65, 271, 69, 72, 289, 289, 289, 0, 289, + 289, 249, 46, 63, 58, 238, 237, 243, 235, 68, + 56, 241, 289, 289, 289, 226, 289, 289, 0, 289, + 108, 289, 289, 271, 270, 289, 0, 289, 273, 98, + 104, 106, 268, 0, 96, 103, 259, 95, 125, 140, + 0, 230, 226, 226, 233, 241, 227, 82, 222, 229, + 0, 233, 94, 235, 217, 221, 225, 206, 0, 289, + 289, 289, 289, 289, 289, 289, 289, 289, 0, 252, + + 251, 0, 289, 113, 289, 289, 113, 115, 131, 225, + 218, 223, 210, 219, 215, 205, 218, 221, 211, 204, + 209, 213, 200, 211, 210, 201, 185, 0, 289, 232, + 208, 0, 198, 204, 197, 202, 188, 189, 186, 0, + 181, 201, 190, 197, 0, 0, 187, 172, 0, 289, + 179, 192, 0, 190, 183, 0, 187, 183, 0, 175, + 189, 173, 0, 0, 176, 0, 172, 173, 143, 130, + 0, 0, 133, 289, 121, 122, 127, 135, 125, 121, + 129, 0, 115, 127, 0, 111, 0, 108, 0, 114, + 0, 106, 105, 0, 289, 172, 178, 184, 190, 192, + + 194, 197, 203, 209, 135, 120, 97, 55 + } ; + +static const flex_int16_t yy_def[209] = + { 0, + 195, 1, 196, 196, 197, 197, 198, 198, 199, 199, + 195, 195, 195, 195, 195, 195, 195, 195, 200, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 201, 195, + 195, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 195, 195, 195, 195, 195, 195, 202, 195, + 203, 195, 195, 195, 195, 195, 204, 195, 195, 195, + 195, 195, 195, 200, 195, 195, 195, 195, 195, 195, + 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 201, 201, 201, 201, 195, 202, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 205, 195, + + 195, 204, 195, 195, 195, 195, 195, 195, 195, 201, + 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 201, 201, 201, 195, 206, 195, 195, + 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 201, 201, 201, 201, 195, 207, 195, + 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 208, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 195, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 201, 0, 195, 195, 195, 195, 195, + + 195, 195, 195, 195, 195, 195, 195, 195 + } ; + +static const flex_int16_t yy_nxt[345] = + { 0, + 12, 13, 14, 15, 13, 16, 17, 18, 19, 12, + 20, 21, 12, 22, 23, 12, 24, 25, 26, 27, + 28, 29, 29, 29, 30, 12, 31, 29, 29, 29, + 32, 33, 34, 29, 29, 35, 29, 36, 37, 38, + 29, 39, 29, 40, 41, 42, 29, 29, 29, 43, + 44, 45, 12, 12, 46, 12, 12, 47, 48, 174, + 52, 50, 12, 12, 47, 48, 54, 52, 50, 58, + 59, 58, 59, 54, 60, 61, 61, 60, 62, 61, + 51, 65, 66, 68, 73, 55, 68, 51, 70, 70, + 75, 69, 55, 74, 69, 77, 78, 83, 85, 60, + + 69, 164, 60, 69, 86, 76, 61, 61, 61, 104, + 68, 107, 107, 84, 91, 62, 61, 68, 69, 70, + 70, 121, 116, 92, 149, 69, 117, 69, 122, 107, + 107, 109, 109, 93, 69, 69, 94, 108, 108, 128, + 95, 109, 109, 194, 69, 193, 96, 109, 109, 192, + 97, 191, 98, 99, 68, 190, 70, 70, 189, 188, + 187, 186, 69, 185, 184, 183, 182, 181, 180, 179, + 178, 69, 49, 49, 49, 49, 49, 49, 53, 53, + 53, 53, 53, 53, 56, 56, 56, 56, 56, 56, + 57, 57, 57, 57, 57, 57, 64, 64, 71, 71, + + 89, 89, 89, 90, 177, 90, 90, 90, 90, 102, + 176, 175, 102, 102, 102, 173, 172, 171, 170, 169, + 168, 167, 166, 165, 88, 163, 162, 161, 160, 159, + 158, 157, 156, 155, 154, 153, 152, 151, 150, 148, + 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, + 137, 136, 135, 134, 133, 132, 131, 130, 129, 127, + 126, 125, 124, 123, 120, 119, 118, 115, 114, 113, + 112, 111, 110, 106, 105, 103, 101, 100, 88, 87, + 82, 81, 80, 79, 72, 67, 63, 195, 11, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 195, 195 + } ; + +static const flex_int16_t yy_chk[345] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 3, 3, 3, 208, + 5, 3, 4, 4, 4, 4, 5, 6, 4, 9, + 9, 10, 10, 6, 13, 14, 14, 13, 15, 15, + 3, 22, 22, 24, 33, 5, 25, 4, 25, 25, + 34, 24, 6, 33, 25, 35, 35, 40, 41, 60, + + 24, 207, 60, 25, 41, 34, 61, 61, 62, 62, + 65, 68, 68, 40, 51, 104, 104, 66, 65, 66, + 66, 83, 78, 51, 206, 66, 78, 65, 83, 107, + 107, 108, 108, 51, 66, 107, 51, 69, 69, 205, + 51, 69, 69, 193, 107, 192, 51, 109, 109, 190, + 51, 188, 51, 51, 70, 186, 70, 70, 184, 183, + 181, 180, 70, 179, 178, 177, 176, 175, 173, 170, + 169, 70, 196, 196, 196, 196, 196, 196, 197, 197, + 197, 197, 197, 197, 198, 198, 198, 198, 198, 198, + 199, 199, 199, 199, 199, 199, 200, 200, 201, 201, + + 202, 202, 202, 203, 168, 203, 203, 203, 203, 204, + 167, 165, 204, 204, 204, 162, 161, 160, 158, 157, + 155, 154, 152, 151, 148, 147, 144, 143, 142, 141, + 139, 138, 137, 136, 135, 134, 133, 131, 130, 127, + 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, + 116, 115, 114, 113, 112, 111, 110, 101, 100, 88, + 87, 86, 85, 84, 82, 80, 79, 77, 76, 75, + 74, 73, 72, 67, 63, 59, 55, 54, 46, 42, + 39, 38, 37, 36, 32, 23, 17, 11, 195, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, + 195, 195, 195, 195 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "lexer.lpp" +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#line 9 "lexer.lpp" +#include +#include +#include +#include +#include +#include +#include +#include "location.hh" +#include "position.hh" +#include "parser.tab.hpp" +#include "syntaxdefs.h" + +// Keep track of token lengths. +#define YY_USER_ACTION yyextra->loc.columns(yyleng); + +static void escape(char c, char *buf); + +static std::string clean_up_block_string(const std::string &str); + +#line 615 "lexer.cpp" +#define YY_NO_INPUT 1 + +#line 618 "lexer.cpp" + +#define INITIAL 0 +#define STRING_STATE 1 +#define BLOCK_STRING_STATE 2 +#define C_COMMENT_STATE 3 +#define LINE_COMMENT_STATE 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#define YY_EXTRA_TYPE struct LexerExtra * + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals ( yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +YYSTYPE * yyget_lval ( yyscan_t yyscanner ); + +void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); + + YYLTYPE *yyget_lloc ( yyscan_t yyscanner ); + + void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( yyscan_t yyscanner ); +#else +static int input ( yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_load_buffer_state( yyscanner ); + } + + { +#line 54 "lexer.lpp" + + + +#line 58 "lexer.lpp" + yyextra->loc.step(); + + +#line 910 "lexer.cpp" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 196 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_current_state != 195 ); + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 62 "lexer.lpp" +{ + BEGIN(INITIAL); + yylval->str = yyextra->str.c_str(); + *yylloc = yyextra->loc; + return yy::GraphQLParserImpl::token::TOK_STRING; + } + YY_BREAK +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +#line 69 "lexer.lpp" +{ + throw make_error(yyextra->loc, "Unterminated string"); + } + YY_BREAK +case YY_STATE_EOF(STRING_STATE): +#line 73 "lexer.lpp" +{ + throw make_error(yyextra->loc, "Unterminated string at EOF"); + } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 77 "lexer.lpp" +{ + char *p = yytext; + while (*p) { + yyextra->str.push_back(*p++); + } + } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 84 "lexer.lpp" +{ yyextra->str.push_back('"'); } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 85 "lexer.lpp" +{ yyextra->str.push_back('\\'); } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 86 "lexer.lpp" +{ yyextra->str.push_back('/'); } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 87 "lexer.lpp" +{ yyextra->str.push_back('\n'); } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 88 "lexer.lpp" +{ yyextra->str.push_back('\t'); } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 89 "lexer.lpp" +{ yyextra->str.push_back('\r'); } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 90 "lexer.lpp" +{ yyextra->str.push_back('\b'); } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 91 "lexer.lpp" +{ yyextra->str.push_back('\f'); } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 93 "lexer.lpp" +{ + int ch; + sscanf(yytext + 2, "%x", &ch); + yyextra->str.push_back(ch); + } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 99 "lexer.lpp" +{ throw make_error(yyextra->loc, "bad Unicode escape sequence"); } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 100 "lexer.lpp" +{ throw make_error(yyextra->loc, std::string("bad escape sequence \\") + yytext[1]); } + YY_BREAK + + +case YY_STATE_EOF(BLOCK_STRING_STATE): +#line 105 "lexer.lpp" +{ + throw make_error(yyextra->loc, "Unterminated block string at EOF"); + } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 109 "lexer.lpp" +{ + throw make_error(yyextra->loc, std::string("Invalid character ") + yytext[0]); + } + YY_BREAK +case 16: +/* rule 16 can match eol */ +YY_RULE_SETUP +#line 113 "lexer.lpp" +{ + /* Can't use {GOODCHAR}+ because that would be a better match for + """ than the explicit rule! */ + yyextra->str.push_back(*yytext); + } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 119 "lexer.lpp" +{ + yyextra->str.append(3, '"'); + } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 123 "lexer.lpp" +{ + BEGIN(INITIAL); + yyextra->str = clean_up_block_string(yyextra->str); + yylval->str = yyextra->str.c_str(); + *yylloc = yyextra->loc; + return yy::GraphQLParserImpl::token::TOK_STRING; + } + YY_BREAK + + +case 19: +/* rule 19 can match eol */ +YY_RULE_SETUP +#line 133 "lexer.lpp" +{ yyextra->loc.lines(yyleng / 2); yyextra->loc.step(); BEGIN(INITIAL); } + YY_BREAK +case 20: +/* rule 20 can match eol */ +YY_RULE_SETUP +#line 134 "lexer.lpp" +{ yyextra->loc.lines(yyleng); yyextra->loc.step(); BEGIN(INITIAL); } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 135 "lexer.lpp" +/* eat comment character */ + YY_BREAK + + +case 22: +YY_RULE_SETUP +#line 139 "lexer.lpp" +{ yyextra->loc.step(); } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 140 "lexer.lpp" +{ yyextra->loc.step(); yyextra->loc.step(); yyextra->loc.step(); } + YY_BREAK +case 24: +/* rule 24 can match eol */ +YY_RULE_SETUP +#line 141 "lexer.lpp" +{ yyextra->loc.lines(yyleng / 2); yyextra->loc.step(); } + YY_BREAK +case 25: +/* rule 25 can match eol */ +YY_RULE_SETUP +#line 142 "lexer.lpp" +{ yyextra->loc.lines(yyleng); yyextra->loc.step(); } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 144 "lexer.lpp" +{yyextra->loc.step(); BEGIN(LINE_COMMENT_STATE); } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 146 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_DIRECTIVE; } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 147 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_ENUM; } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 148 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_EXTEND; } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 149 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_FALSE; } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 150 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_FRAGMENT; } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 151 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_IMPLEMENTS; } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 152 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_INPUT; } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 153 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_INTERFACE; } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 154 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_MUTATION; } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 155 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_NULL; } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 156 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_ON; } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 157 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_QUERY; } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 158 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_SCALAR; } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 159 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_SCHEMA; } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 160 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_SUBSCRIPTION; } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 161 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_TRUE; } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 162 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_TYPE; } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 163 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_UNION; } + YY_BREAK +case 45: +YY_RULE_SETUP +#line 165 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_INTEGER; } + YY_BREAK +case 46: +YY_RULE_SETUP +#line 166 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_FLOAT; } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 167 "lexer.lpp" +{ yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_IDENTIFIER; } + YY_BREAK +case 48: +YY_RULE_SETUP +#line 168 "lexer.lpp" +{ yylval->str = yytext + 1; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_VARIABLE; } + YY_BREAK +case 49: +YY_RULE_SETUP +#line 170 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_BANG; } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 171 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_LPAREN; } + YY_BREAK +case 51: +YY_RULE_SETUP +#line 172 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_RPAREN; } + YY_BREAK +case 52: +YY_RULE_SETUP +#line 173 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_ELLIPSIS; } + YY_BREAK +case 53: +YY_RULE_SETUP +#line 174 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_COLON; } + YY_BREAK +case 54: +YY_RULE_SETUP +#line 175 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_EQUAL; } + YY_BREAK +case 55: +YY_RULE_SETUP +#line 176 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_AT; } + YY_BREAK +case 56: +YY_RULE_SETUP +#line 177 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_LBRACKET; } + YY_BREAK +case 57: +YY_RULE_SETUP +#line 178 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_RBRACKET; } + YY_BREAK +case 58: +YY_RULE_SETUP +#line 179 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_LBRACE; } + YY_BREAK +case 59: +YY_RULE_SETUP +#line 180 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_PIPE; } + YY_BREAK +case 60: +YY_RULE_SETUP +#line 181 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_RBRACE; } + YY_BREAK +case YY_STATE_EOF(INITIAL): +#line 184 "lexer.lpp" +{ *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_EOF; } + YY_BREAK +case 61: +YY_RULE_SETUP +#line 186 "lexer.lpp" +{ + BEGIN(BLOCK_STRING_STATE); + yyextra->str.clear(); + } + YY_BREAK +case 62: +YY_RULE_SETUP +#line 191 "lexer.lpp" +{ + BEGIN(STRING_STATE); + yyextra->str.clear(); + } + YY_BREAK + +case 63: +YY_RULE_SETUP +#line 197 "lexer.lpp" +{ + char buf[6]; + escape(yytext[0], buf); + throw make_error( + yyextra->loc, + std::string("unrecognized character ") + buf); +} + YY_BREAK +case 64: +YY_RULE_SETUP +#line 205 "lexer.lpp" +ECHO; + YY_BREAK +#line 1354 "lexer.cpp" +case YY_STATE_EOF(C_COMMENT_STATE): +case YY_STATE_EOF(LINE_COMMENT_STATE): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( yywrap( yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = yyg->yytext_ptr; + int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin , yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + yy_state_type yy_current_state; + char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 196 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + char *yy_cp = yyg->yy_c_buf_p; + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 196 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 195); + + (void)yyg; + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin , yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( yyscanner ) ) + return 0; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); + yy_load_buffer_state( yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file , yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * @param yyscanner The scanner object. + */ + void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf , yyscanner ); + + yyfree( (void *) b , yyscanner ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_flush_buffer( b , yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(yyscanner); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (yyscan_t yyscanner) +{ + yy_size_t num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b , yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n , yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n , yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param _line_number line number + * @param yyscanner The scanner object. + */ +void yyset_lineno (int _line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); + + yylineno = _line_number; +} + +/** Set the current column. + * @param _column_no column number + * @param yyscanner The scanner object. + */ +void yyset_column (int _column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + YY_FATAL_ERROR( "yyset_column called with no buffer" ); + + yycolumn = _column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * @param yyscanner The scanner object. + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = _out_str ; +} + +int yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void yyset_debug (int _bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = _bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *yyget_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ +int yylex_init(yyscan_t* ptr_yy_globals) +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* yylex_init_extra has the same functionality as yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to yyalloc in + * the yyextra field. + */ +int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) +{ + struct yyguts_t dummy_yyguts; + + yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = NULL; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = NULL; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + yyfree(yyg->yy_buffer_stack , yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + yyfree( yyg->yy_start_stack , yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s , yyscan_t yyscanner) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + (void)yyg; + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 205 "lexer.lpp" + + +static void escape(char c, char *buf) { + if (std::isgraph(c)) { + *buf = c; + buf[1] = '\0'; + } else { + buf[0] = '\\'; + buf[2] = '\0'; + switch (c) { + case '\a': + buf[1] = 'a'; + break; + case '\b': + buf[1] = 'b'; + break; + case '\f': + buf[1] = 'f'; + break; + case '\n': + buf[1] = 'n'; + break; + case '\r': + buf[1] = 'r'; + break; + case '\t': + buf[1] = 't'; + break; + case '\v': + buf[1] = 'v'; + break; + default: + buf[1] = 'x'; + std::snprintf(buf + 2, 3, "%x", ((int)c & 0xFF)); + break; + } + } +} + +static std::vector splitLines(const std::string &str) { + std::vector lines; + auto it = str.begin(); + while (it != str.end()) { + static char terminators[2] = {'\r', '\n'}; + auto nextIt = std::find_first_of(it, str.end(), terminators, terminators + sizeof(terminators)); + lines.emplace_back(str.data() + (it - str.begin()), nextIt - it); + if (nextIt != str.end()) { + auto advancedIt = nextIt + 1; + if (advancedIt != str.end()) { + if (*nextIt == '\r' && *advancedIt == '\n') { + ++advancedIt; + } + } + nextIt = std::move(advancedIt); + } + it = std::move(nextIt); + } + return lines; +} + +static int count_leading_whitespace(const std::string &str) { + auto pos = str.find_first_not_of(" \t", 0, strlen(" \t")); + if (pos == std::string::npos) { + return str.length(); + } + return pos; +} + +static bool is_all_whitespace(const std::string &str) { + return count_leading_whitespace(str) == str.length(); +} + +static std::string clean_up_block_string(const std::string &str) { + auto lines = splitLines(str); + bool first = true; + int commonIndent = INT_MAX; + for (const auto &line : lines) { + if (first) { + first = false; + continue; + } + const auto indent = count_leading_whitespace(line); + if (indent < line.length()) { + if (indent < commonIndent) { + commonIndent = indent; + } + } + } + if (commonIndent != INT_MAX) { + first = true; + for (auto &line : lines) { + if (first) { + first = false; + continue; + } + line.erase(0, commonIndent); + } + } + + const auto firstNonBlankIt = std::find_if(lines.begin(), lines.end(), [](const std::string &line) { + return !is_all_whitespace(line); + }); + lines.erase(lines.begin(), firstNonBlankIt); + + const auto firstNonBlankReverseIt = std::find_if(lines.rbegin(), lines.rend(), [](const std::string &line) { + return !is_all_whitespace(line); + }); + lines.erase(lines.end() - (firstNonBlankReverseIt - lines.rbegin()), lines.end()); + + std::string formatted; + first = true; + for (const auto &line: lines) { + if (first) { + first = false; + } else { + formatted.push_back('\n'); + } + formatted.append(line); + } + return formatted; +} + diff --git a/external/graphqlparser/parsergen/lexer.h b/external/graphqlparser/parsergen/lexer.h new file mode 100644 index 0000000..c0b5f91 --- /dev/null +++ b/external/graphqlparser/parsergen/lexer.h @@ -0,0 +1,528 @@ +#ifndef yyHEADER_H +#define yyHEADER_H 1 +#define yyIN_HEADER 1 + +#line 5 "lexer.h" + +#line 7 "lexer.h" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yyget_lval +#define yyget_lval_ALREADY_DEFINED +#else +#define yyget_lval yyget_lval +#endif + +#ifdef yyset_lval +#define yyset_lval_ALREADY_DEFINED +#else +#define yyset_lval yyset_lval +#endif + +#ifdef yyget_lloc +#define yyget_lloc_ALREADY_DEFINED +#else +#define yyget_lloc yyget_lloc +#endif + +#ifdef yyset_lloc +#define yyset_lloc_ALREADY_DEFINED +#else +#define yyset_lloc yyset_lloc +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +/* Begin user sect3 */ + +#define yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 +#define STRING_STATE 1 +#define BLOCK_STRING_STATE 2 +#define C_COMMENT_STATE 3 +#define LINE_COMMENT_STATE 4 + +#endif + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#define YY_EXTRA_TYPE struct LexerExtra * + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +YYSTYPE * yyget_lval ( yyscan_t yyscanner ); + +void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); + + YYLTYPE *yyget_lloc ( yyscan_t yyscanner ); + + void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner); + +#define YY_DECL int yylex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#ifndef yy_create_buffer_ALREADY_DEFINED +#undef yy_create_buffer +#endif +#ifndef yy_delete_buffer_ALREADY_DEFINED +#undef yy_delete_buffer +#endif +#ifndef yy_scan_buffer_ALREADY_DEFINED +#undef yy_scan_buffer +#endif +#ifndef yy_scan_string_ALREADY_DEFINED +#undef yy_scan_string +#endif +#ifndef yy_scan_bytes_ALREADY_DEFINED +#undef yy_scan_bytes +#endif +#ifndef yy_init_buffer_ALREADY_DEFINED +#undef yy_init_buffer +#endif +#ifndef yy_flush_buffer_ALREADY_DEFINED +#undef yy_flush_buffer +#endif +#ifndef yy_load_buffer_state_ALREADY_DEFINED +#undef yy_load_buffer_state +#endif +#ifndef yy_switch_to_buffer_ALREADY_DEFINED +#undef yy_switch_to_buffer +#endif +#ifndef yypush_buffer_state_ALREADY_DEFINED +#undef yypush_buffer_state +#endif +#ifndef yypop_buffer_state_ALREADY_DEFINED +#undef yypop_buffer_state +#endif +#ifndef yyensure_buffer_stack_ALREADY_DEFINED +#undef yyensure_buffer_stack +#endif +#ifndef yylex_ALREADY_DEFINED +#undef yylex +#endif +#ifndef yyrestart_ALREADY_DEFINED +#undef yyrestart +#endif +#ifndef yylex_init_ALREADY_DEFINED +#undef yylex_init +#endif +#ifndef yylex_init_extra_ALREADY_DEFINED +#undef yylex_init_extra +#endif +#ifndef yylex_destroy_ALREADY_DEFINED +#undef yylex_destroy +#endif +#ifndef yyget_debug_ALREADY_DEFINED +#undef yyget_debug +#endif +#ifndef yyset_debug_ALREADY_DEFINED +#undef yyset_debug +#endif +#ifndef yyget_extra_ALREADY_DEFINED +#undef yyget_extra +#endif +#ifndef yyset_extra_ALREADY_DEFINED +#undef yyset_extra +#endif +#ifndef yyget_in_ALREADY_DEFINED +#undef yyget_in +#endif +#ifndef yyset_in_ALREADY_DEFINED +#undef yyset_in +#endif +#ifndef yyget_out_ALREADY_DEFINED +#undef yyget_out +#endif +#ifndef yyset_out_ALREADY_DEFINED +#undef yyset_out +#endif +#ifndef yyget_leng_ALREADY_DEFINED +#undef yyget_leng +#endif +#ifndef yyget_text_ALREADY_DEFINED +#undef yyget_text +#endif +#ifndef yyget_lineno_ALREADY_DEFINED +#undef yyget_lineno +#endif +#ifndef yyset_lineno_ALREADY_DEFINED +#undef yyset_lineno +#endif +#ifndef yyget_column_ALREADY_DEFINED +#undef yyget_column +#endif +#ifndef yyset_column_ALREADY_DEFINED +#undef yyset_column +#endif +#ifndef yywrap_ALREADY_DEFINED +#undef yywrap +#endif +#ifndef yyget_lval_ALREADY_DEFINED +#undef yyget_lval +#endif +#ifndef yyset_lval_ALREADY_DEFINED +#undef yyset_lval +#endif +#ifndef yyget_lloc_ALREADY_DEFINED +#undef yyget_lloc +#endif +#ifndef yyset_lloc_ALREADY_DEFINED +#undef yyset_lloc +#endif +#ifndef yyalloc_ALREADY_DEFINED +#undef yyalloc +#endif +#ifndef yyrealloc_ALREADY_DEFINED +#undef yyrealloc +#endif +#ifndef yyfree_ALREADY_DEFINED +#undef yyfree +#endif +#ifndef yytext_ALREADY_DEFINED +#undef yytext +#endif +#ifndef yyleng_ALREADY_DEFINED +#undef yyleng +#endif +#ifndef yyin_ALREADY_DEFINED +#undef yyin +#endif +#ifndef yyout_ALREADY_DEFINED +#undef yyout +#endif +#ifndef yy_flex_debug_ALREADY_DEFINED +#undef yy_flex_debug +#endif +#ifndef yylineno_ALREADY_DEFINED +#undef yylineno +#endif +#ifndef yytables_fload_ALREADY_DEFINED +#undef yytables_fload +#endif +#ifndef yytables_destroy_ALREADY_DEFINED +#undef yytables_destroy +#endif +#ifndef yyTABLES_NAME_ALREADY_DEFINED +#undef yyTABLES_NAME +#endif + +#line 205 "lexer.lpp" + + +#line 526 "lexer.h" +#undef yyIN_HEADER +#endif /* yyHEADER_H */ diff --git a/external/graphqlparser/parsergen/location.hh b/external/graphqlparser/parsergen/location.hh new file mode 100644 index 0000000..0ff8530 --- /dev/null +++ b/external/graphqlparser/parsergen/location.hh @@ -0,0 +1,189 @@ +// A Bison parser, made by GNU Bison 3.0.5. + +// Locations for Bison parsers in C++ + +// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +/** + ** \file location.hh + ** Define the yy::location class. + */ + +#ifndef YY_YY_LOCATION_HH_INCLUDED +# define YY_YY_LOCATION_HH_INCLUDED + +# include "position.hh" + + +namespace yy { +#line 46 "location.hh" // location.cc:333 + /// Abstract a location. + class location + { + public: + + /// Construct a location from \a b to \a e. + location (const position& b, const position& e) + : begin (b) + , end (e) + {} + + /// Construct a 0-width location in \a p. + explicit location (const position& p = position ()) + : begin (p) + , end (p) + {} + + /// Construct a 0-width location in \a f, \a l, \a c. + explicit location (std::string* f, + unsigned l = 1u, + unsigned c = 1u) + : begin (f, l, c) + , end (f, l, c) + {} + + + /// Initialization. + void initialize (std::string* f = YY_NULLPTR, + unsigned l = 1u, + unsigned c = 1u) + { + begin.initialize (f, l, c); + end = begin; + } + + /** \name Line and Column related manipulators + ** \{ */ + public: + /// Reset initial location to final location. + void step () + { + begin = end; + } + + /// Extend the current location to the COUNT next columns. + void columns (int count = 1) + { + end += count; + } + + /// Extend the current location to the COUNT next lines. + void lines (int count = 1) + { + end.lines (count); + } + /** \} */ + + + public: + /// Beginning of the located region. + position begin; + /// End of the located region. + position end; + }; + + /// Join two locations, in place. + inline location& operator+= (location& res, const location& end) + { + res.end = end.end; + return res; + } + + /// Join two locations. + inline location operator+ (location res, const location& end) + { + return res += end; + } + + /// Add \a width columns to the end position, in place. + inline location& operator+= (location& res, int width) + { + res.columns (width); + return res; + } + + /// Add \a width columns to the end position. + inline location operator+ (location res, int width) + { + return res += width; + } + + /// Subtract \a width columns to the end position, in place. + inline location& operator-= (location& res, int width) + { + return res += -width; + } + + /// Subtract \a width columns to the end position. + inline location operator- (location res, int width) + { + return res -= width; + } + + /// Compare two location objects. + inline bool + operator== (const location& loc1, const location& loc2) + { + return loc1.begin == loc2.begin && loc1.end == loc2.end; + } + + /// Compare two location objects. + inline bool + operator!= (const location& loc1, const location& loc2) + { + return !(loc1 == loc2); + } + + /** \brief Intercept output stream redirection. + ** \param ostr the destination output stream + ** \param loc a reference to the location to redirect + ** + ** Avoid duplicate information. + */ + template + inline std::basic_ostream& + operator<< (std::basic_ostream& ostr, const location& loc) + { + unsigned end_col = 0 < loc.end.column ? loc.end.column - 1 : 0; + ostr << loc.begin; + if (loc.end.filename + && (!loc.begin.filename + || *loc.begin.filename != *loc.end.filename)) + ostr << '-' << loc.end.filename << ':' << loc.end.line << '.' << end_col; + else if (loc.begin.line < loc.end.line) + ostr << '-' << loc.end.line << '.' << end_col; + else if (loc.begin.column < end_col) + ostr << '-' << end_col; + return ostr; + } + + +} // yy +#line 189 "location.hh" // location.cc:333 +#endif // !YY_YY_LOCATION_HH_INCLUDED diff --git a/external/graphqlparser/parsergen/parser.tab.cpp b/external/graphqlparser/parsergen/parser.tab.cpp new file mode 100644 index 0000000..181fc28 --- /dev/null +++ b/external/graphqlparser/parsergen/parser.tab.cpp @@ -0,0 +1,3300 @@ +// A Bison parser, made by GNU Bison 3.0.5. + +// Skeleton implementation for Bison LALR(1) parsers in C++ + +// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + + +// First part of user declarations. + +#line 37 "parser.tab.cpp" // lalr1.cc:406 + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +#include "parser.tab.hpp" + +// User implementation prologue. + +#line 51 "parser.tab.cpp" // lalr1.cc:414 +// Unqualified %code blocks. +#line 157 "parser.ypp" // lalr1.cc:415 + +#include "lexer.h" +#include "syntaxdefs.h" + +#line 58 "parser.tab.cpp" // lalr1.cc:415 + + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include // FIXME: INFRINGES ON USER NAME SPACE. +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K].location) +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +# ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).begin = YYRHSLOC (Rhs, 1).begin; \ + (Current).end = YYRHSLOC (Rhs, N).end; \ + } \ + else \ + { \ + (Current).begin = (Current).end = YYRHSLOC (Rhs, 0).end; \ + } \ + while (/*CONSTCOND*/ false) +# endif + + +// Suppress unused-variable warnings by "using" E. +#define YYUSE(E) ((void) (E)) + +// Enable debugging if requested. +#if YYDEBUG + +// A pseudo ostream that takes yydebug_ into account. +# define YYCDEBUG if (yydebug_) (*yycdebug_) + +# define YY_SYMBOL_PRINT(Title, Symbol) \ + do { \ + if (yydebug_) \ + { \ + *yycdebug_ << Title << ' '; \ + yy_print_ (*yycdebug_, Symbol); \ + *yycdebug_ << '\n'; \ + } \ + } while (false) + +# define YY_REDUCE_PRINT(Rule) \ + do { \ + if (yydebug_) \ + yy_reduce_print_ (Rule); \ + } while (false) + +# define YY_STACK_PRINT() \ + do { \ + if (yydebug_) \ + yystack_print_ (); \ + } while (false) + +#else // !YYDEBUG + +# define YYCDEBUG if (false) std::cerr +# define YY_SYMBOL_PRINT(Title, Symbol) YYUSE (Symbol) +# define YY_REDUCE_PRINT(Rule) static_cast (0) +# define YY_STACK_PRINT() static_cast (0) + +#endif // !YYDEBUG + +#define yyerrok (yyerrstatus_ = 0) +#define yyclearin (yyla.clear ()) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYRECOVERING() (!!yyerrstatus_) + + +namespace yy { +#line 144 "parser.tab.cpp" // lalr1.cc:481 + + /* Return YYSTR after stripping away unnecessary quotes and + backslashes, so that it's suitable for yyerror. The heuristic is + that double-quoting is unnecessary unless the string contains an + apostrophe, a comma, or backslash (other than backslash-backslash). + YYSTR is taken from yytname. */ + std::string + GraphQLParserImpl::yytnamerr_ (const char *yystr) + { + if (*yystr == '"') + { + std::string yyr = ""; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + // Fall through. + default: + yyr += *yyp; + break; + + case '"': + return yyr; + } + do_not_strip_quotes: ; + } + + return yystr; + } + + + /// Build a parser object. + GraphQLParserImpl::GraphQLParserImpl (bool enableSchema_yyarg, Node **outAST_yyarg, const char **outError_yyarg, void *scanner_yyarg) + : +#if YYDEBUG + yydebug_ (false), + yycdebug_ (&std::cerr), +#endif + enableSchema (enableSchema_yyarg), + outAST (outAST_yyarg), + outError (outError_yyarg), + scanner (scanner_yyarg) + {} + + GraphQLParserImpl::~GraphQLParserImpl () + {} + + + /*---------------. + | Symbol types. | + `---------------*/ + + GraphQLParserImpl::syntax_error::syntax_error (const location_type& l, const std::string& m) + : std::runtime_error (m) + , location (l) + {} + + // basic_symbol. + template + GraphQLParserImpl::basic_symbol::basic_symbol () + : value () + {} + + template + GraphQLParserImpl::basic_symbol::basic_symbol (const basic_symbol& other) + : Base (other) + , value () + , location (other.location) + { + value = other.value; + } + + template + GraphQLParserImpl::basic_symbol::basic_symbol (typename Base::kind_type t, const semantic_type& v, const location_type& l) + : Base (t) + , value (v) + , location (l) + {} + + + /// Constructor for valueless symbols. + template + GraphQLParserImpl::basic_symbol::basic_symbol (typename Base::kind_type t, const location_type& l) + : Base (t) + , value () + , location (l) + {} + + template + GraphQLParserImpl::basic_symbol::~basic_symbol () + { + clear (); + } + + template + void + GraphQLParserImpl::basic_symbol::clear () + { + Base::clear (); + } + + template + bool + GraphQLParserImpl::basic_symbol::empty () const + { + return Base::type_get () == empty_symbol; + } + + template + void + GraphQLParserImpl::basic_symbol::move (basic_symbol& s) + { + super_type::move (s); + value = s.value; + location = s.location; + } + + // by_type. + GraphQLParserImpl::by_type::by_type () + : type (empty_symbol) + {} + + GraphQLParserImpl::by_type::by_type (const by_type& other) + : type (other.type) + {} + + GraphQLParserImpl::by_type::by_type (token_type t) + : type (yytranslate_ (t)) + {} + + void + GraphQLParserImpl::by_type::clear () + { + type = empty_symbol; + } + + void + GraphQLParserImpl::by_type::move (by_type& that) + { + type = that.type; + that.clear (); + } + + int + GraphQLParserImpl::by_type::type_get () const + { + return type; + } + + + // by_state. + GraphQLParserImpl::by_state::by_state () + : state (empty_state) + {} + + GraphQLParserImpl::by_state::by_state (const by_state& other) + : state (other.state) + {} + + void + GraphQLParserImpl::by_state::clear () + { + state = empty_state; + } + + void + GraphQLParserImpl::by_state::move (by_state& that) + { + state = that.state; + that.clear (); + } + + GraphQLParserImpl::by_state::by_state (state_type s) + : state (s) + {} + + GraphQLParserImpl::symbol_number_type + GraphQLParserImpl::by_state::type_get () const + { + if (state == empty_state) + return empty_symbol; + else + return yystos_[state]; + } + + GraphQLParserImpl::stack_symbol_type::stack_symbol_type () + {} + + GraphQLParserImpl::stack_symbol_type::stack_symbol_type (const stack_symbol_type& that) + : super_type (that.state, that.location) + { + value = that.value; + } + + GraphQLParserImpl::stack_symbol_type::stack_symbol_type (state_type s, symbol_type& that) + : super_type (s, that.location) + { + value = that.value; + // that is emptied. + that.type = empty_symbol; + } + + GraphQLParserImpl::stack_symbol_type& + GraphQLParserImpl::stack_symbol_type::operator= (const stack_symbol_type& that) + { + state = that.state; + value = that.value; + location = that.location; + return *this; + } + + + template + void + GraphQLParserImpl::yy_destroy_ (const char* yymsg, basic_symbol& yysym) const + { + if (yymsg) + YY_SYMBOL_PRINT (yymsg, yysym); + + // User destructor. + switch (yysym.type_get ()) + { + case 3: // "directive" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 379 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 4: // "enum" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 386 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 5: // "extend" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 393 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 6: // "false" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 400 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 7: // "fragment" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 407 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 8: // "implements" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 414 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 9: // "input" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 421 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 10: // "interface" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 428 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 11: // "mutation" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 435 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 12: // "null" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 442 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 13: // "query" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 449 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 14: // "on" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 456 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 15: // "scalar" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 463 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 16: // "schema" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 470 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 17: // "subscription" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 477 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 18: // "true" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 484 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 19: // "type" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 491 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 20: // "union" + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 498 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 33: // VARIABLE + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 505 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 34: // INTEGER + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 512 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 35: // FLOAT + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 519 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 36: // STRING + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 526 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 37: // IDENTIFIER + +#line 289 "parser.ypp" // lalr1.cc:616 + { } +#line 533 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 39: // start + +#line 291 "parser.ypp" // lalr1.cc:616 + { } +#line 540 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 40: // fragment_name + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.name); } +#line 547 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 41: // name + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.name); } +#line 554 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 42: // name_opt + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.name); } +#line 561 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 43: // document + +#line 291 "parser.ypp" // lalr1.cc:616 + { } +#line 568 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 44: // definition_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.definitionList); } +#line 575 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 45: // definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.definition); } +#line 582 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 46: // schema_gate + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.definition); } +#line 589 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 47: // operation_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.operationDefinition); } +#line 596 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 48: // operation_type + +#line 290 "parser.ypp" // lalr1.cc:616 + { free((void *)(yysym.value.heapStr)); } +#line 603 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 49: // variable_definitions + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.variableDefinitionList); } +#line 610 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 50: // variable_definition_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.variableDefinitionList); } +#line 617 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 51: // variable + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.variable); } +#line 624 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 52: // variable_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.variableDefinition); } +#line 631 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 53: // default_value_opt + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.value); } +#line 638 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 54: // default_value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.value); } +#line 645 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 55: // selection_set + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.selectionSet); } +#line 652 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 56: // selection_set_opt + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.selectionSet); } +#line 659 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 57: // selection_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.selectionList); } +#line 666 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 58: // selection + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.selection); } +#line 673 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 59: // field + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.field); } +#line 680 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 60: // arguments + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.argumentList); } +#line 687 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 61: // arguments_opt + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.argumentList); } +#line 694 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 62: // argument_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.argumentList); } +#line 701 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 63: // argument + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.argument); } +#line 708 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 64: // fragment_spread + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.fragmentSpread); } +#line 715 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 65: // inline_fragment + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.inlineFragment); } +#line 722 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 66: // fragment_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.fragmentDefinition); } +#line 729 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 67: // type_condition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.namedType); } +#line 736 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 68: // value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.value); } +#line 743 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 69: // int_value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.intValue); } +#line 750 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 70: // float_value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.floatValue); } +#line 757 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 71: // string_value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.stringValue); } +#line 764 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 72: // value_const + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.value); } +#line 771 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 73: // boolean_value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.booleanValue); } +#line 778 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 74: // null_value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.nullValue); } +#line 785 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 75: // enum_value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.enumValue); } +#line 792 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 76: // list_value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.arrayValue); } +#line 799 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 77: // value_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.valueList); } +#line 806 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 78: // list_value_const + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.arrayValue); } +#line 813 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 79: // value_const_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.valueList); } +#line 820 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 80: // object_value + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.objectValue); } +#line 827 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 81: // object_field_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.objectFieldList); } +#line 834 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 82: // object_field + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.objectField); } +#line 841 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 83: // object_value_const + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.objectValue); } +#line 848 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 84: // object_field_const_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.objectFieldList); } +#line 855 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 85: // object_field_const + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.objectField); } +#line 862 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 86: // directives + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.directiveList); } +#line 869 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 87: // directives_opt + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.directiveList); } +#line 876 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 88: // directive_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.directiveList); } +#line 883 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 89: // directive + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.directive); } +#line 890 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 90: // type + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.type); } +#line 897 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 91: // type_name + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.namedType); } +#line 904 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 92: // list_type + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.listType); } +#line 911 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 93: // non_null_type + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.nonNullType); } +#line 918 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 94: // schema_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.schemaDefinition); } +#line 925 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 95: // operation_type_definition_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.operationTypeDefinitionList); } +#line 932 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 96: // operation_type_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.operationTypeDefinition); } +#line 939 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 97: // scalar_type_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.scalarTypeDefinition); } +#line 946 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 98: // object_type_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.objectTypeDefinition); } +#line 953 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 99: // implements_interfaces_opt + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.typeNameList); } +#line 960 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 100: // type_name_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.typeNameList); } +#line 967 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 101: // field_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.fieldDefinition); } +#line 974 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 102: // field_definition_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.fieldDefinitionList); } +#line 981 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 103: // arguments_definition_opt + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.inputValueDefinitionList); } +#line 988 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 104: // arguments_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.inputValueDefinitionList); } +#line 995 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 105: // input_value_definition_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.inputValueDefinitionList); } +#line 1002 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 106: // input_value_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.inputValueDefinition); } +#line 1009 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 107: // interface_type_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.interfaceTypeDefinition); } +#line 1016 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 108: // union_type_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.unionTypeDefinition); } +#line 1023 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 109: // union_members + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.typeNameList); } +#line 1030 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 110: // enum_type_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.enumTypeDefinition); } +#line 1037 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 111: // enum_value_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.enumValueDefinition); } +#line 1044 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 112: // enum_value_definition_list + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.enumValueDefinitionList); } +#line 1051 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 113: // input_object_type_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.inputObjectTypeDefinition); } +#line 1058 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 114: // type_extension_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.typeExtensionDefinition); } +#line 1065 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 115: // directive_definition + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.directiveDefinition); } +#line 1072 "parser.tab.cpp" // lalr1.cc:616 + break; + + case 116: // directive_locations + +#line 292 "parser.ypp" // lalr1.cc:616 + { delete (yysym.value.nameList); } +#line 1079 "parser.tab.cpp" // lalr1.cc:616 + break; + + + default: + break; + } + } + +#if YYDEBUG + template + void + GraphQLParserImpl::yy_print_ (std::ostream& yyo, + const basic_symbol& yysym) const + { + std::ostream& yyoutput = yyo; + YYUSE (yyoutput); + symbol_number_type yytype = yysym.type_get (); + // Avoid a (spurious) G++ 4.8 warning about "array subscript is + // below array bounds". + if (yysym.empty ()) + std::abort (); + yyo << (yytype < yyntokens_ ? "token" : "nterm") + << ' ' << yytname_[yytype] << " (" + << yysym.location << ": "; + switch (yytype) + { + case 3: // "directive" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1110 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 4: // "enum" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1117 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 5: // "extend" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1124 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 6: // "false" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1131 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 7: // "fragment" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1138 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 8: // "implements" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1145 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 9: // "input" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1152 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 10: // "interface" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1159 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 11: // "mutation" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1166 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 12: // "null" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1173 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 13: // "query" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1180 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 14: // "on" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1187 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 15: // "scalar" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1194 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 16: // "schema" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1201 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 17: // "subscription" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1208 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 18: // "true" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1215 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 19: // "type" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1222 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 20: // "union" + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1229 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 33: // VARIABLE + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1236 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 34: // INTEGER + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1243 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 35: // FLOAT + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1250 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 36: // STRING + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1257 "parser.tab.cpp" // lalr1.cc:635 + break; + + case 37: // IDENTIFIER + +#line 294 "parser.ypp" // lalr1.cc:635 + { yyoutput << (yysym.value.str); } +#line 1264 "parser.tab.cpp" // lalr1.cc:635 + break; + + + default: + break; + } + yyo << ')'; + } +#endif + + void + GraphQLParserImpl::yypush_ (const char* m, state_type s, symbol_type& sym) + { + stack_symbol_type t (s, sym); + yypush_ (m, t); + } + + void + GraphQLParserImpl::yypush_ (const char* m, stack_symbol_type& s) + { + if (m) + YY_SYMBOL_PRINT (m, s); + yystack_.push (s); + } + + void + GraphQLParserImpl::yypop_ (unsigned n) + { + yystack_.pop (n); + } + +#if YYDEBUG + std::ostream& + GraphQLParserImpl::debug_stream () const + { + return *yycdebug_; + } + + void + GraphQLParserImpl::set_debug_stream (std::ostream& o) + { + yycdebug_ = &o; + } + + + GraphQLParserImpl::debug_level_type + GraphQLParserImpl::debug_level () const + { + return yydebug_; + } + + void + GraphQLParserImpl::set_debug_level (debug_level_type l) + { + yydebug_ = l; + } +#endif // YYDEBUG + + GraphQLParserImpl::state_type + GraphQLParserImpl::yy_lr_goto_state_ (state_type yystate, int yysym) + { + int yyr = yypgoto_[yysym - yyntokens_] + yystate; + if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate) + return yytable_[yyr]; + else + return yydefgoto_[yysym - yyntokens_]; + } + + bool + GraphQLParserImpl::yy_pact_value_is_default_ (int yyvalue) + { + return yyvalue == yypact_ninf_; + } + + bool + GraphQLParserImpl::yy_table_value_is_error_ (int yyvalue) + { + return yyvalue == yytable_ninf_; + } + + int + GraphQLParserImpl::parse () + { + // State. + int yyn; + /// Length of the RHS of the rule being reduced. + int yylen = 0; + + // Error handling. + int yynerrs_ = 0; + int yyerrstatus_ = 0; + + /// The lookahead symbol. + symbol_type yyla; + + /// The locations where the error started and ended. + stack_symbol_type yyerror_range[3]; + + /// The return value of parse (). + int yyresult; + + // FIXME: This shoud be completely indented. It is not yet to + // avoid gratuitous conflicts when merging into the master branch. + try + { + YYCDEBUG << "Starting parse\n"; + + + /* Initialize the stack. The initial state will be set in + yynewstate, since the latter expects the semantical and the + location values to have been already stored, initialize these + stacks with a primary value. */ + yystack_.clear (); + yypush_ (YY_NULLPTR, 0, yyla); + + // A new symbol was pushed on the stack. + yynewstate: + YYCDEBUG << "Entering state " << yystack_[0].state << '\n'; + + // Accept? + if (yystack_[0].state == yyfinal_) + goto yyacceptlab; + + goto yybackup; + + // Backup. + yybackup: + + // Try to take a decision without lookahead. + yyn = yypact_[yystack_[0].state]; + if (yy_pact_value_is_default_ (yyn)) + goto yydefault; + + // Read a lookahead token. + if (yyla.empty ()) + { + YYCDEBUG << "Reading a token: "; + try + { + yyla.type = yytranslate_ (yylex (&yyla.value, &yyla.location, scanner)); + } + catch (const syntax_error& yyexc) + { + error (yyexc); + goto yyerrlab1; + } + } + YY_SYMBOL_PRINT ("Next token is", yyla); + + /* If the proper action on seeing token YYLA.TYPE is to reduce or + to detect an error, take that action. */ + yyn += yyla.type_get (); + if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.type_get ()) + goto yydefault; + + // Reduce or error. + yyn = yytable_[yyn]; + if (yyn <= 0) + { + if (yy_table_value_is_error_ (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + // Count tokens shifted since error; after three, turn off error status. + if (yyerrstatus_) + --yyerrstatus_; + + // Shift the lookahead token. + yypush_ ("Shifting", yyn, yyla); + goto yynewstate; + + /*-----------------------------------------------------------. + | yydefault -- do the default action for the current state. | + `-----------------------------------------------------------*/ + yydefault: + yyn = yydefact_[yystack_[0].state]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + /*-----------------------------. + | yyreduce -- Do a reduction. | + `-----------------------------*/ + yyreduce: + yylen = yyr2_[yyn]; + { + stack_symbol_type yylhs; + yylhs.state = yy_lr_goto_state_ (yystack_[yylen].state, yyr1_[yyn]); + /* If YYLEN is nonzero, implement the default value of the + action: '$$ = $1'. Otherwise, use the top of the stack. + + Otherwise, the following line sets YYLHS.VALUE to garbage. + This behavior is undocumented and Bison users should not rely + upon it. */ + if (yylen) + yylhs.value = yystack_[yylen - 1].value; + else + yylhs.value = yystack_[0].value; + + // Default location. + { + slice slice (yystack_, yylen); + YYLLOC_DEFAULT (yylhs.location, slice, yylen); + yyerror_range[1].location = yylhs.location; + } + + // Perform the reduction. + YY_REDUCE_PRINT (yyn); + try + { + switch (yyn) + { + case 2: +#line 298 "parser.ypp" // lalr1.cc:856 + { *outAST = (yystack_[0].value.document); } +#line 1482 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 3: +#line 303 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1488 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 4: +#line 304 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1494 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 5: +#line 305 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1500 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 6: +#line 306 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1506 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 7: +#line 307 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1512 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 8: +#line 308 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1518 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 9: +#line 309 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1524 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 10: +#line 310 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1530 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 11: +#line 311 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1536 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 12: +#line 312 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1542 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 13: +#line 313 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1548 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 14: +#line 314 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1554 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 15: +#line 315 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1560 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 16: +#line 316 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1566 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 17: +#line 317 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1572 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 18: +#line 318 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1578 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 19: +#line 319 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1584 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 20: +#line 320 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1590 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 22: +#line 324 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.name) = new Name(yystack_[0].location, strdup((yystack_[0].value.str))); } +#line 1596 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 23: +#line 328 "parser.ypp" // lalr1.cc:856 + {(yylhs.value.name) = nullptr;} +#line 1602 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 25: +#line 334 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.document) = new Document(yylhs.location, (yystack_[0].value.definitionList)); } +#line 1608 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 26: +#line 337 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definitionList) = new std::vector>(); (yylhs.value.definitionList)->emplace_back((yystack_[0].value.definition)); } +#line 1614 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 27: +#line 338 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.definitionList)->emplace_back((yystack_[0].value.definition)); (yylhs.value.definitionList) = (yystack_[1].value.definitionList); } +#line 1620 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 28: +#line 341 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.operationDefinition)); } +#line 1626 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 29: +#line 342 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.fragmentDefinition)); } +#line 1632 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 30: +#line 343 "parser.ypp" // lalr1.cc:856 + { + if (!enableSchema) { + error(yylhs.location, "schema support disabled"); + // %destructor doesn't work with YYERROR. See + // https://www.gnu.org/software/bison/manual/html_node/Destructor-Decl.html + delete (yylhs.value.definition); + YYERROR; + } + (yylhs.value.definition) = static_cast((yystack_[0].value.definition)); + } +#line 1647 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 31: +#line 355 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.schemaDefinition)); } +#line 1653 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 32: +#line 356 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.scalarTypeDefinition)); } +#line 1659 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 33: +#line 357 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.objectTypeDefinition)); } +#line 1665 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 34: +#line 358 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.interfaceTypeDefinition)); } +#line 1671 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 35: +#line 359 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.unionTypeDefinition)); } +#line 1677 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 36: +#line 360 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.enumTypeDefinition)); } +#line 1683 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 37: +#line 361 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.inputObjectTypeDefinition)); } +#line 1689 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 38: +#line 362 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.typeExtensionDefinition)); } +#line 1695 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 39: +#line 363 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.definition) = static_cast((yystack_[0].value.directiveDefinition)); } +#line 1701 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 40: +#line 369 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.operationDefinition) = new OperationDefinition(yylhs.location, strdup("query"), nullptr, nullptr, nullptr, (yystack_[0].value.selectionSet)); } +#line 1707 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 41: +#line 370 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.operationDefinition) = new OperationDefinition(yylhs.location, (yystack_[2].value.heapStr), (yystack_[1].value.name), nullptr, nullptr, (yystack_[0].value.selectionSet)); } +#line 1713 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 42: +#line 371 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.operationDefinition) = new OperationDefinition(yylhs.location, (yystack_[3].value.heapStr), (yystack_[2].value.name), (yystack_[1].value.variableDefinitionList), nullptr, (yystack_[0].value.selectionSet)); } +#line 1719 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 43: +#line 372 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.operationDefinition) = new OperationDefinition(yylhs.location, (yystack_[3].value.heapStr), (yystack_[2].value.name), nullptr, (yystack_[1].value.directiveList), (yystack_[0].value.selectionSet)); } +#line 1725 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 44: +#line 373 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.operationDefinition) = new OperationDefinition(yylhs.location, (yystack_[4].value.heapStr), (yystack_[3].value.name), (yystack_[2].value.variableDefinitionList), (yystack_[1].value.directiveList), (yystack_[0].value.selectionSet)); } +#line 1731 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 45: +#line 376 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.heapStr) = strdup((yystack_[0].value.str)); } +#line 1737 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 46: +#line 377 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.heapStr) = strdup((yystack_[0].value.str)); } +#line 1743 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 47: +#line 378 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.heapStr) = strdup((yystack_[0].value.str)); } +#line 1749 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 48: +#line 382 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.variableDefinitionList) = (yystack_[1].value.variableDefinitionList); } +#line 1755 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 49: +#line 386 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.variableDefinitionList) = new std::vector>(); (yylhs.value.variableDefinitionList)->emplace_back((yystack_[0].value.variableDefinition)); } +#line 1761 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 50: +#line 387 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.variableDefinitionList)->emplace_back((yystack_[0].value.variableDefinition)); (yylhs.value.variableDefinitionList) = (yystack_[1].value.variableDefinitionList); } +#line 1767 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 51: +#line 390 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.variable) = new Variable(yylhs.location, new Name(yystack_[0].location, strdup((yystack_[0].value.str)))); } +#line 1773 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 52: +#line 394 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.variableDefinition) = new VariableDefinition(yylhs.location, (yystack_[3].value.variable), (yystack_[1].value.type), (yystack_[0].value.value)); } +#line 1779 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 53: +#line 398 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = nullptr; } +#line 1785 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 55: +#line 402 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = (yystack_[0].value.value); } +#line 1791 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 56: +#line 406 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.selectionSet) = new SelectionSet(yylhs.location, (yystack_[1].value.selectionList)); } +#line 1797 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 57: +#line 410 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.selectionSet) = nullptr; } +#line 1803 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 59: +#line 413 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.selectionList) = new std::vector>(); (yylhs.value.selectionList)->emplace_back((yystack_[0].value.selection)); } +#line 1809 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 60: +#line 414 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.selectionList)->emplace_back((yystack_[0].value.selection)); (yylhs.value.selectionList) = (yystack_[1].value.selectionList); } +#line 1815 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 61: +#line 417 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.selection) = static_cast((yystack_[0].value.field)); } +#line 1821 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 62: +#line 418 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.selection) = static_cast((yystack_[0].value.fragmentSpread)); } +#line 1827 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 63: +#line 419 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.selection) = static_cast((yystack_[0].value.inlineFragment)); } +#line 1833 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 64: +#line 422 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.field) = new Field(yylhs.location, nullptr, (yystack_[3].value.name), (yystack_[2].value.argumentList), (yystack_[1].value.directiveList), (yystack_[0].value.selectionSet)); } +#line 1839 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 65: +#line 423 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.field) = new Field(yylhs.location, (yystack_[5].value.name), (yystack_[3].value.name), (yystack_[2].value.argumentList), (yystack_[1].value.directiveList), (yystack_[0].value.selectionSet)); } +#line 1845 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 66: +#line 426 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.argumentList) = (yystack_[1].value.argumentList); } +#line 1851 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 67: +#line 429 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.argumentList) = nullptr; } +#line 1857 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 68: +#line 430 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.argumentList) = (yystack_[0].value.argumentList); } +#line 1863 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 69: +#line 433 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.argumentList) = new std::vector>(); (yylhs.value.argumentList)->emplace_back((yystack_[0].value.argument)); } +#line 1869 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 70: +#line 434 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.argumentList)->emplace_back((yystack_[0].value.argument)); (yylhs.value.argumentList) = (yystack_[1].value.argumentList); } +#line 1875 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 71: +#line 437 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.argument) = new Argument(yylhs.location, (yystack_[2].value.name), (yystack_[0].value.value)); } +#line 1881 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 72: +#line 442 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.fragmentSpread) = new FragmentSpread(yylhs.location, (yystack_[1].value.name), (yystack_[0].value.directiveList)); } +#line 1887 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 73: +#line 446 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.inlineFragment) = new InlineFragment(yylhs.location, (yystack_[2].value.namedType), (yystack_[1].value.directiveList), (yystack_[0].value.selectionSet)); } +#line 1893 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 74: +#line 447 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.inlineFragment) = new InlineFragment(yylhs.location, nullptr, (yystack_[1].value.directiveList), (yystack_[0].value.selectionSet)); } +#line 1899 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 75: +#line 451 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.fragmentDefinition) = new FragmentDefinition(yylhs.location, (yystack_[4].value.name), (yystack_[2].value.namedType), (yystack_[1].value.directiveList), (yystack_[0].value.selectionSet)); } +#line 1905 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 77: +#line 458 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.variable)); } +#line 1911 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 78: +#line 459 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.intValue)); } +#line 1917 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 79: +#line 460 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.floatValue)); } +#line 1923 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 80: +#line 461 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.stringValue)); } +#line 1929 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 81: +#line 462 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.booleanValue)); } +#line 1935 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 82: +#line 463 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.nullValue)); } +#line 1941 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 83: +#line 464 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.enumValue)); } +#line 1947 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 84: +#line 465 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.arrayValue)); } +#line 1953 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 85: +#line 466 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.objectValue)); } +#line 1959 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 86: +#line 469 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.intValue) = new IntValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 1965 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 87: +#line 472 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.floatValue) = new FloatValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 1971 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 88: +#line 475 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.stringValue) = new StringValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 1977 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 89: +#line 478 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.intValue)); } +#line 1983 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 90: +#line 479 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.floatValue)); } +#line 1989 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 91: +#line 480 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.stringValue)); } +#line 1995 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 92: +#line 481 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.booleanValue)); } +#line 2001 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 93: +#line 482 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.nullValue)); } +#line 2007 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 94: +#line 483 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.enumValue)); } +#line 2013 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 95: +#line 484 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.arrayValue)); } +#line 2019 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 96: +#line 485 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.value) = static_cast((yystack_[0].value.objectValue)); } +#line 2025 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 97: +#line 488 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.booleanValue) = new BooleanValue(yylhs.location, true); } +#line 2031 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 98: +#line 489 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.booleanValue) = new BooleanValue(yylhs.location, false); } +#line 2037 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 99: +#line 492 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.nullValue) = new NullValue(yylhs.location); } +#line 2043 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 100: +#line 495 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2049 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 101: +#line 496 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2055 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 102: +#line 497 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2061 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 103: +#line 498 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2067 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 104: +#line 499 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2073 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 105: +#line 500 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2079 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 106: +#line 501 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2085 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 107: +#line 502 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2091 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 108: +#line 503 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2097 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 109: +#line 504 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2103 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 110: +#line 505 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2109 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 111: +#line 506 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2115 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 112: +#line 507 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2121 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 113: +#line 508 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2127 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 114: +#line 509 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2133 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 115: +#line 510 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValue) = new EnumValue(yylhs.location, strdup((yystack_[0].value.str))); } +#line 2139 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 116: +#line 517 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.arrayValue) = new ListValue(yylhs.location, new std::vector>()); } +#line 2145 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 117: +#line 518 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.arrayValue) = new ListValue(yylhs.location, (yystack_[1].value.valueList)); } +#line 2151 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 118: +#line 521 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.valueList) = new std::vector>(); (yylhs.value.valueList)->emplace_back((yystack_[0].value.value)); } +#line 2157 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 119: +#line 522 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.valueList)->emplace_back((yystack_[0].value.value)); (yylhs.value.valueList) = (yystack_[1].value.valueList); } +#line 2163 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 120: +#line 526 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.arrayValue) = new ListValue(yylhs.location, new std::vector>()); } +#line 2169 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 121: +#line 527 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.arrayValue) = new ListValue(yylhs.location, (yystack_[1].value.valueList)); } +#line 2175 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 122: +#line 531 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.valueList) = new std::vector>(); (yylhs.value.valueList)->emplace_back((yystack_[0].value.value)); } +#line 2181 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 123: +#line 532 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.valueList)->emplace_back((yystack_[0].value.value)); (yylhs.value.valueList) = (yystack_[1].value.valueList); } +#line 2187 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 124: +#line 537 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.objectValue) = new ObjectValue(yylhs.location, new std::vector>()); } +#line 2193 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 125: +#line 538 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.objectValue) = new ObjectValue(yylhs.location, (yystack_[1].value.objectFieldList)); } +#line 2199 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 126: +#line 542 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.objectFieldList) = new std::vector>(); (yylhs.value.objectFieldList)->emplace_back((yystack_[0].value.objectField)); } +#line 2205 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 127: +#line 543 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.objectFieldList)->emplace_back((yystack_[0].value.objectField)); (yylhs.value.objectFieldList) = (yystack_[1].value.objectFieldList); } +#line 2211 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 128: +#line 546 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.objectField) = new ObjectField(yylhs.location, (yystack_[2].value.name), (yystack_[0].value.value)); } +#line 2217 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 129: +#line 550 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.objectValue) = new ObjectValue(yylhs.location, new std::vector>()); } +#line 2223 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 130: +#line 551 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.objectValue) = new ObjectValue(yylhs.location, (yystack_[1].value.objectFieldList)); } +#line 2229 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 131: +#line 555 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.objectFieldList) = new std::vector>(); (yylhs.value.objectFieldList)->emplace_back((yystack_[0].value.objectField)); } +#line 2235 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 132: +#line 556 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.objectFieldList)->emplace_back((yystack_[0].value.objectField)); (yylhs.value.objectFieldList) = (yystack_[1].value.objectFieldList); } +#line 2241 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 133: +#line 559 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.objectField) = new ObjectField(yylhs.location, (yystack_[2].value.name), (yystack_[0].value.value)); } +#line 2247 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 135: +#line 567 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.directiveList) = nullptr; } +#line 2253 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 137: +#line 571 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.directiveList) = new std::vector>(); (yylhs.value.directiveList)->emplace_back((yystack_[0].value.directive)); } +#line 2259 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 138: +#line 572 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.directiveList)->emplace_back((yystack_[0].value.directive)); (yylhs.value.directiveList) = (yystack_[1].value.directiveList); } +#line 2265 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 139: +#line 575 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.directive) = new Directive(yylhs.location, (yystack_[1].value.name), (yystack_[0].value.argumentList)); } +#line 2271 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 140: +#line 580 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.type) = static_cast((yystack_[0].value.namedType)); } +#line 2277 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 141: +#line 581 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.type) = static_cast((yystack_[0].value.listType)); } +#line 2283 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 142: +#line 582 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.type) = static_cast((yystack_[0].value.nonNullType)); } +#line 2289 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 143: +#line 585 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.namedType) = new NamedType(yylhs.location, (yystack_[0].value.name)); } +#line 2295 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 144: +#line 588 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.listType) = new ListType(yylhs.location, (yystack_[1].value.type)); } +#line 2301 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 145: +#line 591 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.nonNullType) = new NonNullType(yylhs.location, (yystack_[1].value.namedType)); } +#line 2307 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 146: +#line 592 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.nonNullType) = new NonNullType(yylhs.location, (yystack_[1].value.listType)); } +#line 2313 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 147: +#line 597 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.schemaDefinition) = new SchemaDefinition(yylhs.location, (yystack_[3].value.directiveList), (yystack_[1].value.operationTypeDefinitionList)); } +#line 2319 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 148: +#line 601 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.operationTypeDefinitionList) = new std::vector>(); (yylhs.value.operationTypeDefinitionList)->emplace_back((yystack_[0].value.operationTypeDefinition)); } +#line 2325 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 149: +#line 602 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.operationTypeDefinitionList)->emplace_back((yystack_[0].value.operationTypeDefinition)); (yylhs.value.operationTypeDefinitionList) = (yystack_[1].value.operationTypeDefinitionList); } +#line 2331 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 150: +#line 606 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.operationTypeDefinition) = new OperationTypeDefinition(yylhs.location, (yystack_[2].value.heapStr), (yystack_[0].value.namedType)); } +#line 2337 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 151: +#line 609 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.scalarTypeDefinition) = new ScalarTypeDefinition(yylhs.location, (yystack_[1].value.name), (yystack_[0].value.directiveList)); } +#line 2343 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 152: +#line 612 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.objectTypeDefinition) = new ObjectTypeDefinition(yylhs.location, (yystack_[5].value.name), (yystack_[4].value.typeNameList), (yystack_[3].value.directiveList), (yystack_[1].value.fieldDefinitionList)); } +#line 2349 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 153: +#line 615 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.typeNameList) = nullptr; } +#line 2355 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 154: +#line 616 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.typeNameList) = (yystack_[0].value.typeNameList); } +#line 2361 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 155: +#line 619 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.typeNameList) = new std::vector>(); (yylhs.value.typeNameList)->emplace_back((yystack_[0].value.namedType)); } +#line 2367 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 156: +#line 620 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.typeNameList)->emplace_back((yystack_[0].value.namedType)); (yylhs.value.typeNameList) = (yystack_[1].value.typeNameList); } +#line 2373 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 157: +#line 623 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.fieldDefinition) = new FieldDefinition(yylhs.location, (yystack_[4].value.name), (yystack_[3].value.inputValueDefinitionList), (yystack_[1].value.type), (yystack_[0].value.directiveList)); } +#line 2379 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 158: +#line 627 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.fieldDefinitionList) = new std::vector>(); (yylhs.value.fieldDefinitionList)->emplace_back((yystack_[0].value.fieldDefinition)); } +#line 2385 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 159: +#line 628 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.fieldDefinitionList)->emplace_back((yystack_[0].value.fieldDefinition)); (yylhs.value.fieldDefinitionList) = (yystack_[1].value.fieldDefinitionList); } +#line 2391 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 160: +#line 631 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.inputValueDefinitionList) = nullptr; } +#line 2397 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 161: +#line 632 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.inputValueDefinitionList) = (yystack_[0].value.inputValueDefinitionList); } +#line 2403 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 162: +#line 635 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.inputValueDefinitionList) = (yystack_[1].value.inputValueDefinitionList); } +#line 2409 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 163: +#line 638 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.inputValueDefinitionList) = new std::vector>(); (yylhs.value.inputValueDefinitionList)->emplace_back((yystack_[0].value.inputValueDefinition)); } +#line 2415 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 164: +#line 639 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.inputValueDefinitionList)->emplace_back((yystack_[0].value.inputValueDefinition)); (yylhs.value.inputValueDefinitionList) = (yystack_[1].value.inputValueDefinitionList); } +#line 2421 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 165: +#line 642 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.inputValueDefinition) = new InputValueDefinition(yylhs.location, (yystack_[4].value.name), (yystack_[2].value.type), (yystack_[1].value.value), (yystack_[0].value.directiveList)); } +#line 2427 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 166: +#line 644 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.interfaceTypeDefinition) = new InterfaceTypeDefinition(yylhs.location, (yystack_[4].value.name), (yystack_[3].value.directiveList), (yystack_[1].value.fieldDefinitionList)); } +#line 2433 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 167: +#line 647 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.unionTypeDefinition) = new UnionTypeDefinition(yylhs.location, (yystack_[3].value.name), (yystack_[2].value.directiveList), (yystack_[0].value.typeNameList)); } +#line 2439 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 168: +#line 650 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.typeNameList) = new std::vector>(); (yylhs.value.typeNameList)->emplace_back((yystack_[0].value.namedType)); } +#line 2445 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 169: +#line 651 "parser.ypp" // lalr1.cc:856 + { (yystack_[2].value.typeNameList)->emplace_back((yystack_[0].value.namedType)); (yylhs.value.typeNameList) = (yystack_[2].value.typeNameList); } +#line 2451 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 170: +#line 654 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumTypeDefinition) = new EnumTypeDefinition(yylhs.location, (yystack_[4].value.name), (yystack_[3].value.directiveList), (yystack_[1].value.enumValueDefinitionList)); } +#line 2457 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 171: +#line 657 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValueDefinition) = new EnumValueDefinition(yylhs.location, (yystack_[1].value.name), (yystack_[0].value.directiveList)); } +#line 2463 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 172: +#line 661 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.enumValueDefinitionList) = new std::vector>(); (yylhs.value.enumValueDefinitionList)->emplace_back((yystack_[0].value.enumValueDefinition)); } +#line 2469 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 173: +#line 662 "parser.ypp" // lalr1.cc:856 + { (yystack_[1].value.enumValueDefinitionList)->emplace_back((yystack_[0].value.enumValueDefinition)); (yylhs.value.enumValueDefinitionList) = (yystack_[1].value.enumValueDefinitionList); } +#line 2475 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 174: +#line 665 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.inputObjectTypeDefinition) = new InputObjectTypeDefinition(yylhs.location, (yystack_[4].value.name), (yystack_[3].value.directiveList), (yystack_[1].value.inputValueDefinitionList)); } +#line 2481 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 175: +#line 668 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.typeExtensionDefinition) = new TypeExtensionDefinition(yylhs.location, (yystack_[0].value.objectTypeDefinition)); } +#line 2487 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 176: +#line 671 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.directiveDefinition) = new DirectiveDefinition(yylhs.location, (yystack_[3].value.name), (yystack_[2].value.inputValueDefinitionList), (yystack_[0].value.nameList)); } +#line 2493 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 177: +#line 675 "parser.ypp" // lalr1.cc:856 + { (yylhs.value.nameList) = new std::vector>(); (yylhs.value.nameList)->emplace_back((yystack_[0].value.name)); } +#line 2499 "parser.tab.cpp" // lalr1.cc:856 + break; + + case 178: +#line 676 "parser.ypp" // lalr1.cc:856 + { (yystack_[2].value.nameList)->emplace_back((yystack_[0].value.name)); (yylhs.value.nameList) = (yystack_[2].value.nameList); } +#line 2505 "parser.tab.cpp" // lalr1.cc:856 + break; + + +#line 2509 "parser.tab.cpp" // lalr1.cc:856 + default: + break; + } + } + catch (const syntax_error& yyexc) + { + error (yyexc); + YYERROR; + } + YY_SYMBOL_PRINT ("-> $$ =", yylhs); + yypop_ (yylen); + yylen = 0; + YY_STACK_PRINT (); + + // Shift the result of the reduction. + yypush_ (YY_NULLPTR, yylhs); + } + goto yynewstate; + + /*--------------------------------------. + | yyerrlab -- here on detecting error. | + `--------------------------------------*/ + yyerrlab: + // If not already recovering from an error, report this error. + if (!yyerrstatus_) + { + ++yynerrs_; + error (yyla.location, yysyntax_error_ (yystack_[0].state, yyla)); + } + + + yyerror_range[1].location = yyla.location; + if (yyerrstatus_ == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + // Return failure if at end of input. + if (yyla.type_get () == yyeof_) + YYABORT; + else if (!yyla.empty ()) + { + yy_destroy_ ("Error: discarding", yyla); + yyla.clear (); + } + } + + // Else will try to reuse lookahead token after shifting the error token. + goto yyerrlab1; + + + /*---------------------------------------------------. + | yyerrorlab -- error raised explicitly by YYERROR. | + `---------------------------------------------------*/ + yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (false) + goto yyerrorlab; + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + yypop_ (yylen); + yylen = 0; + goto yyerrlab1; + + /*-------------------------------------------------------------. + | yyerrlab1 -- common code for both syntax error and YYERROR. | + `-------------------------------------------------------------*/ + yyerrlab1: + yyerrstatus_ = 3; // Each real token shifted decrements this. + { + stack_symbol_type error_token; + for (;;) + { + yyn = yypact_[yystack_[0].state]; + if (!yy_pact_value_is_default_ (yyn)) + { + yyn += yyterror_; + if (0 <= yyn && yyn <= yylast_ && yycheck_[yyn] == yyterror_) + { + yyn = yytable_[yyn]; + if (0 < yyn) + break; + } + } + + // Pop the current state because it cannot handle the error token. + if (yystack_.size () == 1) + YYABORT; + + yyerror_range[1].location = yystack_[0].location; + yy_destroy_ ("Error: popping", yystack_[0]); + yypop_ (); + YY_STACK_PRINT (); + } + + yyerror_range[2].location = yyla.location; + YYLLOC_DEFAULT (error_token.location, yyerror_range, 2); + + // Shift the error token. + error_token.state = yyn; + yypush_ ("Shifting", error_token); + } + goto yynewstate; + + // Accept. + yyacceptlab: + yyresult = 0; + goto yyreturn; + + // Abort. + yyabortlab: + yyresult = 1; + goto yyreturn; + + yyreturn: + if (!yyla.empty ()) + yy_destroy_ ("Cleanup: discarding lookahead", yyla); + + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + yypop_ (yylen); + while (1 < yystack_.size ()) + { + yy_destroy_ ("Cleanup: popping", yystack_[0]); + yypop_ (); + } + + return yyresult; + } + catch (...) + { + YYCDEBUG << "Exception caught: cleaning lookahead and stack\n"; + // Do not try to display the values of the reclaimed symbols, + // as their printer might throw an exception. + if (!yyla.empty ()) + yy_destroy_ (YY_NULLPTR, yyla); + + while (1 < yystack_.size ()) + { + yy_destroy_ (YY_NULLPTR, yystack_[0]); + yypop_ (); + } + throw; + } + } + + void + GraphQLParserImpl::error (const syntax_error& yyexc) + { + error (yyexc.location, yyexc.what ()); + } + + // Generate an error message. + std::string + GraphQLParserImpl::yysyntax_error_ (state_type yystate, const symbol_type& yyla) const + { + // Number of reported tokens (one for the "unexpected", one per + // "expected"). + size_t yycount = 0; + // Its maximum. + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + // Arguments of yyformat. + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yyla) is + if this state is a consistent state with a default action. + Thus, detecting the absence of a lookahead is sufficient to + determine that there is no unexpected or expected token to + report. In that case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is + a consistent state with a default action. There might have + been a previous inconsistent state, consistent state with a + non-default action, or user semantic action that manipulated + yyla. (However, yyla is currently not documented for users.) + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state + merging (from LALR or IELR) and default reductions corrupt the + expected token list. However, the list is correct for + canonical LR with one exception: it will still contain any + token that will not be accepted due to an error action in a + later state. + */ + if (!yyla.empty ()) + { + int yytoken = yyla.type_get (); + yyarg[yycount++] = yytname_[yytoken]; + int yyn = yypact_[yystate]; + if (!yy_pact_value_is_default_ (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + // Stay within bounds of both yycheck and yytname. + int yychecklim = yylast_ - yyn + 1; + int yyxend = yychecklim < yyntokens_ ? yychecklim : yyntokens_; + for (int yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck_[yyx + yyn] == yyx && yyx != yyterror_ + && !yy_table_value_is_error_ (yytable_[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + break; + } + else + yyarg[yycount++] = yytname_[yyx]; + } + } + } + + char const* yyformat = YY_NULLPTR; + switch (yycount) + { +#define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + default: // Avoid compiler warnings. + YYCASE_ (0, YY_("syntax error")); + YYCASE_ (1, YY_("syntax error, unexpected %s")); + YYCASE_ (2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_ (3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_ (4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_ (5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +#undef YYCASE_ + } + + std::string yyres; + // Argument number. + size_t yyi = 0; + for (char const* yyp = yyformat; *yyp; ++yyp) + if (yyp[0] == '%' && yyp[1] == 's' && yyi < yycount) + { + yyres += yytnamerr_ (yyarg[yyi++]); + ++yyp; + } + else + yyres += *yyp; + return yyres; + } + + + const short int GraphQLParserImpl::yypact_ninf_ = -228; + + const signed char GraphQLParserImpl::yytable_ninf_ = -1; + + const short int + GraphQLParserImpl::yypact_[] = + { + 198, -11, 895, 6, 918, 895, 895, -228, -228, 895, + 13, -228, 895, 895, 440, 50, -228, 198, -228, -228, + -228, 895, -228, -228, -228, -228, -228, -228, -228, -228, + -228, -228, -228, 895, -228, -228, -228, -228, -228, -228, + -228, -228, -228, -228, -228, -228, -228, -228, -228, -228, + -228, -228, -228, -228, 13, -228, 58, 13, 13, 13, + 895, -228, 44, 13, -228, 79, 13, 475, 74, 405, + -228, -228, -228, -228, -228, -228, -228, 76, 54, 52, + 895, 65, 67, -228, 94, 100, -228, 895, 13, 84, + 895, 13, 89, 895, 895, -228, 13, -228, -228, 87, + 88, -228, 89, 895, 109, -228, 895, -228, 13, -228, + 895, 895, -228, 99, 68, -228, -228, 895, 95, 895, + 13, -228, -228, 101, 510, -228, 94, 89, -228, -9, + 103, -228, -228, 89, -228, 104, 545, -228, 895, 13, + -228, 580, 89, 615, 54, -228, 650, 895, -228, -228, + -228, 895, -228, 102, 89, 265, -228, -228, 13, -228, + -228, -228, -228, 685, -228, 685, -228, -228, -228, 106, + -228, -228, -228, -228, -228, 105, -228, -228, -228, 720, + 895, -228, -228, -228, -228, -228, -228, -228, -228, -228, + -228, -228, -228, -228, -228, -228, -228, -228, -228, -228, + 150, 755, -228, -228, -228, -228, -228, -228, -228, -228, + -228, -228, -228, -228, -228, -228, 89, 685, 112, 110, + 111, -228, 112, 895, 685, -228, -228, -228, -228, 228, + -228, 115, 790, -228, -228, 113, 370, -228, -228, -228, + -228, 13, -228, 13, -228, -228, 265, -228, -228, -228, + 300, 825, -228, -228, -228, -228, -228, -228, -228, -228, + -228, -228, -228, -228, -228, -228, 335, -228, 118, 860, + -228, -228, -228, 370, -228, -228, -228 + }; + + const unsigned char + GraphQLParserImpl::yydefact_[] = + { + 0, 0, 0, 0, 0, 0, 0, 46, 45, 0, + 135, 47, 0, 0, 0, 0, 2, 25, 26, 30, + 28, 23, 40, 29, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 0, 3, 4, 5, 6, 7, 9, + 10, 11, 12, 13, 14, 22, 15, 16, 17, 18, + 19, 20, 8, 21, 135, 175, 0, 135, 135, 135, + 0, 136, 0, 134, 137, 153, 135, 135, 67, 0, + 59, 61, 62, 63, 1, 27, 24, 0, 160, 0, + 0, 0, 0, 151, 67, 0, 138, 0, 135, 0, + 0, 135, 0, 0, 0, 68, 135, 56, 60, 0, + 0, 41, 0, 0, 0, 161, 0, 143, 135, 76, + 0, 0, 139, 0, 0, 148, 155, 154, 0, 0, + 135, 72, 74, 0, 0, 69, 67, 57, 51, 0, + 0, 49, 42, 0, 43, 0, 0, 163, 0, 135, + 172, 0, 0, 0, 160, 158, 0, 0, 147, 149, + 156, 0, 168, 167, 0, 0, 66, 70, 135, 58, + 64, 48, 50, 0, 44, 0, 162, 164, 177, 176, + 171, 170, 173, 75, 174, 0, 166, 159, 150, 0, + 0, 73, 100, 101, 102, 98, 103, 105, 106, 107, + 108, 99, 110, 109, 111, 112, 113, 97, 114, 115, + 0, 0, 86, 87, 88, 104, 77, 71, 78, 79, + 80, 81, 82, 83, 84, 85, 57, 0, 53, 140, + 141, 142, 53, 0, 0, 152, 169, 116, 118, 0, + 124, 0, 0, 126, 65, 0, 0, 52, 54, 145, + 146, 135, 178, 135, 117, 119, 0, 125, 127, 144, + 0, 0, 89, 90, 91, 55, 92, 93, 94, 95, + 96, 165, 157, 128, 120, 122, 0, 129, 0, 0, + 131, 121, 123, 0, 130, 132, 133 + }; + + const short int + GraphQLParserImpl::yypgoto_[] = + { + -228, -228, 1, -2, -228, -228, -228, 128, -228, -228, + -52, -228, -228, -84, 17, -87, -228, -64, -69, -228, + 81, -228, -228, -82, -228, 24, -228, -228, -228, 61, + -194, -227, -218, -193, -224, -189, -180, -161, -228, -228, + -228, -228, -228, -228, -61, -228, -228, -97, -12, -37, + -228, 119, -164, -53, -228, -228, -228, -228, 59, -228, + 171, -228, -228, -138, 25, 31, -228, 71, -29, -228, + -228, -228, -228, 47, -228, -228, -228, -228, -228 + }; + + const short int + GraphQLParserImpl::yydefgoto_[] = + { + -1, 15, 53, 107, 77, 16, 17, 18, 19, 20, + 21, 100, 129, 206, 131, 237, 238, 22, 160, 69, + 70, 71, 95, 96, 124, 125, 72, 73, 23, 108, + 207, 208, 209, 210, 255, 211, 212, 213, 214, 229, + 259, 266, 215, 232, 233, 260, 269, 270, 61, 62, + 63, 64, 218, 219, 220, 221, 24, 114, 115, 25, + 26, 88, 117, 145, 146, 104, 105, 136, 137, 27, + 28, 153, 29, 140, 141, 30, 31, 32, 169 + }; + + const unsigned short int + GraphQLParserImpl::yytable_[] = + { + 54, 222, 112, 57, 58, 56, 228, 59, 177, 252, + 65, 66, 68, 101, 161, 130, 33, 79, 253, 76, + 81, 82, 83, 252, 128, 12, 265, 109, 122, 89, + 92, 78, 253, 113, 116, 245, 132, 109, 134, 252, + 60, 177, 272, 254, 158, 130, 252, 256, 253, 276, + 74, 118, 263, 235, 121, 253, 257, 254, 84, 127, + 243, 256, 113, 159, 150, 102, 152, 68, 91, 164, + 257, 142, 80, 254, 85, 258, 103, 256, 173, 7, + 254, 8, 106, 154, 256, 11, 257, 87, 133, 258, + 181, 123, 126, 257, 178, 110, 93, 111, 99, 94, + 148, 135, 170, 60, 139, 258, 14, 167, 135, 144, + 119, 7, 258, 8, 167, 60, 93, 11, 14, 14, + 128, 216, 123, 138, 147, 151, 155, 226, 163, 165, + 224, 239, 240, 180, 135, 241, 168, 223, 236, 139, + 246, 135, 249, 273, 144, 75, 162, 234, 157, 144, + 98, 120, 159, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 248, 275, 149, 55, 175, 179, 144, 200, 227, + 201, 143, 86, 128, 202, 203, 204, 205, 172, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, + 0, 1, 2, 3, 261, 4, 262, 5, 6, 7, + 0, 8, 0, 9, 10, 11, 0, 12, 13, 0, + 0, 242, 0, 0, 0, 0, 0, 0, 14, 0, + 231, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 268, + 0, 0, 0, 0, 0, 0, 200, 244, 201, 0, + 0, 128, 202, 203, 204, 205, 0, 268, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 0, 0, 0, 0, + 0, 0, 0, 200, 0, 201, 0, 0, 128, 202, + 203, 204, 205, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 0, 0, 0, 0, 0, 0, 0, 250, 264, + 251, 0, 0, 0, 202, 203, 204, 205, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 0, 0, 0, 0, + 0, 0, 0, 250, 271, 251, 0, 0, 0, 202, + 203, 204, 205, 182, 183, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 0, 0, 0, 0, 0, 0, 0, 250, 0, + 251, 0, 0, 0, 202, 203, 204, 205, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 0, 0, 0, 67, + 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, + 0, 0, 52, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 0, 0, 0, 67, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 52, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 90, + 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, + 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 52, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 0, 0, 156, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 52, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 0, 0, 166, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 52, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 171, 0, 0, 0, 0, 52, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 174, 0, 0, + 0, 0, 52, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 176, 0, 0, 0, 0, 52, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, + 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, + 0, 0, 52, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 225, 0, 0, 0, 0, 52, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 230, 0, 0, + 0, 0, 52, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 247, 0, 0, 0, 0, 52, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, + 0, 0, 52, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 274, 0, 0, 0, 0, 52, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, + 0, 34, 35, 36, 37, 38, 39, 40, 41, 42, + 43, 44, 52, 46, 47, 48, 49, 50, 51, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 52 + }; + + const short int + GraphQLParserImpl::yycheck_[] = + { + 2, 165, 84, 5, 6, 4, 200, 9, 146, 236, + 12, 13, 14, 77, 23, 99, 27, 54, 236, 21, + 57, 58, 59, 250, 33, 19, 250, 80, 92, 66, + 67, 33, 250, 85, 87, 229, 100, 90, 102, 266, + 27, 179, 266, 236, 126, 129, 273, 236, 266, 273, + 0, 88, 246, 217, 91, 273, 236, 250, 60, 96, + 224, 250, 114, 127, 117, 77, 119, 69, 67, 133, + 250, 108, 14, 266, 30, 236, 22, 266, 142, 11, + 273, 13, 30, 120, 273, 17, 266, 8, 100, 250, + 154, 93, 94, 273, 147, 30, 22, 30, 22, 25, + 32, 103, 139, 27, 106, 266, 30, 136, 110, 111, + 26, 11, 273, 13, 143, 27, 22, 17, 30, 30, + 33, 158, 124, 14, 25, 30, 25, 180, 25, 25, + 25, 21, 21, 31, 136, 222, 138, 31, 26, 141, + 25, 143, 29, 25, 146, 17, 129, 216, 124, 151, + 69, 90, 216, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 232, 269, 114, 3, 144, 151, 179, 28, 29, + 30, 110, 63, 33, 34, 35, 36, 37, 141, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 201, + -1, 3, 4, 5, 241, 7, 243, 9, 10, 11, + -1, 13, -1, 15, 16, 17, -1, 19, 20, -1, + -1, 223, -1, -1, -1, -1, -1, -1, 30, -1, + 232, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 251, + -1, -1, -1, -1, -1, -1, 28, 29, 30, -1, + -1, 33, 34, 35, 36, 37, -1, 269, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, -1, -1, + -1, -1, -1, 28, -1, 30, -1, -1, 33, 34, + 35, 36, 37, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, -1, -1, -1, -1, -1, -1, -1, 28, 29, + 30, -1, -1, -1, 34, 35, 36, 37, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, -1, -1, + -1, -1, -1, 28, 29, 30, -1, -1, -1, 34, + 35, 36, 37, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, -1, -1, -1, -1, -1, -1, -1, 28, -1, + 30, -1, -1, -1, 34, 35, 36, 37, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, -1, 24, + -1, -1, -1, -1, -1, -1, -1, 32, -1, -1, + -1, -1, 37, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, -1, -1, -1, 24, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 37, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, -1, -1, + -1, -1, 27, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 37, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, -1, -1, 23, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 37, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, 23, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 37, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 32, -1, -1, -1, -1, 37, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 32, -1, -1, + -1, -1, 37, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 32, -1, -1, -1, -1, 37, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, -1, -1, + -1, -1, -1, 28, -1, -1, -1, -1, -1, -1, + -1, -1, 37, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 32, -1, -1, -1, -1, 37, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 32, -1, -1, + -1, -1, 37, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 32, -1, -1, -1, -1, 37, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 32, -1, -1, + -1, -1, 37, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 32, -1, -1, -1, -1, 37, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, -1, -1, -1, -1, + -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 37, 15, 16, 17, 18, 19, 20, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 37 + }; + + const unsigned char + GraphQLParserImpl::yystos_[] = + { + 0, 3, 4, 5, 7, 9, 10, 11, 13, 15, + 16, 17, 19, 20, 30, 39, 43, 44, 45, 46, + 47, 48, 55, 66, 94, 97, 98, 107, 108, 110, + 113, 114, 115, 27, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 37, 40, 41, 98, 40, 41, 41, 41, + 27, 86, 87, 88, 89, 41, 41, 24, 41, 57, + 58, 59, 64, 65, 0, 45, 41, 42, 41, 87, + 14, 87, 87, 87, 41, 30, 89, 8, 99, 87, + 14, 40, 87, 22, 25, 60, 61, 32, 58, 22, + 49, 55, 86, 22, 103, 104, 30, 41, 67, 91, + 30, 30, 61, 48, 95, 96, 91, 100, 87, 26, + 67, 87, 55, 41, 62, 63, 41, 87, 33, 50, + 51, 52, 55, 86, 55, 41, 105, 106, 14, 41, + 111, 112, 87, 105, 41, 101, 102, 25, 32, 96, + 91, 30, 91, 109, 87, 25, 23, 63, 61, 55, + 56, 23, 52, 25, 55, 25, 23, 106, 41, 116, + 87, 32, 111, 55, 32, 103, 32, 101, 91, 102, + 31, 55, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 28, 30, 34, 35, 36, 37, 51, 68, 69, 70, + 71, 73, 74, 75, 76, 80, 87, 28, 90, 91, + 92, 93, 90, 31, 25, 32, 91, 29, 68, 77, + 32, 41, 81, 82, 56, 90, 26, 53, 54, 21, + 21, 53, 41, 90, 29, 68, 25, 32, 82, 29, + 28, 30, 69, 70, 71, 72, 73, 74, 75, 78, + 83, 87, 87, 68, 29, 72, 79, 32, 41, 84, + 85, 29, 72, 25, 32, 85, 72 + }; + + const unsigned char + GraphQLParserImpl::yyr1_[] = + { + 0, 38, 39, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 41, 41, 42, 42, 43, 44, 44, 45, 45, + 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 47, 47, 47, 47, 47, 48, 48, 48, 49, 50, + 50, 51, 52, 53, 53, 54, 55, 56, 56, 57, + 57, 58, 58, 58, 59, 59, 60, 61, 61, 62, + 62, 63, 64, 65, 65, 66, 67, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 69, 70, 71, 72, + 72, 72, 72, 72, 72, 72, 72, 73, 73, 74, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 76, 76, 77, 77, + 78, 78, 79, 79, 80, 80, 81, 81, 82, 83, + 83, 84, 84, 85, 86, 87, 87, 88, 88, 89, + 90, 90, 90, 91, 92, 93, 93, 94, 95, 95, + 96, 97, 98, 99, 99, 100, 100, 101, 102, 102, + 103, 103, 104, 105, 105, 106, 107, 108, 109, 109, + 110, 111, 112, 112, 113, 114, 115, 116, 116 + }; + + const unsigned char + GraphQLParserImpl::yyr2_[] = + { + 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 4, 4, 5, 1, 1, 1, 3, 1, + 2, 1, 4, 0, 1, 2, 3, 0, 1, 1, + 2, 1, 1, 1, 4, 6, 3, 0, 1, 1, + 2, 3, 3, 5, 3, 6, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 3, 1, 2, + 2, 3, 1, 2, 2, 3, 1, 2, 3, 2, + 3, 1, 2, 3, 1, 0, 1, 1, 2, 3, + 1, 1, 1, 1, 3, 2, 2, 5, 1, 2, + 3, 3, 7, 0, 2, 1, 2, 5, 1, 2, + 0, 1, 3, 1, 2, 5, 6, 5, 1, 3, + 6, 2, 1, 2, 6, 2, 6, 1, 3 + }; + + + + // YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + // First, the terminals, then, starting at \a yyntokens_, nonterminals. + const char* + const GraphQLParserImpl::yytname_[] = + { + "EOF", "error", "$undefined", "\"directive\"", "\"enum\"", "\"extend\"", + "\"false\"", "\"fragment\"", "\"implements\"", "\"input\"", + "\"interface\"", "\"mutation\"", "\"null\"", "\"query\"", "\"on\"", + "\"scalar\"", "\"schema\"", "\"subscription\"", "\"true\"", "\"type\"", + "\"union\"", "\"!\"", "\"(\"", "\")\"", "\"...\"", "\":\"", "\"=\"", + "\"@\"", "\"[\"", "\"]\"", "\"{\"", "\"|\"", "\"}\"", "VARIABLE", + "INTEGER", "FLOAT", "STRING", "IDENTIFIER", "$accept", "start", + "fragment_name", "name", "name_opt", "document", "definition_list", + "definition", "schema_gate", "operation_definition", "operation_type", + "variable_definitions", "variable_definition_list", "variable", + "variable_definition", "default_value_opt", "default_value", + "selection_set", "selection_set_opt", "selection_list", "selection", + "field", "arguments", "arguments_opt", "argument_list", "argument", + "fragment_spread", "inline_fragment", "fragment_definition", + "type_condition", "value", "int_value", "float_value", "string_value", + "value_const", "boolean_value", "null_value", "enum_value", "list_value", + "value_list", "list_value_const", "value_const_list", "object_value", + "object_field_list", "object_field", "object_value_const", + "object_field_const_list", "object_field_const", "directives", + "directives_opt", "directive_list", "directive", "type", "type_name", + "list_type", "non_null_type", "schema_definition", + "operation_type_definition_list", "operation_type_definition", + "scalar_type_definition", "object_type_definition", + "implements_interfaces_opt", "type_name_list", "field_definition", + "field_definition_list", "arguments_definition_opt", + "arguments_definition", "input_value_definition_list", + "input_value_definition", "interface_type_definition", + "union_type_definition", "union_members", "enum_type_definition", + "enum_value_definition", "enum_value_definition_list", + "input_object_type_definition", "type_extension_definition", + "directive_definition", "directive_locations", YY_NULLPTR + }; + +#if YYDEBUG + const unsigned short int + GraphQLParserImpl::yyrline_[] = + { + 0, 298, 298, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 323, 324, 328, 329, 334, 337, 338, 341, 342, + 343, 355, 356, 357, 358, 359, 360, 361, 362, 363, + 369, 370, 371, 372, 373, 376, 377, 378, 382, 386, + 387, 390, 394, 398, 399, 402, 406, 410, 411, 413, + 414, 417, 418, 419, 422, 423, 426, 429, 430, 433, + 434, 437, 442, 446, 447, 451, 454, 458, 459, 460, + 461, 462, 463, 464, 465, 466, 469, 472, 475, 478, + 479, 480, 481, 482, 483, 484, 485, 488, 489, 492, + 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 510, 517, 518, 521, 522, + 526, 527, 531, 532, 537, 538, 542, 543, 546, 550, + 551, 555, 556, 559, 564, 567, 568, 571, 572, 575, + 580, 581, 582, 585, 588, 591, 592, 597, 601, 602, + 606, 609, 612, 615, 616, 619, 620, 623, 627, 628, + 631, 632, 635, 638, 639, 642, 644, 647, 650, 651, + 654, 657, 661, 662, 665, 668, 671, 675, 676 + }; + + // Print the state stack on the debug stream. + void + GraphQLParserImpl::yystack_print_ () + { + *yycdebug_ << "Stack now"; + for (stack_type::const_iterator + i = yystack_.begin (), + i_end = yystack_.end (); + i != i_end; ++i) + *yycdebug_ << ' ' << i->state; + *yycdebug_ << '\n'; + } + + // Report on the debug stream that the rule \a yyrule is going to be reduced. + void + GraphQLParserImpl::yy_reduce_print_ (int yyrule) + { + unsigned yylno = yyrline_[yyrule]; + int yynrhs = yyr2_[yyrule]; + // Print the symbols being reduced, and their result. + *yycdebug_ << "Reducing stack by rule " << yyrule - 1 + << " (line " << yylno << "):\n"; + // The symbols being reduced. + for (int yyi = 0; yyi < yynrhs; yyi++) + YY_SYMBOL_PRINT (" $" << yyi + 1 << " =", + yystack_[(yynrhs) - (yyi + 1)]); + } +#endif // YYDEBUG + + // Symbol number corresponding to token number t. + GraphQLParserImpl::token_number_type + GraphQLParserImpl::yytranslate_ (int t) + { + static + const token_number_type + translate_table[] = + { + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37 + }; + const unsigned user_token_number_max_ = 292; + const token_number_type undef_token_ = 2; + + if (static_cast (t) <= yyeof_) + return yyeof_; + else if (static_cast (t) <= user_token_number_max_) + return translate_table[t]; + else + return undef_token_; + } + + +} // yy +#line 3285 "parser.tab.cpp" // lalr1.cc:1163 +#line 679 "parser.ypp" // lalr1.cc:1164 + + +void yy::GraphQLParserImpl::error(const yy::location &loc, const std::string &str) { + std::ostringstream out; + out << loc << ": " << str; + if (outError) { + *outError = strdup(out.str().c_str()); + } +} + +/* Workaround for syntax_error ctor being marked inline, which causes link + errors if used from lexer.lpp. */ +yy::GraphQLParserImpl::syntax_error make_error(const yy::location &loc, const std::string &str) { + return yy::GraphQLParserImpl::syntax_error(loc, str); +} diff --git a/external/graphqlparser/parsergen/parser.tab.hpp b/external/graphqlparser/parsergen/parser.tab.hpp new file mode 100644 index 0000000..b6862be --- /dev/null +++ b/external/graphqlparser/parsergen/parser.tab.hpp @@ -0,0 +1,646 @@ +// A Bison parser, made by GNU Bison 3.0.5. + +// Skeleton interface for Bison LALR(1) parsers in C++ + +// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +/** + ** \file parser.tab.hpp + ** Define the yy::parser class. + */ + +// C++ LALR(1) parser skeleton written by Akim Demaille. + +#ifndef YY_YY_PARSER_TAB_HPP_INCLUDED +# define YY_YY_PARSER_TAB_HPP_INCLUDED +// // "%code requires" blocks. +#line 20 "parser.ypp" // lalr1.cc:394 + +#include +#include +#include +#include +#include + +#include "Ast.h" + +using facebook::graphql::ast::Node; +using facebook::graphql::ast::Name; +using facebook::graphql::ast::Definition; +using facebook::graphql::ast::Document; +using facebook::graphql::ast::OperationDefinition; +using facebook::graphql::ast::VariableDefinition; +using facebook::graphql::ast::Variable; +using facebook::graphql::ast::SelectionSet; +using facebook::graphql::ast::Selection; +using facebook::graphql::ast::Field; +using facebook::graphql::ast::Argument; +using facebook::graphql::ast::FragmentSpread; +using facebook::graphql::ast::InlineFragment; +using facebook::graphql::ast::FragmentDefinition; +using facebook::graphql::ast::Value; +using facebook::graphql::ast::IntValue; +using facebook::graphql::ast::FloatValue; +using facebook::graphql::ast::StringValue; +using facebook::graphql::ast::BooleanValue; +using facebook::graphql::ast::NullValue; +using facebook::graphql::ast::EnumValue; +using facebook::graphql::ast::ListValue; +using facebook::graphql::ast::ObjectValue; +using facebook::graphql::ast::ObjectField; +using facebook::graphql::ast::Directive; +using facebook::graphql::ast::Type; +using facebook::graphql::ast::NamedType; +using facebook::graphql::ast::ListType; +using facebook::graphql::ast::NonNullType; + +// Experimental schema support. +using facebook::graphql::ast::SchemaDefinition; +using facebook::graphql::ast::ScalarTypeDefinition; +using facebook::graphql::ast::ObjectTypeDefinition; +using facebook::graphql::ast::InterfaceTypeDefinition; +using facebook::graphql::ast::UnionTypeDefinition; +using facebook::graphql::ast::EnumTypeDefinition; +using facebook::graphql::ast::InputObjectTypeDefinition; +using facebook::graphql::ast::TypeExtensionDefinition; +using facebook::graphql::ast::DirectiveDefinition; +using facebook::graphql::ast::SchemaDefinition; +using facebook::graphql::ast::OperationTypeDefinition; +using facebook::graphql::ast::ScalarTypeDefinition; +using facebook::graphql::ast::ObjectTypeDefinition; +using facebook::graphql::ast::FieldDefinition; +using facebook::graphql::ast::InputValueDefinition; +using facebook::graphql::ast::InterfaceTypeDefinition; +using facebook::graphql::ast::UnionTypeDefinition; +using facebook::graphql::ast::EnumTypeDefinition; +using facebook::graphql::ast::EnumValueDefinition; +using facebook::graphql::ast::InputObjectTypeDefinition; +using facebook::graphql::ast::TypeExtensionDefinition; +using facebook::graphql::ast::DirectiveDefinition; + +union yystype { \ + const char *str; \ + const char *heapStr; \ + Name *name; \ + Definition *definition; \ + Document *document; \ + OperationDefinition *operationDefinition; \ + VariableDefinition *variableDefinition; \ + Variable *variable; \ + SelectionSet *selectionSet; \ + Selection *selection; \ + Field *field; \ + Argument *argument; \ + FragmentSpread *fragmentSpread; \ + InlineFragment *inlineFragment; \ + FragmentDefinition *fragmentDefinition; \ + Value *value; \ + IntValue *intValue; \ + FloatValue *floatValue; \ + StringValue *stringValue; \ + BooleanValue *booleanValue; \ + NullValue *nullValue; \ + EnumValue *enumValue; \ + ListValue *arrayValue; \ + ObjectValue *objectValue; \ + ObjectField *objectField; \ + Directive *directive; \ + Type *type; \ + NamedType *namedType; \ + ListType *listType; \ + NonNullType *nonNullType; \ + \ + std::vector> *definitionList; \ + std::vector> *variableDefinitionList; \ + std::vector> *selectionList; \ + std::vector> *fieldList; \ + std::vector> *argumentList; \ + std::vector> *valueList; \ + std::vector> *objectFieldList; \ + std::vector> *directiveList; \ + \ + SchemaDefinition *schemaDefinition; \ + ScalarTypeDefinition *scalarTypeDefinition; \ + ObjectTypeDefinition *objectTypeDefinition; \ + InterfaceTypeDefinition *interfaceTypeDefinition; \ + UnionTypeDefinition *unionTypeDefinition; \ + EnumTypeDefinition *enumTypeDefinition; \ + InputObjectTypeDefinition *inputObjectTypeDefinition; \ + TypeExtensionDefinition *typeExtensionDefinition; \ + DirectiveDefinition *directiveDefinition; \ + OperationTypeDefinition *operationTypeDefinition; \ + InputValueDefinition *inputValueDefinition; \ + FieldDefinition *fieldDefinition; \ + EnumValueDefinition *enumValueDefinition; \ + \ + std::vector> *operationTypeDefinitionList; \ + std::vector> *typeNameList; \ + std::vector> *inputValueDefinitionList; \ + std::vector> *fieldDefinitionList; \ + std::vector> *nameList; \ + std::vector> *enumValueDefinitionList; \ +}; + +#define YYSTYPE union yystype +#define YYLTYPE yy::location + + +#line 175 "parser.tab.hpp" // lalr1.cc:394 + + +# include // std::abort +# include +# include +# include +# include +# include "stack.hh" +# include "location.hh" + + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + +namespace yy { +#line 247 "parser.tab.hpp" // lalr1.cc:394 + + + + + + /// A Bison parser. + class GraphQLParserImpl + { + public: +#ifndef YYSTYPE + /// Symbol semantic values. + +#else + typedef YYSTYPE semantic_type; +#endif + /// Symbol locations. + typedef location location_type; + + /// Syntax errors thrown from user actions. + struct syntax_error : std::runtime_error + { + syntax_error (const location_type& l, const std::string& m); + location_type location; + }; + + /// Tokens. + struct token + { + enum yytokentype + { + TOK_EOF = 0, + TOK_DIRECTIVE = 258, + TOK_ENUM = 259, + TOK_EXTEND = 260, + TOK_FALSE = 261, + TOK_FRAGMENT = 262, + TOK_IMPLEMENTS = 263, + TOK_INPUT = 264, + TOK_INTERFACE = 265, + TOK_MUTATION = 266, + TOK_NULL = 267, + TOK_QUERY = 268, + TOK_ON = 269, + TOK_SCALAR = 270, + TOK_SCHEMA = 271, + TOK_SUBSCRIPTION = 272, + TOK_TRUE = 273, + TOK_TYPE = 274, + TOK_UNION = 275, + TOK_BANG = 276, + TOK_LPAREN = 277, + TOK_RPAREN = 278, + TOK_ELLIPSIS = 279, + TOK_COLON = 280, + TOK_EQUAL = 281, + TOK_AT = 282, + TOK_LBRACKET = 283, + TOK_RBRACKET = 284, + TOK_LBRACE = 285, + TOK_PIPE = 286, + TOK_RBRACE = 287, + TOK_VARIABLE = 288, + TOK_INTEGER = 289, + TOK_FLOAT = 290, + TOK_STRING = 291, + TOK_IDENTIFIER = 292 + }; + }; + + /// (External) token type, as returned by yylex. + typedef token::yytokentype token_type; + + /// Symbol type: an internal symbol number. + typedef int symbol_number_type; + + /// The symbol type number to denote an empty symbol. + enum { empty_symbol = -2 }; + + /// Internal symbol number for tokens (subsumed by symbol_number_type). + typedef unsigned char token_number_type; + + /// A complete symbol. + /// + /// Expects its Base type to provide access to the symbol type + /// via type_get(). + /// + /// Provide access to semantic value and location. + template + struct basic_symbol : Base + { + /// Alias to Base. + typedef Base super_type; + + /// Default constructor. + basic_symbol (); + + /// Copy constructor. + basic_symbol (const basic_symbol& other); + + /// Constructor for valueless symbols. + basic_symbol (typename Base::kind_type t, + const location_type& l); + + /// Constructor for symbols with semantic value. + basic_symbol (typename Base::kind_type t, + const semantic_type& v, + const location_type& l); + + /// Destroy the symbol. + ~basic_symbol (); + + /// Destroy contents, and record that is empty. + void clear (); + + /// Whether empty. + bool empty () const; + + /// Destructive move, \a s is emptied into this. + void move (basic_symbol& s); + + /// The semantic value. + semantic_type value; + + /// The location. + location_type location; + + private: + /// Assignment operator. + basic_symbol& operator= (const basic_symbol& other); + }; + + /// Type access provider for token (enum) based symbols. + struct by_type + { + /// Default constructor. + by_type (); + + /// Copy constructor. + by_type (const by_type& other); + + /// The symbol type as needed by the constructor. + typedef token_type kind_type; + + /// Constructor from (external) token numbers. + by_type (kind_type t); + + /// Record that this symbol is empty. + void clear (); + + /// Steal the symbol type from \a that. + void move (by_type& that); + + /// The (internal) type number (corresponding to \a type). + /// \a empty when empty. + symbol_number_type type_get () const; + + /// The token. + token_type token () const; + + /// The symbol type. + /// \a empty_symbol when empty. + /// An int, not token_number_type, to be able to store empty_symbol. + int type; + }; + + /// "External" symbols: returned by the scanner. + typedef basic_symbol symbol_type; + + + /// Build a parser object. + GraphQLParserImpl (bool enableSchema_yyarg, Node **outAST_yyarg, const char **outError_yyarg, void *scanner_yyarg); + virtual ~GraphQLParserImpl (); + + /// Parse. + /// \returns 0 iff parsing succeeded. + virtual int parse (); + +#if YYDEBUG + /// The current debugging stream. + std::ostream& debug_stream () const YY_ATTRIBUTE_PURE; + /// Set the current debugging stream. + void set_debug_stream (std::ostream &); + + /// Type for debugging levels. + typedef int debug_level_type; + /// The current debugging level. + debug_level_type debug_level () const YY_ATTRIBUTE_PURE; + /// Set the current debugging level. + void set_debug_level (debug_level_type l); +#endif + + /// Report a syntax error. + /// \param loc where the syntax error is found. + /// \param msg a description of the syntax error. + virtual void error (const location_type& loc, const std::string& msg); + + /// Report a syntax error. + void error (const syntax_error& err); + + private: + /// This class is not copyable. + GraphQLParserImpl (const GraphQLParserImpl&); + GraphQLParserImpl& operator= (const GraphQLParserImpl&); + + /// State numbers. + typedef int state_type; + + /// Generate an error message. + /// \param yystate the state where the error occurred. + /// \param yyla the lookahead token. + virtual std::string yysyntax_error_ (state_type yystate, + const symbol_type& yyla) const; + + /// Compute post-reduction state. + /// \param yystate the current state + /// \param yysym the nonterminal to push on the stack + state_type yy_lr_goto_state_ (state_type yystate, int yysym); + + /// Whether the given \c yypact_ value indicates a defaulted state. + /// \param yyvalue the value to check + static bool yy_pact_value_is_default_ (int yyvalue); + + /// Whether the given \c yytable_ value indicates a syntax error. + /// \param yyvalue the value to check + static bool yy_table_value_is_error_ (int yyvalue); + + static const short int yypact_ninf_; + static const signed char yytable_ninf_; + + /// Convert a scanner token number \a t to a symbol number. + static token_number_type yytranslate_ (int t); + + // Tables. + // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + // STATE-NUM. + static const short int yypact_[]; + + // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + // Performed when YYTABLE does not specify something else to do. Zero + // means the default is an error. + static const unsigned char yydefact_[]; + + // YYPGOTO[NTERM-NUM]. + static const short int yypgoto_[]; + + // YYDEFGOTO[NTERM-NUM]. + static const short int yydefgoto_[]; + + // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + // positive, shift that token. If negative, reduce the rule whose + // number is the opposite. If YYTABLE_NINF, syntax error. + static const unsigned short int yytable_[]; + + static const short int yycheck_[]; + + // YYSTOS[STATE-NUM] -- The (internal number of the) accessing + // symbol of state STATE-NUM. + static const unsigned char yystos_[]; + + // YYR1[YYN] -- Symbol number of symbol that rule YYN derives. + static const unsigned char yyr1_[]; + + // YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. + static const unsigned char yyr2_[]; + + + /// Convert the symbol name \a n to a form suitable for a diagnostic. + static std::string yytnamerr_ (const char *n); + + + /// For a symbol, its name in clear. + static const char* const yytname_[]; +#if YYDEBUG + // YYRLINE[YYN] -- Source line where rule number YYN was defined. + static const unsigned short int yyrline_[]; + /// Report on the debug stream that the rule \a r is going to be reduced. + virtual void yy_reduce_print_ (int r); + /// Print the state stack on the debug stream. + virtual void yystack_print_ (); + + // Debugging. + int yydebug_; + std::ostream* yycdebug_; + + /// \brief Display a symbol type, value and location. + /// \param yyo The output stream. + /// \param yysym The symbol. + template + void yy_print_ (std::ostream& yyo, const basic_symbol& yysym) const; +#endif + + /// \brief Reclaim the memory associated to a symbol. + /// \param yymsg Why this token is reclaimed. + /// If null, print nothing. + /// \param yysym The symbol. + template + void yy_destroy_ (const char* yymsg, basic_symbol& yysym) const; + + private: + /// Type access provider for state based symbols. + struct by_state + { + /// Default constructor. + by_state (); + + /// The symbol type as needed by the constructor. + typedef state_type kind_type; + + /// Constructor. + by_state (kind_type s); + + /// Copy constructor. + by_state (const by_state& other); + + /// Record that this symbol is empty. + void clear (); + + /// Steal the symbol type from \a that. + void move (by_state& that); + + /// The (internal) type number (corresponding to \a state). + /// \a empty_symbol when empty. + symbol_number_type type_get () const; + + /// The state number used to denote an empty symbol. + enum { empty_state = -1 }; + + /// The state. + /// \a empty when empty. + state_type state; + }; + + /// "Internal" symbol: element of the stack. + struct stack_symbol_type : basic_symbol + { + /// Superclass. + typedef basic_symbol super_type; + /// Construct an empty symbol. + stack_symbol_type (); + /// Copy construct. + stack_symbol_type (const stack_symbol_type& that); + /// Steal the contents from \a sym to build this. + stack_symbol_type (state_type s, symbol_type& sym); + /// Assignment, needed by push_back. + stack_symbol_type& operator= (const stack_symbol_type& that); + }; + + /// Stack type. + typedef stack stack_type; + + /// The stack. + stack_type yystack_; + + /// Push a new state on the stack. + /// \param m a debug message to display + /// if null, no trace is output. + /// \param s the symbol + /// \warning the contents of \a s.value is stolen. + void yypush_ (const char* m, stack_symbol_type& s); + + /// Push a new look ahead token on the state on the stack. + /// \param m a debug message to display + /// if null, no trace is output. + /// \param s the state + /// \param sym the symbol (for its value and location). + /// \warning the contents of \a s.value is stolen. + void yypush_ (const char* m, state_type s, symbol_type& sym); + + /// Pop \a n symbols the three stacks. + void yypop_ (unsigned n = 1); + + /// Constants. + enum + { + yyeof_ = 0, + yylast_ = 955, ///< Last index in yytable_. + yynnts_ = 79, ///< Number of nonterminal symbols. + yyfinal_ = 74, ///< Termination state number. + yyterror_ = 1, + yyerrcode_ = 256, + yyntokens_ = 38 ///< Number of tokens. + }; + + + // User arguments. + bool enableSchema; + Node **outAST; + const char **outError; + void *scanner; + }; + + + +} // yy +#line 642 "parser.tab.hpp" // lalr1.cc:394 + + + + +#endif // !YY_YY_PARSER_TAB_HPP_INCLUDED diff --git a/external/graphqlparser/parsergen/position.hh b/external/graphqlparser/parsergen/position.hh new file mode 100644 index 0000000..53c9aff --- /dev/null +++ b/external/graphqlparser/parsergen/position.hh @@ -0,0 +1,179 @@ +// A Bison parser, made by GNU Bison 3.0.5. + +// Positions for Bison parsers in C++ + +// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +/** + ** \file position.hh + ** Define the yy::position class. + */ + +#ifndef YY_YY_POSITION_HH_INCLUDED +# define YY_YY_POSITION_HH_INCLUDED + +# include // std::max +# include +# include + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + + +namespace yy { +#line 56 "position.hh" // location.cc:333 + /// Abstract a position. + class position + { + public: + /// Construct a position. + explicit position (std::string* f = YY_NULLPTR, + unsigned l = 1u, + unsigned c = 1u) + : filename (f) + , line (l) + , column (c) + {} + + + /// Initialization. + void initialize (std::string* fn = YY_NULLPTR, + unsigned l = 1u, + unsigned c = 1u) + { + filename = fn; + line = l; + column = c; + } + + /** \name Line and Column related manipulators + ** \{ */ + /// (line related) Advance to the COUNT next lines. + void lines (int count = 1) + { + if (count) + { + column = 1u; + line = add_ (line, count, 1); + } + } + + /// (column related) Advance to the COUNT next columns. + void columns (int count = 1) + { + column = add_ (column, count, 1); + } + /** \} */ + + /// File name to which this position refers. + std::string* filename; + /// Current line number. + unsigned line; + /// Current column number. + unsigned column; + + private: + /// Compute max(min, lhs+rhs) (provided min <= lhs). + static unsigned add_ (unsigned lhs, int rhs, unsigned min) + { + return (0 < rhs || -static_cast(rhs) < lhs + ? rhs + lhs + : min); + } + }; + + /// Add \a width columns, in place. + inline position& + operator+= (position& res, int width) + { + res.columns (width); + return res; + } + + /// Add \a width columns. + inline position + operator+ (position res, int width) + { + return res += width; + } + + /// Subtract \a width columns, in place. + inline position& + operator-= (position& res, int width) + { + return res += -width; + } + + /// Subtract \a width columns. + inline position + operator- (position res, int width) + { + return res -= width; + } + + /// Compare two position objects. + inline bool + operator== (const position& pos1, const position& pos2) + { + return (pos1.line == pos2.line + && pos1.column == pos2.column + && (pos1.filename == pos2.filename + || (pos1.filename && pos2.filename + && *pos1.filename == *pos2.filename))); + } + + /// Compare two position objects. + inline bool + operator!= (const position& pos1, const position& pos2) + { + return !(pos1 == pos2); + } + + /** \brief Intercept output stream redirection. + ** \param ostr the destination output stream + ** \param pos a reference to the position to redirect + */ + template + inline std::basic_ostream& + operator<< (std::basic_ostream& ostr, const position& pos) + { + if (pos.filename) + ostr << *pos.filename << ':'; + return ostr << pos.line << '.' << pos.column; + } + + +} // yy +#line 179 "position.hh" // location.cc:333 +#endif // !YY_YY_POSITION_HH_INCLUDED diff --git a/external/graphqlparser/parsergen/stack.hh b/external/graphqlparser/parsergen/stack.hh new file mode 100644 index 0000000..9535b3e --- /dev/null +++ b/external/graphqlparser/parsergen/stack.hh @@ -0,0 +1,156 @@ +// A Bison parser, made by GNU Bison 3.0.5. + +// Stack handling for Bison parsers in C++ + +// Copyright (C) 2002-2015, 2018 Free Software Foundation, Inc. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// As a special exception, you may create a larger work that contains +// part or all of the Bison parser skeleton and distribute that work +// under terms of your choice, so long as that work isn't itself a +// parser generator using the skeleton or a modified version thereof +// as a parser skeleton. Alternatively, if you modify or redistribute +// the parser skeleton itself, you may (at your option) remove this +// special exception, which will cause the skeleton and the resulting +// Bison output files to be licensed under the GNU General Public +// License without this special exception. + +// This special exception was added by the Free Software Foundation in +// version 2.2 of Bison. + +/** + ** \file stack.hh + ** Define the yy::stack class. + */ + +#ifndef YY_YY_STACK_HH_INCLUDED +# define YY_YY_STACK_HH_INCLUDED + +# include + + +namespace yy { +#line 46 "stack.hh" // stack.hh:150 + /// A stack with random access from its top. + template > + class stack + { + public: + // Hide our reversed order. + typedef typename S::reverse_iterator iterator; + typedef typename S::const_reverse_iterator const_iterator; + + stack () + : seq_ () + { + seq_.reserve (200); + } + + stack (unsigned n) + : seq_ (n) + {} + + /// Random access. + /// + /// Index 0 returns the topmost element. + T& + operator[] (unsigned i) + { + return seq_[seq_.size () - 1 - i]; + } + + /// Random access. + /// + /// Index 0 returns the topmost element. + const T& + operator[] (unsigned i) const + { + return seq_[seq_.size () - 1 - i]; + } + + /// Steal the contents of \a t. + /// + /// Close to move-semantics. + void + push (T& t) + { + seq_.push_back (T()); + operator[](0).move (t); + } + + void + pop (unsigned n = 1) + { + for (; n; --n) + seq_.pop_back (); + } + + void + clear () + { + seq_.clear (); + } + + typename S::size_type + size () const + { + return seq_.size (); + } + + const_iterator + begin () const + { + return seq_.rbegin (); + } + + const_iterator + end () const + { + return seq_.rend (); + } + + private: + stack (const stack&); + stack& operator= (const stack&); + /// The wrapped container. + S seq_; + }; + + /// Present a slice of the top of a stack. + template > + class slice + { + public: + slice (const S& stack, unsigned range) + : stack_ (stack) + , range_ (range) + {} + + const T& + operator [] (unsigned i) const + { + return stack_[range_ - i]; + } + + private: + const S& stack_; + unsigned range_; + }; + + +} // yy +#line 155 "stack.hh" // stack.hh:150 + +#endif // !YY_YY_STACK_HH_INCLUDED diff --git a/external/graphqlparser/python/.gitignore b/external/graphqlparser/python/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/external/graphqlparser/python/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/external/graphqlparser/python/CMakeLists.txt b/external/graphqlparser/python/CMakeLists.txt new file mode 100644 index 0000000..d812f45 --- /dev/null +++ b/external/graphqlparser/python/CMakeLists.txt @@ -0,0 +1,14 @@ + +IF (CTYPESGEN_FOUND) + ADD_CUSTOM_COMMAND( + OUTPUT GraphQLParser.py + COMMAND ctypesgen.py ${CMAKE_CURRENT_SOURCE_DIR}/../c/*.h ${CMAKE_CURRENT_BINARY_DIR}/../c/*.h -o ${CMAKE_CURRENT_SOURCE_DIR}/GraphQLParser.py -I ${CMAKE_CURRENT_SOURCE_DIR}/.. -I ${CMAKE_CURRENT_BINARY_DIR}/.. -l graphqlparser -L ${CMAKE_CURRENT_BINARY_DIR}/.. 2>&1 > /dev/null + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../c/GraphQLAstForEachConcreteType.h ${CMAKE_CURRENT_BINARY_DIR}/../c/GraphQLAst.h ${CMAKE_CURRENT_SOURCE_DIR}/../c/GraphQLAstNode.h ${CMAKE_CURRENT_SOURCE_DIR}/../c/GraphQLAstVisitor.h ${CMAKE_CURRENT_SOURCE_DIR}/../c/GraphQLParser.h + ) + ADD_CUSTOM_TARGET( + graphql-parser-python + ALL + DEPENDS GraphQLParser.py) +ELSE() + MESSAGE(WARNING "ctypesgen.py not found; install with pip or easy_install if you want to run pythontest.py.") +ENDIF() diff --git a/external/graphqlparser/python/README.md b/external/graphqlparser/python/README.md new file mode 100644 index 0000000..cfec5bf --- /dev/null +++ b/external/graphqlparser/python/README.md @@ -0,0 +1,5 @@ +This directory contains an example Python binding to the GraphQL +parser and AST library. It uses +[ctypesgen.py](https://github.com/davidjamesca/ctypesgen) to generate +the binding code automatically from the pure C API in +`../c`. `example.py` is a short program that uses this binding. diff --git a/external/graphqlparser/python/example.py b/external/graphqlparser/python/example.py new file mode 100755 index 0000000..310c261 --- /dev/null +++ b/external/graphqlparser/python/example.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +from ctypes import * +from GraphQLParser import * + +def print_field(field, unused): + field_name = GraphQLAstField_get_name(field) + field_name_value = GraphQLAstName_get_value(field_name) + print 'field : ' + field_name_value + return 0 + +def main(): + error = POINTER(c_char)() + ast = graphql_parse_string('query myquery { myfield }', byref(error)) + field_visitor_callbacks = GraphQLAstVisitorCallbacks(visit_field = visit_field_func(print_field)) + graphql_node_visit(ast, pointer(field_visitor_callbacks), None) + + graphql_node_free(ast) + + ast = graphql_parse_string('query errorQuery on oops { myfield }', byref(error)) + print 'Example error:', string_at(error) + graphql_error_free(error) + if ast: + print 'BUG: we should have got a null AST back, but we got:', ast + +if __name__ == '__main__': + main() diff --git a/external/graphqlparser/syntaxdefs.h b/external/graphqlparser/syntaxdefs.h new file mode 100644 index 0000000..de37b2c --- /dev/null +++ b/external/graphqlparser/syntaxdefs.h @@ -0,0 +1,19 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#pragma once + +/*** + * This file contains definitions that need to be shared by the parser + * and the lexer. + */ + +yy::GraphQLParserImpl::syntax_error make_error(const yy::location &loc, const std::string &str); + +struct LexerExtra { + std::string str; + yy::location loc; +}; diff --git a/external/graphqlparser/test/.gitignore b/external/graphqlparser/test/.gitignore new file mode 100644 index 0000000..ef5d622 --- /dev/null +++ b/external/graphqlparser/test/.gitignore @@ -0,0 +1,5 @@ +CTestTestfile.cmake +gtest*/* +googletest* +release-1.8.0* +runTests* diff --git a/external/graphqlparser/test/BuildCAPI.c b/external/graphqlparser/test/BuildCAPI.c new file mode 100644 index 0000000..cb28307 --- /dev/null +++ b/external/graphqlparser/test/BuildCAPI.c @@ -0,0 +1,5 @@ +// Copyright GraphQL Foundation +#include +#include + +/* This file is just here to make sure our C API builds OK. */ diff --git a/external/graphqlparser/test/CMakeLists.txt b/external/graphqlparser/test/CMakeLists.txt new file mode 100644 index 0000000..4d08a33 --- /dev/null +++ b/external/graphqlparser/test/CMakeLists.txt @@ -0,0 +1,25 @@ +ADD_SUBDIRECTORY(googletest-release-1.8.0/googletest) + +ENABLE_TESTING() + +INCLUDE_DIRECTORIES(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR} /usr/local/include/graphqlparser) + +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -g") + +FILE(COPY valgrind.supp DESTINATION .) + +FILE(COPY kitchen-sink.graphql DESTINATION .) + +FILE(COPY kitchen-sink.json DESTINATION .) + +FILE(COPY schema-kitchen-sink.graphql DESTINATION .) + +FILE(COPY schema-kitchen-sink.json DESTINATION .) + +ADD_EXECUTABLE(runTests ParserTests.cpp JsonVisitorTests.cpp BuildCAPI.c) + +find_library(LIBGRAPHQLPARSER_LIBRARY libgraphqlparser.dylib HINTS /usr/local/lib) + +TARGET_LINK_LIBRARIES(runTests gtest gtest_main ${LIBGRAPHQLPARSER_LIBRARY}) + +ADD_TEST(gtest_tests runTests) diff --git a/external/graphqlparser/test/JsonVisitorTests.cpp b/external/graphqlparser/test/JsonVisitorTests.cpp new file mode 100644 index 0000000..75f4073 --- /dev/null +++ b/external/graphqlparser/test/JsonVisitorTests.cpp @@ -0,0 +1,28 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include "Ast.h" +#include "GraphQLParser.h" +#include "c/GraphQLAstToJSON.h" + +using facebook::graphql::parseString; + +TEST(JsonVisitorTests, NullValueEmitsValidJSONWithoutTrailingComma) { + const char *error = nullptr; + auto AST = parseString("{field(arg: null)}", &error); + ASSERT_STREQ(nullptr, error) << "GraphQL parser error: " << error; + const char *json = graphql_ast_to_json(reinterpret_cast(AST.get())); + + EXPECT_STREQ( + json, + "{\"kind\":\"Document\",\"loc\":{\"start\": {\"line\": 1,\"column\":1}, \"end\": {\"line\":1,\"column\":19}},\"definitions\":[{\"kind\":\"OperationDefinition\",\"loc\":{\"start\": {\"line\": 1,\"column\":1}, \"end\": {\"line\":1,\"column\":19}},\"operation\":\"query\",\"name\":null,\"variableDefinitions\":null,\"directives\":null,\"selectionSet\":{\"kind\":\"SelectionSet\",\"loc\":{\"start\": {\"line\": 1,\"column\":1}, \"end\": {\"line\":1,\"column\":19}},\"selections\":[{\"kind\":\"Field\",\"loc\":{\"start\": {\"line\": 1,\"column\":2}, \"end\": {\"line\":1,\"column\":18}},\"alias\":null,\"name\":{\"kind\":\"Name\",\"loc\":{\"start\": {\"line\": 1,\"column\":2}, \"end\": {\"line\":1,\"column\":7}},\"value\":\"field\"},\"arguments\":[{\"kind\":\"Argument\",\"loc\":{\"start\": {\"line\": 1,\"column\":8}, \"end\": {\"line\":1,\"column\":17}},\"name\":{\"kind\":\"Name\",\"loc\":{\"start\": {\"line\": 1,\"column\":8}, \"end\": {\"line\":1,\"column\":11}},\"value\":\"arg\"},\"value\":{\"kind\":\"NullValue\",\"loc\":{\"start\": {\"line\": 1,\"column\":13}, \"end\": {\"line\":1,\"column\":17}}}}],\"directives\":null,\"selectionSet\":null}]}}]}" + ); + + free((void *)json); +} diff --git a/external/graphqlparser/test/ParserTests.cpp b/external/graphqlparser/test/ParserTests.cpp new file mode 100644 index 0000000..ae0d6ca --- /dev/null +++ b/external/graphqlparser/test/ParserTests.cpp @@ -0,0 +1,352 @@ +/** + * Copyright 2019-present, GraphQL Foundation + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +#include "Ast.h" +#include "GraphQLParser.h" +#include "c/GraphQLAstToJSON.h" + +using namespace facebook::graphql; +using namespace facebook::graphql::ast; + + +static void expectError(const char *queryStr, const char *expectedError) { + const char *actualError = nullptr; + auto ast = parseString(queryStr, &actualError); + + EXPECT_FALSE(ast); + EXPECT_STREQ(actualError, expectedError); + + std::free((void *)actualError); +} + +static void expectSuccessImpl(const char *queryStr, bool enableSchema) { + const char *actualError = nullptr; + auto ast = enableSchema + ? parseStringWithExperimentalSchemaSupport(queryStr, &actualError) + : parseString(queryStr, &actualError); + + EXPECT_TRUE(ast != nullptr); + EXPECT_STREQ(nullptr, actualError); + + std::free((void *)actualError); // NOLINT +} + +static void expectSuccess(const char *queryStr) { + expectSuccessImpl(queryStr, false); +} + +static void expectSchemaSuccess(const char *queryStr) { + expectSuccessImpl(queryStr, true); +} + +static void checkSimpleError() { + expectError("query myquery on type { field }", + "1.15-16: syntax error, unexpected on, expecting ( or @ or {"); +} + +TEST(ParserTests, RejectsUnrecognizedCharacter) { + expectError("query myquery { field };", + "1.24: unrecognized character ;"); +} + +TEST(ParserTests, RejectsControlCharacter) { + expectError("query myQuery { \a }", + R"(1.17: unrecognized character \a)"); +} + +TEST(ParserTests, AcceptsUnicodeBOM) { + expectSuccess("\xef\xbb\xbfquery myquery { field }"); + expectSuccess("query myquery\xef\xbb\xbf{ field }"); +} + +TEST(ParserTests, ReportsErrorLocationAfterIgnoredBOM) { + expectError("\xef\xbb\xbfquery myquery { field };", + "1.27: unrecognized character ;"); + +} + +TEST(ParserTests, RejectsPartialBOM) { + expectError("\xefquery myquery { field };", + R"(1.1: unrecognized character \xef)"); +} + +TEST(ParserTests, RejectsVerticalTab) { + expectError("\v", R"(1.1: unrecognized character \v)"); +} + +TEST(ParserTests, RejectsFormFeed) { + expectError("\f", R"(1.1: unrecognized character \f)"); +} + +TEST(ParserTests, RejectsNoBreakSpace) { + expectError("\xa0", R"(1.1: unrecognized character \xa0)"); +} + + +TEST(ParserTests, LocationTracking) { + SCOPED_TRACE("LocationTracking"); + checkSimpleError(); +} + +TEST(ParserTests, LocationTrackingResetsAcrossInputs) { + { + SCOPED_TRACE("LocationTrackingResetsAcrossInputsFirstTime"); + checkSimpleError(); + } + + { + SCOPED_TRACE("LocationTrackingResetsAcrossInputsSecondTime"); + checkSimpleError(); + } + +} + +TEST(ParserTests, LocationTrackingCollapsesCRLF) { + expectError("\r\n;", "2.1: unrecognized character ;"); +} + +TEST(ParserTests, AcceptsEmptyString) { + expectSuccess(R"({ field(arg:"") })"); +} + +TEST(ParserTests, AcceptsEmptyBlockString) { + expectSuccess(R"({ field(arg:"""""") })"); +} + +TEST(ParserTests, UnterminatedString) { + expectError("\"", "1.1: Unterminated string at EOF"); + expectError("\"\n\"", "1.1-2: Unterminated string"); +} + +TEST(ParserTests, RejectControlCharacterInString) { + expectError("{ field(arg:\"\b\") }", R"(1.13-14: unrecognized character \b)"); +} + +TEST(ParserTests, RejectsBadXEscapeSequence) { + expectError(R"({ field(arg:"\x") })", R"(1.13-15: bad escape sequence \x)"); +} + +TEST(ParserTests, RejectsIncompleteUnicodeEscape) { + expectError(R"({ field(arg:"\u1") })", "1.13-15: bad Unicode escape sequence"); +} + +TEST(ParserTests, RejectsUnicodeEscapeWithBadChars) { + expectError(R"({ field(arg:"\u0XX1") })", "1.13-15: bad Unicode escape sequence"); + expectError(R"({ field(arg:"\uXXXX") })", "1.13-15: bad Unicode escape sequence"); + expectError(R"({ field(arg:"\uFXXX") })", "1.13-15: bad Unicode escape sequence"); + expectError(R"({ field(arg:"\uXXXF") })", "1.13-15: bad Unicode escape sequence"); +} + +TEST(ParserTests, AcceptsValidUnicodeEscape) { + const char *actualError = nullptr; + auto ast = parseString(R"({ field(arg:"\u0009Hello") })", &actualError); + + EXPECT_TRUE(ast != nullptr); + EXPECT_STREQ(nullptr, actualError); + std::free((void *)actualError); + + auto doc = dynamic_cast(ast.get()); + ASSERT_TRUE(doc != nullptr); + + const auto& defs = doc->getDefinitions(); + ASSERT_EQ(1, defs.size()); + + auto opDef = dynamic_cast(defs[0].get()); + ASSERT_TRUE(opDef != nullptr); + + ASSERT_EQ(1, opDef->getSelectionSet().getSelections().size()); + + auto field = dynamic_cast(opDef->getSelectionSet().getSelections()[0].get()); + ASSERT_TRUE(field != nullptr); + + auto *args = field->getArguments(); + ASSERT_NE(nullptr, args); + ASSERT_EQ(1, args->size()); + auto *val = dynamic_cast(&(*args)[0]->getValue()); + ASSERT_NE(nullptr, val); + EXPECT_STREQ("\tHello", val->getValue()); +} + +TEST(ParserTests, TracksLocationAcrossStrings) { + expectError(R"({ field(arg:"\uFEFF\n") };)", + "1.26: unrecognized character ;"); +} + +TEST(ParserTests, UsefulErrors) { + expectError("{ ...MissingOn }\nfragment MissingOn Type", + "2.20-23: syntax error, unexpected IDENTIFIER, expecting on"); + + expectError("{ field: {} }", + "1.10: syntax error, unexpected {"); + + expectError( + "notanoperation Foo { field }", + "1.1-14: syntax error, unexpected IDENTIFIER"); + + expectError("...", + "1.1-3: syntax error, unexpected ..."); +} + +TEST(ParserTests, AcceptsVariableInlineValues) { + expectSuccess("{ field(complex: { a: { b: [ $var ] } }) }"); +} + +TEST(ParserTests, RejectsVariablesInConstantValues) { + expectError("query Foo($x: Complex = { a: { b: [ $var ] } }) { field }", + "1.37-40: syntax error, unexpected VARIABLE"); +} + +TEST(ParserTests, RejectsFragmentsNamedOn) { + expectError("fragment on on on { on }", + "1.10-11: syntax error, unexpected on"); +} + +TEST(ParserTests, RejectsFragmentSpreadOfOn) { + expectError("{ ...on }", + "1.9: syntax error, unexpected }"); +}; + +TEST(ParserTests, AcceptsNullValue) { + expectSuccess("{ fieldWithNullableStringInput(input: null) }"); +} + +TEST(ParserTests, AcceptsSimpleQuery) { + expectSuccess("query MyQuery { myfield }"); +} + +TEST(ParserTests, AcceptsSimpleMutation) { + expectSuccess("mutation MyMut { myfield }"); +} + +TEST(ParserTests, AcceptsSimpleSubscription) { + expectSuccess("subscription MySub { myfield }"); +} + +TEST(ParserTests, AcceptsQueryShorthand) { + expectSuccess("{ myfield }"); +} + +TEST(ParserTests, AcceptsLonghandUnnamedQuery) { + expectSuccess("query { myfield }"); +} + +TEST(ParserTests, AcceptsLonghandUnnamedMutation) { + expectSuccess("mutation { myfield }"); +} + +TEST(ParserTests, AcceptsLonghandUnnamedSubscription) { + expectSuccess("subscription { myfield }"); +} + +TEST(ParserTests, AllowsNonKeywordsForNames) { + const char *nonKeywords[] = { + "on", + "fragment", + "query", + "mutation", + "subscription", + "true", + "false" + }; + + for (auto keyword : nonKeywords) { + const char *fragmentName = !strcmp(keyword, "on") ? "a" : keyword; + + std::ostringstream str; + + str << "query " << keyword << "{\n" + << " ... " << fragmentName << '\n' + << " ... on " << keyword << " { field }\n" + << "}\n" + << "fragment " << fragmentName << " on Type {" + << " " << keyword << '(' << keyword << ": $" << keyword << ") @" << keyword << '(' << keyword << ": " << keyword << ")\n" + << "}\n"; + expectSuccess(str.str().c_str()); + } +} + +static void testCorrectOutputForStockFile( + const char *inputFileName, + const char *outputFileName, + bool withSchemaParsing) { + FILE *fp = fopen(inputFileName, "r"); + ASSERT_NE(nullptr, fp); + const char *error = nullptr; + std::unique_ptr ast; + if (withSchemaParsing) { + ast = parseFileWithExperimentalSchemaSupport(fp, &error); + } else { + ast = parseFile(fp, &error); + } + ASSERT_TRUE(ast); + ASSERT_FALSE(error); + fclose(fp); + + const char *json = graphql_ast_to_json((const struct GraphQLAstNode *)ast.get()); + std::ifstream ifs(outputFileName); + std::stringstream ss; + ss << ifs.rdbuf(); + EXPECT_STREQ( + json, + ss.str().c_str() + ); + free((void *)json); +} + +TEST(ParserTests, ProducesCorrectOutputForKitchenSink) { + SCOPED_TRACE("KitchenSink"); + testCorrectOutputForStockFile( + "test/kitchen-sink.graphql", + "test/kitchen-sink.json", + false); +} + +TEST(ParserTests, ProducesCorrectOutputForSchemaKitchenSink) { + SCOPED_TRACE("SchemaKitchenSink"); + testCorrectOutputForStockFile( + "test/schema-kitchen-sink.graphql", + "test/schema-kitchen-sink.json", + true); +} + +static void expectSchemaParsing(const char *queryStr) { + char buf[strlen("1.1-XXX: schema support disabled") + 1]; + ASSERT_LT(strlen(queryStr), 999); + snprintf( + buf, + sizeof(buf), + "1.1-%lu: schema support disabled", + strlen(queryStr)); + expectError(queryStr, buf); + expectSchemaSuccess(queryStr); +} + +#define DIRECTIVES "@d1(a: 1) @d2(a: 2)" + +TEST(SchemaParserTests, SimpleSchema) { + expectSchemaParsing( + "schema " DIRECTIVES " { query: QueryType, mutation: MutType }"); + expectSchemaParsing("scalar SomeScalar " DIRECTIVES); + expectSchemaParsing("type SomeObject implements SomeInterface " DIRECTIVES + " { someField : SomeType }"); + expectSchemaParsing("interface SomeInterface " DIRECTIVES + " { someField : SomeType }"); + expectSchemaParsing("union SomeUnion " DIRECTIVES + " = SomeType | SomeOtherType"); + expectSchemaParsing("enum SomeEnum " DIRECTIVES " { VALUE, OTHER_VALUE }"); + expectSchemaParsing("input SomeInput " DIRECTIVES "{ someField: SomeType, " + "otherField: otherType }"); + expectSchemaParsing("extend type SomeType " DIRECTIVES + "{ anotherField : AnotherType }"); + expectSchemaParsing("directive @somedirective(a1 : t1 = 1 " DIRECTIVES + ", a2 : t2) on foo | bar"); +} diff --git a/external/graphqlparser/test/kitchen-sink.graphql b/external/graphqlparser/test/kitchen-sink.graphql new file mode 100644 index 0000000..7fd8f24 --- /dev/null +++ b/external/graphqlparser/test/kitchen-sink.graphql @@ -0,0 +1,59 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +query queryName($foo: ComplexType, $site: Site = MOBILE) { + whoever123is: node(id: [123, 456]) { + id , + ... on User @defer { + field2 { + id , + alias: field1(first:10, after:$foo,) @include(if: $foo) { + id, + ...frag + } + } + } + ... @skip(unless: $foo) { + id + } + ... { + id + } + } +} + +mutation likeStory { + like(story: 123) @defer { + story { + id + } + } +} + +subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) { + storyLikeSubscribe(input: $input) { + story { + likers { + count + } + likeSentence { + text + } + } + } +} + +fragment frag on Friend { + foo(size: $size, bar: $b, obj: {key: "value", block: """ + + block string uses \""" + + """}) +} + +{ + unnamed(truthy: true, falsey: false, nullish: null), + query +} diff --git a/external/graphqlparser/test/kitchen-sink.json b/external/graphqlparser/test/kitchen-sink.json new file mode 100644 index 0000000..14b93ab --- /dev/null +++ b/external/graphqlparser/test/kitchen-sink.json @@ -0,0 +1 @@ +{"kind":"Document","loc":{"start": {"line": 6,"column":1}, "end": {"line":55,"column":2}},"definitions":[{"kind":"OperationDefinition","loc":{"start": {"line": 6,"column":1}, "end": {"line":25,"column":2}},"operation":"query","name":{"kind":"Name","loc":{"start": {"line": 6,"column":7}, "end": {"line":6,"column":16}},"value":"queryName"},"variableDefinitions":[{"kind":"VariableDefinition","loc":{"start": {"line": 6,"column":17}, "end": {"line":6,"column":34}},"variable":{"kind":"Variable","loc":{"start": {"line": 6,"column":17}, "end": {"line":6,"column":21}},"name":{"kind":"Name","loc":{"start": {"line": 6,"column":17}, "end": {"line":6,"column":21}},"value":"foo"}},"type":{"kind":"NamedType","loc":{"start": {"line": 6,"column":23}, "end": {"line":6,"column":34}},"name":{"kind":"Name","loc":{"start": {"line": 6,"column":23}, "end": {"line":6,"column":34}},"value":"ComplexType"}},"defaultValue":null},{"kind":"VariableDefinition","loc":{"start": {"line": 6,"column":36}, "end": {"line":6,"column":56}},"variable":{"kind":"Variable","loc":{"start": {"line": 6,"column":36}, "end": {"line":6,"column":41}},"name":{"kind":"Name","loc":{"start": {"line": 6,"column":36}, "end": {"line":6,"column":41}},"value":"site"}},"type":{"kind":"NamedType","loc":{"start": {"line": 6,"column":43}, "end": {"line":6,"column":47}},"name":{"kind":"Name","loc":{"start": {"line": 6,"column":43}, "end": {"line":6,"column":47}},"value":"Site"}},"defaultValue":{"kind":"EnumValue","loc":{"start": {"line": 6,"column":50}, "end": {"line":6,"column":56}},"value":"MOBILE"}}],"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 6,"column":58}, "end": {"line":25,"column":2}},"selections":[{"kind":"Field","loc":{"start": {"line": 7,"column":3}, "end": {"line":24,"column":4}},"alias":{"kind":"Name","loc":{"start": {"line": 7,"column":3}, "end": {"line":7,"column":15}},"value":"whoever123is"},"name":{"kind":"Name","loc":{"start": {"line": 7,"column":17}, "end": {"line":7,"column":21}},"value":"node"},"arguments":[{"kind":"Argument","loc":{"start": {"line": 7,"column":22}, "end": {"line":7,"column":36}},"name":{"kind":"Name","loc":{"start": {"line": 7,"column":22}, "end": {"line":7,"column":24}},"value":"id"},"value":{"kind":"ListValue","loc":{"start": {"line": 7,"column":26}, "end": {"line":7,"column":36}},"values":[{"kind":"IntValue","loc":{"start": {"line": 7,"column":27}, "end": {"line":7,"column":30}},"value":"123"},{"kind":"IntValue","loc":{"start": {"line": 7,"column":32}, "end": {"line":7,"column":35}},"value":"456"}]}}],"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 7,"column":38}, "end": {"line":24,"column":4}},"selections":[{"kind":"Field","loc":{"start": {"line": 8,"column":5}, "end": {"line":8,"column":7}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 8,"column":5}, "end": {"line":8,"column":7}},"value":"id"},"arguments":null,"directives":null,"selectionSet":null},{"kind":"InlineFragment","loc":{"start": {"line": 9,"column":5}, "end": {"line":17,"column":6}},"typeCondition":{"kind":"NamedType","loc":{"start": {"line": 9,"column":12}, "end": {"line":9,"column":16}},"name":{"kind":"Name","loc":{"start": {"line": 9,"column":12}, "end": {"line":9,"column":16}},"value":"User"}},"directives":[{"kind":"Directive","loc":{"start": {"line": 9,"column":17}, "end": {"line":9,"column":23}},"name":{"kind":"Name","loc":{"start": {"line": 9,"column":18}, "end": {"line":9,"column":23}},"value":"defer"},"arguments":null}],"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 9,"column":24}, "end": {"line":17,"column":6}},"selections":[{"kind":"Field","loc":{"start": {"line": 10,"column":7}, "end": {"line":16,"column":8}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 10,"column":7}, "end": {"line":10,"column":13}},"value":"field2"},"arguments":null,"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 10,"column":14}, "end": {"line":16,"column":8}},"selections":[{"kind":"Field","loc":{"start": {"line": 11,"column":9}, "end": {"line":11,"column":11}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 11,"column":9}, "end": {"line":11,"column":11}},"value":"id"},"arguments":null,"directives":null,"selectionSet":null},{"kind":"Field","loc":{"start": {"line": 12,"column":9}, "end": {"line":15,"column":10}},"alias":{"kind":"Name","loc":{"start": {"line": 12,"column":9}, "end": {"line":12,"column":14}},"value":"alias"},"name":{"kind":"Name","loc":{"start": {"line": 12,"column":16}, "end": {"line":12,"column":22}},"value":"field1"},"arguments":[{"kind":"Argument","loc":{"start": {"line": 12,"column":23}, "end": {"line":12,"column":31}},"name":{"kind":"Name","loc":{"start": {"line": 12,"column":23}, "end": {"line":12,"column":28}},"value":"first"},"value":{"kind":"IntValue","loc":{"start": {"line": 12,"column":29}, "end": {"line":12,"column":31}},"value":"10"}},{"kind":"Argument","loc":{"start": {"line": 12,"column":33}, "end": {"line":12,"column":43}},"name":{"kind":"Name","loc":{"start": {"line": 12,"column":33}, "end": {"line":12,"column":38}},"value":"after"},"value":{"kind":"Variable","loc":{"start": {"line": 12,"column":39}, "end": {"line":12,"column":43}},"name":{"kind":"Name","loc":{"start": {"line": 12,"column":39}, "end": {"line":12,"column":43}},"value":"foo"}}}],"directives":[{"kind":"Directive","loc":{"start": {"line": 12,"column":46}, "end": {"line":12,"column":64}},"name":{"kind":"Name","loc":{"start": {"line": 12,"column":47}, "end": {"line":12,"column":54}},"value":"include"},"arguments":[{"kind":"Argument","loc":{"start": {"line": 12,"column":55}, "end": {"line":12,"column":63}},"name":{"kind":"Name","loc":{"start": {"line": 12,"column":55}, "end": {"line":12,"column":57}},"value":"if"},"value":{"kind":"Variable","loc":{"start": {"line": 12,"column":59}, "end": {"line":12,"column":63}},"name":{"kind":"Name","loc":{"start": {"line": 12,"column":59}, "end": {"line":12,"column":63}},"value":"foo"}}}]}],"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 12,"column":65}, "end": {"line":15,"column":10}},"selections":[{"kind":"Field","loc":{"start": {"line": 13,"column":11}, "end": {"line":13,"column":13}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 13,"column":11}, "end": {"line":13,"column":13}},"value":"id"},"arguments":null,"directives":null,"selectionSet":null},{"kind":"FragmentSpread","loc":{"start": {"line": 14,"column":11}, "end": {"line":14,"column":18}},"name":{"kind":"Name","loc":{"start": {"line": 14,"column":14}, "end": {"line":14,"column":18}},"value":"frag"},"directives":null}]}}]}}]}},{"kind":"InlineFragment","loc":{"start": {"line": 18,"column":5}, "end": {"line":20,"column":6}},"typeCondition":null,"directives":[{"kind":"Directive","loc":{"start": {"line": 18,"column":9}, "end": {"line":18,"column":28}},"name":{"kind":"Name","loc":{"start": {"line": 18,"column":10}, "end": {"line":18,"column":14}},"value":"skip"},"arguments":[{"kind":"Argument","loc":{"start": {"line": 18,"column":15}, "end": {"line":18,"column":27}},"name":{"kind":"Name","loc":{"start": {"line": 18,"column":15}, "end": {"line":18,"column":21}},"value":"unless"},"value":{"kind":"Variable","loc":{"start": {"line": 18,"column":23}, "end": {"line":18,"column":27}},"name":{"kind":"Name","loc":{"start": {"line": 18,"column":23}, "end": {"line":18,"column":27}},"value":"foo"}}}]}],"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 18,"column":29}, "end": {"line":20,"column":6}},"selections":[{"kind":"Field","loc":{"start": {"line": 19,"column":7}, "end": {"line":19,"column":9}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 19,"column":7}, "end": {"line":19,"column":9}},"value":"id"},"arguments":null,"directives":null,"selectionSet":null}]}},{"kind":"InlineFragment","loc":{"start": {"line": 21,"column":5}, "end": {"line":23,"column":6}},"typeCondition":null,"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 21,"column":9}, "end": {"line":23,"column":6}},"selections":[{"kind":"Field","loc":{"start": {"line": 22,"column":7}, "end": {"line":22,"column":9}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 22,"column":7}, "end": {"line":22,"column":9}},"value":"id"},"arguments":null,"directives":null,"selectionSet":null}]}}]}}]}},{"kind":"OperationDefinition","loc":{"start": {"line": 27,"column":1}, "end": {"line":33,"column":2}},"operation":"mutation","name":{"kind":"Name","loc":{"start": {"line": 27,"column":10}, "end": {"line":27,"column":19}},"value":"likeStory"},"variableDefinitions":null,"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 27,"column":20}, "end": {"line":33,"column":2}},"selections":[{"kind":"Field","loc":{"start": {"line": 28,"column":3}, "end": {"line":32,"column":4}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 28,"column":3}, "end": {"line":28,"column":7}},"value":"like"},"arguments":[{"kind":"Argument","loc":{"start": {"line": 28,"column":8}, "end": {"line":28,"column":18}},"name":{"kind":"Name","loc":{"start": {"line": 28,"column":8}, "end": {"line":28,"column":13}},"value":"story"},"value":{"kind":"IntValue","loc":{"start": {"line": 28,"column":15}, "end": {"line":28,"column":18}},"value":"123"}}],"directives":[{"kind":"Directive","loc":{"start": {"line": 28,"column":20}, "end": {"line":28,"column":26}},"name":{"kind":"Name","loc":{"start": {"line": 28,"column":21}, "end": {"line":28,"column":26}},"value":"defer"},"arguments":null}],"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 28,"column":27}, "end": {"line":32,"column":4}},"selections":[{"kind":"Field","loc":{"start": {"line": 29,"column":5}, "end": {"line":31,"column":6}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 29,"column":5}, "end": {"line":29,"column":10}},"value":"story"},"arguments":null,"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 29,"column":11}, "end": {"line":31,"column":6}},"selections":[{"kind":"Field","loc":{"start": {"line": 30,"column":7}, "end": {"line":30,"column":9}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 30,"column":7}, "end": {"line":30,"column":9}},"value":"id"},"arguments":null,"directives":null,"selectionSet":null}]}}]}}]}},{"kind":"OperationDefinition","loc":{"start": {"line": 35,"column":1}, "end": {"line":46,"column":2}},"operation":"subscription","name":{"kind":"Name","loc":{"start": {"line": 35,"column":14}, "end": {"line":35,"column":35}},"value":"StoryLikeSubscription"},"variableDefinitions":[{"kind":"VariableDefinition","loc":{"start": {"line": 35,"column":36}, "end": {"line":35,"column":67}},"variable":{"kind":"Variable","loc":{"start": {"line": 35,"column":36}, "end": {"line":35,"column":42}},"name":{"kind":"Name","loc":{"start": {"line": 35,"column":36}, "end": {"line":35,"column":42}},"value":"input"}},"type":{"kind":"NamedType","loc":{"start": {"line": 35,"column":44}, "end": {"line":35,"column":67}},"name":{"kind":"Name","loc":{"start": {"line": 35,"column":44}, "end": {"line":35,"column":67}},"value":"StoryLikeSubscribeInput"}},"defaultValue":null}],"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 35,"column":69}, "end": {"line":46,"column":2}},"selections":[{"kind":"Field","loc":{"start": {"line": 36,"column":3}, "end": {"line":45,"column":4}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 36,"column":3}, "end": {"line":36,"column":21}},"value":"storyLikeSubscribe"},"arguments":[{"kind":"Argument","loc":{"start": {"line": 36,"column":22}, "end": {"line":36,"column":35}},"name":{"kind":"Name","loc":{"start": {"line": 36,"column":22}, "end": {"line":36,"column":27}},"value":"input"},"value":{"kind":"Variable","loc":{"start": {"line": 36,"column":29}, "end": {"line":36,"column":35}},"name":{"kind":"Name","loc":{"start": {"line": 36,"column":29}, "end": {"line":36,"column":35}},"value":"input"}}}],"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 36,"column":37}, "end": {"line":45,"column":4}},"selections":[{"kind":"Field","loc":{"start": {"line": 37,"column":5}, "end": {"line":44,"column":6}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 37,"column":5}, "end": {"line":37,"column":10}},"value":"story"},"arguments":null,"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 37,"column":11}, "end": {"line":44,"column":6}},"selections":[{"kind":"Field","loc":{"start": {"line": 38,"column":7}, "end": {"line":40,"column":8}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 38,"column":7}, "end": {"line":38,"column":13}},"value":"likers"},"arguments":null,"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 38,"column":14}, "end": {"line":40,"column":8}},"selections":[{"kind":"Field","loc":{"start": {"line": 39,"column":9}, "end": {"line":39,"column":14}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 39,"column":9}, "end": {"line":39,"column":14}},"value":"count"},"arguments":null,"directives":null,"selectionSet":null}]}},{"kind":"Field","loc":{"start": {"line": 41,"column":7}, "end": {"line":43,"column":8}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 41,"column":7}, "end": {"line":41,"column":19}},"value":"likeSentence"},"arguments":null,"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 41,"column":20}, "end": {"line":43,"column":8}},"selections":[{"kind":"Field","loc":{"start": {"line": 42,"column":9}, "end": {"line":42,"column":13}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 42,"column":9}, "end": {"line":42,"column":13}},"value":"text"},"arguments":null,"directives":null,"selectionSet":null}]}}]}}]}}]}},{"kind":"FragmentDefinition","loc":{"start": {"line": 48,"column":1}, "end": {"line":50,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 48,"column":10}, "end": {"line":48,"column":14}},"value":"frag"},"typeCondition":{"kind":"NamedType","loc":{"start": {"line": 48,"column":18}, "end": {"line":48,"column":24}},"name":{"kind":"Name","loc":{"start": {"line": 48,"column":18}, "end": {"line":48,"column":24}},"value":"Friend"}},"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 48,"column":25}, "end": {"line":50,"column":2}},"selections":[{"kind":"Field","loc":{"start": {"line": 49,"column":3}, "end": {"line":49,"column":98}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 49,"column":3}, "end": {"line":49,"column":6}},"value":"foo"},"arguments":[{"kind":"Argument","loc":{"start": {"line": 49,"column":7}, "end": {"line":49,"column":18}},"name":{"kind":"Name","loc":{"start": {"line": 49,"column":7}, "end": {"line":49,"column":11}},"value":"size"},"value":{"kind":"Variable","loc":{"start": {"line": 49,"column":13}, "end": {"line":49,"column":18}},"name":{"kind":"Name","loc":{"start": {"line": 49,"column":13}, "end": {"line":49,"column":18}},"value":"size"}}},{"kind":"Argument","loc":{"start": {"line": 49,"column":20}, "end": {"line":49,"column":27}},"name":{"kind":"Name","loc":{"start": {"line": 49,"column":20}, "end": {"line":49,"column":23}},"value":"bar"},"value":{"kind":"Variable","loc":{"start": {"line": 49,"column":25}, "end": {"line":49,"column":27}},"name":{"kind":"Name","loc":{"start": {"line": 49,"column":25}, "end": {"line":49,"column":27}},"value":"b"}}},{"kind":"Argument","loc":{"start": {"line": 49,"column":29}, "end": {"line":49,"column":97}},"name":{"kind":"Name","loc":{"start": {"line": 49,"column":29}, "end": {"line":49,"column":32}},"value":"obj"},"value":{"kind":"ObjectValue","loc":{"start": {"line": 49,"column":34}, "end": {"line":49,"column":97}},"fields":[{"kind":"ObjectField","loc":{"start": {"line": 49,"column":35}, "end": {"line":49,"column":47}},"name":{"kind":"Name","loc":{"start": {"line": 49,"column":35}, "end": {"line":49,"column":38}},"value":"key"},"value":{"kind":"StringValue","loc":{"start": {"line": 49,"column":40}, "end": {"line":49,"column":47}},"value":"value"}},{"kind":"ObjectField","loc":{"start": {"line": 49,"column":49}, "end": {"line":49,"column":96}},"name":{"kind":"Name","loc":{"start": {"line": 49,"column":49}, "end": {"line":49,"column":54}},"value":"block"},"value":{"kind":"StringValue","loc":{"start": {"line": 49,"column":56}, "end": {"line":49,"column":96}},"value":"block string uses \"\"\""}}]}}],"directives":null,"selectionSet":null}]}},{"kind":"OperationDefinition","loc":{"start": {"line": 52,"column":1}, "end": {"line":55,"column":2}},"operation":"query","name":null,"variableDefinitions":null,"directives":null,"selectionSet":{"kind":"SelectionSet","loc":{"start": {"line": 52,"column":1}, "end": {"line":55,"column":2}},"selections":[{"kind":"Field","loc":{"start": {"line": 53,"column":3}, "end": {"line":53,"column":54}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 53,"column":3}, "end": {"line":53,"column":10}},"value":"unnamed"},"arguments":[{"kind":"Argument","loc":{"start": {"line": 53,"column":11}, "end": {"line":53,"column":23}},"name":{"kind":"Name","loc":{"start": {"line": 53,"column":11}, "end": {"line":53,"column":17}},"value":"truthy"},"value":{"kind":"BooleanValue","loc":{"start": {"line": 53,"column":19}, "end": {"line":53,"column":23}},"value":true}},{"kind":"Argument","loc":{"start": {"line": 53,"column":25}, "end": {"line":53,"column":38}},"name":{"kind":"Name","loc":{"start": {"line": 53,"column":25}, "end": {"line":53,"column":31}},"value":"falsey"},"value":{"kind":"BooleanValue","loc":{"start": {"line": 53,"column":33}, "end": {"line":53,"column":38}},"value":false}},{"kind":"Argument","loc":{"start": {"line": 53,"column":40}, "end": {"line":53,"column":53}},"name":{"kind":"Name","loc":{"start": {"line": 53,"column":40}, "end": {"line":53,"column":47}},"value":"nullish"},"value":{"kind":"NullValue","loc":{"start": {"line": 53,"column":49}, "end": {"line":53,"column":53}}}}],"directives":null,"selectionSet":null},{"kind":"Field","loc":{"start": {"line": 54,"column":3}, "end": {"line":54,"column":8}},"alias":null,"name":{"kind":"Name","loc":{"start": {"line": 54,"column":3}, "end": {"line":54,"column":8}},"value":"query"},"arguments":null,"directives":null,"selectionSet":null}]}}]} \ No newline at end of file diff --git a/external/graphqlparser/test/schema-kitchen-sink.graphql b/external/graphqlparser/test/schema-kitchen-sink.graphql new file mode 100644 index 0000000..c1d495b --- /dev/null +++ b/external/graphqlparser/test/schema-kitchen-sink.graphql @@ -0,0 +1,78 @@ +# Copyright 2019-present, GraphQL Foundation +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# (this line is padding to maintain test line numbers) + +schema { + query: QueryType + mutation: MutationType +} + +type Foo implements Bar { + one: Type + two(argument: InputType!): Type + three(argument: InputType, other: String): Int + four(argument: String = "string"): String + five(argument: [String] = ["string", "string"]): String + six(argument: InputType = {key: "value"}): Type + seven(argument: Int = null): Type +} + +type AnnotatedObject @onObject(arg: "value") { + annotatedField(arg: Type = "default" @onArg): Type @onField +} + +interface Bar { + one: Type + four(argument: String = "string"): String +} + +interface AnnotatedInterface @onInterface { + annotatedField(arg: Type @onArg): Type @onField +} + +union Feed = Story | Article | Advert + +union AnnotatedUnion @onUnion = A | B + +scalar CustomScalar + +scalar AnnotatedScalar @onScalar + +enum Site { + DESKTOP + MOBILE +} + +enum AnnotatedEnum @onEnum { + ANNOTATED_VALUE @onEnumValue + OTHER_VALUE +} + +input InputType { + key: String! + answer: Int = 42 +} + +input AnnotatedInput @onInputObjectType { + annotatedField: Type @onField +} + +extend type Foo { + seven(argument: [String]): Type +} + +# NOTE: out-of-spec test cases commented out until the spec is clarified; see +# https://github.com/graphql/graphql-js/issues/650 . +# extend type Foo @onType {} + +#type NoFields {} + +directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT + +directive @include(if: Boolean!) + on FIELD + | FRAGMENT_SPREAD + | INLINE_FRAGMENT diff --git a/external/graphqlparser/test/schema-kitchen-sink.json b/external/graphqlparser/test/schema-kitchen-sink.json new file mode 100644 index 0000000..ccdc8d4 --- /dev/null +++ b/external/graphqlparser/test/schema-kitchen-sink.json @@ -0,0 +1 @@ +{"kind":"Document","loc":{"start": {"line": 8,"column":1}, "end": {"line":78,"column":21}},"definitions":[{"kind":"SchemaDefinition","loc":{"start": {"line": 8,"column":1}, "end": {"line":11,"column":2}},"directives":null,"operationTypes":[{"kind":"OperationTypeDefinition","loc":{"start": {"line": 9,"column":3}, "end": {"line":9,"column":19}},"operation":"query","type":{"kind":"NamedType","loc":{"start": {"line": 9,"column":10}, "end": {"line":9,"column":19}},"name":{"kind":"Name","loc":{"start": {"line": 9,"column":10}, "end": {"line":9,"column":19}},"value":"QueryType"}}},{"kind":"OperationTypeDefinition","loc":{"start": {"line": 10,"column":3}, "end": {"line":10,"column":25}},"operation":"mutation","type":{"kind":"NamedType","loc":{"start": {"line": 10,"column":13}, "end": {"line":10,"column":25}},"name":{"kind":"Name","loc":{"start": {"line": 10,"column":13}, "end": {"line":10,"column":25}},"value":"MutationType"}}}]},{"kind":"ObjectTypeDefinition","loc":{"start": {"line": 13,"column":1}, "end": {"line":21,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 13,"column":6}, "end": {"line":13,"column":9}},"value":"Foo"},"interfaces":[{"kind":"NamedType","loc":{"start": {"line": 13,"column":21}, "end": {"line":13,"column":24}},"name":{"kind":"Name","loc":{"start": {"line": 13,"column":21}, "end": {"line":13,"column":24}},"value":"Bar"}}],"directives":null,"fields":[{"kind":"FieldDefinition","loc":{"start": {"line": 14,"column":3}, "end": {"line":14,"column":12}},"name":{"kind":"Name","loc":{"start": {"line": 14,"column":3}, "end": {"line":14,"column":6}},"value":"one"},"arguments":null,"type":{"kind":"NamedType","loc":{"start": {"line": 14,"column":8}, "end": {"line":14,"column":12}},"name":{"kind":"Name","loc":{"start": {"line": 14,"column":8}, "end": {"line":14,"column":12}},"value":"Type"}},"directives":null},{"kind":"FieldDefinition","loc":{"start": {"line": 15,"column":3}, "end": {"line":15,"column":34}},"name":{"kind":"Name","loc":{"start": {"line": 15,"column":3}, "end": {"line":15,"column":6}},"value":"two"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 15,"column":7}, "end": {"line":15,"column":27}},"name":{"kind":"Name","loc":{"start": {"line": 15,"column":7}, "end": {"line":15,"column":15}},"value":"argument"},"type":{"kind":"NonNullType","loc":{"start": {"line": 15,"column":17}, "end": {"line":15,"column":27}},"type":{"kind":"NamedType","loc":{"start": {"line": 15,"column":17}, "end": {"line":15,"column":26}},"name":{"kind":"Name","loc":{"start": {"line": 15,"column":17}, "end": {"line":15,"column":26}},"value":"InputType"}}},"defaultValue":null,"directives":null}],"type":{"kind":"NamedType","loc":{"start": {"line": 15,"column":30}, "end": {"line":15,"column":34}},"name":{"kind":"Name","loc":{"start": {"line": 15,"column":30}, "end": {"line":15,"column":34}},"value":"Type"}},"directives":null},{"kind":"FieldDefinition","loc":{"start": {"line": 16,"column":3}, "end": {"line":16,"column":49}},"name":{"kind":"Name","loc":{"start": {"line": 16,"column":3}, "end": {"line":16,"column":8}},"value":"three"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 16,"column":9}, "end": {"line":16,"column":28}},"name":{"kind":"Name","loc":{"start": {"line": 16,"column":9}, "end": {"line":16,"column":17}},"value":"argument"},"type":{"kind":"NamedType","loc":{"start": {"line": 16,"column":19}, "end": {"line":16,"column":28}},"name":{"kind":"Name","loc":{"start": {"line": 16,"column":19}, "end": {"line":16,"column":28}},"value":"InputType"}},"defaultValue":null,"directives":null},{"kind":"InputValueDefinition","loc":{"start": {"line": 16,"column":30}, "end": {"line":16,"column":43}},"name":{"kind":"Name","loc":{"start": {"line": 16,"column":30}, "end": {"line":16,"column":35}},"value":"other"},"type":{"kind":"NamedType","loc":{"start": {"line": 16,"column":37}, "end": {"line":16,"column":43}},"name":{"kind":"Name","loc":{"start": {"line": 16,"column":37}, "end": {"line":16,"column":43}},"value":"String"}},"defaultValue":null,"directives":null}],"type":{"kind":"NamedType","loc":{"start": {"line": 16,"column":46}, "end": {"line":16,"column":49}},"name":{"kind":"Name","loc":{"start": {"line": 16,"column":46}, "end": {"line":16,"column":49}},"value":"Int"}},"directives":null},{"kind":"FieldDefinition","loc":{"start": {"line": 17,"column":3}, "end": {"line":17,"column":44}},"name":{"kind":"Name","loc":{"start": {"line": 17,"column":3}, "end": {"line":17,"column":7}},"value":"four"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 17,"column":8}, "end": {"line":17,"column":35}},"name":{"kind":"Name","loc":{"start": {"line": 17,"column":8}, "end": {"line":17,"column":16}},"value":"argument"},"type":{"kind":"NamedType","loc":{"start": {"line": 17,"column":18}, "end": {"line":17,"column":24}},"name":{"kind":"Name","loc":{"start": {"line": 17,"column":18}, "end": {"line":17,"column":24}},"value":"String"}},"defaultValue":{"kind":"StringValue","loc":{"start": {"line": 17,"column":27}, "end": {"line":17,"column":35}},"value":"string"},"directives":null}],"type":{"kind":"NamedType","loc":{"start": {"line": 17,"column":38}, "end": {"line":17,"column":44}},"name":{"kind":"Name","loc":{"start": {"line": 17,"column":38}, "end": {"line":17,"column":44}},"value":"String"}},"directives":null},{"kind":"FieldDefinition","loc":{"start": {"line": 18,"column":3}, "end": {"line":18,"column":58}},"name":{"kind":"Name","loc":{"start": {"line": 18,"column":3}, "end": {"line":18,"column":7}},"value":"five"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 18,"column":8}, "end": {"line":18,"column":49}},"name":{"kind":"Name","loc":{"start": {"line": 18,"column":8}, "end": {"line":18,"column":16}},"value":"argument"},"type":{"kind":"ListType","loc":{"start": {"line": 18,"column":18}, "end": {"line":18,"column":26}},"type":{"kind":"NamedType","loc":{"start": {"line": 18,"column":19}, "end": {"line":18,"column":25}},"name":{"kind":"Name","loc":{"start": {"line": 18,"column":19}, "end": {"line":18,"column":25}},"value":"String"}}},"defaultValue":{"kind":"ListValue","loc":{"start": {"line": 18,"column":29}, "end": {"line":18,"column":49}},"values":[{"kind":"StringValue","loc":{"start": {"line": 18,"column":30}, "end": {"line":18,"column":38}},"value":"string"},{"kind":"StringValue","loc":{"start": {"line": 18,"column":40}, "end": {"line":18,"column":48}},"value":"string"}]},"directives":null}],"type":{"kind":"NamedType","loc":{"start": {"line": 18,"column":52}, "end": {"line":18,"column":58}},"name":{"kind":"Name","loc":{"start": {"line": 18,"column":52}, "end": {"line":18,"column":58}},"value":"String"}},"directives":null},{"kind":"FieldDefinition","loc":{"start": {"line": 19,"column":3}, "end": {"line":19,"column":50}},"name":{"kind":"Name","loc":{"start": {"line": 19,"column":3}, "end": {"line":19,"column":6}},"value":"six"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 19,"column":7}, "end": {"line":19,"column":43}},"name":{"kind":"Name","loc":{"start": {"line": 19,"column":7}, "end": {"line":19,"column":15}},"value":"argument"},"type":{"kind":"NamedType","loc":{"start": {"line": 19,"column":17}, "end": {"line":19,"column":26}},"name":{"kind":"Name","loc":{"start": {"line": 19,"column":17}, "end": {"line":19,"column":26}},"value":"InputType"}},"defaultValue":{"kind":"ObjectValue","loc":{"start": {"line": 19,"column":29}, "end": {"line":19,"column":43}},"fields":[{"kind":"ObjectField","loc":{"start": {"line": 19,"column":30}, "end": {"line":19,"column":42}},"name":{"kind":"Name","loc":{"start": {"line": 19,"column":30}, "end": {"line":19,"column":33}},"value":"key"},"value":{"kind":"StringValue","loc":{"start": {"line": 19,"column":35}, "end": {"line":19,"column":42}},"value":"value"}}]},"directives":null}],"type":{"kind":"NamedType","loc":{"start": {"line": 19,"column":46}, "end": {"line":19,"column":50}},"name":{"kind":"Name","loc":{"start": {"line": 19,"column":46}, "end": {"line":19,"column":50}},"value":"Type"}},"directives":null},{"kind":"FieldDefinition","loc":{"start": {"line": 20,"column":3}, "end": {"line":20,"column":36}},"name":{"kind":"Name","loc":{"start": {"line": 20,"column":3}, "end": {"line":20,"column":8}},"value":"seven"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 20,"column":9}, "end": {"line":20,"column":29}},"name":{"kind":"Name","loc":{"start": {"line": 20,"column":9}, "end": {"line":20,"column":17}},"value":"argument"},"type":{"kind":"NamedType","loc":{"start": {"line": 20,"column":19}, "end": {"line":20,"column":22}},"name":{"kind":"Name","loc":{"start": {"line": 20,"column":19}, "end": {"line":20,"column":22}},"value":"Int"}},"defaultValue":{"kind":"NullValue","loc":{"start": {"line": 20,"column":25}, "end": {"line":20,"column":29}}},"directives":null}],"type":{"kind":"NamedType","loc":{"start": {"line": 20,"column":32}, "end": {"line":20,"column":36}},"name":{"kind":"Name","loc":{"start": {"line": 20,"column":32}, "end": {"line":20,"column":36}},"value":"Type"}},"directives":null}]},{"kind":"ObjectTypeDefinition","loc":{"start": {"line": 23,"column":1}, "end": {"line":25,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 23,"column":6}, "end": {"line":23,"column":21}},"value":"AnnotatedObject"},"interfaces":null,"directives":[{"kind":"Directive","loc":{"start": {"line": 23,"column":22}, "end": {"line":23,"column":45}},"name":{"kind":"Name","loc":{"start": {"line": 23,"column":23}, "end": {"line":23,"column":31}},"value":"onObject"},"arguments":[{"kind":"Argument","loc":{"start": {"line": 23,"column":32}, "end": {"line":23,"column":44}},"name":{"kind":"Name","loc":{"start": {"line": 23,"column":32}, "end": {"line":23,"column":35}},"value":"arg"},"value":{"kind":"StringValue","loc":{"start": {"line": 23,"column":37}, "end": {"line":23,"column":44}},"value":"value"}}]}],"fields":[{"kind":"FieldDefinition","loc":{"start": {"line": 24,"column":3}, "end": {"line":24,"column":62}},"name":{"kind":"Name","loc":{"start": {"line": 24,"column":3}, "end": {"line":24,"column":17}},"value":"annotatedField"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 24,"column":18}, "end": {"line":24,"column":46}},"name":{"kind":"Name","loc":{"start": {"line": 24,"column":18}, "end": {"line":24,"column":21}},"value":"arg"},"type":{"kind":"NamedType","loc":{"start": {"line": 24,"column":23}, "end": {"line":24,"column":27}},"name":{"kind":"Name","loc":{"start": {"line": 24,"column":23}, "end": {"line":24,"column":27}},"value":"Type"}},"defaultValue":{"kind":"StringValue","loc":{"start": {"line": 24,"column":30}, "end": {"line":24,"column":39}},"value":"default"},"directives":[{"kind":"Directive","loc":{"start": {"line": 24,"column":40}, "end": {"line":24,"column":46}},"name":{"kind":"Name","loc":{"start": {"line": 24,"column":41}, "end": {"line":24,"column":46}},"value":"onArg"},"arguments":null}]}],"type":{"kind":"NamedType","loc":{"start": {"line": 24,"column":49}, "end": {"line":24,"column":53}},"name":{"kind":"Name","loc":{"start": {"line": 24,"column":49}, "end": {"line":24,"column":53}},"value":"Type"}},"directives":[{"kind":"Directive","loc":{"start": {"line": 24,"column":54}, "end": {"line":24,"column":62}},"name":{"kind":"Name","loc":{"start": {"line": 24,"column":55}, "end": {"line":24,"column":62}},"value":"onField"},"arguments":null}]}]},{"kind":"InterfaceTypeDefinition","loc":{"start": {"line": 27,"column":1}, "end": {"line":30,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 27,"column":11}, "end": {"line":27,"column":14}},"value":"Bar"},"directives":null,"fields":[{"kind":"FieldDefinition","loc":{"start": {"line": 28,"column":3}, "end": {"line":28,"column":12}},"name":{"kind":"Name","loc":{"start": {"line": 28,"column":3}, "end": {"line":28,"column":6}},"value":"one"},"arguments":null,"type":{"kind":"NamedType","loc":{"start": {"line": 28,"column":8}, "end": {"line":28,"column":12}},"name":{"kind":"Name","loc":{"start": {"line": 28,"column":8}, "end": {"line":28,"column":12}},"value":"Type"}},"directives":null},{"kind":"FieldDefinition","loc":{"start": {"line": 29,"column":3}, "end": {"line":29,"column":44}},"name":{"kind":"Name","loc":{"start": {"line": 29,"column":3}, "end": {"line":29,"column":7}},"value":"four"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 29,"column":8}, "end": {"line":29,"column":35}},"name":{"kind":"Name","loc":{"start": {"line": 29,"column":8}, "end": {"line":29,"column":16}},"value":"argument"},"type":{"kind":"NamedType","loc":{"start": {"line": 29,"column":18}, "end": {"line":29,"column":24}},"name":{"kind":"Name","loc":{"start": {"line": 29,"column":18}, "end": {"line":29,"column":24}},"value":"String"}},"defaultValue":{"kind":"StringValue","loc":{"start": {"line": 29,"column":27}, "end": {"line":29,"column":35}},"value":"string"},"directives":null}],"type":{"kind":"NamedType","loc":{"start": {"line": 29,"column":38}, "end": {"line":29,"column":44}},"name":{"kind":"Name","loc":{"start": {"line": 29,"column":38}, "end": {"line":29,"column":44}},"value":"String"}},"directives":null}]},{"kind":"InterfaceTypeDefinition","loc":{"start": {"line": 32,"column":1}, "end": {"line":34,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 32,"column":11}, "end": {"line":32,"column":29}},"value":"AnnotatedInterface"},"directives":[{"kind":"Directive","loc":{"start": {"line": 32,"column":30}, "end": {"line":32,"column":42}},"name":{"kind":"Name","loc":{"start": {"line": 32,"column":31}, "end": {"line":32,"column":42}},"value":"onInterface"},"arguments":null}],"fields":[{"kind":"FieldDefinition","loc":{"start": {"line": 33,"column":3}, "end": {"line":33,"column":50}},"name":{"kind":"Name","loc":{"start": {"line": 33,"column":3}, "end": {"line":33,"column":17}},"value":"annotatedField"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 33,"column":18}, "end": {"line":33,"column":34}},"name":{"kind":"Name","loc":{"start": {"line": 33,"column":18}, "end": {"line":33,"column":21}},"value":"arg"},"type":{"kind":"NamedType","loc":{"start": {"line": 33,"column":23}, "end": {"line":33,"column":27}},"name":{"kind":"Name","loc":{"start": {"line": 33,"column":23}, "end": {"line":33,"column":27}},"value":"Type"}},"defaultValue":null,"directives":[{"kind":"Directive","loc":{"start": {"line": 33,"column":28}, "end": {"line":33,"column":34}},"name":{"kind":"Name","loc":{"start": {"line": 33,"column":29}, "end": {"line":33,"column":34}},"value":"onArg"},"arguments":null}]}],"type":{"kind":"NamedType","loc":{"start": {"line": 33,"column":37}, "end": {"line":33,"column":41}},"name":{"kind":"Name","loc":{"start": {"line": 33,"column":37}, "end": {"line":33,"column":41}},"value":"Type"}},"directives":[{"kind":"Directive","loc":{"start": {"line": 33,"column":42}, "end": {"line":33,"column":50}},"name":{"kind":"Name","loc":{"start": {"line": 33,"column":43}, "end": {"line":33,"column":50}},"value":"onField"},"arguments":null}]}]},{"kind":"UnionTypeDefinition","loc":{"start": {"line": 36,"column":1}, "end": {"line":36,"column":38}},"name":{"kind":"Name","loc":{"start": {"line": 36,"column":7}, "end": {"line":36,"column":11}},"value":"Feed"},"directives":null,"types":[{"kind":"NamedType","loc":{"start": {"line": 36,"column":14}, "end": {"line":36,"column":19}},"name":{"kind":"Name","loc":{"start": {"line": 36,"column":14}, "end": {"line":36,"column":19}},"value":"Story"}},{"kind":"NamedType","loc":{"start": {"line": 36,"column":22}, "end": {"line":36,"column":29}},"name":{"kind":"Name","loc":{"start": {"line": 36,"column":22}, "end": {"line":36,"column":29}},"value":"Article"}},{"kind":"NamedType","loc":{"start": {"line": 36,"column":32}, "end": {"line":36,"column":38}},"name":{"kind":"Name","loc":{"start": {"line": 36,"column":32}, "end": {"line":36,"column":38}},"value":"Advert"}}]},{"kind":"UnionTypeDefinition","loc":{"start": {"line": 38,"column":1}, "end": {"line":38,"column":38}},"name":{"kind":"Name","loc":{"start": {"line": 38,"column":7}, "end": {"line":38,"column":21}},"value":"AnnotatedUnion"},"directives":[{"kind":"Directive","loc":{"start": {"line": 38,"column":22}, "end": {"line":38,"column":30}},"name":{"kind":"Name","loc":{"start": {"line": 38,"column":23}, "end": {"line":38,"column":30}},"value":"onUnion"},"arguments":null}],"types":[{"kind":"NamedType","loc":{"start": {"line": 38,"column":33}, "end": {"line":38,"column":34}},"name":{"kind":"Name","loc":{"start": {"line": 38,"column":33}, "end": {"line":38,"column":34}},"value":"A"}},{"kind":"NamedType","loc":{"start": {"line": 38,"column":37}, "end": {"line":38,"column":38}},"name":{"kind":"Name","loc":{"start": {"line": 38,"column":37}, "end": {"line":38,"column":38}},"value":"B"}}]},{"kind":"ScalarTypeDefinition","loc":{"start": {"line": 40,"column":1}, "end": {"line":40,"column":20}},"name":{"kind":"Name","loc":{"start": {"line": 40,"column":8}, "end": {"line":40,"column":20}},"value":"CustomScalar"},"directives":null},{"kind":"ScalarTypeDefinition","loc":{"start": {"line": 42,"column":1}, "end": {"line":42,"column":33}},"name":{"kind":"Name","loc":{"start": {"line": 42,"column":8}, "end": {"line":42,"column":23}},"value":"AnnotatedScalar"},"directives":[{"kind":"Directive","loc":{"start": {"line": 42,"column":24}, "end": {"line":42,"column":33}},"name":{"kind":"Name","loc":{"start": {"line": 42,"column":25}, "end": {"line":42,"column":33}},"value":"onScalar"},"arguments":null}]},{"kind":"EnumTypeDefinition","loc":{"start": {"line": 44,"column":1}, "end": {"line":47,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 44,"column":6}, "end": {"line":44,"column":10}},"value":"Site"},"directives":null,"values":[{"kind":"EnumValueDefinition","loc":{"start": {"line": 45,"column":3}, "end": {"line":45,"column":10}},"name":{"kind":"Name","loc":{"start": {"line": 45,"column":3}, "end": {"line":45,"column":10}},"value":"DESKTOP"},"directives":null},{"kind":"EnumValueDefinition","loc":{"start": {"line": 46,"column":3}, "end": {"line":46,"column":9}},"name":{"kind":"Name","loc":{"start": {"line": 46,"column":3}, "end": {"line":46,"column":9}},"value":"MOBILE"},"directives":null}]},{"kind":"EnumTypeDefinition","loc":{"start": {"line": 49,"column":1}, "end": {"line":52,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 49,"column":6}, "end": {"line":49,"column":19}},"value":"AnnotatedEnum"},"directives":[{"kind":"Directive","loc":{"start": {"line": 49,"column":20}, "end": {"line":49,"column":27}},"name":{"kind":"Name","loc":{"start": {"line": 49,"column":21}, "end": {"line":49,"column":27}},"value":"onEnum"},"arguments":null}],"values":[{"kind":"EnumValueDefinition","loc":{"start": {"line": 50,"column":3}, "end": {"line":50,"column":31}},"name":{"kind":"Name","loc":{"start": {"line": 50,"column":3}, "end": {"line":50,"column":18}},"value":"ANNOTATED_VALUE"},"directives":[{"kind":"Directive","loc":{"start": {"line": 50,"column":19}, "end": {"line":50,"column":31}},"name":{"kind":"Name","loc":{"start": {"line": 50,"column":20}, "end": {"line":50,"column":31}},"value":"onEnumValue"},"arguments":null}]},{"kind":"EnumValueDefinition","loc":{"start": {"line": 51,"column":3}, "end": {"line":51,"column":14}},"name":{"kind":"Name","loc":{"start": {"line": 51,"column":3}, "end": {"line":51,"column":14}},"value":"OTHER_VALUE"},"directives":null}]},{"kind":"InputObjectTypeDefinition","loc":{"start": {"line": 54,"column":1}, "end": {"line":57,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 54,"column":7}, "end": {"line":54,"column":16}},"value":"InputType"},"directives":null,"fields":[{"kind":"InputValueDefinition","loc":{"start": {"line": 55,"column":3}, "end": {"line":55,"column":15}},"name":{"kind":"Name","loc":{"start": {"line": 55,"column":3}, "end": {"line":55,"column":6}},"value":"key"},"type":{"kind":"NonNullType","loc":{"start": {"line": 55,"column":8}, "end": {"line":55,"column":15}},"type":{"kind":"NamedType","loc":{"start": {"line": 55,"column":8}, "end": {"line":55,"column":14}},"name":{"kind":"Name","loc":{"start": {"line": 55,"column":8}, "end": {"line":55,"column":14}},"value":"String"}}},"defaultValue":null,"directives":null},{"kind":"InputValueDefinition","loc":{"start": {"line": 56,"column":3}, "end": {"line":56,"column":19}},"name":{"kind":"Name","loc":{"start": {"line": 56,"column":3}, "end": {"line":56,"column":9}},"value":"answer"},"type":{"kind":"NamedType","loc":{"start": {"line": 56,"column":11}, "end": {"line":56,"column":14}},"name":{"kind":"Name","loc":{"start": {"line": 56,"column":11}, "end": {"line":56,"column":14}},"value":"Int"}},"defaultValue":{"kind":"IntValue","loc":{"start": {"line": 56,"column":17}, "end": {"line":56,"column":19}},"value":"42"},"directives":null}]},{"kind":"InputObjectTypeDefinition","loc":{"start": {"line": 59,"column":1}, "end": {"line":61,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 59,"column":7}, "end": {"line":59,"column":21}},"value":"AnnotatedInput"},"directives":[{"kind":"Directive","loc":{"start": {"line": 59,"column":22}, "end": {"line":59,"column":40}},"name":{"kind":"Name","loc":{"start": {"line": 59,"column":23}, "end": {"line":59,"column":40}},"value":"onInputObjectType"},"arguments":null}],"fields":[{"kind":"InputValueDefinition","loc":{"start": {"line": 60,"column":3}, "end": {"line":60,"column":32}},"name":{"kind":"Name","loc":{"start": {"line": 60,"column":3}, "end": {"line":60,"column":17}},"value":"annotatedField"},"type":{"kind":"NamedType","loc":{"start": {"line": 60,"column":19}, "end": {"line":60,"column":23}},"name":{"kind":"Name","loc":{"start": {"line": 60,"column":19}, "end": {"line":60,"column":23}},"value":"Type"}},"defaultValue":null,"directives":[{"kind":"Directive","loc":{"start": {"line": 60,"column":24}, "end": {"line":60,"column":32}},"name":{"kind":"Name","loc":{"start": {"line": 60,"column":25}, "end": {"line":60,"column":32}},"value":"onField"},"arguments":null}]}]},{"kind":"TypeExtensionDefinition","loc":{"start": {"line": 63,"column":1}, "end": {"line":65,"column":2}},"definition":{"kind":"ObjectTypeDefinition","loc":{"start": {"line": 63,"column":8}, "end": {"line":65,"column":2}},"name":{"kind":"Name","loc":{"start": {"line": 63,"column":13}, "end": {"line":63,"column":16}},"value":"Foo"},"interfaces":null,"directives":null,"fields":[{"kind":"FieldDefinition","loc":{"start": {"line": 64,"column":3}, "end": {"line":64,"column":34}},"name":{"kind":"Name","loc":{"start": {"line": 64,"column":3}, "end": {"line":64,"column":8}},"value":"seven"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 64,"column":9}, "end": {"line":64,"column":27}},"name":{"kind":"Name","loc":{"start": {"line": 64,"column":9}, "end": {"line":64,"column":17}},"value":"argument"},"type":{"kind":"ListType","loc":{"start": {"line": 64,"column":19}, "end": {"line":64,"column":27}},"type":{"kind":"NamedType","loc":{"start": {"line": 64,"column":20}, "end": {"line":64,"column":26}},"name":{"kind":"Name","loc":{"start": {"line": 64,"column":20}, "end": {"line":64,"column":26}},"value":"String"}}},"defaultValue":null,"directives":null}],"type":{"kind":"NamedType","loc":{"start": {"line": 64,"column":30}, "end": {"line":64,"column":34}},"name":{"kind":"Name","loc":{"start": {"line": 64,"column":30}, "end": {"line":64,"column":34}},"value":"Type"}},"directives":null}]}},{"kind":"DirectiveDefinition","loc":{"start": {"line": 73,"column":1}, "end": {"line":73,"column":75}},"name":{"kind":"Name","loc":{"start": {"line": 73,"column":12}, "end": {"line":73,"column":16}},"value":"skip"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 73,"column":17}, "end": {"line":73,"column":29}},"name":{"kind":"Name","loc":{"start": {"line": 73,"column":17}, "end": {"line":73,"column":19}},"value":"if"},"type":{"kind":"NonNullType","loc":{"start": {"line": 73,"column":21}, "end": {"line":73,"column":29}},"type":{"kind":"NamedType","loc":{"start": {"line": 73,"column":21}, "end": {"line":73,"column":28}},"name":{"kind":"Name","loc":{"start": {"line": 73,"column":21}, "end": {"line":73,"column":28}},"value":"Boolean"}}},"defaultValue":null,"directives":null}],"locations":[{"kind":"Name","loc":{"start": {"line": 73,"column":34}, "end": {"line":73,"column":39}},"value":"FIELD"},{"kind":"Name","loc":{"start": {"line": 73,"column":42}, "end": {"line":73,"column":57}},"value":"FRAGMENT_SPREAD"},{"kind":"Name","loc":{"start": {"line": 73,"column":60}, "end": {"line":73,"column":75}},"value":"INLINE_FRAGMENT"}]},{"kind":"DirectiveDefinition","loc":{"start": {"line": 75,"column":1}, "end": {"line":78,"column":21}},"name":{"kind":"Name","loc":{"start": {"line": 75,"column":12}, "end": {"line":75,"column":19}},"value":"include"},"arguments":[{"kind":"InputValueDefinition","loc":{"start": {"line": 75,"column":20}, "end": {"line":75,"column":32}},"name":{"kind":"Name","loc":{"start": {"line": 75,"column":20}, "end": {"line":75,"column":22}},"value":"if"},"type":{"kind":"NonNullType","loc":{"start": {"line": 75,"column":24}, "end": {"line":75,"column":32}},"type":{"kind":"NamedType","loc":{"start": {"line": 75,"column":24}, "end": {"line":75,"column":31}},"name":{"kind":"Name","loc":{"start": {"line": 75,"column":24}, "end": {"line":75,"column":31}},"value":"Boolean"}}},"defaultValue":null,"directives":null}],"locations":[{"kind":"Name","loc":{"start": {"line": 76,"column":6}, "end": {"line":76,"column":11}},"value":"FIELD"},{"kind":"Name","loc":{"start": {"line": 77,"column":6}, "end": {"line":77,"column":21}},"value":"FRAGMENT_SPREAD"},{"kind":"Name","loc":{"start": {"line": 78,"column":6}, "end": {"line":78,"column":21}},"value":"INLINE_FRAGMENT"}]}]} \ No newline at end of file diff --git a/external/graphqlparser/test/valgrind.supp b/external/graphqlparser/test/valgrind.supp new file mode 100644 index 0000000..cc3c44e --- /dev/null +++ b/external/graphqlparser/test/valgrind.supp @@ -0,0 +1,33 @@ +{ + + Memcheck:Cond + fun:strlen + fun:strdup + fun:_ZN2yy17GraphQLParserImpl5parseEv + fun:_ZN8facebook7graphqlL7doParseEPPKcPv + fun:_ZN8facebook7graphql11parseStringEPKcPS2_ + fun:_ZL11expectErrorPKcS0_ + fun:_ZN44ParserTests_TracksLocationAcrossStrings_Test8TestBodyEv + fun:_ZN7testing8internal38HandleSehExceptionsInMethodIfSupportedINS_4TestEvEET0_PT_MS4_FS3_vEPKc + fun:_ZN7testing8internal35HandleExceptionsInMethodIfSupportedINS_4TestEvEET0_PT_MS4_FS3_vEPKc + fun:_ZN7testing4Test3RunEv + fun:_ZN7testing8TestInfo3RunEv + fun:_ZN7testing8TestCase3RunEv +} + +{ + + Memcheck:Cond + fun:__GI_strlen + fun:strdup + fun:_ZN2yy17GraphQLParserImpl5parseEv + fun:_ZN8facebook7graphqlL7doParseEPPKcPv + fun:_ZN8facebook7graphql11parseStringEPKcPS2_ + fun:_ZL11expectErrorPKcS0_ + fun:_ZN44ParserTests_TracksLocationAcrossStrings_Test8TestBodyEv + fun:_ZN7testing8internal38HandleSehExceptionsInMethodIfSupportedINS_4TestEvEET0_PT_MS4_FS3_vEPKc + fun:_ZN7testing8internal35HandleExceptionsInMethodIfSupportedINS_4TestEvEET0_PT_MS4_FS3_vEPKc + fun:_ZN7testing4Test3RunEv + fun:_ZN7testing8TestInfo3RunEv + fun:_ZN7testing8TestCase3RunEv +} diff --git a/nodes/http_transaction_handler/CMakeLists.txt b/nodes/http_transaction_handler/CMakeLists.txt index 56a1db0..12b60bc 100755 --- a/nodes/http_transaction_handler/CMakeLists.txt +++ b/nodes/http_transaction_handler/CMakeLists.txt @@ -9,6 +9,7 @@ target_link_libraries(cp-nano-http-transaction-handler -Wl,--start-group ${COMMON_LIBRARIES} + graphqlparser xml2 pcre2-8 pcre2-posix diff --git a/nodes/orchestration/package/open-appsec-ctl.sh b/nodes/orchestration/package/open-appsec-ctl.sh index 4921e20..317c6ff 100644 --- a/nodes/orchestration/package/open-appsec-ctl.sh +++ b/nodes/orchestration/package/open-appsec-ctl.sh @@ -912,7 +912,7 @@ get_status_content() gsc_temp_old_status=$(echo "$gsc_orch_status" | sed -r "${gsc_line_count},${gsc_line_count}d; "' 1,1d; s/^\s*//g; s/^\n//g; s/\"//g; s/\\n/\n/g; s/\,//g') else - gsc_temp_old_status=$(sed 's/{//g' <${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestrations_status.json | sed 's/}//g' | sed 's/"//g' | sed 's/,//g' | sed -r '/^\s*$/d' | sed -r 's/^ //g') + gsc_temp_old_status=$(sed 's/{//g' <${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestration_status.json | sed 's/}//g' | sed 's/"//g' | sed 's/,//g' | sed -r '/^\s*$/d' | sed -r 's/^ //g') fi echo ${gsc_temp_old_status} @@ -948,8 +948,8 @@ run_status() # Initials - rs rs_temp_old_status=$(echo "$rs_orch_status" | sed -r "${rs_line_count},${rs_line_count}d; "' 1,1d; s/^\s*//g; s/^\n//g; s/\"//g; s/\\n/\n/g; s/\,//g') else - rs_temp_old_status=$(sed 's/{//g' <${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestrations_status.json | sed 's/}//g' | sed 's/"//g' | sed 's/,//g' | sed -r '/^\s*$/d' | sed -r 's/^ //g') - rs_policy_load_time="$(cat /etc/cp/conf/orchestrations_status.json | grep "Last policy update" | sed "s|\"||g" | sed "s|,||g")" + rs_temp_old_status=$(sed 's/{//g' <${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestration_status.json | sed 's/}//g' | sed 's/"//g' | sed 's/,//g' | sed -r '/^\s*$/d' | sed -r 's/^ //g') + rs_policy_load_time="$(cat /etc/cp/conf/orchestration_status.json | grep "Last policy update" | sed "s|\"||g" | sed "s|,||g")" fi if [ -n "$(cat /etc/cp/conf/agent_details.json | grep "hybrid_mode")" ]; then @@ -1221,7 +1221,7 @@ run_ai() # Initials - ra else ra_orch_status=$(curl_func "$(extract_api_port orchestration)"/show-orchestration-status) if ! echo "$ra_orch_status" | grep -q "update status"; then - ra_orch_status=$(cat ${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestrations_status.json) + ra_orch_status=$(cat ${FILESYSTEM_PATH}/$cp_nano_conf_location/orchestration_status.json) fi if [ -n "${ra_orch_status}" ]; then ra_fog_address=$(printf "%s" "$ra_orch_status" | grep "Fog address" | cut -d '"' -f4) @@ -1453,7 +1453,7 @@ set_mode() sed -i "s,\"fog-address\":\"$old_fog\",\"fog-address\":\"$fog_address\"," ${FILESYSTEM_PATH}/${cp_nano_conf_location}/orchestration/orchestration.policy rm ${FILESYSTEM_PATH}/${cp_nano_conf_location}/agent_details.json - rm ${FILESYSTEM_PATH}/${cp_nano_conf_location}/orchestrations_status.json + rm ${FILESYSTEM_PATH}/${cp_nano_conf_location}/orchestration_status.json echo '{}'>${FILESYSTEM_PATH}/${cp_nano_conf_location}/policy.json if [ -f ${FILESYSTEM_PATH}/data/data5.a ]; then diff --git a/nodes/orchestration/package/orchestration_package.sh b/nodes/orchestration/package/orchestration_package.sh index cac5578..58dd640 100755 --- a/nodes/orchestration/package/orchestration_package.sh +++ b/nodes/orchestration/package/orchestration_package.sh @@ -286,7 +286,7 @@ while true; do LOG_FILE_PATH=$1 fi echo "Log files path: ${LOG_FILE_PATH}" - elif [ "$1" = "--arm64_trustbox" ] || [ "$1" = "--arm64_linaro" ] || [ "$1" = "--arm32_rpi" ] || [ "$1" = "--gaia" ] || [ "$1" = "--smb_mrv_v1" ] || [ "$1" = "--x86" ] || [ "$1" = "./orchestration_package.sh" ]; then + elif [ "$1" = "--arm64_trustbox" ] || [ "$1" = "--arm64_linaro" ] || [ "$1" = "--arm32_rpi" ] || [ "$1" = "--gaia" ] || [ "$1" = "--smb_mrv_v1" ] || [ "$1" = "--smb_sve_v2" ] || [ "$1" = "--smb_thx_v3" ] || [ "$1" = "--x86" ] || [ "$1" = "./orchestration_package.sh" ]; then shift continue elif [ "$1" = "--skip_registration" ]; then @@ -323,7 +323,6 @@ if [ "$RUN_MODE" = "install" ] && [ $var_offline_mode = false ]; then fi fi fi - if [ $var_hybrid_mode = true ] && [ -z "$var_fog_address" ]; then var_fog_address="$var_default_gem_fog_address" fi @@ -540,6 +539,7 @@ install_cp_nano_ctl() CP_NANO_CLI="cp-nano-cli.sh" CP_NANO_JSON="cpnano_json" CP_NANO_CTL="cpnano" + OPEN_APPSEC_CTL="open-appsec-ctl" CP_NANO_YQ_LOCATION="./scripts/yq" CP_NANO_YQ="yq" @@ -558,8 +558,8 @@ install_cp_nano_ctl() cp_exec "cp -f $CP_NANO_CLI ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/$CP_NANO_AGENT_CTL" cp_exec "chmod 700 ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/$CP_NANO_AGENT_CTL" if ! [ -f $USR_SBIN_PATH/${CP_NANO_CTL} ]; then - cp_exec "ln -s ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/$CP_NANO_AGENT_CTL $USR_SBIN_PATH/${CP_NANO_CTL}" - cp_exec "ln -s ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/$CP_NANO_AGENT_CTL $USR_SBIN_PATH/open-appsec-ctl" + cp_exec "ln -s ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/$CP_NANO_AGENT_CTL $USR_SBIN_PATH/${CP_NANO_CTL}" + cp_exec "ln -s ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/${OPEN_APPSEC_CTL}.sh $USR_SBIN_PATH/${OPEN_APPSEC_CTL}" fi cp_exec "cp -f ${CP_NANO_DEBUG} ${FILESYSTEM_PATH}/${SCRIPTS_PATH}/${CP_NANO_DEBUG}" @@ -774,7 +774,7 @@ install_orchestration() cp_exec "mkdir -p ${FILESYSTEM_PATH}/${CERTS_PATH}" if [ -n "$var_upgrade_mode" ]; then upgrade_orchestration_policy - cp_print "\nStarting upgrading of Check Point Nano Agent [$INSTALLATION_TIME]" ${FORCE_STDOUT} + cp_print "\nStarting upgrading of open-appsec Nano Agent [$INSTALLATION_TIME]" ${FORCE_STDOUT} install_cp_nano_ctl add_uninstall_script cp_exec "cp -f certificate/ngen.body.crt ${FILESYSTEM_PATH}/${CERTS_PATH}/fog.pem" @@ -824,15 +824,17 @@ install_orchestration() cp_print "Upgrade completed successfully" ${FORCE_STDOUT} - cat "/etc/systemd/system/nano_agent.service" | grep -q "EnvironmentFile=/etc/environment" - result=$? + if [ -f /etc/systemd/system/nano_agent.service ]; then + cat "/etc/systemd/system/nano_agent.service" | grep -q "EnvironmentFile=/etc/environment" + result=$? - if [ $var_container_mode = false ] && [ $result -eq 0 ]; then - sed -i "$ d" /etc/systemd/system/nano_agent.service - echo "EnvironmentFile=/etc/environment" >> /etc/systemd/system/nano_agent.service - echo >> /etc/systemd/system/nano_agent.service - cp_exec "systemctl daemon-reload" - cp_exec "systemctl restart nano_agent" + if [ $var_container_mode = false ] && [ $result -eq 0 ]; then + sed -i "$ d" /etc/systemd/system/nano_agent.service + echo "EnvironmentFile=/etc/environment" >> /etc/systemd/system/nano_agent.service + echo >> /etc/systemd/system/nano_agent.service + cp_exec "systemctl daemon-reload" + cp_exec "systemctl restart nano_agent" + fi fi exit 0 fi