grpc 1.78.0 → 1.80.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (431) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +22 -8
  3. data/include/grpc/credentials.h +47 -37
  4. data/include/grpc/credentials_cpp.h +39 -0
  5. data/include/grpc/event_engine/event_engine.h +8 -3
  6. data/include/grpc/grpc.h +4 -0
  7. data/include/grpc/impl/call.h +9 -0
  8. data/include/grpc/impl/channel_arg_names.h +7 -0
  9. data/include/grpc/module.modulemap +2 -0
  10. data/include/grpc/private_key_signer.h +104 -0
  11. data/include/grpc/support/port_platform.h +6 -0
  12. data/src/core/call/call_filters.h +101 -78
  13. data/src/core/call/call_spine.h +91 -68
  14. data/src/core/call/call_state.h +60 -4
  15. data/src/core/call/client_call.cc +9 -9
  16. data/src/core/call/client_call.h +1 -1
  17. data/src/core/call/metadata_batch.cc +2 -0
  18. data/src/core/call/metadata_batch.h +48 -1
  19. data/src/core/call/metadata_info.cc +35 -0
  20. data/src/core/call/metadata_info.h +2 -0
  21. data/src/core/call/simple_slice_based_metadata.h +2 -1
  22. data/src/core/channelz/channelz.cc +9 -6
  23. data/src/core/channelz/channelz.h +7 -4
  24. data/src/core/channelz/property_list.h +5 -0
  25. data/src/core/channelz/v2tov1/convert.cc +1 -1
  26. data/src/core/channelz/v2tov1/legacy_api.cc +164 -307
  27. data/src/core/client_channel/buffered_call.cc +7 -3
  28. data/src/core/client_channel/buffered_call.h +11 -5
  29. data/src/core/client_channel/client_channel.cc +106 -44
  30. data/src/core/client_channel/client_channel.h +3 -6
  31. data/src/core/client_channel/client_channel_filter.cc +90 -64
  32. data/src/core/client_channel/client_channel_filter.h +3 -6
  33. data/src/core/client_channel/client_channel_internal.h +5 -0
  34. data/src/core/client_channel/config_selector.h +17 -12
  35. data/src/core/client_channel/dynamic_filters.cc +8 -7
  36. data/src/core/client_channel/dynamic_filters.h +7 -5
  37. data/src/core/client_channel/retry_filter.cc +1 -1
  38. data/src/core/client_channel/retry_filter.h +2 -2
  39. data/src/core/client_channel/subchannel.cc +1682 -266
  40. data/src/core/client_channel/subchannel.h +411 -134
  41. data/src/core/client_channel/subchannel_stream_client.cc +22 -18
  42. data/src/core/client_channel/subchannel_stream_client.h +8 -9
  43. data/src/core/client_channel/subchannel_stream_limiter.cc +76 -0
  44. data/src/core/client_channel/subchannel_stream_limiter.h +51 -0
  45. data/src/core/config/config_vars.cc +9 -1
  46. data/src/core/config/config_vars.h +6 -0
  47. data/src/core/credentials/call/call_creds_registry.h +51 -22
  48. data/src/core/credentials/call/call_creds_registry_init.cc +86 -2
  49. data/src/core/credentials/call/external/aws_external_account_credentials.cc +2 -2
  50. data/src/core/credentials/call/external/external_account_credentials.cc +11 -4
  51. data/src/core/credentials/call/external/file_external_account_credentials.cc +2 -2
  52. data/src/core/credentials/transport/channel_creds_registry.h +71 -20
  53. data/src/core/credentials/transport/channel_creds_registry_init.cc +338 -29
  54. data/src/core/credentials/transport/ssl/ssl_credentials.cc +43 -24
  55. data/src/core/credentials/transport/ssl/ssl_credentials.h +7 -1
  56. data/src/core/credentials/transport/ssl/ssl_security_connector.cc +2 -8
  57. data/src/core/credentials/transport/ssl/ssl_security_connector.h +4 -3
  58. data/src/core/credentials/transport/tls/grpc_tls_certificate_distributor.cc +25 -5
  59. data/src/core/credentials/transport/tls/grpc_tls_certificate_distributor.h +7 -5
  60. data/src/core/credentials/transport/tls/grpc_tls_certificate_provider.cc +181 -109
  61. data/src/core/credentials/transport/tls/grpc_tls_certificate_provider.h +55 -42
  62. data/src/core/credentials/transport/tls/grpc_tls_credentials_options.cc +28 -23
  63. data/src/core/credentials/transport/tls/grpc_tls_credentials_options.h +26 -23
  64. data/src/core/credentials/transport/tls/spiffe_utils.cc +2 -2
  65. data/src/core/credentials/transport/tls/ssl_utils.cc +18 -18
  66. data/src/core/credentials/transport/tls/ssl_utils.h +12 -10
  67. data/src/core/credentials/transport/tls/tls_security_connector.cc +106 -74
  68. data/src/core/credentials/transport/tls/tls_security_connector.h +12 -8
  69. data/src/core/credentials/transport/xds/xds_credentials.cc +76 -32
  70. data/src/core/credentials/transport/xds/xds_credentials.h +4 -2
  71. data/src/core/ext/filters/fault_injection/fault_injection_filter.cc +117 -35
  72. data/src/core/ext/filters/fault_injection/fault_injection_filter.h +42 -4
  73. data/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.cc +58 -29
  74. data/src/core/ext/filters/gcp_authentication/gcp_authentication_filter.h +19 -11
  75. data/src/core/ext/filters/stateful_session/stateful_session_filter.cc +82 -25
  76. data/src/core/ext/filters/stateful_session/stateful_session_filter.h +28 -3
  77. data/src/core/ext/filters/stateful_session/stateful_session_service_config_parser.cc +9 -7
  78. data/src/core/ext/filters/stateful_session/stateful_session_service_config_parser.h +1 -1
  79. data/src/core/ext/transport/chttp2/transport/call_tracer_wrapper.h +7 -1
  80. data/src/core/ext/transport/chttp2/transport/chttp2_transport.cc +117 -67
  81. data/src/core/ext/transport/chttp2/transport/chttp2_transport.h +2 -0
  82. data/src/core/ext/transport/chttp2/transport/flow_control.h +11 -1
  83. data/src/core/ext/transport/chttp2/transport/frame.cc +2 -15
  84. data/src/core/ext/transport/chttp2/transport/frame.h +0 -4
  85. data/src/core/ext/transport/chttp2/transport/goaway.cc +17 -2
  86. data/src/core/ext/transport/chttp2/transport/goaway.h +27 -6
  87. data/src/core/ext/transport/chttp2/transport/header_assembler.h +8 -21
  88. data/src/core/ext/transport/chttp2/transport/hpack_encoder.cc +101 -40
  89. data/src/core/ext/transport/chttp2/transport/hpack_encoder.h +95 -0
  90. data/src/core/ext/transport/chttp2/transport/http2_client_transport.cc +923 -772
  91. data/src/core/ext/transport/chttp2/transport/http2_client_transport.h +406 -423
  92. data/src/core/ext/transport/chttp2/transport/http2_settings.cc +1 -0
  93. data/src/core/ext/transport/chttp2/transport/http2_settings.h +8 -1
  94. data/src/core/ext/transport/chttp2/transport/http2_settings_promises.h +25 -13
  95. data/src/core/ext/transport/chttp2/transport/http2_transport.cc +71 -24
  96. data/src/core/ext/transport/chttp2/transport/http2_transport.h +25 -49
  97. data/src/core/ext/transport/chttp2/transport/http2_ztrace_collector.h +2 -2
  98. data/src/core/ext/transport/chttp2/transport/incoming_metadata_tracker.h +29 -9
  99. data/src/core/ext/transport/chttp2/transport/internal.h +6 -2
  100. data/src/core/ext/transport/chttp2/transport/keepalive.cc +14 -20
  101. data/src/core/ext/transport/chttp2/transport/keepalive.h +9 -6
  102. data/src/core/ext/transport/chttp2/transport/parsing.cc +11 -0
  103. data/src/core/ext/transport/chttp2/transport/ping_promise.cc +34 -74
  104. data/src/core/ext/transport/chttp2/transport/ping_promise.h +123 -79
  105. data/src/core/ext/transport/chttp2/transport/security_frame.h +233 -3
  106. data/src/core/ext/transport/chttp2/transport/stream.h +152 -73
  107. data/src/core/ext/transport/chttp2/transport/stream_data_queue.h +155 -85
  108. data/src/core/ext/transport/chttp2/transport/transport_common.h +0 -5
  109. data/src/core/ext/transport/chttp2/transport/writable_streams.h +8 -7
  110. data/src/core/ext/transport/chttp2/transport/write_cycle.cc +86 -0
  111. data/src/core/ext/transport/chttp2/transport/write_cycle.h +355 -0
  112. data/src/core/ext/transport/chttp2/transport/writing.cc +31 -29
  113. data/src/core/ext/upb-gen/cel/expr/checked.upb.h +1875 -0
  114. data/src/core/ext/upb-gen/cel/expr/checked.upb_minitable.c +409 -0
  115. data/src/core/ext/upb-gen/cel/expr/checked.upb_minitable.h +56 -0
  116. data/src/core/ext/upb-gen/cel/expr/syntax.upb.h +2223 -0
  117. data/src/core/ext/upb-gen/cel/expr/syntax.upb_minitable.c +489 -0
  118. data/src/core/ext/upb-gen/cel/expr/syntax.upb_minitable.h +60 -0
  119. data/src/core/ext/upb-gen/envoy/config/accesslog/v3/accesslog.upb.h +2 -1
  120. data/src/core/ext/upb-gen/envoy/config/bootstrap/v3/bootstrap.upb.h +130 -18
  121. data/src/core/ext/upb-gen/envoy/config/bootstrap/v3/bootstrap.upb_minitable.c +18 -13
  122. data/src/core/ext/upb-gen/envoy/config/cluster/v3/cluster.upb.h +70 -38
  123. data/src/core/ext/upb-gen/envoy/config/cluster/v3/cluster.upb_minitable.c +20 -17
  124. data/src/core/ext/upb-gen/envoy/config/common/matcher/v3/matcher.upb.h +26 -10
  125. data/src/core/ext/upb-gen/envoy/config/common/matcher/v3/matcher.upb_minitable.c +8 -7
  126. data/src/core/ext/upb-gen/envoy/config/common/mutation_rules/v3/mutation_rules.upb.h +495 -0
  127. data/src/core/ext/upb-gen/envoy/config/common/mutation_rules/v3/mutation_rules.upb_minitable.c +114 -0
  128. data/src/core/ext/upb-gen/envoy/config/common/mutation_rules/v3/mutation_rules.upb_minitable.h +36 -0
  129. data/src/core/ext/upb-gen/envoy/config/core/v3/address.upb.h +26 -10
  130. data/src/core/ext/upb-gen/envoy/config/core/v3/address.upb_minitable.c +8 -7
  131. data/src/core/ext/upb-gen/envoy/config/core/v3/cel.upb.h +121 -0
  132. data/src/core/ext/upb-gen/envoy/config/core/v3/cel.upb_minitable.c +54 -0
  133. data/src/core/ext/upb-gen/envoy/config/core/v3/cel.upb_minitable.h +32 -0
  134. data/src/core/ext/upb-gen/envoy/config/core/v3/grpc_service.upb.h +143 -9
  135. data/src/core/ext/upb-gen/envoy/config/core/v3/grpc_service.upb_minitable.c +18 -6
  136. data/src/core/ext/upb-gen/envoy/config/core/v3/protocol.upb.h +112 -11
  137. data/src/core/ext/upb-gen/envoy/config/core/v3/protocol.upb_minitable.c +22 -9
  138. data/src/core/ext/upb-gen/envoy/config/core/v3/proxy_protocol.upb.h +276 -0
  139. data/src/core/ext/upb-gen/envoy/config/core/v3/proxy_protocol.upb_minitable.c +60 -5
  140. data/src/core/ext/upb-gen/envoy/config/core/v3/proxy_protocol.upb_minitable.h +4 -0
  141. data/src/core/ext/upb-gen/envoy/config/endpoint/v3/endpoint_components.upb.h +72 -0
  142. data/src/core/ext/upb-gen/envoy/config/endpoint/v3/endpoint_components.upb_minitable.c +23 -2
  143. data/src/core/ext/upb-gen/envoy/config/endpoint/v3/endpoint_components.upb_minitable.h +2 -0
  144. data/src/core/ext/upb-gen/envoy/config/listener/v3/listener.upb.h +129 -13
  145. data/src/core/ext/upb-gen/envoy/config/listener/v3/listener.upb_minitable.c +36 -10
  146. data/src/core/ext/upb-gen/envoy/config/listener/v3/listener.upb_minitable.h +2 -0
  147. data/src/core/ext/upb-gen/envoy/config/listener/v3/quic_config.upb.h +30 -0
  148. data/src/core/ext/upb-gen/envoy/config/listener/v3/quic_config.upb_minitable.c +5 -3
  149. data/src/core/ext/upb-gen/envoy/config/metrics/v3/metrics_service.upb.h +16 -0
  150. data/src/core/ext/upb-gen/envoy/config/metrics/v3/metrics_service.upb_minitable.c +4 -3
  151. data/src/core/ext/upb-gen/envoy/config/metrics/v3/stats.upb.h +31 -0
  152. data/src/core/ext/upb-gen/envoy/config/metrics/v3/stats.upb_minitable.c +5 -3
  153. data/src/core/ext/upb-gen/envoy/config/overload/v3/overload.upb.h +2 -1
  154. data/src/core/ext/upb-gen/envoy/config/rbac/v3/rbac.upb.h +63 -0
  155. data/src/core/ext/upb-gen/envoy/config/rbac/v3/rbac.upb_minitable.c +12 -7
  156. data/src/core/ext/upb-gen/envoy/config/route/v3/route.upb.h +97 -81
  157. data/src/core/ext/upb-gen/envoy/config/route/v3/route.upb_minitable.c +40 -23
  158. data/src/core/ext/upb-gen/envoy/config/route/v3/route_components.upb.h +604 -228
  159. data/src/core/ext/upb-gen/envoy/config/route/v3/route_components.upb_minitable.c +146 -100
  160. data/src/core/ext/upb-gen/envoy/config/tap/v3/common.upb.h +30 -0
  161. data/src/core/ext/upb-gen/envoy/config/tap/v3/common.upb_minitable.c +5 -3
  162. data/src/core/ext/upb-gen/envoy/config/trace/v3/opentelemetry.upb.h +35 -3
  163. data/src/core/ext/upb-gen/envoy/config/trace/v3/opentelemetry.upb_minitable.c +7 -4
  164. data/src/core/ext/upb-gen/envoy/config/trace/v3/zipkin.upb.h +66 -14
  165. data/src/core/ext/upb-gen/envoy/config/trace/v3/zipkin.upb_minitable.c +22 -11
  166. data/src/core/ext/upb-gen/envoy/extensions/clusters/aggregate/v3/cluster.upb.h +87 -0
  167. data/src/core/ext/upb-gen/envoy/extensions/clusters/aggregate/v3/cluster.upb_minitable.c +29 -2
  168. data/src/core/ext/upb-gen/envoy/extensions/clusters/aggregate/v3/cluster.upb_minitable.h +2 -0
  169. data/src/core/ext/upb-gen/envoy/extensions/filters/http/rbac/v3/rbac.upb.h +0 -1
  170. data/src/core/ext/upb-gen/envoy/extensions/filters/http/rbac/v3/rbac.upb_minitable.c +0 -1
  171. data/src/core/ext/upb-gen/envoy/extensions/filters/http/stateful_session/v3/stateful_session.upb.h +20 -4
  172. data/src/core/ext/upb-gen/envoy/extensions/filters/http/stateful_session/v3/stateful_session.upb_minitable.c +5 -4
  173. data/src/core/ext/upb-gen/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb.h +239 -60
  174. data/src/core/ext/upb-gen/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb_minitable.c +59 -28
  175. data/src/core/ext/upb-gen/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upb_minitable.h +2 -0
  176. data/src/core/ext/upb-gen/envoy/extensions/grpc_service/call_credentials/access_token/v3/access_token_credentials.upb.h +89 -0
  177. data/src/core/ext/upb-gen/envoy/extensions/grpc_service/call_credentials/access_token/v3/access_token_credentials.upb_minitable.c +50 -0
  178. data/src/core/ext/upb-gen/envoy/extensions/grpc_service/call_credentials/access_token/v3/access_token_credentials.upb_minitable.h +32 -0
  179. data/src/core/ext/upb-gen/envoy/extensions/grpc_service/channel_credentials/tls/v3/tls_credentials.upb.h +135 -0
  180. data/src/core/ext/upb-gen/envoy/extensions/grpc_service/channel_credentials/tls/v3/tls_credentials.upb_minitable.c +53 -0
  181. data/src/core/ext/upb-gen/envoy/extensions/grpc_service/channel_credentials/tls/v3/tls_credentials.upb_minitable.h +32 -0
  182. data/src/core/ext/upb-gen/envoy/extensions/grpc_service/channel_credentials/xds/v3/xds_credentials.upb.h +105 -0
  183. data/src/core/ext/upb-gen/envoy/extensions/grpc_service/channel_credentials/xds/v3/xds_credentials.upb_minitable.c +51 -0
  184. data/src/core/ext/upb-gen/envoy/extensions/grpc_service/channel_credentials/xds/v3/xds_credentials.upb_minitable.h +32 -0
  185. data/src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.upb.h +32 -0
  186. data/src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/client_side_weighted_round_robin/v3/client_side_weighted_round_robin.upb_minitable.c +6 -3
  187. data/src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/common/v3/common.upb.h +206 -0
  188. data/src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/common/v3/common.upb_minitable.c +41 -8
  189. data/src/core/ext/upb-gen/envoy/extensions/load_balancing_policies/common/v3/common.upb_minitable.h +2 -0
  190. data/src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/common.upb.h +64 -0
  191. data/src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/common.upb_minitable.c +4 -3
  192. data/src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/secret.upb.h +64 -0
  193. data/src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/secret.upb_minitable.c +31 -5
  194. data/src/core/ext/upb-gen/envoy/extensions/transport_sockets/tls/v3/secret.upb_minitable.h +2 -0
  195. data/src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb.h +283 -14
  196. data/src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb_minitable.c +48 -11
  197. data/src/core/ext/upb-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upb_minitable.h +2 -0
  198. data/src/core/ext/upb-gen/envoy/type/http/v3/cookie.upb.h +144 -6
  199. data/src/core/ext/upb-gen/envoy/type/http/v3/cookie.upb_minitable.c +35 -7
  200. data/src/core/ext/upb-gen/envoy/type/http/v3/cookie.upb_minitable.h +2 -0
  201. data/src/core/ext/upb-gen/envoy/type/tracing/v3/custom_tag.upb.h +42 -21
  202. data/src/core/ext/upb-gen/envoy/type/tracing/v3/custom_tag.upb_minitable.c +9 -8
  203. data/src/core/ext/upb-gen/src/proto/grpc/channelz/v2/promise.upb.h +164 -1
  204. data/src/core/ext/upb-gen/src/proto/grpc/channelz/v2/promise.upb_minitable.c +37 -6
  205. data/src/core/ext/upb-gen/src/proto/grpc/channelz/v2/promise.upb_minitable.h +2 -0
  206. data/src/core/ext/upb-gen/xds/type/matcher/v3/cel.upb.h +0 -1
  207. data/src/core/ext/upb-gen/xds/type/matcher/v3/cel.upb_minitable.c +0 -1
  208. data/src/core/ext/upb-gen/xds/type/matcher/v3/http_inputs.upb.h +0 -1
  209. data/src/core/ext/upb-gen/xds/type/matcher/v3/http_inputs.upb_minitable.c +0 -1
  210. data/src/core/ext/upb-gen/xds/type/matcher/v3/matcher.upb.h +26 -11
  211. data/src/core/ext/upb-gen/xds/type/matcher/v3/matcher.upb_minitable.c +8 -8
  212. data/src/core/ext/upb-gen/xds/type/matcher/v3/string.upb.h +33 -0
  213. data/src/core/ext/upb-gen/xds/type/matcher/v3/string.upb_minitable.c +14 -3
  214. data/src/core/ext/upb-gen/xds/type/v3/cel.upb.h +90 -10
  215. data/src/core/ext/upb-gen/xds/type/v3/cel.upb_minitable.c +18 -7
  216. data/src/core/ext/upbdefs-gen/cel/expr/checked.upbdefs.c +248 -0
  217. data/src/core/ext/upbdefs-gen/cel/expr/checked.upbdefs.h +97 -0
  218. data/src/core/ext/upbdefs-gen/cel/expr/syntax.upbdefs.c +283 -0
  219. data/src/core/ext/upbdefs-gen/cel/expr/syntax.upbdefs.h +107 -0
  220. data/src/core/ext/upbdefs-gen/envoy/config/accesslog/v3/accesslog.upbdefs.c +213 -211
  221. data/src/core/ext/upbdefs-gen/envoy/config/bootstrap/v3/bootstrap.upbdefs.c +635 -614
  222. data/src/core/ext/upbdefs-gen/envoy/config/cluster/v3/cluster.upbdefs.c +1012 -1000
  223. data/src/core/ext/upbdefs-gen/envoy/config/common/matcher/v3/matcher.upbdefs.c +276 -273
  224. data/src/core/ext/upbdefs-gen/envoy/config/common/mutation_rules/v3/mutation_rules.upbdefs.c +152 -0
  225. data/src/core/ext/upbdefs-gen/envoy/config/common/mutation_rules/v3/mutation_rules.upbdefs.h +47 -0
  226. data/src/core/ext/upbdefs-gen/envoy/config/core/v3/address.upbdefs.c +149 -144
  227. data/src/core/ext/upbdefs-gen/envoy/config/core/v3/base.upbdefs.c +367 -370
  228. data/src/core/ext/upbdefs-gen/envoy/config/core/v3/cel.upbdefs.c +63 -0
  229. data/src/core/ext/upbdefs-gen/envoy/config/core/v3/cel.upbdefs.h +37 -0
  230. data/src/core/ext/upbdefs-gen/envoy/config/core/v3/grpc_service.upbdefs.c +297 -284
  231. data/src/core/ext/upbdefs-gen/envoy/config/core/v3/protocol.upbdefs.c +492 -469
  232. data/src/core/ext/upbdefs-gen/envoy/config/core/v3/proxy_protocol.upbdefs.c +74 -43
  233. data/src/core/ext/upbdefs-gen/envoy/config/core/v3/proxy_protocol.upbdefs.h +10 -0
  234. data/src/core/ext/upbdefs-gen/envoy/config/core/v3/substitution_format_string.upbdefs.c +60 -59
  235. data/src/core/ext/upbdefs-gen/envoy/config/endpoint/v3/endpoint_components.upbdefs.c +202 -184
  236. data/src/core/ext/upbdefs-gen/envoy/config/endpoint/v3/endpoint_components.upbdefs.h +5 -0
  237. data/src/core/ext/upbdefs-gen/envoy/config/listener/v3/listener.upbdefs.c +354 -339
  238. data/src/core/ext/upbdefs-gen/envoy/config/listener/v3/listener.upbdefs.h +5 -0
  239. data/src/core/ext/upbdefs-gen/envoy/config/listener/v3/quic_config.upbdefs.c +28 -19
  240. data/src/core/ext/upbdefs-gen/envoy/config/metrics/v3/metrics_service.upbdefs.c +30 -27
  241. data/src/core/ext/upbdefs-gen/envoy/config/metrics/v3/stats.upbdefs.c +71 -66
  242. data/src/core/ext/upbdefs-gen/envoy/config/overload/v3/overload.upbdefs.c +94 -91
  243. data/src/core/ext/upbdefs-gen/envoy/config/rbac/v3/rbac.upbdefs.c +386 -369
  244. data/src/core/ext/upbdefs-gen/envoy/config/route/v3/route.upbdefs.c +60 -57
  245. data/src/core/ext/upbdefs-gen/envoy/config/route/v3/route_components.upbdefs.c +1974 -1884
  246. data/src/core/ext/upbdefs-gen/envoy/config/tap/v3/common.upbdefs.c +119 -112
  247. data/src/core/ext/upbdefs-gen/envoy/config/trace/v3/opentelemetry.upbdefs.c +62 -51
  248. data/src/core/ext/upbdefs-gen/envoy/config/trace/v3/zipkin.upbdefs.c +109 -88
  249. data/src/core/ext/upbdefs-gen/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.c +54 -36
  250. data/src/core/ext/upbdefs-gen/envoy/extensions/clusters/aggregate/v3/cluster.upbdefs.h +5 -0
  251. data/src/core/ext/upbdefs-gen/envoy/extensions/filters/http/rbac/v3/rbac.upbdefs.c +78 -84
  252. data/src/core/ext/upbdefs-gen/envoy/extensions/filters/http/stateful_session/v3/stateful_session.upbdefs.c +48 -46
  253. data/src/core/ext/upbdefs-gen/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.c +1041 -984
  254. data/src/core/ext/upbdefs-gen/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.upbdefs.h +5 -0
  255. data/src/core/ext/upbdefs-gen/envoy/extensions/transport_sockets/tls/v3/common.upbdefs.c +304 -290
  256. data/src/core/ext/upbdefs-gen/envoy/extensions/transport_sockets/tls/v3/secret.upbdefs.c +94 -77
  257. data/src/core/ext/upbdefs-gen/envoy/extensions/transport_sockets/tls/v3/secret.upbdefs.h +5 -0
  258. data/src/core/ext/upbdefs-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upbdefs.c +246 -193
  259. data/src/core/ext/upbdefs-gen/envoy/extensions/upstreams/http/v3/http_protocol_options.upbdefs.h +5 -0
  260. data/src/core/ext/upbdefs-gen/envoy/type/http/v3/cookie.upbdefs.c +37 -23
  261. data/src/core/ext/upbdefs-gen/envoy/type/http/v3/cookie.upbdefs.h +5 -0
  262. data/src/core/ext/upbdefs-gen/envoy/type/tracing/v3/custom_tag.upbdefs.c +5 -3
  263. data/src/core/ext/upbdefs-gen/google/api/http.upbdefs.c +4 -4
  264. data/src/core/ext/upbdefs-gen/google/api/httpbody.upbdefs.c +4 -5
  265. data/src/core/ext/upbdefs-gen/src/proto/grpc/channelz/v2/promise.upbdefs.c +113 -87
  266. data/src/core/ext/upbdefs-gen/src/proto/grpc/channelz/v2/promise.upbdefs.h +5 -0
  267. data/src/core/ext/upbdefs-gen/udpa/annotations/migrate.upbdefs.c +5 -5
  268. data/src/core/ext/upbdefs-gen/udpa/annotations/security.upbdefs.c +6 -5
  269. data/src/core/ext/upbdefs-gen/udpa/annotations/sensitive.upbdefs.c +5 -5
  270. data/src/core/ext/upbdefs-gen/udpa/annotations/status.upbdefs.c +5 -5
  271. data/src/core/ext/upbdefs-gen/udpa/annotations/versioning.upbdefs.c +5 -5
  272. data/src/core/ext/upbdefs-gen/xds/type/matcher/v3/cel.upbdefs.c +25 -30
  273. data/src/core/ext/upbdefs-gen/xds/type/matcher/v3/http_inputs.upbdefs.c +14 -20
  274. data/src/core/ext/upbdefs-gen/xds/type/matcher/v3/matcher.upbdefs.c +180 -183
  275. data/src/core/ext/upbdefs-gen/xds/type/matcher/v3/string.upbdefs.c +56 -47
  276. data/src/core/ext/upbdefs-gen/xds/type/v3/cel.upbdefs.c +69 -47
  277. data/src/core/filter/filter_chain.h +95 -0
  278. data/src/core/handshaker/http_connect/{http_connect_handshaker.cc → http_connect_client_handshaker.cc} +32 -31
  279. data/src/core/handshaker/http_connect/{http_connect_handshaker.h → http_connect_client_handshaker.h} +4 -4
  280. data/src/core/handshaker/http_connect/http_proxy_mapper.cc +1 -1
  281. data/src/core/handshaker/http_connect/xds_http_proxy_mapper.cc +1 -1
  282. data/src/core/handshaker/security/pipelined_secure_endpoint.cc +14 -13
  283. data/src/core/handshaker/security/secure_endpoint.cc +282 -68
  284. data/src/core/handshaker/security/secure_endpoint.h +0 -7
  285. data/src/core/lib/channel/channel_args.h +1 -1
  286. data/src/core/lib/channel/promise_based_filter.cc +17 -4
  287. data/src/core/lib/channel/promise_based_filter.h +3 -2
  288. data/src/core/lib/debug/trace_flags.cc +2 -0
  289. data/src/core/lib/debug/trace_flags.h +1 -0
  290. data/src/core/lib/event_engine/cf_engine/cfstream_endpoint.cc +35 -8
  291. data/src/core/lib/event_engine/cf_engine/dns_service_resolver.h +1 -2
  292. data/src/core/lib/event_engine/event_engine.cc +9 -0
  293. data/src/core/lib/event_engine/extensions/tcp_trace.h +0 -3
  294. data/src/core/lib/event_engine/posix_engine/ev_poll_posix.cc +2 -2
  295. data/src/core/lib/event_engine/posix_engine/posix_endpoint.h +1 -1
  296. data/src/core/lib/event_engine/posix_engine/posix_engine.cc +34 -9
  297. data/src/core/lib/event_engine/posix_engine/posix_engine.h +24 -2
  298. data/src/core/lib/event_engine/posix_engine/posix_engine_listener.cc +1 -3
  299. data/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.cc +141 -14
  300. data/src/core/lib/event_engine/posix_engine/posix_engine_listener_utils.h +19 -2
  301. data/src/core/lib/event_engine/posix_engine/posix_interface.h +7 -0
  302. data/src/core/lib/event_engine/posix_engine/posix_interface_posix.cc +21 -3
  303. data/src/core/lib/event_engine/posix_engine/posix_interface_windows.cc +16 -0
  304. data/src/core/lib/experiments/experiments.cc +309 -201
  305. data/src/core/lib/experiments/experiments.h +141 -80
  306. data/src/core/lib/iomgr/event_engine_shims/endpoint.cc +2 -2
  307. data/src/core/lib/iomgr/resolve_address.h +0 -2
  308. data/src/core/lib/iomgr/resolved_address.h +0 -2
  309. data/src/core/lib/iomgr/tcp_posix.cc +13 -5
  310. data/src/core/lib/iomgr/tcp_server.cc +0 -5
  311. data/src/core/lib/iomgr/tcp_server.h +0 -7
  312. data/src/core/lib/iomgr/tcp_server_posix.cc +0 -17
  313. data/src/core/lib/iomgr/tcp_server_utils_posix.h +0 -3
  314. data/src/core/lib/iomgr/tcp_server_windows.cc +12 -51
  315. data/src/core/lib/promise/all_ok.h +17 -12
  316. data/src/core/lib/promise/cancel_callback.h +12 -13
  317. data/src/core/lib/promise/detail/join_state.h +626 -0
  318. data/src/core/lib/promise/detail/promise_factory.h +14 -14
  319. data/src/core/lib/promise/for_each.h +32 -8
  320. data/src/core/lib/promise/if.h +9 -7
  321. data/src/core/lib/promise/loop.h +18 -16
  322. data/src/core/lib/promise/map.h +54 -47
  323. data/src/core/lib/promise/mpsc.h +11 -10
  324. data/src/core/lib/promise/observable.h +6 -6
  325. data/src/core/lib/promise/party.h +25 -19
  326. data/src/core/lib/promise/poll.h +5 -5
  327. data/src/core/lib/promise/prioritized_race.h +10 -7
  328. data/src/core/lib/promise/promise.h +16 -11
  329. data/src/core/lib/promise/race.h +6 -5
  330. data/src/core/lib/promise/seq.h +109 -74
  331. data/src/core/lib/promise/try_join.h +14 -6
  332. data/src/core/lib/promise/try_seq.h +76 -60
  333. data/src/core/lib/resource_quota/api.cc +7 -0
  334. data/src/core/lib/resource_quota/arena.h +1 -1
  335. data/src/core/lib/resource_quota/memory_quota.cc +4 -1
  336. data/src/core/lib/resource_quota/resource_quota.cc +2 -1
  337. data/src/core/lib/resource_quota/resource_quota.h +3 -0
  338. data/src/core/lib/resource_quota/stream_quota.cc +77 -1
  339. data/src/core/lib/resource_quota/stream_quota.h +64 -1
  340. data/src/core/lib/resource_quota/telemetry.h +1 -1
  341. data/src/core/lib/surface/call.cc +13 -0
  342. data/src/core/lib/surface/call_utils.h +58 -43
  343. data/src/core/lib/surface/channel.h +1 -4
  344. data/src/core/lib/surface/completion_queue.cc +13 -6
  345. data/src/core/lib/surface/validate_metadata.cc +20 -15
  346. data/src/core/lib/surface/validate_metadata.h +3 -1
  347. data/src/core/lib/surface/version.cc +2 -2
  348. data/src/core/lib/transport/promise_endpoint.cc +1 -1
  349. data/src/core/lib/transport/promise_endpoint.h +1 -1
  350. data/src/core/lib/transport/transport.h +5 -0
  351. data/src/core/load_balancing/health_check_client.cc +1 -15
  352. data/src/core/load_balancing/health_check_client_internal.h +0 -2
  353. data/src/core/load_balancing/oob_backend_metric.cc +1 -5
  354. data/src/core/load_balancing/oob_backend_metric_internal.h +0 -1
  355. data/src/core/load_balancing/xds/xds_cluster_impl.cc +12 -9
  356. data/src/core/plugin_registry/grpc_plugin_registry.cc +3 -2
  357. data/src/core/resolver/xds/xds_resolver.cc +162 -116
  358. data/src/core/server/server.cc +18 -1
  359. data/src/core/server/server.h +2 -0
  360. data/src/core/server/xds_server_config_fetcher.cc +4 -4
  361. data/src/core/telemetry/call_tracer.cc +87 -2
  362. data/src/core/telemetry/call_tracer.h +46 -8
  363. data/src/core/telemetry/instrument.cc +102 -40
  364. data/src/core/telemetry/instrument.h +246 -65
  365. data/src/core/tsi/fake_transport_security.cc +3 -1
  366. data/src/core/tsi/ssl_transport_security.cc +516 -137
  367. data/src/core/tsi/ssl_transport_security.h +28 -22
  368. data/src/core/tsi/ssl_transport_security_utils.cc +2 -2
  369. data/src/core/tsi/ssl_transport_security_utils.h +2 -2
  370. data/src/core/util/bitset.h +6 -0
  371. data/src/core/util/function_signature.h +3 -1
  372. data/src/core/util/http_client/httpcli_security_connector.cc +2 -1
  373. data/src/core/util/json/json_reader.cc +0 -4
  374. data/src/core/xds/grpc/certificate_provider_store.cc +2 -1
  375. data/src/core/xds/grpc/certificate_provider_store.h +3 -17
  376. data/src/core/xds/grpc/certificate_provider_store_interface.h +61 -0
  377. data/src/core/xds/grpc/xds_bootstrap_grpc.cc +48 -0
  378. data/src/core/xds/grpc/xds_bootstrap_grpc.h +18 -0
  379. data/src/core/xds/grpc/xds_certificate_provider.cc +7 -2
  380. data/src/core/xds/grpc/xds_certificate_provider.h +13 -2
  381. data/src/core/xds/grpc/xds_client_grpc.cc +13 -6
  382. data/src/core/xds/grpc/xds_client_grpc.h +10 -7
  383. data/src/core/xds/grpc/xds_cluster.cc +18 -4
  384. data/src/core/xds/grpc/xds_cluster.h +17 -2
  385. data/src/core/xds/grpc/xds_cluster_parser.cc +36 -11
  386. data/src/core/xds/grpc/xds_common_types.cc +45 -0
  387. data/src/core/xds/grpc/xds_common_types.h +31 -0
  388. data/src/core/xds/grpc/xds_common_types_parser.cc +274 -16
  389. data/src/core/xds/grpc/xds_common_types_parser.h +12 -0
  390. data/src/core/xds/grpc/xds_http_fault_filter.cc +128 -24
  391. data/src/core/xds/grpc/xds_http_fault_filter.h +19 -10
  392. data/src/core/xds/grpc/xds_http_filter.cc +38 -0
  393. data/src/core/xds/grpc/xds_http_filter.h +70 -47
  394. data/src/core/xds/grpc/xds_http_filter_registry.cc +48 -14
  395. data/src/core/xds/grpc/xds_http_filter_registry.h +29 -15
  396. data/src/core/xds/grpc/xds_http_gcp_authn_filter.cc +88 -22
  397. data/src/core/xds/grpc/xds_http_gcp_authn_filter.h +22 -11
  398. data/src/core/xds/grpc/xds_http_rbac_filter.cc +36 -20
  399. data/src/core/xds/grpc/xds_http_rbac_filter.h +19 -10
  400. data/src/core/xds/grpc/xds_http_stateful_session_filter.cc +143 -26
  401. data/src/core/xds/grpc/xds_http_stateful_session_filter.h +19 -10
  402. data/src/core/xds/grpc/xds_listener.cc +4 -1
  403. data/src/core/xds/grpc/xds_listener.h +10 -2
  404. data/src/core/xds/grpc/xds_listener_parser.cc +23 -18
  405. data/src/core/xds/grpc/xds_matcher.cc +40 -5
  406. data/src/core/xds/grpc/xds_matcher.h +13 -0
  407. data/src/core/xds/grpc/xds_matcher_action.h +1 -1
  408. data/src/core/xds/grpc/xds_matcher_parse.cc +60 -40
  409. data/src/core/xds/grpc/xds_matcher_parse.h +2 -1
  410. data/src/core/xds/grpc/xds_route_config.cc +12 -1
  411. data/src/core/xds/grpc/xds_route_config.h +15 -2
  412. data/src/core/xds/grpc/xds_route_config_parser.cc +11 -5
  413. data/src/core/xds/grpc/xds_routing.cc +181 -6
  414. data/src/core/xds/grpc/xds_routing.h +57 -0
  415. data/src/core/xds/grpc/xds_server_grpc.cc +55 -43
  416. data/src/core/xds/grpc/xds_server_grpc.h +13 -6
  417. data/src/core/xds/grpc/xds_server_grpc_interface.h +3 -2
  418. data/src/core/xds/grpc/xds_transport_grpc.cc +12 -6
  419. data/src/core/xds/grpc/xds_transport_grpc.h +5 -1
  420. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +12 -8
  421. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +18 -12
  422. data/src/ruby/lib/grpc/grpc.rb +7 -9
  423. data/src/ruby/lib/grpc/version.rb +1 -1
  424. data/src/ruby/pb/generate_proto_ruby.sh +1 -1
  425. data/src/ruby/spec/client_server_spec.rb +1 -1
  426. data/src/ruby/spec/generic/rpc_server_pool_spec.rb +1 -1
  427. data/src/ruby/spec/generic/rpc_server_spec.rb +3 -4
  428. data/src/ruby/spec/spec_helper.rb +1 -1
  429. metadata +64 -14
  430. data/src/core/ext/transport/chttp2/transport/security_frame.cc +0 -31
  431. data/src/core/handshaker/security/legacy_secure_endpoint.cc +0 -597
@@ -23,10 +23,8 @@
23
23
  #include <grpc/support/port_platform.h>
24
24
  #include <limits.h>
25
25
 
26
- #include <algorithm>
27
26
  #include <cstddef>
28
27
  #include <cstdint>
29
- #include <iterator>
30
28
  #include <memory>
31
29
  #include <optional>
32
30
  #include <string>
@@ -37,7 +35,6 @@
37
35
  #include "src/core/call/message.h"
38
36
  #include "src/core/call/metadata.h"
39
37
  #include "src/core/call/metadata_batch.h"
40
- #include "src/core/call/metadata_info.h"
41
38
  #include "src/core/channelz/channelz.h"
42
39
  #include "src/core/ext/transport/chttp2/transport/flow_control.h"
43
40
  #include "src/core/ext/transport/chttp2/transport/flow_control_manager.h"
@@ -53,23 +50,23 @@
53
50
  #include "src/core/ext/transport/chttp2/transport/keepalive.h"
54
51
  #include "src/core/ext/transport/chttp2/transport/message_assembler.h"
55
52
  #include "src/core/ext/transport/chttp2/transport/ping_promise.h"
53
+ #include "src/core/ext/transport/chttp2/transport/security_frame.h"
56
54
  #include "src/core/ext/transport/chttp2/transport/stream.h"
57
55
  #include "src/core/ext/transport/chttp2/transport/stream_data_queue.h"
58
56
  #include "src/core/ext/transport/chttp2/transport/transport_common.h"
57
+ #include "src/core/ext/transport/chttp2/transport/write_cycle.h"
59
58
  #include "src/core/lib/channel/channel_args.h"
60
59
  #include "src/core/lib/iomgr/exec_ctx.h"
61
- #include "src/core/lib/promise/activity.h"
62
- #include "src/core/lib/promise/context.h"
63
60
  #include "src/core/lib/promise/for_each.h"
64
61
  #include "src/core/lib/promise/if.h"
65
62
  #include "src/core/lib/promise/loop.h"
66
63
  #include "src/core/lib/promise/map.h"
67
- #include "src/core/lib/promise/match_promise.h"
68
64
  #include "src/core/lib/promise/party.h"
69
65
  #include "src/core/lib/promise/poll.h"
70
66
  #include "src/core/lib/promise/promise.h"
71
67
  #include "src/core/lib/promise/race.h"
72
68
  #include "src/core/lib/promise/sleep.h"
69
+ #include "src/core/lib/promise/status_flag.h"
73
70
  #include "src/core/lib/promise/try_seq.h"
74
71
  #include "src/core/lib/resource_quota/arena.h"
75
72
  #include "src/core/lib/resource_quota/resource_quota.h"
@@ -85,25 +82,24 @@
85
82
  #include "src/core/util/ref_counted_ptr.h"
86
83
  #include "src/core/util/sync.h"
87
84
  #include "src/core/util/time.h"
88
- #include "absl/base/thread_annotations.h"
89
85
  #include "absl/container/flat_hash_map.h"
90
86
  #include "absl/log/log.h"
91
87
  #include "absl/status/status.h"
92
88
  #include "absl/strings/cord.h"
93
89
  #include "absl/strings/str_cat.h"
94
90
  #include "absl/strings/string_view.h"
95
- #include "absl/types/span.h"
96
91
 
97
92
  namespace grpc_core {
98
93
  namespace http2 {
99
94
 
100
- // TODO(akshitpatel)(tjagtap) [PH2][P2] : When settings frame increases incoming
95
+ // TODO(akshitpatel)(tjagtap) [PH2][P1] : When settings frame increases incoming
101
96
  // window size, our transport must make the streams that were blocked on stream
102
97
  // flow control as writeable.
103
98
 
104
99
  // As a gRPC server never initiates a stream, the last incoming stream id on
105
100
  // the client side will always be 0.
106
101
  constexpr uint32_t kLastIncomingStreamIdClient = 0;
102
+ const bool kIsClient = true;
107
103
 
108
104
  using grpc_event_engine::experimental::EventEngine;
109
105
  using StreamWritabilityUpdate =
@@ -113,39 +109,13 @@ using StreamWritabilityUpdate =
113
109
  // and it is functions. The code will be written iteratively.
114
110
  // Do not use or edit any of these functions unless you are
115
111
  // familiar with the PH2 project (Moving chttp2 to promises.)
116
- // TODO(tjagtap) : [PH2][P3] : Delete this comment when http2
117
- // rollout begins
118
-
119
- template <typename Factory>
120
- void Http2ClientTransport::SpawnInfallible(RefCountedPtr<Party> party,
121
- absl::string_view name,
122
- Factory&& factory) {
123
- party->Spawn(name, std::forward<Factory>(factory), [](Empty) {});
124
- }
125
-
126
- template <typename Factory>
127
- void Http2ClientTransport::SpawnInfallibleTransportParty(absl::string_view name,
128
- Factory&& factory) {
129
- SpawnInfallible(general_party_, name, std::forward<Factory>(factory));
130
- }
131
-
132
- template <typename Factory>
133
- void Http2ClientTransport::SpawnGuardedTransportParty(absl::string_view name,
134
- Factory&& factory) {
135
- general_party_->Spawn(
136
- name, std::forward<Factory>(factory),
137
- [self = RefAsSubclass<Http2ClientTransport>()](absl::Status status) {
138
- if (!status.ok()) {
139
- GRPC_UNUSED absl::Status error = self->HandleError(
140
- /*stream_id=*/std::nullopt, ToHttpOkOrConnError(status));
141
- }
142
- });
143
- }
112
+ // TODO(tjagtap) : [PH2][P5] : Update the experimental status of the code when
113
+ // http2 rollout is completed.
144
114
 
145
115
  void Http2ClientTransport::PerformOp(grpc_transport_op* op) {
146
116
  // Notes : Refer : src/core/ext/transport/chaotic_good/client_transport.cc
147
117
  // Functions : StartConnectivityWatch, StopConnectivityWatch, PerformOp
148
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport PerformOp Begin";
118
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::PerformOp Begin";
149
119
  bool did_stuff = false;
150
120
  if (op->start_connectivity_watch != nullptr) {
151
121
  StartConnectivityWatch(op->start_connectivity_watch_state,
@@ -161,7 +131,7 @@ void Http2ClientTransport::PerformOp(grpc_transport_op* op) {
161
131
  GRPC_DCHECK(did_stuff) << "Unimplemented transport perform op ";
162
132
 
163
133
  ExecCtx::Run(DEBUG_LOCATION, op->on_consumed, absl::OkStatus());
164
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport PerformOp End";
134
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::PerformOp End";
165
135
  // TODO(tjagtap) : [PH2][P2] :
166
136
  // Refer src/core/ext/transport/chttp2/transport/chttp2_transport.cc
167
137
  // perform_transport_op_locked
@@ -193,8 +163,9 @@ void Http2ClientTransport::ReportDisconnection(
193
163
  void Http2ClientTransport::ReportDisconnectionLocked(
194
164
  const absl::Status& status, StateWatcher::DisconnectInfo disconnect_info,
195
165
  const char* reason) {
196
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ReportDisconnection: status="
197
- << status.ToString() << "; reason=" << reason;
166
+ GRPC_HTTP2_CLIENT_DLOG
167
+ << "Http2ClientTransport::ReportDisconnectionLocked status="
168
+ << status.ToString() << "; reason=" << reason;
198
169
  state_tracker_.SetState(GRPC_CHANNEL_TRANSIENT_FAILURE, status, reason);
199
170
  NotifyStateWatcherOnDisconnectLocked(status, disconnect_info);
200
171
  }
@@ -230,8 +201,27 @@ void Http2ClientTransport::NotifyStateWatcherOnDisconnectLocked(
230
201
  });
231
202
  }
232
203
 
204
+ absl::Status Http2ClientTransport::AckPing(uint64_t opaque_data) {
205
+ // It is possible that the PingRatePolicy may decide to not send a ping
206
+ // request (in cases like the number of inflight pings is too high).
207
+ // When this happens, it becomes important to ensure that if a ping ack
208
+ // is received and there is an "important" outstanding ping request, we
209
+ // should retry to send it out now.
210
+ if (ping_manager_->AckPing(opaque_data)) {
211
+ if (ping_manager_->ImportantPingRequested()) {
212
+ return TriggerWriteCycle();
213
+ }
214
+ } else {
215
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::AckPing Unknown ping "
216
+ "response received for ping id="
217
+ << opaque_data;
218
+ }
219
+
220
+ return absl::OkStatus();
221
+ }
222
+
233
223
  void Http2ClientTransport::Orphan() {
234
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Orphan Begin";
224
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::Orphan Begin";
235
225
  // Accessing general_party here is not advisable. It may so happen that
236
226
  // the party is already freed/may free up any time. The only guarantee here
237
227
  // is that the transport is still valid.
@@ -239,37 +229,33 @@ void Http2ClientTransport::Orphan() {
239
229
  MaybeSpawnCloseTransport(
240
230
  ToHttpOkOrConnError(absl::UnavailableError("Orphaned")));
241
231
  Unref();
242
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Orphan End";
232
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::Orphan End";
243
233
  }
244
234
 
245
235
  ///////////////////////////////////////////////////////////////////////////////
246
236
  // Processing each type of frame
247
237
 
248
- Http2Status Http2ClientTransport::ProcessHttp2DataFrame(Http2DataFrame frame) {
238
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(Http2DataFrame&& frame) {
249
239
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-data
250
240
  GRPC_HTTP2_CLIENT_DLOG
251
- << "Http2ClientTransport ProcessHttp2DataFrame { stream_id="
252
- << frame.stream_id << ", end_stream=" << frame.end_stream
253
- << ", payload=" << MaybeTruncatePayload(frame.payload)
241
+ << "Http2ClientTransport::ProcessIncomingFrame(DataFrame) { stream_id="
242
+ << frame.stream_id << ", end_stream:" << frame.end_stream
254
243
  << ", payload length=" << frame.payload.Length() << "}";
255
244
 
256
245
  // TODO(akshitpatel) : [PH2][P3] : Investigate if we should do this even if
257
246
  // the function returns a non-ok status?
258
247
  ping_manager_->ReceivedDataFrame();
259
248
 
260
- // Lookup stream
261
- GRPC_HTTP2_CLIENT_DLOG
262
- << "Http2ClientTransport ProcessHttp2DataFrame LookupStream";
263
249
  RefCountedPtr<Stream> stream = LookupStream(frame.stream_id);
264
250
 
265
251
  ValueOrHttp2Status<chttp2::FlowControlAction> flow_control_action =
266
252
  ProcessIncomingDataFrameFlowControl(current_frame_header_, flow_control_,
267
- stream);
253
+ stream.get());
268
254
  if (!flow_control_action.IsOk()) {
269
255
  return ValueOrHttp2Status<chttp2::FlowControlAction>::TakeStatus(
270
256
  std::move(flow_control_action));
271
257
  }
272
- ActOnFlowControlAction(flow_control_action.value(), stream);
258
+ ActOnFlowControlAction(flow_control_action.value(), stream.get());
273
259
 
274
260
  if (stream == nullptr) {
275
261
  // TODO(tjagtap) : [PH2][P2] : Implement the correct behaviour later.
@@ -277,7 +263,7 @@ Http2Status Http2ClientTransport::ProcessHttp2DataFrame(Http2DataFrame frame) {
277
263
  // or "half-closed (local)" state, the recipient MUST respond with a stream
278
264
  // error (Section 5.4.2) of type STREAM_CLOSED.
279
265
  GRPC_HTTP2_CLIENT_DLOG
280
- << "Http2ClientTransport ProcessHttp2DataFrame { stream_id="
266
+ << "Http2ClientTransport::ProcessIncomingFrame(DataFrame) { stream_id="
281
267
  << frame.stream_id << "} Lookup Failed";
282
268
  return Http2Status::Ok();
283
269
  }
@@ -292,36 +278,41 @@ Http2Status Http2ClientTransport::ProcessHttp2DataFrame(Http2DataFrame frame) {
292
278
 
293
279
  // Add frame to assembler
294
280
  GRPC_HTTP2_CLIENT_DLOG
295
- << "Http2ClientTransport ProcessHttp2DataFrame AppendNewDataFrame";
296
- GrpcMessageAssembler& assembler = stream->assembler;
281
+ << "Http2ClientTransport::ProcessIncomingFrame(DataFrame) "
282
+ "AppendNewDataFrame";
283
+ GrpcMessageAssembler& assembler = stream->GetGrpcMessageAssembler();
297
284
  Http2Status status =
298
285
  assembler.AppendNewDataFrame(frame.payload, frame.end_stream);
299
286
  if (!status.IsOk()) {
300
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessHttp2DataFrame "
301
- "AppendNewDataFrame Failed";
287
+ GRPC_HTTP2_CLIENT_DLOG
288
+ << "Http2ClientTransport::ProcessIncomingFrame(DataFrame) "
289
+ "AppendNewDataFrame Failed";
302
290
  return status;
303
291
  }
304
292
 
305
293
  // Pass the messages up the stack if it is ready.
306
294
  while (true) {
307
295
  GRPC_HTTP2_CLIENT_DLOG
308
- << "Http2ClientTransport ProcessHttp2DataFrame ExtractMessage";
296
+ << "Http2ClientTransport::ProcessIncomingFrame(DataFrame) "
297
+ "ExtractMessage";
309
298
  ValueOrHttp2Status<MessageHandle> result = assembler.ExtractMessage();
310
299
  if (!result.IsOk()) {
311
300
  GRPC_HTTP2_CLIENT_DLOG
312
- << "Http2ClientTransport ProcessHttp2DataFrame ExtractMessage Failed";
301
+ << "Http2ClientTransport::ProcessIncomingFrame(DataFrame) "
302
+ "ExtractMessage Failed";
313
303
  return ValueOrHttp2Status<MessageHandle>::TakeStatus(std::move(result));
314
304
  }
315
305
  MessageHandle message = TakeValue(std::move(result));
316
306
  if (message != nullptr) {
317
307
  GRPC_HTTP2_CLIENT_DLOG
318
- << "Http2ClientTransport ProcessHttp2DataFrame SpawnPushMessage "
308
+ << "Http2ClientTransport::ProcessIncomingFrame(DataFrame) "
309
+ "SpawnPushMessage "
319
310
  << message->DebugString();
320
- stream->call.SpawnPushMessage(std::move(message));
311
+ stream->GetCallHandler().SpawnPushMessage(std::move(message));
321
312
  continue;
322
313
  }
323
314
  GRPC_HTTP2_CLIENT_DLOG
324
- << "Http2ClientTransport ProcessHttp2DataFrame While Break";
315
+ << "Http2ClientTransport::ProcessIncomingFrame(DataFrame) While Break";
325
316
  break;
326
317
  }
327
318
 
@@ -337,14 +328,13 @@ Http2Status Http2ClientTransport::ProcessHttp2DataFrame(Http2DataFrame frame) {
337
328
  return Http2Status::Ok();
338
329
  }
339
330
 
340
- Http2Status Http2ClientTransport::ProcessHttp2HeaderFrame(
341
- Http2HeaderFrame frame) {
331
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(
332
+ Http2HeaderFrame&& frame) {
342
333
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-headers
343
334
  GRPC_HTTP2_CLIENT_DLOG
344
- << "Http2ClientTransport ProcessHttp2HeaderFrame Promise { stream_id="
335
+ << "Http2ClientTransport::ProcessIncomingFrame(HeaderFrame) { stream_id="
345
336
  << frame.stream_id << ", end_headers=" << frame.end_headers
346
- << ", end_stream=" << frame.end_stream
347
- << ", payload=" << MaybeTruncatePayload(frame.payload) << " }";
337
+ << ", end_stream=" << frame.end_stream << " }";
348
338
  // State update MUST happen before processing the frame.
349
339
  incoming_headers_.OnHeaderReceived(frame);
350
340
 
@@ -360,7 +350,8 @@ Http2Status Http2ClientTransport::ProcessHttp2HeaderFrame(
360
350
  // receives an unexpected stream identifier MUST respond with a connection
361
351
  // error (Section 5.4.1) of type PROTOCOL_ERROR.
362
352
  GRPC_HTTP2_CLIENT_DLOG
363
- << "Http2ClientTransport ProcessHttp2HeaderFrame Promise { stream_id="
353
+ << "Http2ClientTransport::ProcessIncomingFrame(HeaderFrame) { "
354
+ "stream_id="
364
355
  << frame.stream_id << "} Lookup Failed";
365
356
  return ParseAndDiscardHeaders(std::move(frame.payload), frame.end_headers,
366
357
  /*stream=*/nullptr, Http2Status::Ok());
@@ -368,85 +359,49 @@ Http2Status Http2ClientTransport::ProcessHttp2HeaderFrame(
368
359
 
369
360
  if (stream->IsStreamHalfClosedRemote()) {
370
361
  return ParseAndDiscardHeaders(
371
- std::move(frame.payload), frame.end_headers, stream,
362
+ std::move(frame.payload), frame.end_headers, stream.get(),
372
363
  Http2Status::Http2StreamError(
373
364
  Http2ErrorCode::kStreamClosed,
374
365
  std::string(RFC9113::kHalfClosedRemoteState)));
375
366
  }
376
367
 
377
- if (incoming_headers_.ClientReceivedDuplicateMetadata(
378
- stream->did_receive_initial_metadata,
379
- stream->did_receive_trailing_metadata)) {
368
+ if (incoming_headers_.DidReceiveDuplicateMetadata(
369
+ stream->IsInitialMetadataReceived(),
370
+ stream->IsTrailingMetadataReceived())) {
380
371
  return ParseAndDiscardHeaders(
381
- std::move(frame.payload), frame.end_headers, stream,
372
+ std::move(frame.payload), frame.end_headers, stream.get(),
382
373
  Http2Status::Http2StreamError(
383
374
  Http2ErrorCode::kInternalError,
384
375
  std::string(GrpcErrors::kTooManyMetadata)));
385
376
  }
386
377
 
387
- Http2Status append_result = stream->header_assembler.AppendHeaderFrame(frame);
378
+ Http2Status append_result =
379
+ stream->GetHeaderAssembler().AppendHeaderFrame(frame);
388
380
  if (!append_result.IsOk()) {
389
381
  // Frame payload is not consumed if AppendHeaderFrame returns a non-OK
390
382
  // status. We need to process it to keep our in consistent state.
391
383
  return ParseAndDiscardHeaders(std::move(frame.payload), frame.end_headers,
392
- stream, std::move(append_result));
384
+ stream.get(), std::move(append_result));
393
385
  }
394
386
 
395
387
  Http2Status status = ProcessMetadata(stream);
396
388
  if (!status.IsOk()) {
397
389
  // Frame payload has been moved to the HeaderAssembler. So calling
398
390
  // ParseAndDiscardHeaders with an empty buffer.
399
- return ParseAndDiscardHeaders(SliceBuffer(), frame.end_headers, stream,
400
- std::move(status));
391
+ return ParseAndDiscardHeaders(SliceBuffer(), frame.end_headers,
392
+ stream.get(), std::move(status));
401
393
  }
402
394
 
403
395
  // Frame payload has either been processed or moved to the HeaderAssembler.
404
396
  return Http2Status::Ok();
405
397
  }
406
398
 
407
- Http2Status Http2ClientTransport::ProcessMetadata(
408
- RefCountedPtr<Stream> stream) {
409
- HeaderAssembler& assembler = stream->header_assembler;
410
- CallHandler call = stream->call;
411
-
412
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessMetadata";
413
- if (assembler.IsReady()) {
414
- ValueOrHttp2Status<ServerMetadataHandle> read_result =
415
- assembler.ReadMetadata(parser_, !incoming_headers_.HeaderHasEndStream(),
416
- /*is_client=*/true,
417
- /*max_header_list_size_soft_limit=*/
418
- incoming_headers_.soft_limit(),
419
- /*max_header_list_size_hard_limit=*/
420
- settings_->acked().max_header_list_size());
421
- if (read_result.IsOk()) {
422
- ServerMetadataHandle metadata = TakeValue(std::move(read_result));
423
- if (incoming_headers_.HeaderHasEndStream()) {
424
- // TODO(tjagtap) : [PH2][P1] : Is this the right way to differentiate
425
- // between initial and trailing metadata?
426
- stream->MarkHalfClosedRemote();
427
- stream->did_receive_trailing_metadata = true;
428
- BeginCloseStream(stream, /*reset_stream_error_code=*/std::nullopt,
429
- std::move(metadata));
430
- } else {
431
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessMetadata "
432
- "SpawnPushServerInitialMetadata";
433
- stream->did_receive_initial_metadata = true;
434
- call.SpawnPushServerInitialMetadata(std::move(metadata));
435
- }
436
- return Http2Status::Ok();
437
- }
438
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessMetadata Failed";
439
- return ValueOrHttp2Status<Arena::PoolPtr<grpc_metadata_batch>>::TakeStatus(
440
- std::move(read_result));
441
- }
442
- return Http2Status::Ok();
443
- }
444
-
445
- Http2Status Http2ClientTransport::ProcessHttp2RstStreamFrame(
446
- Http2RstStreamFrame frame) {
399
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(
400
+ Http2RstStreamFrame&& frame) {
447
401
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-rst_stream
448
402
  GRPC_HTTP2_CLIENT_DLOG
449
- << "Http2ClientTransport ProcessHttp2RstStreamFrame { stream_id="
403
+ << "Http2ClientTransport::ProcessIncomingFrame(RstStreamFrame) { "
404
+ "stream_id="
450
405
  << frame.stream_id << ", error_code=" << frame.error_code << " }";
451
406
 
452
407
  Http2ErrorCode error_code = FrameErrorCodeToHttp2ErrorCode(frame.error_code);
@@ -455,7 +410,8 @@ Http2Status Http2ClientTransport::ProcessHttp2RstStreamFrame(
455
410
  RefCountedPtr<Stream> stream = LookupStream(frame.stream_id);
456
411
  if (stream != nullptr) {
457
412
  stream->MarkHalfClosedRemote();
458
- BeginCloseStream(stream, /*reset_stream_error_code=*/std::nullopt,
413
+ BeginCloseStream(std::move(stream),
414
+ /*reset_stream_error_code=*/std::nullopt,
459
415
  CancelledServerMetadataFromStatus(status));
460
416
  }
461
417
 
@@ -464,13 +420,13 @@ Http2Status Http2ClientTransport::ProcessHttp2RstStreamFrame(
464
420
  return Http2Status::Ok();
465
421
  }
466
422
 
467
- Http2Status Http2ClientTransport::ProcessHttp2SettingsFrame(
468
- Http2SettingsFrame frame) {
423
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(
424
+ Http2SettingsFrame&& frame) {
469
425
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-settings
470
426
 
471
427
  GRPC_HTTP2_CLIENT_DLOG
472
- << "Http2ClientTransport ProcessHttp2SettingsFrame { ack=" << frame.ack
473
- << ", settings length=" << frame.settings.size() << "}";
428
+ << "Http2ClientTransport::ProcessIncomingFrame(SettingsFrame) { ack="
429
+ << frame.ack << ", settings length=" << frame.settings.size() << "}";
474
430
 
475
431
  if (!frame.ack) {
476
432
  Http2Status status = ValidateSettingsValues(frame.settings);
@@ -478,7 +434,11 @@ Http2Status Http2ClientTransport::ProcessHttp2SettingsFrame(
478
434
  return status;
479
435
  }
480
436
  settings_->BufferPeerSettings(std::move(frame.settings));
481
- SpawnGuardedTransportParty("SettingsAck", TriggerWriteCycle());
437
+ absl::Status trigger_write_status = TriggerWriteCycle();
438
+ if (!trigger_write_status.ok()) {
439
+ return ToHttpOkOrConnError(trigger_write_status);
440
+ }
441
+
482
442
  if (GPR_UNLIKELY(!settings_->IsFirstPeerSettingsApplied())) {
483
443
  // Apply the first settings before we read any other frames.
484
444
  reader_state_.SetPauseReadLoop();
@@ -501,63 +461,53 @@ Http2Status Http2ClientTransport::ProcessHttp2SettingsFrame(
501
461
  return Http2Status::Ok();
502
462
  }
503
463
 
504
- auto Http2ClientTransport::ProcessHttp2PingFrame(Http2PingFrame frame) {
464
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(Http2PingFrame&& frame) {
505
465
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-ping
506
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessHttp2PingFrame { ack="
507
- << frame.ack << ", opaque=" << frame.opaque << " }";
508
- return AssertResultType<Http2Status>(If(
509
- frame.ack,
510
- [self = RefAsSubclass<Http2ClientTransport>(), opaque = frame.opaque]() {
511
- // Received a ping ack.
512
- return self->AckPing(opaque);
513
- },
514
- [self = RefAsSubclass<Http2ClientTransport>(), opaque = frame.opaque]() {
515
- return If(
516
- self->test_only_ack_pings_,
517
- [self, opaque]() {
518
- // TODO(akshitpatel) : [PH2][P2] : Have a counter to track number
519
- // of pending induced frames (Ping/Settings Ack). This is to
520
- // ensure that if write is taking a long time, we can stop reads
521
- // and prioritize writes. RFC9113: PING responses SHOULD be given
522
- // higher priority than any other frame.
523
- self->ping_manager_->AddPendingPingAck(opaque);
524
- // TODO(akshitpatel) : [PH2][P2] : This is done assuming that the
525
- // other ProcessFrame promises may return stream or connection
526
- // failures. If this does not turn out to be true, consider
527
- // returning absl::Status here.
528
- return Map(self->TriggerWriteCycle(), [](absl::Status status) {
529
- return ToHttpOkOrConnError(status);
530
- });
531
- },
532
- []() {
533
- GRPC_HTTP2_CLIENT_DLOG
534
- << "Http2ClientTransport ProcessHttp2PingFrame "
535
- "test_only_ack_pings_ is false. Ignoring the ping "
536
- "request.";
537
- return Immediate(Http2Status::Ok());
538
- });
539
- }));
466
+ GRPC_HTTP2_CLIENT_DLOG
467
+ << "Http2ClientTransport::ProcessIncomingFrame(PingFrame) { ack="
468
+ << frame.ack << ", opaque=" << frame.opaque << " }";
469
+ if (frame.ack) {
470
+ return ToHttpOkOrConnError(AckPing(frame.opaque));
471
+ } else {
472
+ if (test_only_ack_pings_) {
473
+ // TODO(akshitpatel) : [PH2][P2] : Have a counter to track number
474
+ // of pending induced frames (Ping/Settings Ack). This is to
475
+ // ensure that if write is taking a long time, we can stop reads
476
+ // and prioritize writes. RFC9113: PING responses SHOULD be given
477
+ // higher priority than any other frame.
478
+ ping_manager_->AddPendingPingAck(frame.opaque);
479
+ // TODO(akshitpatel) : [PH2][P2] : This is done assuming that the
480
+ // other ProcessFrame promises may return stream or connection
481
+ // failures. If this does not turn out to be true, consider
482
+ // returning absl::Status here.
483
+ return ToHttpOkOrConnError(TriggerWriteCycle());
484
+ } else {
485
+ GRPC_HTTP2_CLIENT_DLOG
486
+ << "Http2ClientTransport::ProcessIncomingFrame(PingFrame) "
487
+ "test_only_ack_pings_ is false. Ignoring the ping request.";
488
+ }
489
+ }
490
+ return Http2Status::Ok();
540
491
  }
541
492
 
542
- Http2Status Http2ClientTransport::ProcessHttp2GoawayFrame(
543
- Http2GoawayFrame frame) {
493
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(
494
+ Http2GoawayFrame&& frame) {
544
495
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-goaway
545
496
  GRPC_HTTP2_CLIENT_DLOG
546
- << "Http2ClientTransport ProcessHttp2GoawayFrame Promise { "
497
+ << "Http2ClientTransport::ProcessIncomingFrame(GoawayFrame) { "
547
498
  "last_stream_id="
548
- << frame.last_stream_id << ", error_code=" << frame.error_code
549
- << ", debug_data=" << frame.debug_data.as_string_view() << "}";
499
+ << frame.last_stream_id << ", error_code=" << frame.error_code << "}";
550
500
  LOG_IF(ERROR,
551
501
  frame.error_code != static_cast<uint32_t>(Http2ErrorCode::kNoError))
552
- << "Received GOAWAY frame with error code: " << frame.error_code
553
- << " and debug data: " << frame.debug_data.as_string_view();
502
+ << "Received GOAWAY frame with error code: " << frame.error_code;
554
503
 
555
504
  uint32_t last_stream_id = 0;
556
505
  absl::Status status(ErrorCodeToAbslStatusCode(
557
506
  FrameErrorCodeToHttp2ErrorCode(frame.error_code)),
558
- frame.debug_data.as_string_view());
559
- if (frame.error_code == static_cast<uint32_t>(Http2ErrorCode::kNoError) &&
560
- frame.last_stream_id == RFC9113::kMaxStreamId31Bit) {
507
+ frame.debug_data.empty()
508
+ ? absl::string_view("GOAWAY received")
509
+ : frame.debug_data.as_string_view());
510
+ if (GoawayManager::IsGracefulGoaway(frame)) {
561
511
  const uint32_t next_stream_id = PeekNextStreamId();
562
512
  last_stream_id = (next_stream_id > 1) ? next_stream_id - 2 : 0;
563
513
  } else {
@@ -570,7 +520,8 @@ Http2Status Http2ClientTransport::ProcessHttp2GoawayFrame(
570
520
  MutexLock lock(&transport_mutex_);
571
521
  if (CanCloseTransportLocked()) {
572
522
  close_transport = true;
573
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessHttp2GoawayFrame "
523
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::ProcessIncomingFrame("
524
+ "GoawayFrame) "
574
525
  "stream_list_ is empty";
575
526
  }
576
527
  }
@@ -596,7 +547,7 @@ Http2Status Http2ClientTransport::ProcessHttp2GoawayFrame(
596
547
  keepalive_time_.millis() > max_keepalive_time_millis
597
548
  ? INT_MAX
598
549
  : keepalive_time_.millis() * KEEPALIVE_TIME_BACKOFF_MULTIPLIER;
599
- if (!IsTransportStateWatcherEnabled()) {
550
+ if (!IsSubchannelConnectionScalingEnabled()) {
600
551
  status.SetPayload(kKeepaliveThrottlingKey,
601
552
  absl::Cord(std::to_string(throttled_keepalive_time)));
602
553
  }
@@ -614,7 +565,9 @@ Http2Status Http2ClientTransport::ProcessHttp2GoawayFrame(
614
565
  Http2ErrorCodeToFrameErrorCode(Http2ErrorCode::kNoError)
615
566
  ? Http2ErrorCodeToFrameErrorCode(Http2ErrorCode::kInternalError)
616
567
  : frame.error_code)),
617
- std::string(frame.debug_data.as_string_view())));
568
+ frame.debug_data.empty()
569
+ ? std::string("GOAWAY received")
570
+ : std::string(frame.debug_data.as_string_view())));
618
571
  }
619
572
 
620
573
  // lie: use transient failure from the transport to indicate goaway has been
@@ -623,11 +576,11 @@ Http2Status Http2ClientTransport::ProcessHttp2GoawayFrame(
623
576
  return Http2Status::Ok();
624
577
  }
625
578
 
626
- Http2Status Http2ClientTransport::ProcessHttp2WindowUpdateFrame(
627
- Http2WindowUpdateFrame frame) {
579
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(
580
+ Http2WindowUpdateFrame&& frame) {
628
581
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-window_update
629
582
  GRPC_HTTP2_CLIENT_DLOG
630
- << "Http2ClientTransport ProcessHttp2WindowUpdateFrame Promise { "
583
+ << "Http2ClientTransport::ProcessIncomingFrame(WindowUpdateFrame) { "
631
584
  " stream_id="
632
585
  << frame.stream_id << ", increment=" << frame.increment << "}";
633
586
 
@@ -647,22 +600,21 @@ Http2Status Http2ClientTransport::ProcessHttp2WindowUpdateFrame(
647
600
  }
648
601
  }
649
602
 
650
- const bool should_trigger_write =
651
- ProcessIncomingWindowUpdateFrameFlowControl(frame, flow_control_, stream);
603
+ const bool should_trigger_write = ProcessIncomingWindowUpdateFrameFlowControl(
604
+ frame, flow_control_, stream.get());
652
605
  if (should_trigger_write) {
653
- SpawnGuardedTransportParty("TransportTokensAvailable", TriggerWriteCycle());
606
+ return ToHttpOkOrConnError(TriggerWriteCycle());
654
607
  }
655
608
  return Http2Status::Ok();
656
609
  }
657
610
 
658
- Http2Status Http2ClientTransport::ProcessHttp2ContinuationFrame(
659
- Http2ContinuationFrame frame) {
611
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(
612
+ Http2ContinuationFrame&& frame) {
660
613
  // https://www.rfc-editor.org/rfc/rfc9113.html#name-continuation
661
614
  GRPC_HTTP2_CLIENT_DLOG
662
- << "Http2ClientTransport ProcessHttp2ContinuationFrame Promise { "
615
+ << "Http2ClientTransport::ProcessIncomingFrame(ContinuationFrame) { "
663
616
  "stream_id="
664
- << frame.stream_id << ", end_headers=" << frame.end_headers
665
- << ", payload=" << MaybeTruncatePayload(frame.payload) << " }";
617
+ << frame.stream_id << ", end_headers=" << frame.end_headers << " }";
666
618
 
667
619
  // State update MUST happen before processing the frame.
668
620
  incoming_headers_.OnContinuationReceived(frame);
@@ -682,102 +634,102 @@ Http2Status Http2ClientTransport::ProcessHttp2ContinuationFrame(
682
634
 
683
635
  if (stream->IsStreamHalfClosedRemote()) {
684
636
  return ParseAndDiscardHeaders(
685
- std::move(frame.payload), frame.end_headers, stream,
637
+ std::move(frame.payload), frame.end_headers, stream.get(),
686
638
  Http2Status::Http2StreamError(
687
639
  Http2ErrorCode::kStreamClosed,
688
640
  std::string(RFC9113::kHalfClosedRemoteState)));
689
641
  }
690
642
 
691
643
  Http2Status append_result =
692
- stream->header_assembler.AppendContinuationFrame(frame);
644
+ stream->GetHeaderAssembler().AppendContinuationFrame(frame);
693
645
  if (!append_result.IsOk()) {
694
646
  // Frame payload is not consumed if AppendContinuationFrame returns a
695
647
  // non-OK status. We need to process it to keep our in consistent state.
696
648
  return ParseAndDiscardHeaders(std::move(frame.payload), frame.end_headers,
697
- stream, std::move(append_result));
649
+ stream.get(), std::move(append_result));
698
650
  }
699
651
 
700
652
  Http2Status status = ProcessMetadata(stream);
701
653
  if (!status.IsOk()) {
702
654
  // Frame payload is consumed by HeaderAssembler. So passing an empty
703
655
  // SliceBuffer to ParseAndDiscardHeaders.
704
- return ParseAndDiscardHeaders(SliceBuffer(), frame.end_headers, stream,
705
- std::move(status));
656
+ return ParseAndDiscardHeaders(SliceBuffer(), frame.end_headers,
657
+ stream.get(), std::move(status));
706
658
  }
707
659
 
708
660
  // Frame payload has either been processed or moved to the HeaderAssembler.
709
661
  return Http2Status::Ok();
710
662
  }
711
663
 
712
- Http2Status Http2ClientTransport::ProcessHttp2SecurityFrame(
713
- Http2SecurityFrame frame) {
714
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessHttp2SecurityFrame "
715
- "{ payload.Length="
716
- << frame.payload.Length() << " }";
664
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(
665
+ Http2SecurityFrame&& frame) {
666
+ GRPC_HTTP2_CLIENT_DLOG
667
+ << "Http2ClientTransport::ProcessIncomingFrame(SecurityFrame) ";
717
668
  if (settings_->IsSecurityFrameExpected()) {
718
- // TODO(tjagtap) : [PH2][P3] : Add handling of Security frame
719
- // Just the frame.payload needs to be passed to the endpoint_ object.
720
- // Refer usage of TransportFramingEndpointExtension.
669
+ security_frame_handler_->ProcessPayload(std::move(frame.payload));
721
670
  }
722
- // Ignore the Security frame if it is not expected.
723
671
  return Http2Status::Ok();
724
672
  }
725
673
 
726
- auto Http2ClientTransport::ProcessOneFrame(Http2Frame frame) {
727
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ProcessOneFrame Factory";
728
- return AssertResultType<Http2Status>(MatchPromise(
729
- std::move(frame),
730
- [self = RefAsSubclass<Http2ClientTransport>()](Http2DataFrame frame) {
731
- return self->ProcessHttp2DataFrame(std::move(frame));
732
- },
733
- [self = RefAsSubclass<Http2ClientTransport>()](Http2HeaderFrame frame) {
734
- return self->ProcessHttp2HeaderFrame(std::move(frame));
735
- },
736
- [self =
737
- RefAsSubclass<Http2ClientTransport>()](Http2RstStreamFrame frame) {
738
- return self->ProcessHttp2RstStreamFrame(frame);
739
- },
740
- [self = RefAsSubclass<Http2ClientTransport>()](Http2SettingsFrame frame) {
741
- return self->ProcessHttp2SettingsFrame(std::move(frame));
742
- },
743
- [self = RefAsSubclass<Http2ClientTransport>()](Http2PingFrame frame) {
744
- return self->ProcessHttp2PingFrame(frame);
745
- },
746
- [self = RefAsSubclass<Http2ClientTransport>()](Http2GoawayFrame frame) {
747
- return self->ProcessHttp2GoawayFrame(std::move(frame));
748
- },
749
- [self = RefAsSubclass<Http2ClientTransport>()](
750
- Http2WindowUpdateFrame frame) {
751
- return self->ProcessHttp2WindowUpdateFrame(frame);
752
- },
753
- [self = RefAsSubclass<Http2ClientTransport>()](
754
- Http2ContinuationFrame frame) {
755
- return self->ProcessHttp2ContinuationFrame(std::move(frame));
756
- },
757
- [self = RefAsSubclass<Http2ClientTransport>()](Http2SecurityFrame frame) {
758
- return self->ProcessHttp2SecurityFrame(std::move(frame));
759
- },
760
- [](GRPC_UNUSED Http2UnknownFrame frame) {
761
- // RFC9113: Implementations MUST ignore and discard frames of
762
- // unknown types.
763
- return Http2Status::Ok();
764
- },
765
- [](GRPC_UNUSED Http2EmptyFrame frame) {
766
- LOG(DFATAL)
767
- << "ParseFramePayload should never return a Http2EmptyFrame";
768
- return Http2Status::Ok();
769
- }));
674
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(
675
+ GRPC_UNUSED Http2UnknownFrame&& frame) {
676
+ // RFC9113: Implementations MUST ignore and discard frames of
677
+ // unknown types.
678
+ GRPC_HTTP2_CLIENT_DLOG
679
+ << "Http2ClientTransport::ProcessIncomingFrame(UnknownFrame) ";
680
+ return Http2Status::Ok();
681
+ }
682
+
683
+ Http2Status Http2ClientTransport::ProcessIncomingFrame(
684
+ GRPC_UNUSED Http2EmptyFrame&& frame) {
685
+ LOG(DFATAL) << "ParseFramePayload should never return a Http2EmptyFrame";
686
+ return Http2Status::Ok();
687
+ }
688
+
689
+ Http2Status Http2ClientTransport::ProcessMetadata(
690
+ RefCountedPtr<Stream> stream) {
691
+ HeaderAssembler& assembler = stream->GetHeaderAssembler();
692
+ CallHandler& call = stream->GetCallHandler();
693
+
694
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::ProcessMetadata";
695
+ if (assembler.IsReady()) {
696
+ ValueOrHttp2Status<ServerMetadataHandle> read_result =
697
+ assembler.ReadMetadata(parser_, !incoming_headers_.HeaderHasEndStream(),
698
+ /*max_header_list_size_soft_limit=*/
699
+ incoming_headers_.soft_limit(),
700
+ /*max_header_list_size_hard_limit=*/
701
+ settings_->acked().max_header_list_size());
702
+ if (read_result.IsOk()) {
703
+ ServerMetadataHandle metadata = TakeValue(std::move(read_result));
704
+ if (incoming_headers_.HeaderHasEndStream()) {
705
+ stream->MarkHalfClosedRemote();
706
+ stream->SetTrailingMetadataReceived();
707
+ BeginCloseStream(std::move(stream),
708
+ /*reset_stream_error_code=*/std::nullopt,
709
+ std::move(metadata));
710
+ } else {
711
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::ProcessMetadata "
712
+ "SpawnPushServerInitialMetadata";
713
+ metadata->Set(PeerString(), incoming_headers_.peer_string());
714
+ stream->SetInitialMetadataReceived();
715
+ call.SpawnPushServerInitialMetadata(std::move(metadata));
716
+ }
717
+ return Http2Status::Ok();
718
+ }
719
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::ProcessMetadata Failed";
720
+ return ValueOrHttp2Status<Arena::PoolPtr<grpc_metadata_batch>>::TakeStatus(
721
+ std::move(read_result));
722
+ }
723
+ return Http2Status::Ok();
770
724
  }
771
725
 
772
726
  Http2Status Http2ClientTransport::ParseAndDiscardHeaders(
773
- SliceBuffer&& buffer, const bool is_end_headers,
774
- const RefCountedPtr<Stream> stream, Http2Status&& original_status,
775
- DebugLocation whence) {
727
+ SliceBuffer&& buffer, const bool is_end_headers, Stream* stream,
728
+ Http2Status&& original_status, DebugLocation whence) {
776
729
  const bool is_initial_metadata = !incoming_headers_.HeaderHasEndStream();
777
730
  const uint32_t incoming_stream_id = incoming_headers_.GetStreamId();
778
731
  GRPC_HTTP2_CLIENT_DLOG
779
- << "Http2ClientTransport ParseAndDiscardHeaders buffer "
780
- "size: "
732
+ << "Http2ClientTransport::ParseAndDiscardHeaders buffer size: "
781
733
  << buffer.Length() << " is_initial_metadata: " << is_initial_metadata
782
734
  << " is_end_headers: " << is_end_headers
783
735
  << " incoming_stream_id: " << incoming_stream_id
@@ -790,7 +742,7 @@ Http2Status Http2ClientTransport::ParseAndDiscardHeaders(
790
742
  HeaderAssembler::ParseHeaderArgs{
791
743
  /*is_initial_metadata=*/is_initial_metadata,
792
744
  /*is_end_headers=*/is_end_headers,
793
- /*is_client=*/true,
745
+ /*is_client=*/kIsClient,
794
746
  /*max_header_list_size_soft_limit=*/
795
747
  incoming_headers_.soft_limit(),
796
748
  /*max_header_list_size_hard_limit=*/
@@ -802,35 +754,9 @@ Http2Status Http2ClientTransport::ParseAndDiscardHeaders(
802
754
 
803
755
  ///////////////////////////////////////////////////////////////////////////////
804
756
  // Read Related Promises and Promise Factories
805
- auto Http2ClientTransport::EndpointReadSlice(const size_t num_bytes) {
806
- return Map(
807
- endpoint_.ReadSlice(num_bytes),
808
- [self = RefAsSubclass<Http2ClientTransport>(),
809
- num_bytes](absl::StatusOr<Slice> status) {
810
- if (status.ok()) {
811
- self->keepalive_manager_->GotData();
812
- self->ztrace_collector_->Append(PromiseEndpointReadTrace{num_bytes});
813
- }
814
- return status;
815
- });
816
- }
817
-
818
- auto Http2ClientTransport::EndpointRead(const size_t num_bytes) {
819
- return Map(
820
- endpoint_.Read(num_bytes),
821
- [self = RefAsSubclass<Http2ClientTransport>(),
822
- num_bytes](absl::StatusOr<SliceBuffer> status) {
823
- if (status.ok()) {
824
- self->keepalive_manager_->GotData();
825
- self->ztrace_collector_->Append(PromiseEndpointReadTrace{num_bytes});
826
- }
827
- return status;
828
- });
829
- }
830
-
831
757
  auto Http2ClientTransport::ReadAndProcessOneFrame() {
832
758
  GRPC_HTTP2_CLIENT_DLOG
833
- << "Http2ClientTransport ReadAndProcessOneFrame Factory";
759
+ << "Http2ClientTransport::ReadAndProcessOneFrame Factory";
834
760
  return AssertResultType<absl::Status>(TrySeq(
835
761
  // Fetch the first kFrameHeaderSize bytes of the Frame, these contain
836
762
  // the frame header.
@@ -838,136 +764,128 @@ auto Http2ClientTransport::ReadAndProcessOneFrame() {
838
764
  // Parse the frame header.
839
765
  [](Slice header_bytes) -> Http2FrameHeader {
840
766
  GRPC_HTTP2_CLIENT_DLOG
841
- << "Http2ClientTransport ReadAndProcessOneFrame Parse "
767
+ << "Http2ClientTransport::ReadAndProcessOneFrame Parse "
842
768
  << header_bytes.as_string_view();
843
769
  return Http2FrameHeader::Parse(header_bytes.begin());
844
770
  },
845
771
  // Validate the incoming frame as per the current state of the transport
846
- [self = RefAsSubclass<Http2ClientTransport>()](Http2FrameHeader header) {
772
+ [this](Http2FrameHeader header) {
847
773
  Http2Status status = ValidateFrameHeader(
848
- /*max_frame_size_setting*/ self->settings_->acked()
849
- .max_frame_size(),
774
+ /*max_frame_size_setting*/ settings_->acked().max_frame_size(),
850
775
  /*incoming_header_in_progress*/
851
- self->incoming_headers_.IsWaitingForContinuationFrame(),
776
+ incoming_headers_.IsWaitingForContinuationFrame(),
852
777
  /*incoming_header_stream_id*/
853
- self->incoming_headers_.GetStreamId(),
778
+ incoming_headers_.GetStreamId(),
854
779
  /*current_frame_header*/ header,
855
- /*last_stream_id=*/self->GetLastStreamId(),
856
- /*is_client=*/true, /*is_first_settings_processed=*/
857
- self->settings_->IsFirstPeerSettingsApplied());
780
+ /*last_stream_id=*/GetLastStreamId(),
781
+ /*is_client=*/kIsClient, /*is_first_settings_processed=*/
782
+ settings_->IsFirstPeerSettingsApplied());
858
783
 
859
784
  if (GPR_UNLIKELY(!status.IsOk())) {
860
785
  GRPC_DCHECK(status.GetType() ==
861
786
  Http2Status::Http2ErrorType::kConnectionError);
862
- return self->HandleError(std::nullopt, std::move(status));
787
+ return HandleError(std::nullopt, std::move(status));
863
788
  }
864
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ReadAndProcessOneFrame "
865
- "Validated Frame Header:"
866
- << header.ToString();
867
- self->current_frame_header_ = header;
789
+ GRPC_HTTP2_CLIENT_DLOG
790
+ << "Http2ClientTransport::ReadAndProcessOneFrame "
791
+ "Validated Frame Header:"
792
+ << header.ToString();
793
+ current_frame_header_ = header;
868
794
  return absl::OkStatus();
869
795
  },
870
796
  // Read the payload of the frame.
871
- [self = RefAsSubclass<Http2ClientTransport>()]() {
797
+ [this]() {
872
798
  GRPC_HTTP2_CLIENT_DLOG
873
- << "Http2ClientTransport ReadAndProcessOneFrame Read Frame ";
874
- return AssertResultType<absl::StatusOr<SliceBuffer>>(
875
- self->EndpointRead(self->current_frame_header_.length));
876
- },
877
- // Parse the payload of the frame based on frame type.
878
- [self = RefAsSubclass<Http2ClientTransport>()](
879
- SliceBuffer payload) -> absl::StatusOr<Http2Frame> {
880
- GRPC_HTTP2_CLIENT_DLOG
881
- << "Http2ClientTransport ReadAndProcessOneFrame ParseFramePayload "
882
- << MaybeTruncatePayload(payload);
883
- ValueOrHttp2Status<Http2Frame> frame =
884
- ParseFramePayload(self->current_frame_header_, std::move(payload));
885
- if (!frame.IsOk()) {
886
- return self->HandleError(
887
- self->current_frame_header_.stream_id,
888
- ValueOrHttp2Status<Http2Frame>::TakeStatus(std::move(frame)));
889
- }
890
- return TakeValue(std::move(frame));
891
- },
892
- [self = RefAsSubclass<Http2ClientTransport>()](
893
- GRPC_UNUSED Http2Frame frame) {
894
- GRPC_HTTP2_CLIENT_DLOG
895
- << "Http2ClientTransport ReadAndProcessOneFrame ProcessOneFrame";
799
+ << "Http2ClientTransport::ReadAndProcessOneFrame Read Frame ";
896
800
  return AssertResultType<absl::Status>(Map(
897
- self->ProcessOneFrame(std::move(frame)),
898
- [self](Http2Status status) {
899
- if (!status.IsOk()) {
900
- return self->HandleError(self->current_frame_header_.stream_id,
901
- std::move(status));
801
+ EndpointRead(current_frame_header_.length),
802
+ [this](absl::StatusOr<SliceBuffer>&& payload) {
803
+ if (GPR_UNLIKELY(!payload.ok())) {
804
+ return payload.status();
805
+ }
806
+ GRPC_HTTP2_CLIENT_DLOG
807
+ << "Http2ClientTransport::ReadAndProcessOneFrame "
808
+ "ParseFramePayload payload length: "
809
+ << payload.value().Length();
810
+ ValueOrHttp2Status<Http2Frame> frame = ParseFramePayload(
811
+ current_frame_header_, TakeValue(std::move(payload)));
812
+ if (GPR_UNLIKELY(!frame.IsOk())) {
813
+ return HandleError(current_frame_header_.stream_id,
814
+ ValueOrHttp2Status<Http2Frame>::TakeStatus(
815
+ std::move(frame)));
816
+ }
817
+ Http2Status status =
818
+ ProcessOneIncomingFrame(TakeValue(std::move(frame)));
819
+ if (GPR_UNLIKELY(!status.IsOk())) {
820
+ return HandleError(current_frame_header_.stream_id,
821
+ std::move(status));
902
822
  }
903
823
  return absl::OkStatus();
904
824
  }));
905
825
  },
906
- [self = RefAsSubclass<Http2ClientTransport>()]() -> Poll<absl::Status> {
907
- return self->reader_state_.MaybePauseReadLoop();
826
+ [this]() -> Poll<absl::Status> {
827
+ return reader_state_.MaybePauseReadLoop();
908
828
  }));
909
829
  }
910
830
 
911
831
  auto Http2ClientTransport::ReadLoop() {
912
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport ReadLoop Factory";
913
- return AssertResultType<absl::Status>(
914
- Loop([self = RefAsSubclass<Http2ClientTransport>()]() {
915
- return TrySeq(self->ReadAndProcessOneFrame(),
916
- []() -> LoopCtl<absl::Status> {
917
- GRPC_HTTP2_CLIENT_DLOG
918
- << "Http2ClientTransport ReadLoop Continue";
919
- return Continue();
920
- });
921
- }));
832
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::ReadLoop Factory";
833
+ return AssertResultType<absl::Status>(Loop([this]() {
834
+ return TrySeq(ReadAndProcessOneFrame(), []() -> LoopCtl<absl::Status> {
835
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::ReadLoop Continue";
836
+ return Continue();
837
+ });
838
+ }));
922
839
  }
923
840
 
924
841
  ///////////////////////////////////////////////////////////////////////////////
925
842
  // Flow Control for the Transport
926
843
 
927
844
  auto Http2ClientTransport::FlowControlPeriodicUpdateLoop() {
928
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport PeriodicUpdateLoop Factory";
845
+ GRPC_HTTP2_CLIENT_DLOG
846
+ << "Http2ClientTransport::FlowControlPeriodicUpdateLoop Factory";
929
847
  return AssertResultType<absl::Status>(
930
- Loop([self = RefAsSubclass<Http2ClientTransport>()]() {
848
+ Loop([this]() {
931
849
  GRPC_HTTP2_CLIENT_DLOG
932
- << "Http2ClientTransport FlowControlPeriodicUpdateLoop Loop";
850
+ << "Http2ClientTransport::FlowControlPeriodicUpdateLoop Loop";
933
851
  return TrySeq(
934
852
  // TODO(tjagtap) [PH2][P2][BDP] Remove this static sleep when the
935
853
  // BDP code is done.
936
854
  Sleep(chttp2::kFlowControlPeriodicUpdateTimer),
937
- [self]() -> Poll<absl::Status> {
855
+ [this]() -> Poll<absl::Status> {
938
856
  GRPC_HTTP2_CLIENT_DLOG
939
- << "Http2ClientTransport FlowControl PeriodicUpdate()";
940
- chttp2::FlowControlAction action =
941
- self->flow_control_.PeriodicUpdate();
857
+ << "Http2ClientTransport::FlowControlPeriodicUpdateLoop "
858
+ "PeriodicUpdate()";
859
+ chttp2::FlowControlAction action = flow_control_.PeriodicUpdate();
942
860
  bool is_action_empty = action == chttp2::FlowControlAction();
943
861
  // This may trigger a write cycle
944
- self->ActOnFlowControlAction(action, nullptr);
862
+ ActOnFlowControlAction(action, nullptr);
945
863
  if (is_action_empty) {
946
864
  // TODO(tjagtap) [PH2][P2][BDP] Remove this when the BDP code is
947
865
  // done. We must continue to do PeriodicUpdate once BDP is in
948
866
  // place.
949
- MutexLock lock(&self->transport_mutex_);
950
- if (self->GetActiveStreamCountLocked() == 0) {
951
- self->AddPeriodicUpdatePromiseWaker();
867
+ MutexLock lock(&transport_mutex_);
868
+ if (GetActiveStreamCountLocked() == 0) {
869
+ AddPeriodicUpdatePromiseWaker();
952
870
  return Pending{};
953
871
  }
954
872
  }
955
873
  return absl::OkStatus();
956
874
  },
957
- [self]() -> LoopCtl<absl::Status> { return Continue{}; });
875
+ []() -> LoopCtl<absl::Status> { return Continue{}; });
958
876
  }));
959
877
  }
960
878
 
961
879
  // Equivalent to grpc_chttp2_act_on_flowctl_action in chttp2_transport.cc
962
880
  void Http2ClientTransport::ActOnFlowControlAction(
963
- const chttp2::FlowControlAction& action, RefCountedPtr<Stream> stream) {
881
+ const chttp2::FlowControlAction& action, Stream* stream) {
964
882
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::ActOnFlowControlAction"
965
883
  << action.DebugString();
966
884
  if (action.send_stream_update() != kNoActionNeeded) {
967
885
  if (GPR_LIKELY(stream != nullptr)) {
968
886
  GRPC_DCHECK_GT(stream->GetStreamId(), 0u);
969
887
  if (stream->CanSendWindowUpdateFrames()) {
970
- window_update_list_.insert(stream->GetStreamId());
888
+ flow_control_.AddStreamToWindowUpdateList(stream->GetStreamId());
971
889
  GRPC_HTTP2_CLIENT_DLOG
972
890
  << "Http2ClientTransport::ActOnFlowControlAction "
973
891
  "added stream "
@@ -990,7 +908,10 @@ void Http2ClientTransport::ActOnFlowControlAction(
990
908
  // updates to the peer, causing the peer to block unnecessarily while
991
909
  // waiting for flow control tokens.
992
910
  reader_state_.SetPauseReadLoop();
993
- SpawnGuardedTransportParty("SendControlFrames", TriggerWriteCycle());
911
+ if (!TriggerWriteCycleOrHandleError()) {
912
+ return;
913
+ }
914
+
994
915
  GRPC_HTTP2_CLIENT_DLOG << "Update Immediately : "
995
916
  << action.ImmediateUpdateReasons();
996
917
  }
@@ -998,18 +919,34 @@ void Http2ClientTransport::ActOnFlowControlAction(
998
919
 
999
920
  ///////////////////////////////////////////////////////////////////////////////
1000
921
  // Write Related Promises and Promise Factories
922
+ auto Http2ClientTransport::EndpointWrite(SliceBuffer&& output_buf) {
923
+ size_t output_buf_length = output_buf.Length();
924
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::EndpointWrite output_buf: "
925
+ << output_buf_length;
1001
926
 
1002
- auto Http2ClientTransport::ProcessAndWriteControlFrames() {
1003
- SliceBuffer output_buf;
1004
- if (is_first_write_) {
927
+ transport_write_context_.GetWriteCycle().BeginWrite(output_buf_length);
928
+ return Map(
929
+ endpoint_.Write(std::forward<SliceBuffer>(output_buf),
930
+ TransportWriteContext::GetWriteArgs(settings_->peer())),
931
+ [this](absl::Status status) {
932
+ GRPC_HTTP2_CLIENT_DLOG
933
+ << "Http2ClientTransport::EndpointWrite complete with status = "
934
+ << status;
935
+ transport_write_context_.GetWriteCycle().EndWrite(status.ok());
936
+ return status;
937
+ });
938
+ }
939
+
940
+ absl::Status Http2ClientTransport::PrepareControlFrames() {
941
+ FrameSender frame_sender =
942
+ transport_write_context_.GetWriteCycle().GetFrameSender();
943
+ if (transport_write_context_.IsFirstWrite()) {
1005
944
  // RFC9113: That is, the connection preface starts with the string
1006
- // "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
1007
- // This sequence MUST be followed by a SETTINGS frame, which MAY be empty.
1008
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport WriteControlFrames "
1009
- "GRPC_CHTTP2_CLIENT_CONNECT_STRING";
1010
- output_buf.Append(
1011
- Slice::FromCopiedString(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
1012
- settings_->MaybeGetSettingsAndSettingsAckFrames(flow_control_, output_buf);
945
+ // "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n". This connection preface string will
946
+ // be sent as part of the first write cycle. This sequence MUST be followed
947
+ // by a SETTINGS frame, which MAY be empty.
948
+ settings_->MaybeGetSettingsAndSettingsAckFrames(flow_control_,
949
+ frame_sender);
1013
950
  // TODO(tjagtap) [PH2][P2][Server] : This will be opposite for server. We
1014
951
  // must read before we write for the server. So the ReadLoop will be Spawned
1015
952
  // just after the constructor, and the write loop should be spawned only
@@ -1018,7 +955,6 @@ auto Http2ClientTransport::ProcessAndWriteControlFrames() {
1018
955
  // Because the client is expected to write before it reads, we spawn the
1019
956
  // ReadLoop of the client only after the first write is queued.
1020
957
  SpawnGuardedTransportParty("ReadLoop", UntilTransportClosed(ReadLoop()));
1021
- is_first_write_ = false;
1022
958
  }
1023
959
 
1024
960
  // Order of Control Frames is important.
@@ -1029,86 +965,105 @@ auto Http2ClientTransport::ProcessAndWriteControlFrames() {
1029
965
  // 4. WINDOW_UPDATE
1030
966
  // 5. Custom gRPC security frame
1031
967
 
1032
- goaway_manager_.MaybeGetSerializedGoawayFrame(output_buf);
968
+ goaway_manager_.MaybeGetSerializedGoawayFrame(frame_sender);
969
+ bool should_spawn_security_frame_loop = false;
1033
970
  http2::Http2ErrorCode apply_status =
1034
- settings_->MaybeReportAndApplyBufferedPeerSettings(event_engine_.get());
971
+ settings_->MaybeReportAndApplyBufferedPeerSettings(
972
+ event_engine_.get(), should_spawn_security_frame_loop);
973
+ if (should_spawn_security_frame_loop) {
974
+ const SecurityFrameHandler::EndpointExtensionState state =
975
+ security_frame_handler_->Initialize(event_engine_);
976
+ if (state.is_set) {
977
+ SpawnInfallibleTransportParty("SecurityFrameLoop",
978
+ UntilTransportClosed(SecurityFrameLoop()));
979
+ }
980
+ }
981
+
1035
982
  if (!goaway_manager_.IsImmediateGoAway() &&
1036
983
  apply_status == http2::Http2ErrorCode::kNoError) {
1037
984
  EnforceLatestIncomingSettings();
1038
- settings_->MaybeGetSettingsAndSettingsAckFrames(flow_control_, output_buf);
1039
- ping_manager_->MaybeGetSerializedPingFrames(output_buf,
1040
- NextAllowedPingInterval());
1041
- MaybeGetWindowUpdateFrames(output_buf);
1042
- }
1043
- const uint64_t buffer_length = output_buf.Length();
1044
- ztrace_collector_->Append(PromiseEndpointWriteTrace{buffer_length});
1045
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport WriteControlFrames Size : "
1046
- << buffer_length;
1047
- return AssertResultType<absl::Status>(
1048
- If((buffer_length > 0 && apply_status == http2::Http2ErrorCode::kNoError),
1049
- [self = RefAsSubclass<Http2ClientTransport>(),
1050
- output_buf = std::move(output_buf)]() mutable {
1051
- return self->endpoint_.Write(std::move(output_buf),
1052
- GetWriteArgs(self->settings_->peer()));
1053
- },
1054
- [self = RefAsSubclass<Http2ClientTransport>(), apply_status]() {
1055
- if (apply_status != http2::Http2ErrorCode::kNoError) {
1056
- return self->HandleError(
1057
- std::nullopt,
1058
- Http2Status::Http2ConnectionError(
1059
- apply_status, "Failed to apply incoming settings"));
1060
- }
1061
- return absl::OkStatus();
1062
- }));
1063
- }
1064
-
1065
- void Http2ClientTransport::NotifyControlFramesWriteDone() {
985
+ settings_->MaybeGetSettingsAndSettingsAckFrames(flow_control_,
986
+ frame_sender);
987
+ MaybeSpawnDelayedPing(ping_manager_->MaybeGetSerializedPingFrames(
988
+ frame_sender, NextAllowedPingInterval()));
989
+ MaybeGetWindowUpdateFrames(frame_sender);
990
+ security_frame_handler_->MaybeAppendSecurityFrame(frame_sender);
991
+ }
992
+
993
+ if (apply_status != http2::Http2ErrorCode::kNoError) {
994
+ return HandleError(std::nullopt,
995
+ Http2Status::Http2ConnectionError(
996
+ apply_status, "Failed to apply incoming settings"));
997
+ }
998
+
999
+ return absl::OkStatus();
1000
+ }
1001
+
1002
+ auto Http2ClientTransport::MaybeWriteUrgentFrames() {
1003
+ return AssertResultType<absl::Status>(If(
1004
+ transport_write_context_.GetWriteCycle().CanSerializeUrgentFrames(),
1005
+ [this]() mutable {
1006
+ WriteCycle& write_cycle = transport_write_context_.GetWriteCycle();
1007
+ const uint64_t buffer_length = write_cycle.GetUrgentFrameCount();
1008
+ ztrace_collector_->Append(PromiseEndpointWriteTrace{buffer_length});
1009
+ GRPC_HTTP2_CLIENT_DLOG
1010
+ << "Http2ClientTransport::MaybeWriteUrgentFrames frame count: "
1011
+ << buffer_length;
1012
+ return EndpointWrite(write_cycle.SerializeUrgentFrames(
1013
+ WriteCycle::SerializeStats{should_reset_ping_clock_}));
1014
+ },
1015
+ []() { return absl::OkStatus(); }));
1016
+ }
1017
+
1018
+ void Http2ClientTransport::NotifyFramesWriteDone() {
1066
1019
  // Notify Control modules that we have sent the frames.
1067
1020
  // All notifications are expected to be synchronous.
1068
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport NotifyControlFramesWriteDone";
1021
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::NotifyFramesWriteDone";
1069
1022
  reader_state_.ResumeReadLoopIfPaused();
1070
- ping_manager_->NotifyPingSent();
1023
+ MaybeSpawnPingTimeout(ping_manager_->NotifyPingSent());
1071
1024
  goaway_manager_.NotifyGoawaySent();
1072
1025
  MaybeSpawnWaitForSettingsTimeout();
1073
1026
  }
1074
1027
 
1075
- auto Http2ClientTransport::SerializeAndWrite(std::vector<Http2Frame>&& frames) {
1076
- SliceBuffer output_buf;
1077
- should_reset_ping_clock_ =
1078
- Serialize(absl::Span<Http2Frame>(frames), output_buf)
1079
- .should_reset_ping_clock;
1080
- size_t output_buf_length = output_buf.Length();
1081
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport SerializeAndWrite Write "
1082
- "output_buf.length() = "
1083
- << output_buf_length;
1028
+ void Http2ClientTransport::NotifyUrgentFramesWriteDone() {}
1029
+
1030
+ auto Http2ClientTransport::SerializeAndWrite() {
1084
1031
  return AssertResultType<absl::Status>(If(
1085
- output_buf_length > 0,
1086
- [self = RefAsSubclass<Http2ClientTransport>(),
1087
- output_buf = std::move(output_buf)]() mutable {
1088
- return self->endpoint_.Write(std::move(output_buf),
1089
- GetWriteArgs(self->settings_->peer()));
1032
+ transport_write_context_.GetWriteCycle().CanSerializeRegularFrames(),
1033
+ [this]() mutable {
1034
+ WriteCycle& write_cycle = transport_write_context_.GetWriteCycle();
1035
+ const uint64_t frame_count = write_cycle.GetRegularFrameCount();
1036
+ GRPC_HTTP2_CLIENT_DLOG
1037
+ << "Http2ClientTransport::SerializeAndWrite frame count: "
1038
+ << frame_count;
1039
+ ztrace_collector_->Append(PromiseEndpointWriteTrace{frame_count});
1040
+ return EndpointWrite(write_cycle.SerializeRegularFrames(
1041
+ WriteCycle::SerializeStats{should_reset_ping_clock_}));
1090
1042
  },
1091
1043
  []() { return absl::OkStatus(); }));
1092
1044
  }
1093
1045
 
1094
- absl::StatusOr<std::vector<Http2Frame>>
1095
- Http2ClientTransport::DequeueStreamFrames(RefCountedPtr<Stream> stream) {
1046
+ absl::Status Http2ClientTransport::DequeueStreamFrames(
1047
+ RefCountedPtr<Stream> stream, WriteCycle& write_cycle) {
1096
1048
  // write_bytes_remaining_ is passed as an upper bound on the max
1097
1049
  // number of tokens that can be dequeued to prevent dequeuing huge
1098
1050
  // data frames when write_bytes_remaining_ is very low. As the
1099
1051
  // available transport tokens can only range from 0 to 2^31 - 1,
1100
1052
  // we are clamping the write_bytes_remaining_ to that range.
1101
- const uint32_t tokens =
1102
- GetMaxPermittedDequeue(flow_control_, stream->flow_control,
1103
- write_bytes_remaining_, settings_->peer());
1104
- const uint32_t stream_flow_control_tokens = static_cast<uint32_t>(
1105
- GetStreamFlowControlTokens(stream->flow_control, settings_->peer()));
1106
- stream->flow_control.ReportIfStalled(
1107
- /*is_client=*/true, stream->GetStreamId(), settings_->peer());
1053
+ FrameSender frame_sender = write_cycle.GetFrameSender();
1054
+ const uint32_t tokens = GetMaxPermittedDequeue(
1055
+ flow_control_, stream->GetStreamFlowControl(),
1056
+ write_cycle.GetWriteBytesRemaining(), settings_->peer());
1057
+ const uint32_t stream_flow_control_tokens =
1058
+ static_cast<uint32_t>(GetStreamFlowControlTokens(
1059
+ stream->GetStreamFlowControl(), settings_->peer()));
1060
+ stream->GetStreamFlowControl().ReportIfStalled(
1061
+ /*is_client=*/kIsClient, stream->GetStreamId(), settings_->peer());
1108
1062
  StreamDataQueue<ClientMetadataHandle>::DequeueResult result =
1109
1063
  stream->DequeueFrames(tokens, stream_flow_control_tokens,
1110
- settings_->peer().max_frame_size(), encoder_);
1111
- ProcessOutgoingDataFrameFlowControl(stream->flow_control,
1064
+ settings_->peer().max_frame_size(), encoder_,
1065
+ frame_sender);
1066
+ ProcessOutgoingDataFrameFlowControl(stream->GetStreamFlowControl(),
1112
1067
  result.flow_control_tokens_consumed);
1113
1068
  if (result.is_writable) {
1114
1069
  // Stream is still writable. Enqueue it back to the writable
@@ -1118,7 +1073,7 @@ Http2ClientTransport::DequeueStreamFrames(RefCountedPtr<Stream> stream) {
1118
1073
 
1119
1074
  if (GPR_UNLIKELY(!status.ok())) {
1120
1075
  GRPC_HTTP2_CLIENT_DLOG
1121
- << "Http2ClientTransport DequeueStreamFrames Failed to "
1076
+ << "Http2ClientTransport::DequeueStreamFrames Failed to "
1122
1077
  "enqueue stream "
1123
1078
  << stream->GetStreamId() << " with status: " << status;
1124
1079
  // Close transport if we fail to enqueue stream.
@@ -1134,9 +1089,9 @@ Http2ClientTransport::DequeueStreamFrames(RefCountedPtr<Stream> stream) {
1134
1089
  // multiplexer loop as the stream will never be writable again. Additionally,
1135
1090
  // the other two stream refs, CallHandler OnDone and OutboundLoop will be
1136
1091
  // dropped by Callv3 triggering cleaning up the stream object.
1137
- if (result.InitialMetadataDequeued()) {
1092
+ if (result.IsInitialMetadataDequeued()) {
1138
1093
  GRPC_HTTP2_CLIENT_DLOG
1139
- << "Http2ClientTransport DequeueStreamFrames InitialMetadataDequeued "
1094
+ << "Http2ClientTransport::DequeueStreamFrames InitialMetadataDequeued "
1140
1095
  "stream_id = "
1141
1096
  << stream->GetStreamId();
1142
1097
  stream->SentInitialMetadata();
@@ -1144,178 +1099,170 @@ Http2ClientTransport::DequeueStreamFrames(RefCountedPtr<Stream> stream) {
1144
1099
  AddToStreamList(stream);
1145
1100
  }
1146
1101
 
1147
- if (result.HalfCloseDequeued()) {
1148
- GRPC_HTTP2_CLIENT_DLOG
1149
- << "Http2ClientTransport DequeueStreamFrames HalfCloseDequeued "
1150
- "stream_id = "
1151
- << stream->GetStreamId();
1102
+ if (result.IsHalfCloseDequeued()) {
1103
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::DequeueStreamFrames "
1104
+ "HalfCloseDequeued stream_id = "
1105
+ << stream->GetStreamId();
1152
1106
  stream->MarkHalfClosedLocal();
1153
- CloseStream(
1154
- stream,
1155
- CloseStreamArgs{/*close_reads=*/stream->did_receive_trailing_metadata,
1156
- /*close_writes=*/true});
1107
+
1108
+ if (stream->IsTrailingMetadataReceived()) {
1109
+ CloseStream(*stream, CloseStreamArgs{/*close_reads=*/true,
1110
+ /*close_writes=*/true});
1111
+ }
1157
1112
  }
1158
- if (result.ResetStreamDequeued()) {
1113
+ if (result.IsResetStreamDequeued()) {
1159
1114
  GRPC_HTTP2_CLIENT_DLOG
1160
- << "Http2ClientTransport DequeueStreamFrames ResetStreamDequeued "
1115
+ << "Http2ClientTransport::DequeueStreamFrames ResetStreamDequeued "
1161
1116
  "stream_id = "
1162
1117
  << stream->GetStreamId();
1163
1118
  stream->MarkHalfClosedLocal();
1164
- CloseStream(stream, CloseStreamArgs{/*close_reads=*/true,
1165
- /*close_writes=*/true});
1119
+ CloseStream(*stream, CloseStreamArgs{/*close_reads=*/true,
1120
+ /*close_writes=*/true});
1166
1121
  }
1167
1122
 
1168
1123
  // Update the write_bytes_remaining_ based on the bytes consumed
1169
1124
  // in the current dequeue.
1170
- write_bytes_remaining_ =
1171
- (write_bytes_remaining_ >= result.total_bytes_consumed)
1172
- ? (write_bytes_remaining_ - result.total_bytes_consumed)
1173
- : 0;
1174
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport DequeueStreamFrames "
1175
- "write_bytes_remaining_ after dequeue = "
1176
- << write_bytes_remaining_ << " total_bytes_consumed = "
1177
- << result.total_bytes_consumed
1125
+ // Note: We do tend to overestimate the bytes consumed here. This may result
1126
+ // in sending less data than target_write_size_.
1127
+
1128
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::DequeueStreamFrames "
1129
+ "After dequeue: "
1130
+ << write_cycle.DebugString()
1178
1131
  << " stream_id = " << stream->GetStreamId()
1179
1132
  << " is_writable = " << result.is_writable
1180
1133
  << " stream_priority = "
1181
- << static_cast<uint8_t>(result.priority)
1182
- << " number of frames = " << result.frames.size();
1183
- return std::move(result.frames);
1134
+ << static_cast<uint8_t>(result.priority);
1135
+ return absl::OkStatus();
1184
1136
  }
1185
1137
 
1186
1138
  // This MultiplexerLoop promise is responsible for Multiplexing multiple gRPC
1187
1139
  // Requests (HTTP2 Streams) and writing them into one common endpoint.
1188
1140
  auto Http2ClientTransport::MultiplexerLoop() {
1189
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport MultiplexerLoop Factory";
1190
- return AssertResultType<
1191
- absl::Status>(Loop([self = RefAsSubclass<Http2ClientTransport>()]() {
1192
- self->write_bytes_remaining_ = self->GetMaxWriteSize();
1193
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport MultiplexerLoop "
1194
- << " max_write_size_=" << self->GetMaxWriteSize();
1141
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::MultiplexerLoop Factory";
1142
+ return AssertResultType<absl::Status>(Loop([this]() {
1195
1143
  return TrySeq(
1196
- self->writable_stream_list_.WaitForReady(
1197
- self->AreTransportFlowControlTokensAvailable()),
1198
- [self]() {
1199
- // TODO(akshitpatel) : [PH2][P2] : Return an `important` tag from
1200
- // WriteControlFrames() to indicate if we should do a separate write
1201
- // for the queued control frames or send the queued frames with the
1202
- // data frames(if any).
1203
- return Map(
1204
- self->ProcessAndWriteControlFrames(),
1205
- [self](absl::Status status) {
1206
- if (GPR_UNLIKELY(!status.ok())) {
1207
- GRPC_HTTP2_CLIENT_DLOG
1208
- << "Http2ClientTransport MultiplexerLoop Failed to "
1209
- "write control frames with status: "
1210
- << status;
1211
- return status;
1212
- }
1213
- self->NotifyControlFramesWriteDone();
1214
- return absl::OkStatus();
1215
- });
1216
- },
1217
- [self]() -> absl::StatusOr<std::vector<Http2Frame>> {
1218
- std::vector<Http2Frame> frames;
1219
- // Drain all the writable streams till we have written
1220
- // max_write_size_ bytes of data or there is no more data to send. In
1221
- // some cases, we may write more than max_write_size_ bytes(like
1222
- // writing metadata).
1223
- while (self->write_bytes_remaining_ > 0) {
1224
- std::optional<RefCountedPtr<Stream>> optional_stream =
1225
- self->writable_stream_list_.ImmediateNext(
1226
- self->AreTransportFlowControlTokensAvailable());
1227
- if (!optional_stream.has_value()) {
1228
- GRPC_HTTP2_CLIENT_DLOG
1229
- << "Http2ClientTransport MultiplexerLoop "
1230
- "No writable streams available, write_bytes_remaining_ = "
1231
- << self->write_bytes_remaining_;
1232
- break;
1144
+ Map(writable_stream_list_.WaitForReady(
1145
+ AreTransportFlowControlTokensAvailable()),
1146
+ [this](absl::StatusOr<Empty> status) -> absl::Status {
1147
+ if (GPR_UNLIKELY(!status.ok())) {
1148
+ return status.status();
1149
+ }
1150
+ transport_write_context_.StartWriteCycle();
1151
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::MultiplexerLoop "
1152
+ "Created WriteCycle: "
1153
+ << transport_write_context_.DebugString();
1154
+ return PrepareControlFrames();
1155
+ }),
1156
+ [this] {
1157
+ return Map(MaybeWriteUrgentFrames(), [this](absl::Status status) {
1158
+ if (GPR_UNLIKELY(!status.ok())) {
1159
+ return status;
1233
1160
  }
1234
- RefCountedPtr<Stream> stream = std::move(optional_stream.value());
1161
+ NotifyUrgentFramesWriteDone();
1162
+ WriteCycle& write_cycle = transport_write_context_.GetWriteCycle();
1235
1163
  GRPC_HTTP2_CLIENT_DLOG
1236
- << "Http2ClientTransport MultiplexerLoop "
1237
- "Next writable stream id = "
1238
- << stream->GetStreamId()
1239
- << " is_closed_for_writes = " << stream->IsClosedForWrites();
1240
-
1241
- if (stream->GetStreamId() == kInvalidStreamId) {
1242
- GRPC_DCHECK(stream->IsStreamIdle());
1243
- // TODO(akshitpatel) : [PH2][P5] : We will waste a stream id in
1244
- // the rare scenario where the stream is aborted before it can be
1245
- // written to. This is a possible area to optimize in future.
1246
- absl::Status status = self->InitializeStream(stream);
1247
- if (!status.ok()) {
1164
+ << "Http2ClientTransport::MultiplexerLoop "
1165
+ << "Starting to iterate over writable stream list "
1166
+ << write_cycle.DebugString();
1167
+ // Drain all the writable streams till we have written
1168
+ // max_write_size_ bytes of data or there is no more data to send.
1169
+ // In some cases, we may write more than max_write_size_ bytes(like
1170
+ // writing metadata).
1171
+ while (write_cycle.GetWriteBytesRemaining() > 0) {
1172
+ std::optional<RefCountedPtr<Stream>> optional_stream =
1173
+ writable_stream_list_.ImmediateNext(
1174
+ AreTransportFlowControlTokensAvailable());
1175
+ if (!optional_stream.has_value()) {
1248
1176
  GRPC_HTTP2_CLIENT_DLOG
1249
- << "Http2ClientTransport MultiplexerLoop "
1250
- "Failed to assign stream id and add to stream list for "
1251
- "stream: "
1252
- << stream.get() << " closing this stream.";
1253
- self->BeginCloseStream(
1254
- stream, /*reset_stream_error_code=*/std::nullopt,
1255
- CancelledServerMetadataFromStatus(status));
1256
- continue;
1177
+ << "Http2ClientTransport::MultiplexerLoop "
1178
+ "No writable streams available ";
1179
+ break;
1257
1180
  }
1258
- }
1259
-
1260
- if (GPR_LIKELY(!stream->IsClosedForWrites())) {
1261
- absl::StatusOr<std::vector<Http2Frame>> stream_frames =
1262
- self->DequeueStreamFrames(stream);
1263
- if (GPR_UNLIKELY(!stream_frames.ok())) {
1264
- GRPC_HTTP2_CLIENT_DLOG
1265
- << "Http2ClientTransport MultiplexerLoop "
1266
- "Failed to dequeue stream frames with status: "
1267
- << stream_frames.status();
1268
- return stream_frames.status();
1181
+ RefCountedPtr<Stream> stream = std::move(optional_stream.value());
1182
+ GRPC_HTTP2_CLIENT_DLOG
1183
+ << "Http2ClientTransport::MultiplexerLoop "
1184
+ "Next writable stream id = "
1185
+ << stream->GetStreamId()
1186
+ << " is_closed_for_writes = " << stream->IsClosedForWrites();
1187
+
1188
+ if (stream->GetStreamId() == kInvalidStreamId) {
1189
+ GRPC_DCHECK(stream->IsStreamIdle());
1190
+ // TODO(akshitpatel) : [PH2][P5] : We will waste a stream id in
1191
+ // the rare scenario where the stream is aborted before it can
1192
+ // be written to. This is a possible area to optimize in future.
1193
+ absl::Status status = InitializeStream(*stream);
1194
+ if (!status.ok()) {
1195
+ GRPC_HTTP2_CLIENT_DLOG
1196
+ << "Http2ClientTransport::MultiplexerLoop "
1197
+ "Failed to assign stream id and add to stream list for"
1198
+ " stream: "
1199
+ << stream.get() << " closing this stream.";
1200
+ BeginCloseStream(std::move(stream),
1201
+ /*reset_stream_error_code=*/std::nullopt,
1202
+ CancelledServerMetadataFromStatus(status));
1203
+ continue;
1204
+ }
1269
1205
  }
1270
1206
 
1271
- frames.reserve(frames.size() + stream_frames.value().size());
1272
- frames.insert(
1273
- frames.end(),
1274
- std::make_move_iterator(stream_frames.value().begin()),
1275
- std::make_move_iterator(stream_frames.value().end()));
1207
+ if (GPR_LIKELY(!stream->IsClosedForWrites())) {
1208
+ absl::Status status = DequeueStreamFrames(
1209
+ std::move(stream),
1210
+ transport_write_context_.GetWriteCycle());
1211
+ if (GPR_UNLIKELY(!status.ok())) {
1212
+ GRPC_HTTP2_CLIENT_DLOG
1213
+ << "Http2ClientTransport::MultiplexerLoop "
1214
+ "Failed to dequeue stream frames with status: "
1215
+ << status;
1216
+ return status;
1217
+ }
1218
+ }
1276
1219
  }
1277
- }
1278
1220
 
1279
- GRPC_HTTP2_CLIENT_DLOG
1280
- << "Http2ClientTransport MultiplexerLoop "
1281
- "write_bytes_remaining_ after draining all writable streams = "
1282
- << self->write_bytes_remaining_;
1221
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::MultiplexerLoop "
1222
+ "After draining all writable streams "
1223
+ << write_cycle.DebugString();
1283
1224
 
1284
- return std::move(frames);
1225
+ return absl::OkStatus();
1226
+ });
1285
1227
  },
1286
- [self](std::vector<Http2Frame> frames) {
1287
- return self->SerializeAndWrite(std::move(frames));
1228
+ [this]() {
1229
+ return Map(SerializeAndWrite(), [this](absl::Status status) {
1230
+ if (GPR_UNLIKELY(!status.ok())) {
1231
+ return status;
1232
+ }
1233
+ NotifyFramesWriteDone();
1234
+ return absl::OkStatus();
1235
+ });
1288
1236
  },
1289
- [self]() -> LoopCtl<absl::Status> {
1290
- if (self->should_reset_ping_clock_) {
1237
+ [this]() -> LoopCtl<absl::Status> {
1238
+ if (should_reset_ping_clock_) {
1291
1239
  GRPC_HTTP2_CLIENT_DLOG
1292
- << "Http2ClientTransport MultiplexerLoop ResetPingClock";
1293
- self->ping_manager_->ResetPingClock(/*is_client=*/true);
1294
- self->should_reset_ping_clock_ = false;
1240
+ << "Http2ClientTransport::MultiplexerLoop ResetPingClock";
1241
+ ping_manager_->ResetPingClock(/*is_client=*/kIsClient);
1242
+ should_reset_ping_clock_ = false;
1295
1243
  }
1244
+ transport_write_context_.EndWriteCycle();
1296
1245
  return Continue();
1297
1246
  });
1298
1247
  }));
1299
1248
  }
1300
1249
 
1301
- absl::Status Http2ClientTransport::InitializeStream(
1302
- RefCountedPtr<Stream> stream) {
1250
+ absl::Status Http2ClientTransport::InitializeStream(Stream& stream) {
1303
1251
  absl::StatusOr<uint32_t> next_stream_id = NextStreamId();
1304
1252
  if (!next_stream_id.ok()) {
1305
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport InitializeStream "
1253
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::InitializeStream "
1306
1254
  "Failed to get next stream id for stream: "
1307
- << stream.get();
1255
+ << &stream;
1308
1256
  return std::move(next_stream_id).status();
1309
1257
  }
1310
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport InitializeStream "
1258
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::InitializeStream "
1311
1259
  "Assigned stream id: "
1312
- << next_stream_id.value()
1313
- << " to stream: " << stream.get()
1260
+ << next_stream_id.value() << " to stream: " << &stream
1314
1261
  << ", allow_true_binary_metadata:"
1315
1262
  << settings_->peer().allow_true_binary_metadata();
1316
- stream->InitializeStream(next_stream_id.value(),
1317
- settings_->peer().allow_true_binary_metadata(),
1318
- settings_->acked().allow_true_binary_metadata());
1263
+ stream.InitializeStream(next_stream_id.value(),
1264
+ settings_->peer().allow_true_binary_metadata(),
1265
+ settings_->acked().allow_true_binary_metadata());
1319
1266
  return absl::OkStatus();
1320
1267
  }
1321
1268
 
@@ -1326,9 +1273,10 @@ void Http2ClientTransport::AddToStreamList(RefCountedPtr<Stream> stream) {
1326
1273
  GRPC_DCHECK(stream != nullptr) << "stream is null";
1327
1274
  GRPC_DCHECK_GT(stream->GetStreamId(), 0u) << "stream id is invalid";
1328
1275
  GRPC_HTTP2_CLIENT_DLOG
1329
- << "Http2ClientTransport AddToStreamList for stream id: "
1276
+ << "Http2ClientTransport::AddToStreamList for stream id: "
1330
1277
  << stream->GetStreamId();
1331
- stream_list_.emplace(stream->GetStreamId(), stream);
1278
+ const uint32_t stream_id = stream->GetStreamId();
1279
+ stream_list_.emplace(stream_id, std::move(stream));
1332
1280
  // TODO(tjagtap) [PH2][P2][BDP] Remove this when the BDP code is done.
1333
1281
  if (GetActiveStreamCountLocked() == 1) {
1334
1282
  should_wake_periodic_updates = true;
@@ -1363,36 +1311,22 @@ void Http2ClientTransport::MaybeSpawnWaitForSettingsTimeout() {
1363
1311
  if (settings_->ShouldSpawnWaitForSettingsTimeout()) {
1364
1312
  GRPC_HTTP2_CLIENT_DLOG
1365
1313
  << "Http2ClientTransport::MaybeSpawnWaitForSettingsTimeout Spawning";
1366
- general_party_->Spawn("WaitForSettingsTimeout",
1367
- settings_->WaitForSettingsTimeout(),
1368
- WaitForSettingsTimeoutOnDone());
1314
+ SpawnWithOnDoneTransportParty("WaitForSettingsTimeout",
1315
+ settings_->WaitForSettingsTimeout(),
1316
+ WaitForSettingsTimeoutOnDone());
1369
1317
  }
1370
1318
  }
1371
1319
 
1372
- void Http2ClientTransport::MaybeGetWindowUpdateFrames(SliceBuffer& output_buf) {
1373
- std::vector<Http2Frame> frames;
1374
- frames.reserve(window_update_list_.size() + 1);
1375
- uint32_t window_size =
1376
- flow_control_.DesiredAnnounceSize(/*writing_anyway=*/true);
1377
- if (window_size > 0) {
1378
- GRPC_HTTP2_CLIENT_DLOG
1379
- << "Http2ClientTransport::MaybeGetWindowUpdateFrames Transport Window "
1380
- "Update : "
1381
- << window_size;
1382
- frames.emplace_back(Http2WindowUpdateFrame{/*stream_id=*/0, window_size});
1383
- flow_control_.SentUpdate(window_size);
1384
- }
1385
- for (const uint32_t stream_id : window_update_list_) {
1320
+ void Http2ClientTransport::MaybeGetWindowUpdateFrames(
1321
+ FrameSender& frame_sender) {
1322
+ frame_sender.ReserveRegularFrames(flow_control_.window_update_list_size() +
1323
+ 1);
1324
+ MaybeAddTransportWindowUpdateFrame(flow_control_, frame_sender);
1325
+ for (const uint32_t stream_id : flow_control_.DrainWindowUpdateList()) {
1386
1326
  RefCountedPtr<Stream> stream = LookupStream(stream_id);
1387
- MaybeAddStreamWindowUpdateFrame(stream, frames);
1388
- }
1389
- window_update_list_.clear();
1390
- if (!frames.empty()) {
1391
- GRPC_HTTP2_CLIENT_DLOG
1392
- << "Http2ClientTransport::MaybeGetWindowUpdateFrames Total Window "
1393
- "Update Frames : "
1394
- << frames.size();
1395
- Serialize(absl::Span<Http2Frame>(frames), output_buf);
1327
+ if (stream != nullptr) {
1328
+ MaybeAddStreamWindowUpdateFrame(*stream, frame_sender);
1329
+ }
1396
1330
  }
1397
1331
  }
1398
1332
 
@@ -1400,7 +1334,7 @@ void Http2ClientTransport::MaybeGetWindowUpdateFrames(SliceBuffer& output_buf) {
1400
1334
  // Constructor Destructor
1401
1335
 
1402
1336
  Http2ClientTransport::Http2ClientTransport(
1403
- PromiseEndpoint endpoint, GRPC_UNUSED const ChannelArgs& channel_args,
1337
+ PromiseEndpoint endpoint, const ChannelArgs& channel_args,
1404
1338
  std::shared_ptr<EventEngine> event_engine,
1405
1339
  absl::AnyInvocable<void(absl::StatusOr<uint32_t>)> on_receive_settings)
1406
1340
  : channelz::DataSource(http2::CreateChannelzSocketNode(
@@ -1411,11 +1345,12 @@ Http2ClientTransport::Http2ClientTransport(
1411
1345
  std::move(on_receive_settings))),
1412
1346
  next_stream_id_(/*Initial Stream ID*/ 1),
1413
1347
  should_reset_ping_clock_(false),
1414
- is_first_write_(true),
1415
- max_write_size_(kMaxWriteSize),
1348
+ incoming_headers_(IncomingMetadataTracker::GetPeerString(endpoint_)),
1349
+ transport_write_context_(kIsClient),
1416
1350
  ping_manager_(std::nullopt),
1417
1351
  keepalive_manager_(std::nullopt),
1418
1352
  goaway_manager_(GoawayInterfaceImpl::Make(this)),
1353
+ security_frame_handler_(MakeRefCounted<SecurityFrameHandler>()),
1419
1354
  memory_owner_(channel_args.GetObject<ResourceQuota>()
1420
1355
  ->memory_quota()
1421
1356
  ->CreateMemoryOwner()),
@@ -1424,13 +1359,13 @@ Http2ClientTransport::Http2ClientTransport(
1424
1359
  channel_args.GetBool(GRPC_ARG_HTTP2_BDP_PROBE).value_or(true),
1425
1360
  &memory_owner_),
1426
1361
  ztrace_collector_(std::make_shared<PromiseHttp2ZTraceCollector>()) {
1427
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Constructor Begin";
1362
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::Http2ClientTransport Begin";
1428
1363
  // Initialize the general party and write party.
1429
1364
  RefCountedPtr<Arena> party_arena = SimpleArenaAllocator(0)->MakeArena();
1430
1365
  party_arena->SetContext<EventEngine>(event_engine_.get());
1431
1366
  general_party_ = Party::Make(std::move(party_arena));
1432
1367
 
1433
- InitLocalSettings(settings_->mutable_local(), /*is_client=*/true);
1368
+ InitLocalSettings(settings_->mutable_local(), /*is_client=*/kIsClient);
1434
1369
  TransportChannelArgs args;
1435
1370
  ReadChannelArgs(channel_args, args);
1436
1371
 
@@ -1442,28 +1377,28 @@ Http2ClientTransport::Http2ClientTransport(
1442
1377
  KeepAliveInterfaceImpl::Make(this),
1443
1378
  ((args.keepalive_timeout < args.ping_timeout) ? args.keepalive_timeout
1444
1379
  : Duration::Infinity()),
1445
- args.keepalive_time, general_party_.get());
1446
-
1447
- if (settings_->local().allow_security_frame()) {
1448
- // TODO(tjagtap) : [PH2][P3] : Setup the plumbing to pass the security frame
1449
- // to the endpoing via TransportFramingEndpointExtension.
1450
- // Also decide if this plumbing is done here, or when the peer sends
1451
- // allow_security_frame too.
1452
- }
1380
+ args.keepalive_time);
1453
1381
 
1454
1382
  GRPC_DCHECK(ping_manager_.has_value());
1455
1383
  GRPC_DCHECK(keepalive_manager_.has_value());
1456
1384
  SourceConstructed();
1457
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Constructor End";
1385
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::Http2ClientTransport End";
1458
1386
  }
1459
1387
 
1460
1388
  void Http2ClientTransport::SpawnTransportLoops() {
1461
1389
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::SpawnTransportLoops Begin";
1390
+ MaybeSpawnKeepaliveLoop();
1462
1391
  SpawnGuardedTransportParty(
1463
1392
  "FlowControlPeriodicUpdateLoop",
1464
1393
  UntilTransportClosed(FlowControlPeriodicUpdateLoop()));
1465
1394
 
1466
- SpawnGuardedTransportParty("FlushInitialFrames", TriggerWriteCycle());
1395
+ if (!TriggerWriteCycleOrHandleError()) {
1396
+ return;
1397
+ }
1398
+ // For Client, write happens before read. So MultiplexerLoop is spawned first.
1399
+ // ReadLoop is spawned after the first write.
1400
+ // For Server, read happens before write. So ReadLoop is spawned first.
1401
+ // MultiplexerLoop is spawned after the first read.
1467
1402
  SpawnGuardedTransportParty("MultiplexerLoop",
1468
1403
  UntilTransportClosed(MultiplexerLoop()));
1469
1404
  GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::SpawnTransportLoops End";
@@ -1473,7 +1408,7 @@ void Http2ClientTransport::ReadChannelArgs(const ChannelArgs& channel_args,
1473
1408
  TransportChannelArgs& args) {
1474
1409
  http2::ReadChannelArgs(channel_args, args, settings_->mutable_local(),
1475
1410
  flow_control_,
1476
- /*is_client=*/true);
1411
+ /*is_client=*/kIsClient);
1477
1412
 
1478
1413
  // Assign the channel args to the member variables.
1479
1414
  keepalive_time_ = args.keepalive_time;
@@ -1493,10 +1428,38 @@ void Http2ClientTransport::ReadChannelArgs(const ChannelArgs& channel_args,
1493
1428
  }
1494
1429
  }
1495
1430
 
1431
+ absl::Status Http2ClientTransport::HandleError(
1432
+ const std::optional<uint32_t> stream_id, Http2Status status,
1433
+ DebugLocation whence) {
1434
+ Http2Status::Http2ErrorType error_type = status.GetType();
1435
+ GRPC_DCHECK(error_type != Http2Status::Http2ErrorType::kOk);
1436
+
1437
+ if (error_type == Http2Status::Http2ErrorType::kStreamError) {
1438
+ GRPC_HTTP2_CLIENT_ERROR_DLOG
1439
+ << "Http2ClientTransport::HandleError Stream Error:"
1440
+ << status.DebugString();
1441
+ GRPC_DCHECK(stream_id.has_value());
1442
+ // Passing a cancelled server metadata handle to propagate the error
1443
+ // to the upper layers.
1444
+ BeginCloseStream(
1445
+ LookupStream(stream_id.value()),
1446
+ Http2ErrorCodeToFrameErrorCode(status.GetStreamErrorCode()),
1447
+ CancelledServerMetadataFromStatus(status.GetAbslStreamError()), whence);
1448
+ return absl::OkStatus();
1449
+ } else if (error_type == Http2Status::Http2ErrorType::kConnectionError) {
1450
+ GRPC_HTTP2_CLIENT_ERROR_DLOG
1451
+ << "Http2ClientTransport::HandleError Connection Error:"
1452
+ << status.DebugString();
1453
+ absl::Status absl_status = status.GetAbslConnectionError();
1454
+ MaybeSpawnCloseTransport(std::move(status), whence);
1455
+ return absl_status;
1456
+ }
1457
+ GPR_UNREACHABLE_CODE(return absl::InternalError("Invalid error type"));
1458
+ }
1459
+
1496
1460
  // This function MUST be idempotent. This function MUST be called from the
1497
1461
  // transport party.
1498
- void Http2ClientTransport::CloseStream(RefCountedPtr<Stream> stream,
1499
- CloseStreamArgs args,
1462
+ void Http2ClientTransport::CloseStream(Stream& stream, CloseStreamArgs args,
1500
1463
  DebugLocation whence) {
1501
1464
  std::optional<Http2Status> close_transport_error;
1502
1465
 
@@ -1504,22 +1467,21 @@ void Http2ClientTransport::CloseStream(RefCountedPtr<Stream> stream,
1504
1467
  // TODO(akshitpatel) : [PH2][P3] : Measure the impact of holding mutex
1505
1468
  // throughout this function.
1506
1469
  MutexLock lock(&transport_mutex_);
1507
- GRPC_DCHECK(stream != nullptr) << "stream is null";
1508
1470
  GRPC_HTTP2_CLIENT_DLOG
1509
1471
  << "Http2ClientTransport::CloseStream for stream id: "
1510
- << stream->GetStreamId() << " close_reads=" << args.close_reads
1472
+ << stream.GetStreamId() << " close_reads=" << args.close_reads
1511
1473
  << " close_writes=" << args.close_writes
1512
1474
  << " incoming_headers_=" << incoming_headers_.DebugString()
1513
1475
  << " location=" << whence.file() << ":" << whence.line();
1514
1476
 
1515
1477
  if (args.close_writes) {
1516
- stream->SetWriteClosed();
1478
+ stream.SetWriteClosed();
1517
1479
  }
1518
1480
 
1519
1481
  if (args.close_reads) {
1520
1482
  GRPC_HTTP2_CLIENT_DLOG
1521
1483
  << "Http2ClientTransport::CloseStream for stream id: "
1522
- << stream->GetStreamId() << " closing stream for reads.";
1484
+ << stream.GetStreamId() << " closing stream for reads.";
1523
1485
  // If the stream is closed while reading HEADER/CONTINUATION frames, we
1524
1486
  // should still parse the enqueued buffer to maintain HPACK state between
1525
1487
  // peers.
@@ -1529,25 +1491,24 @@ void Http2ClientTransport::CloseStream(RefCountedPtr<Stream> stream,
1529
1491
  HeaderAssembler::ParseHeaderArgs{
1530
1492
  /*is_initial_metadata=*/!incoming_headers_.HeaderHasEndStream(),
1531
1493
  /*is_end_headers=*/false,
1532
- /*is_client=*/true,
1494
+ /*is_client=*/kIsClient,
1533
1495
  /*max_header_list_size_soft_limit=*/
1534
1496
  incoming_headers_.soft_limit(),
1535
1497
  /*max_header_list_size_hard_limit=*/
1536
1498
  settings_->acked().max_header_list_size(),
1537
1499
  /*stream_id=*/incoming_headers_.GetStreamId(),
1538
1500
  },
1539
- stream, /*original_status=*/Http2Status::Ok());
1501
+ &stream, /*original_status=*/Http2Status::Ok());
1540
1502
  if (result.GetType() == Http2Status::Http2ErrorType::kConnectionError) {
1541
1503
  GRPC_HTTP2_CLIENT_DLOG
1542
1504
  << "Http2ClientTransport::CloseStream for stream id: "
1543
- << stream->GetStreamId()
1544
- << " failed to partially process header: "
1505
+ << stream.GetStreamId() << " failed to partially process header: "
1545
1506
  << result.DebugString();
1546
1507
  close_transport_error.emplace(std::move(result));
1547
1508
  }
1548
1509
  }
1549
1510
 
1550
- stream_list_.erase(stream->GetStreamId());
1511
+ stream_list_.erase(stream.GetStreamId());
1551
1512
  if (!close_transport_error.has_value() && CanCloseTransportLocked()) {
1552
1513
  // TODO(akshitpatel) : [PH2][P3] : Is kInternalError the right error
1553
1514
  // code to use here? IMO it should be kNoError.
@@ -1653,7 +1614,9 @@ void Http2ClientTransport::BeginCloseStream(
1653
1614
  } else {
1654
1615
  // Callers taking this path:
1655
1616
  // 1. Reading Trailing Metadata (MAY send half close from OnDone).
1656
- if (stream->IsClosedForWrites()) {
1617
+ // If a half close frame has already been sent, we should close the stream
1618
+ // for reads and writes.
1619
+ if (stream->IsHalfClosedLocal() || stream->IsStreamClosed()) {
1657
1620
  close_reads = true;
1658
1621
  close_writes = true;
1659
1622
  GRPC_HTTP2_CLIENT_DLOG
@@ -1664,7 +1627,7 @@ void Http2ClientTransport::BeginCloseStream(
1664
1627
  }
1665
1628
 
1666
1629
  if (close_reads || close_writes) {
1667
- CloseStream(stream, CloseStreamArgs{close_reads, close_writes}, whence);
1630
+ CloseStream(*stream, CloseStreamArgs{close_reads, close_writes}, whence);
1668
1631
  }
1669
1632
 
1670
1633
  // If the call was cancelled, the stream MUST be closed for reads.
@@ -1691,7 +1654,6 @@ void Http2ClientTransport::CloseTransport() {
1691
1654
  transport_closed_latch_.Set();
1692
1655
  settings_->HandleTransportShutdown(event_engine_.get());
1693
1656
 
1694
- MutexLock lock(&transport_mutex_);
1695
1657
  // This is the only place where the general_party_ is reset.
1696
1658
  general_party_.reset();
1697
1659
  }
@@ -1727,16 +1689,18 @@ void Http2ClientTransport::MaybeSpawnCloseTransport(Http2Status http2_status,
1727
1689
  "CloseTransport", [self = RefAsSubclass<Http2ClientTransport>(),
1728
1690
  stream_list = std::move(stream_list),
1729
1691
  http2_status = std::move(http2_status)]() mutable {
1692
+ self->security_frame_handler_->OnTransportClosed();
1730
1693
  GRPC_HTTP2_CLIENT_DLOG
1731
- << "Http2ClientTransport::CloseTransport Cleaning up call stacks";
1694
+ << "Http2ClientTransport::MaybeSpawnCloseTransport "
1695
+ "Cleaning up call stacks";
1732
1696
  // Clean up the call stacks for all active streams.
1733
1697
  for (const auto& pair : stream_list) {
1734
1698
  // There is no merit in transitioning the stream to
1735
1699
  // closed state here as the subsequent lookups would
1736
1700
  // fail. Also, as this is running on the transport
1737
1701
  // party, there would not be concurrent access to the stream.
1738
- auto& stream = pair.second;
1739
- self->BeginCloseStream(stream,
1702
+ RefCountedPtr<Stream> stream = pair.second;
1703
+ self->BeginCloseStream(std::move(stream),
1740
1704
  Http2ErrorCodeToFrameErrorCode(
1741
1705
  http2_status.GetConnectionErrorCode()),
1742
1706
  CancelledServerMetadataFromStatus(
@@ -1784,11 +1748,11 @@ bool Http2ClientTransport::CanCloseTransportLocked() const {
1784
1748
  }
1785
1749
 
1786
1750
  Http2ClientTransport::~Http2ClientTransport() {
1787
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Destructor Begin";
1751
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::~Http2ClientTransport Begin";
1788
1752
  GRPC_DCHECK(stream_list_.empty());
1789
1753
  GRPC_DCHECK(general_party_ == nullptr);
1790
1754
  memory_owner_.Reset();
1791
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport Destructor End";
1755
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::~Http2ClientTransport End";
1792
1756
  }
1793
1757
 
1794
1758
  void Http2ClientTransport::SpawnAddChannelzData(RefCountedPtr<Party> party,
@@ -1797,7 +1761,7 @@ void Http2ClientTransport::SpawnAddChannelzData(RefCountedPtr<Party> party,
1797
1761
  std::move(party), "AddData",
1798
1762
  [self = RefAsSubclass<Http2ClientTransport>(),
1799
1763
  sink = std::move(sink)]() mutable {
1800
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::AddData Promise";
1764
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::SpawnAddChannelzData";
1801
1765
  sink.AddData(
1802
1766
  "Http2ClientTransport",
1803
1767
  channelz::PropertyList()
@@ -1809,7 +1773,8 @@ void Http2ClientTransport::SpawnAddChannelzData(RefCountedPtr<Party> party,
1809
1773
  self->flow_control_.stats().ChannelzProperties()));
1810
1774
  self->general_party_->ExportToChannelz("Http2ClientTransport Party",
1811
1775
  sink);
1812
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::AddData End";
1776
+ GRPC_HTTP2_CLIENT_DLOG
1777
+ << "Http2ClientTransport::SpawnAddChannelzData End";
1813
1778
  return Empty{};
1814
1779
  });
1815
1780
  }
@@ -1819,48 +1784,103 @@ void Http2ClientTransport::AddData(channelz::DataSink sink) {
1819
1784
 
1820
1785
  event_engine_->Run([self = RefAsSubclass<Http2ClientTransport>(),
1821
1786
  sink = std::move(sink)]() mutable {
1822
- bool is_party_null = false;
1787
+ RefCountedPtr<Party> party = nullptr;
1823
1788
  {
1824
- // Apart from CloseTransport, this is the only place where a lock is taken
1825
- // to access general_party_. All other access to general_party_ happens
1826
- // on the general party itself and hence do not race with CloseTransport.
1827
- // TODO(akshitpatel) : [PH2][P4] : Check if a new mutex is needed to
1828
- // protect general_party_. Curently transport_mutex_ can is used in
1829
- // these places:
1830
- // 1. In promises running on the transport party
1831
- // 2. In AddData promise
1832
- // 3. In Orphan function.
1833
- // 4. Stream creation (this will be removed soon).
1834
- // Given that #1 is already serialized (guaranteed by party), #2 is on
1835
- // demand and #3 happens once for the lifetime of the transport while
1836
- // closing the transport, the contention should be minimal.
1837
1789
  MutexLock lock(&self->transport_mutex_);
1838
- // TODO(akshitpatel) : [PH2][P2] : There is still a potential for a race
1839
- // here where the general_party_ is reset between the lock being
1840
- // released and the spawn. We cannot just do a spawn inside the mutex as
1841
- // that may result in deadlock.
1842
- // Potential fix to hold a ref to the party inside the mutex and do a
1843
- // spawn outside the mutex. The only side effect is that this introduces
1844
- // an additional ref to the party other the transport's copy.
1845
- if (GPR_UNLIKELY(self->general_party_ == nullptr)) {
1846
- is_party_null = true;
1790
+ if (GPR_LIKELY(!self->is_transport_closed_)) {
1791
+ GRPC_DCHECK(self->general_party_ != nullptr);
1792
+ party = self->general_party_;
1793
+ } else {
1847
1794
  GRPC_HTTP2_CLIENT_DLOG
1848
- << "Http2ClientTransport::AddData general_party_ is "
1849
- "null. Transport is closed.";
1795
+ << "Http2ClientTransport::AddData Transport is closed.";
1850
1796
  }
1851
1797
  }
1852
1798
 
1853
1799
  ExecCtx exec_ctx;
1854
- if (!is_party_null) {
1855
- self->SpawnAddChannelzData(self->general_party_, std::move(sink));
1800
+ if (party != nullptr) {
1801
+ self->SpawnAddChannelzData(std::move(party), std::move(sink));
1856
1802
  }
1857
1803
  self.reset(); // Cleanup with exec_ctx in scope
1858
1804
  });
1859
1805
  }
1860
1806
 
1807
+ RefCountedPtr<channelz::SocketNode> Http2ClientTransport::GetSocketNode()
1808
+ const {
1809
+ const channelz::BaseNode* node = channelz::DataSource::channelz_node();
1810
+ if (node == nullptr) {
1811
+ return nullptr;
1812
+ }
1813
+ return const_cast<channelz::BaseNode*>(node)
1814
+ ->RefAsSubclass<channelz::SocketNode>();
1815
+ }
1816
+
1861
1817
  ///////////////////////////////////////////////////////////////////////////////
1862
1818
  // Stream Related Operations
1863
1819
 
1820
+ absl::StatusOr<uint32_t> Http2ClientTransport::NextStreamId() {
1821
+ if (next_stream_id_ > GetMaxAllowedStreamId()) {
1822
+ // TODO(tjagtap) : [PH2][P3] : Handle case if transport runs out of stream
1823
+ // ids
1824
+ // RFC9113 : Stream identifiers cannot be reused. Long-lived connections
1825
+ // can result in an endpoint exhausting the available range of stream
1826
+ // identifiers. A client that is unable to establish a new stream
1827
+ // identifier can establish a new connection for new streams. A server
1828
+ // that is unable to establish a new stream identifier can send a GOAWAY
1829
+ // frame so that the client is forced to open a new connection for new
1830
+ // streams.
1831
+ return absl::ResourceExhaustedError("No more stream ids available");
1832
+ }
1833
+ // TODO(akshitpatel) : [PH2][P3] : There is a channel arg to delay
1834
+ // starting new streams instead of failing them. This needs to be
1835
+ // implemented.
1836
+ {
1837
+ // TODO(tjagtap) : [PH2][P1] : For a server we will have to do
1838
+ // this for incoming streams only. If a server receives more
1839
+ // streams from a client than is allowed by the clients settings,
1840
+ // whether or not we should fail is debatable.
1841
+ MutexLock lock(&transport_mutex_);
1842
+ if (GetActiveStreamCountLocked() >=
1843
+ settings_->peer().max_concurrent_streams()) {
1844
+ return absl::ResourceExhaustedError("Reached max concurrent streams");
1845
+ }
1846
+ }
1847
+
1848
+ // RFC9113 : Streams initiated by a client MUST use odd-numbered stream
1849
+ // identifiers.
1850
+ uint32_t new_stream_id = std::exchange(next_stream_id_, next_stream_id_ + 2);
1851
+ if (GPR_UNLIKELY(next_stream_id_ > GetMaxAllowedStreamId())) {
1852
+ ReportDisconnection(
1853
+ absl::ResourceExhaustedError("Transport Stream IDs exhausted"),
1854
+ {}, // TODO(tjagtap) : [PH2][P2] : Report better disconnect info.
1855
+ "no_more_stream_ids");
1856
+ }
1857
+ return new_stream_id;
1858
+ }
1859
+
1860
+ absl::Status Http2ClientTransport::MaybeAddStreamToWritableStreamList(
1861
+ RefCountedPtr<Stream> stream,
1862
+ const StreamDataQueue<ClientMetadataHandle>::StreamWritabilityUpdate
1863
+ result) {
1864
+ if (result.became_writable) {
1865
+ GRPC_HTTP2_CLIENT_DLOG
1866
+ << "Http2ClientTransport::MaybeAddStreamToWritableStreamList Stream "
1867
+ "id: "
1868
+ << stream->GetStreamId() << " became writable";
1869
+ // TODO(akshitpatel) [Perf]: Might be worth exploring if this funciton
1870
+ // should take a raw stream ptr and take a ref here.
1871
+ absl::Status status =
1872
+ writable_stream_list_.Enqueue(std::move(stream), result.priority);
1873
+ if (!status.ok()) {
1874
+ return HandleError(
1875
+ std::nullopt,
1876
+ Http2Status::Http2ConnectionError(
1877
+ Http2ErrorCode::kRefusedStream,
1878
+ "Failed to enqueue stream to writable stream list"));
1879
+ }
1880
+ }
1881
+ return absl::OkStatus();
1882
+ }
1883
+
1864
1884
  RefCountedPtr<Stream> Http2ClientTransport::LookupStream(uint32_t stream_id) {
1865
1885
  MutexLock lock(&transport_mutex_);
1866
1886
  auto it = stream_list_.find(stream_id);
@@ -1875,64 +1895,69 @@ RefCountedPtr<Stream> Http2ClientTransport::LookupStream(uint32_t stream_id) {
1875
1895
 
1876
1896
  bool Http2ClientTransport::SetOnDone(CallHandler call_handler,
1877
1897
  RefCountedPtr<Stream> stream) {
1878
- return call_handler.OnDone(
1879
- [self = RefAsSubclass<Http2ClientTransport>(), stream,
1880
- stream_id = stream->GetStreamId()](bool cancelled) {
1881
- GRPC_HTTP2_CLIENT_DLOG << "PH2: Client call " << self.get()
1882
- << " id=" << stream_id
1883
- << " done: cancelled=" << cancelled;
1884
- absl::StatusOr<StreamWritabilityUpdate> enqueue_result;
1885
- GRPC_HTTP2_CLIENT_DLOG
1886
- << "PH2: Client call " << self.get() << " id=" << stream_id
1887
- << " done: stream=" << stream.get() << " cancelled=" << cancelled;
1888
- if (cancelled) {
1889
- // In most of the cases, EnqueueResetStream would be a no-op as
1890
- // BeginCloseStream would have already enqueued the reset stream.
1891
- // Currently only Aborts from application will actually enqueue
1892
- // the reset stream here.
1893
- enqueue_result = stream->EnqueueResetStream(
1894
- static_cast<uint32_t>(Http2ErrorCode::kCancel));
1895
- GRPC_HTTP2_CLIENT_DLOG
1896
- << "Enqueued ResetStream with error code="
1897
- << static_cast<uint32_t>(Http2ErrorCode::kCancel)
1898
- << " status=" << enqueue_result.status();
1899
- } else {
1900
- enqueue_result = stream->EnqueueHalfClosed();
1901
- GRPC_HTTP2_CLIENT_DLOG << "Enqueued HalfClosed with result="
1902
- << enqueue_result.status();
1903
- }
1898
+ return call_handler.OnDone([self = RefAsSubclass<Http2ClientTransport>(),
1899
+ stream =
1900
+ std::move(stream)](bool cancelled) mutable {
1901
+ GRPC_HTTP2_CLIENT_DLOG << "PH2: Client call " << self.get()
1902
+ << " id=" << stream->GetStreamId()
1903
+ << " done: cancelled=" << cancelled;
1904
+ absl::StatusOr<StreamWritabilityUpdate> enqueue_result;
1905
+ GRPC_HTTP2_CLIENT_DLOG << "PH2: Client call " << self.get()
1906
+ << " id=" << stream->GetStreamId()
1907
+ << " done: stream=" << stream.get()
1908
+ << " cancelled=" << cancelled;
1909
+
1910
+ // If the stream is already closed for writes, then we don't need to
1911
+ // enqueue the reset stream or the half closed frame.
1912
+ if (stream->IsClosedForWrites()) {
1913
+ GRPC_HTTP2_CLIENT_DLOG << "PH2: Client call " << self.get()
1914
+ << " id=" << stream->GetStreamId()
1915
+ << " done: stream already closed for writes";
1916
+ return;
1917
+ }
1904
1918
 
1905
- if (enqueue_result.ok()) {
1906
- GRPC_HTTP2_CLIENT_DLOG
1907
- << "Http2ClientTransport::SetOnDone "
1908
- "MaybeAddStreamToWritableStreamList for stream= "
1909
- << stream->GetStreamId() << " enqueue_result={became_writable="
1910
- << enqueue_result.value().became_writable << ", priority="
1911
- << static_cast<uint8_t>(enqueue_result.value().priority) << "}";
1912
- GRPC_UNUSED absl::Status status =
1913
- self->MaybeAddStreamToWritableStreamList(stream,
1914
- enqueue_result.value());
1915
- }
1916
- });
1919
+ if (cancelled) {
1920
+ // In most of the cases, EnqueueResetStream would be a no-op as
1921
+ // BeginCloseStream would have already enqueued the reset stream.
1922
+ // Currently only Aborts from application will actually enqueue
1923
+ // the reset stream here.
1924
+ enqueue_result = stream->EnqueueResetStream(
1925
+ static_cast<uint32_t>(Http2ErrorCode::kCancel));
1926
+ GRPC_HTTP2_CLIENT_DLOG << "Enqueued ResetStream with error code="
1927
+ << static_cast<uint32_t>(Http2ErrorCode::kCancel)
1928
+ << " status=" << enqueue_result.status();
1929
+ } else {
1930
+ enqueue_result = stream->EnqueueHalfClosed();
1931
+ GRPC_HTTP2_CLIENT_DLOG << "Enqueued HalfClosed with result="
1932
+ << enqueue_result.status();
1933
+ }
1934
+
1935
+ if (GPR_LIKELY(enqueue_result.ok())) {
1936
+ GRPC_HTTP2_CLIENT_DLOG
1937
+ << "Http2ClientTransport::SetOnDone "
1938
+ "MaybeAddStreamToWritableStreamList for stream= "
1939
+ << stream->GetStreamId() << " enqueue_result={became_writable="
1940
+ << enqueue_result.value().became_writable << ", priority="
1941
+ << static_cast<uint8_t>(enqueue_result.value().priority) << "}";
1942
+ GRPC_UNUSED absl::Status status =
1943
+ self->MaybeAddStreamToWritableStreamList(std::move(stream),
1944
+ enqueue_result.value());
1945
+ }
1946
+ });
1917
1947
  }
1918
1948
 
1919
1949
  std::optional<RefCountedPtr<Stream>> Http2ClientTransport::MakeStream(
1920
1950
  CallHandler call_handler) {
1921
1951
  // https://datatracker.ietf.org/doc/html/rfc9113#name-stream-identifiers
1922
1952
  RefCountedPtr<Stream> stream;
1923
- {
1924
- // TODO(akshitpatel) : [PH2][P3] : Remove this mutex once settings is in
1925
- // place.
1926
- MutexLock lock(&transport_mutex_);
1927
- stream = MakeRefCounted<Stream>(call_handler, flow_control_);
1928
- }
1929
- const bool on_done_added = SetOnDone(call_handler, stream);
1953
+ stream = MakeRefCounted<Stream>(call_handler, flow_control_);
1954
+ const bool on_done_added = SetOnDone(std::move(call_handler), stream);
1930
1955
  if (!on_done_added) return std::nullopt;
1931
- return stream;
1956
+ return std::move(stream);
1932
1957
  }
1933
1958
 
1934
1959
  uint32_t Http2ClientTransport::GetMaxAllowedStreamId() const {
1935
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport GetMaxAllowedStreamId "
1960
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::GetMaxAllowedStreamId "
1936
1961
  << max_allowed_stream_id_;
1937
1962
  return max_allowed_stream_id_;
1938
1963
  }
@@ -1940,7 +1965,7 @@ uint32_t Http2ClientTransport::GetMaxAllowedStreamId() const {
1940
1965
  void Http2ClientTransport::SetMaxAllowedStreamId(
1941
1966
  const uint32_t max_allowed_stream_id) {
1942
1967
  const uint32_t old_max_allowed_stream_id = GetMaxAllowedStreamId();
1943
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport SetMaxAllowedStreamId "
1968
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::SetMaxAllowedStreamId "
1944
1969
  << " max_allowed_stream_id: " << max_allowed_stream_id
1945
1970
  << " old_allowed_max_stream_id: "
1946
1971
  << old_max_allowed_stream_id;
@@ -1962,115 +1987,241 @@ void Http2ClientTransport::SetMaxAllowedStreamId(
1962
1987
  }
1963
1988
 
1964
1989
  ///////////////////////////////////////////////////////////////////////////////
1965
- // Call Spine related operations
1990
+ // Http2ClientTransport - Call Spine related operations
1966
1991
 
1967
- auto Http2ClientTransport::CallOutboundLoop(CallHandler call_handler,
1968
- RefCountedPtr<Stream> stream,
1969
- ClientMetadataHandle metadata) {
1970
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport CallOutboundLoop";
1992
+ auto Http2ClientTransport::CallOutboundLoop(RefCountedPtr<Stream> stream) {
1993
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::CallOutboundLoop";
1971
1994
  GRPC_DCHECK(stream != nullptr);
1972
1995
 
1973
- auto send_message = [self = RefAsSubclass<Http2ClientTransport>(),
1974
- stream](MessageHandle&& message) mutable {
1975
- return TrySeq(stream->EnqueueMessage(std::move(message)),
1976
- [self, stream](const StreamWritabilityUpdate result) mutable {
1977
- GRPC_HTTP2_CLIENT_DLOG
1978
- << "Http2ClientTransport CallOutboundLoop "
1979
- "Enqueued Message";
1980
- return self->MaybeAddStreamToWritableStreamList(
1981
- std::move(stream), result);
1982
- });
1983
- };
1984
-
1985
- auto send_initial_metadata = [self = RefAsSubclass<Http2ClientTransport>(),
1986
- stream,
1987
- metadata = std::move(metadata)]() mutable {
1996
+ auto send_message = [this, stream](MessageHandle&& message) mutable {
1988
1997
  return TrySeq(
1989
- [stream, metadata = std::move(metadata)]() mutable {
1990
- return stream->EnqueueInitialMetadata(std::move(metadata));
1991
- },
1992
- [self, stream](const StreamWritabilityUpdate result) mutable {
1993
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport CallOutboundLoop "
1994
- "Enqueued Initial Metadata";
1995
- return self->MaybeAddStreamToWritableStreamList(std::move(stream),
1996
- result);
1998
+ stream->EnqueueMessage(std::move(message)),
1999
+ [this, stream](const StreamWritabilityUpdate result) mutable {
2000
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::CallOutboundLoop "
2001
+ "Enqueued Message";
2002
+ return MaybeAddStreamToWritableStreamList(std::move(stream), result);
1997
2003
  });
1998
2004
  };
1999
2005
 
2000
- auto send_half_closed = [self = RefAsSubclass<Http2ClientTransport>(),
2001
- stream]() mutable {
2002
- return TrySeq([stream]() { return stream->EnqueueHalfClosed(); },
2003
- [self, stream](const StreamWritabilityUpdate result) mutable {
2004
- GRPC_HTTP2_CLIENT_DLOG
2005
- << "Http2ClientTransport CallOutboundLoop "
2006
- "Enqueued Half Closed";
2007
- return self->MaybeAddStreamToWritableStreamList(
2008
- std::move(stream), result);
2009
- });
2006
+ auto send_initial_metadata =
2007
+ [this, stream](ClientMetadataHandle&& metadata) mutable {
2008
+ absl::StatusOr<StreamWritabilityUpdate> enqueue_result =
2009
+ stream->EnqueueInitialMetadata(
2010
+ std::forward<ClientMetadataHandle>(metadata));
2011
+ if (GPR_UNLIKELY(!enqueue_result.ok())) {
2012
+ return enqueue_result.status();
2013
+ }
2014
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport CallOutboundLoop "
2015
+ "Enqueued Initial Metadata";
2016
+ return MaybeAddStreamToWritableStreamList(std::move(stream),
2017
+ enqueue_result.value());
2018
+ };
2019
+
2020
+ auto send_half_closed = [this, stream]() mutable {
2021
+ absl::StatusOr<StreamWritabilityUpdate> enqueue_result =
2022
+ stream->EnqueueHalfClosed();
2023
+ if (GPR_UNLIKELY(!enqueue_result.ok())) {
2024
+ return enqueue_result.status();
2025
+ }
2026
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport CallOutboundLoop "
2027
+ "Enqueued Half Closed";
2028
+ return MaybeAddStreamToWritableStreamList(std::move(stream),
2029
+ enqueue_result.value());
2010
2030
  };
2031
+
2011
2032
  return GRPC_LATENT_SEE_PROMISE(
2012
2033
  "Ph2CallOutboundLoop",
2013
2034
  TrySeq(
2014
- send_initial_metadata(),
2015
- [call_handler, send_message]() {
2016
- // The lock will be released once the promise is constructed from
2017
- // this factory. ForEach will be polled after the lock is
2018
- // released.
2019
- return ForEach(MessagesFrom(call_handler), send_message);
2020
- },
2021
- [self = RefAsSubclass<Http2ClientTransport>(),
2022
- send_half_closed = std::move(send_half_closed)]() mutable {
2023
- return send_half_closed();
2035
+ Map(stream->GetCallHandler().PullClientInitialMetadata(),
2036
+ [send_initial_metadata = std::move(send_initial_metadata)](
2037
+ ValueOrFailure<ClientMetadataHandle> metadata) mutable {
2038
+ if (GPR_UNLIKELY(!metadata.ok())) {
2039
+ return absl::InternalError(
2040
+ "Failed to pull client initial metadata");
2041
+ }
2042
+ return std::move(send_initial_metadata)(
2043
+ TakeValue(std::move(metadata)));
2044
+ }),
2045
+ ForEach(MessagesFrom(stream->GetCallHandler()),
2046
+ std::move(send_message)),
2047
+ [send_half_closed = std::move(send_half_closed)]() mutable {
2048
+ return std::move(send_half_closed)();
2024
2049
  },
2025
- [call_handler]() mutable {
2026
- return Map(call_handler.WasCancelled(), [](bool cancelled) {
2027
- GRPC_HTTP2_CLIENT_DLOG
2028
- << "Http2ClientTransport PH2CallOutboundLoop End with "
2029
- "cancelled="
2030
- << cancelled;
2031
- return (cancelled) ? absl::CancelledError() : absl::OkStatus();
2032
- });
2050
+ [stream]() mutable {
2051
+ return Map(
2052
+ stream->GetCallHandler().WasCancelled(), [](bool cancelled) {
2053
+ GRPC_HTTP2_CLIENT_DLOG
2054
+ << "Http2ClientTransport::CallOutboundLoop End with "
2055
+ "cancelled="
2056
+ << cancelled;
2057
+ return (cancelled) ? absl::CancelledError()
2058
+ : absl::OkStatus();
2059
+ });
2033
2060
  }));
2034
2061
  }
2035
2062
 
2036
2063
  void Http2ClientTransport::StartCall(CallHandler call_handler) {
2037
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport StartCall Begin";
2064
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::StartCall Begin";
2065
+
2038
2066
  call_handler.SpawnGuarded(
2039
2067
  "OutboundLoop",
2040
- TrySeq(call_handler.PullClientInitialMetadata(),
2041
- [self = RefAsSubclass<Http2ClientTransport>(),
2042
- call_handler](ClientMetadataHandle metadata) mutable {
2043
- // For a gRPC Client, we only need to check the
2044
- // MAX_CONCURRENT_STREAMS setting compliance at the time of
2045
- // sending (that is write path). A gRPC Client will never
2046
- // receive a stream initiated by a server, so we dont have to
2047
- // check MAX_CONCURRENT_STREAMS compliance on the Read-Path.
2048
- //
2049
- // TODO(tjagtap) : [PH2][P1] Check for MAX_CONCURRENT_STREAMS
2050
- // sent by peer before making a stream. Decide behaviour if we
2051
- // are crossing this threshold.
2052
- //
2053
- // TODO(tjagtap) : [PH2][P1] : For a server we will have to do
2054
- // this for incoming streams only. If a server receives more
2055
- // streams from a client than is allowed by the clients settings,
2056
- // whether or not we should fail is debatable.
2057
- std::optional<RefCountedPtr<Stream>> stream =
2058
- self->MakeStream(call_handler);
2059
- return If(
2060
- stream.has_value(),
2061
- [self, call_handler, stream,
2062
- initial_metadata = std::move(metadata)]() mutable {
2063
- return Map(
2064
- self->CallOutboundLoop(call_handler, stream.value(),
2065
- std::move(initial_metadata)),
2066
- [](absl::Status status) { return status; });
2067
- },
2068
- []() {
2069
- return absl::InternalError("Failed to make stream");
2070
- });
2071
- }));
2072
- GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport StartCall End";
2068
+ [self = RefAsSubclass<Http2ClientTransport>(), call_handler]() mutable {
2069
+ std::optional<RefCountedPtr<Stream>> stream =
2070
+ self->MakeStream(std::move(call_handler));
2071
+
2072
+ return If(
2073
+ stream.has_value(),
2074
+ [self = std::move(self), stream]() mutable {
2075
+ return Map(self->CallOutboundLoop(std::move(stream.value())),
2076
+ [self](absl::Status status) { return status; });
2077
+ },
2078
+ []() { return absl::InternalError("Failed to make stream"); });
2079
+ });
2080
+ GRPC_HTTP2_CLIENT_DLOG << "Http2ClientTransport::StartCall End";
2081
+ }
2082
+
2083
+ ///////////////////////////////////////////////////////////////////////////////
2084
+ // Http2ClientTransport - Test Only Functions
2085
+
2086
+ int64_t Http2ClientTransport::TestOnlyTransportFlowControlWindow() {
2087
+ return flow_control_.remote_window();
2088
+ }
2089
+
2090
+ int64_t Http2ClientTransport::TestOnlyGetStreamFlowControlWindow(
2091
+ const uint32_t stream_id) {
2092
+ RefCountedPtr<Stream> stream = LookupStream(stream_id);
2093
+ if (stream == nullptr) {
2094
+ return -1;
2095
+ }
2096
+ return stream->GetStreamFlowControl().remote_window_delta();
2097
+ }
2098
+
2099
+ ////////////////////////////////////////////////////////////////////////////////
2100
+ // Http2ClientTransport - Ping Helpers
2101
+
2102
+ void Http2ClientTransport::MaybeSpawnPingTimeout(
2103
+ std::optional<uint64_t> opaque_data) {
2104
+ if (opaque_data.has_value()) {
2105
+ SpawnGuardedTransportParty(
2106
+ "PingTimeout", [self = RefAsSubclass<Http2ClientTransport>(),
2107
+ opaque_data = *opaque_data]() {
2108
+ return self->ping_manager_->TimeoutPromise(opaque_data);
2109
+ });
2110
+ }
2111
+ }
2112
+ void Http2ClientTransport::MaybeSpawnDelayedPing(
2113
+ std::optional<Duration> delayed_ping_wait) {
2114
+ if (delayed_ping_wait.has_value()) {
2115
+ SpawnGuardedTransportParty(
2116
+ "DelayedPing", [self = RefAsSubclass<Http2ClientTransport>(),
2117
+ wait = *delayed_ping_wait]() {
2118
+ GRPC_HTTP2_PING_LOG << "Scheduling delayed ping after wait=" << wait;
2119
+ return self->ping_manager_->DelayedPingPromise(wait);
2120
+ });
2121
+ }
2122
+ }
2123
+
2124
+ void Http2ClientTransport::MaybeSpawnKeepaliveLoop() {
2125
+ if (keepalive_manager_->IsKeepAliveLoopNeeded()) {
2126
+ SpawnGuardedTransportParty(
2127
+ "KeepaliveLoop", [self = RefAsSubclass<Http2ClientTransport>()]() {
2128
+ return self->keepalive_manager_->KeepaliveLoop();
2129
+ });
2130
+ }
2131
+ }
2132
+
2133
+ ///////////////////////////////////////////////////////////////////////////////
2134
+ // Class PingSystemInterfaceImpl
2135
+
2136
+ std::unique_ptr<PingInterface>
2137
+ Http2ClientTransport::PingSystemInterfaceImpl::Make(
2138
+ Http2ClientTransport* transport) {
2139
+ return std::make_unique<PingSystemInterfaceImpl>(
2140
+ PingSystemInterfaceImpl(transport));
2073
2141
  }
2074
2142
 
2143
+ absl::Status Http2ClientTransport::PingSystemInterfaceImpl::TriggerWrite() {
2144
+ return transport_->TriggerWriteCycle();
2145
+ }
2146
+
2147
+ Promise<absl::Status>
2148
+ Http2ClientTransport::PingSystemInterfaceImpl::PingTimeout() {
2149
+ GRPC_HTTP2_CLIENT_DLOG << "PingSystemInterfaceImpl::PingTimeout at time: "
2150
+ << Timestamp::Now();
2151
+
2152
+ // TODO(akshitpatel) : [PH2][P2] : The error code here has been chosen
2153
+ // based on CHTTP2's usage of GRPC_STATUS_UNAVAILABLE (which corresponds
2154
+ // to kRefusedStream). However looking at RFC9113, definition of
2155
+ // kRefusedStream doesn't seem to fit this case. We should revisit this
2156
+ // and update the error code.
2157
+ return Immediate(transport_->HandleError(
2158
+ std::nullopt,
2159
+ Http2Status::Http2ConnectionError(Http2ErrorCode::kRefusedStream,
2160
+ GRPC_CHTTP2_PING_TIMEOUT_STR)));
2161
+ }
2162
+
2163
+ ///////////////////////////////////////////////////////////////////////////////
2164
+ // Class KeepAliveInterfaceImpl
2165
+
2166
+ std::unique_ptr<KeepAliveInterface>
2167
+ Http2ClientTransport::KeepAliveInterfaceImpl::Make(
2168
+ Http2ClientTransport* transport) {
2169
+ return std::make_unique<KeepAliveInterfaceImpl>(
2170
+ KeepAliveInterfaceImpl(transport));
2171
+ }
2172
+
2173
+ Promise<absl::Status>
2174
+ Http2ClientTransport::KeepAliveInterfaceImpl::SendPingAndWaitForAck() {
2175
+ return TrySeq(
2176
+ [transport = transport_] { return transport->TriggerWriteCycle(); },
2177
+ [transport = transport_] { return transport->WaitForPingAck(); });
2178
+ }
2179
+
2180
+ Promise<absl::Status>
2181
+ Http2ClientTransport::KeepAliveInterfaceImpl::OnKeepAliveTimeout() {
2182
+ GRPC_HTTP2_CLIENT_DLOG
2183
+ << "KeepAliveInterfaceImpl::OnKeepAliveTimeout triggered";
2184
+ // TODO(akshitpatel) : [PH2][P2] : The error code here has been chosen
2185
+ // based on CHTTP2's usage of GRPC_STATUS_UNAVAILABLE (which corresponds
2186
+ // to kRefusedStream). However looking at RFC9113, definition of
2187
+ // kRefusedStream doesn't seem to fit this case. We should revisit this
2188
+ // and update the error code.
2189
+ return Immediate(transport_->HandleError(
2190
+ std::nullopt,
2191
+ Http2Status::Http2ConnectionError(Http2ErrorCode::kRefusedStream,
2192
+ GRPC_CHTTP2_KEEPALIVE_TIMEOUT_STR)));
2193
+ }
2194
+
2195
+ bool Http2ClientTransport::KeepAliveInterfaceImpl::NeedToSendKeepAlivePing() {
2196
+ bool need_to_send_ping = false;
2197
+ {
2198
+ MutexLock lock(&transport_->transport_mutex_);
2199
+ need_to_send_ping = (transport_->keepalive_permit_without_calls_ ||
2200
+ transport_->GetActiveStreamCountLocked() > 0);
2201
+ }
2202
+ return need_to_send_ping;
2203
+ }
2204
+
2205
+ ///////////////////////////////////////////////////////////////////////////////
2206
+ // Class GoawayInterfaceImpl
2207
+
2208
+ std::unique_ptr<GoawayInterface>
2209
+ Http2ClientTransport::GoawayInterfaceImpl::Make(
2210
+ Http2ClientTransport* transport) {
2211
+ return std::make_unique<GoawayInterfaceImpl>(GoawayInterfaceImpl(transport));
2212
+ }
2213
+
2214
+ uint32_t Http2ClientTransport::GoawayInterfaceImpl::GetLastAcceptedStreamId() {
2215
+ LOG(DFATAL) << "GetLastAcceptedStreamId is not implemented for client "
2216
+ "transport.";
2217
+ return 0;
2218
+ }
2219
+
2220
+ // TODO(akshitpatel) : [PH2][P2] : Eventually there should be a separate ref
2221
+ // counted struct/class passed to all the transport promises/members. This
2222
+ // will help removing back references from the transport members to
2223
+ // transport and greatly simpilfy the cleanup path. Need to do this for
2224
+ // PingSystemInterfaceImpl, KeepAliveInterfaceImpl and GoawayInterfaceImpl.
2225
+
2075
2226
  } // namespace http2
2076
2227
  } // namespace grpc_core