Third attempt: Convert client_auth_filter to promises (#28968)

* wip

* Automated change: Fix sanity tests

* fixes

* progress

* progress

* grpc compiles

* Automated change: Fix sanity tests

* fixing tests

* x

* progress

* better code

* Automated change: Fix sanity tests

* progress

* progress

* windows fix

* Make Duration metadata trivial

* better message

* fix

* Automated change: Fix sanity tests

* fix

* fix

* fix

* fix

* Automated change: Fix sanity tests

* Automated change: Fix sanity tests

* fix

* progress

* fixes

* fix

* fix

* spam

* un-disable errantly disabled tests

* gain insight

* Automated change: Fix sanity tests

* fixes

* fixes

* fix

* debug

* tweak

* fix

* fix timeout

* fix comment

* fixes

* x

* better test

* tests

* Automated change: Fix sanity tests

* missed file

* fix

* x

* fix

* fix

* fix

* fix

* Automated change: Fix sanity tests

* fix

* merge

* Automated change: Fix sanity tests

* Revert "Revert "Revert "Revert "Convert client_auth_filter to promises (#28767)" (#28951)" (#28952)" (#28967)"

This reverts commit 0f73576b17.

* fix potential memory leak

* Fix behavior if >1 pending request

* fix

* fix nullptr access

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/28980/head^2
Craig Tiller 3 years ago committed by GitHub
parent 5fc3ff8203
commit 87acbadba1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      BUILD
  2. 187
      CMakeLists.txt
  3. 4
      Makefile
  4. 292
      build_autogenerated.yaml
  5. 2
      config.m4
  6. 2
      config.w32
  7. 2
      gRPC-C++.podspec
  8. 4
      gRPC-Core.podspec
  9. 3
      grpc.gemspec
  10. 4
      grpc.gyp
  11. 3
      package.xml
  12. 11
      src/core/lib/channel/context.h
  13. 50
      src/core/lib/channel/promise_based_filter.cc
  14. 241
      src/core/lib/channel/promise_based_filter.h
  15. 15
      src/core/lib/http/httpcli_security_connector.cc
  16. 6
      src/core/lib/iomgr/polling_entity.h
  17. 22
      src/core/lib/promise/activity.cc
  18. 270
      src/core/lib/promise/activity.h
  19. 6
      src/core/lib/promise/arena_promise.h
  20. 89
      src/core/lib/promise/detail/basic_seq.h
  21. 2
      src/core/lib/promise/detail/promise_factory.h
  22. 2
      src/core/lib/promise/intra_activity_waiter.h
  23. 6
      src/core/lib/promise/poll.h
  24. 7
      src/core/lib/promise/promise.h
  25. 20
      src/core/lib/promise/seq.h
  26. 27
      src/core/lib/promise/try_seq.h
  27. 2
      src/core/lib/resource_quota/memory_quota.cc
  28. 87
      src/core/lib/security/credentials/call_creds_util.cc
  29. 42
      src/core/lib/security/credentials/call_creds_util.h
  30. 94
      src/core/lib/security/credentials/composite/composite_credentials.cc
  31. 12
      src/core/lib/security/credentials/composite/composite_credentials.h
  32. 34
      src/core/lib/security/credentials/credentials.h
  33. 30
      src/core/lib/security/credentials/fake/fake_credentials.cc
  34. 19
      src/core/lib/security/credentials/fake/fake_credentials.h
  35. 29
      src/core/lib/security/credentials/iam/iam_credentials.cc
  36. 13
      src/core/lib/security/credentials/iam/iam_credentials.h
  37. 40
      src/core/lib/security/credentials/jwt/jwt_credentials.cc
  38. 12
      src/core/lib/security/credentials/jwt/jwt_credentials.h
  39. 122
      src/core/lib/security/credentials/oauth2/oauth2_credentials.cc
  40. 34
      src/core/lib/security/credentials/oauth2/oauth2_credentials.h
  41. 247
      src/core/lib/security/credentials/plugin/plugin_credentials.cc
  42. 78
      src/core/lib/security/credentials/plugin/plugin_credentials.h
  43. 18
      src/core/lib/security/security_connector/alts/alts_security_connector.cc
  44. 14
      src/core/lib/security/security_connector/fake/fake_security_connector.cc
  45. 16
      src/core/lib/security/security_connector/insecure/insecure_security_connector.cc
  46. 13
      src/core/lib/security/security_connector/insecure/insecure_security_connector.h
  47. 18
      src/core/lib/security/security_connector/local/local_security_connector.cc
  48. 4
      src/core/lib/security/security_connector/security_connector.cc
  49. 31
      src/core/lib/security/security_connector/security_connector.h
  50. 17
      src/core/lib/security/security_connector/ssl/ssl_security_connector.cc
  51. 16
      src/core/lib/security/security_connector/ssl_utils.cc
  52. 9
      src/core/lib/security/security_connector/ssl_utils.h
  53. 19
      src/core/lib/security/security_connector/tls/tls_security_connector.cc
  54. 8
      src/core/lib/security/security_connector/tls/tls_security_connector.h
  55. 34
      src/core/lib/security/transport/auth_filters.h
  56. 438
      src/core/lib/security/transport/client_auth_filter.cc
  57. 7
      src/core/lib/transport/transport.h
  58. 2
      src/python/grpcio/grpc_core_dependencies.py
  59. 4
      test/core/end2end/fixtures/h2_oauth2.cc
  60. 30
      test/core/end2end/tests/call_creds.cc
  61. 12
      test/core/promise/activity_test.cc
  62. 8
      test/core/promise/arena_promise_test.cc
  63. 23
      test/core/promise/seq_test.cc
  64. 42
      test/core/promise/try_seq_test.cc
  65. 702
      test/core/security/credentials_test.cc
  66. 115
      test/core/security/oauth2_utils.cc
  67. 2
      test/core/security/tls_security_connector_test.cc
  68. 4
      test/core/transport/binder/end2end/BUILD
  69. 2
      test/cpp/end2end/grpclb_end2end_test.cc
  70. 2
      test/cpp/end2end/rls_end2end_test.cc
  71. 3
      tools/doxygen/Doxyfile.c++.internal
  72. 3
      tools/doxygen/Doxyfile.core.internal

21
BUILD

@ -1099,6 +1099,7 @@ grpc_cc_library(
name = "promise",
external_deps = [
"absl/types:optional",
"absl/status",
],
language = "c++",
public_hdrs = [
@ -1313,6 +1314,7 @@ grpc_cc_library(
"context",
"gpr_base",
"gpr_codegen",
"orphanable",
"poll",
"promise_factory",
"promise_status",
@ -1866,6 +1868,7 @@ grpc_cc_library(
"src/core/lib/channel/channelz_registry.cc",
"src/core/lib/channel/connected_channel.cc",
"src/core/lib/channel/handshaker.cc",
"src/core/lib/channel/promise_based_filter.cc",
"src/core/lib/channel/status_util.cc",
"src/core/lib/compression/compression.cc",
"src/core/lib/compression/compression_internal.cc",
@ -3698,6 +3701,7 @@ grpc_cc_library(
"gpr_base",
"grpc_base",
"grpc_security_base",
"promise",
"ref_counted_ptr",
"tsi_fake_credentials",
],
@ -3716,6 +3720,7 @@ grpc_cc_library(
deps = [
"gpr",
"grpc_security_base",
"promise",
"ref_counted_ptr",
"tsi_local_credentials",
],
@ -3758,6 +3763,7 @@ grpc_cc_library(
"grpc_client_channel",
"grpc_security_base",
"grpc_sockaddr",
"promise",
"ref_counted_ptr",
"sockaddr_utils",
"tsi_local_credentials",
@ -3787,6 +3793,7 @@ grpc_cc_library(
"gpr_base",
"grpc_base",
"grpc_security_base",
"promise",
"ref_counted_ptr",
"tsi_alts_credentials",
"tsi_base",
@ -3814,6 +3821,7 @@ grpc_cc_library(
"grpc_credentials_util",
"grpc_security_base",
"grpc_transport_chttp2_alpn",
"promise",
"ref_counted_ptr",
"tsi_base",
"tsi_ssl_credentials",
@ -3882,6 +3890,7 @@ grpc_cc_library(
"grpc_base",
"grpc_credentials_util",
"grpc_security_base",
"promise",
"tsi_base",
"tsi_ssl_credentials",
],
@ -3904,6 +3913,7 @@ grpc_cc_library(
"gpr_base",
"grpc_base",
"grpc_security_base",
"promise",
"ref_counted_ptr",
],
)
@ -3935,6 +3945,7 @@ grpc_cc_library(
"httpcli",
"httpcli_ssl_credentials",
"json",
"promise",
"ref_counted",
"ref_counted_ptr",
"tsi_ssl_types",
@ -3954,9 +3965,11 @@ grpc_cc_library(
"absl/container:inlined_vector",
"absl/strings",
"absl/strings:str_format",
"absl/status",
],
language = "c++",
deps = [
"capture",
"gpr_base",
"grpc_base",
"grpc_codegen",
@ -3965,6 +3978,7 @@ grpc_cc_library(
"httpcli",
"httpcli_ssl_credentials",
"json",
"promise",
"ref_counted_ptr",
"uri_parser",
],
@ -4023,6 +4037,7 @@ grpc_cc_library(
"gpr_base",
"grpc_base",
"grpc_security_base",
"promise",
"ref_counted_ptr",
"tsi_ssl_credentials",
],
@ -4058,6 +4073,7 @@ grpc_cc_library(
"httpcli",
"httpcli_ssl_credentials",
"json",
"promise",
"ref_counted",
"ref_counted_ptr",
"slice",
@ -4084,6 +4100,7 @@ grpc_cc_library(
name = "grpc_security_base",
srcs = [
"src/core/lib/security/context/security_context.cc",
"src/core/lib/security/credentials/call_creds_util.cc",
"src/core/lib/security/credentials/composite/composite_credentials.cc",
"src/core/lib/security/credentials/credentials.cc",
"src/core/lib/security/credentials/plugin/plugin_credentials.cc",
@ -4096,6 +4113,7 @@ grpc_cc_library(
],
hdrs = [
"src/core/lib/security/context/security_context.h",
"src/core/lib/security/credentials/call_creds_util.h",
"src/core/lib/security/credentials/composite/composite_credentials.h",
"src/core/lib/security/credentials/credentials.h",
"src/core/lib/security/credentials/plugin/plugin_credentials.h",
@ -4115,13 +4133,16 @@ grpc_cc_library(
visibility = ["@grpc:public"],
deps = [
"arena",
"arena_promise",
"config",
"gpr_base",
"grpc_base",
"grpc_trace",
"json",
"promise",
"ref_counted",
"ref_counted_ptr",
"try_seq",
"tsi_base",
],
)

187
CMakeLists.txt generated

@ -1988,6 +1988,7 @@ add_library(grpc
src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc
src/core/lib/channel/handshaker_registry.cc
src/core/lib/channel/promise_based_filter.cc
src/core/lib/channel/status_util.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_internal.cc
@ -2124,6 +2125,7 @@ add_library(grpc
src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
src/core/lib/security/credentials/call_creds_util.cc
src/core/lib/security/credentials/channel_creds_registry_init.cc
src/core/lib/security/credentials/composite/composite_credentials.cc
src/core/lib/security/credentials/credentials.cc
@ -2630,6 +2632,7 @@ add_library(grpc_unsecure
src/core/lib/channel/connected_channel.cc
src/core/lib/channel/handshaker.cc
src/core/lib/channel/handshaker_registry.cc
src/core/lib/channel/promise_based_filter.cc
src/core/lib/channel/status_util.cc
src/core/lib/compression/compression.cc
src/core/lib/compression/compression_internal.cc
@ -2753,6 +2756,7 @@ add_library(grpc_unsecure
src/core/lib/security/authorization/evaluate_args.cc
src/core/lib/security/authorization/grpc_server_authz_filter.cc
src/core/lib/security/context/security_context.cc
src/core/lib/security/credentials/call_creds_util.cc
src/core/lib/security/credentials/composite/composite_credentials.cc
src/core/lib/security/credentials/credentials.cc
src/core/lib/security/credentials/fake/fake_credentials.cc
@ -7373,52 +7377,7 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(activity_test
src/core/ext/upb-generated/google/protobuf/any.upb.c
src/core/ext/upb-generated/google/rpc/status.upb.c
src/core/lib/gpr/alloc.cc
src/core/lib/gpr/atm.cc
src/core/lib/gpr/cpu_iphone.cc
src/core/lib/gpr/cpu_linux.cc
src/core/lib/gpr/cpu_posix.cc
src/core/lib/gpr/cpu_windows.cc
src/core/lib/gpr/env_linux.cc
src/core/lib/gpr/env_posix.cc
src/core/lib/gpr/env_windows.cc
src/core/lib/gpr/log.cc
src/core/lib/gpr/log_android.cc
src/core/lib/gpr/log_linux.cc
src/core/lib/gpr/log_posix.cc
src/core/lib/gpr/log_windows.cc
src/core/lib/gpr/murmur_hash.cc
src/core/lib/gpr/string.cc
src/core/lib/gpr/string_posix.cc
src/core/lib/gpr/string_util_windows.cc
src/core/lib/gpr/string_windows.cc
src/core/lib/gpr/sync.cc
src/core/lib/gpr/sync_abseil.cc
src/core/lib/gpr/sync_posix.cc
src/core/lib/gpr/sync_windows.cc
src/core/lib/gpr/time.cc
src/core/lib/gpr/time_posix.cc
src/core/lib/gpr/time_precise.cc
src/core/lib/gpr/time_windows.cc
src/core/lib/gpr/tmpfile_msys.cc
src/core/lib/gpr/tmpfile_posix.cc
src/core/lib/gpr/tmpfile_windows.cc
src/core/lib/gpr/wrap_memcpy.cc
src/core/lib/gprpp/examine_stack.cc
src/core/lib/gprpp/fork.cc
src/core/lib/gprpp/global_config_env.cc
src/core/lib/gprpp/host_port.cc
src/core/lib/gprpp/mpscq.cc
src/core/lib/gprpp/stat_posix.cc
src/core/lib/gprpp/stat_windows.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/thd_posix.cc
src/core/lib/gprpp/thd_windows.cc
src/core/lib/gprpp/time_util.cc
src/core/lib/profiling/basic_timers.cc
src/core/lib/profiling/stap_timers.cc
src/core/lib/debug/trace.cc
src/core/lib/promise/activity.cc
test/core/promise/activity_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -7447,21 +7406,10 @@ target_include_directories(activity_test
target_link_libraries(activity_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::base
absl::core_headers
absl::flat_hash_set
absl::memory
absl::random_random
absl::status
absl::statusor
absl::cord
absl::str_format
absl::strings
absl::synchronization
absl::time
absl::optional
absl::variant
upb
gpr
)
@ -12503,52 +12451,7 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(latch_test
src/core/ext/upb-generated/google/protobuf/any.upb.c
src/core/ext/upb-generated/google/rpc/status.upb.c
src/core/lib/gpr/alloc.cc
src/core/lib/gpr/atm.cc
src/core/lib/gpr/cpu_iphone.cc
src/core/lib/gpr/cpu_linux.cc
src/core/lib/gpr/cpu_posix.cc
src/core/lib/gpr/cpu_windows.cc
src/core/lib/gpr/env_linux.cc
src/core/lib/gpr/env_posix.cc
src/core/lib/gpr/env_windows.cc
src/core/lib/gpr/log.cc
src/core/lib/gpr/log_android.cc
src/core/lib/gpr/log_linux.cc
src/core/lib/gpr/log_posix.cc
src/core/lib/gpr/log_windows.cc
src/core/lib/gpr/murmur_hash.cc
src/core/lib/gpr/string.cc
src/core/lib/gpr/string_posix.cc
src/core/lib/gpr/string_util_windows.cc
src/core/lib/gpr/string_windows.cc
src/core/lib/gpr/sync.cc
src/core/lib/gpr/sync_abseil.cc
src/core/lib/gpr/sync_posix.cc
src/core/lib/gpr/sync_windows.cc
src/core/lib/gpr/time.cc
src/core/lib/gpr/time_posix.cc
src/core/lib/gpr/time_precise.cc
src/core/lib/gpr/time_windows.cc
src/core/lib/gpr/tmpfile_msys.cc
src/core/lib/gpr/tmpfile_posix.cc
src/core/lib/gpr/tmpfile_windows.cc
src/core/lib/gpr/wrap_memcpy.cc
src/core/lib/gprpp/examine_stack.cc
src/core/lib/gprpp/fork.cc
src/core/lib/gprpp/global_config_env.cc
src/core/lib/gprpp/host_port.cc
src/core/lib/gprpp/mpscq.cc
src/core/lib/gprpp/stat_posix.cc
src/core/lib/gprpp/stat_windows.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/thd_posix.cc
src/core/lib/gprpp/thd_windows.cc
src/core/lib/gprpp/time_util.cc
src/core/lib/profiling/basic_timers.cc
src/core/lib/profiling/stap_timers.cc
src/core/lib/debug/trace.cc
src/core/lib/promise/activity.cc
test/core/promise/latch_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -12577,20 +12480,9 @@ target_include_directories(latch_test
target_link_libraries(latch_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::base
absl::core_headers
absl::memory
absl::random_random
absl::status
absl::statusor
absl::cord
absl::str_format
absl::strings
absl::synchronization
absl::time
absl::optional
absl::variant
upb
gpr
)
@ -13166,52 +13058,7 @@ endif()
if(gRPC_BUILD_TESTS)
add_executable(observable_test
src/core/ext/upb-generated/google/protobuf/any.upb.c
src/core/ext/upb-generated/google/rpc/status.upb.c
src/core/lib/gpr/alloc.cc
src/core/lib/gpr/atm.cc
src/core/lib/gpr/cpu_iphone.cc
src/core/lib/gpr/cpu_linux.cc
src/core/lib/gpr/cpu_posix.cc
src/core/lib/gpr/cpu_windows.cc
src/core/lib/gpr/env_linux.cc
src/core/lib/gpr/env_posix.cc
src/core/lib/gpr/env_windows.cc
src/core/lib/gpr/log.cc
src/core/lib/gpr/log_android.cc
src/core/lib/gpr/log_linux.cc
src/core/lib/gpr/log_posix.cc
src/core/lib/gpr/log_windows.cc
src/core/lib/gpr/murmur_hash.cc
src/core/lib/gpr/string.cc
src/core/lib/gpr/string_posix.cc
src/core/lib/gpr/string_util_windows.cc
src/core/lib/gpr/string_windows.cc
src/core/lib/gpr/sync.cc
src/core/lib/gpr/sync_abseil.cc
src/core/lib/gpr/sync_posix.cc
src/core/lib/gpr/sync_windows.cc
src/core/lib/gpr/time.cc
src/core/lib/gpr/time_posix.cc
src/core/lib/gpr/time_precise.cc
src/core/lib/gpr/time_windows.cc
src/core/lib/gpr/tmpfile_msys.cc
src/core/lib/gpr/tmpfile_posix.cc
src/core/lib/gpr/tmpfile_windows.cc
src/core/lib/gpr/wrap_memcpy.cc
src/core/lib/gprpp/examine_stack.cc
src/core/lib/gprpp/fork.cc
src/core/lib/gprpp/global_config_env.cc
src/core/lib/gprpp/host_port.cc
src/core/lib/gprpp/mpscq.cc
src/core/lib/gprpp/stat_posix.cc
src/core/lib/gprpp/stat_windows.cc
src/core/lib/gprpp/status_helper.cc
src/core/lib/gprpp/thd_posix.cc
src/core/lib/gprpp/thd_windows.cc
src/core/lib/gprpp/time_util.cc
src/core/lib/profiling/basic_timers.cc
src/core/lib/profiling/stap_timers.cc
src/core/lib/debug/trace.cc
src/core/lib/promise/activity.cc
test/core/promise/observable_test.cc
third_party/googletest/googletest/src/gtest-all.cc
@ -13240,21 +13087,10 @@ target_include_directories(observable_test
target_link_libraries(observable_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::base
absl::core_headers
absl::flat_hash_set
absl::memory
absl::random_random
absl::status
absl::statusor
absl::cord
absl::str_format
absl::strings
absl::synchronization
absl::time
absl::optional
absl::variant
upb
gpr
)
@ -13603,6 +13439,7 @@ target_link_libraries(promise_factory_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::bind_front
absl::status
absl::optional
absl::variant
absl::utility
@ -13640,6 +13477,7 @@ target_include_directories(promise_map_test
target_link_libraries(promise_map_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::status
absl::optional
absl::variant
)
@ -13676,6 +13514,7 @@ target_include_directories(promise_test
target_link_libraries(promise_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
absl::status
absl::optional
absl::variant
)

4
Makefile generated

@ -1429,6 +1429,7 @@ LIBGRPC_SRC = \
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/promise_based_filter.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
@ -1565,6 +1566,7 @@ LIBGRPC_SRC = \
src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc \
src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc \
src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc \
src/core/lib/security/credentials/call_creds_util.cc \
src/core/lib/security/credentials/channel_creds_registry_init.cc \
src/core/lib/security/credentials/composite/composite_credentials.cc \
src/core/lib/security/credentials/credentials.cc \
@ -1920,6 +1922,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/promise_based_filter.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
@ -2043,6 +2046,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/security/authorization/evaluate_args.cc \
src/core/lib/security/authorization/grpc_server_authz_filter.cc \
src/core/lib/security/context/security_context.cc \
src/core/lib/security/credentials/call_creds_util.cc \
src/core/lib/security/credentials/composite/composite_credentials.cc \
src/core/lib/security/credentials/credentials.cc \
src/core/lib/security/credentials/fake/fake_credentials.cc \

@ -970,6 +970,7 @@ libs:
- src/core/lib/security/credentials/alts/alts_credentials.h
- src/core/lib/security/credentials/alts/check_gcp_environment.h
- src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h
- src/core/lib/security/credentials/call_creds_util.h
- src/core/lib/security/credentials/channel_creds_registry.h
- src/core/lib/security/credentials/composite/composite_credentials.h
- src/core/lib/security/credentials/credentials.h
@ -1487,6 +1488,7 @@ libs:
- src/core/lib/channel/connected_channel.cc
- src/core/lib/channel/handshaker.cc
- src/core/lib/channel/handshaker_registry.cc
- src/core/lib/channel/promise_based_filter.cc
- src/core/lib/channel/status_util.cc
- src/core/lib/compression/compression.cc
- src/core/lib/compression/compression_internal.cc
@ -1623,6 +1625,7 @@ libs:
- src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc
- src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc
- src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc
- src/core/lib/security/credentials/call_creds_util.cc
- src/core/lib/security/credentials/channel_creds_registry_init.cc
- src/core/lib/security/credentials/composite/composite_credentials.cc
- src/core/lib/security/credentials/credentials.cc
@ -2129,6 +2132,7 @@ libs:
- src/core/lib/security/authorization/evaluate_args.h
- src/core/lib/security/authorization/grpc_server_authz_filter.h
- src/core/lib/security/context/security_context.h
- src/core/lib/security/credentials/call_creds_util.h
- src/core/lib/security/credentials/channel_creds_registry.h
- src/core/lib/security/credentials/composite/composite_credentials.h
- src/core/lib/security/credentials/credentials.h
@ -2308,6 +2312,7 @@ libs:
- src/core/lib/channel/connected_channel.cc
- src/core/lib/channel/handshaker.cc
- src/core/lib/channel/handshaker_registry.cc
- src/core/lib/channel/promise_based_filter.cc
- src/core/lib/channel/status_util.cc
- src/core/lib/compression/compression.cc
- src/core/lib/compression/compression_internal.cc
@ -2431,6 +2436,7 @@ libs:
- src/core/lib/security/authorization/evaluate_args.cc
- src/core/lib/security/authorization/grpc_server_authz_filter.cc
- src/core/lib/security/context/security_context.cc
- src/core/lib/security/credentials/call_creds_util.cc
- src/core/lib/security/credentials/composite/composite_credentials.cc
- src/core/lib/security/credentials/credentials.cc
- src/core/lib/security/credentials/fake/fake_credentials.cc
@ -4411,38 +4417,12 @@ targets:
build: test
language: c++
headers:
- src/core/ext/upb-generated/google/protobuf/any.upb.h
- src/core/ext/upb-generated/google/rpc/status.upb.h
- src/core/lib/gpr/alloc.h
- src/core/lib/gpr/env.h
- src/core/lib/gpr/murmur_hash.h
- src/core/lib/gpr/spinlock.h
- src/core/lib/gpr/string.h
- src/core/lib/gpr/string_windows.h
- src/core/lib/gpr/time_precise.h
- src/core/lib/gpr/tls.h
- src/core/lib/gpr/tmpfile.h
- src/core/lib/gpr/useful.h
- src/core/lib/debug/trace.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/bitset.h
- src/core/lib/gprpp/construct_destruct.h
- src/core/lib/gprpp/debug_location.h
- src/core/lib/gprpp/examine_stack.h
- src/core/lib/gprpp/fork.h
- src/core/lib/gprpp/global_config.h
- src/core/lib/gprpp/global_config_custom.h
- src/core/lib/gprpp/global_config_env.h
- src/core/lib/gprpp/global_config_generic.h
- src/core/lib/gprpp/host_port.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/memory.h
- src/core/lib/gprpp/mpscq.h
- src/core/lib/gprpp/stat.h
- src/core/lib/gprpp/status_helper.h
- src/core/lib/gprpp/sync.h
- src/core/lib/gprpp/thd.h
- src/core/lib/gprpp/time_util.h
- src/core/lib/profiling/timers.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_join.h
@ -4458,70 +4438,14 @@ targets:
- src/core/lib/promise/wait_set.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/ext/upb-generated/google/protobuf/any.upb.c
- src/core/ext/upb-generated/google/rpc/status.upb.c
- src/core/lib/gpr/alloc.cc
- src/core/lib/gpr/atm.cc
- src/core/lib/gpr/cpu_iphone.cc
- src/core/lib/gpr/cpu_linux.cc
- src/core/lib/gpr/cpu_posix.cc
- src/core/lib/gpr/cpu_windows.cc
- src/core/lib/gpr/env_linux.cc
- src/core/lib/gpr/env_posix.cc
- src/core/lib/gpr/env_windows.cc
- src/core/lib/gpr/log.cc
- src/core/lib/gpr/log_android.cc
- src/core/lib/gpr/log_linux.cc
- src/core/lib/gpr/log_posix.cc
- src/core/lib/gpr/log_windows.cc
- src/core/lib/gpr/murmur_hash.cc
- src/core/lib/gpr/string.cc
- src/core/lib/gpr/string_posix.cc
- src/core/lib/gpr/string_util_windows.cc
- src/core/lib/gpr/string_windows.cc
- src/core/lib/gpr/sync.cc
- src/core/lib/gpr/sync_abseil.cc
- src/core/lib/gpr/sync_posix.cc
- src/core/lib/gpr/sync_windows.cc
- src/core/lib/gpr/time.cc
- src/core/lib/gpr/time_posix.cc
- src/core/lib/gpr/time_precise.cc
- src/core/lib/gpr/time_windows.cc
- src/core/lib/gpr/tmpfile_msys.cc
- src/core/lib/gpr/tmpfile_posix.cc
- src/core/lib/gpr/tmpfile_windows.cc
- src/core/lib/gpr/wrap_memcpy.cc
- src/core/lib/gprpp/examine_stack.cc
- src/core/lib/gprpp/fork.cc
- src/core/lib/gprpp/global_config_env.cc
- src/core/lib/gprpp/host_port.cc
- src/core/lib/gprpp/mpscq.cc
- src/core/lib/gprpp/stat_posix.cc
- src/core/lib/gprpp/stat_windows.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/thd_posix.cc
- src/core/lib/gprpp/thd_windows.cc
- src/core/lib/gprpp/time_util.cc
- src/core/lib/profiling/basic_timers.cc
- src/core/lib/profiling/stap_timers.cc
- src/core/lib/debug/trace.cc
- src/core/lib/promise/activity.cc
- test/core/promise/activity_test.cc
deps:
- absl/base:base
- absl/base:core_headers
- absl/container:flat_hash_set
- absl/memory:memory
- absl/random:random
- absl/status:status
- absl/status:statusor
- absl/strings:cord
- absl/strings:str_format
- absl/strings:strings
- absl/synchronization:synchronization
- absl/time:time
- absl/types:optional
- absl/types:variant
- upb
- gpr
uses_polling: false
- name: address_sorting_test
gtest: true
@ -5690,6 +5614,7 @@ targets:
headers:
- src/core/lib/debug/trace.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/time.h
@ -6516,38 +6441,12 @@ targets:
build: test
language: c++
headers:
- src/core/ext/upb-generated/google/protobuf/any.upb.h
- src/core/ext/upb-generated/google/rpc/status.upb.h
- src/core/lib/gpr/alloc.h
- src/core/lib/gpr/env.h
- src/core/lib/gpr/murmur_hash.h
- src/core/lib/gpr/spinlock.h
- src/core/lib/gpr/string.h
- src/core/lib/gpr/string_windows.h
- src/core/lib/gpr/time_precise.h
- src/core/lib/gpr/tls.h
- src/core/lib/gpr/tmpfile.h
- src/core/lib/gpr/useful.h
- src/core/lib/debug/trace.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/bitset.h
- src/core/lib/gprpp/construct_destruct.h
- src/core/lib/gprpp/debug_location.h
- src/core/lib/gprpp/examine_stack.h
- src/core/lib/gprpp/fork.h
- src/core/lib/gprpp/global_config.h
- src/core/lib/gprpp/global_config_custom.h
- src/core/lib/gprpp/global_config_env.h
- src/core/lib/gprpp/global_config_generic.h
- src/core/lib/gprpp/host_port.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/memory.h
- src/core/lib/gprpp/mpscq.h
- src/core/lib/gprpp/stat.h
- src/core/lib/gprpp/status_helper.h
- src/core/lib/gprpp/sync.h
- src/core/lib/gprpp/thd.h
- src/core/lib/gprpp/time_util.h
- src/core/lib/profiling/timers.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_join.h
@ -6563,69 +6462,13 @@ targets:
- src/core/lib/promise/seq.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/ext/upb-generated/google/protobuf/any.upb.c
- src/core/ext/upb-generated/google/rpc/status.upb.c
- src/core/lib/gpr/alloc.cc
- src/core/lib/gpr/atm.cc
- src/core/lib/gpr/cpu_iphone.cc
- src/core/lib/gpr/cpu_linux.cc
- src/core/lib/gpr/cpu_posix.cc
- src/core/lib/gpr/cpu_windows.cc
- src/core/lib/gpr/env_linux.cc
- src/core/lib/gpr/env_posix.cc
- src/core/lib/gpr/env_windows.cc
- src/core/lib/gpr/log.cc
- src/core/lib/gpr/log_android.cc
- src/core/lib/gpr/log_linux.cc
- src/core/lib/gpr/log_posix.cc
- src/core/lib/gpr/log_windows.cc
- src/core/lib/gpr/murmur_hash.cc
- src/core/lib/gpr/string.cc
- src/core/lib/gpr/string_posix.cc
- src/core/lib/gpr/string_util_windows.cc
- src/core/lib/gpr/string_windows.cc
- src/core/lib/gpr/sync.cc
- src/core/lib/gpr/sync_abseil.cc
- src/core/lib/gpr/sync_posix.cc
- src/core/lib/gpr/sync_windows.cc
- src/core/lib/gpr/time.cc
- src/core/lib/gpr/time_posix.cc
- src/core/lib/gpr/time_precise.cc
- src/core/lib/gpr/time_windows.cc
- src/core/lib/gpr/tmpfile_msys.cc
- src/core/lib/gpr/tmpfile_posix.cc
- src/core/lib/gpr/tmpfile_windows.cc
- src/core/lib/gpr/wrap_memcpy.cc
- src/core/lib/gprpp/examine_stack.cc
- src/core/lib/gprpp/fork.cc
- src/core/lib/gprpp/global_config_env.cc
- src/core/lib/gprpp/host_port.cc
- src/core/lib/gprpp/mpscq.cc
- src/core/lib/gprpp/stat_posix.cc
- src/core/lib/gprpp/stat_windows.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/thd_posix.cc
- src/core/lib/gprpp/thd_windows.cc
- src/core/lib/gprpp/time_util.cc
- src/core/lib/profiling/basic_timers.cc
- src/core/lib/profiling/stap_timers.cc
- src/core/lib/debug/trace.cc
- src/core/lib/promise/activity.cc
- test/core/promise/latch_test.cc
deps:
- absl/base:base
- absl/base:core_headers
- absl/memory:memory
- absl/random:random
- absl/status:status
- absl/status:statusor
- absl/strings:cord
- absl/strings:str_format
- absl/strings:strings
- absl/synchronization:synchronization
- absl/time:time
- absl/types:optional
- absl/types:variant
- upb
- gpr
uses_polling: false
- name: lb_get_cpu_stats_test
gtest: true
@ -6851,37 +6694,11 @@ targets:
build: test
language: c++
headers:
- src/core/ext/upb-generated/google/protobuf/any.upb.h
- src/core/ext/upb-generated/google/rpc/status.upb.h
- src/core/lib/gpr/alloc.h
- src/core/lib/gpr/env.h
- src/core/lib/gpr/murmur_hash.h
- src/core/lib/gpr/spinlock.h
- src/core/lib/gpr/string.h
- src/core/lib/gpr/string_windows.h
- src/core/lib/gpr/time_precise.h
- src/core/lib/gpr/tls.h
- src/core/lib/gpr/tmpfile.h
- src/core/lib/gpr/useful.h
- src/core/lib/debug/trace.h
- src/core/lib/gprpp/atomic_utils.h
- src/core/lib/gprpp/construct_destruct.h
- src/core/lib/gprpp/debug_location.h
- src/core/lib/gprpp/examine_stack.h
- src/core/lib/gprpp/fork.h
- src/core/lib/gprpp/global_config.h
- src/core/lib/gprpp/global_config_custom.h
- src/core/lib/gprpp/global_config_env.h
- src/core/lib/gprpp/global_config_generic.h
- src/core/lib/gprpp/host_port.h
- src/core/lib/gprpp/manual_constructor.h
- src/core/lib/gprpp/memory.h
- src/core/lib/gprpp/mpscq.h
- src/core/lib/gprpp/stat.h
- src/core/lib/gprpp/status_helper.h
- src/core/lib/gprpp/sync.h
- src/core/lib/gprpp/thd.h
- src/core/lib/gprpp/time_util.h
- src/core/lib/profiling/timers.h
- src/core/lib/gprpp/orphanable.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/promise/activity.h
- src/core/lib/promise/context.h
- src/core/lib/promise/detail/basic_seq.h
@ -6896,70 +6713,14 @@ targets:
- src/core/lib/promise/wait_set.h
- test/core/promise/test_wakeup_schedulers.h
src:
- src/core/ext/upb-generated/google/protobuf/any.upb.c
- src/core/ext/upb-generated/google/rpc/status.upb.c
- src/core/lib/gpr/alloc.cc
- src/core/lib/gpr/atm.cc
- src/core/lib/gpr/cpu_iphone.cc
- src/core/lib/gpr/cpu_linux.cc
- src/core/lib/gpr/cpu_posix.cc
- src/core/lib/gpr/cpu_windows.cc
- src/core/lib/gpr/env_linux.cc
- src/core/lib/gpr/env_posix.cc
- src/core/lib/gpr/env_windows.cc
- src/core/lib/gpr/log.cc
- src/core/lib/gpr/log_android.cc
- src/core/lib/gpr/log_linux.cc
- src/core/lib/gpr/log_posix.cc
- src/core/lib/gpr/log_windows.cc
- src/core/lib/gpr/murmur_hash.cc
- src/core/lib/gpr/string.cc
- src/core/lib/gpr/string_posix.cc
- src/core/lib/gpr/string_util_windows.cc
- src/core/lib/gpr/string_windows.cc
- src/core/lib/gpr/sync.cc
- src/core/lib/gpr/sync_abseil.cc
- src/core/lib/gpr/sync_posix.cc
- src/core/lib/gpr/sync_windows.cc
- src/core/lib/gpr/time.cc
- src/core/lib/gpr/time_posix.cc
- src/core/lib/gpr/time_precise.cc
- src/core/lib/gpr/time_windows.cc
- src/core/lib/gpr/tmpfile_msys.cc
- src/core/lib/gpr/tmpfile_posix.cc
- src/core/lib/gpr/tmpfile_windows.cc
- src/core/lib/gpr/wrap_memcpy.cc
- src/core/lib/gprpp/examine_stack.cc
- src/core/lib/gprpp/fork.cc
- src/core/lib/gprpp/global_config_env.cc
- src/core/lib/gprpp/host_port.cc
- src/core/lib/gprpp/mpscq.cc
- src/core/lib/gprpp/stat_posix.cc
- src/core/lib/gprpp/stat_windows.cc
- src/core/lib/gprpp/status_helper.cc
- src/core/lib/gprpp/thd_posix.cc
- src/core/lib/gprpp/thd_windows.cc
- src/core/lib/gprpp/time_util.cc
- src/core/lib/profiling/basic_timers.cc
- src/core/lib/profiling/stap_timers.cc
- src/core/lib/debug/trace.cc
- src/core/lib/promise/activity.cc
- test/core/promise/observable_test.cc
deps:
- absl/base:base
- absl/base:core_headers
- absl/container:flat_hash_set
- absl/memory:memory
- absl/random:random
- absl/status:status
- absl/status:statusor
- absl/strings:cord
- absl/strings:str_format
- absl/strings:strings
- absl/synchronization:synchronization
- absl/time:time
- absl/types:optional
- absl/types:variant
- upb
- gpr
uses_polling: false
- name: orphanable_test
gtest: true
@ -7124,6 +6885,7 @@ targets:
- test/core/promise/promise_factory_test.cc
deps:
- absl/functional:bind_front
- absl/status:status
- absl/types:optional
- absl/types:variant
- absl/utility:utility
@ -7140,6 +6902,7 @@ targets:
src:
- test/core/promise/map_test.cc
deps:
- absl/status:status
- absl/types:optional
- absl/types:variant
uses_polling: false
@ -7154,6 +6917,7 @@ targets:
src:
- test/core/promise/promise_test.cc
deps:
- absl/status:status
- absl/types:optional
- absl/types:variant
uses_polling: false

2
config.m4 generated

@ -447,6 +447,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/channel/connected_channel.cc \
src/core/lib/channel/handshaker.cc \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/promise_based_filter.cc \
src/core/lib/channel/status_util.cc \
src/core/lib/compression/compression.cc \
src/core/lib/compression/compression_internal.cc \
@ -627,6 +628,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc \
src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc \
src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc \
src/core/lib/security/credentials/call_creds_util.cc \
src/core/lib/security/credentials/channel_creds_registry_init.cc \
src/core/lib/security/credentials/composite/composite_credentials.cc \
src/core/lib/security/credentials/credentials.cc \

2
config.w32 generated

@ -413,6 +413,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\channel\\connected_channel.cc " +
"src\\core\\lib\\channel\\handshaker.cc " +
"src\\core\\lib\\channel\\handshaker_registry.cc " +
"src\\core\\lib\\channel\\promise_based_filter.cc " +
"src\\core\\lib\\channel\\status_util.cc " +
"src\\core\\lib\\compression\\compression.cc " +
"src\\core\\lib\\compression\\compression_internal.cc " +
@ -593,6 +594,7 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\security\\credentials\\alts\\grpc_alts_credentials_client_options.cc " +
"src\\core\\lib\\security\\credentials\\alts\\grpc_alts_credentials_options.cc " +
"src\\core\\lib\\security\\credentials\\alts\\grpc_alts_credentials_server_options.cc " +
"src\\core\\lib\\security\\credentials\\call_creds_util.cc " +
"src\\core\\lib\\security\\credentials\\channel_creds_registry_init.cc " +
"src\\core\\lib\\security\\credentials\\composite\\composite_credentials.cc " +
"src\\core\\lib\\security\\credentials\\credentials.cc " +

2
gRPC-C++.podspec generated

@ -816,6 +816,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/alts/check_gcp_environment.h',
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/call_creds_util.h',
'src/core/lib/security/credentials/channel_creds_registry.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',
@ -1614,6 +1615,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/alts/check_gcp_environment.h',
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/call_creds_util.h',
'src/core/lib/security/credentials/channel_creds_registry.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',

4
gRPC-Core.podspec generated

@ -993,6 +993,7 @@ Pod::Spec.new do |s|
'src/core/lib/channel/handshaker_factory.h',
'src/core/lib/channel/handshaker_registry.cc',
'src/core/lib/channel/handshaker_registry.h',
'src/core/lib/channel/promise_based_filter.cc',
'src/core/lib/channel/promise_based_filter.h',
'src/core/lib/channel/status_util.cc',
'src/core/lib/channel/status_util.h',
@ -1342,6 +1343,8 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc',
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc',
'src/core/lib/security/credentials/call_creds_util.cc',
'src/core/lib/security/credentials/call_creds_util.h',
'src/core/lib/security/credentials/channel_creds_registry.h',
'src/core/lib/security/credentials/channel_creds_registry_init.cc',
'src/core/lib/security/credentials/composite/composite_credentials.cc',
@ -2209,6 +2212,7 @@ Pod::Spec.new do |s|
'src/core/lib/security/credentials/alts/alts_credentials.h',
'src/core/lib/security/credentials/alts/check_gcp_environment.h',
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h',
'src/core/lib/security/credentials/call_creds_util.h',
'src/core/lib/security/credentials/channel_creds_registry.h',
'src/core/lib/security/credentials/composite/composite_credentials.h',
'src/core/lib/security/credentials/credentials.h',

3
grpc.gemspec generated

@ -912,6 +912,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/channel/handshaker_factory.h )
s.files += %w( src/core/lib/channel/handshaker_registry.cc )
s.files += %w( src/core/lib/channel/handshaker_registry.h )
s.files += %w( src/core/lib/channel/promise_based_filter.cc )
s.files += %w( src/core/lib/channel/promise_based_filter.h )
s.files += %w( src/core/lib/channel/status_util.cc )
s.files += %w( src/core/lib/channel/status_util.h )
@ -1261,6 +1262,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc )
s.files += %w( src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h )
s.files += %w( src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc )
s.files += %w( src/core/lib/security/credentials/call_creds_util.cc )
s.files += %w( src/core/lib/security/credentials/call_creds_util.h )
s.files += %w( src/core/lib/security/credentials/channel_creds_registry.h )
s.files += %w( src/core/lib/security/credentials/channel_creds_registry_init.cc )
s.files += %w( src/core/lib/security/credentials/composite/composite_credentials.cc )

4
grpc.gyp generated

@ -891,6 +891,7 @@
'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc',
'src/core/lib/channel/handshaker_registry.cc',
'src/core/lib/channel/promise_based_filter.cc',
'src/core/lib/channel/status_util.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
@ -1027,6 +1028,7 @@
'src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc',
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc',
'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc',
'src/core/lib/security/credentials/call_creds_util.cc',
'src/core/lib/security/credentials/channel_creds_registry_init.cc',
'src/core/lib/security/credentials/composite/composite_credentials.cc',
'src/core/lib/security/credentials/credentials.cc',
@ -1353,6 +1355,7 @@
'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc',
'src/core/lib/channel/handshaker_registry.cc',
'src/core/lib/channel/promise_based_filter.cc',
'src/core/lib/channel/status_util.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
@ -1476,6 +1479,7 @@
'src/core/lib/security/authorization/evaluate_args.cc',
'src/core/lib/security/authorization/grpc_server_authz_filter.cc',
'src/core/lib/security/context/security_context.cc',
'src/core/lib/security/credentials/call_creds_util.cc',
'src/core/lib/security/credentials/composite/composite_credentials.cc',
'src/core/lib/security/credentials/credentials.cc',
'src/core/lib/security/credentials/fake/fake_credentials.cc',

3
package.xml generated

@ -892,6 +892,7 @@
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/handshaker_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/promise_based_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/promise_based_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/status_util.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/channel/status_util.h" role="src" />
@ -1241,6 +1242,8 @@
<file baseinstalldir="/" name="src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/call_creds_util.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/call_creds_util.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/channel_creds_registry.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/channel_creds_registry_init.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/security/credentials/composite/composite_credentials.cc" role="src" />

@ -19,6 +19,10 @@
#ifndef GRPC_CORE_LIB_CHANNEL_CONTEXT_H
#define GRPC_CORE_LIB_CHANNEL_CONTEXT_H
#include <grpc/support/port_platform.h>
#include "src/core/lib/promise/context.h"
/// Call object context pointers.
/// Call context is represented as an array of \a grpc_call_context_elements.
@ -49,4 +53,11 @@ struct grpc_call_context_element {
void (*destroy)(void*) = nullptr;
};
namespace grpc_core {
// Bind the legacy context array into the new style structure
// TODO(ctiller): remove as we migrate these contexts to the new system.
template <>
struct ContextType<grpc_call_context_element> {};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_CHANNEL_CONTEXT_H */

@ -0,0 +1,50 @@
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <grpc/support/port_platform.h>
#include "src/core/lib/channel/promise_based_filter.h"
#include "src/core/lib/channel/channel_stack.h"
namespace grpc_core {
namespace promise_filter_detail {
// We don't form ActivityPtr's to this type, and consequently don't need
// Orphan().
void BaseCallData::Orphan() { abort(); }
// For now we don't care about owning/non-owning wakers, instead just share
// implementation.
Waker BaseCallData::MakeNonOwningWaker() { return MakeOwningWaker(); }
Waker BaseCallData::MakeOwningWaker() {
GRPC_CALL_STACK_REF(call_stack_, "waker");
return Waker(this);
}
void BaseCallData::Wakeup() {
auto wakeup = [](void* p, grpc_error_handle) {
auto* self = static_cast<BaseCallData*>(p);
self->OnWakeup();
self->Drop();
};
auto* closure = GRPC_CLOSURE_CREATE(wakeup, this, nullptr);
GRPC_CALL_COMBINER_START(call_combiner_, closure, GRPC_ERROR_NONE, "wakeup");
}
void BaseCallData::Drop() { GRPC_CALL_STACK_UNREF(call_stack_, "waker"); }
} // namespace promise_filter_detail
} // namespace grpc_core

@ -27,6 +27,7 @@
#include <grpc/support/log.h>
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/context.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/promise/arena_promise.h"
@ -77,19 +78,34 @@ enum class FilterEndpoint {
namespace promise_filter_detail {
// Call data shared between all implementations of promise-based filters.
class BaseCallData {
class BaseCallData : public Activity, private Wakeable {
public:
BaseCallData(grpc_call_element* elem, const grpc_call_element_args* args)
: elem_(elem),
: call_stack_(args->call_stack),
elem_(elem),
arena_(args->arena),
call_combiner_(args->call_combiner),
deadline_(args->deadline) {}
deadline_(args->deadline),
context_(args->context) {}
void set_pollent(grpc_polling_entity* pollent) { pollent_ = pollent; }
// Activity implementation (partial).
void Orphan() final;
Waker MakeNonOwningWaker() final;
Waker MakeOwningWaker() final;
protected:
class ScopedContext : public promise_detail::Context<Arena> {
class ScopedContext
: public promise_detail::Context<Arena>,
public promise_detail::Context<grpc_call_context_element>,
public promise_detail::Context<grpc_polling_entity> {
public:
explicit ScopedContext(BaseCallData* call_data)
: promise_detail::Context<Arena>(call_data->arena_) {}
: promise_detail::Context<Arena>(call_data->arena_),
promise_detail::Context<grpc_call_context_element>(
call_data->context_),
promise_detail::Context<grpc_polling_entity>(call_data->pollent_) {}
};
static MetadataHandle<grpc_metadata_batch> WrapMetadata(
@ -105,12 +121,22 @@ class BaseCallData {
grpc_call_element* elem() const { return elem_; }
CallCombiner* call_combiner() const { return call_combiner_; }
Timestamp deadline() const { return deadline_; }
grpc_call_stack* call_stack() const { return call_stack_; }
private:
// Wakeable implementation.
void Wakeup() final;
void Drop() final;
virtual void OnWakeup() = 0;
grpc_call_stack* const call_stack_;
grpc_call_element* const elem_;
Arena* const arena_;
CallCombiner* const call_combiner_;
const Timestamp deadline_;
grpc_call_context_element* const context_;
grpc_polling_entity* pollent_ = nullptr;
};
// Specific call data per channel filter.
@ -130,11 +156,17 @@ class CallData<ChannelFilter, FilterEndpoint::kClient> : public BaseCallData {
grpc_schedule_on_exec_ctx);
}
~CallData() {
~CallData() override {
GPR_ASSERT(!is_polling_);
GRPC_ERROR_UNREF(cancelled_error_);
}
// Activity implementation.
void ForceImmediateRepoll() final {
GPR_ASSERT(is_polling_);
repoll_ = true;
}
// Handle one grpc_transport_stream_op_batch
void StartBatch(grpc_transport_stream_op_batch* batch) {
// Fake out the activity based context.
@ -235,9 +267,23 @@ class CallData<ChannelFilter, FilterEndpoint::kClient> : public BaseCallData {
if (recv_trailing_state_ == RecvTrailingState::kQueued) {
recv_trailing_state_ = RecvTrailingState::kCancelled;
}
grpc_transport_stream_op_batch_finish_with_failure(
absl::exchange(send_initial_metadata_batch_, nullptr),
GRPC_ERROR_REF(cancelled_error_), call_combiner());
struct FailBatch : public grpc_closure {
grpc_transport_stream_op_batch* batch;
CallCombiner* call_combiner;
};
auto fail = [](void* p, grpc_error_handle error) {
auto* f = static_cast<FailBatch*>(p);
grpc_transport_stream_op_batch_finish_with_failure(
f->batch, GRPC_ERROR_REF(error), f->call_combiner);
delete f;
};
auto* b = new FailBatch();
GRPC_CLOSURE_INIT(b, fail, b, nullptr);
b->batch = absl::exchange(send_initial_metadata_batch_, nullptr);
b->call_combiner = call_combiner();
GRPC_CALL_COMBINER_START(call_combiner(), b,
GRPC_ERROR_REF(cancelled_error_),
"cancel pending batch");
} else {
send_initial_state_ = SendInitialState::kCancelled;
}
@ -250,12 +296,15 @@ class CallData<ChannelFilter, FilterEndpoint::kClient> : public BaseCallData {
ChannelFilter* filter = static_cast<ChannelFilter*>(elem()->channel_data);
// Construct the promise.
promise_ = filter->MakeCallPromise(
WrapMetadata(send_initial_metadata_batch_->payload
->send_initial_metadata.send_initial_metadata),
[this](ClientInitialMetadata initial_metadata) {
return MakeNextPromise(std::move(initial_metadata));
});
{
ScopedActivity activity(this);
promise_ = filter->MakeCallPromise(
WrapMetadata(send_initial_metadata_batch_->payload
->send_initial_metadata.send_initial_metadata),
[this](ClientInitialMetadata initial_metadata) {
return MakeNextPromise(std::move(initial_metadata));
});
}
// Poll once.
WakeInsideCombiner();
}
@ -366,24 +415,75 @@ class CallData<ChannelFilter, FilterEndpoint::kClient> : public BaseCallData {
GPR_ASSERT(!is_polling_);
grpc_closure* call_closure = nullptr;
is_polling_ = true;
grpc_error_handle cancel_send_initial_metadata_error = GRPC_ERROR_NONE;
grpc_transport_stream_op_batch* forward_batch = nullptr;
switch (send_initial_state_) {
case SendInitialState::kQueued:
case SendInitialState::kForwarded: {
// Poll the promise once since we're waiting for it.
Poll<TrailingMetadata> poll = promise_();
Poll<TrailingMetadata> poll;
{
ScopedActivity activity(this);
poll = promise_();
}
if (auto* r = absl::get_if<TrailingMetadata>(&poll)) {
GPR_ASSERT(recv_trailing_state_ == RecvTrailingState::kComplete);
GPR_ASSERT(recv_trailing_metadata_ == UnwrapMetadata(std::move(*r)));
recv_trailing_state_ = RecvTrailingState::kResponded;
call_closure =
absl::exchange(original_recv_trailing_metadata_ready_, nullptr);
promise_ = ArenaPromise<TrailingMetadata>();
auto* md = UnwrapMetadata(std::move(*r));
bool destroy_md = true;
switch (recv_trailing_state_) {
case RecvTrailingState::kComplete:
if (recv_trailing_metadata_ != md) {
*recv_trailing_metadata_ = std::move(*md);
} else {
destroy_md = false;
}
recv_trailing_state_ = RecvTrailingState::kResponded;
call_closure = absl::exchange(
original_recv_trailing_metadata_ready_, nullptr);
break;
case RecvTrailingState::kQueued:
case RecvTrailingState::kForwarded: {
GPR_ASSERT(*md->get_pointer(GrpcStatusMetadata()) !=
GRPC_STATUS_OK);
grpc_error_handle error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"early return from promise based filter"),
GRPC_ERROR_INT_GRPC_STATUS,
*md->get_pointer(GrpcStatusMetadata()));
if (auto* message = md->get_pointer(GrpcMessageMetadata())) {
error = grpc_error_set_str(error, GRPC_ERROR_STR_GRPC_MESSAGE,
message->as_string_view());
}
if (recv_trailing_state_ == RecvTrailingState::kQueued) {
GPR_ASSERT(send_initial_state_ == SendInitialState::kQueued);
send_initial_state_ = SendInitialState::kCancelled;
cancel_send_initial_metadata_error = error;
} else {
call_combiner()->Cancel(GRPC_ERROR_REF(error));
forward_batch =
grpc_make_transport_stream_op(GRPC_CLOSURE_CREATE(
[](void*, grpc_error_handle) {}, nullptr, nullptr));
forward_batch->cancel_stream = true;
forward_batch->payload->cancel_stream.cancel_error = error;
}
recv_trailing_state_ = RecvTrailingState::kCancelled;
} break;
case RecvTrailingState::kInitial:
abort(); // unimplemented
case RecvTrailingState::kResponded:
case RecvTrailingState::kCancelled:
abort(); // unreachable
}
if (destroy_md) {
md->~grpc_metadata_batch();
}
}
} break;
case SendInitialState::kInitial:
case SendInitialState::kCancelled:
// If we get a response without sending anything, we just propagate that
// up. (note: that situation isn't possible once we finish the promise
// transition).
// If we get a response without sending anything, we just propagate
// that up. (note: that situation isn't possible once we finish the
// promise transition).
if (recv_trailing_state_ == RecvTrailingState::kComplete) {
recv_trailing_state_ = RecvTrailingState::kResponded;
call_closure =
@ -391,14 +491,64 @@ class CallData<ChannelFilter, FilterEndpoint::kClient> : public BaseCallData {
}
break;
}
GRPC_CALL_STACK_REF(call_stack(), "finish_poll");
is_polling_ = false;
bool in_combiner = true;
bool repoll = absl::exchange(repoll_, false);
if (forward_batch != nullptr) {
GPR_ASSERT(in_combiner);
in_combiner = false;
forward_send_initial_metadata_ = false;
grpc_call_next_op(elem(), forward_batch);
}
if (cancel_send_initial_metadata_error != GRPC_ERROR_NONE) {
GPR_ASSERT(in_combiner);
forward_send_initial_metadata_ = false;
in_combiner = false;
grpc_transport_stream_op_batch_finish_with_failure(
absl::exchange(send_initial_metadata_batch_, nullptr),
cancel_send_initial_metadata_error, call_combiner());
}
if (absl::exchange(forward_send_initial_metadata_, false)) {
GPR_ASSERT(in_combiner);
in_combiner = false;
grpc_call_next_op(elem(),
absl::exchange(send_initial_metadata_batch_, nullptr));
}
if (call_closure != nullptr) {
GPR_ASSERT(in_combiner);
in_combiner = false;
Closure::Run(DEBUG_LOCATION, call_closure, GRPC_ERROR_NONE);
}
if (repoll) {
if (in_combiner) {
WakeInsideCombiner();
} else {
struct NextPoll : public grpc_closure {
grpc_call_stack* call_stack;
CallData* call_data;
};
auto run = [](void* p, grpc_error_handle) {
auto* next_poll = static_cast<NextPoll*>(p);
next_poll->call_data->WakeInsideCombiner();
GRPC_CALL_STACK_UNREF(next_poll->call_stack, "re-poll");
delete next_poll;
};
auto* p = new NextPoll;
GRPC_CALL_STACK_REF(call_stack(), "re-poll");
GRPC_CLOSURE_INIT(p, run, p, nullptr);
GRPC_CALL_COMBINER_START(call_combiner(), p, GRPC_ERROR_NONE,
"re-poll");
}
} else if (in_combiner) {
GRPC_CALL_COMBINER_STOP(call_combiner(), "poll paused");
}
GRPC_CALL_STACK_UNREF(call_stack(), "finish_poll");
}
void OnWakeup() override {
ScopedContext context(this);
WakeInsideCombiner();
}
// Contained promise
@ -419,6 +569,8 @@ class CallData<ChannelFilter, FilterEndpoint::kClient> : public BaseCallData {
RecvTrailingState recv_trailing_state_ = RecvTrailingState::kInitial;
// Whether we're currently polling the promise.
bool is_polling_ = false;
// Should we repoll after completing polling?
bool repoll_ = false;
// Whether we should forward send initial metadata after polling?
bool forward_send_initial_metadata_ = false;
};
@ -434,18 +586,21 @@ class CallData<ChannelFilter, FilterEndpoint::kServer> : public BaseCallData {
grpc_schedule_on_exec_ctx);
}
~CallData() {
~CallData() override {
GPR_ASSERT(!is_polling_);
GRPC_ERROR_UNREF(cancelled_error_);
}
// Activity implementation.
void ForceImmediateRepoll() final { abort(); } // Not implemented.
// Handle one grpc_transport_stream_op_batch
void StartBatch(grpc_transport_stream_op_batch* batch) {
// Fake out the activity based context.
ScopedContext context(this);
// If this is a cancel stream, cancel anything we have pending and propagate
// the cancellation.
// If this is a cancel stream, cancel anything we have pending and
// propagate the cancellation.
if (batch->cancel_stream) {
GPR_ASSERT(!batch->send_initial_metadata &&
!batch->send_trailing_metadata && !batch->send_message &&
@ -535,9 +690,23 @@ class CallData<ChannelFilter, FilterEndpoint::kServer> : public BaseCallData {
promise_ = ArenaPromise<TrailingMetadata>();
if (send_trailing_state_ == SendTrailingState::kQueued) {
send_trailing_state_ = SendTrailingState::kCancelled;
grpc_transport_stream_op_batch_finish_with_failure(
absl::exchange(send_trailing_metadata_batch_, nullptr),
GRPC_ERROR_REF(cancelled_error_), call_combiner());
struct FailBatch : public grpc_closure {
grpc_transport_stream_op_batch* batch;
CallCombiner* call_combiner;
};
auto fail = [](void* p, grpc_error_handle error) {
auto* f = static_cast<FailBatch*>(p);
grpc_transport_stream_op_batch_finish_with_failure(
f->batch, GRPC_ERROR_REF(error), f->call_combiner);
delete f;
};
auto* b = new FailBatch();
GRPC_CLOSURE_INIT(b, fail, b, nullptr);
b->batch = absl::exchange(send_trailing_metadata_batch_, nullptr);
b->call_combiner = call_combiner();
GRPC_CALL_COMBINER_START(call_combiner(), b,
GRPC_ERROR_REF(cancelled_error_),
"cancel pending batch");
} else {
send_trailing_state_ = SendTrailingState::kCancelled;
}
@ -623,7 +792,11 @@ class CallData<ChannelFilter, FilterEndpoint::kServer> : public BaseCallData {
bool forward_send_trailing_metadata = false;
is_polling_ = true;
if (recv_initial_state_ == RecvInitialState::kComplete) {
Poll<TrailingMetadata> poll = promise_();
Poll<TrailingMetadata> poll;
{
ScopedActivity activity(this);
poll = promise_();
}
if (auto* r = absl::get_if<TrailingMetadata>(&poll)) {
auto* md = UnwrapMetadata(std::move(*r));
bool destroy_md = true;
@ -672,6 +845,8 @@ class CallData<ChannelFilter, FilterEndpoint::kServer> : public BaseCallData {
}
}
void OnWakeup() override { abort(); } // not implemented
// Contained promise
ArenaPromise<TrailingMetadata> promise_;
// Pointer to where initial metadata will be stored.
@ -736,7 +911,9 @@ MakePromiseBasedFilter(const char* name) {
return GRPC_ERROR_NONE;
},
// set_pollset_or_pollset_set
grpc_call_stack_ignore_set_pollset_or_pollset_set,
[](grpc_call_element* elem, grpc_polling_entity* pollent) {
static_cast<CallData*>(elem->call_data)->set_pollent(pollent);
},
// destroy_call_elem
[](grpc_call_element* elem, const grpc_call_final_info*, grpc_closure*) {
static_cast<CallData*>(elem->call_data)->~CallData();

@ -32,6 +32,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/security_connector/ssl_utils.h"
#include "src/core/lib/security/transport/security_handshaker.h"
@ -116,17 +117,9 @@ class grpc_httpcli_ssl_channel_security_connector final
return strcmp(secure_peer_name_, other->secure_peer_name_);
}
bool check_call_host(absl::string_view /*host*/,
grpc_auth_context* /*auth_context*/,
grpc_closure* /*on_call_host_checked*/,
grpc_error_handle* error) override {
*error = GRPC_ERROR_NONE;
return true;
}
void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
grpc_error_handle error) override {
GRPC_ERROR_UNREF(error);
ArenaPromise<absl::Status> CheckCallHost(absl::string_view,
grpc_auth_context*) override {
return ImmediateOkStatus();
}
const char* secure_peer_name() const { return secure_peer_name_; }

@ -23,6 +23,7 @@
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/promise/context.h"
typedef enum grpc_pollset_tag {
GRPC_POLLS_NONE,
@ -65,4 +66,9 @@ void grpc_polling_entity_add_to_pollset_set(grpc_polling_entity* pollent,
void grpc_polling_entity_del_from_pollset_set(grpc_polling_entity* pollent,
grpc_pollset_set* pss_dst);
namespace grpc_core {
template <>
struct ContextType<grpc_polling_entity> {};
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_IOMGR_POLLING_ENTITY_H */

@ -28,14 +28,16 @@ namespace grpc_core {
GPR_THREAD_LOCAL(Activity*) Activity::g_current_activity_{nullptr};
Waker::Unwakeable Waker::unwakeable_;
namespace promise_detail {
///////////////////////////////////////////////////////////////////////////////
// HELPER TYPES
// Weak handle to an Activity.
// Handle can persist while Activity goes away.
class Activity::Handle final : public Wakeable {
class FreestandingActivity::Handle final : public Wakeable {
public:
explicit Handle(Activity* activity) : activity_(activity) {}
explicit Handle(FreestandingActivity* activity) : activity_(activity) {}
// Ref the Handle (not the activity).
void Ref() { refs_.fetch_add(1, std::memory_order_relaxed); }
@ -57,7 +59,7 @@ class Activity::Handle final : public Wakeable {
// against DropActivity, so we need to only increase activities refcount if
// it is non-zero.
if (activity_ && activity_->RefIfNonzero()) {
Activity* activity = activity_;
FreestandingActivity* activity = activity_;
mu_.Unlock();
// Activity still exists and we have a reference: wake it up, which will
// drop the ref.
@ -85,15 +87,15 @@ class Activity::Handle final : public Wakeable {
// activity.
std::atomic<size_t> refs_{2};
Mutex mu_ ABSL_ACQUIRED_AFTER(activity_->mu_);
Activity* activity_ ABSL_GUARDED_BY(mu_);
FreestandingActivity* activity_ ABSL_GUARDED_BY(mu_);
};
///////////////////////////////////////////////////////////////////////////////
// ACTIVITY IMPLEMENTATION
bool Activity::RefIfNonzero() { return IncrementIfNonzero(&refs_); }
bool FreestandingActivity::RefIfNonzero() { return IncrementIfNonzero(&refs_); }
Activity::Handle* Activity::RefHandle() {
FreestandingActivity::Handle* FreestandingActivity::RefHandle() {
if (handle_ == nullptr) {
// No handle created yet - construct it and return it.
handle_ = new Handle(this);
@ -105,11 +107,15 @@ Activity::Handle* Activity::RefHandle() {
}
}
void Activity::DropHandle() {
void FreestandingActivity::DropHandle() {
handle_->DropActivity();
handle_ = nullptr;
}
Waker Activity::MakeNonOwningWaker() { return Waker(RefHandle()); }
Waker FreestandingActivity::MakeNonOwningWaker() {
mu_.AssertHeld();
return Waker(RefHandle());
}
} // namespace promise_detail
} // namespace grpc_core

@ -37,6 +37,7 @@
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gprpp/construct_destruct.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/promise/context.h"
#include "src/core/lib/promise/detail/promise_factory.h"
@ -110,22 +111,8 @@ class Waker {
// Activity execution may be cancelled by simply deleting the activity. In such
// a case, if execution had not already finished, the done callback would be
// called with absl::CancelledError().
class Activity : private Wakeable {
class Activity : public Orphanable {
public:
// Cancel execution of the underlying promise.
virtual void Cancel() ABSL_LOCKS_EXCLUDED(mu_) = 0;
// Destroy the Activity - used for the type alias ActivityPtr.
struct Deleter {
void operator()(Activity* activity) {
activity->Cancel();
activity->Unref();
}
};
// Fetch the size of the implementation of this activity.
virtual size_t Size() = 0;
// Force wakeup from the outside.
// This should be rarely needed, and usages should be accompanied with a note
// on why it's not possible to wakeup with a Waker object.
@ -133,11 +120,8 @@ class Activity : private Wakeable {
// an Activity to repoll.
void ForceWakeup() { MakeOwningWaker().Wakeup(); }
// Wakeup the current threads activity - will force a subsequent poll after
// the one that's running.
static void WakeupCurrent() {
current()->SetActionDuringRun(ActionDuringRun::kWakeup);
}
// Force the current activity to immediately repoll if it doesn't complete.
virtual void ForceImmediateRepoll() = 0;
// Return the current activity.
// Additionally:
@ -146,58 +130,23 @@ class Activity : private Wakeable {
// locked
// - back up that assertation with a runtime check in debug builds (it's
// prohibitively expensive in non-debug builds)
static Activity* current() ABSL_ASSERT_EXCLUSIVE_LOCK(current()->mu_) {
#ifndef NDEBUG
GPR_ASSERT(g_current_activity_);
if (g_current_activity_ != nullptr) {
g_current_activity_->mu_.AssertHeld();
}
#endif
return g_current_activity_;
}
static Activity* current() { return g_current_activity_; }
// Produce an activity-owning Waker. The produced waker will keep the activity
// alive until it's awoken or dropped.
Waker MakeOwningWaker() {
Ref();
return Waker(this);
}
virtual Waker MakeOwningWaker() = 0;
// Produce a non-owning Waker. The waker will own a small heap allocated weak
// pointer to this activity. This is more suitable for wakeups that may not be
// delivered until long after the activity should be destroyed.
Waker MakeNonOwningWaker() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
virtual Waker MakeNonOwningWaker() = 0;
protected:
// Action received during a run, in priority order.
// If more than one action is received during a run, we use max() to resolve
// which one to report (so Cancel overrides Wakeup).
enum class ActionDuringRun : uint8_t {
kNone, // No action occured during run.
kWakeup, // A wakeup occured during run.
kCancel, // Cancel was called during run.
};
inline virtual ~Activity() {
if (handle_) {
DropHandle();
}
}
// All promise execution occurs under this mutex.
Mutex mu_;
// Check if this activity is the current activity executing on the current
// thread.
bool is_current() const { return this == g_current_activity_; }
// Check if there is an activity executing on the current thread.
static bool have_current() { return g_current_activity_ != nullptr; }
// Check if we got an internal wakeup since the last time this function was
// called.
ActionDuringRun GotActionDuringRun() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
return absl::exchange(action_during_run_, ActionDuringRun::kNone);
}
// Set the current activity at construction, clean it up at destruction.
class ScopedActivity {
public:
@ -210,58 +159,14 @@ class Activity : private Wakeable {
ScopedActivity& operator=(const ScopedActivity&) = delete;
};
// Implementors of Wakeable::Wakeup should call this after the wakeup has
// completed.
void WakeupComplete() { Unref(); }
// Mark the current activity as being cancelled (so we can actually cancel it
// after polling).
void CancelCurrent() {
current()->SetActionDuringRun(ActionDuringRun::kCancel);
}
private:
class Handle;
void Ref() { refs_.fetch_add(1, std::memory_order_relaxed); }
void Unref() {
if (1 == refs_.fetch_sub(1, std::memory_order_acq_rel)) {
delete this;
}
}
// Return a Handle instance with a ref so that it can be stored waiting for
// some wakeup.
Handle* RefHandle() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
// If our refcount is non-zero, ref and return true.
// Otherwise, return false.
bool RefIfNonzero();
// Drop the (proved existing) wait handle.
void DropHandle() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
// Set the action that occured during this run.
// We use max to combine actions so that cancellation overrides wakeups.
void SetActionDuringRun(ActionDuringRun action)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
action_during_run_ = std::max(action_during_run_, action);
}
// Current refcount.
std::atomic<uint32_t> refs_{1};
// If wakeup is called during Promise polling, we set this to Wakeup and
// repoll. If cancel is called during Promise polling, we set this to Cancel
// and cancel at the end of polling.
ActionDuringRun action_during_run_ ABSL_GUARDED_BY(mu_) =
ActionDuringRun::kNone;
// Handle for long waits. Allows a very small weak pointer type object to
// queue for wakeups while Activity may be deleted earlier.
Handle* handle_ ABSL_GUARDED_BY(mu_) = nullptr;
// Set during RunLoop to the Activity that's executing.
// Being set implies that mu_ is held.
static GPR_THREAD_LOCAL(Activity*) g_current_activity_;
};
// Owned pointer to one Activity.
using ActivityPtr = std::unique_ptr<Activity, Activity::Deleter>;
using ActivityPtr = OrphanablePtr<Activity>;
namespace promise_detail {
@ -320,6 +225,107 @@ class ActivityContexts : public ContextHolder<Contexts>... {
};
};
// A free standing activity: an activity that owns its own synchronization and
// memory.
// The alternative is an activity that's somehow tied into another system, for
// instance the type seen in promise_based_filter.h as we're transitioning from
// the old filter stack to the new system.
// FreestandingActivity is-a Wakeable, but needs to increment a refcount before
// returning that Wakeable interface. Additionally, we want to keep
// FreestandingActivity as small as is possible, since it will be used
// everywhere. So we use inheritance to provide the Wakeable interface: this
// makes it zero sized, and we make the inheritance private to prevent
// accidental casting.
class FreestandingActivity : public Activity, private Wakeable {
public:
Waker MakeOwningWaker() final {
Ref();
return Waker(this);
}
Waker MakeNonOwningWaker() final;
void Orphan() final {
Cancel();
Unref();
}
void ForceImmediateRepoll() final {
mu_.AssertHeld();
SetActionDuringRun(ActionDuringRun::kWakeup);
}
protected:
// Action received during a run, in priority order.
// If more than one action is received during a run, we use max() to resolve
// which one to report (so Cancel overrides Wakeup).
enum class ActionDuringRun : uint8_t {
kNone, // No action occured during run.
kWakeup, // A wakeup occured during run.
kCancel, // Cancel was called during run.
};
inline ~FreestandingActivity() override {
if (handle_) {
DropHandle();
}
}
// Check if we got an internal wakeup since the last time this function was
// called.
ActionDuringRun GotActionDuringRun() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
return absl::exchange(action_during_run_, ActionDuringRun::kNone);
}
// Implementors of Wakeable::Wakeup should call this after the wakeup has
// completed.
void WakeupComplete() { Unref(); }
// Set the action that occured during this run.
// We use max to combine actions so that cancellation overrides wakeups.
void SetActionDuringRun(ActionDuringRun action)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
action_during_run_ = std::max(action_during_run_, action);
}
Mutex* mu() ABSL_LOCK_RETURNED(mu_) { return &mu_; }
private:
class Handle;
// Cancel execution of the underlying promise.
virtual void Cancel() = 0;
void Ref() { refs_.fetch_add(1, std::memory_order_relaxed); }
void Unref() {
if (1 == refs_.fetch_sub(1, std::memory_order_acq_rel)) {
delete this;
}
}
// Return a Handle instance with a ref so that it can be stored waiting for
// some wakeup.
Handle* RefHandle() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
// If our refcount is non-zero, ref and return true.
// Otherwise, return false.
bool RefIfNonzero();
// Drop the (proved existing) wait handle.
void DropHandle() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
// All promise execution occurs under this mutex.
Mutex mu_;
// Current refcount.
std::atomic<uint32_t> refs_{1};
// If wakeup is called during Promise polling, we set this to Wakeup and
// repoll. If cancel is called during Promise polling, we set this to Cancel
// and cancel at the end of polling.
ActionDuringRun action_during_run_ ABSL_GUARDED_BY(mu_) =
ActionDuringRun::kNone;
// Handle for long waits. Allows a very small weak pointer type object to
// queue for wakeups while Activity may be deleted earlier.
Handle* handle_ ABSL_GUARDED_BY(mu_) = nullptr;
};
// Implementation details for an Activity of an arbitrary type of promise.
// There should exist a static function:
// struct WakeupScheduler {
@ -331,8 +337,12 @@ class ActivityContexts : public ContextHolder<Contexts>... {
// It can assume that activity will remain live until RunScheduledWakeup() is
// invoked, and that a given activity will not be concurrently scheduled again
// until its RunScheduledWakeup() has been invoked.
// We use private inheritance here as a way of getting private members for
// each of the contexts.
// TODO(ctiller): We can probably reconsider the private inheritance here
// when we move away from C++11 and have more powerful template features.
template <class F, class WakeupScheduler, class OnDone, typename... Contexts>
class PromiseActivity final : public Activity,
class PromiseActivity final : public FreestandingActivity,
private ActivityContexts<Contexts...> {
public:
using Factory = PromiseFactory<void, F>;
@ -340,7 +350,7 @@ class PromiseActivity final : public Activity,
PromiseActivity(F promise_factory, WakeupScheduler wakeup_scheduler,
OnDone on_done, Contexts&&... contexts)
: Activity(),
: FreestandingActivity(),
ActivityContexts<Contexts...>(std::forward<Contexts>(contexts)...),
wakeup_scheduler_(std::move(wakeup_scheduler)),
on_done_(std::move(on_done)) {
@ -348,9 +358,9 @@ class PromiseActivity final : public Activity,
// This may hit a waiter, which could expose our this pointer to other
// threads, meaning we do need to hold this mutex even though we're still
// constructing.
mu_.Lock();
mu()->Lock();
auto status = Start(Factory(std::move(promise_factory)));
mu_.Unlock();
mu()->Unlock();
// We may complete immediately.
if (status.has_value()) {
on_done_(std::move(*status));
@ -364,16 +374,24 @@ class PromiseActivity final : public Activity,
GPR_ASSERT(done_);
}
size_t Size() override { return sizeof(*this); }
void RunScheduledWakeup() {
GPR_ASSERT(wakeup_scheduled_.exchange(false, std::memory_order_acq_rel));
Step();
WakeupComplete();
}
private:
using typename ActivityContexts<Contexts...>::ScopedContext;
void Cancel() final {
if (Activity::is_current()) {
CancelCurrent();
mu()->AssertHeld();
SetActionDuringRun(ActionDuringRun::kCancel);
return;
}
bool was_done;
{
MutexLock lock(&mu_);
MutexLock lock(mu());
// Check if we were done, and flag done.
was_done = done_;
if (!done_) MarkDone();
@ -384,15 +402,6 @@ class PromiseActivity final : public Activity,
}
}
void RunScheduledWakeup() {
GPR_ASSERT(wakeup_scheduled_.exchange(false, std::memory_order_acq_rel));
Step();
WakeupComplete();
}
private:
using typename ActivityContexts<Contexts...>::ScopedContext;
// Wakeup this activity. Arrange to poll the activity again at a convenient
// time: this could be inline if it's deemed safe, or it could be by passing
// the activity to an external threadpool to run. If the activity is already
@ -402,7 +411,8 @@ class PromiseActivity final : public Activity,
// If there is an active activity, but hey it's us, flag that and we'll loop
// in RunLoop (that's calling from above here!).
if (Activity::is_current()) {
WakeupCurrent();
mu()->AssertHeld();
SetActionDuringRun(ActionDuringRun::kWakeup);
WakeupComplete();
return;
}
@ -420,7 +430,7 @@ class PromiseActivity final : public Activity,
// Notification that we're no longer executing - it's ok to destruct the
// promise.
void MarkDone() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
void MarkDone() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu()) {
GPR_ASSERT(!done_);
done_ = true;
Destruct(&promise_holder_.promise);
@ -428,16 +438,16 @@ class PromiseActivity final : public Activity,
// In response to Wakeup, run the Promise state machine again until it
// settles. Then check for completion, and if we have completed, call on_done.
void Step() ABSL_LOCKS_EXCLUDED(mu_) {
void Step() ABSL_LOCKS_EXCLUDED(mu()) {
// Poll the promise until things settle out under a lock.
mu_.Lock();
mu()->Lock();
if (done_) {
// We might get some spurious wakeups after finishing.
mu_.Unlock();
mu()->Unlock();
return;
}
auto status = RunStep();
mu_.Unlock();
mu()->Unlock();
if (status.has_value()) {
on_done_(std::move(*status));
}
@ -446,7 +456,7 @@ class PromiseActivity final : public Activity,
// The main body of a step: set the current activity, and any contexts, and
// then run the main polling loop. Contained in a function by itself in
// order to keep the scoping rules a little easier in Step().
absl::optional<ResultType> RunStep() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
absl::optional<ResultType> RunStep() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu()) {
ScopedActivity scoped_activity(this);
ScopedContext contexts(this);
return StepLoop();
@ -456,7 +466,7 @@ class PromiseActivity final : public Activity,
// promise factory before entering the main loop. Called once from the
// constructor.
absl::optional<ResultType> Start(Factory promise_factory)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu()) {
ScopedActivity scoped_activity(this);
ScopedContext contexts(this);
Construct(&promise_holder_.promise, promise_factory.Once());
@ -465,7 +475,7 @@ class PromiseActivity final : public Activity,
// Until there are no wakeups from within and the promise is incomplete:
// poll the promise.
absl::optional<ResultType> StepLoop() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
absl::optional<ResultType> StepLoop() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu()) {
GPR_ASSERT(is_current());
while (true) {
// Run the promise.
@ -495,7 +505,7 @@ class PromiseActivity final : public Activity,
// Callback on completion of the promise.
GPR_NO_UNIQUE_ADDRESS OnDone on_done_;
// Has execution completed?
GPR_NO_UNIQUE_ADDRESS bool done_ ABSL_GUARDED_BY(mu_) = false;
GPR_NO_UNIQUE_ADDRESS bool done_ ABSL_GUARDED_BY(mu()) = false;
// Is there a wakeup scheduled?
GPR_NO_UNIQUE_ADDRESS std::atomic<bool> wakeup_scheduled_{false};
// We wrap the promise in a union to allow control over the construction
@ -506,7 +516,7 @@ class PromiseActivity final : public Activity,
~PromiseHolder() {}
GPR_NO_UNIQUE_ADDRESS Promise promise;
};
GPR_NO_UNIQUE_ADDRESS PromiseHolder promise_holder_ ABSL_GUARDED_BY(mu_);
GPR_NO_UNIQUE_ADDRESS PromiseHolder promise_holder_ ABSL_GUARDED_BY(mu());
};
} // namespace promise_detail

@ -69,7 +69,7 @@ class CallableImpl final : public ImplInterface<T> {
public:
explicit CallableImpl(Callable&& callable) : callable_(std::move(callable)) {}
// Forward polls to the callable object.
Poll<T> PollOnce() override { return callable_(); }
Poll<T> PollOnce() override { return poll_cast<T>(callable_()); }
// Destroy destructs the callable object.
void Destroy() override { this->~CallableImpl(); }
@ -152,7 +152,8 @@ class ArenaPromise {
template <typename Callable,
typename Ignored =
absl::enable_if_t<!std::is_same<Callable, ArenaPromise>::value>>
explicit ArenaPromise(Callable&& callable)
// NOLINTNEXTLINE(google-explicit-constructor)
ArenaPromise(Callable&& callable)
: impl_(arena_promise_detail::MakeImplForCallable<T>(
std::forward<Callable>(callable))) {}
@ -164,6 +165,7 @@ class ArenaPromise {
other.impl_ = arena_promise_detail::NullImpl<T>::Get();
}
ArenaPromise& operator=(ArenaPromise&& other) noexcept {
impl_->Destroy();
impl_ = other.impl_;
other.impl_ = arena_promise_detail::NullImpl<T>::Get();
return *this;

@ -401,6 +401,95 @@ class BasicSeq {
}
};
// As above, but models a sequence of unknown size
// At each element, the accumulator A and the current value V is passed to some
// function of type F as f(V, A); f is expected to return a promise that
// resolves to Traits::WrappedType.
template <template <typename Wrapped> class Traits, typename F, typename Arg,
typename Iter>
class BasicSeqIter {
private:
using IterValue = decltype(*std::declval<Iter>());
using StateCreated = decltype(std::declval<F>()(std::declval<IterValue>(),
std::declval<Arg>()));
using State = PromiseLike<StateCreated>;
using Wrapped = typename State::Result;
public:
BasicSeqIter(Iter begin, Iter end, F f, Arg arg)
: cur_(begin), end_(end), f_(std::move(f)) {
if (cur_ == end_) {
Construct(&result_, std::move(arg));
} else {
Construct(&state_, f_(*cur_, std::move(arg)));
}
}
~BasicSeqIter() {
if (cur_ == end_) {
Destruct(&result_);
} else {
Destruct(&state_);
}
}
BasicSeqIter(const BasicSeqIter& other) = delete;
BasicSeqIter& operator=(const BasicSeqIter&) = delete;
BasicSeqIter(BasicSeqIter&& other) noexcept
: cur_(other.cur_), end_(other.end_), f_(std::move(other.f_)) {
if (cur_ == end_) {
Construct(&result_, std::move(other.result_));
} else {
Construct(&state_, std::move(other.state_));
}
}
BasicSeqIter& operator=(BasicSeqIter&& other) noexcept {
cur_ = other.cur_;
end_ = other.end_;
if (cur_ == end_) {
Construct(&result_, std::move(other.result_));
} else {
Construct(&state_, std::move(other.state_));
}
return *this;
}
Poll<Wrapped> operator()() {
if (cur_ == end_) {
return std::move(result_);
}
return PollNonEmpty();
}
private:
Poll<Wrapped> PollNonEmpty() {
Poll<Wrapped> r = state_();
if (absl::holds_alternative<Pending>(r)) return r;
return Traits<Wrapped>::template CheckResultAndRunNext<Wrapped>(
std::move(absl::get<Wrapped>(r)), [this](Wrapped arg) -> Poll<Wrapped> {
auto next = cur_;
++next;
if (next == end_) {
return std::move(arg);
}
cur_ = next;
state_.~State();
Construct(&state_,
Traits<Wrapped>::CallSeqFactory(f_, *cur_, std::move(arg)));
return PollNonEmpty();
});
}
Iter cur_;
const Iter end_;
GPR_NO_UNIQUE_ADDRESS F f_;
union {
GPR_NO_UNIQUE_ADDRESS State state_;
GPR_NO_UNIQUE_ADDRESS Arg result_;
};
};
} // namespace promise_detail
} // namespace grpc_core

@ -88,7 +88,7 @@ class Curried {
: f_(std::forward<F>(f)), arg_(std::forward<Arg>(arg)) {}
Curried(const F& f, Arg&& arg) : f_(f), arg_(std::forward<Arg>(arg)) {}
using Result = decltype(std::declval<F>()(std::declval<Arg>()));
Result operator()() { return f_(arg_); }
Result operator()() { return f_(std::move(arg_)); }
private:
GPR_NO_UNIQUE_ADDRESS F f_;

@ -36,7 +36,7 @@ class IntraActivityWaiter {
void Wake() {
if (waiting_) {
waiting_ = false;
Activity::WakeupCurrent();
Activity::current()->ForceImmediateRepoll();
}
}

@ -37,6 +37,12 @@ struct Pending {
template <typename T>
using Poll = absl::variant<Pending, T>;
template <typename T, typename U>
Poll<T> poll_cast(Poll<U> poll) {
if (absl::holds_alternative<Pending>(poll)) return Pending{};
return std::move(absl::get<U>(poll));
}
// Variant of Poll that serves as a ready value
static constexpr size_t kPollReadyIdx = 1;

@ -20,6 +20,7 @@
#include <functional>
#include <type_traits>
#include "absl/status/status.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
@ -64,7 +65,6 @@ class Immediate {
private:
T value_;
};
} // namespace promise_detail
// Return \a value immediately
@ -73,6 +73,11 @@ promise_detail::Immediate<T> Immediate(T value) {
return promise_detail::Immediate<T>(std::move(value));
}
// Return status Ok immediately
struct ImmediateOkStatus {
Poll<absl::Status> operator()() { return absl::OkStatus(); }
};
// Typecheck that a promise returns the expected return type.
// usage: auto promise = WithResult<int>([]() { return 3; });
// NOTE: there are tests in promise_test.cc that are commented out because they

@ -37,7 +37,11 @@ struct SeqTraits {
-> decltype(next->Once(std::forward<T>(value))) {
return next->Once(std::forward<T>(value));
}
template <typename F, typename Elem>
static auto CallSeqFactory(F& f, Elem&& elem, T&& value)
-> decltype(f(std::forward<Elem>(elem), std::forward<T>(value))) {
return f(std::forward<Elem>(elem), std::forward<T>(value));
}
template <typename Result, typename PriorResult, typename RunNext>
static Poll<Result> CheckResultAndRunNext(PriorResult prior,
RunNext run_next) {
@ -66,6 +70,20 @@ F Seq(F functor) {
return functor;
}
// Execute a sequence of operations of unknown length.
// Asynchronously:
// for (element in (begin, end)) {
// argument = wait_for factory(element, argument);
// }
// return argument;
template <typename Iter, typename Factory, typename Argument>
promise_detail::BasicSeqIter<promise_detail::SeqTraits, Factory, Argument, Iter>
SeqIter(Iter begin, Iter end, Argument argument, Factory factory) {
return promise_detail::BasicSeqIter<promise_detail::SeqTraits, Factory,
Argument, Iter>(
begin, end, std::move(factory), std::move(argument));
}
} // namespace grpc_core
#endif // GRPC_CORE_LIB_PROMISE_SEQ_H

@ -41,6 +41,11 @@ struct TrySeqTraitsWithSfinae {
-> decltype(next->Once(std::forward<T>(value))) {
return next->Once(std::forward<T>(value));
}
template <typename F, typename Elem>
static auto CallSeqFactory(F& f, Elem&& elem, T&& value)
-> decltype(f(std::forward<Elem>(elem), std::forward<T>(value))) {
return f(std::forward<Elem>(elem), std::forward<T>(value));
}
template <typename Result, typename RunNext>
static Poll<Result> CheckResultAndRunNext(T prior, RunNext run_next) {
return run_next(std::move(prior));
@ -56,6 +61,11 @@ struct TrySeqTraitsWithSfinae<absl::StatusOr<T>> {
-> decltype(next->Once(std::move(*status))) {
return next->Once(std::move(*status));
}
template <typename F, typename Elem>
static auto CallSeqFactory(F& f, Elem&& elem, absl::StatusOr<T> value)
-> decltype(f(std::forward<Elem>(elem), std::move(*value))) {
return f(std::forward<Elem>(elem), std::move(*value));
}
template <typename Result, typename RunNext>
static Poll<Result> CheckResultAndRunNext(absl::StatusOr<T> prior,
RunNext run_next) {
@ -109,6 +119,23 @@ promise_detail::TrySeq<Functors...> TrySeq(Functors... functors) {
return promise_detail::TrySeq<Functors...>(std::move(functors)...);
}
// Try a sequence of operations of unknown length.
// Asynchronously:
// for (element in (begin, end)) {
// auto r = wait_for factory(element, argument);
// if (!r.ok()) return r;
// argument = *r;
// }
// return argument;
template <typename Iter, typename Factory, typename Argument>
promise_detail::BasicSeqIter<promise_detail::TrySeqTraits, Factory, Argument,
Iter>
TrySeqIter(Iter begin, Iter end, Argument argument, Factory factory) {
return promise_detail::BasicSeqIter<promise_detail::TrySeqTraits, Factory,
Argument, Iter>(
begin, end, std::move(factory), std::move(argument));
}
} // namespace grpc_core
#endif // GRPC_CORE_LIB_PROMISE_TRY_SEQ_H

@ -135,7 +135,7 @@ Poll<RefCountedPtr<ReclaimerQueue::Handle>> ReclaimerQueue::PollNext() {
if (!empty) {
// If we don't, but the queue is probably not empty, schedule an immediate
// repoll.
Activity::WakeupCurrent();
Activity::current()->ForceImmediateRepoll();
} else {
// Otherwise, schedule a wakeup for whenever something is pushed.
state_->waker = Activity::current()->MakeNonOwningWaker();

@ -0,0 +1,87 @@
//
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/credentials/call_creds_util.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
namespace grpc_core {
namespace {
struct ServiceUrlAndMethod {
std::string service_url;
absl::string_view method_name;
};
ServiceUrlAndMethod MakeServiceUrlAndMethod(
const ClientInitialMetadata& initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs* args) {
auto service =
initial_metadata->get_pointer(HttpPathMetadata())->as_string_view();
auto last_slash = service.find_last_of('/');
absl::string_view method_name;
if (last_slash == absl::string_view::npos) {
gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
service = "";
method_name = "";
} else if (last_slash == 0) {
method_name = "";
} else {
method_name = service.substr(last_slash + 1);
service = service.substr(0, last_slash);
}
auto host_and_port =
initial_metadata->get_pointer(HttpAuthorityMetadata())->as_string_view();
absl::string_view url_scheme = args->security_connector->url_scheme();
if (url_scheme == GRPC_SSL_URL_SCHEME) {
// Remove the port if it is 443.
auto port_delimiter = host_and_port.find_last_of(':');
if (port_delimiter != absl::string_view::npos &&
host_and_port.substr(port_delimiter + 1) == "443") {
host_and_port = host_and_port.substr(0, port_delimiter);
}
}
return ServiceUrlAndMethod{
absl::StrCat(url_scheme, "://", host_and_port, service), method_name};
}
} // namespace
std::string MakeJwtServiceUrl(
const ClientInitialMetadata& initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs* args) {
return MakeServiceUrlAndMethod(initial_metadata, args).service_url;
}
grpc_auth_metadata_context MakePluginAuthMetadataContext(
const ClientInitialMetadata& initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs* args) {
auto fields = MakeServiceUrlAndMethod(initial_metadata, args);
grpc_auth_metadata_context ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.channel_auth_context = args->auth_context != nullptr
? args->auth_context->Ref().release()
: nullptr;
ctx.service_url = gpr_strdup(fields.service_url.c_str());
ctx.method_name = gpr_strdup(std::string(fields.method_name).c_str());
return ctx;
}
} // namespace grpc_core

@ -0,0 +1,42 @@
//
// Copyright 2022 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_CALL_CREDS_UTIL_H
#define GRPC_CORE_LIB_SECURITY_CREDENTIALS_CALL_CREDS_UTIL_H
#include <grpc/support/port_platform.h>
#include <string>
#include <grpc/grpc_security.h>
#include "src/core/lib/security/credentials/credentials.h"
namespace grpc_core {
// Helper function to construct service URL for jwt call creds.
std::string MakeJwtServiceUrl(
const ClientInitialMetadata& initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs* args);
// Helper function to construct context for plugin call creds.
grpc_auth_metadata_context MakePluginAuthMetadataContext(
const ClientInitialMetadata& initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs* args);
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_CALL_CREDS_UTIL_H */

@ -33,7 +33,9 @@
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/transport/transport.h"
namespace grpc_core {
const char kCredentialsTypeComposite[] = "composite";
@ -41,87 +43,17 @@ const char kCredentialsTypeComposite[] = "composite";
/* -- Composite call credentials. -- */
static void composite_call_metadata_cb(void* arg, grpc_error_handle error);
namespace {
struct grpc_composite_call_credentials_metadata_context {
grpc_composite_call_credentials_metadata_context(
grpc_composite_call_credentials* composite_creds,
grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata)
: composite_creds(composite_creds),
pollent(pollent),
auth_md_context(auth_md_context),
md_array(md_array),
on_request_metadata(on_request_metadata) {
GRPC_CLOSURE_INIT(&internal_on_request_metadata, composite_call_metadata_cb,
this, grpc_schedule_on_exec_ctx);
}
grpc_composite_call_credentials* composite_creds;
size_t creds_index = 0;
grpc_polling_entity* pollent;
grpc_auth_metadata_context auth_md_context;
grpc_core::CredentialsMetadataArray* md_array;
grpc_closure* on_request_metadata;
grpc_closure internal_on_request_metadata;
};
} // namespace
static void composite_call_metadata_cb(void* arg, grpc_error_handle error) {
grpc_composite_call_credentials_metadata_context* ctx =
static_cast<grpc_composite_call_credentials_metadata_context*>(arg);
if (error == GRPC_ERROR_NONE) {
const grpc_composite_call_credentials::CallCredentialsList& inner =
ctx->composite_creds->inner();
/* See if we need to get some more metadata. */
if (ctx->creds_index < inner.size()) {
if (inner[ctx->creds_index++]->get_request_metadata(
ctx->pollent, ctx->auth_md_context, ctx->md_array,
&ctx->internal_on_request_metadata, &error)) {
// Synchronous response, so call ourselves recursively.
composite_call_metadata_cb(arg, error);
GRPC_ERROR_UNREF(error);
}
return;
}
// We're done!
}
grpc_core::ExecCtx::Run(DEBUG_LOCATION, ctx->on_request_metadata,
GRPC_ERROR_REF(error));
delete ctx;
}
bool grpc_composite_call_credentials::get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata, grpc_error_handle* error) {
grpc_composite_call_credentials_metadata_context* ctx;
ctx = new grpc_composite_call_credentials_metadata_context(
this, pollent, auth_md_context, md_array, on_request_metadata);
bool synchronous = true;
const CallCredentialsList& inner = ctx->composite_creds->inner();
while (ctx->creds_index < inner.size()) {
if (inner[ctx->creds_index++]->get_request_metadata(
ctx->pollent, ctx->auth_md_context, ctx->md_array,
&ctx->internal_on_request_metadata, error)) {
if (*error != GRPC_ERROR_NONE) break;
} else {
synchronous = false; // Async return.
break;
}
}
if (synchronous) delete ctx;
return synchronous;
}
void grpc_composite_call_credentials::cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array, grpc_error_handle error) {
for (size_t i = 0; i < inner_.size(); ++i) {
inner_[i]->cancel_get_request_metadata(md_array, GRPC_ERROR_REF(error));
}
GRPC_ERROR_UNREF(error);
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
grpc_composite_call_credentials::GetRequestMetadata(
grpc_core::ClientInitialMetadata initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs* args) {
auto self = Ref();
return TrySeqIter(
inner_.begin(), inner_.end(), std::move(initial_metadata),
[self, args](const grpc_core::RefCountedPtr<grpc_call_credentials>& creds,
grpc_core::ClientInitialMetadata initial_metadata) {
return creds->GetRequestMetadata(std::move(initial_metadata), args);
});
}
std::string grpc_composite_call_credentials::debug_string() {

@ -90,15 +90,9 @@ class grpc_composite_call_credentials : public grpc_call_credentials {
grpc_core::RefCountedPtr<grpc_call_credentials> creds2);
~grpc_composite_call_credentials() override = default;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata,
grpc_error_handle* error) override;
void cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array,
grpc_error_handle error) override;
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
GetRequestMetadata(grpc_core::ClientInitialMetadata initial_metadata,
const GetRequestMetadataArgs* args) override;
grpc_security_level min_security_level() const override {
return min_security_level_;

@ -31,8 +31,11 @@
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/promise/arena_promise.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/security_connector/security_connector.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/lib/transport/transport.h"
struct grpc_http_response;
@ -185,6 +188,16 @@ using CredentialsMetadataArray = std::vector<std::pair<Slice, Slice>>;
struct grpc_call_credentials
: public grpc_core::RefCounted<grpc_call_credentials> {
public:
// TODO(roth): Consider whether security connector actually needs to
// be part of this interface. Currently, it is here only for the
// url_scheme() method, which we might be able to instead add as an
// auth context property.
struct GetRequestMetadataArgs {
grpc_core::RefCountedPtr<grpc_channel_security_connector>
security_connector;
grpc_core::RefCountedPtr<grpc_auth_context> auth_context;
};
explicit grpc_call_credentials(
const char* type,
grpc_security_level min_security_level = GRPC_PRIVACY_AND_INTEGRITY)
@ -192,21 +205,10 @@ struct grpc_call_credentials
~grpc_call_credentials() override = default;
// Returns true if completed synchronously, in which case \a error will
// be set to indicate the result. Otherwise, \a on_request_metadata will
// be invoked asynchronously when complete. \a md_array will be populated
// with the resulting metadata once complete.
virtual bool get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata, grpc_error_handle* error) = 0;
// Cancels a pending asynchronous operation started by
// grpc_call_credentials_get_request_metadata() with the corresponding
// value of \a md_array.
virtual void cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array,
grpc_error_handle error) = 0;
virtual grpc_core::ArenaPromise<
absl::StatusOr<grpc_core::ClientInitialMetadata>>
GetRequestMetadata(grpc_core::ClientInitialMetadata initial_metadata,
const GetRequestMetadataArgs* args) = 0;
virtual grpc_security_level min_security_level() const {
return min_security_level_;
@ -240,7 +242,7 @@ struct grpc_call_credentials
/* Metadata-only credentials with the specified key and value where
asynchronicity can be simulated for testing. */
grpc_call_credentials* grpc_md_only_test_credentials_create(
const char* md_key, const char* md_value, bool is_async);
const char* md_key, const char* md_value);
/* --- grpc_server_credentials. --- */

@ -29,6 +29,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/executor.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/security_connector/fake/fake_security_connector.h"
/* -- Fake transport security credentials. -- */
@ -96,26 +97,17 @@ const char* grpc_fake_transport_get_expected_targets(
/* -- Metadata-only test credentials. -- */
bool grpc_md_only_test_credentials::get_request_metadata(
grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context /*context*/,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata, grpc_error_handle* /*error*/) {
md_array->emplace_back(key_.Ref(), value_.Ref());
if (is_async_) {
grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_request_metadata,
GRPC_ERROR_NONE);
return false;
}
return true;
}
void grpc_md_only_test_credentials::cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* /*md_array*/,
grpc_error_handle error) {
GRPC_ERROR_UNREF(error);
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
grpc_md_only_test_credentials::GetRequestMetadata(
grpc_core::ClientInitialMetadata initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs*) {
initial_metadata->Append(
key_.as_string_view(), value_.Ref(),
[](absl::string_view, const grpc_core::Slice&) { abort(); });
return grpc_core::Immediate(std::move(initial_metadata));
}
grpc_call_credentials* grpc_md_only_test_credentials_create(
const char* md_key, const char* md_value, bool is_async) {
return new grpc_md_only_test_credentials(md_key, md_value, is_async);
const char* md_key, const char* md_value) {
return new grpc_md_only_test_credentials(md_key, md_value);
}

@ -59,23 +59,15 @@ const char* grpc_fake_transport_get_expected_targets(
class grpc_md_only_test_credentials : public grpc_call_credentials {
public:
grpc_md_only_test_credentials(const char* md_key, const char* md_value,
bool is_async)
grpc_md_only_test_credentials(const char* md_key, const char* md_value)
: grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_OAUTH2,
GRPC_SECURITY_NONE),
key_(grpc_core::Slice::FromCopiedString(md_key)),
value_(grpc_core::Slice::FromCopiedString(md_value)),
is_async_(is_async) {}
value_(grpc_core::Slice::FromCopiedString(md_value)) {}
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata,
grpc_error_handle* error) override;
void cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array,
grpc_error_handle error) override;
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
GetRequestMetadata(grpc_core::ClientInitialMetadata initial_metadata,
const GetRequestMetadataArgs* args) override;
std::string debug_string() override { return "MD only Test Credentials"; };
@ -88,7 +80,6 @@ class grpc_md_only_test_credentials : public grpc_call_credentials {
grpc_core::Slice key_;
grpc_core::Slice value_;
bool is_async_;
};
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_FAKE_FAKE_CREDENTIALS_H */

@ -28,27 +28,22 @@
#include <grpc/support/sync.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/surface/api_trace.h"
bool grpc_google_iam_credentials::get_request_metadata(
grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context /*context*/,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* /*on_request_metadata*/, grpc_error_handle* /*error*/) {
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
grpc_google_iam_credentials::GetRequestMetadata(
grpc_core::ClientInitialMetadata initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs*) {
if (token_.has_value()) {
md_array->emplace_back(grpc_core::Slice::FromStaticString(
GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY),
token_->Ref());
initial_metadata->Append(
GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY, token_->Ref(),
[](absl::string_view, const grpc_core::Slice&) { abort(); });
}
md_array->emplace_back(grpc_core::Slice::FromStaticString(
GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY),
authority_selector_.Ref());
return true;
}
void grpc_google_iam_credentials::cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* /*md_array*/,
grpc_error_handle error) {
GRPC_ERROR_UNREF(error);
initial_metadata->Append(
GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY, authority_selector_.Ref(),
[](absl::string_view, const grpc_core::Slice&) { abort(); });
return grpc_core::Immediate(std::move(initial_metadata));
}
grpc_google_iam_credentials::grpc_google_iam_credentials(

@ -30,15 +30,10 @@ class grpc_google_iam_credentials : public grpc_call_credentials {
grpc_google_iam_credentials(const char* token,
const char* authority_selector);
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata,
grpc_error_handle* error) override;
void cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array,
grpc_error_handle error) override;
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
GetRequestMetadata(grpc_core::ClientInitialMetadata initial_metadata,
const GetRequestMetadataArgs* args) override;
std::string debug_string() override { return debug_string_; }
private:

@ -34,6 +34,8 @@
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/credentials/call_creds_util.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/transport/error_utils.h"
@ -47,22 +49,21 @@ grpc_service_account_jwt_access_credentials::
gpr_mu_destroy(&cache_mu_);
}
bool grpc_service_account_jwt_access_credentials::get_request_metadata(
grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* /*on_request_metadata*/, grpc_error_handle* error) {
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
grpc_service_account_jwt_access_credentials::GetRequestMetadata(
grpc_core::ClientInitialMetadata initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs* args) {
gpr_timespec refresh_threshold = gpr_time_from_seconds(
GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS, GPR_TIMESPAN);
// Remove service name from service_url to follow the audience format
// dictated in https://google.aip.dev/auth/4111.
absl::StatusOr<std::string> uri =
grpc_core::RemoveServiceNameFromJwtUri(context.service_url);
absl::StatusOr<std::string> uri = grpc_core::RemoveServiceNameFromJwtUri(
grpc_core::MakeJwtServiceUrl(initial_metadata, args));
if (!uri.ok()) {
*error = absl_status_to_grpc_error(uri.status());
return true;
return grpc_core::Immediate(uri.status());
}
/* See if we can return a cached jwt. */
// See if we can return a cached jwt.
absl::optional<grpc_core::Slice> jwt_value;
{
gpr_mu_lock(&cache_mu_);
@ -77,7 +78,7 @@ bool grpc_service_account_jwt_access_credentials::get_request_metadata(
if (!jwt_value.has_value()) {
char* jwt = nullptr;
/* Generate a new jwt. */
// Generate a new jwt.
gpr_mu_lock(&cache_mu_);
cached_.reset();
jwt = grpc_jwt_encode_and_sign(&key_, uri->c_str(), jwt_lifetime_, nullptr);
@ -91,20 +92,15 @@ bool grpc_service_account_jwt_access_credentials::get_request_metadata(
gpr_mu_unlock(&cache_mu_);
}
if (jwt_value.has_value()) {
md_array->emplace_back(
grpc_core::Slice::FromStaticString(GRPC_AUTHORIZATION_METADATA_KEY),
std::move(*jwt_value));
} else {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Could not generate JWT.");
if (!jwt_value.has_value()) {
return grpc_core::Immediate(
absl::UnauthenticatedError("Could not generate JWT."));
}
return true;
}
void grpc_service_account_jwt_access_credentials::cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* /*md_array*/,
grpc_error_handle error) {
GRPC_ERROR_UNREF(error);
initial_metadata->Append(
GRPC_AUTHORIZATION_METADATA_KEY, std::move(*jwt_value),
[](absl::string_view, const grpc_core::Slice&) { abort(); });
return grpc_core::Immediate(std::move(initial_metadata));
}
grpc_service_account_jwt_access_credentials::

@ -38,15 +38,9 @@ class grpc_service_account_jwt_access_credentials
gpr_timespec token_lifetime);
~grpc_service_account_jwt_access_credentials() override;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata,
grpc_error_handle* error) override;
void cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array,
grpc_error_handle error) override;
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
GetRequestMetadata(grpc_core::ClientInitialMetadata initial_metadata,
const GetRequestMetadataArgs* args) override;
const gpr_timespec& jwt_lifetime() const { return jwt_lifetime_; }
const grpc_auth_json_key& key() const { return key_; }

@ -22,7 +22,10 @@
#include <string.h>
#include <atomic>
#include "absl/container/inlined_vector.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
@ -35,14 +38,18 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/capture.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/http/httpcli_ssl_credentials.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/util/json_util.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/api_trace.h"
#include "src/core/lib/transport/error_utils.h"
#include "src/core/lib/transport/transport.h"
#include "src/core/lib/uri/uri_parser.h"
using grpc_core::Json;
@ -252,34 +259,33 @@ void grpc_oauth2_token_fetcher_credentials::on_http_response(
gpr_mu_unlock(&mu_);
// Invoke callbacks for all pending requests.
while (pending_request != nullptr) {
grpc_error_handle new_error = GRPC_ERROR_NONE;
if (status == GRPC_CREDENTIALS_OK) {
pending_request->md_array->emplace_back(
grpc_core::Slice::FromStaticString(GRPC_AUTHORIZATION_METADATA_KEY),
access_token_value->Ref());
pending_request->md->Append(
GRPC_AUTHORIZATION_METADATA_KEY, access_token_value->Ref(),
[](absl::string_view, const grpc_core::Slice&) { abort(); });
pending_request->result = std::move(pending_request->md);
} else {
new_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
auto err = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
"Error occurred when fetching oauth2 token.", &error, 1);
pending_request->result = grpc_error_to_absl_status(err);
GRPC_ERROR_UNREF(err);
}
grpc_core::ExecCtx::Run(DEBUG_LOCATION,
pending_request->on_request_metadata, new_error);
pending_request->done.store(true, std::memory_order_release);
pending_request->waker.Wakeup();
grpc_polling_entity_del_from_pollset_set(
pending_request->pollent, grpc_polling_entity_pollset_set(&pollent_));
grpc_oauth2_pending_get_request_metadata* prev = pending_request;
pending_request = pending_request->next;
gpr_free(prev);
prev->Unref();
}
Unref();
delete r;
}
bool grpc_oauth2_token_fetcher_credentials::get_request_metadata(
grpc_polling_entity* pollent, grpc_auth_metadata_context /*context*/,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata, grpc_error_handle* /*error*/) {
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
grpc_oauth2_token_fetcher_credentials::GetRequestMetadata(
grpc_core::ClientInitialMetadata initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs*) {
// Check if we can use the cached token.
grpc_core::Duration refresh_threshold =
grpc_core::Duration::Seconds(GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS);
absl::optional<grpc_core::Slice> cached_access_token_value;
gpr_mu_lock(&mu_);
if (access_token_value_.has_value() &&
@ -291,23 +297,24 @@ bool grpc_oauth2_token_fetcher_credentials::get_request_metadata(
}
if (cached_access_token_value.has_value()) {
gpr_mu_unlock(&mu_);
md_array->emplace_back(
grpc_core::Slice::FromStaticString(GRPC_AUTHORIZATION_METADATA_KEY),
std::move(*cached_access_token_value));
return true;
initial_metadata->Append(
GRPC_AUTHORIZATION_METADATA_KEY, std::move(*cached_access_token_value),
[](absl::string_view, const grpc_core::Slice&) { abort(); });
return grpc_core::Immediate(std::move(initial_metadata));
}
// Couldn't get the token from the cache.
// Add request to pending_requests_ and start a new fetch if needed.
grpc_oauth2_pending_get_request_metadata* pending_request =
static_cast<grpc_oauth2_pending_get_request_metadata*>(
gpr_malloc(sizeof(*pending_request)));
pending_request->md_array = md_array;
pending_request->on_request_metadata = on_request_metadata;
pending_request->pollent = pollent;
grpc_core::Duration refresh_threshold =
grpc_core::Duration::Seconds(GRPC_SECURE_TOKEN_REFRESH_THRESHOLD_SECS);
auto pending_request =
grpc_core::MakeRefCounted<grpc_oauth2_pending_get_request_metadata>();
pending_request->pollent = grpc_core::GetContext<grpc_polling_entity>();
pending_request->waker = grpc_core::Activity::current()->MakeNonOwningWaker();
grpc_polling_entity_add_to_pollset_set(
pollent, grpc_polling_entity_pollset_set(&pollent_));
pending_request->pollent, grpc_polling_entity_pollset_set(&pollent_));
pending_request->next = pending_requests_;
pending_requests_ = pending_request;
pending_request->md = std::move(initial_metadata);
pending_requests_ = pending_request->Ref().release();
bool start_fetch = false;
if (!token_fetch_pending_) {
token_fetch_pending_ = true;
@ -315,39 +322,18 @@ bool grpc_oauth2_token_fetcher_credentials::get_request_metadata(
}
gpr_mu_unlock(&mu_);
if (start_fetch) {
Ref().release();
fetch_oauth2(new grpc_credentials_metadata_request(this->Ref()), &pollent_,
fetch_oauth2(new grpc_credentials_metadata_request(Ref()), &pollent_,
on_oauth2_token_fetcher_http_response,
grpc_core::ExecCtx::Get()->Now() + refresh_threshold);
}
return false;
}
void grpc_oauth2_token_fetcher_credentials::cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array, grpc_error_handle error) {
gpr_mu_lock(&mu_);
grpc_oauth2_pending_get_request_metadata* prev = nullptr;
grpc_oauth2_pending_get_request_metadata* pending_request = pending_requests_;
while (pending_request != nullptr) {
if (pending_request->md_array == md_array) {
// Remove matching pending request from the list.
if (prev != nullptr) {
prev->next = pending_request->next;
} else {
pending_requests_ = pending_request->next;
}
// Invoke the callback immediately with an error.
grpc_core::ExecCtx::Run(DEBUG_LOCATION,
pending_request->on_request_metadata,
GRPC_ERROR_REF(error));
gpr_free(pending_request);
break;
}
prev = pending_request;
pending_request = pending_request->next;
}
gpr_mu_unlock(&mu_);
GRPC_ERROR_UNREF(error);
return
[pending_request]()
-> grpc_core::Poll<absl::StatusOr<grpc_core::ClientInitialMetadata>> {
if (!pending_request->done.load(std::memory_order_acquire)) {
return grpc_core::Pending{};
}
return std::move(pending_request->result);
};
}
grpc_oauth2_token_fetcher_credentials::grpc_oauth2_token_fetcher_credentials()
@ -710,20 +696,14 @@ grpc_call_credentials* grpc_sts_credentials_create(
// Oauth2 Access Token credentials.
//
bool grpc_access_token_credentials::get_request_metadata(
grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context /*context*/,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* /*on_request_metadata*/, grpc_error_handle* /*error*/) {
md_array->emplace_back(
grpc_core::Slice::FromStaticString(GRPC_AUTHORIZATION_METADATA_KEY),
access_token_value_.Ref());
return true;
}
void grpc_access_token_credentials::cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* /*md_array*/,
grpc_error_handle error) {
GRPC_ERROR_UNREF(error);
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
grpc_access_token_credentials::GetRequestMetadata(
grpc_core::ClientInitialMetadata initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs*) {
initial_metadata->Append(
GRPC_AUTHORIZATION_METADATA_KEY, access_token_value_.Ref(),
[](absl::string_view, const grpc_core::Slice&) { abort(); });
return grpc_core::Immediate(std::move(initial_metadata));
}
grpc_access_token_credentials::grpc_access_token_credentials(

@ -25,6 +25,7 @@
#include <grpc/grpc_security.h>
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/http/httpcli.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/security/credentials/credentials.h"
@ -73,11 +74,14 @@ struct grpc_credentials_metadata_request {
grpc_http_response response;
};
struct grpc_oauth2_pending_get_request_metadata {
grpc_core::CredentialsMetadataArray* md_array;
grpc_closure* on_request_metadata;
struct grpc_oauth2_pending_get_request_metadata
: public grpc_core::RefCounted<grpc_oauth2_pending_get_request_metadata> {
std::atomic<bool> done{false};
grpc_core::Waker waker;
grpc_polling_entity* pollent;
grpc_core::ClientInitialMetadata md;
struct grpc_oauth2_pending_get_request_metadata* next;
absl::StatusOr<grpc_core::ClientInitialMetadata> result;
};
// -- Oauth2 Token Fetcher credentials --
@ -90,15 +94,9 @@ class grpc_oauth2_token_fetcher_credentials : public grpc_call_credentials {
grpc_oauth2_token_fetcher_credentials();
~grpc_oauth2_token_fetcher_credentials() override;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata,
grpc_error_handle* error) override;
void cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array,
grpc_error_handle error) override;
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
GetRequestMetadata(grpc_core::ClientInitialMetadata initial_metadata,
const GetRequestMetadataArgs* args) override;
void on_http_response(grpc_credentials_metadata_request* r,
grpc_error_handle error);
@ -154,15 +152,9 @@ class grpc_access_token_credentials final : public grpc_call_credentials {
public:
explicit grpc_access_token_credentials(const char* access_token);
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata,
grpc_error_handle* error) override;
void cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array,
grpc_error_handle error) override;
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
GetRequestMetadata(grpc_core::ClientInitialMetadata initial_metadata,
const GetRequestMetadataArgs* args) override;
std::string debug_string() override;

@ -22,6 +22,8 @@
#include <string.h>
#include <atomic>
#include "absl/strings/str_cat.h"
#include <grpc/grpc.h>
@ -30,6 +32,8 @@
#include <grpc/support/sync.h>
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/credentials/plugin/plugin_credentials.h"
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/api_trace.h"
@ -38,7 +42,6 @@
grpc_core::TraceFlag grpc_plugin_credentials_trace(false, "plugin_credentials");
grpc_plugin_credentials::~grpc_plugin_credentials() {
gpr_mu_destroy(&mu_);
if (plugin_.state != nullptr && plugin_.destroy != nullptr) {
plugin_.destroy(plugin_.state);
}
@ -57,38 +60,12 @@ std::string grpc_plugin_credentials::debug_string() {
return debug_str;
}
void grpc_plugin_credentials::pending_request_remove_locked(
pending_request* pending_request) {
if (pending_request->prev == nullptr) {
pending_requests_ = pending_request->next;
} else {
pending_request->prev->next = pending_request->next;
}
if (pending_request->next != nullptr) {
pending_request->next->prev = pending_request->prev;
}
}
// Checks if the request has been cancelled.
// If not, removes it from the pending list, so that it cannot be
// cancelled out from under us.
// When this returns, r->cancelled indicates whether the request was
// cancelled before completion.
void grpc_plugin_credentials::pending_request_complete(pending_request* r) {
GPR_DEBUG_ASSERT(r->creds == this);
gpr_mu_lock(&mu_);
if (!r->cancelled) pending_request_remove_locked(r);
gpr_mu_unlock(&mu_);
// Ref to credentials not needed anymore.
Unref();
}
static grpc_error_handle process_plugin_result(
grpc_plugin_credentials::pending_request* r, const grpc_metadata* md,
size_t num_md, grpc_status_code status, const char* error_details) {
grpc_error_handle error = GRPC_ERROR_NONE;
absl::StatusOr<grpc_core::ClientInitialMetadata>
grpc_plugin_credentials::PendingRequest::ProcessPluginResult(
const grpc_metadata* md, size_t num_md, grpc_status_code status,
const char* error_details) {
if (status != GRPC_STATUS_OK) {
error = GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
return absl::UnavailableError(absl::StrCat(
"Getting metadata from plugin failed with error: ", error_details));
} else {
bool seen_illegal_header = false;
@ -107,154 +84,120 @@ static grpc_error_handle process_plugin_result(
}
}
if (seen_illegal_header) {
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Illegal metadata");
return absl::UnavailableError("Illegal metadata");
} else {
absl::Status error;
for (size_t i = 0; i < num_md; ++i) {
r->md_array->emplace_back(
grpc_core::Slice(grpc_slice_ref_internal(md[i].key)),
grpc_core::Slice(grpc_slice_ref_internal(md[i].value)));
md_->Append(
grpc_core::StringViewFromSlice(md[i].key),
grpc_core::Slice(grpc_slice_ref_internal(md[i].value)),
[&error](absl::string_view message, const grpc_core::Slice&) {
error = absl::UnavailableError(message);
});
}
if (!error.ok()) return std::move(error);
return grpc_core::ClientInitialMetadata(std::move(md_));
}
}
return error;
}
static void plugin_md_request_metadata_ready(void* request,
const grpc_metadata* md,
size_t num_md,
grpc_status_code status,
const char* error_details) {
grpc_core::Poll<absl::StatusOr<grpc_core::ClientInitialMetadata>>
grpc_plugin_credentials::PendingRequest::PollAsyncResult() {
if (!ready_.load(std::memory_order_acquire)) {
return grpc_core::Pending{};
}
return ProcessPluginResult(metadata_.data(), metadata_.size(), status_,
error_details_.c_str());
}
void grpc_plugin_credentials::PendingRequest::RequestMetadataReady(
void* request, const grpc_metadata* md, size_t num_md,
grpc_status_code status, const char* error_details) {
/* called from application code */
grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
grpc_core::ExecCtx exec_ctx(GRPC_EXEC_CTX_FLAG_IS_FINISHED |
GRPC_EXEC_CTX_FLAG_THREAD_RESOURCE_LOOP);
grpc_plugin_credentials::pending_request* r =
static_cast<grpc_plugin_credentials::pending_request*>(request);
grpc_core::RefCountedPtr<grpc_plugin_credentials::PendingRequest> r(
static_cast<grpc_plugin_credentials::PendingRequest*>(request));
if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin returned "
"asynchronously",
r->creds, r);
r->creds(), r.get());
}
// Remove request from pending list if not previously cancelled.
r->creds->pending_request_complete(r);
// If it has not been cancelled, process it.
if (!r->cancelled) {
grpc_error_handle error =
process_plugin_result(r, md, num_md, status, error_details);
grpc_core::ExecCtx::Run(DEBUG_LOCATION, r->on_request_metadata, error);
} else if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin was previously "
"cancelled",
r->creds, r);
for (size_t i = 0; i < num_md; ++i) {
grpc_metadata p;
p.key = grpc_slice_ref_internal(md[i].key);
p.value = grpc_slice_ref_internal(md[i].value);
r->metadata_.push_back(p);
}
gpr_free(r);
r->error_details_ = error_details == nullptr ? "" : error_details;
r->status_ = status;
r->ready_.store(true, std::memory_order_release);
r->waker_.Wakeup();
}
bool grpc_plugin_credentials::get_request_metadata(
grpc_polling_entity* /*pollent*/, grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata, grpc_error_handle* error) {
bool retval = true; // Synchronous return.
if (plugin_.get_metadata != nullptr) {
// Create pending_request object.
pending_request* request = grpc_core::Zalloc<pending_request>();
request->creds = this;
request->md_array = md_array;
request->on_request_metadata = on_request_metadata;
// Add it to the pending list.
gpr_mu_lock(&mu_);
if (pending_requests_ != nullptr) {
pending_requests_->prev = request;
}
request->next = pending_requests_;
pending_requests_ = request;
gpr_mu_unlock(&mu_);
// Invoke the plugin. The callback holds a ref to us.
if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: invoking plugin",
this, request);
}
Ref().release();
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX];
size_t num_creds_md = 0;
grpc_status_code status = GRPC_STATUS_OK;
const char* error_details = nullptr;
if (!plugin_.get_metadata(
plugin_.state, context, plugin_md_request_metadata_ready, request,
creds_md, &num_creds_md, &status, &error_details)) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin will return "
"asynchronously",
this, request);
}
return false; // Asynchronous return.
}
// Returned synchronously.
// Remove request from pending list if not previously cancelled.
request->creds->pending_request_complete(request);
// If the request was cancelled, the error will have been returned
// asynchronously by plugin_cancel_get_request_metadata(), so return
// false. Otherwise, process the result.
if (request->cancelled) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p was cancelled, error "
"will be returned asynchronously",
this, request);
}
retval = false;
} else {
if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin returned "
"synchronously",
this, request);
}
*error = process_plugin_result(request, creds_md, num_creds_md, status,
error_details);
}
// Clean up.
for (size_t i = 0; i < num_creds_md; ++i) {
grpc_slice_unref_internal(creds_md[i].key);
grpc_slice_unref_internal(creds_md[i].value);
}
gpr_free(const_cast<char*>(error_details));
gpr_free(request);
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
grpc_plugin_credentials::GetRequestMetadata(
grpc_core::ClientInitialMetadata initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs* args) {
if (plugin_.get_metadata == nullptr) {
return grpc_core::Immediate(std::move(initial_metadata));
}
return retval;
}
void grpc_plugin_credentials::cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array, grpc_error_handle error) {
gpr_mu_lock(&mu_);
for (pending_request* pending_request = pending_requests_;
pending_request != nullptr; pending_request = pending_request->next) {
if (pending_request->md_array == md_array) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO, "plugin_credentials[%p]: cancelling request %p", this,
pending_request);
}
pending_request->cancelled = true;
grpc_core::ExecCtx::Run(DEBUG_LOCATION,
pending_request->on_request_metadata,
GRPC_ERROR_REF(error));
pending_request_remove_locked(pending_request);
break;
// Create pending_request object.
auto request = grpc_core::MakeRefCounted<PendingRequest>(
Ref(), std::move(initial_metadata), args);
// Invoke the plugin. The callback holds a ref to us.
if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO, "plugin_credentials[%p]: request %p: invoking plugin",
this, request.get());
}
grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX];
size_t num_creds_md = 0;
grpc_status_code status = GRPC_STATUS_OK;
const char* error_details = nullptr;
// Add an extra ref to the request object for the async callback.
// If the request completes synchronously, we'll drop this later.
// If the request completes asynchronously, it will own a ref to the request
// object (which we release from our ownership below).
auto child_request = request->Ref();
if (!plugin_.get_metadata(plugin_.state, request->context(),
PendingRequest::RequestMetadataReady,
child_request.get(), creds_md, &num_creds_md,
&status, &error_details)) {
child_request.release();
if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin will return "
"asynchronously",
this, request.get());
}
return [request] { return request->PollAsyncResult(); };
}
// Synchronous return.
if (GRPC_TRACE_FLAG_ENABLED(grpc_plugin_credentials_trace)) {
gpr_log(GPR_INFO,
"plugin_credentials[%p]: request %p: plugin returned "
"synchronously",
this, request.get());
}
auto result = request->ProcessPluginResult(creds_md, num_creds_md, status,
error_details);
// Clean up.
for (size_t i = 0; i < num_creds_md; ++i) {
grpc_slice_unref_internal(creds_md[i].key);
grpc_slice_unref_internal(creds_md[i].value);
}
gpr_mu_unlock(&mu_);
GRPC_ERROR_UNREF(error);
gpr_free(const_cast<char*>(error_details));
return grpc_core::Immediate(std::move(result));
}
grpc_plugin_credentials::grpc_plugin_credentials(
grpc_metadata_credentials_plugin plugin,
grpc_security_level min_security_level)
: grpc_call_credentials(plugin.type, min_security_level), plugin_(plugin) {
gpr_mu_init(&mu_);
}
: grpc_call_credentials(plugin.type, min_security_level), plugin_(plugin) {}
grpc_call_credentials* grpc_metadata_credentials_create_from_plugin(
grpc_metadata_credentials_plugin plugin,

@ -21,6 +21,7 @@
#include <grpc/support/port_platform.h>
#include "src/core/lib/security/credentials/call_creds_util.h"
#include "src/core/lib/security/credentials/credentials.h"
extern grpc_core::TraceFlag grpc_plugin_credentials_trace;
@ -30,50 +31,69 @@ extern grpc_core::TraceFlag grpc_plugin_credentials_trace;
// -Wmismatched-tags.
struct grpc_plugin_credentials final : public grpc_call_credentials {
public:
struct pending_request {
bool cancelled;
struct grpc_plugin_credentials* creds;
grpc_core::CredentialsMetadataArray* md_array;
grpc_closure* on_request_metadata;
struct pending_request* prev;
struct pending_request* next;
};
explicit grpc_plugin_credentials(grpc_metadata_credentials_plugin plugin,
grpc_security_level min_security_level);
~grpc_plugin_credentials() override;
bool get_request_metadata(grpc_polling_entity* pollent,
grpc_auth_metadata_context context,
grpc_core::CredentialsMetadataArray* md_array,
grpc_closure* on_request_metadata,
grpc_error_handle* error) override;
void cancel_get_request_metadata(
grpc_core::CredentialsMetadataArray* md_array,
grpc_error_handle error) override;
// Checks if the request has been cancelled.
// If not, removes it from the pending list, so that it cannot be
// cancelled out from under us.
// When this returns, r->cancelled indicates whether the request was
// cancelled before completion.
void pending_request_complete(pending_request* r);
grpc_core::ArenaPromise<absl::StatusOr<grpc_core::ClientInitialMetadata>>
GetRequestMetadata(grpc_core::ClientInitialMetadata initial_metadata,
const GetRequestMetadataArgs* args) override;
std::string debug_string() override;
private:
class PendingRequest : public grpc_core::RefCounted<PendingRequest> {
public:
PendingRequest(grpc_core::RefCountedPtr<grpc_plugin_credentials> creds,
grpc_core::ClientInitialMetadata initial_metadata,
const grpc_call_credentials::GetRequestMetadataArgs* args)
: call_creds_(std::move(creds)),
context_(
grpc_core::MakePluginAuthMetadataContext(initial_metadata, args)),
md_(std::move(initial_metadata)) {}
~PendingRequest() override {
grpc_auth_metadata_context_reset(&context_);
for (size_t i = 0; i < metadata_.size(); i++) {
grpc_slice_unref_internal(metadata_[i].key);
grpc_slice_unref_internal(metadata_[i].value);
}
}
absl::StatusOr<grpc_core::ClientInitialMetadata> ProcessPluginResult(
const grpc_metadata* md, size_t num_md, grpc_status_code status,
const char* error_details);
grpc_core::Poll<absl::StatusOr<grpc_core::ClientInitialMetadata>>
PollAsyncResult();
static void RequestMetadataReady(void* request, const grpc_metadata* md,
size_t num_md, grpc_status_code status,
const char* error_details);
grpc_auth_metadata_context context() const { return context_; }
grpc_plugin_credentials* creds() const { return call_creds_.get(); }
private:
std::atomic<bool> ready_{false};
grpc_core::Waker waker_{
grpc_core::Activity::current()->MakeNonOwningWaker()};
grpc_core::RefCountedPtr<grpc_plugin_credentials> call_creds_;
grpc_auth_metadata_context context_;
grpc_core::ClientInitialMetadata md_;
// final status
absl::InlinedVector<grpc_metadata, 2> metadata_;
std::string error_details_;
grpc_status_code status_;
};
int cmp_impl(const grpc_call_credentials* other) const override {
// TODO(yashykt): Check if we can do something better here
return grpc_core::QsortCompare(
static_cast<const grpc_call_credentials*>(this), other);
}
void pending_request_remove_locked(pending_request* pending_request);
grpc_metadata_credentials_plugin plugin_;
gpr_mu mu_;
pending_request* pending_requests_ = nullptr;
};
#endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_PLUGIN_PLUGIN_CREDENTIALS_H */

@ -29,6 +29,7 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/credentials/alts/alts_credentials.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/slice/slice_internal.h"
@ -116,20 +117,13 @@ class grpc_alts_channel_security_connector final
return strcmp(target_name_, other->target_name_);
}
bool check_call_host(absl::string_view host,
grpc_auth_context* /*auth_context*/,
grpc_closure* /*on_call_host_checked*/,
grpc_error_handle* error) override {
grpc_core::ArenaPromise<absl::Status> CheckCallHost(
absl::string_view host, grpc_auth_context*) override {
if (host.empty() || host != target_name_) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"ALTS call host does not match target name");
return grpc_core::Immediate(absl::UnauthenticatedError(
"ALTS call host does not match target name"));
}
return true;
}
void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
grpc_error_handle error) override {
GRPC_ERROR_UNREF(error);
return grpc_core::ImmediateOkStatus();
}
private:

@ -34,6 +34,7 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
@ -105,10 +106,8 @@ class grpc_fake_channel_security_connector final
tsi_create_fake_handshaker(/*is_client=*/true), this, args));
}
bool check_call_host(absl::string_view host,
grpc_auth_context* /*auth_context*/,
grpc_closure* /*on_call_host_checked*/,
grpc_error_handle* /*error*/) override {
grpc_core::ArenaPromise<absl::Status> CheckCallHost(
absl::string_view host, grpc_auth_context*) override {
absl::string_view authority_hostname;
absl::string_view authority_ignored_port;
absl::string_view target_hostname;
@ -134,12 +133,7 @@ class grpc_fake_channel_security_connector final
target_);
abort();
}
return true;
}
void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
grpc_error_handle error) override {
GRPC_ERROR_UNREF(error);
return grpc_core::ImmediateOkStatus();
}
char* target() const { return target_; }

@ -21,6 +21,7 @@
#include "src/core/lib/security/security_connector/insecure/insecure_security_connector.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/tsi/local_transport_security.h"
@ -48,18 +49,9 @@ RefCountedPtr<grpc_auth_context> TestOnlyMakeInsecureAuthContext() {
return MakeAuthContext();
}
// check_call_host and cancel_check_call_host are no-ops since we want to
// provide an insecure channel.
bool InsecureChannelSecurityConnector::check_call_host(
absl::string_view /*host*/, grpc_auth_context* /*auth_context*/,
grpc_closure* /*on_call_host_checked*/, grpc_error_handle* error) {
*error = GRPC_ERROR_NONE;
return true;
}
void InsecureChannelSecurityConnector::cancel_check_call_host(
grpc_closure* /*on_call_host_checked*/, grpc_error_handle error) {
GRPC_ERROR_UNREF(error);
ArenaPromise<absl::Status> InsecureChannelSecurityConnector::CheckCallHost(
absl::string_view, grpc_auth_context*) {
return ImmediateOkStatus();
}
// add_handshakers should have been a no-op but we need to add a minimalist

@ -41,16 +41,11 @@ class InsecureChannelSecurityConnector
InsecureChannelSecurityConnector(
RefCountedPtr<grpc_channel_credentials> channel_creds,
RefCountedPtr<grpc_call_credentials> request_metadata_creds)
: grpc_channel_security_connector(/* url_scheme */ nullptr,
std::move(channel_creds),
: grpc_channel_security_connector("", std::move(channel_creds),
std::move(request_metadata_creds)) {}
bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error_handle* error) override;
void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error_handle error) override;
ArenaPromise<absl::Status> CheckCallHost(
absl::string_view host, grpc_auth_context* auth_context) override;
void add_handshakers(const grpc_channel_args* args,
grpc_pollset_set* /* interested_parties */,
@ -72,7 +67,7 @@ class InsecureServerSecurityConnector : public grpc_server_security_connector {
public:
explicit InsecureServerSecurityConnector(
RefCountedPtr<grpc_server_credentials> server_creds)
: grpc_server_security_connector(nullptr /* url_scheme */,
: grpc_server_security_connector("" /* url_scheme */,
std::move(server_creds)) {}
void add_handshakers(const grpc_channel_args* args,

@ -38,6 +38,7 @@
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/iomgr/socket_utils.h"
#include "src/core/lib/iomgr/unix_sockets_posix.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/credentials/local/local_credentials.h"
#include "src/core/lib/security/transport/security_handshaker.h"
#include "src/core/lib/uri/uri_parser.h"
@ -189,20 +190,13 @@ class grpc_local_channel_security_connector final
GRPC_ERROR_UNREF(error);
}
bool check_call_host(absl::string_view host,
grpc_auth_context* /*auth_context*/,
grpc_closure* /*on_call_host_checked*/,
grpc_error_handle* error) override {
grpc_core::ArenaPromise<absl::Status> CheckCallHost(
absl::string_view host, grpc_auth_context*) override {
if (host.empty() || host != target_name_) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"local call host does not match target name");
return grpc_core::Immediate(absl::UnauthenticatedError(
"local call host does not match target name"));
}
return true;
}
void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
grpc_error_handle error) override {
GRPC_ERROR_UNREF(error);
return grpc_core::ImmediateOkStatus();
}
const char* target_name() const { return target_name_; }

@ -37,7 +37,7 @@ grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount(
false, "security_connector_refcount");
grpc_server_security_connector::grpc_server_security_connector(
const char* url_scheme,
absl::string_view url_scheme,
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
: grpc_security_connector(url_scheme),
server_creds_(std::move(server_creds)) {}
@ -45,7 +45,7 @@ grpc_server_security_connector::grpc_server_security_connector(
grpc_server_security_connector::~grpc_server_security_connector() = default;
grpc_channel_security_connector::grpc_channel_security_connector(
const char* url_scheme,
absl::string_view url_scheme,
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds)
: grpc_security_connector(url_scheme),

@ -30,6 +30,7 @@
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/lib/promise/arena_promise.h"
#include "src/core/tsi/transport_security_interface.h"
extern grpc_core::DebugOnlyTraceFlag grpc_trace_security_connector_refcount;
@ -51,7 +52,7 @@ typedef enum { GRPC_SECURITY_OK = 0, GRPC_SECURITY_ERROR } grpc_security_status;
class grpc_security_connector
: public grpc_core::RefCounted<grpc_security_connector> {
public:
explicit grpc_security_connector(const char* url_scheme)
explicit grpc_security_connector(absl::string_view url_scheme)
: grpc_core::RefCounted<grpc_security_connector>(
GRPC_TRACE_FLAG_ENABLED(grpc_trace_security_connector_refcount)
? "security_connector_refcount"
@ -74,10 +75,10 @@ class grpc_security_connector
/* Compares two security connectors. */
virtual int cmp(const grpc_security_connector* other) const = 0;
const char* url_scheme() const { return url_scheme_; }
absl::string_view url_scheme() const { return url_scheme_; }
private:
const char* url_scheme_;
absl::string_view url_scheme_;
};
/* Util to encapsulate the connector in a channel arg. */
@ -98,26 +99,16 @@ grpc_security_connector* grpc_security_connector_find_in_args(
class grpc_channel_security_connector : public grpc_security_connector {
public:
grpc_channel_security_connector(
const char* url_scheme,
absl::string_view url_scheme,
grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds
/*,
grpc_channel_args* channel_args = nullptr*/);
grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds);
~grpc_channel_security_connector() override;
/// Checks that the host that will be set for a call is acceptable.
/// Returns true if completed synchronously, in which case \a error will
/// be set to indicate the result. Otherwise, \a on_call_host_checked
/// will be invoked when complete.
virtual bool check_call_host(absl::string_view host,
grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error_handle* error) = 0;
/// Cancels a pending asynchronous call to
/// grpc_channel_security_connector_check_call_host() with
/// \a on_call_host_checked as its callback.
virtual void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error_handle error) = 0;
/// Returns ok if the host is acceptable, otherwise returns an error.
virtual grpc_core::ArenaPromise<absl::Status> CheckCallHost(
absl::string_view host, grpc_auth_context* auth_context) = 0;
/// Registers handshakers with \a handshake_mgr.
virtual void add_handshakers(const grpc_channel_args* args,
grpc_pollset_set* interested_parties,
@ -160,7 +151,7 @@ class grpc_channel_security_connector : public grpc_security_connector {
class grpc_server_security_connector : public grpc_security_connector {
public:
grpc_server_security_connector(
const char* url_scheme,
absl::string_view url_scheme,
grpc_core::RefCountedPtr<grpc_server_credentials> server_creds);
~grpc_server_security_connector() override;

@ -35,6 +35,7 @@
#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/credentials/ssl/ssl_credentials.h"
@ -185,17 +186,11 @@ class grpc_ssl_channel_security_connector final
return overridden_target_name_.compare(other->overridden_target_name_);
}
bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
grpc_closure* /*on_call_host_checked*/,
grpc_error_handle* error) override {
return grpc_ssl_check_call_host(host, target_name_.c_str(),
overridden_target_name_.c_str(),
auth_context, error);
}
void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
grpc_error_handle error) override {
GRPC_ERROR_UNREF(error);
grpc_core::ArenaPromise<absl::Status> CheckCallHost(
absl::string_view host, grpc_auth_context* auth_context) override {
return grpc_core::Immediate(
SslCheckCallHost(host, target_name_.c_str(),
overridden_target_name_.c_str(), auth_context));
}
private:

@ -165,11 +165,12 @@ void grpc_tsi_ssl_pem_key_cert_pairs_destroy(tsi_ssl_pem_key_cert_pair* kp,
gpr_free(kp);
}
bool grpc_ssl_check_call_host(absl::string_view host,
namespace grpc_core {
absl::Status SslCheckCallHost(absl::string_view host,
absl::string_view target_name,
absl::string_view overridden_target_name,
grpc_auth_context* auth_context,
grpc_error_handle* error) {
grpc_auth_context* auth_context) {
grpc_security_status status = GRPC_SECURITY_ERROR;
tsi_peer peer = grpc_shallow_peer_from_ssl_auth_context(auth_context);
if (grpc_ssl_host_matches_name(&peer, host)) status = GRPC_SECURITY_OK;
@ -180,14 +181,17 @@ bool grpc_ssl_check_call_host(absl::string_view host,
status = GRPC_SECURITY_OK;
}
if (status != GRPC_SECURITY_OK) {
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"call host does not match SSL server name");
gpr_log(GPR_ERROR, "call host does not match SSL server name");
grpc_shallow_peer_destruct(&peer);
return absl::UnauthenticatedError(
"call host does not match SSL server name");
}
grpc_shallow_peer_destruct(&peer);
return true;
return absl::OkStatus();
}
} // namespace grpc_core
const char** grpc_fill_alpn_protocol_strings(size_t* num_alpn_protocols) {
GPR_ASSERT(num_alpn_protocols != nullptr);
*num_alpn_protocols = grpc_chttp2_num_alpn_versions();

@ -51,12 +51,15 @@ int grpc_ssl_cmp_target_name(absl::string_view target_name,
absl::string_view other_target_name,
absl::string_view overridden_target_name,
absl::string_view other_overridden_target_name);
namespace grpc_core {
/* Check the host that will be set for a call is acceptable.*/
bool grpc_ssl_check_call_host(absl::string_view host,
absl::Status SslCheckCallHost(absl::string_view host,
absl::string_view target_name,
absl::string_view overridden_target_name,
grpc_auth_context* auth_context,
grpc_error_handle* error);
grpc_auth_context* auth_context);
} // namespace grpc_core
/* Return HTTP2-compliant cipher suites that gRPC accepts by default. */
const char* grpc_get_ssl_cipher_suites(void);

@ -34,6 +34,7 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/gprpp/host_port.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/security/credentials/tls/tls_credentials.h"
#include "src/core/lib/security/security_connector/ssl_utils.h"
#include "src/core/lib/security/transport/security_handshaker.h"
@ -408,20 +409,14 @@ int TlsChannelSecurityConnector::cmp(
return 0;
}
bool TlsChannelSecurityConnector::check_call_host(
absl::string_view host, grpc_auth_context* auth_context,
grpc_closure* /*on_call_host_checked*/, grpc_error_handle* error) {
ArenaPromise<absl::Status> TlsChannelSecurityConnector::CheckCallHost(
absl::string_view host, grpc_auth_context* auth_context) {
if (options_->check_call_host()) {
return grpc_ssl_check_call_host(host, target_name_.c_str(),
overridden_target_name_.c_str(),
auth_context, error);
return Immediate(SslCheckCallHost(host, target_name_.c_str(),
overridden_target_name_.c_str(),
auth_context));
}
return true;
}
void TlsChannelSecurityConnector::cancel_check_call_host(
grpc_closure* /*on_call_host_checked*/, grpc_error_handle error) {
GRPC_ERROR_UNREF(error);
return ImmediateOkStatus();
}
void TlsChannelSecurityConnector::TlsChannelCertificateWatcher::

@ -67,12 +67,8 @@ class TlsChannelSecurityConnector final
int cmp(const grpc_security_connector* other_sc) const override;
bool check_call_host(absl::string_view host, grpc_auth_context* auth_context,
grpc_closure* on_call_host_checked,
grpc_error_handle* error) override;
void cancel_check_call_host(grpc_closure* on_call_host_checked,
grpc_error_handle error) override;
ArenaPromise<absl::Status> CheckCallHost(
absl::string_view host, grpc_auth_context* auth_context) override;
tsi_ssl_client_handshaker_factory* ClientHandshakerFactoryForTesting() {
MutexLock lock(&mu_);

@ -24,14 +24,40 @@
#include <grpc/grpc_security.h>
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/promise_based_filter.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/security_connector/security_connector.h"
#include "src/core/lib/transport/transport.h"
extern const grpc_channel_filter grpc_client_auth_filter;
extern const grpc_channel_filter grpc_server_auth_filter;
void grpc_auth_metadata_context_build(
const char* url_scheme, const grpc_slice& call_host,
const grpc_slice& call_method, grpc_auth_context* auth_context,
grpc_auth_metadata_context* auth_md_context);
namespace grpc_core {
// Handles calling out to credentials to fill in metadata per call.
class ClientAuthFilter final : public ChannelFilter {
public:
static absl::StatusOr<ClientAuthFilter> Create(const grpc_channel_args* args,
ChannelFilter::Args);
// Construct a promise for one call.
ArenaPromise<TrailingMetadata> MakeCallPromise(
ClientInitialMetadata initial_metadata,
NextPromiseFactory next_promise_factory) override;
private:
ClientAuthFilter(
RefCountedPtr<grpc_channel_security_connector> security_connector,
RefCountedPtr<grpc_auth_context> auth_context);
ArenaPromise<absl::StatusOr<ClientInitialMetadata>> GetCallCredsMetadata(
ClientInitialMetadata initial_metadata);
// Contains refs to security connector and auth context.
grpc_call_credentials::GetRequestMetadataArgs args_;
};
} // namespace grpc_core
// Exposed for testing purposes only.
// Check if the channel's security level is higher or equal to

@ -29,9 +29,12 @@
#include <grpc/support/string_util.h>
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/promise_based_filter.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/profiling/timers.h"
#include "src/core/lib/promise/promise.h"
#include "src/core/lib/promise/try_seq.h"
#include "src/core/lib/security/context/security_context.h"
#include "src/core/lib/security/credentials/credentials.h"
#include "src/core/lib/security/security_connector/security_connector.h"
@ -39,83 +42,10 @@
#include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/slice/slice_string_helpers.h"
#include "src/core/lib/surface/call.h"
#include "src/core/lib/transport/transport.h"
#define MAX_CREDENTIALS_METADATA_COUNT 4
namespace {
/* We can have a per-channel credentials. */
struct channel_data {
channel_data(grpc_channel_security_connector* security_connector,
grpc_auth_context* auth_context)
: security_connector(
security_connector->Ref(DEBUG_LOCATION, "client_auth_filter")),
auth_context(auth_context->Ref(DEBUG_LOCATION, "client_auth_filter")) {}
~channel_data() {
security_connector.reset(DEBUG_LOCATION, "client_auth_filter");
auth_context.reset(DEBUG_LOCATION, "client_auth_filter");
}
grpc_core::RefCountedPtr<grpc_channel_security_connector> security_connector;
grpc_core::RefCountedPtr<grpc_auth_context> auth_context;
};
/* We can have a per-call credentials. */
struct call_data {
call_data(grpc_call_element* elem, const grpc_call_element_args& args)
: owning_call(args.call_stack), call_combiner(args.call_combiner) {
host.Init();
method.Init();
md_array.Init();
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
GPR_ASSERT(args.context != nullptr);
if (args.context[GRPC_CONTEXT_SECURITY].value == nullptr) {
args.context[GRPC_CONTEXT_SECURITY].value =
grpc_client_security_context_create(args.arena, /*creds=*/nullptr);
args.context[GRPC_CONTEXT_SECURITY].destroy =
grpc_client_security_context_destroy;
}
grpc_client_security_context* sec_ctx =
static_cast<grpc_client_security_context*>(
args.context[GRPC_CONTEXT_SECURITY].value);
sec_ctx->auth_context.reset(DEBUG_LOCATION, "client_auth_filter");
sec_ctx->auth_context =
chand->auth_context->Ref(DEBUG_LOCATION, "client_auth_filter");
}
// This method is technically the dtor of this class. However, since
// `get_request_metadata_cancel_closure` can run in parallel to
// `destroy_call_elem`, we cannot call the dtor in them. Otherwise,
// fields will be accessed after calling dtor, and msan correctly complains
// that the memory is not initialized.
void destroy() {
md_array.Destroy();
creds.reset();
grpc_auth_metadata_context_reset(&auth_md_context);
host.Destroy();
method.Destroy();
}
grpc_call_stack* owning_call;
grpc_core::CallCombiner* call_combiner;
grpc_core::RefCountedPtr<grpc_call_credentials> creds;
grpc_core::ManualConstructor<grpc_core::Slice> host;
grpc_core::ManualConstructor<grpc_core::Slice> method;
/* pollset{_set} bound to this call; if we need to make external
network requests, they should be done under a pollset added to this
pollset_set so that work can progress when this call wants work to progress
*/
grpc_polling_entity* pollent = nullptr;
grpc_core::ManualConstructor<grpc_core::CredentialsMetadataArray> md_array;
grpc_auth_metadata_context auth_md_context =
grpc_auth_metadata_context(); // Zero-initialize the C struct.
grpc_closure async_result_closure;
grpc_closure check_call_host_cancel_closure;
grpc_closure get_request_metadata_cancel_closure;
};
} // namespace
void grpc_auth_metadata_context_copy(grpc_auth_metadata_context* from,
grpc_auth_metadata_context* to) {
grpc_auth_metadata_context_reset(to);
@ -146,98 +76,6 @@ void grpc_auth_metadata_context_reset(
}
}
static void add_error(grpc_error_handle* combined, grpc_error_handle error) {
if (error == GRPC_ERROR_NONE) return;
if (*combined == GRPC_ERROR_NONE) {
*combined = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Client auth metadata plugin error");
}
*combined = grpc_error_add_child(*combined, error);
}
static void on_credentials_metadata(void* arg, grpc_error_handle input_error) {
grpc_transport_stream_op_batch* batch =
static_cast<grpc_transport_stream_op_batch*>(arg);
grpc_call_element* elem =
static_cast<grpc_call_element*>(batch->handler_private.extra_arg);
call_data* calld = static_cast<call_data*>(elem->call_data);
grpc_auth_metadata_context_reset(&calld->auth_md_context);
grpc_error_handle error = GRPC_ERROR_REF(input_error);
if (error == GRPC_ERROR_NONE) {
GPR_ASSERT(calld->md_array->size() <= MAX_CREDENTIALS_METADATA_COUNT);
GPR_ASSERT(batch->send_initial_metadata);
grpc_metadata_batch* mdb =
batch->payload->send_initial_metadata.send_initial_metadata;
for (const auto& md : *calld->md_array) {
mdb->Append(
md.first.as_string_view(), md.second.Ref(),
[&](absl::string_view error_message, const grpc_core::Slice& value) {
add_error(&error, GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"on_credentials_metadata: ", error_message,
": ", md.first.as_string_view(), ": ",
value.as_string_view())));
});
}
grpc_call_next_op(elem, batch);
} else {
error = grpc_error_set_int(error, GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAVAILABLE);
grpc_transport_stream_op_batch_finish_with_failure(batch, error,
calld->call_combiner);
}
GRPC_CALL_STACK_UNREF(calld->owning_call, "get_request_metadata");
}
void grpc_auth_metadata_context_build(
const char* url_scheme, const grpc_slice& call_host,
const grpc_slice& call_method, grpc_auth_context* auth_context,
grpc_auth_metadata_context* auth_md_context) {
char* service = grpc_slice_to_c_string(call_method);
char* last_slash = strrchr(service, '/');
char* method_name = nullptr;
char* service_url = nullptr;
grpc_auth_metadata_context_reset(auth_md_context);
if (last_slash == nullptr) {
gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
service[0] = '\0';
method_name = gpr_strdup("");
} else if (last_slash == service) {
method_name = gpr_strdup("");
} else {
*last_slash = '\0';
method_name = gpr_strdup(last_slash + 1);
}
char* host_and_port = grpc_slice_to_c_string(call_host);
if (url_scheme != nullptr && strcmp(url_scheme, GRPC_SSL_URL_SCHEME) == 0) {
/* Remove the port if it is 443. */
char* port_delimiter = strrchr(host_and_port, ':');
if (port_delimiter != nullptr && strcmp(port_delimiter + 1, "443") == 0) {
*port_delimiter = '\0';
}
}
gpr_asprintf(&service_url, "%s://%s%s",
url_scheme == nullptr ? "" : url_scheme, host_and_port, service);
auth_md_context->service_url = service_url;
auth_md_context->method_name = method_name;
auth_md_context->channel_auth_context =
auth_context == nullptr
? nullptr
: auth_context->Ref(DEBUG_LOCATION, "grpc_auth_metadata_context")
.release();
gpr_free(service);
gpr_free(host_and_port);
}
static void cancel_get_request_metadata(void* arg, grpc_error_handle error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
call_data* calld = static_cast<call_data*>(elem->call_data);
if (error != GRPC_ERROR_NONE) {
calld->creds->cancel_get_request_metadata(&*calld->md_array,
GRPC_ERROR_REF(error));
}
GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_get_request_metadata");
}
static grpc_security_level convert_security_level_string_to_enum(
const char* security_level) {
if (strcmp(security_level, "TSI_INTEGRITY_ONLY") == 0) {
@ -253,242 +91,112 @@ bool grpc_check_security_level(grpc_security_level channel_level,
return static_cast<int>(channel_level) >= static_cast<int>(call_cred_level);
}
static void send_security_metadata(grpc_call_element* elem,
grpc_transport_stream_op_batch* batch) {
call_data* calld = static_cast<call_data*>(elem->call_data);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
grpc_client_security_context* ctx =
static_cast<grpc_client_security_context*>(
batch->payload->context[GRPC_CONTEXT_SECURITY].value);
namespace grpc_core {
ClientAuthFilter::ClientAuthFilter(
RefCountedPtr<grpc_channel_security_connector> security_connector,
RefCountedPtr<grpc_auth_context> auth_context)
: args_{std::move(security_connector), std::move(auth_context)} {}
ArenaPromise<absl::StatusOr<ClientInitialMetadata>>
ClientAuthFilter::GetCallCredsMetadata(ClientInitialMetadata initial_metadata) {
auto* ctx = static_cast<grpc_client_security_context*>(
GetContext<grpc_call_context_element>()[GRPC_CONTEXT_SECURITY].value);
grpc_call_credentials* channel_call_creds =
chand->security_connector->mutable_request_metadata_creds();
int call_creds_has_md = (ctx != nullptr) && (ctx->creds != nullptr);
args_.security_connector->mutable_request_metadata_creds();
const bool call_creds_has_md = (ctx != nullptr) && (ctx->creds != nullptr);
if (channel_call_creds == nullptr && !call_creds_has_md) {
/* Skip sending metadata altogether. */
grpc_call_next_op(elem, batch);
return;
return Immediate(
absl::StatusOr<ClientInitialMetadata>(std::move(initial_metadata)));
}
RefCountedPtr<grpc_call_credentials> creds;
if (channel_call_creds != nullptr && call_creds_has_md) {
calld->creds = grpc_core::RefCountedPtr<grpc_call_credentials>(
creds = RefCountedPtr<grpc_call_credentials>(
grpc_composite_call_credentials_create(channel_call_creds,
ctx->creds.get(), nullptr));
if (calld->creds == nullptr) {
grpc_transport_stream_op_batch_finish_with_failure(
batch,
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Incompatible credentials set on channel and call."),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED),
calld->call_combiner);
return;
if (creds == nullptr) {
return Immediate(absl::UnauthenticatedError(
"Incompatible credentials set on channel and call."));
}
} else if (call_creds_has_md) {
creds = ctx->creds->Ref();
} else {
calld->creds =
call_creds_has_md ? ctx->creds->Ref() : channel_call_creds->Ref();
creds = channel_call_creds->Ref();
}
/* Check security level of call credential and channel, and do not send
* metadata if the check fails. */
grpc_auth_property_iterator it = grpc_auth_context_find_properties_by_name(
chand->auth_context.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME);
args_.auth_context.get(), GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME);
const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
if (prop == nullptr) {
grpc_transport_stream_op_batch_finish_with_failure(
batch,
grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Established channel does not have an auth property "
"representing a security level."),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAUTHENTICATED),
calld->call_combiner);
return;
return Immediate(
absl::UnauthenticatedError("Established channel does not have an auth "
"property representing a security level."));
}
grpc_security_level call_cred_security_level =
calld->creds->min_security_level();
int is_security_level_ok = grpc_check_security_level(
const grpc_security_level call_cred_security_level =
creds->min_security_level();
const bool is_security_level_ok = grpc_check_security_level(
convert_security_level_string_to_enum(prop->value),
call_cred_security_level);
if (!is_security_level_ok) {
grpc_transport_stream_op_batch_finish_with_failure(
batch,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
"Established channel does not have a sufficient "
"security level to transfer call credential."),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAUTHENTICATED),
calld->call_combiner);
return;
return Immediate(absl::UnauthenticatedError(
"Established channel does not have a sufficient security level to "
"transfer call credential."));
}
grpc_auth_metadata_context_build(
chand->security_connector->url_scheme(), calld->host->c_slice(),
calld->method->c_slice(), chand->auth_context.get(),
&calld->auth_md_context);
GPR_ASSERT(calld->pollent != nullptr);
GRPC_CALL_STACK_REF(calld->owning_call, "get_request_metadata");
GRPC_CLOSURE_INIT(&calld->async_result_closure, on_credentials_metadata,
batch, grpc_schedule_on_exec_ctx);
grpc_error_handle error = GRPC_ERROR_NONE;
if (calld->creds->get_request_metadata(
calld->pollent, calld->auth_md_context, &*calld->md_array,
&calld->async_result_closure, &error)) {
// Synchronous return; invoke on_credentials_metadata() directly.
on_credentials_metadata(batch, error);
GRPC_ERROR_UNREF(error);
} else {
// Async return; register cancellation closure with call combiner.
// TODO(yashykt): We would not need this ref if call combiners used
// Closure::Run() instead of ExecCtx::Run()
GRPC_CALL_STACK_REF(calld->owning_call, "cancel_get_request_metadata");
calld->call_combiner->SetNotifyOnCancel(GRPC_CLOSURE_INIT(
&calld->get_request_metadata_cancel_closure,
cancel_get_request_metadata, elem, grpc_schedule_on_exec_ctx));
}
}
static void on_host_checked(void* arg, grpc_error_handle error) {
grpc_transport_stream_op_batch* batch =
static_cast<grpc_transport_stream_op_batch*>(arg);
grpc_call_element* elem =
static_cast<grpc_call_element*>(batch->handler_private.extra_arg);
call_data* calld = static_cast<call_data*>(elem->call_data);
if (error == GRPC_ERROR_NONE) {
send_security_metadata(elem, batch);
} else {
grpc_transport_stream_op_batch_finish_with_failure(
batch,
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat(
"Invalid host ", calld->host->as_string_view(),
" set in :authority metadata.")),
GRPC_ERROR_INT_GRPC_STATUS,
GRPC_STATUS_UNAUTHENTICATED),
calld->call_combiner);
}
GRPC_CALL_STACK_UNREF(calld->owning_call, "check_call_host");
return creds->GetRequestMetadata(std::move(initial_metadata), &args_);
}
static void cancel_check_call_host(void* arg, grpc_error_handle error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(arg);
call_data* calld = static_cast<call_data*>(elem->call_data);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
if (error != GRPC_ERROR_NONE) {
chand->security_connector->cancel_check_call_host(
&calld->async_result_closure, GRPC_ERROR_REF(error));
ArenaPromise<TrailingMetadata> ClientAuthFilter::MakeCallPromise(
ClientInitialMetadata initial_metadata,
NextPromiseFactory next_promise_factory) {
auto* legacy_ctx = GetContext<grpc_call_context_element>();
if (legacy_ctx[GRPC_CONTEXT_SECURITY].value == nullptr) {
legacy_ctx[GRPC_CONTEXT_SECURITY].value =
grpc_client_security_context_create(GetContext<Arena>(),
/*creds=*/nullptr);
legacy_ctx[GRPC_CONTEXT_SECURITY].destroy =
grpc_client_security_context_destroy;
}
GRPC_CALL_STACK_UNREF(calld->owning_call, "cancel_check_call_host");
}
static_cast<grpc_client_security_context*>(
legacy_ctx[GRPC_CONTEXT_SECURITY].value)
->auth_context = args_.auth_context;
static void client_auth_start_transport_stream_op_batch(
grpc_call_element* elem, grpc_transport_stream_op_batch* batch) {
GPR_TIMER_SCOPE("auth_start_transport_stream_op_batch", 0);
/* grab pointers to our data from the call element */
call_data* calld = static_cast<call_data*>(elem->call_data);
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
if (batch->send_initial_metadata) {
grpc_metadata_batch* metadata =
batch->payload->send_initial_metadata.send_initial_metadata;
if (metadata->get_pointer(grpc_core::HttpPathMetadata()) != nullptr) {
*calld->method =
metadata->get_pointer(grpc_core::HttpPathMetadata())->Ref();
}
if (metadata->get_pointer(grpc_core::HttpAuthorityMetadata()) != nullptr) {
*calld->host =
metadata->get_pointer(grpc_core::HttpAuthorityMetadata())->Ref();
batch->handler_private.extra_arg = elem;
GRPC_CALL_STACK_REF(calld->owning_call, "check_call_host");
GRPC_CLOSURE_INIT(&calld->async_result_closure, on_host_checked, batch,
grpc_schedule_on_exec_ctx);
absl::string_view call_host = calld->host->as_string_view();
grpc_error_handle error = GRPC_ERROR_NONE;
if (chand->security_connector->check_call_host(
call_host, chand->auth_context.get(),
&calld->async_result_closure, &error)) {
// Synchronous return; invoke on_host_checked() directly.
on_host_checked(batch, error);
GRPC_ERROR_UNREF(error);
} else {
// Async return; register cancellation closure with call combiner.
// TODO(yashykt): We would not need this ref if call combiners used
// Closure::Run() instead of ExecCtx::Run()
GRPC_CALL_STACK_REF(calld->owning_call, "cancel_check_call_host");
calld->call_combiner->SetNotifyOnCancel(GRPC_CLOSURE_INIT(
&calld->check_call_host_cancel_closure, cancel_check_call_host,
elem, grpc_schedule_on_exec_ctx));
}
return; /* early exit */
}
auto* host = initial_metadata->get_pointer(HttpAuthorityMetadata());
if (host == nullptr) {
return next_promise_factory(std::move(initial_metadata));
}
/* pass control down the stack */
grpc_call_next_op(elem, batch);
}
/* Constructor for call_data */
static grpc_error_handle client_auth_init_call_elem(
grpc_call_element* elem, const grpc_call_element_args* args) {
new (elem->call_data) call_data(elem, *args);
return GRPC_ERROR_NONE;
return TrySeq(args_.security_connector->CheckCallHost(
host->as_string_view(), args_.auth_context.get()),
GetCallCredsMetadata(std::move(initial_metadata)),
next_promise_factory);
}
static void client_auth_set_pollset_or_pollset_set(
grpc_call_element* elem, grpc_polling_entity* pollent) {
call_data* calld = static_cast<call_data*>(elem->call_data);
calld->pollent = pollent;
}
/* Destructor for call_data */
static void client_auth_destroy_call_elem(
grpc_call_element* elem, const grpc_call_final_info* /*final_info*/,
grpc_closure* /*ignored*/) {
call_data* calld = static_cast<call_data*>(elem->call_data);
calld->destroy();
}
/* Constructor for channel_data */
static grpc_error_handle client_auth_init_channel_elem(
grpc_channel_element* elem, grpc_channel_element_args* args) {
/* The first and the last filters tend to be implemented differently to
handle the case that there's no 'next' filter to call on the up or down
path */
GPR_ASSERT(!args->is_last);
grpc_security_connector* sc =
grpc_security_connector_find_in_args(args->channel_args);
absl::StatusOr<ClientAuthFilter> ClientAuthFilter::Create(
const grpc_channel_args* args, ChannelFilter::Args) {
grpc_security_connector* sc = grpc_security_connector_find_in_args(args);
if (sc == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
return absl::InvalidArgumentError(
"Security connector missing from client auth filter args");
}
grpc_auth_context* auth_context =
grpc_find_auth_context_in_args(args->channel_args);
grpc_auth_context* auth_context = grpc_find_auth_context_in_args(args);
if (auth_context == nullptr) {
return GRPC_ERROR_CREATE_FROM_STATIC_STRING(
return absl::InvalidArgumentError(
"Auth context missing from client auth filter args");
}
new (elem->channel_data) channel_data(
static_cast<grpc_channel_security_connector*>(sc), auth_context);
return GRPC_ERROR_NONE;
}
/* Destructor for channel data */
static void client_auth_destroy_channel_elem(grpc_channel_element* elem) {
channel_data* chand = static_cast<channel_data*>(elem->channel_data);
chand->~channel_data();
return ClientAuthFilter(
static_cast<grpc_channel_security_connector*>(sc)->Ref(),
auth_context->Ref());
}
const grpc_channel_filter grpc_client_auth_filter = {
client_auth_start_transport_stream_op_batch,
nullptr,
grpc_channel_next_op,
sizeof(call_data),
client_auth_init_call_elem,
client_auth_set_pollset_or_pollset_set,
client_auth_destroy_call_elem,
sizeof(channel_data),
client_auth_init_channel_elem,
client_auth_destroy_channel_elem,
grpc_channel_next_get_info,
"client-auth"};
} // namespace grpc_core
const grpc_channel_filter grpc_client_auth_filter =
grpc_core::MakePromiseBasedFilter<grpc_core::ClientAuthFilter,
grpc_core::FilterEndpoint::kClient>(
"client-auth-filter");

@ -101,6 +101,13 @@ class MetadataHandle {
// TODO(ctiller): This should be a bespoke instance of MetadataMap<>
using TrailingMetadata = MetadataHandle<grpc_metadata_batch>;
// Ok/not-ok check for trailing metadata, so that it can be used as result types
// for TrySeq.
inline bool IsStatusOk(const TrailingMetadata& m) {
return m->get(GrpcStatusMetadata()).value_or(GRPC_STATUS_UNKNOWN) ==
GRPC_STATUS_OK;
}
// Client initial metadata type
// TODO(ctiller): This should be a bespoke instance of MetadataMap<>
using ClientInitialMetadata = MetadataHandle<grpc_metadata_batch>;

@ -422,6 +422,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/channel/connected_channel.cc',
'src/core/lib/channel/handshaker.cc',
'src/core/lib/channel/handshaker_registry.cc',
'src/core/lib/channel/promise_based_filter.cc',
'src/core/lib/channel/status_util.cc',
'src/core/lib/compression/compression.cc',
'src/core/lib/compression/compression_internal.cc',
@ -602,6 +603,7 @@ CORE_SOURCE_FILES = [
'src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc',
'src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc',
'src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc',
'src/core/lib/security/credentials/call_creds_util.cc',
'src/core/lib/security/credentials/channel_creds_registry_init.cc',
'src/core/lib/security/credentials/composite/composite_credentials.cc',
'src/core/lib/security/credentials/credentials.cc',

@ -175,8 +175,8 @@ static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack(
creds->set_min_tls_version(ffd->tls_version);
creds->set_max_tls_version(ffd->tls_version);
}
grpc_call_credentials* oauth2_creds = grpc_md_only_test_credentials_create(
"authorization", oauth2_md, true /* is_async */);
grpc_call_credentials* oauth2_creds =
grpc_md_only_test_credentials_create("authorization", oauth2_md);
grpc_channel_credentials* ssl_oauth2_creds =
grpc_composite_channel_credentials_create(ssl_creds, oauth2_creds,
nullptr);

@ -156,8 +156,8 @@ static void request_response_with_payload_and_call_creds(
grpc_slice details;
int was_cancelled = 2;
grpc_call_credentials* creds = nullptr;
grpc_auth_context* s_auth_context = nullptr;
grpc_auth_context* c_auth_context = nullptr;
grpc_auth_context* server_auth_context = nullptr;
grpc_auth_context* client_auth_context = nullptr;
f = begin_test(config, test_name, use_secure_call_creds, 0);
cqv = cq_verifier_create(f.cq);
@ -171,8 +171,7 @@ static void request_response_with_payload_and_call_creds(
creds =
grpc_google_iam_credentials_create(iam_token, iam_selector, nullptr);
} else {
creds =
grpc_md_only_test_credentials_create(fake_md_key, fake_md_value, false);
creds = grpc_md_only_test_credentials_create(fake_md_key, fake_md_value);
}
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK);
@ -185,8 +184,8 @@ static void request_response_with_payload_and_call_creds(
creds = grpc_google_iam_credentials_create(
overridden_iam_token, overridden_iam_selector, nullptr);
} else {
creds = grpc_md_only_test_credentials_create(
overridden_fake_md_key, overridden_fake_md_value, false);
creds = grpc_md_only_test_credentials_create(overridden_fake_md_key,
overridden_fake_md_value);
}
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK);
@ -255,15 +254,15 @@ static void request_response_with_payload_and_call_creds(
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
cq_verify(cqv);
s_auth_context = grpc_call_auth_context(s);
GPR_ASSERT(s_auth_context != nullptr);
print_auth_context(0, s_auth_context);
grpc_auth_context_release(s_auth_context);
server_auth_context = grpc_call_auth_context(s);
GPR_ASSERT(server_auth_context != nullptr);
print_auth_context(0, server_auth_context);
grpc_auth_context_release(server_auth_context);
c_auth_context = grpc_call_auth_context(c);
GPR_ASSERT(c_auth_context != nullptr);
print_auth_context(1, c_auth_context);
grpc_auth_context_release(c_auth_context);
client_auth_context = grpc_call_auth_context(c);
GPR_ASSERT(client_auth_context != nullptr);
print_auth_context(1, client_auth_context);
grpc_auth_context_release(client_auth_context);
/* Cannot set creds on the server call object. */
GPR_ASSERT(grpc_call_set_credentials(s, nullptr) != GRPC_CALL_OK);
@ -453,8 +452,7 @@ static void test_request_with_server_rejecting_client_creds(
deadline, nullptr);
GPR_ASSERT(c);
creds =
grpc_md_only_test_credentials_create(fake_md_key, fake_md_value, false);
creds = grpc_md_only_test_credentials_create(fake_md_key, fake_md_value);
GPR_ASSERT(creds != nullptr);
GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK);
grpc_call_credentials_release(creds);

@ -118,18 +118,6 @@ TEST(ActivityTest, DropImmediately) {
[&on_done](absl::Status status) { on_done.Call(std::move(status)); });
}
TEST(ActivityTest, Cancel) {
StrictMock<MockFunction<void(absl::Status)>> on_done;
auto activity = MakeActivity(
[] { return []() -> Poll<absl::Status> { return Pending(); }; },
NoWakeupScheduler(),
[&on_done](absl::Status status) { on_done.Call(std::move(status)); });
EXPECT_CALL(on_done, Call(absl::CancelledError()));
activity->Cancel();
Mock::VerifyAndClearExpectations(&on_done);
activity.reset();
}
template <typename B>
class BarrierTest : public testing::Test {
public:

@ -44,6 +44,14 @@ TEST(ArenaPromiseTest, DestructionWorks) {
EXPECT_EQ(q(), Poll<int>(42));
}
TEST(ArenaPromiseTest, MoveAssignmentWorks) {
auto arena = MakeScopedArena(1024, g_memory_allocator);
promise_detail::Context<Arena> context(arena.get());
auto x = std::make_shared<int>(42);
auto p = ArenaPromise<int>([x] { return Poll<int>(*x); });
p = ArenaPromise<int>();
}
} // namespace grpc_core
int main(int argc, char** argv) {

@ -18,17 +18,17 @@
namespace grpc_core {
TEST(PromiseTest, Immediate) {
TEST(SeqTest, Immediate) {
EXPECT_EQ(Seq([] { return 3; })(), 3);
}
TEST(PromiseTest, OneThen) {
TEST(SeqTest, OneThen) {
auto initial = [] { return 3; };
auto then = [](int i) { return [i]() { return i + 4; }; };
EXPECT_EQ(Seq(initial, then)(), Poll<int>(7));
}
TEST(PromiseTest, TwoTypedThens) {
TEST(SeqTest, TwoTypedThens) {
struct A {};
struct B {};
struct C {};
@ -39,7 +39,7 @@ TEST(PromiseTest, TwoTypedThens) {
}
/* This does not compile, but is useful for testing error messages generated
TEST(PromiseTest, MisTypedThen) {
TEST(SeqTest, MisTypedThen) {
struct A {};
struct B {};
auto initial = [] { return A{}; };
@ -48,14 +48,14 @@ TEST(PromiseTest, MisTypedThen) {
}
*/
TEST(PromiseTest, TwoThens) {
TEST(SeqTest, TwoThens) {
auto initial = [] { return std::string("a"); };
auto next1 = [](std::string i) { return [i]() { return i + "b"; }; };
auto next2 = [](std::string i) { return [i]() { return i + "c"; }; };
EXPECT_EQ(Seq(initial, next1, next2)(), Poll<std::string>("abc"));
}
TEST(PromiseTest, ThreeThens) {
TEST(SeqTest, ThreeThens) {
EXPECT_EQ(Seq([] { return std::string("a"); },
[](std::string i) { return [i]() { return i + "b"; }; },
[](std::string i) { return [i]() { return i + "c"; }; },
@ -68,7 +68,7 @@ struct Big {
void YesItIsUnused() const {}
};
TEST(PromiseTest, SaneSizes) {
TEST(SeqTest, SaneSizes) {
auto x = Big();
auto p1 = Seq(
[x] {
@ -86,6 +86,15 @@ TEST(PromiseTest, SaneSizes) {
EXPECT_LT(sizeof(p1), 2 * sizeof(Big));
}
TEST(SeqIterTest, Accumulate) {
std::vector<int> v{1, 2, 3, 4, 5};
EXPECT_EQ(SeqIter(v.begin(), v.end(), 0,
[](int cur, int next) {
return [cur, next]() { return cur + next; };
})(),
Poll<int>(15));
}
} // namespace grpc_core
int main(int argc, char** argv) {

@ -18,7 +18,7 @@
namespace grpc_core {
TEST(PromiseTest, SucceedAndThen) {
TEST(TrySeqTest, SucceedAndThen) {
EXPECT_EQ(TrySeq([] { return absl::StatusOr<int>(1); },
[](int i) {
return [i]() { return absl::StatusOr<int>(i + 1); };
@ -26,13 +26,13 @@ TEST(PromiseTest, SucceedAndThen) {
Poll<absl::StatusOr<int>>(absl::StatusOr<int>(2)));
}
TEST(PromiseTest, SucceedDirectlyAndThenDirectly) {
TEST(TrySeqTest, SucceedDirectlyAndThenDirectly) {
EXPECT_EQ(
TrySeq([] { return 1; }, [](int i) { return [i]() { return i + 1; }; })(),
Poll<absl::StatusOr<int>>(absl::StatusOr<int>(2)));
}
TEST(PromiseTest, SucceedAndThenChangeType) {
TEST(TrySeqTest, SucceedAndThenChangeType) {
EXPECT_EQ(
TrySeq([] { return absl::StatusOr<int>(42); },
[](int i) {
@ -43,7 +43,7 @@ TEST(PromiseTest, SucceedAndThenChangeType) {
Poll<absl::StatusOr<std::string>>(absl::StatusOr<std::string>("42")));
}
TEST(PromiseTest, FailAndThen) {
TEST(TrySeqTest, FailAndThen) {
EXPECT_EQ(TrySeq([]() { return absl::StatusOr<int>(absl::CancelledError()); },
[](int) {
return []() -> Poll<absl::StatusOr<double>> { abort(); };
@ -52,24 +52,52 @@ TEST(PromiseTest, FailAndThen) {
absl::StatusOr<double>(absl::CancelledError())));
}
TEST(PromiseTest, RawSucceedAndThen) {
TEST(TrySeqTest, RawSucceedAndThen) {
EXPECT_EQ(TrySeq([] { return absl::OkStatus(); },
[] { return []() { return absl::OkStatus(); }; })(),
Poll<absl::Status>(absl::OkStatus()));
}
TEST(PromiseTest, RawFailAndThen) {
TEST(TrySeqTest, RawFailAndThen) {
EXPECT_EQ(TrySeq([] { return absl::CancelledError(); },
[]() { return []() -> Poll<absl::Status> { abort(); }; })(),
Poll<absl::Status>(absl::CancelledError()));
}
TEST(PromiseTest, RawSucceedAndThenValue) {
TEST(TrySeqTest, RawSucceedAndThenValue) {
EXPECT_EQ(TrySeq([] { return absl::OkStatus(); },
[] { return []() { return absl::StatusOr<int>(42); }; })(),
Poll<absl::StatusOr<int>>(absl::StatusOr<int>(42)));
}
TEST(TrySeqIterTest, Ok) {
std::vector<int> v{1, 2, 3, 4, 5};
EXPECT_EQ(TrySeqIter(v.begin(), v.end(), 0,
[](int elem, int accum) {
return [elem, accum]() -> absl::StatusOr<int> {
return elem + accum;
};
})(),
Poll<absl::StatusOr<int>>(15));
}
TEST(TrySeqIterTest, ErrorAt3) {
std::vector<int> v{1, 2, 3, 4, 5};
EXPECT_EQ(TrySeqIter(v.begin(), v.end(), 0,
[](int elem, int accum) {
return [elem, accum]() -> absl::StatusOr<int> {
if (elem < 3) {
return elem + accum;
}
if (elem == 3) {
return absl::CancelledError();
}
abort(); // unreachable
};
})(),
Poll<absl::StatusOr<int>>(absl::CancelledError()));
}
} // namespace grpc_core
int main(int argc, char** argv) {

File diff suppressed because it is too large Load Diff

@ -28,87 +28,80 @@
#include <grpc/support/sync.h>
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/promise/exec_ctx_wakeup_scheduler.h"
#include "src/core/lib/promise/map.h"
#include "src/core/lib/resource_quota/resource_quota.h"
#include "src/core/lib/security/credentials/credentials.h"
typedef struct oauth2_request {
gpr_mu* mu = nullptr;
grpc_polling_entity pops = {};
bool is_done = false;
char* token = nullptr;
grpc_core::CredentialsMetadataArray md_array;
grpc_closure closure = {};
} oauth2_request;
static void on_oauth2_response(void* arg, grpc_error_handle error) {
oauth2_request* request = static_cast<oauth2_request*>(arg);
char* token = nullptr;
grpc_core::Slice token_slice;
if (error != GRPC_ERROR_NONE) {
gpr_log(GPR_ERROR, "Fetching token failed: %s",
grpc_error_std_string(error).c_str());
} else {
GPR_ASSERT(request->md_array.size() == 1);
token_slice = request->md_array[0].second.Ref();
token = static_cast<char*>(gpr_malloc(token_slice.length() + 1));
memcpy(token, token_slice.data(), token_slice.length());
token[token_slice.length()] = '\0';
}
gpr_mu_lock(request->mu);
request->is_done = true;
request->token = token;
GRPC_LOG_IF_ERROR(
"pollset_kick",
grpc_pollset_kick(grpc_polling_entity_pollset(&request->pops), nullptr));
gpr_mu_unlock(request->mu);
}
static void do_nothing(void* /*arg*/, grpc_error_handle /*error*/) {}
static auto* g_memory_allocator = new grpc_core::MemoryAllocator(
grpc_core::ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
"test"));
char* grpc_test_fetch_oauth2_token_with_credentials(
grpc_call_credentials* creds) {
oauth2_request request;
grpc_core::ExecCtx exec_ctx;
grpc_closure do_nothing_closure;
grpc_auth_metadata_context null_ctx = {"", "", nullptr, nullptr};
grpc_call_credentials::GetRequestMetadataArgs get_request_metadata_args;
grpc_pollset* pollset =
static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
grpc_pollset_init(pollset, &request.mu);
request.pops = grpc_polling_entity_create_from_pollset(pollset);
request.is_done = false;
gpr_mu* mu = nullptr;
grpc_pollset_init(pollset, &mu);
auto pops = grpc_polling_entity_create_from_pollset(pollset);
bool is_done = false;
GRPC_CLOSURE_INIT(&do_nothing_closure, do_nothing, nullptr,
grpc_schedule_on_exec_ctx);
auto arena = grpc_core::MakeScopedArena(1024, g_memory_allocator);
grpc_metadata_batch initial_metadata{arena.get()};
char* token = nullptr;
GRPC_CLOSURE_INIT(&request.closure, on_oauth2_response, &request,
grpc_schedule_on_exec_ctx);
auto activity = grpc_core::MakeActivity(
[creds, &initial_metadata, &get_request_metadata_args]() {
return grpc_core::Map(
creds->GetRequestMetadata(
grpc_core::ClientInitialMetadata::TestOnlyWrap(
&initial_metadata),
&get_request_metadata_args),
[](const absl::StatusOr<grpc_core::ClientInitialMetadata>& s) {
return s.status();
});
},
grpc_core::ExecCtxWakeupScheduler(),
[&is_done, &token, &initial_metadata](absl::Status result) {
is_done = true;
if (!result.ok()) {
gpr_log(GPR_ERROR, "Fetching token failed: %s",
result.ToString().c_str());
} else {
std::string buffer;
token = gpr_strdup(
std::string(
initial_metadata
.GetStringValue(GRPC_AUTHORIZATION_METADATA_KEY, &buffer)
.value_or(""))
.c_str());
}
},
arena.get(), &pops);
grpc_error_handle error = GRPC_ERROR_NONE;
if (creds->get_request_metadata(&request.pops, null_ctx, &request.md_array,
&request.closure, &error)) {
// Synchronous result; invoke callback directly.
on_oauth2_response(&request, error);
GRPC_ERROR_UNREF(error);
}
grpc_core::ExecCtx::Get()->Flush();
gpr_mu_lock(request.mu);
while (!request.is_done) {
gpr_mu_lock(mu);
while (!is_done) {
grpc_pollset_worker* worker = nullptr;
if (!GRPC_LOG_IF_ERROR(
"pollset_work",
grpc_pollset_work(grpc_polling_entity_pollset(&request.pops),
&worker, grpc_core::Timestamp::InfFuture()))) {
request.is_done = true;
grpc_pollset_work(grpc_polling_entity_pollset(&pops), &worker,
grpc_core::Timestamp::InfFuture()))) {
is_done = true;
}
}
gpr_mu_unlock(request.mu);
gpr_mu_unlock(mu);
grpc_pollset_shutdown(grpc_polling_entity_pollset(&request.pops),
&do_nothing_closure);
grpc_pollset_shutdown(
grpc_polling_entity_pollset(&pops),
GRPC_CLOSURE_CREATE([](void*, grpc_error_handle) {}, nullptr, nullptr));
grpc_core::ExecCtx::Get()->Flush();
grpc_pollset_destroy(grpc_polling_entity_pollset(&request.pops));
grpc_pollset_destroy(grpc_polling_entity_pollset(&pops));
gpr_free(pollset);
return request.token;
return token;
}

@ -508,7 +508,7 @@ TEST_F(TlsSecurityConnectorTest,
credential->create_security_connector(nullptr, kTargetName, nullptr,
nullptr);
grpc_call_credentials* call_creds =
grpc_md_only_test_credentials_create("", "", true);
grpc_md_only_test_credentials_create("", "");
RefCountedPtr<grpc_channel_security_connector> other_connector =
credential->create_security_connector(
RefCountedPtr<grpc_call_credentials>(call_creds), kTargetName,

@ -79,6 +79,10 @@ grpc_cc_test(
"gtest",
],
language = "C++",
tags = [
# Known race between stream creation and cancellation
"notsan",
],
deps = [
":end2end_binder_channel",
":fake_binder",

@ -424,7 +424,7 @@ class GrpclbEnd2endTest : public ::testing::Test {
grpc_channel_credentials* channel_creds =
grpc_fake_transport_security_credentials_create();
grpc_call_credentials* call_creds = grpc_md_only_test_credentials_create(
g_kCallCredsMdKey, g_kCallCredsMdValue, false);
g_kCallCredsMdKey, g_kCallCredsMdValue);
std::shared_ptr<ChannelCredentials> creds(
new SecureChannelCredentials(grpc_composite_channel_credentials_create(
channel_creds, call_creds, nullptr)));

@ -285,7 +285,7 @@ class RlsEnd2endTest : public ::testing::Test {
grpc_channel_credentials* channel_creds =
grpc_fake_transport_security_credentials_create();
grpc_call_credentials* call_creds = grpc_md_only_test_credentials_create(
kCallCredsMdKey, kCallCredsMdValue, false);
kCallCredsMdKey, kCallCredsMdValue);
auto creds = std::make_shared<SecureChannelCredentials>(
grpc_composite_channel_credentials_create(channel_creds, call_creds,
nullptr));

@ -1891,6 +1891,7 @@ src/core/lib/channel/handshaker.h \
src/core/lib/channel/handshaker_factory.h \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/handshaker_registry.h \
src/core/lib/channel/promise_based_filter.cc \
src/core/lib/channel/promise_based_filter.h \
src/core/lib/channel/status_util.cc \
src/core/lib/channel/status_util.h \
@ -2240,6 +2241,8 @@ src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc \
src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc \
src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h \
src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc \
src/core/lib/security/credentials/call_creds_util.cc \
src/core/lib/security/credentials/call_creds_util.h \
src/core/lib/security/credentials/channel_creds_registry.h \
src/core/lib/security/credentials/channel_creds_registry_init.cc \
src/core/lib/security/credentials/composite/composite_credentials.cc \

@ -1683,6 +1683,7 @@ src/core/lib/channel/handshaker.h \
src/core/lib/channel/handshaker_factory.h \
src/core/lib/channel/handshaker_registry.cc \
src/core/lib/channel/handshaker_registry.h \
src/core/lib/channel/promise_based_filter.cc \
src/core/lib/channel/promise_based_filter.h \
src/core/lib/channel/status_util.cc \
src/core/lib/channel/status_util.h \
@ -2035,6 +2036,8 @@ src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc \
src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc \
src/core/lib/security/credentials/alts/grpc_alts_credentials_options.h \
src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc \
src/core/lib/security/credentials/call_creds_util.cc \
src/core/lib/security/credentials/call_creds_util.h \
src/core/lib/security/credentials/channel_creds_registry.h \
src/core/lib/security/credentials/channel_creds_registry_init.cc \
src/core/lib/security/credentials/composite/composite_credentials.cc \

Loading…
Cancel
Save