13
13
#include < memory>
14
14
#include < numeric>
15
15
#include < optional>
16
+ #include < sstream>
16
17
#include < tuple>
17
18
#include < utility>
18
19
@@ -659,6 +660,56 @@ struct executable_selector<type_condition> : std::true_type
659
660
{
660
661
};
661
662
663
+ template <typename Rule>
664
+ struct ast_action : nothing<Rule>
665
+ {
666
+ };
667
+
668
+ struct [[nodiscard]] depth_guard
669
+ {
670
+ explicit depth_guard (size_t & depth) noexcept
671
+ : _depth (depth)
672
+ {
673
+ ++_depth;
674
+ }
675
+
676
+ ~depth_guard ()
677
+ {
678
+ --_depth;
679
+ }
680
+
681
+ depth_guard (depth_guard&&) noexcept = delete ;
682
+ depth_guard (const depth_guard&) = delete ;
683
+
684
+ depth_guard& operator =(depth_guard&&) noexcept = delete ;
685
+ depth_guard& operator =(const depth_guard&) = delete ;
686
+
687
+ private:
688
+ size_t & _depth;
689
+ };
690
+
691
+ template <>
692
+ struct ast_action <selection_set> : maybe_nothing
693
+ {
694
+ template <typename Rule, apply_mode A, rewind_mode M, template <typename ...> class Action ,
695
+ template <typename ...> class Control , typename ParseInput, typename ... States>
696
+ [[nodiscard]] static bool match (ParseInput& in, States&&... st)
697
+ {
698
+ depth_guard guard (in.selectionSetDepth );
699
+ if (in.selectionSetDepth > in.depthLimit ())
700
+ {
701
+ std::ostringstream oss;
702
+
703
+ oss << " Exceeded " << in.depthLimit ()
704
+ << " nested depth limit for https://spec.graphql.org/October2021/#SelectionSet" ;
705
+
706
+ throw parse_error (oss.str (), in);
707
+ }
708
+
709
+ return tao::graphqlpeg::template match<Rule, A, M, Action, Control>(in, st...);
710
+ }
711
+ };
712
+
662
713
template <typename Rule>
663
714
struct ast_control : normal<Rule>
664
715
{
@@ -843,7 +894,7 @@ template <>
843
894
const char * ast_control<schema_document_content>::error_message =
844
895
" Expected schema type https://spec.graphql.org/October2021/#Document" ;
845
896
846
- ast parseSchemaString (std::string_view input)
897
+ ast parseSchemaString (std::string_view input, size_t depthLimit )
847
898
{
848
899
ast result { std::make_shared<ast_input>(
849
900
ast_input { std::vector<char > { input.cbegin (), input.cend () } }),
@@ -854,55 +905,55 @@ ast parseSchemaString(std::string_view input)
854
905
{
855
906
// Try a smaller grammar with only schema type definitions first.
856
907
result.root =
857
- parse_tree::parse<schema_document, ast_node, schema_selector, nothing , ast_control>(
858
- memory_input<>( data.data (), data.size (), " GraphQL" ));
908
+ parse_tree::parse<schema_document, ast_node, schema_selector, ast_action , ast_control>(
909
+ ast_memory (depthLimit, data.data (), data.size (), " GraphQL" s ));
859
910
}
860
911
catch (const peg::parse_error&)
861
912
{
862
913
// Try again with the full document grammar so validation can handle the unexepected
863
914
// executable definitions if this is a mixed document.
864
915
result.root =
865
- parse_tree::parse<mixed_document, ast_node, schema_selector, nothing , ast_control>(
866
- memory_input<>( data.data (), data.size (), " GraphQL" ));
916
+ parse_tree::parse<mixed_document, ast_node, schema_selector, ast_action , ast_control>(
917
+ ast_memory (depthLimit, data.data (), data.size (), " GraphQL" s ));
867
918
}
868
919
869
920
return result;
870
921
}
871
922
872
- ast parseSchemaFile (std::string_view filename)
923
+ ast parseSchemaFile (std::string_view filename, size_t depthLimit )
873
924
{
874
925
ast result;
875
926
876
927
try
877
928
{
878
- result.input =
879
- std::make_shared< ast_input>(ast_input { std::make_unique<file_input<>>( filename) });
929
+ result.input = std::make_shared<ast_input>(
930
+ ast_input { std::make_unique<ast_file>(depthLimit, filename) });
880
931
881
- auto & in = *std::get<std::unique_ptr<file_input<> >>(result.input ->data );
932
+ auto & in = *std::get<std::unique_ptr<ast_file >>(result.input ->data );
882
933
883
934
// Try a smaller grammar with only schema type definitions first.
884
935
result.root =
885
- parse_tree::parse<schema_document, ast_node, schema_selector, nothing , ast_control>(
936
+ parse_tree::parse<schema_document, ast_node, schema_selector, ast_action , ast_control>(
886
937
std::move (in));
887
938
}
888
939
catch (const peg::parse_error&)
889
940
{
890
- result.input =
891
- std::make_shared< ast_input>(ast_input { std::make_unique<file_input<>>( filename) });
941
+ result.input = std::make_shared<ast_input>(
942
+ ast_input { std::make_unique<ast_file>(depthLimit, filename) });
892
943
893
- auto & in = *std::get<std::unique_ptr<file_input<> >>(result.input ->data );
944
+ auto & in = *std::get<std::unique_ptr<ast_file >>(result.input ->data );
894
945
895
946
// Try again with the full document grammar so validation can handle the unexepected
896
947
// executable definitions if this is a mixed document.
897
948
result.root =
898
- parse_tree::parse<mixed_document, ast_node, schema_selector, nothing , ast_control>(
949
+ parse_tree::parse<mixed_document, ast_node, schema_selector, ast_action , ast_control>(
899
950
std::move (in));
900
951
}
901
952
902
953
return result;
903
954
}
904
955
905
- ast parseString (std::string_view input)
956
+ ast parseString (std::string_view input, size_t depthLimit )
906
957
{
907
958
ast result { std::make_shared<ast_input>(
908
959
ast_input { std::vector<char > { input.cbegin (), input.cend () } }),
@@ -913,48 +964,48 @@ ast parseString(std::string_view input)
913
964
{
914
965
// Try a smaller grammar with only executable definitions first.
915
966
result.root = parse_tree::
916
- parse<executable_document, ast_node, executable_selector, nothing , ast_control>(
917
- memory_input<>( data.data (), data.size (), " GraphQL" ));
967
+ parse<executable_document, ast_node, executable_selector, ast_action , ast_control>(
968
+ ast_memory (depthLimit, data.data (), data.size (), " GraphQL" s ));
918
969
}
919
970
catch (const peg::parse_error&)
920
971
{
921
972
// Try again with the full document grammar so validation can handle the unexepected type
922
973
// definitions if this is a mixed document.
923
- result.root =
924
- parse_tree:: parse<mixed_document, ast_node, executable_selector, nothing , ast_control>(
925
- memory_input<>( data.data (), data.size (), " GraphQL" ));
974
+ result.root = parse_tree::
975
+ parse<mixed_document, ast_node, executable_selector, ast_action , ast_control>(
976
+ ast_memory (depthLimit, data.data (), data.size (), " GraphQL" s ));
926
977
}
927
978
928
979
return result;
929
980
}
930
981
931
- ast parseFile (std::string_view filename)
982
+ ast parseFile (std::string_view filename, size_t depthLimit )
932
983
{
933
984
ast result;
934
985
935
986
try
936
987
{
937
- result.input =
938
- std::make_shared< ast_input>(ast_input { std::make_unique<file_input<>>( filename) });
988
+ result.input = std::make_shared<ast_input>(
989
+ ast_input { std::make_unique<ast_file>(depthLimit, filename) });
939
990
940
- auto & in = *std::get<std::unique_ptr<file_input<> >>(result.input ->data );
991
+ auto & in = *std::get<std::unique_ptr<ast_file >>(result.input ->data );
941
992
942
993
// Try a smaller grammar with only executable definitions first.
943
994
result.root = parse_tree::
944
- parse<executable_document, ast_node, executable_selector, nothing , ast_control>(
995
+ parse<executable_document, ast_node, executable_selector, ast_action , ast_control>(
945
996
std::move (in));
946
997
}
947
998
catch (const peg::parse_error&)
948
999
{
949
- result.input =
950
- std::make_shared< ast_input>(ast_input { std::make_unique<file_input<>>( filename) });
1000
+ result.input = std::make_shared<ast_input>(
1001
+ ast_input { std::make_unique<ast_file>(depthLimit, filename) });
951
1002
952
- auto & in = *std::get<std::unique_ptr<file_input<> >>(result.input ->data );
1003
+ auto & in = *std::get<std::unique_ptr<ast_file >>(result.input ->data );
953
1004
954
1005
// Try again with the full document grammar so validation can handle the unexepected type
955
1006
// definitions if this is a mixed document.
956
- result.root =
957
- parse_tree:: parse<mixed_document, ast_node, executable_selector, nothing , ast_control>(
1007
+ result.root = parse_tree::
1008
+ parse<mixed_document, ast_node, executable_selector, ast_action , ast_control>(
958
1009
std::move (in));
959
1010
}
960
1011
@@ -976,7 +1027,7 @@ peg::ast operator"" _graphql(const char* text, size_t size)
976
1027
peg::ast_node,
977
1028
peg::executable_selector,
978
1029
peg::nothing,
979
- peg::ast_control>(peg::memory_input<>(text, size, " GraphQL" ));
1030
+ peg::ast_control>(peg::memory_input<>(text, size, " GraphQL" s ));
980
1031
}
981
1032
catch (const peg::parse_error&)
982
1033
{
@@ -986,7 +1037,7 @@ peg::ast operator"" _graphql(const char* text, size_t size)
986
1037
peg::ast_node,
987
1038
peg::executable_selector,
988
1039
peg::nothing,
989
- peg::ast_control>(peg::memory_input<>(text, size, " GraphQL" ));
1040
+ peg::ast_control>(peg::memory_input<>(text, size, " GraphQL" s ));
990
1041
}
991
1042
992
1043
return result;
0 commit comments