Move metadata setting into HPackParser (#27545)

* forward work to get append, limit check into parser

* further cleanup

* Remove chttp2_incoming_metadata_buffer

* Automated change: Fix sanity tests

* test fixes

* fix cronet

* wip

* first pass mementofication of parsing - libgrpc compiles

* further progress

* fixes

* fixes

* fix leak

* Automated change: Fix sanity tests

* fix leak

* fixes

* x

* improve fuzzer

* init ordering fix

* Update hpack_parser_table.h

* Update hpack_parser.cc

* Update hpack_parser_test.cc

* Automated change: Fix sanity tests

* Automated change: Fix sanity tests

* i mustache myself why

* fix use after free

* Automated change: Fix sanity tests

* fixes

* eliminate second pass metadata - this is an illegal frame and fails the new parser

* handle mementos with size > sizeof(intptr_t)

* fix

* add parsed metadata header, test

* Automated change: Fix sanity tests

* fix includes

* phase1

* phase2

* Update parsed_metadata.h

* fix

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/27686/head
Craig Tiller 3 years ago committed by GitHub
parent 2f56cb3d87
commit f57a1f7d8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      BUILD
  2. 166
      CMakeLists.txt
  3. 2
      Makefile
  4. 55
      build_autogenerated.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 6
      gRPC-C++.podspec
  8. 7
      gRPC-Core.podspec
  9. 4
      grpc.gemspec
  10. 2
      grpc.gyp
  11. 4
      package.xml
  12. 6
      src/core/ext/filters/client_channel/health/health_check_client.cc
  13. 12
      src/core/ext/filters/client_channel/retry_filter.cc
  14. 13
      src/core/ext/transport/chttp2/transport/chttp2_transport.cc
  15. 3
      src/core/ext/transport/chttp2/transport/frame_rst_stream.cc
  16. 204
      src/core/ext/transport/chttp2/transport/hpack_parser.cc
  17. 19
      src/core/ext/transport/chttp2/transport/hpack_parser.h
  18. 37
      src/core/ext/transport/chttp2/transport/hpack_parser_table.cc
  19. 65
      src/core/ext/transport/chttp2/transport/hpack_parser_table.h
  20. 65
      src/core/ext/transport/chttp2/transport/incoming_metadata.cc
  21. 54
      src/core/ext/transport/chttp2/transport/incoming_metadata.h
  22. 6
      src/core/ext/transport/chttp2/transport/internal.h
  23. 191
      src/core/ext/transport/chttp2/transport/parsing.cc
  24. 20
      src/core/ext/transport/cronet/transport/cronet_transport.cc
  25. 20
      src/core/ext/transport/inproc/inproc_transport.cc
  26. 10
      src/core/lib/gprpp/arena.h
  27. 8
      src/core/lib/gprpp/chunked_vector.h
  28. 48
      src/core/lib/surface/call.cc
  29. 1
      src/core/lib/transport/metadata_batch.cc
  30. 97
      src/core/lib/transport/metadata_batch.h
  31. 260
      src/core/lib/transport/parsed_metadata.h
  32. 1
      src/python/grpcio/grpc_core_dependencies.py
  33. 17
      test/core/gprpp/chunked_vector_fuzzer.cc
  34. 229
      test/core/gprpp/chunked_vector_test.cc
  35. 14
      test/core/transport/BUILD
  36. 12
      test/core/transport/binder/binder_transport_test.cc
  37. 7
      test/core/transport/chttp2/BUILD
  38. 9
      test/core/transport/chttp2/hpack_encoder_test.cc
  39. 1
      test/core/transport/chttp2/hpack_parser_corpus/0141fcddc9807ee093313b2256f1306fbbdc6cda
  40. BIN
      test/core/transport/chttp2/hpack_parser_corpus/0255050a9ccb25f46d6c1bf6a5a8a4c0c7635599
  41. 1
      test/core/transport/chttp2/hpack_parser_corpus/0320a995a8c76c64c8a0e0297f632b76d9bc92d6
  42. 1
      test/core/transport/chttp2/hpack_parser_corpus/042091aeac4cc255506b96fa11c7354e699fde76
  43. 1
      test/core/transport/chttp2/hpack_parser_corpus/051268ade45dbed0aab896d7d9f4d10ba89d3b09
  44. 1
      test/core/transport/chttp2/hpack_parser_corpus/0696e7bf7837d98de01c915d3c9d80e5d21b30d2
  45. BIN
      test/core/transport/chttp2/hpack_parser_corpus/06995c2f3f01c7ec50547415dc324c64030b7a3e
  46. 1
      test/core/transport/chttp2/hpack_parser_corpus/06f7ce769fe07804fc842462d4be8c1aa2ba82c2
  47. 1
      test/core/transport/chttp2/hpack_parser_corpus/0781b055c85ab8fbd0a3d0080a32e394af8761c4
  48. 1
      test/core/transport/chttp2/hpack_parser_corpus/080e1f19e6061c5bcac31add2095f87f6ce46129
  49. 1
      test/core/transport/chttp2/hpack_parser_corpus/0828169ba82152a8907f1001e3d98804397d4610
  50. BIN
      test/core/transport/chttp2/hpack_parser_corpus/08ffc4a4160e9fe6f322c28870a89a41fd9c37d7
  51. 1
      test/core/transport/chttp2/hpack_parser_corpus/090a7a758898a6e7c9108b7e8a1cb9cda383e707
  52. 1
      test/core/transport/chttp2/hpack_parser_corpus/0940663729501b750a18542e1041cc26385c6148
  53. BIN
      test/core/transport/chttp2/hpack_parser_corpus/0a10bd140c6c5fb109a0816ca061739688a6db9a
  54. BIN
      test/core/transport/chttp2/hpack_parser_corpus/0a4d3fda02cdcb7adad1daa80d65780c9c8d1464
  55. BIN
      test/core/transport/chttp2/hpack_parser_corpus/0ad812832efa33e086874fbf3496664d3f1b4dbe
  56. BIN
      test/core/transport/chttp2/hpack_parser_corpus/0c9996d4fef87bacd7a001e99a515b3ba3d5788f
  57. 1
      test/core/transport/chttp2/hpack_parser_corpus/0d6210208831fe55951af56cdeee3d54a91a5361
  58. 1
      test/core/transport/chttp2/hpack_parser_corpus/0d784965b2262df7ed7a1eb57b92a718cc76bde8
  59. BIN
      test/core/transport/chttp2/hpack_parser_corpus/0dc9e41eedf35ccedf4e2b0d230ead7c4d72fdb2
  60. 1
      test/core/transport/chttp2/hpack_parser_corpus/0dd470c8939ed535de6b36f7b7bfb68aeace493e
  61. BIN
      test/core/transport/chttp2/hpack_parser_corpus/0e61e471fa6d3405daef4276ee00cf5fc189f378
  62. BIN
      test/core/transport/chttp2/hpack_parser_corpus/0e9196f951874edbb5ed098739ea5c8b6c0751c2
  63. BIN
      test/core/transport/chttp2/hpack_parser_corpus/11442d93a554b9e7f9ab02782bbf9443bf6e1ddc
  64. 1
      test/core/transport/chttp2/hpack_parser_corpus/11833b795d04eda5a3af56ef7b3c3a26a8ee3444
  65. 1
      test/core/transport/chttp2/hpack_parser_corpus/141272316382b0f3e9ec841c735b84e7aa517c3e
  66. BIN
      test/core/transport/chttp2/hpack_parser_corpus/15ae43369798e48c396dfe7d53a21878b96e66c8
  67. 1
      test/core/transport/chttp2/hpack_parser_corpus/166bf1843c229d34a2880d234dd166c27bdc11fd
  68. BIN
      test/core/transport/chttp2/hpack_parser_corpus/179e8ac763b4051a953a38b6b3b1f1e1f6cc6c9e
  69. BIN
      test/core/transport/chttp2/hpack_parser_corpus/17faf0ba8a491a835d35977a9007b90ab7d30d2a
  70. 1
      test/core/transport/chttp2/hpack_parser_corpus/188f6cf2470e95b228341de305ef839b27f01a5c
  71. 1
      test/core/transport/chttp2/hpack_parser_corpus/1ab3e52adace335d02e2b5130eb4f7c918add7fd
  72. BIN
      test/core/transport/chttp2/hpack_parser_corpus/1b5150514364e2c17f5a4edac1b7af99b936f55a
  73. BIN
      test/core/transport/chttp2/hpack_parser_corpus/1e8befb98cbaba059d6771abd1680e19484e7723
  74. BIN
      test/core/transport/chttp2/hpack_parser_corpus/1e9b962969c359bc2ff766704c8ca8e25f5eccfc
  75. 1
      test/core/transport/chttp2/hpack_parser_corpus/1f80af104acf41b912bf4a48fb938267e3718719
  76. BIN
      test/core/transport/chttp2/hpack_parser_corpus/1fcc4afd6f48e83d61ea74970df3ca9dcd8ec291
  77. 1
      test/core/transport/chttp2/hpack_parser_corpus/213a734ccdb813b18ad9f2dd99b7f9967ee1460b
  78. 1
      test/core/transport/chttp2/hpack_parser_corpus/2151945f43991c27e123c45dc72b93752a47e65f
  79. 1
      test/core/transport/chttp2/hpack_parser_corpus/21545d998c27a5a1572a89a552937752432b1c14
  80. 1
      test/core/transport/chttp2/hpack_parser_corpus/23c7443fa1ab713e7c34ec50222b1b8cceaedc65
  81. BIN
      test/core/transport/chttp2/hpack_parser_corpus/2445bb2c6779712dc9e14c01fecb7103f8732858
  82. 1
      test/core/transport/chttp2/hpack_parser_corpus/244b0a20500e31d3c538418800db816b07f4d210
  83. 1
      test/core/transport/chttp2/hpack_parser_corpus/2461b9fa6b5bc4b6424dec5b9a18d4ec7c309112
  84. BIN
      test/core/transport/chttp2/hpack_parser_corpus/24ec2f3e17d3850564788f3fed17a5c586c44658
  85. 1
      test/core/transport/chttp2/hpack_parser_corpus/2537b8d6b902b8dfc6e17f194cf7d05ddecf74cf
  86. 1
      test/core/transport/chttp2/hpack_parser_corpus/253ad01acea4b7038edc3f2a8c4a0c0f5c4dcd05
  87. BIN
      test/core/transport/chttp2/hpack_parser_corpus/256d0bbdbed22f5867a6f503bf082011e61ee12b
  88. 1
      test/core/transport/chttp2/hpack_parser_corpus/26f0e88adbd8f8cdf778131a35b33ecf8711fa49
  89. 1
      test/core/transport/chttp2/hpack_parser_corpus/2e5dd8fb9d2a31fad9d681eda697d085b647b57c
  90. BIN
      test/core/transport/chttp2/hpack_parser_corpus/2fdfd2abf30c636ec8c841f1ac26594e25664f0f
  91. 1
      test/core/transport/chttp2/hpack_parser_corpus/311dac5092e36134d3490f98aa4207425e0ee941
  92. 1
      test/core/transport/chttp2/hpack_parser_corpus/320fe6224a5b691c0425e34b6b14e8c6fe9f9620
  93. 1
      test/core/transport/chttp2/hpack_parser_corpus/3255f1c7441a7150dc3c33022bfbe8c956c7b7b1
  94. BIN
      test/core/transport/chttp2/hpack_parser_corpus/33bc9db104eb72891fb096f34cbac191b3f9918d
  95. 1
      test/core/transport/chttp2/hpack_parser_corpus/342ff1db70a7616b4ef76c03a42802c6702c18cb
  96. 1
      test/core/transport/chttp2/hpack_parser_corpus/344c011df992ccfc0ec682c14a1cb2d7959998c7
  97. 1
      test/core/transport/chttp2/hpack_parser_corpus/35775efb9d0d68fa07987b9a84934389b528e436
  98. 1
      test/core/transport/chttp2/hpack_parser_corpus/3650168db6fe115fb1e73eed4b76cd224d977d01
  99. 1
      test/core/transport/chttp2/hpack_parser_corpus/38228bf98cdb50fd3fa830ba5a9d4c7399063dff
  100. 1
      test/core/transport/chttp2/hpack_parser_corpus/38717bee901151b22a10beb12c6623ccc844d3c2
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1742,6 +1742,7 @@ grpc_cc_library(
"src/core/lib/transport/connectivity_state.h",
"src/core/lib/transport/metadata.h",
"src/core/lib/transport/metadata_batch.h",
"src/core/lib/transport/parsed_metadata.h",
"src/core/lib/transport/pid_controller.h",
"src/core/lib/transport/static_metadata.h",
"src/core/lib/transport/status_conversion.h",
@ -1785,6 +1786,7 @@ grpc_cc_library(
deps = [
"bitset",
"channel_stack_type",
"chunked_vector",
"closure",
"config",
"dual_ref_counted",
@ -3220,7 +3222,6 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/hpack_utils.cc",
"src/core/ext/transport/chttp2/transport/http2_settings.cc",
"src/core/ext/transport/chttp2/transport/huffsyms.cc",
"src/core/ext/transport/chttp2/transport/incoming_metadata.cc",
"src/core/ext/transport/chttp2/transport/parsing.cc",
"src/core/ext/transport/chttp2/transport/stream_lists.cc",
"src/core/ext/transport/chttp2/transport/stream_map.cc",
@ -3246,7 +3247,6 @@ grpc_cc_library(
"src/core/ext/transport/chttp2/transport/hpack_utils.h",
"src/core/ext/transport/chttp2/transport/http2_settings.h",
"src/core/ext/transport/chttp2/transport/huffsyms.h",
"src/core/ext/transport/chttp2/transport/incoming_metadata.h",
"src/core/ext/transport/chttp2/transport/internal.h",
"src/core/ext/transport/chttp2/transport/stream_map.h",
"src/core/ext/transport/chttp2/transport/varint.h",

166
CMakeLists.txt generated

@ -629,8 +629,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_c histogram_test)
add_dependencies(buildtests_c host_port_test)
add_dependencies(buildtests_c hpack_encoder_test)
add_dependencies(buildtests_c hpack_parser_table_test)
add_dependencies(buildtests_c hpack_parser_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_c httpcli_test)
endif()
@ -832,6 +830,8 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx headers_bad_client_test)
add_dependencies(buildtests_cxx health_service_end2end_test)
add_dependencies(buildtests_cxx hpack_encoder_index_test)
add_dependencies(buildtests_cxx hpack_parser_table_test)
add_dependencies(buildtests_cxx hpack_parser_test)
add_dependencies(buildtests_cxx http2_client)
add_dependencies(buildtests_cxx hybrid_end2end_test)
add_dependencies(buildtests_cxx idle_filter_state_test)
@ -866,6 +866,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx orphanable_test)
add_dependencies(buildtests_cxx out_of_bounds_bad_client_test)
add_dependencies(buildtests_cxx overload_test)
add_dependencies(buildtests_cxx parsed_metadata_test)
add_dependencies(buildtests_cxx pid_controller_test)
add_dependencies(buildtests_cxx pipe_test)
add_dependencies(buildtests_cxx poll_test)
@ -1590,7 +1591,6 @@ add_library(grpc
src/core/ext/transport/chttp2/transport/hpack_utils.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
src/core/ext/transport/chttp2/transport/huffsyms.cc
src/core/ext/transport/chttp2/transport/incoming_metadata.cc
src/core/ext/transport/chttp2/transport/parsing.cc
src/core/ext/transport/chttp2/transport/stream_lists.cc
src/core/ext/transport/chttp2/transport/stream_map.cc
@ -2421,7 +2421,6 @@ add_library(grpc_unsecure
src/core/ext/transport/chttp2/transport/hpack_utils.cc
src/core/ext/transport/chttp2/transport/http2_settings.cc
src/core/ext/transport/chttp2/transport/huffsyms.cc
src/core/ext/transport/chttp2/transport/incoming_metadata.cc
src/core/ext/transport/chttp2/transport/parsing.cc
src/core/ext/transport/chttp2/transport/stream_lists.cc
src/core/ext/transport/chttp2/transport/stream_map.cc
@ -5743,60 +5742,6 @@ target_link_libraries(hpack_encoder_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(hpack_parser_table_test
test/core/transport/chttp2/hpack_parser_table_test.cc
)
target_include_directories(hpack_parser_table_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
)
target_link_libraries(hpack_parser_table_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(hpack_parser_test
test/core/transport/chttp2/hpack_parser_test.cc
)
target_include_directories(hpack_parser_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
)
target_link_libraries(hpack_parser_test
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -11714,6 +11659,76 @@ target_link_libraries(hpack_encoder_index_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(hpack_parser_table_test
test/core/transport/chttp2/hpack_parser_table_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(hpack_parser_table_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(hpack_parser_table_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(hpack_parser_test
test/core/transport/chttp2/hpack_parser_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(hpack_parser_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(hpack_parser_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)
@ -13119,6 +13134,41 @@ target_link_libraries(overload_test
)
endif()
if(gRPC_BUILD_TESTS)
add_executable(parsed_metadata_test
test/core/transport/parsed_metadata_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(parsed_metadata_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(parsed_metadata_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif()
if(gRPC_BUILD_TESTS)

2
Makefile generated

@ -1149,7 +1149,6 @@ LIBGRPC_SRC = \
src/core/ext/transport/chttp2/transport/hpack_utils.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
src/core/ext/transport/chttp2/transport/huffsyms.cc \
src/core/ext/transport/chttp2/transport/incoming_metadata.cc \
src/core/ext/transport/chttp2/transport/parsing.cc \
src/core/ext/transport/chttp2/transport/stream_lists.cc \
src/core/ext/transport/chttp2/transport/stream_map.cc \
@ -1827,7 +1826,6 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/transport/chttp2/transport/hpack_utils.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
src/core/ext/transport/chttp2/transport/huffsyms.cc \
src/core/ext/transport/chttp2/transport/incoming_metadata.cc \
src/core/ext/transport/chttp2/transport/parsing.cc \
src/core/ext/transport/chttp2/transport/stream_lists.cc \
src/core/ext/transport/chttp2/transport/stream_map.cc \

@ -521,7 +521,6 @@ libs:
- src/core/ext/transport/chttp2/transport/hpack_utils.h
- src/core/ext/transport/chttp2/transport/http2_settings.h
- src/core/ext/transport/chttp2/transport/huffsyms.h
- src/core/ext/transport/chttp2/transport/incoming_metadata.h
- src/core/ext/transport/chttp2/transport/internal.h
- src/core/ext/transport/chttp2/transport/popularity_count.h
- src/core/ext/transport/chttp2/transport/stream_map.h
@ -755,6 +754,7 @@ libs:
- src/core/lib/event_engine/sockaddr.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/bitset.h
- src/core/lib/gprpp/chunked_vector.h
- src/core/lib/gprpp/dual_ref_counted.h
- src/core/lib/gprpp/match.h
- src/core/lib/gprpp/orphanable.h
@ -922,6 +922,7 @@ libs:
- src/core/lib/transport/http2_errors.h
- src/core/lib/transport/metadata.h
- src/core/lib/transport/metadata_batch.h
- src/core/lib/transport/parsed_metadata.h
- src/core/lib/transport/pid_controller.h
- src/core/lib/transport/static_metadata.h
- src/core/lib/transport/status_conversion.h
@ -1063,7 +1064,6 @@ libs:
- src/core/ext/transport/chttp2/transport/hpack_utils.cc
- src/core/ext/transport/chttp2/transport/http2_settings.cc
- src/core/ext/transport/chttp2/transport/huffsyms.cc
- src/core/ext/transport/chttp2/transport/incoming_metadata.cc
- src/core/ext/transport/chttp2/transport/parsing.cc
- src/core/ext/transport/chttp2/transport/stream_lists.cc
- src/core/ext/transport/chttp2/transport/stream_map.cc
@ -1764,7 +1764,6 @@ libs:
- src/core/ext/transport/chttp2/transport/hpack_utils.h
- src/core/ext/transport/chttp2/transport/http2_settings.h
- src/core/ext/transport/chttp2/transport/huffsyms.h
- src/core/ext/transport/chttp2/transport/incoming_metadata.h
- src/core/ext/transport/chttp2/transport/internal.h
- src/core/ext/transport/chttp2/transport/popularity_count.h
- src/core/ext/transport/chttp2/transport/stream_map.h
@ -1806,6 +1805,7 @@ libs:
- src/core/lib/event_engine/sockaddr.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/bitset.h
- src/core/lib/gprpp/chunked_vector.h
- src/core/lib/gprpp/dual_ref_counted.h
- src/core/lib/gprpp/match.h
- src/core/lib/gprpp/orphanable.h
@ -1925,6 +1925,7 @@ libs:
- src/core/lib/transport/http2_errors.h
- src/core/lib/transport/metadata.h
- src/core/lib/transport/metadata_batch.h
- src/core/lib/transport/parsed_metadata.h
- src/core/lib/transport/pid_controller.h
- src/core/lib/transport/static_metadata.h
- src/core/lib/transport/status_conversion.h
@ -2031,7 +2032,6 @@ libs:
- src/core/ext/transport/chttp2/transport/hpack_utils.cc
- src/core/ext/transport/chttp2/transport/http2_settings.cc
- src/core/ext/transport/chttp2/transport/huffsyms.cc
- src/core/ext/transport/chttp2/transport/incoming_metadata.cc
- src/core/ext/transport/chttp2/transport/parsing.cc
- src/core/ext/transport/chttp2/transport/stream_lists.cc
- src/core/ext/transport/chttp2/transport/stream_map.cc
@ -3530,24 +3530,6 @@ targets:
deps:
- grpc_test_util
uses_polling: false
- name: hpack_parser_table_test
build: test
language: c
headers: []
src:
- test/core/transport/chttp2/hpack_parser_table_test.cc
deps:
- grpc_test_util
uses_polling: false
- name: hpack_parser_test
build: test
language: c
headers: []
src:
- test/core/transport/chttp2/hpack_parser_test.cc
deps:
- grpc_test_util
uses_polling: false
- name: httpcli_test
build: test
language: c
@ -6082,6 +6064,26 @@ targets:
- test/core/transport/chttp2/hpack_encoder_index_test.cc
deps:
- absl/types:optional
- name: hpack_parser_table_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/transport/chttp2/hpack_parser_table_test.cc
deps:
- grpc_test_util
uses_polling: false
- name: hpack_parser_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/transport/chttp2/hpack_parser_test.cc
deps:
- grpc_test_util
uses_polling: false
- name: http2_client
build: test
run: false
@ -6773,6 +6775,15 @@ targets:
- test/core/gprpp/overload_test.cc
deps: []
uses_polling: false
- name: parsed_metadata_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/transport/parsed_metadata_test.cc
deps:
- grpc_test_util
- name: pid_controller_test
gtest: true
build: test

1
config.m4 generated

@ -144,7 +144,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/transport/chttp2/transport/hpack_utils.cc \
src/core/ext/transport/chttp2/transport/http2_settings.cc \
src/core/ext/transport/chttp2/transport/huffsyms.cc \
src/core/ext/transport/chttp2/transport/incoming_metadata.cc \
src/core/ext/transport/chttp2/transport/parsing.cc \
src/core/ext/transport/chttp2/transport/stream_lists.cc \
src/core/ext/transport/chttp2/transport/stream_map.cc \

1
config.w32 generated

@ -110,7 +110,6 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\transport\\chttp2\\transport\\hpack_utils.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\http2_settings.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\huffsyms.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\incoming_metadata.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\parsing.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\stream_lists.cc " +
"src\\core\\ext\\transport\\chttp2\\transport\\stream_map.cc " +

6
gRPC-C++.podspec generated

@ -294,7 +294,6 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/hpack_utils.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/popularity_count.h',
'src/core/ext/transport/chttp2/transport/stream_map.h',
@ -552,6 +551,7 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic_utils.h',
'src/core/lib/gprpp/bitset.h',
'src/core/lib/gprpp/chunked_vector.h',
'src/core/lib/gprpp/construct_destruct.h',
'src/core/lib/gprpp/debug_location.h',
'src/core/lib/gprpp/dual_ref_counted.h',
@ -737,6 +737,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/http2_errors.h',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/parsed_metadata.h',
'src/core/lib/transport/pid_controller.h',
'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/status_conversion.h',
@ -964,7 +965,6 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/hpack_utils.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/popularity_count.h',
'src/core/ext/transport/chttp2/transport/stream_map.h',
@ -1222,6 +1222,7 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic_utils.h',
'src/core/lib/gprpp/bitset.h',
'src/core/lib/gprpp/chunked_vector.h',
'src/core/lib/gprpp/construct_destruct.h',
'src/core/lib/gprpp/debug_location.h',
'src/core/lib/gprpp/dual_ref_counted.h',
@ -1407,6 +1408,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/http2_errors.h',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/parsed_metadata.h',
'src/core/lib/transport/pid_controller.h',
'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/status_conversion.h',

7
gRPC-Core.podspec generated

@ -378,8 +378,6 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/huffsyms.cc',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/incoming_metadata.cc',
'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/parsing.cc',
'src/core/ext/transport/chttp2/transport/popularity_count.h',
@ -912,6 +910,7 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic_utils.h',
'src/core/lib/gprpp/bitset.h',
'src/core/lib/gprpp/chunked_vector.h',
'src/core/lib/gprpp/construct_destruct.h',
'src/core/lib/gprpp/debug_location.h',
'src/core/lib/gprpp/dual_ref_counted.h',
@ -1305,6 +1304,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.cc',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/parsed_metadata.h',
'src/core/lib/transport/pid_controller.cc',
'src/core/lib/transport/pid_controller.h',
'src/core/lib/transport/static_metadata.cc',
@ -1538,7 +1538,6 @@ Pod::Spec.new do |s|
'src/core/ext/transport/chttp2/transport/hpack_utils.h',
'src/core/ext/transport/chttp2/transport/http2_settings.h',
'src/core/ext/transport/chttp2/transport/huffsyms.h',
'src/core/ext/transport/chttp2/transport/incoming_metadata.h',
'src/core/ext/transport/chttp2/transport/internal.h',
'src/core/ext/transport/chttp2/transport/popularity_count.h',
'src/core/ext/transport/chttp2/transport/stream_map.h',
@ -1796,6 +1795,7 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/arena.h',
'src/core/lib/gprpp/atomic_utils.h',
'src/core/lib/gprpp/bitset.h',
'src/core/lib/gprpp/chunked_vector.h',
'src/core/lib/gprpp/construct_destruct.h',
'src/core/lib/gprpp/debug_location.h',
'src/core/lib/gprpp/dual_ref_counted.h',
@ -1981,6 +1981,7 @@ Pod::Spec.new do |s|
'src/core/lib/transport/http2_errors.h',
'src/core/lib/transport/metadata.h',
'src/core/lib/transport/metadata_batch.h',
'src/core/lib/transport/parsed_metadata.h',
'src/core/lib/transport/pid_controller.h',
'src/core/lib/transport/static_metadata.h',
'src/core/lib/transport/status_conversion.h',

4
grpc.gemspec generated

@ -299,8 +299,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/transport/chttp2/transport/http2_settings.h )
s.files += %w( src/core/ext/transport/chttp2/transport/huffsyms.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/huffsyms.h )
s.files += %w( src/core/ext/transport/chttp2/transport/incoming_metadata.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/incoming_metadata.h )
s.files += %w( src/core/ext/transport/chttp2/transport/internal.h )
s.files += %w( src/core/ext/transport/chttp2/transport/parsing.cc )
s.files += %w( src/core/ext/transport/chttp2/transport/popularity_count.h )
@ -833,6 +831,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gprpp/arena.h )
s.files += %w( src/core/lib/gprpp/atomic_utils.h )
s.files += %w( src/core/lib/gprpp/bitset.h )
s.files += %w( src/core/lib/gprpp/chunked_vector.h )
s.files += %w( src/core/lib/gprpp/construct_destruct.h )
s.files += %w( src/core/lib/gprpp/debug_location.h )
s.files += %w( src/core/lib/gprpp/dual_ref_counted.h )
@ -1226,6 +1225,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/transport/metadata.h )
s.files += %w( src/core/lib/transport/metadata_batch.cc )
s.files += %w( src/core/lib/transport/metadata_batch.h )
s.files += %w( src/core/lib/transport/parsed_metadata.h )
s.files += %w( src/core/lib/transport/pid_controller.cc )
s.files += %w( src/core/lib/transport/pid_controller.h )
s.files += %w( src/core/lib/transport/static_metadata.cc )

2
grpc.gyp generated

@ -591,7 +591,6 @@
'src/core/ext/transport/chttp2/transport/hpack_utils.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
'src/core/ext/transport/chttp2/transport/huffsyms.cc',
'src/core/ext/transport/chttp2/transport/incoming_metadata.cc',
'src/core/ext/transport/chttp2/transport/parsing.cc',
'src/core/ext/transport/chttp2/transport/stream_lists.cc',
'src/core/ext/transport/chttp2/transport/stream_map.cc',
@ -1244,7 +1243,6 @@
'src/core/ext/transport/chttp2/transport/hpack_utils.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
'src/core/ext/transport/chttp2/transport/huffsyms.cc',
'src/core/ext/transport/chttp2/transport/incoming_metadata.cc',
'src/core/ext/transport/chttp2/transport/parsing.cc',
'src/core/ext/transport/chttp2/transport/stream_lists.cc',
'src/core/ext/transport/chttp2/transport/stream_map.cc',

4
package.xml generated

@ -279,8 +279,6 @@
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/http2_settings.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/huffsyms.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/huffsyms.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/incoming_metadata.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/incoming_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/internal.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/parsing.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/transport/chttp2/transport/popularity_count.h" role="src" />
@ -813,6 +811,7 @@
<file baseinstalldir="/" name="src/core/lib/gprpp/arena.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/atomic_utils.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/bitset.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/chunked_vector.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/construct_destruct.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/debug_location.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gprpp/dual_ref_counted.h" role="src" />
@ -1206,6 +1205,7 @@
<file baseinstalldir="/" name="src/core/lib/transport/metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/metadata_batch.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/parsed_metadata.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/pid_controller.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/pid_controller.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/transport/static_metadata.cc" role="src" />

@ -254,7 +254,11 @@ HealthCheckClient::CallState::CallState(
pollent_(grpc_polling_entity_create_from_pollset_set(interested_parties)),
arena_(Arena::Create(health_check_client_->connected_subchannel_
->GetInitialCallSizeEstimate())),
payload_(context_) {}
payload_(context_),
send_initial_metadata_(arena_),
send_trailing_metadata_(arena_),
recv_initial_metadata_(arena_),
recv_trailing_metadata_(arena_) {}
HealthCheckClient::CallState::~CallState() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_health_check_client_trace)) {

@ -425,22 +425,22 @@ class RetryFilter::CallData {
// because filters in the subchannel stack may modify the metadata,
// so we need to start in a pristine state for each attempt of the call.
grpc_linked_mdelem* send_initial_metadata_storage_;
grpc_metadata_batch send_initial_metadata_;
grpc_metadata_batch send_initial_metadata_{calld_->arena_};
// For send_message.
// TODO(roth): Restructure this to eliminate use of ManualConstructor.
ManualConstructor<ByteStreamCache::CachingByteStream> send_message_;
// For send_trailing_metadata.
grpc_linked_mdelem* send_trailing_metadata_storage_;
grpc_metadata_batch send_trailing_metadata_;
grpc_metadata_batch send_trailing_metadata_{calld_->arena_};
// For intercepting recv_initial_metadata.
grpc_metadata_batch recv_initial_metadata_;
grpc_metadata_batch recv_initial_metadata_{calld_->arena_};
grpc_closure recv_initial_metadata_ready_;
bool trailing_metadata_available_ = false;
// For intercepting recv_message.
grpc_closure recv_message_ready_;
OrphanablePtr<ByteStream> recv_message_;
// For intercepting recv_trailing_metadata.
grpc_metadata_batch recv_trailing_metadata_;
grpc_metadata_batch recv_trailing_metadata_{calld_->arena_};
grpc_transport_stream_stats collect_stats_;
grpc_closure recv_trailing_metadata_ready_;
// These fields indicate which ops have been started and completed on
@ -574,7 +574,7 @@ class RetryFilter::CallData {
// send_initial_metadata
bool seen_send_initial_metadata_ = false;
grpc_linked_mdelem* send_initial_metadata_storage_ = nullptr;
grpc_metadata_batch send_initial_metadata_;
grpc_metadata_batch send_initial_metadata_{arena_};
uint32_t send_initial_metadata_flags_;
// TODO(roth): As part of implementing hedging, we'll probably need to
// have the LB call set a value in CallAttempt and then propagate it
@ -600,7 +600,7 @@ class RetryFilter::CallData {
// send_trailing_metadata
bool seen_send_trailing_metadata_ = false;
grpc_linked_mdelem* send_trailing_metadata_storage_ = nullptr;
grpc_metadata_batch send_trailing_metadata_;
grpc_metadata_batch send_trailing_metadata_{arena_};
};
//

@ -1859,8 +1859,7 @@ void grpc_chttp2_maybe_complete_recv_initial_metadata(
&s->unprocessed_incoming_frames_buffer);
}
}
grpc_chttp2_incoming_metadata_buffer_publish(&s->initial_metadata_buffer,
s->recv_initial_metadata);
*s->recv_initial_metadata = std::move(s->initial_metadata_buffer);
null_then_sched_closure(&s->recv_initial_metadata_ready);
}
}
@ -2014,8 +2013,7 @@ void grpc_chttp2_maybe_complete_recv_trailing_metadata(grpc_chttp2_transport* t,
s->recv_trailing_metadata_finished != nullptr) {
grpc_transport_move_stats(&s->stats, s->collecting_stats);
s->collecting_stats = nullptr;
grpc_chttp2_incoming_metadata_buffer_publish(&s->trailing_metadata_buffer,
s->recv_trailing_metadata);
*s->recv_trailing_metadata = std::move(s->trailing_metadata_buffer);
null_then_sched_closure(&s->recv_trailing_metadata_finished);
}
}
@ -2108,14 +2106,13 @@ void grpc_chttp2_fake_status(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
char status_string[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(status, status_string);
GRPC_LOG_IF_ERROR("add_status",
grpc_chttp2_incoming_metadata_buffer_replace_or_add(
&s->trailing_metadata_buffer, GRPC_MDSTR_GRPC_STATUS,
s->trailing_metadata_buffer.ReplaceOrAppend(
GRPC_MDSTR_GRPC_STATUS,
grpc_core::UnmanagedMemorySlice(status_string)));
if (!message.empty()) {
grpc_slice message_slice = grpc_slice_from_cpp_string(std::move(message));
GRPC_LOG_IF_ERROR("add_status_message",
grpc_chttp2_incoming_metadata_buffer_replace_or_add(
&s->trailing_metadata_buffer,
s->trailing_metadata_buffer.ReplaceOrAppend(
GRPC_MDSTR_GRPC_MESSAGE, message_slice));
}
s->published_metadata[1] = GRPC_METADATA_SYNTHESIZED_FROM_FAKE;

@ -103,8 +103,7 @@ grpc_error_handle grpc_chttp2_rst_stream_parser_parse(void* parser,
((static_cast<uint32_t>(p->reason_bytes[2])) << 8) |
((static_cast<uint32_t>(p->reason_bytes[3])));
grpc_error_handle error = GRPC_ERROR_NONE;
if (reason != GRPC_HTTP2_NO_ERROR ||
s->trailing_metadata_buffer.size == 0) {
if (reason != GRPC_HTTP2_NO_ERROR || s->trailing_metadata_buffer.empty()) {
error = grpc_error_set_int(
grpc_error_set_str(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("RST_STREAM"),

@ -935,15 +935,18 @@ class HPackParser::String {
value_;
};
// Parser parses one frame + continuations worth of headers.
// Parser parses one key/value pair from a byte stream.
class HPackParser::Parser {
public:
Parser(Input* input, HPackParser::Sink* sink, HPackTable* table,
uint8_t* dynamic_table_updates_allowed)
Parser(Input* input, grpc_metadata_batch* metadata_buffer,
uint32_t metadata_size_limit, HPackTable* table,
uint8_t* dynamic_table_updates_allowed, uint32_t* frame_length)
: input_(input),
sink_(sink),
metadata_buffer_(metadata_buffer),
table_(table),
dynamic_table_updates_allowed_(dynamic_table_updates_allowed) {}
dynamic_table_updates_allowed_(dynamic_table_updates_allowed),
frame_length_(frame_length),
metadata_size_limit_(metadata_size_limit) {}
// Skip any priority bits, or return false on failure
bool SkipPriority() {
@ -965,13 +968,12 @@ class HPackParser::Parser {
case 1:
switch (cur & 0xf) {
case 0: // literal key
return FinishHeader<TableAction::kOmitFromTable>(
ParseLiteralKey<String::Extern>());
return FinishHeaderOmitFromTable(ParseLiteralKey<String::Extern>());
case 0xf: // varint encoded key index
return FinishHeader<TableAction::kOmitFromTable>(
return FinishHeaderOmitFromTable(
ParseVarIdxKey<String::Extern>(0xf));
default: // inline encoded key index
return FinishHeader<TableAction::kOmitFromTable>(
return FinishHeaderOmitFromTable(
ParseIdxKey<String::Extern>(cur & 0xf));
}
// Update max table size.
@ -999,23 +1001,22 @@ class HPackParser::Parser {
case 4:
if (cur == 0x40) {
// literal key
return FinishHeader<TableAction::kAddToTable>(
ParseLiteralKey<String::Intern>());
return FinishHeaderAndAddToTable(ParseLiteralKey<String::Intern>());
}
ABSL_FALLTHROUGH_INTENDED;
case 5:
case 6:
// inline encoded key index
return FinishHeader<TableAction::kAddToTable>(
return FinishHeaderAndAddToTable(
ParseIdxKey<String::Intern>(cur & 0x3f));
case 7:
if (cur == 0x7f) {
// varint encoded key index
return FinishHeader<TableAction::kAddToTable>(
return FinishHeaderAndAddToTable(
ParseVarIdxKey<String::Intern>(0x3f));
} else {
// inline encoded key index
return FinishHeader<TableAction::kAddToTable>(
return FinishHeaderAndAddToTable(
ParseIdxKey<String::Intern>(cur & 0x3f));
}
// Indexed Header Field Representation
@ -1056,102 +1057,98 @@ class HPackParser::Parser {
}
private:
void GPR_ATTRIBUTE_NOINLINE LogHeader(grpc_mdelem md) {
char* k = grpc_slice_to_c_string(GRPC_MDKEY(md));
char* v = nullptr;
if (grpc_is_binary_header_internal(GRPC_MDKEY(md))) {
v = grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX);
} else {
v = grpc_slice_to_c_string(GRPC_MDVALUE(md));
}
gpr_log(
GPR_INFO,
"Decode: '%s: %s', elem_interned=%d [%d], k_interned=%d, v_interned=%d",
k, v, GRPC_MDELEM_IS_INTERNED(md), GRPC_MDELEM_STORAGE(md),
grpc_slice_is_interned(GRPC_MDKEY(md)),
grpc_slice_is_interned(GRPC_MDVALUE(md)));
gpr_free(k);
gpr_free(v);
void GPR_ATTRIBUTE_NOINLINE LogHeader(const HPackTable::Memento& memento) {
// TODO(ctiller): what should be here?
gpr_log(GPR_DEBUG, "recvhdr: %s", memento.DebugString().c_str());
}
// During FinishHeader, how should the header be treated in the hpack table
enum class TableAction {
// Add to the table
kAddToTable,
// Do not add to the table
kOmitFromTable,
};
bool EmitHeader(const HPackTable::Memento& md) {
// Pass up to the transport
if (GPR_UNLIKELY(metadata_buffer_ == nullptr)) return true;
*frame_length_ += md.transport_size();
if (GPR_UNLIKELY(*frame_length_ > metadata_size_limit_)) {
return HandleMetadataSizeLimitExceeded(md);
}
grpc_error_handle err = metadata_buffer_->Set(md);
if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) {
input_->SetError(err);
return false;
}
return true;
}
template <TableAction action>
bool FinishHeader(grpc_mdelem md) {
bool FinishHeaderAndAddToTable(absl::optional<HPackTable::Memento> md) {
// Allow higher code to just pass in failures ... simplifies things a bit.
if (GRPC_MDISNULL(md)) return false;
if (!md.has_value()) return false;
// Log if desired
if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_chttp2_hpack_parser)) {
LogHeader(md);
}
// Add to the hpack table if needed
if (action == TableAction::kAddToTable) {
GPR_DEBUG_ASSERT(GRPC_MDELEM_STORAGE(md) ==
GRPC_MDELEM_STORAGE_INTERNED ||
GRPC_MDELEM_STORAGE(md) == GRPC_MDELEM_STORAGE_STATIC);
grpc_error_handle err = table_->Add(md);
if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) {
input_->SetError(err);
return false;
};
LogHeader(*md);
}
// Pass up to the transport
grpc_error_handle err = (*sink_)(md);
// Emit whilst we own the metadata.
auto r = EmitHeader(*md);
// Add to the hpack table
grpc_error_handle err = table_->Add(std::move(*md));
if (GPR_UNLIKELY(err != GRPC_ERROR_NONE)) {
input_->SetError(err);
return false;
};
return r;
}
bool FinishHeaderOmitFromTable(absl::optional<HPackTable::Memento> md) {
// Allow higher code to just pass in failures ... simplifies things a bit.
if (!md.has_value()) return false;
return FinishHeaderOmitFromTable(*md);
}
bool FinishHeaderOmitFromTable(const HPackTable::Memento& md) {
// Log if desired
if (GRPC_TRACE_FLAG_ENABLED(grpc_trace_chttp2_hpack_parser)) {
LogHeader(md);
}
return true;
return EmitHeader(md);
}
// Parse a string encoded key and a string encoded value
template <typename TakeValueType>
grpc_mdelem ParseLiteralKey() {
absl::optional<HPackTable::Memento> ParseLiteralKey() {
auto key = String::Parse(input_);
if (!key.has_value()) return GRPC_MDNULL;
if (!key.has_value()) return {};
auto key_slice = key->Take<String::Intern>();
auto value = ParseValueString(key_slice);
auto value =
ParseValueString(grpc_is_refcounted_slice_binary_header(key_slice));
if (GPR_UNLIKELY(!value.has_value())) {
grpc_slice_unref_internal(key_slice);
return GRPC_MDNULL;
return {};
}
return grpc_mdelem_from_slices(key_slice, value->Take<TakeValueType>());
return grpc_metadata_batch::Parse(key_slice, value->Take<TakeValueType>());
}
// Parse an index encoded key and a string encoded value
template <typename TakeValueType>
grpc_mdelem ParseIdxKey(uint32_t index) {
auto elem = table_->Peek(index);
if (GPR_UNLIKELY(GRPC_MDISNULL(elem))) {
return InvalidHPackIndexError(index, elem);
absl::optional<HPackTable::Memento> ParseIdxKey(uint32_t index) {
const auto* elem = table_->Lookup(index);
if (GPR_UNLIKELY(elem == nullptr)) {
return InvalidHPackIndexError(index,
absl::optional<HPackTable::Memento>());
}
GPR_DEBUG_ASSERT(GRPC_MDELEM_IS_INTERNED(elem));
auto value = ParseValueString(GRPC_MDKEY(elem));
if (GPR_UNLIKELY(!value.has_value())) return GRPC_MDNULL;
return grpc_mdelem_from_slices(
static_cast<const ManagedMemorySlice&>(
grpc_slice_ref_internal(GRPC_MDKEY(elem))),
value->Take<TakeValueType>());
auto value = ParseValueString(elem->is_binary_header());
if (GPR_UNLIKELY(!value.has_value())) return {};
return elem->WithNewValue(value->Take<TakeValueType>());
}
// Parse a varint index encoded key and a string encoded value
template <typename TakeValueType>
grpc_mdelem ParseVarIdxKey(uint32_t offset) {
absl::optional<HPackTable::Memento> ParseVarIdxKey(uint32_t offset) {
auto index = input_->ParseVarint(offset);
if (GPR_UNLIKELY(!index.has_value())) return GRPC_MDNULL;
if (GPR_UNLIKELY(!index.has_value())) return {};
return ParseIdxKey<TakeValueType>(*index);
}
// Parse a string, figuring out if it's binary or not by the key name.
template <typename SliceType>
absl::optional<String> ParseValueString(const SliceType& key) {
if (grpc_is_refcounted_slice_binary_header(key)) {
absl::optional<String> ParseValueString(bool is_binary) {
if (is_binary) {
return String::ParseBinary(input_);
} else {
return String::Parse(input_);
@ -1162,12 +1159,12 @@ class HPackParser::Parser {
bool FinishIndexed(absl::optional<uint32_t> index) {
*dynamic_table_updates_allowed_ = 0;
if (!index.has_value()) return false;
grpc_mdelem md = table_->Fetch(*index);
if (GPR_UNLIKELY(GRPC_MDISNULL(md))) {
const auto* elem = table_->Lookup(*index);
if (GPR_UNLIKELY(elem == nullptr)) {
return InvalidHPackIndexError(*index, false);
}
GRPC_STATS_INC_HPACK_RECV_INDEXED();
return FinishHeader<TableAction::kOmitFromTable>(md);
return FinishHeaderOmitFromTable(*elem);
}
// finish parsing a max table size change
@ -1207,21 +1204,43 @@ class HPackParser::Parser {
GRPC_ERROR_INT_SIZE,
static_cast<intptr_t>(this->table_->num_entries()));
},
result);
std::move(result));
}
GPR_ATTRIBUTE_NOINLINE
bool HandleMetadataSizeLimitExceeded(const HPackTable::Memento&) {
gpr_log(GPR_DEBUG,
"received initial metadata size exceeds limit (%" PRIu32
" vs. %" PRIu32
"). GRPC_ARG_MAX_METADATA_SIZE can be set to increase this limit.",
*frame_length_, metadata_size_limit_);
return input_->MaybeSetErrorAndReturn(
[] {
return grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"received initial metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_RESOURCE_EXHAUSTED);
},
false);
}
Input* input_;
HPackParser::Sink* sink_;
grpc_metadata_batch* metadata_buffer_;
HPackTable* const table_;
uint8_t* dynamic_table_updates_allowed_;
uint8_t* const dynamic_table_updates_allowed_;
uint32_t* const frame_length_;
uint32_t metadata_size_limit_;
};
UnmanagedMemorySlice HPackParser::String::Take(Extern) {
auto s = Match(
value_,
[](const grpc_slice& slice) {
// TODO(ctiller): Think about this before submission.
GPR_DEBUG_ASSERT(!grpc_slice_is_interned(slice));
return static_cast<const UnmanagedMemorySlice&>(slice);
auto out_slice = grpc_slice_copy(slice);
grpc_slice_unref_internal(slice);
return static_cast<const UnmanagedMemorySlice&>(out_slice);
},
[](absl::Span<const uint8_t> span) {
return UnmanagedMemorySlice(
@ -1263,11 +1282,15 @@ HPackParser::HPackParser() = default;
HPackParser::~HPackParser() = default;
void HPackParser::BeginFrame(Sink sink, Boundary boundary, Priority priority) {
sink_ = std::move(sink);
void HPackParser::BeginFrame(grpc_metadata_batch* metadata_buffer,
uint32_t metadata_size_limit, Boundary boundary,
Priority priority) {
metadata_buffer_ = metadata_buffer;
boundary_ = boundary;
priority_ = priority;
dynamic_table_updates_allowed_ = 2;
frame_length_ = 0;
metadata_size_limit_ = metadata_size_limit;
}
grpc_error_handle HPackParser::Parse(const grpc_slice& slice, bool is_last) {
@ -1310,9 +1333,10 @@ bool HPackParser::ParseInputInner(Input* input) {
}
}
while (!input->end_of_stream()) {
if (GPR_UNLIKELY(
!Parser(input, &sink_, &table_, &dynamic_table_updates_allowed_)
.Parse())) {
if (GPR_UNLIKELY(!Parser(input, metadata_buffer_, metadata_size_limit_,
&table_, &dynamic_table_updates_allowed_,
&frame_length_)
.Parse())) {
return false;
}
input->UpdateFrontier();
@ -1320,7 +1344,7 @@ bool HPackParser::ParseInputInner(Input* input) {
return true;
}
void HPackParser::FinishFrame() { sink_ = Sink(); }
void HPackParser::FinishFrame() { metadata_buffer_ = nullptr; }
} // namespace grpc_core
@ -1390,7 +1414,7 @@ grpc_error_handle grpc_chttp2_header_parser_parse(void* hpack_parser,
/* Process stream compression md element if it exists */
if (s->header_frames_received ==
0) { /* Only acts on initial metadata */
parse_stream_compression_md(t, s, &s->initial_metadata_buffer.batch);
parse_stream_compression_md(t, s, &s->initial_metadata_buffer);
}
s->published_metadata[s->header_frames_received] =
GRPC_METADATA_PUBLISHED_FROM_WIRE;

@ -26,6 +26,7 @@
#include "src/core/ext/transport/chttp2/transport/frame.h"
#include "src/core/ext/transport/chttp2/transport/hpack_parser_table.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
namespace grpc_core {
@ -49,9 +50,6 @@ class HPackParser {
Included
};
// User specified structure called for each received header.
using Sink = std::function<grpc_error_handle(grpc_mdelem)>;
HPackParser();
~HPackParser();
@ -61,9 +59,11 @@ class HPackParser {
// Begin parsing a new frame
// Sink receives each parsed header,
void BeginFrame(Sink sink, Boundary boundary, Priority priority);
// Change the header sink mid parse
void ResetSink(Sink sink) { sink_ = std::move(sink); }
void BeginFrame(grpc_metadata_batch* metadata_buffer,
uint32_t metadata_size_limit, Boundary boundary,
Priority priority);
// Start throwing away any received headers after parsing them.
void StopBufferingFrame() { metadata_buffer_ = nullptr; }
// Parse one slice worth of data
grpc_error_handle Parse(const grpc_slice& slice, bool is_last);
// Reset state ready for the next BeginFrame
@ -85,8 +85,8 @@ class HPackParser {
grpc_error_handle ParseInput(Input input, bool is_last);
bool ParseInputInner(Input* input);
// Callback per header received
Sink sink_;
// Target metadata buffer
grpc_metadata_batch* metadata_buffer_ = nullptr;
// Bytes that could not be parsed last parsing round
std::vector<uint8_t> unparsed_bytes_;
@ -99,6 +99,9 @@ class HPackParser {
// buffering.
Priority priority_;
uint8_t dynamic_table_updates_allowed_;
// Length of frame so far.
uint32_t frame_length_;
uint32_t metadata_size_limit_;
// hpack table
HPackTable table_;

@ -38,32 +38,24 @@ extern grpc_core::TraceFlag grpc_http_trace;
namespace grpc_core {
HPackTable::HPackTable() = default;
HPackTable::HPackTable() : static_metadata_(GetStaticMementos()) {}
HPackTable::~HPackTable() {
for (size_t i = 0; i < num_entries_; i++) {
GRPC_MDELEM_UNREF(entries_[(first_entry_ + i) % entries_.size()]);
}
}
HPackTable::~HPackTable() = default;
/* Evict one element from the table */
void HPackTable::EvictOne() {
grpc_mdelem first_entry = entries_[first_entry_];
size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(first_entry)) +
GRPC_SLICE_LENGTH(GRPC_MDVALUE(first_entry)) +
hpack_constants::kEntryOverhead;
GPR_ASSERT(elem_bytes <= mem_used_);
mem_used_ -= static_cast<uint32_t>(elem_bytes);
auto first_entry = std::move(entries_[first_entry_]);
GPR_ASSERT(first_entry.transport_size() <= mem_used_);
mem_used_ -= first_entry.transport_size();
first_entry_ = ((first_entry_ + 1) % entries_.size());
num_entries_--;
GRPC_MDELEM_UNREF(first_entry);
}
void HPackTable::Rebuild(uint32_t new_cap) {
EntriesVec entries;
entries.resize(new_cap);
for (size_t i = 0; i < num_entries_; i++) {
entries[i] = entries_[(first_entry_ + i) % entries_.size()];
entries[i] = std::move(entries_[(first_entry_ + i) % entries_.size()]);
}
first_entry_ = 0;
entries_.swap(entries);
@ -113,12 +105,7 @@ grpc_error_handle HPackTable::SetCurrentTableSize(uint32_t bytes) {
return GRPC_ERROR_NONE;
}
grpc_error_handle HPackTable::Add(grpc_mdelem md) {
/* determine how many bytes of buffer this entry represents */
size_t elem_bytes = GRPC_SLICE_LENGTH(GRPC_MDKEY(md)) +
GRPC_SLICE_LENGTH(GRPC_MDVALUE(md)) +
hpack_constants::kEntryOverhead;
grpc_error_handle HPackTable::Add(Memento md) {
if (current_table_bytes_ > max_bytes_) {
return GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrFormat(
"HPACK max table size reduced to %d but not reflected by hpack "
@ -127,7 +114,7 @@ grpc_error_handle HPackTable::Add(grpc_mdelem md) {
}
// we can't add elements bigger than the max table size
if (elem_bytes > current_table_bytes_) {
if (md.transport_size() > current_table_bytes_) {
// HPACK draft 10 section 4.4 states:
// If the size of the new entry is less than or equal to the maximum
// size, that entry is added to the table. It is not an error to
@ -142,17 +129,17 @@ grpc_error_handle HPackTable::Add(grpc_mdelem md) {
}
// evict entries to ensure no overflow
while (elem_bytes > static_cast<size_t>(current_table_bytes_) - mem_used_) {
while (md.transport_size() >
static_cast<size_t>(current_table_bytes_) - mem_used_) {
EvictOne();
}
// copy the finalized entry in
entries_[(first_entry_ + num_entries_) % entries_.size()] =
GRPC_MDELEM_REF(md);
mem_used_ += md.transport_size();
entries_[(first_entry_ + num_entries_) % entries_.size()] = std::move(md);
// update accounting values
num_entries_++;
mem_used_ += static_cast<uint32_t>(elem_bytes);
return GRPC_ERROR_NONE;
}

@ -27,6 +27,7 @@
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/static_metadata.h"
namespace grpc_core {
@ -37,30 +38,16 @@ class HPackTable {
HPackTable();
~HPackTable();
HPackTable(const HPackTable&);
HPackTable& operator=(const HPackTable&);
HPackTable(const HPackTable&) = delete;
HPackTable& operator=(const HPackTable&) = delete;
void SetMaxBytes(uint32_t max_bytes);
grpc_error_handle SetCurrentTableSize(uint32_t bytes);
// Lookup, but don't ref.
grpc_mdelem Peek(uint32_t index) const { return Lookup<false>(index); }
// Lookup, taking a ref if found.
grpc_mdelem Fetch(uint32_t index) const { return Lookup<true>(index); }
// add a table entry to the index
grpc_error_handle Add(grpc_mdelem md) GRPC_MUST_USE_RESULT;
// Current entry count in the table.
uint32_t num_entries() const { return num_entries_; }
using Memento = ParsedMetadata<grpc_metadata_batch>;
private:
enum { kInlineEntries = hpack_constants::kInitialTableEntries };
using EntriesVec = absl::InlinedVector<grpc_mdelem, kInlineEntries>;
/* lookup a table entry based on its hpack index */
template <bool take_ref>
grpc_mdelem Lookup(uint32_t index) const {
// Lookup, but don't ref.
const Memento* Lookup(uint32_t index) const {
// Static table comes first, just return an entry from it.
// NB: This imposes the constraint that the first
// GRPC_CHTTP2_LAST_STATIC_ENTRY entries in the core static metadata table
@ -68,27 +55,45 @@ class HPackTable {
// reading the core static metadata table here; at that point we'd need our
// own singleton static metadata in the correct order.
if (index <= hpack_constants::kLastStaticEntry) {
return g_static_mdelem_manifested[index - 1];
return &static_metadata_.memento[index - 1];
} else {
return LookupDynamic<take_ref>(index);
return LookupDynamic(index);
}
}
template <bool take_ref>
grpc_mdelem LookupDynamic(uint32_t index) const {
// add a table entry to the index
grpc_error_handle Add(Memento md) GRPC_MUST_USE_RESULT;
// Current entry count in the table.
uint32_t num_entries() const { return num_entries_; }
private:
struct StaticMementos {
StaticMementos() {
for (uint32_t i = 0; i < hpack_constants::kLastStaticEntry; i++) {
memento[i] = Memento(g_static_mdelem_manifested[i]);
}
}
Memento memento[hpack_constants::kLastStaticEntry];
};
static const StaticMementos& GetStaticMementos() {
static const StaticMementos static_mementos;
return static_mementos;
}
enum { kInlineEntries = hpack_constants::kInitialTableEntries };
using EntriesVec = absl::InlinedVector<Memento, kInlineEntries>;
const Memento* LookupDynamic(uint32_t index) const {
// Not static - find the value in the list of valid entries
const uint32_t tbl_index = index - (hpack_constants::kLastStaticEntry + 1);
if (tbl_index < num_entries_) {
uint32_t offset =
(num_entries_ - 1u - tbl_index + first_entry_) % entries_.size();
grpc_mdelem md = entries_[offset];
if (take_ref) {
GRPC_MDELEM_REF(md);
}
return md;
return &entries_[offset];
}
// Invalid entry: return error
return GRPC_MDNULL;
return nullptr;
}
void EvictOne();
@ -110,6 +115,8 @@ class HPackTable {
uint32_t max_entries_ = hpack_constants::kInitialTableEntries;
// HPack table entries
EntriesVec entries_{hpack_constants::kInitialTableEntries};
// Mementos for static data
const StaticMementos& static_metadata_;
};
} // namespace grpc_core

@ -1,65 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include <string.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include "src/core/ext/transport/chttp2/transport/internal.h"
grpc_error_handle grpc_chttp2_incoming_metadata_buffer_add(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_mdelem elem) {
buffer->size += GRPC_MDELEM_LENGTH(elem);
grpc_linked_mdelem* storage;
if (buffer->count < buffer->kPreallocatedMDElem) {
storage = &buffer->preallocated_mdelems[buffer->count];
buffer->count++;
} else {
storage = static_cast<grpc_linked_mdelem*>(
buffer->arena->Alloc(sizeof(grpc_linked_mdelem)));
}
storage->md = elem;
return buffer->batch.LinkTail(storage);
}
grpc_error_handle grpc_chttp2_incoming_metadata_buffer_replace_or_add(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_slice key,
grpc_slice value) {
if (buffer->batch.ReplaceIfExists(key, value)) return GRPC_ERROR_NONE;
return grpc_chttp2_incoming_metadata_buffer_add(
buffer, grpc_mdelem_from_slices(key, value));
}
void grpc_chttp2_incoming_metadata_buffer_set_deadline(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_millis deadline) {
if (deadline != GRPC_MILLIS_INF_FUTURE) {
buffer->batch.Set(grpc_core::GrpcTimeoutMetadata(), deadline);
} else {
buffer->batch.Remove(grpc_core::GrpcTimeoutMetadata());
}
}
void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch) {
*batch = std::move(buffer->batch);
}

@ -1,54 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H
#define GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/transport/transport.h"
struct grpc_chttp2_incoming_metadata_buffer {
explicit grpc_chttp2_incoming_metadata_buffer(grpc_core::Arena* arena)
: arena(arena) {}
~grpc_chttp2_incoming_metadata_buffer() = default;
static constexpr size_t kPreallocatedMDElem = 10;
grpc_core::Arena* arena;
size_t size = 0; // total size of metadata.
size_t count = 0; // minimum of count of metadata and kPreallocatedMDElem.
// These preallocated mdelems are used while count < kPreallocatedMDElem.
grpc_linked_mdelem preallocated_mdelems[kPreallocatedMDElem];
grpc_metadata_batch batch;
};
void grpc_chttp2_incoming_metadata_buffer_publish(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_metadata_batch* batch);
grpc_error_handle grpc_chttp2_incoming_metadata_buffer_add(
grpc_chttp2_incoming_metadata_buffer* buffer,
grpc_mdelem elem) GRPC_MUST_USE_RESULT;
// key & value ownership are transferred to this function.
grpc_error_handle grpc_chttp2_incoming_metadata_buffer_replace_or_add(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_slice key,
grpc_slice value) GRPC_MUST_USE_RESULT;
void grpc_chttp2_incoming_metadata_buffer_set_deadline(
grpc_chttp2_incoming_metadata_buffer* buffer, grpc_millis deadline);
#endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INCOMING_METADATA_H */

@ -34,7 +34,6 @@
#include "src/core/ext/transport/chttp2/transport/frame_window_update.h"
#include "src/core/ext/transport/chttp2/transport/hpack_encoder.h"
#include "src/core/ext/transport/chttp2/transport/hpack_parser.h"
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/ext/transport/chttp2/transport/stream_map.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/compression/stream_compression.h"
@ -43,6 +42,7 @@
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/timer.h"
#include "src/core/lib/transport/connectivity_state.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport_impl.h"
namespace grpc_core {
@ -589,8 +589,8 @@ struct grpc_chttp2_stream {
grpc_published_metadata_method published_metadata[2] = {};
bool final_metadata_requested = false;
grpc_chttp2_incoming_metadata_buffer initial_metadata_buffer;
grpc_chttp2_incoming_metadata_buffer trailing_metadata_buffer;
grpc_metadata_batch initial_metadata_buffer;
grpc_metadata_batch trailing_metadata_buffer;
grpc_slice_buffer frame_storage; /* protected by t combiner */

@ -329,8 +329,11 @@ static grpc_error_handle init_header_skip_frame_parser(
bool is_eoh = t->expect_continuation_stream_id != 0;
t->parser = grpc_chttp2_header_parser_parse;
t->parser_data = &t->hpack_parser;
t->hpack_parser.BeginFrame(skip_header, hpack_boundary_type(t, is_eoh),
priority_type);
t->hpack_parser.BeginFrame(
nullptr,
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE],
hpack_boundary_type(t, is_eoh), priority_type);
return GRPC_ERROR_NONE;
}
@ -342,7 +345,7 @@ static grpc_error_handle init_non_header_skip_frame_parser(
void grpc_chttp2_parsing_become_skip_parser(grpc_chttp2_transport* t) {
if (t->parser == grpc_chttp2_header_parser_parse) {
t->hpack_parser.ResetSink(skip_header);
t->hpack_parser.StopBufferingFrame();
} else {
t->parser = skip_parser;
}
@ -409,173 +412,6 @@ error_handler:
}
}
static void free_timeout(void* p) { gpr_free(p); }
static bool md_key_cmp(grpc_mdelem md, const grpc_slice& reference) {
GPR_DEBUG_ASSERT(grpc_slice_is_interned(GRPC_MDKEY(md)));
return GRPC_MDKEY(md).refcount == reference.refcount;
}
static void GPR_ATTRIBUTE_NOINLINE on_initial_header_log(
grpc_chttp2_transport* t, grpc_chttp2_stream* s, grpc_mdelem md) {
char* key = grpc_slice_to_c_string(GRPC_MDKEY(md));
char* value =
grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_INFO, "HTTP:%d:HDR:%s: %s: %s", s->id,
t->is_client ? "CLI" : "SVR", key, value);
gpr_free(key);
gpr_free(value);
}
static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
handle_timeout(grpc_chttp2_stream* s, grpc_mdelem md) {
grpc_millis* cached_timeout =
static_cast<grpc_millis*>(grpc_mdelem_get_user_data(md, free_timeout));
grpc_millis timeout;
if (cached_timeout != nullptr) {
timeout = *cached_timeout;
} else {
if (GPR_UNLIKELY(!grpc_http2_decode_timeout(GRPC_MDVALUE(md), &timeout))) {
char* val = grpc_slice_to_c_string(GRPC_MDVALUE(md));
gpr_log(GPR_ERROR, "Ignoring bad timeout value '%s'", val);
gpr_free(val);
timeout = GRPC_MILLIS_INF_FUTURE;
}
if (GRPC_MDELEM_IS_INTERNED(md)) {
/* store the result */
cached_timeout =
static_cast<grpc_millis*>(gpr_malloc(sizeof(grpc_millis)));
*cached_timeout = timeout;
grpc_mdelem_set_user_data(md, free_timeout, cached_timeout);
}
}
if (timeout != GRPC_MILLIS_INF_FUTURE) {
grpc_chttp2_incoming_metadata_buffer_set_deadline(
&s->initial_metadata_buffer,
grpc_core::ExecCtx::Get()->Now() + timeout);
}
GRPC_MDELEM_UNREF(md);
return GRPC_ERROR_NONE;
}
static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
handle_metadata_size_limit_exceeded(grpc_chttp2_transport* t,
grpc_chttp2_stream* s, grpc_mdelem md,
size_t new_size,
size_t metadata_size_limit) {
gpr_log(GPR_DEBUG,
"received initial metadata size exceeds limit (%" PRIuPTR
" vs. %" PRIuPTR
"). GRPC_ARG_MAX_METADATA_SIZE can be set to increase this limit.",
new_size, metadata_size_limit);
grpc_chttp2_cancel_stream(
t, s,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"received initial metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_RESOURCE_EXHAUSTED));
grpc_chttp2_parsing_become_skip_parser(t);
s->seen_error = true;
GRPC_MDELEM_UNREF(md);
return GRPC_ERROR_NONE;
}
static grpc_error_handle GPR_ATTRIBUTE_NOINLINE
handle_metadata_add_failure(grpc_chttp2_transport* t, grpc_chttp2_stream* s,
grpc_mdelem md, grpc_error_handle error) {
grpc_chttp2_cancel_stream(t, s, error);
grpc_chttp2_parsing_become_skip_parser(t);
s->seen_error = true;
GRPC_MDELEM_UNREF(md);
return GRPC_ERROR_NONE;
}
static grpc_error_handle on_initial_header(void* tp, grpc_mdelem md) {
GPR_TIMER_SCOPE("on_initial_header", 0);
grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
grpc_chttp2_stream* s = t->incoming_stream;
GPR_DEBUG_ASSERT(s != nullptr);
if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
on_initial_header_log(t, s, md);
}
if (md_key_cmp(md, GRPC_MDSTR_GRPC_TIMEOUT)) {
return handle_timeout(s, md);
}
const size_t new_size =
s->initial_metadata_buffer.size + GRPC_MDELEM_LENGTH(md);
const size_t metadata_size_limit =
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
if (GPR_UNLIKELY(new_size > metadata_size_limit)) {
return handle_metadata_size_limit_exceeded(t, s, md, new_size,
metadata_size_limit);
} else {
grpc_error_handle error = grpc_chttp2_incoming_metadata_buffer_add(
&s->initial_metadata_buffer, md);
if (GPR_UNLIKELY(error != GRPC_ERROR_NONE)) {
return handle_metadata_add_failure(t, s, md, error);
}
}
// Not timeout-related metadata, and no error occurred.
return GRPC_ERROR_NONE;
}
static grpc_error_handle on_trailing_header(void* tp, grpc_mdelem md) {
GPR_TIMER_SCOPE("on_trailing_header", 0);
grpc_chttp2_transport* t = static_cast<grpc_chttp2_transport*>(tp);
grpc_chttp2_stream* s = t->incoming_stream;
GPR_DEBUG_ASSERT(s != nullptr);
if (GRPC_TRACE_FLAG_ENABLED(grpc_http_trace)) {
char* key = grpc_slice_to_c_string(GRPC_MDKEY(md));
char* value =
grpc_dump_slice(GRPC_MDVALUE(md), GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_INFO, "HTTP:%d:TRL:%s: %s: %s", s->id,
t->is_client ? "CLI" : "SVR", key, value);
gpr_free(key);
gpr_free(value);
}
const size_t new_size =
s->trailing_metadata_buffer.size + GRPC_MDELEM_LENGTH(md);
const size_t metadata_size_limit =
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE];
if (new_size > metadata_size_limit) {
gpr_log(GPR_DEBUG,
"received trailing metadata size exceeds limit (%" PRIuPTR
" vs. %" PRIuPTR
"). Please note that the status is also included in the trailing "
"metadata and a large status message can also trigger this. "
"GRPC_ARG_MAX_METADATA_SIZE can be set to increase this limit.",
new_size, metadata_size_limit);
grpc_chttp2_cancel_stream(
t, s,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"received trailing metadata size exceeds limit"),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_RESOURCE_EXHAUSTED));
grpc_chttp2_parsing_become_skip_parser(t);
s->seen_error = true;
GRPC_MDELEM_UNREF(md);
} else {
grpc_error_handle error = grpc_chttp2_incoming_metadata_buffer_add(
&s->trailing_metadata_buffer, md);
if (error != GRPC_ERROR_NONE) {
grpc_chttp2_cancel_stream(t, s, error);
grpc_chttp2_parsing_become_skip_parser(t);
s->seen_error = true;
GRPC_MDELEM_UNREF(md);
}
}
return GRPC_ERROR_NONE;
}
static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
int is_continuation) {
const bool is_eoh =
@ -667,7 +503,7 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
if (t->header_eof) {
s->eos_received = true;
}
HPackParser::Sink on_header;
grpc_metadata_batch* incoming_metadata_buffer = nullptr;
switch (s->header_frames_received) {
case 0:
if (t->is_client && t->header_eof) {
@ -675,22 +511,25 @@ static grpc_error_handle init_header_frame_parser(grpc_chttp2_transport* t,
if (s->trailing_metadata_available != nullptr) {
*s->trailing_metadata_available = true;
}
on_header = [t](grpc_mdelem md) { return on_trailing_header(t, md); };
incoming_metadata_buffer = &s->trailing_metadata_buffer;
} else {
GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "parsing initial_metadata"));
on_header = [t](grpc_mdelem md) { return on_initial_header(t, md); };
incoming_metadata_buffer = &s->initial_metadata_buffer;
}
break;
case 1:
GRPC_CHTTP2_IF_TRACING(gpr_log(GPR_INFO, "parsing trailing_metadata"));
on_header = [t](grpc_mdelem md) { return on_trailing_header(t, md); };
incoming_metadata_buffer = &s->trailing_metadata_buffer;
break;
case 2:
gpr_log(GPR_ERROR, "too many header frames received");
return init_header_skip_frame_parser(t, priority_type);
}
t->hpack_parser.BeginFrame(std::move(on_header),
hpack_boundary_type(t, is_eoh), priority_type);
t->hpack_parser.BeginFrame(
incoming_metadata_buffer,
t->settings[GRPC_ACKED_SETTINGS]
[GRPC_CHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE],
hpack_boundary_type(t, is_eoh), priority_type);
return GRPC_ERROR_NONE;
}

@ -34,7 +34,6 @@
#include "src/core/ext/transport/chttp2/transport/bin_decoder.h"
#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h"
#include "src/core/ext/transport/cronet/transport/cronet_status.h"
#include "src/core/lib/debug/trace.h"
#include "src/core/lib/gpr/string.h"
@ -138,11 +137,11 @@ struct read_state {
grpc_slice_buffer read_slice_buffer;
/* vars for trailing metadata */
grpc_chttp2_incoming_metadata_buffer trailing_metadata;
grpc_metadata_batch trailing_metadata;
bool trailing_metadata_valid = false;
/* vars for initial metadata */
grpc_chttp2_incoming_metadata_buffer initial_metadata;
grpc_metadata_batch initial_metadata;
};
struct write_state {
@ -405,7 +404,7 @@ static void execute_from_storage(stream_obj* s) {
static void convert_cronet_array_to_metadata(
const bidirectional_stream_header_array* header_array,
grpc_chttp2_incoming_metadata_buffer* mds) {
grpc_metadata_batch* mds) {
for (size_t i = 0; i < header_array->count; i++) {
CRONET_LOG(GPR_DEBUG, "header key=%s, value=%s",
header_array->headers[i].key, header_array->headers[i].value);
@ -421,8 +420,7 @@ static void convert_cronet_array_to_metadata(
grpc_slice_from_static_string(header_array->headers[i].value));
}
GRPC_LOG_IF_ERROR("convert_cronet_array_to_metadata",
grpc_chttp2_incoming_metadata_buffer_add(
mds, grpc_mdelem_from_slices(key, value)));
mds->Append(grpc_mdelem_from_slices(key, value)));
}
}
@ -1152,9 +1150,8 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
stream_op->payload->recv_initial_metadata.recv_initial_metadata_ready,
GRPC_ERROR_NONE);
} else {
grpc_chttp2_incoming_metadata_buffer_publish(
&oas->s->state.rs.initial_metadata,
stream_op->payload->recv_initial_metadata.recv_initial_metadata);
*stream_op->payload->recv_initial_metadata.recv_initial_metadata =
std::move(oas->s->state.rs.initial_metadata);
grpc_core::ExecCtx::Run(
DEBUG_LOCATION,
stream_op->payload->recv_initial_metadata.recv_initial_metadata_ready,
@ -1308,9 +1305,8 @@ static enum e_op_result execute_stream_op(struct op_and_state* oas) {
error =
make_error_with_desc(grpc_error_code, stream_state->net_error, desc);
} else if (oas->s->state.rs.trailing_metadata_valid) {
grpc_chttp2_incoming_metadata_buffer_publish(
&oas->s->state.rs.trailing_metadata,
stream_op->payload->recv_trailing_metadata.recv_trailing_metadata);
*stream_op->payload->recv_trailing_metadata.recv_trailing_metadata =
std::move(oas->s->state.rs.trailing_metadata);
stream_state->rs.trailing_metadata_valid = false;
}
grpc_core::ExecCtx::Run(

@ -222,28 +222,28 @@ struct inproc_stream {
#undef STREAM_UNREF
inproc_transport* t;
grpc_metadata_batch to_read_initial_md;
grpc_stream_refcount* refs;
grpc_core::Arena* arena;
grpc_metadata_batch to_read_initial_md{arena};
uint32_t to_read_initial_md_flags = 0;
bool to_read_initial_md_filled = false;
grpc_metadata_batch to_read_trailing_md;
grpc_metadata_batch to_read_trailing_md{arena};
bool to_read_trailing_md_filled = false;
bool ops_needed = false;
// Write buffer used only during gap at init time when client-side
// stream is set up but server side stream is not yet set up
grpc_metadata_batch write_buffer_initial_md;
grpc_metadata_batch write_buffer_initial_md{arena};
bool write_buffer_initial_md_filled = false;
uint32_t write_buffer_initial_md_flags = 0;
grpc_millis write_buffer_deadline = GRPC_MILLIS_INF_FUTURE;
grpc_metadata_batch write_buffer_trailing_md;
grpc_metadata_batch write_buffer_trailing_md{arena};
bool write_buffer_trailing_md_filled = false;
grpc_error_handle write_buffer_cancel_error = GRPC_ERROR_NONE;
struct inproc_stream* other_side;
bool other_side_closed = false; // won't talk anymore
bool write_buffer_other_side_closed = false; // on hold
grpc_stream_refcount* refs;
grpc_core::Arena* arena;
grpc_transport_stream_op_batch* send_message_op = nullptr;
grpc_transport_stream_op_batch* send_trailing_md_op = nullptr;
@ -405,7 +405,7 @@ void fail_helper_locked(inproc_stream* s, grpc_error_handle error) {
// Send trailing md to the other side indicating cancellation
s->trailing_md_sent = true;
grpc_metadata_batch fake_md;
grpc_metadata_batch fake_md(s->arena);
inproc_stream* other = s->other_side;
grpc_metadata_batch* dest = (other == nullptr)
? &s->write_buffer_trailing_md
@ -428,7 +428,7 @@ void fail_helper_locked(inproc_stream* s, grpc_error_handle error) {
if (!s->t->is_client) {
// If this is a server, provide initial metadata with a path and authority
// since it expects that as well as no error yet
grpc_metadata_batch fake_md;
grpc_metadata_batch fake_md(s->arena);
grpc_linked_mdelem* path_md =
static_cast<grpc_linked_mdelem*>(s->arena->Alloc(sizeof(*path_md)));
path_md->md = grpc_mdelem_from_slices(g_fake_path_key, g_fake_path_value);
@ -899,7 +899,7 @@ bool cancel_stream_locked(inproc_stream* s, grpc_error_handle error) {
// already have
s->trailing_md_sent = true;
grpc_metadata_batch cancel_md;
grpc_metadata_batch cancel_md(s->arena);
grpc_metadata_batch* dest = (other == nullptr)
? &s->write_buffer_trailing_md

@ -30,6 +30,7 @@
#include <stddef.h>
#include <atomic>
#include <memory>
#include <new>
#include <utility>
@ -116,6 +117,15 @@ class Arena {
Zone* last_zone_ = nullptr;
};
// Smart pointer for arenas when the final size is not required.
struct ScopedArenaDeleter {
void operator()(Arena* arena) { arena->Destroy(); }
};
using ScopedArenaPtr = std::unique_ptr<Arena, ScopedArenaDeleter>;
inline ScopedArenaPtr MakeScopedArena(size_t initial_size) {
return ScopedArenaPtr(Arena::Create(initial_size));
}
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_GPRPP_ARENA_H */

@ -68,10 +68,14 @@ class ChunkedVector {
std::swap(other->append_, append_);
}
Arena* arena() const { return arena_; }
// Append a new element to the end of the vector.
template <typename... Args>
void EmplaceBack(Args&&... args) {
AppendSlot()->Init(std::forward<Args>(args)...);
T* EmplaceBack(Args&&... args) {
auto* p = AppendSlot();
p->Init(std::forward<Args>(args)...);
return &**p;
}
// Remove the last element and return it.

@ -187,7 +187,10 @@ struct grpc_call {
grpc_transport_stream_op_batch_payload stream_op_payload;
/* first idx: is_receiving, second idx: is_trailing */
grpc_metadata_batch metadata_batch[2][2] = {};
grpc_metadata_batch send_initial_metadata{arena};
grpc_metadata_batch send_trailing_metadata{arena};
grpc_metadata_batch recv_initial_metadata{arena};
grpc_metadata_batch recv_trailing_metadata{arena};
/* Buffered read metadata waiting to be returned to the application.
Element 0 is initial metadata, element 1 is trailing metadata. */
@ -541,9 +544,8 @@ static void release_call(void* call, grpc_error_handle /*error*/) {
static void destroy_call(void* call, grpc_error_handle /*error*/) {
GPR_TIMER_SCOPE("destroy_call", 0);
grpc_call* c = static_cast<grpc_call*>(call);
for (int i = 0; i < 2; i++) {
c->metadata_batch[1 /* is_receiving */][i /* is_initial */].Clear();
}
c->recv_initial_metadata.Clear();
c->recv_trailing_metadata.Clear();
c->receiving_stream.reset();
parent_call* pc = get_parent_call(c);
if (pc != nullptr) {
@ -902,8 +904,8 @@ static int prepare_application_metadata(grpc_call* call, int count,
int additional_metadata_count) {
int total_count = count + additional_metadata_count;
int i;
grpc_metadata_batch* batch =
&call->metadata_batch[0 /* is_receiving */][is_trailing];
grpc_metadata_batch* batch = is_trailing ? &call->send_trailing_metadata
: &call->send_initial_metadata;
for (i = 0; i < total_count; i++) {
grpc_metadata* md = get_md_elem(metadata, additional_metadata, i, count);
grpc_linked_mdelem* l = linked_from_md(md);
@ -1176,7 +1178,7 @@ static void post_batch_completion(batch_control* bctl) {
grpc_error_handle error = GRPC_ERROR_REF(bctl->batch_error.get());
if (bctl->op.send_initial_metadata) {
call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */].Clear();
call->send_initial_metadata.Clear();
}
if (bctl->op.send_message) {
if (bctl->op.payload->send_message.stream_write_closed &&
@ -1188,7 +1190,7 @@ static void post_batch_completion(batch_control* bctl) {
call->sending_message = false;
}
if (bctl->op.send_trailing_metadata) {
call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */].Clear();
call->send_trailing_metadata.Clear();
}
if (bctl->op.recv_trailing_metadata) {
/* propagate cancellation to any interested children */
@ -1460,8 +1462,7 @@ static void receiving_initial_metadata_ready(void* bctlp,
GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_initial_metadata_ready");
if (error == GRPC_ERROR_NONE) {
grpc_metadata_batch* md =
&call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
grpc_metadata_batch* md = &call->recv_initial_metadata;
recv_initial_filter(call, md);
/* TODO(ctiller): this could be moved into recv_initial_filter now */
@ -1517,8 +1518,7 @@ static void receiving_trailing_metadata_ready(void* bctlp,
batch_control* bctl = static_cast<batch_control*>(bctlp);
grpc_call* call = bctl->call;
GRPC_CALL_COMBINER_STOP(&call->call_combiner, "recv_trailing_metadata_ready");
grpc_metadata_batch* md =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
grpc_metadata_batch* md = &call->recv_trailing_metadata;
recv_trailing_filter(call, md, GRPC_ERROR_REF(error));
finish_batch_step(bctl);
}
@ -1653,11 +1653,11 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
}
/* TODO(ctiller): just make these the same variable? */
if (call->is_client && call->send_deadline != GRPC_MILLIS_INF_FUTURE) {
call->metadata_batch[0][0].Set(grpc_core::GrpcTimeoutMetadata(),
call->send_deadline);
call->send_initial_metadata.Set(grpc_core::GrpcTimeoutMetadata(),
call->send_deadline);
}
stream_op_payload->send_initial_metadata.send_initial_metadata =
&call->metadata_batch[0 /* is_receiving */][0 /* is_trailing */];
&call->send_initial_metadata;
stream_op_payload->send_initial_metadata.send_initial_metadata_flags =
op->flags;
if (call->is_client) {
@ -1714,7 +1714,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
stream_op->send_trailing_metadata = true;
call->sent_final_op = true;
stream_op_payload->send_trailing_metadata.send_trailing_metadata =
&call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
&call->send_trailing_metadata;
has_send_ops = true;
break;
}
@ -1784,7 +1784,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
goto done_with_error;
}
stream_op_payload->send_trailing_metadata.send_trailing_metadata =
&call->metadata_batch[0 /* is_receiving */][1 /* is_trailing */];
&call->send_trailing_metadata;
stream_op_payload->send_trailing_metadata.sent =
&call->sent_server_trailing_metadata;
has_send_ops = true;
@ -1808,7 +1808,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
grpc_schedule_on_exec_ctx);
stream_op->recv_initial_metadata = true;
stream_op_payload->recv_initial_metadata.recv_initial_metadata =
&call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */];
&call->recv_initial_metadata;
stream_op_payload->recv_initial_metadata.recv_initial_metadata_ready =
&call->receiving_initial_metadata_ready;
if (call->is_client) {
@ -1869,7 +1869,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
op->data.recv_status_on_client.error_string;
stream_op->recv_trailing_metadata = true;
stream_op_payload->recv_trailing_metadata.recv_trailing_metadata =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
&call->recv_trailing_metadata;
stream_op_payload->recv_trailing_metadata.collect_stats =
&call->final_info.stats.transport_stream_stats;
GRPC_CLOSURE_INIT(&call->receiving_trailing_metadata_ready,
@ -1899,7 +1899,7 @@ static grpc_call_error call_start_batch(grpc_call* call, const grpc_op* ops,
op->data.recv_close_on_server.cancelled;
stream_op->recv_trailing_metadata = true;
stream_op_payload->recv_trailing_metadata.recv_trailing_metadata =
&call->metadata_batch[1 /* is_receiving */][1 /* is_trailing */];
&call->recv_trailing_metadata;
stream_op_payload->recv_trailing_metadata.collect_stats =
&call->final_info.stats.transport_stream_stats;
GRPC_CLOSURE_INIT(&call->receiving_trailing_metadata_ready,
@ -1935,7 +1935,7 @@ done_with_error:
/* reverse any mutations that occurred */
if (stream_op->send_initial_metadata) {
call->sent_initial_metadata = false;
call->metadata_batch[0][0].Clear();
call->send_initial_metadata.Clear();
}
if (stream_op->send_message) {
call->sending_message = false;
@ -1943,7 +1943,7 @@ done_with_error:
}
if (stream_op->send_trailing_metadata) {
call->sent_final_op = false;
call->metadata_batch[0][1].Clear();
call->send_trailing_metadata.Clear();
}
if (stream_op->recv_initial_metadata) {
call->received_initial_metadata = false;
@ -2008,9 +2008,7 @@ grpc_compression_algorithm grpc_call_compression_for_level(
bool grpc_call_is_trailers_only(const grpc_call* call) {
bool result = call->is_trailers_only;
GPR_DEBUG_ASSERT(
!result ||
call->metadata_batch[1 /* is_receiving */][0 /* is_trailing */].empty());
GPR_DEBUG_ASSERT(!result || call->recv_initial_metadata.empty());
return result;
}

@ -45,6 +45,7 @@ void grpc_metadata_batch_copy(grpc_metadata_batch* src,
grpc_metadata_batch* dst,
grpc_linked_mdelem* storage) {
dst->Clear();
// TODO(ctiller): this should be templated and automatically derived.
if (auto* p = src->get_pointer(grpc_core::GrpcTimeoutMetadata())) {
dst->Set(grpc_core::GrpcTimeoutMetadata(), *p);
}

@ -23,6 +23,7 @@
#include <stdbool.h>
#include "absl/strings/match.h"
#include "absl/strings/str_join.h"
#include "absl/types/optional.h"
@ -30,10 +31,14 @@
#include <grpc/slice.h>
#include <grpc/support/time.h>
#include "src/core/lib/gprpp/chunked_vector.h"
#include "src/core/lib/gprpp/table.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/metadata.h"
#include "src/core/lib/transport/parsed_metadata.h"
#include "src/core/lib/transport/static_metadata.h"
#include "src/core/lib/transport/timeout_encoding.h"
typedef struct grpc_linked_mdelem {
grpc_linked_mdelem() {}
@ -76,7 +81,22 @@ namespace grpc_core {
// should not need to.
struct GrpcTimeoutMetadata {
using ValueType = grpc_millis;
using MementoType = grpc_millis;
static const char* key() { return "grpc-timeout"; }
static MementoType ParseMemento(const grpc_slice& value) {
grpc_millis timeout;
if (GPR_UNLIKELY(!grpc_http2_decode_timeout(value, &timeout))) {
timeout = GRPC_MILLIS_INF_FUTURE;
}
return timeout;
}
static ValueType MementoToValue(MementoType timeout) {
if (timeout == GRPC_MILLIS_INF_FUTURE) {
return GRPC_MILLIS_INF_FUTURE;
}
return grpc_core::ExecCtx::Get()->Now() + timeout;
}
static MementoType DisplayValue(MementoType x) { return x; }
};
// MetadataMap encodes the mapping of metadata keys to metadata values.
@ -96,13 +116,44 @@ struct GrpcTimeoutMetadata {
// Each trait object has the following signature:
// // Traits for the grpc-xyz metadata field:
// struct GrpcXyzMetadata {
// // The type that's stored on MetadataBatch
// using ValueType = ...;
// // The type that's stored in compression/decompression tables
// using MementoType = ...;
// // The string key for this metadata type (for transports that require it)
// static constexpr char* key() { return "grpc-xyz"; }
// // Parse a memento from a slice
// static MementoType ParseMemento(const grpc_slice& value) { ... }
// // Convert a memento to a value
// static ValueType MementoToValue(MementoType memento) { ... }
// // Convert a value to something that can be passed to StrCat and displayed
// // for debugging
// static SomeStrCatableType DisplayValue(MementoType value) { ... }
// };
//
// About parsing and mementos:
//
// Many gRPC transports exchange metadata as key/value strings, but also allow
// for a more efficient representation as a single integer. We can use this
// integer representation to avoid reparsing too, by storing the parsed value
// in the compression table. This is what mementos are used for.
//
// A trait offers the capability to turn a slice into a memento via
// ParseMemento. This is exposed to users of MetadataMap via the Parse() method,
// that returns a ParsedMetadata object. That ParsedMetadata object can in turn
// be used to set the same value on many different MetadataMaps without having
// to reparse.
//
// Implementation wise, ParsedMetadata is a type erased wrapper around
// MementoType. When we set a value on MetadataMap, we first turn that memento
// into a value. For most types, this is going to be a no-op, but for example
// for grpc-timeout we make the memento the timeout expressed on the wire, but
// we make the value the timestamp of when the timeout will expire (i.e. the
// deadline).
template <typename... Traits>
class MetadataMap {
public:
MetadataMap();
explicit MetadataMap(Arena* arena);
~MetadataMap();
MetadataMap(const MetadataMap&) = delete;
@ -172,6 +223,31 @@ class MetadataMap {
table_.template clear<Value<Which>>();
}
// Parse metadata from a key/value pair, and return an object representing
// that result.
template <class KeySlice, class ValueSlice>
static ParsedMetadata<MetadataMap> Parse(const KeySlice& key,
const ValueSlice& value) {
auto key_view = StringViewFromSlice(key);
// hack for now.
if (key_view == GrpcTimeoutMetadata::key()) {
ParsedMetadata<MetadataMap> out(
GrpcTimeoutMetadata(), GrpcTimeoutMetadata::ParseMemento(value),
ParsedMetadata<MetadataMap>::TransportSize(GRPC_SLICE_LENGTH(key),
GRPC_SLICE_LENGTH(value)));
grpc_slice_unref_internal(key);
grpc_slice_unref_internal(value);
return out;
}
return ParsedMetadata<MetadataMap>(grpc_mdelem_from_slices(key, value));
}
// Set a value from a parsed metadata object.
GRPC_MUST_USE_RESULT grpc_error_handle
Set(const ParsedMetadata<MetadataMap>& m) {
return m.SetOnContainer(this);
}
//
// All APIs below this point are subject to change.
//
@ -208,6 +284,16 @@ class MetadataMap {
return error;
}
GRPC_MUST_USE_RESULT grpc_error_handle Append(grpc_mdelem md) {
return AddTail(elem_storage_.EmplaceBack(), md);
}
GRPC_MUST_USE_RESULT grpc_error_handle ReplaceOrAppend(grpc_slice key,
grpc_slice value) {
if (ReplaceIfExists(key, value)) return GRPC_ERROR_NONE;
return Append(grpc_mdelem_from_slices(key, value));
}
// Set key to value if it exists and return true, otherwise return false.
// If this function returns true, it takes ownership of key and value.
// If this function returns false, it does not take ownership of key nor
@ -384,6 +470,8 @@ class MetadataMap {
/** Metadata elements in this batch */
grpc_mdelem_list list_;
grpc_metadata_batch_callouts idx_;
// Backing store for added metadata.
ChunkedVector<grpc_linked_mdelem, 10> elem_storage_;
};
template <typename... Traits>
@ -409,7 +497,7 @@ void MetadataMap<Traits...>::AssertOk() {
#endif /* NDEBUG */
template <typename... Traits>
MetadataMap<Traits...>::MetadataMap() {
MetadataMap<Traits...>::MetadataMap(Arena* arena) : elem_storage_(arena) {
memset(&list_, 0, sizeof(list_));
memset(&idx_, 0, sizeof(idx_));
}
@ -636,8 +724,11 @@ grpc_error_handle MetadataMap<Traits...>::Substitute(
template <typename... Traits>
void MetadataMap<Traits...>::Clear() {
// TODO(ctiller): implement this without deconstructing/reconstructing once
// linked_mdelem is no longer a thing.
auto* arena = elem_storage_.arena();
this->~MetadataMap();
new (this) MetadataMap();
new (this) MetadataMap(arena);
}
template <typename... Traits>

@ -0,0 +1,260 @@
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GRPC_CORE_LIB_TRANSPORT_PARSED_METADATA_H
#define GRPC_CORE_LIB_TRANSPORT_PARSED_METADATA_H
#include <grpc/support/port_platform.h>
#include <cstdint>
#include <type_traits>
#include "absl/meta/type_traits.h"
#include "absl/strings/match.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/surface/validate_metadata.h"
#include "src/core/lib/transport/metadata.h"
namespace grpc_core {
namespace metadata_detail {
// Helper to determine whether a traits metadata is inlinable inside a memento,
// or (if not) we'll need to take the memory allocation path.
template <typename Which>
struct HasSimpleMemento {
static constexpr bool value =
std::is_trivial<typename Which::MementoType>::value &&
sizeof(typename Which::MementoType) <= sizeof(intptr_t);
};
} // namespace metadata_detail
// A parsed metadata value.
// This type captures a type erased MementoType from one trait of
// MetadataContainer, and provides utilities to manipulate that and to set it on
// a MetadataContainer.
template <typename MetadataContainer>
class ParsedMetadata {
public:
// Construct metadata from a trait Which of MetadataContainer.
// Two versions: the first is for simple inlinable mementos, and the second
// forces an allocation.
template <typename Which>
ParsedMetadata(
Which,
absl::enable_if_t<metadata_detail::HasSimpleMemento<Which>::value,
typename Which::MementoType>
value,
uint32_t transport_size)
: vtable_(ParsedMetadata::template TrivialTraitVTable<Which>()),
value_(static_cast<intptr_t>(value)),
transport_size_(transport_size) {}
template <typename Which>
ParsedMetadata(
Which,
absl::enable_if_t<!metadata_detail::HasSimpleMemento<Which>::value,
typename Which::MementoType>
value,
uint32_t transport_size)
: vtable_(ParsedMetadata::template NonTrivialTraitVTable<Which>()),
value_(
reinterpret_cast<intptr_t>(new typename Which::MementoType(value))),
transport_size_(transport_size) {}
// Takes ownership of elem
explicit ParsedMetadata(grpc_mdelem elem)
: vtable_(grpc_is_binary_header_internal(GRPC_MDKEY(elem))
? MdelemVtable<true>()
: MdelemVtable<false>()),
value_(static_cast<intptr_t>(elem.payload)),
transport_size_(GRPC_MDELEM_LENGTH(elem)) {}
ParsedMetadata() : vtable_(EmptyVTable()) {}
~ParsedMetadata() { vtable_->destroy(value_); }
// Non copyable, but movable.
ParsedMetadata(const ParsedMetadata&) = delete;
ParsedMetadata& operator=(const ParsedMetadata&) = delete;
ParsedMetadata(ParsedMetadata&& other) noexcept
: vtable_(other.vtable_),
value_(other.value_),
transport_size_(other.transport_size_) {
other.vtable_ = EmptyVTable();
}
ParsedMetadata& operator=(ParsedMetadata&& other) noexcept {
vtable_ = other.vtable_;
value_ = other.value_;
transport_size_ = other.transport_size_;
other.vtable_ = EmptyVTable();
return *this;
}
// Set this parsed value on a container.
GRPC_MUST_USE_RESULT grpc_error_handle
SetOnContainer(MetadataContainer* container) const {
return vtable_->set(value_, container);
}
// Is this a binary header or not?
bool is_binary_header() const { return vtable_->is_binary_header; }
// HTTP2 defined storage size of this metadatum.
uint32_t transport_size() const { return transport_size_; }
// Create a new parsed metadata with the same key but a different value.
ParsedMetadata WithNewValue(const grpc_slice& value) const {
return vtable_->with_new_value(value_, value);
}
std::string DebugString() const { return vtable_->debug_string(value_); }
// TODO(ctiller): move to transport
static uint32_t TransportSize(uint32_t key_size, uint32_t value_size) {
// TODO(ctiller): use hpack constant?
return key_size + value_size + 32;
}
private:
struct VTable {
const bool is_binary_header;
void (*const destroy)(intptr_t value);
grpc_error_handle (*const set)(intptr_t value,
MetadataContainer* container);
ParsedMetadata (*const with_new_value)(intptr_t value,
const grpc_slice& new_value);
std::string (*debug_string)(intptr_t value);
};
static const VTable* EmptyVTable();
template <typename Which>
static const VTable* TrivialTraitVTable();
template <typename Which>
static const VTable* NonTrivialTraitVTable();
template <bool kIsBinaryHeader>
static const VTable* MdelemVtable();
const VTable* vtable_;
intptr_t value_;
uint32_t transport_size_;
};
template <typename MetadataContainer>
const typename ParsedMetadata<MetadataContainer>::VTable*
ParsedMetadata<MetadataContainer>::EmptyVTable() {
static const VTable vtable = {
false,
// destroy
[](intptr_t) {},
// set
[](intptr_t, MetadataContainer*) { return GRPC_ERROR_NONE; },
// with_new_value
[](intptr_t, const grpc_slice&) { return ParsedMetadata(); },
// debug_string
[](intptr_t) -> std::string { return "empty"; }};
return &vtable;
}
template <typename MetadataContainer>
template <typename Which>
const typename ParsedMetadata<MetadataContainer>::VTable*
ParsedMetadata<MetadataContainer>::TrivialTraitVTable() {
static const VTable vtable = {
absl::EndsWith(Which::key(), "-bin"),
// destroy
[](intptr_t) {},
// set
[](intptr_t value, MetadataContainer* map) {
map->Set(Which(), Which::MementoToValue(
static_cast<typename Which::MementoType>(value)));
return GRPC_ERROR_NONE;
},
// with_new_value
[](intptr_t, const grpc_slice& value) {
return ParsedMetadata(
Which(), Which::ParseMemento(value),
TransportSize(strlen(Which::key()), GRPC_SLICE_LENGTH(value)));
},
// debug_string
[](intptr_t value) {
return absl::StrCat(Which::key(), ": ", Which::DisplayValue(value));
}};
return &vtable;
}
template <typename MetadataContainer>
template <typename Which>
const typename ParsedMetadata<MetadataContainer>::VTable*
ParsedMetadata<MetadataContainer>::NonTrivialTraitVTable() {
static const VTable vtable = {
absl::EndsWith(Which::key(), "-bin"),
// destroy
[](intptr_t value) {
delete reinterpret_cast<typename Which::MementoType*>(value);
},
// set
[](intptr_t value, MetadataContainer* map) {
auto* p = reinterpret_cast<typename Which::MementoType*>(value);
map->Set(Which(), Which::MementoToValue(*p));
return GRPC_ERROR_NONE;
},
// with_new_value
[](intptr_t, const grpc_slice& value) {
return ParsedMetadata(
Which(), Which::ParseMemento(value),
TransportSize(strlen(Which::key()), GRPC_SLICE_LENGTH(value)));
},
// debug_string
[](intptr_t value) {
auto* p = reinterpret_cast<typename Which::MementoType*>(value);
return absl::StrCat(Which::key(), ": ", Which::DisplayValue(*p));
}};
return &vtable;
}
template <typename MetadataContainer>
template <bool kIsBinaryHeader>
const typename ParsedMetadata<MetadataContainer>::VTable*
ParsedMetadata<MetadataContainer>::MdelemVtable() {
static const VTable vtable = {
kIsBinaryHeader,
// destroy
[](intptr_t value) { GRPC_MDELEM_UNREF(grpc_mdelem{uintptr_t(value)}); },
// set
[](intptr_t value, MetadataContainer* map) {
auto md = GRPC_MDELEM_REF(grpc_mdelem{uintptr_t(value)});
auto err = map->Append(md);
// If an error occurs, md is not consumed and we need to.
// This is an awful API, but that's why we're replacing it.
if (err != GRPC_ERROR_NONE) {
GRPC_MDELEM_UNREF(md);
}
return err;
},
// with_new_value
[](intptr_t value, const grpc_slice& value_slice) {
grpc_mdelem elem{uintptr_t(value)};
return ParsedMetadata(grpc_mdelem_from_slices(
static_cast<const ManagedMemorySlice&>(
grpc_slice_ref_internal(GRPC_MDKEY(elem))),
value_slice));
},
// debug_string
[](intptr_t value) {
grpc_mdelem elem{uintptr_t(value)};
return absl::StrCat(StringViewFromSlice(GRPC_MDKEY(elem)), ": ",
StringViewFromSlice(GRPC_MDVALUE(elem)));
}};
return &vtable;
}
} // namespace grpc_core
#endif // GRPC_CORE_LIB_TRANSPORT_PARSED_METADATA_H

@ -119,7 +119,6 @@ CORE_SOURCE_FILES = [
'src/core/ext/transport/chttp2/transport/hpack_utils.cc',
'src/core/ext/transport/chttp2/transport/http2_settings.cc',
'src/core/ext/transport/chttp2/transport/huffsyms.cc',
'src/core/ext/transport/chttp2/transport/incoming_metadata.cc',
'src/core/ext/transport/chttp2/transport/parsing.cc',
'src/core/ext/transport/chttp2/transport/stream_lists.cc',
'src/core/ext/transport/chttp2/transport/stream_map.cc',

@ -47,11 +47,8 @@ struct Comparison {
class Fuzzer {
public:
Fuzzer() : arena_(Arena::Create(128)) {}
~Fuzzer() {
vectors_.clear();
arena_->Destroy();
}
Fuzzer() = default;
~Fuzzer() = default;
void Act(const chunked_vector_fuzzer::Action& action) {
switch (action.action_type_case()) {
@ -81,7 +78,8 @@ class Fuzzer {
auto it_from = vectors_.find(action.copy().from());
if (it_from == vectors_.end()) {
it_from =
vectors_.emplace(action.copy().from(), Comparison(arena_)).first;
vectors_.emplace(action.copy().from(), Comparison(arena_.get()))
.first;
}
auto it_to = vectors_.find(action.copy().to());
if (it_to == vectors_.end()) {
@ -98,7 +96,8 @@ class Fuzzer {
auto it_from = vectors_.find(action.move().from());
if (it_from == vectors_.end()) {
it_from =
vectors_.emplace(action.move().from(), Comparison(arena_)).first;
vectors_.emplace(action.move().from(), Comparison(arena_.get()))
.first;
}
auto it_to = vectors_.find(action.move().to());
if (it_to == vectors_.end()) {
@ -137,10 +136,10 @@ class Fuzzer {
if (it != vectors_.end()) {
return &it->second;
}
return &vectors_.emplace(index, Comparison(arena_)).first->second;
return &vectors_.emplace(index, Comparison(arena_.get())).first->second;
}
Arena* arena_;
ScopedArenaPtr arena_ = MakeScopedArena(128);
std::map<int, Comparison> vectors_;
};
} // namespace grpc_core

@ -23,140 +23,125 @@ static constexpr size_t kInitialArenaSize = 1024;
static constexpr size_t kChunkSize = 3;
TEST(ChunkedVector, Noop) {
auto* arena = Arena::Create(kInitialArenaSize);
{
ChunkedVector<int, kChunkSize> v(arena);
EXPECT_EQ(0, v.size());
}
arena->Destroy();
auto arena = MakeScopedArena(kInitialArenaSize);
ChunkedVector<int, kChunkSize> v(arena.get());
EXPECT_EQ(0, v.size());
}
TEST(ChunkedVector, Stack) {
auto* arena = Arena::Create(kInitialArenaSize);
{
ChunkedVector<int, kChunkSize> v(arena);
// Populate 2 chunks of memory, and 2/3 of a final chunk.
EXPECT_EQ(0, v.size());
v.EmplaceBack(1);
EXPECT_EQ(1, v.size());
v.EmplaceBack(2);
EXPECT_EQ(2, v.size());
v.EmplaceBack(3);
EXPECT_EQ(3, v.size());
v.EmplaceBack(4);
EXPECT_EQ(4, v.size());
v.EmplaceBack(5);
EXPECT_EQ(5, v.size());
v.EmplaceBack(6);
EXPECT_EQ(6, v.size());
v.EmplaceBack(7);
EXPECT_EQ(7, v.size());
v.EmplaceBack(8);
EXPECT_EQ(8, v.size());
// Now pop all of them out and check the expected ordering.
EXPECT_EQ(8, v.PopBack());
EXPECT_EQ(7, v.size());
EXPECT_EQ(7, v.PopBack());
EXPECT_EQ(6, v.size());
EXPECT_EQ(6, v.PopBack());
EXPECT_EQ(5, v.size());
EXPECT_EQ(5, v.PopBack());
EXPECT_EQ(4, v.size());
EXPECT_EQ(4, v.PopBack());
EXPECT_EQ(3, v.size());
EXPECT_EQ(3, v.PopBack());
EXPECT_EQ(2, v.size());
EXPECT_EQ(2, v.PopBack());
EXPECT_EQ(1, v.size());
EXPECT_EQ(1, v.PopBack());
EXPECT_EQ(0, v.size());
}
arena->Destroy();
auto arena = MakeScopedArena(kInitialArenaSize);
ChunkedVector<int, kChunkSize> v(arena.get());
// Populate 2 chunks of memory, and 2/3 of a final chunk.
EXPECT_EQ(0, v.size());
v.EmplaceBack(1);
EXPECT_EQ(1, v.size());
v.EmplaceBack(2);
EXPECT_EQ(2, v.size());
v.EmplaceBack(3);
EXPECT_EQ(3, v.size());
v.EmplaceBack(4);
EXPECT_EQ(4, v.size());
v.EmplaceBack(5);
EXPECT_EQ(5, v.size());
v.EmplaceBack(6);
EXPECT_EQ(6, v.size());
v.EmplaceBack(7);
EXPECT_EQ(7, v.size());
v.EmplaceBack(8);
EXPECT_EQ(8, v.size());
// Now pop all of them out and check the expected ordering.
EXPECT_EQ(8, v.PopBack());
EXPECT_EQ(7, v.size());
EXPECT_EQ(7, v.PopBack());
EXPECT_EQ(6, v.size());
EXPECT_EQ(6, v.PopBack());
EXPECT_EQ(5, v.size());
EXPECT_EQ(5, v.PopBack());
EXPECT_EQ(4, v.size());
EXPECT_EQ(4, v.PopBack());
EXPECT_EQ(3, v.size());
EXPECT_EQ(3, v.PopBack());
EXPECT_EQ(2, v.size());
EXPECT_EQ(2, v.PopBack());
EXPECT_EQ(1, v.size());
EXPECT_EQ(1, v.PopBack());
EXPECT_EQ(0, v.size());
}
TEST(ChunkedVector, Iterate) {
auto* arena = Arena::Create(kInitialArenaSize);
{
ChunkedVector<int, kChunkSize> v(arena);
v.EmplaceBack(1);
v.EmplaceBack(2);
v.EmplaceBack(3);
v.EmplaceBack(4);
v.EmplaceBack(5);
v.EmplaceBack(6);
v.EmplaceBack(7);
v.EmplaceBack(8);
auto it = v.begin();
EXPECT_EQ(1, *it);
++it;
EXPECT_EQ(2, *it);
++it;
EXPECT_EQ(3, *it);
++it;
EXPECT_EQ(4, *it);
++it;
EXPECT_EQ(5, *it);
++it;
EXPECT_EQ(6, *it);
++it;
EXPECT_EQ(7, *it);
++it;
EXPECT_EQ(8, *it);
++it;
EXPECT_EQ(v.end(), it);
}
arena->Destroy();
auto arena = MakeScopedArena(kInitialArenaSize);
ChunkedVector<int, kChunkSize> v(arena.get());
v.EmplaceBack(1);
v.EmplaceBack(2);
v.EmplaceBack(3);
v.EmplaceBack(4);
v.EmplaceBack(5);
v.EmplaceBack(6);
v.EmplaceBack(7);
v.EmplaceBack(8);
auto it = v.begin();
EXPECT_EQ(1, *it);
++it;
EXPECT_EQ(2, *it);
++it;
EXPECT_EQ(3, *it);
++it;
EXPECT_EQ(4, *it);
++it;
EXPECT_EQ(5, *it);
++it;
EXPECT_EQ(6, *it);
++it;
EXPECT_EQ(7, *it);
++it;
EXPECT_EQ(8, *it);
++it;
EXPECT_EQ(v.end(), it);
}
TEST(ChunkedVector, ConstIterate) {
auto* arena = Arena::Create(kInitialArenaSize);
{
ChunkedVector<int, kChunkSize> v(arena);
v.EmplaceBack(1);
v.EmplaceBack(2);
v.EmplaceBack(3);
v.EmplaceBack(4);
v.EmplaceBack(5);
v.EmplaceBack(6);
v.EmplaceBack(7);
v.EmplaceBack(8);
auto it = v.cbegin();
EXPECT_EQ(1, *it);
++it;
EXPECT_EQ(2, *it);
++it;
EXPECT_EQ(3, *it);
++it;
EXPECT_EQ(4, *it);
++it;
EXPECT_EQ(5, *it);
++it;
EXPECT_EQ(6, *it);
++it;
EXPECT_EQ(7, *it);
++it;
EXPECT_EQ(8, *it);
++it;
EXPECT_EQ(v.cend(), it);
}
arena->Destroy();
auto arena = MakeScopedArena(kInitialArenaSize);
ChunkedVector<int, kChunkSize> v(arena.get());
v.EmplaceBack(1);
v.EmplaceBack(2);
v.EmplaceBack(3);
v.EmplaceBack(4);
v.EmplaceBack(5);
v.EmplaceBack(6);
v.EmplaceBack(7);
v.EmplaceBack(8);
auto it = v.cbegin();
EXPECT_EQ(1, *it);
++it;
EXPECT_EQ(2, *it);
++it;
EXPECT_EQ(3, *it);
++it;
EXPECT_EQ(4, *it);
++it;
EXPECT_EQ(5, *it);
++it;
EXPECT_EQ(6, *it);
++it;
EXPECT_EQ(7, *it);
++it;
EXPECT_EQ(8, *it);
++it;
EXPECT_EQ(v.cend(), it);
}
TEST(ChunkedVector, Clear) {
auto* arena = Arena::Create(kInitialArenaSize);
{
ChunkedVector<int, kChunkSize> v(arena);
v.EmplaceBack(1);
EXPECT_EQ(v.size(), 1);
v.Clear();
EXPECT_EQ(v.size(), 0);
EXPECT_EQ(v.begin(), v.end());
}
arena->Destroy();
auto arena = MakeScopedArena(kInitialArenaSize);
ChunkedVector<int, kChunkSize> v(arena.get());
v.EmplaceBack(1);
EXPECT_EQ(v.size(), 1);
v.Clear();
EXPECT_EQ(v.size(), 0);
EXPECT_EQ(v.begin(), v.end());
}
} // namespace testing

@ -91,6 +91,20 @@ grpc_cc_test(
],
)
grpc_cc_test(
name = "parsed_metadata_test",
srcs = ["parsed_metadata_test.cc"],
external_deps = [
"gtest",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "metadata_test",
srcs = ["metadata_test.cc"],

@ -193,7 +193,8 @@ struct MakeSendInitialMetadata {
std::vector<grpc_linked_mdelem> storage;
grpc_linked_mdelem method_ref_storage;
grpc_metadata_batch grpc_initial_metadata{};
grpc_core::ScopedArenaPtr arena = grpc_core::MakeScopedArena(1024);
grpc_metadata_batch grpc_initial_metadata{arena.get()};
};
struct MakeSendMessage {
@ -224,7 +225,8 @@ struct MakeSendTrailingMetadata {
&grpc_trailing_metadata;
}
grpc_metadata_batch grpc_trailing_metadata{};
grpc_core::ScopedArenaPtr arena = grpc_core::MakeScopedArena(1024);
grpc_metadata_batch grpc_trailing_metadata{arena.get()};
};
struct MakeRecvInitialMetadata {
@ -246,7 +248,8 @@ struct MakeRecvInitialMetadata {
~MakeRecvInitialMetadata() {}
MockGrpcClosure ready;
grpc_metadata_batch grpc_initial_metadata;
grpc_core::ScopedArenaPtr arena = grpc_core::MakeScopedArena(1024);
grpc_metadata_batch grpc_initial_metadata{arena.get()};
absl::Notification notification;
};
@ -288,7 +291,8 @@ struct MakeRecvTrailingMetadata {
~MakeRecvTrailingMetadata() {}
MockGrpcClosure ready;
grpc_metadata_batch grpc_trailing_metadata;
grpc_core::ScopedArenaPtr arena = grpc_core::MakeScopedArena(1024);
grpc_metadata_batch grpc_trailing_metadata{arena.get()};
absl::Notification notification;
};

@ -18,13 +18,14 @@ licenses(["notice"])
grpc_package(name = "test/core/transport/chttp2")
load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer")
load("//test/core/util:grpc_fuzzer.bzl", "grpc_proto_fuzzer")
load("//bazel:custom_exec_properties.bzl", "LARGE_MACHINE")
grpc_fuzzer(
grpc_proto_fuzzer(
name = "hpack_parser_fuzzer",
srcs = ["hpack_parser_fuzzer_test.cc"],
corpus = "hpack_parser_corpus",
proto = "hpack_parser_fuzzer.proto",
tags = ["no_windows"],
deps = [
"//:grpc",
@ -113,6 +114,7 @@ grpc_cc_test(
grpc_cc_test(
name = "hpack_parser_test",
srcs = ["hpack_parser_test.cc"],
external_deps = ["gtest"],
language = "C++",
uses_polling = False,
deps = [
@ -125,6 +127,7 @@ grpc_cc_test(
grpc_cc_test(
name = "hpack_parser_table_test",
srcs = ["hpack_parser_table_test.cc"],
external_deps = ["gtest"],
language = "C++",
uses_polling = False,
deps = [

@ -161,7 +161,8 @@ static void verify(const verify_params params, const char* expected,
va_list l;
grpc_linked_mdelem* e =
static_cast<grpc_linked_mdelem*>(gpr_malloc(sizeof(*e) * nheaders));
grpc_metadata_batch b;
auto arena = grpc_core::MakeScopedArena(1024);
grpc_metadata_batch b(arena.get());
va_start(l, nheaders);
for (i = 0; i < nheaders; i++) {
@ -243,6 +244,7 @@ static void test_basic_headers() {
static void verify_continuation_headers(const char* key, const char* value,
bool is_eof) {
auto arena = grpc_core::MakeScopedArena(1024);
grpc_slice_buffer output;
grpc_mdelem elem = grpc_mdelem_from_slices(
grpc_slice_intern(grpc_slice_from_static_string(key)),
@ -251,7 +253,7 @@ static void verify_continuation_headers(const char* key, const char* value,
e.md = elem;
e.prev = nullptr;
e.next = nullptr;
grpc_metadata_batch b;
grpc_metadata_batch b(arena.get());
GPR_ASSERT(GRPC_ERROR_NONE == b.LinkTail(&e));
grpc_slice_buffer_init(&output);
@ -325,6 +327,7 @@ static void test_decode_table_overflow() {
static void verify_table_size_change_match_elem_size(const char* key,
const char* value,
bool use_true_binary) {
auto arena = grpc_core::MakeScopedArena(1024);
grpc_slice_buffer output;
grpc_mdelem elem = grpc_mdelem_from_slices(
grpc_slice_intern(grpc_slice_from_static_string(key)),
@ -335,7 +338,7 @@ static void verify_table_size_change_match_elem_size(const char* key,
e.md = elem;
e.prev = nullptr;
e.next = nullptr;
grpc_metadata_batch b;
grpc_metadata_batch b(arena.get());
GPR_ASSERT(GRPC_ERROR_NONE == b.LinkTail(&e));
grpc_slice_buffer_init(&output);

@ -1 +0,0 @@
<EFBFBD>!<EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<EFBFBD><EFBFBD><EFBFBD><EFBFBD>*c

@ -1 +0,0 @@
¤¤ğ¤-bin;?0c!(ğK ğ[N!‹c[:¤ğ¤-\!õG!):[(!!¤

@ -1 +0,0 @@
¤¤ğ¤-bin‹c[)(ğ¤-bin-'bin !!?¤Ûğ!ğ{(-binğ !\ !å7é;?Gí([(!!\ğ*¤¤Ûğ

@ -1 +0,0 @@
;?'c<EFBFBD>[(! <EFBFBD>[N!\ !<EFBFBD>G<EFBFBD>!*(! !<EFBFBD>G<EFBFBD>A)(!)<EFBFBD>!<EFBFBD>*)<EFBFBD>G<EFBFBD>I)(<EFBFBD>;)<EFBFBD>

@ -1 +0,0 @@
¤¤ğ¤-bin‹c[)(-'bin !!?¤Ûğ!ğ{(-binğ !\ !åé;?Gí[((!!\ğ

@ -1 +0,0 @@
¤¤ğ¤-bin‹äc[ò)('-bi. *)!?¤Ûâ!ğ{(-bi\n! ! ğåé;?Gí:[((!!\ğ

@ -1 +0,0 @@
¤¤ğ¤-bin‹c[)('-bh *!!?¤Ûâ!ğ{(-bi\n! ! ğåé;?Gí:[((!!\ğ

@ -1 +0,0 @@
¤¤ğ¤-bin‹)['(-cbin !!?¤Ûğ!ğ{(-binğ !\ !åé;?Gí:[((!!\ğ

@ -1 +0,0 @@
;?0c!(πK π[N!\!υG![(!! !εGύA)(!)ν!*εG€ΎύA))Ω+©<EFBFBD>

@ -1 +0,0 @@
;?0c<EFBFBD>[(! <EFBFBD>[N!\ !<EFBFBD>G<EFBFBD>![(!! !<EFBFBD>G<EFBFBD>A)(!)<EFBFBD>!<EFBFBD>*)<EFBFBD>G<EFBFBD>A)(<EFBFBD>;)<EFBFBD>

@ -1 +0,0 @@
¤¤ğ¤-bin‹c[')(-'bin !!?¤Ûğ!ğ{(-banğ !\ !(åé–;?Gí:[((!!\ğ

@ -1 +0,0 @@
?*<EFBFBD>@:[<EFBFBD><EFBFBD>c (!!\<EFBFBD>;<EFBFBD>!~ <EFBFBD><EFBFBD>G<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<EFBFBD>am<EFBFBD>

@ -1 +0,0 @@
¤¤ğ¤-bin‹™[)('-bin !!?¤Ûğ!ğ{(-bi\n! ! ğåé;?Gí:[((!!\ğ

@ -1 +0,0 @@
ð[(-bin! ð(!\ !åGý:[(!'ð[(!! ð[(*! !å!ýGåGýA)([( !!å

@ -1 +0,0 @@
*<EFBFBD><EFBFBD><EFBFBD>-b<EFBFBD>n'<EFBFBD>'c)[<EFBFBD>i(bn-!?<EFBFBD><EFBFBD><EFBFBD>! <EFBFBD>(!\c

@ -1 +0,0 @@
¤¤ğ¤-bin‹-[c'()bin !!?¤Ûğ!;ğ{(-binğ !\ !˜é;?Gí:[((!!\ğ

@ -1 +0,0 @@
¤¤ğ¤-bin‹c[)(-'bin 1!?¤Ûğ!;*ğ{(-binğ !\ !åé;?Gí:[((!!\ğ

@ -1 +0,0 @@
?*<EFBFBD><EFBFBD><EFBFBD>@:<EFBFBD>[<EFBFBD>c (;<EFBFBD>!!\<EFBFBD> !~ <EFBFBD><EFBFBD>G<EFBFBD>!<EFBFBD>cm:'

@ -1 +0,0 @@
<EFBFBD>!<EFBFBD><EFBFBD><EFBFBD>Ф!<EFBFBD>:[o<EFBFBD><EFBFBD>c

@ -1 +0,0 @@
¤¤ğ¤-bin‹c[)(-'bin !!?¤Ûğ!ğ{(-binğ !\ !å7é;?Gí([(!!\ğ

@ -1 +0,0 @@
*<EFBFBD><EFBFBD><EFBFBD>@<EFBFBD>[:<EFBFBD>c 8;'<EFBFBD>!!\<EFBFBD> !~ <EFBFBD>DG<EFBFBD>!<EFBFBD>km'

@ -1 +0,0 @@
;?'c<EFBFBD>[(! <EFBFBD>[N!\ !<EFBFBD>E<EFBFBD>!*(!! !<EFBFBD>G<EFBFBD>A)(!)<EFBFBD>!<EFBFBD>*)<EFBFBD>G<EFBFBD>I)(<EFBFBD>;)<EFBFBD>

@ -1 +0,0 @@
):;!śĘ'ŇŘ)*;}v)7IĎ!¤);–-M*±äâ!'d*Cu«‘X$0):ó*;:äÝ;;();:]ďć@

@ -1 +0,0 @@
¤¤ğ¤-bin‹c)(-'bin !!?¤Ûğ!ğ{(-binğ !\ !åé;?Gí:[((!!\ğ

@ -1 +0,0 @@
*<EFBFBD><EFBFBD><EFBFBD>@:<EFBFBD>[(<EFBFBD>c (;<EFBFBD>!!\ !c<EFBFBD>G<EFBFBD>:

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save