diff --git a/BUILD b/BUILD index 06e33b48d18..0a6c3bd8b08 100644 --- a/BUILD +++ b/BUILD @@ -1797,9 +1797,6 @@ grpc_cc_library( "src/core/lib/debug/stats_data.cc", "src/core/lib/event_engine/channel_args_endpoint_config.cc", "src/core/lib/event_engine/sockaddr.cc", - "src/core/lib/http/format_request.cc", - "src/core/lib/http/httpcli.cc", - "src/core/lib/http/parser.cc", "src/core/lib/iomgr/buffer_list.cc", "src/core/lib/iomgr/call_combiner.cc", "src/core/lib/iomgr/cfstream_handle.cc", @@ -1950,9 +1947,6 @@ grpc_cc_library( "src/core/lib/debug/stats_data.h", "src/core/lib/event_engine/channel_args_endpoint_config.h", "src/core/lib/event_engine/sockaddr.h", - "src/core/lib/http/format_request.h", - "src/core/lib/http/httpcli.h", - "src/core/lib/http/parser.h", "src/core/lib/iomgr/block_annotate.h", "src/core/lib/iomgr/buffer_list.h", "src/core/lib/iomgr/call_combiner.h", @@ -2364,6 +2358,7 @@ grpc_cc_library( "grpc_service_config", "grpc_trace", "handshaker_registry", + "httpcli", "json", "json_util", "orphanable", @@ -3474,14 +3469,48 @@ grpc_cc_library( "grpc_client_channel", "grpc_resolver", "grpc_xds_client", + "httpcli", + ], +) + +grpc_cc_library( + name = "httpcli", + srcs = [ + "src/core/lib/http/format_request.cc", + "src/core/lib/http/httpcli.cc", + "src/core/lib/http/parser.cc", + ], + hdrs = [ + "src/core/lib/http/format_request.h", + "src/core/lib/http/httpcli.h", + "src/core/lib/http/parser.h", + ], + external_deps = [ + "absl/functional:bind_front", + "absl/strings", + "absl/strings:str_format", + ], + language = "c++", + visibility = ["@grpc:httpcli"], + deps = [ + "config", + "gpr_base", + "grpc_base", + "grpc_security_base", + "ref_counted_ptr", + "sockaddr_utils", + "useful", ], ) grpc_cc_library( - name = "grpc_httpcli_security_connector", + name = "httpcli_ssl_credentials", srcs = [ "src/core/lib/http/httpcli_security_connector.cc", ], + hdrs = [ + "src/core/lib/http/httpcli_ssl_credentials.h", + ], external_deps = [ "absl/strings", ], @@ -3563,7 +3592,6 @@ grpc_cc_library( "grpc_client_channel", "grpc_codegen", "grpc_credentials_util", - "grpc_httpcli_security_connector", "grpc_jwt_credentials", "grpc_lb_xds_channel_args", "grpc_security_base", @@ -3572,6 +3600,8 @@ grpc_cc_library( "grpc_tls_credentials", "grpc_trace", "grpc_transport_chttp2_alpn", + "httpcli", + "httpcli_ssl_credentials", "json", "ref_counted", "ref_counted_ptr", @@ -3811,6 +3841,8 @@ grpc_cc_library( "grpc_base", "grpc_credentials_util", "grpc_security_base", + "httpcli", + "httpcli_ssl_credentials", "json", "ref_counted", "ref_counted_ptr", @@ -4136,6 +4168,7 @@ grpc_cc_library( "grpc_transport_chttp2_alpn", "hpack_constants", "hpack_encoder_table", + "httpcli", "memory_quota", "resource_quota_trace", "slice", diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e09cba2926..5927dbb2f34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -690,12 +690,6 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_c histogram_test) add_dependencies(buildtests_c host_port_test) add_dependencies(buildtests_c hpack_encoder_test) - if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) - add_dependencies(buildtests_c httpcli_test) - endif() - if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) - add_dependencies(buildtests_c httpscli_test) - endif() add_dependencies(buildtests_c inproc_callback_test) add_dependencies(buildtests_c invalid_call_argument_test) add_dependencies(buildtests_c json_token_test) @@ -895,6 +889,12 @@ if(gRPC_BUILD_TESTS) add_dependencies(buildtests_cxx hpack_parser_table_test) add_dependencies(buildtests_cxx hpack_parser_test) add_dependencies(buildtests_cxx http2_client) + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_cxx httpcli_test) + endif() + if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) + add_dependencies(buildtests_cxx httpscli_test) + endif() add_dependencies(buildtests_cxx hybrid_end2end_test) add_dependencies(buildtests_cxx idle_filter_state_test) add_dependencies(buildtests_cxx if_test) @@ -2664,6 +2664,16 @@ add_library(grpc_unsecure src/core/lib/resource_quota/thread_quota.cc src/core/lib/resource_quota/trace.cc src/core/lib/security/authorization/authorization_policy_provider_null_vtable.cc + src/core/lib/security/context/security_context.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 + src/core/lib/security/security_connector/security_connector.cc + src/core/lib/security/transport/client_auth_filter.cc + src/core/lib/security/transport/secure_endpoint.cc + src/core/lib/security/transport/security_handshaker.cc + src/core/lib/security/transport/server_auth_filter.cc + src/core/lib/security/transport/tsi_error.cc src/core/lib/service_config/service_config.cc src/core/lib/service_config/service_config_parser.cc src/core/lib/slice/b64.cc @@ -2707,6 +2717,8 @@ add_library(grpc_unsecure src/core/lib/transport/transport_op_string.cc src/core/lib/uri/uri_parser.cc src/core/plugin_registry/grpc_unsecure_plugin_registry.cc + src/core/tsi/transport_security.cc + src/core/tsi/transport_security_grpc.cc ) set_target_properties(grpc_unsecure PROPERTIES @@ -2773,6 +2785,7 @@ foreach(_hdr include/grpc/fork.h include/grpc/grpc.h include/grpc/grpc_posix.h + include/grpc/grpc_security.h include/grpc/grpc_security_constants.h include/grpc/load_reporting.h include/grpc/slice.h @@ -5794,72 +5807,6 @@ target_link_libraries(hpack_encoder_test ) -endif() -if(gRPC_BUILD_TESTS) -if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) - - add_executable(httpcli_test - test/core/end2end/data/client_certs.cc - test/core/end2end/data/server1_cert.cc - test/core/end2end/data/server1_key.cc - test/core/end2end/data/test_root_cert.cc - test/core/http/httpcli_test.cc - ) - - target_include_directories(httpcli_test - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} - ${_gRPC_RE2_INCLUDE_DIR} - ${_gRPC_SSL_INCLUDE_DIR} - ${_gRPC_UPB_GENERATED_DIR} - ${_gRPC_UPB_GRPC_GENERATED_DIR} - ${_gRPC_UPB_INCLUDE_DIR} - ${_gRPC_XXHASH_INCLUDE_DIR} - ${_gRPC_ZLIB_INCLUDE_DIR} - ) - - target_link_libraries(httpcli_test - ${_gRPC_ALLTARGETS_LIBRARIES} - grpc_test_util - ) - - -endif() -endif() -if(gRPC_BUILD_TESTS) -if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) - - add_executable(httpscli_test - test/core/end2end/data/client_certs.cc - test/core/end2end/data/server1_cert.cc - test/core/end2end/data/server1_key.cc - test/core/end2end/data/test_root_cert.cc - test/core/http/httpscli_test.cc - ) - - target_include_directories(httpscli_test - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/include - ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} - ${_gRPC_RE2_INCLUDE_DIR} - ${_gRPC_SSL_INCLUDE_DIR} - ${_gRPC_UPB_GENERATED_DIR} - ${_gRPC_UPB_GRPC_GENERATED_DIR} - ${_gRPC_UPB_INCLUDE_DIR} - ${_gRPC_XXHASH_INCLUDE_DIR} - ${_gRPC_ZLIB_INCLUDE_DIR} - ) - - target_link_libraries(httpscli_test - ${_gRPC_ALLTARGETS_LIBRARIES} - grpc_test_util - ) - - -endif() endif() if(gRPC_BUILD_TESTS) @@ -11886,6 +11833,84 @@ target_link_libraries(http2_client ) +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) + + add_executable(httpcli_test + test/core/http/httpcli_test.cc + test/core/http/httpcli_test_util.cc + test/core/util/fake_udp_and_tcp_server.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc + ) + + target_include_directories(httpcli_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} + ) + + target_link_libraries(httpcli_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc++_test_util + ) + + +endif() +endif() +if(gRPC_BUILD_TESTS) +if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) + + add_executable(httpscli_test + test/core/http/httpcli_test_util.cc + test/core/http/httpscli_test.cc + test/core/util/fake_udp_and_tcp_server.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc + ) + + target_include_directories(httpscli_test + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + ${_gRPC_RE2_INCLUDE_DIR} + ${_gRPC_SSL_INCLUDE_DIR} + ${_gRPC_UPB_GENERATED_DIR} + ${_gRPC_UPB_GRPC_GENERATED_DIR} + ${_gRPC_UPB_INCLUDE_DIR} + ${_gRPC_XXHASH_INCLUDE_DIR} + ${_gRPC_ZLIB_INCLUDE_DIR} + third_party/googletest/googletest/include + third_party/googletest/googletest + third_party/googletest/googlemock/include + third_party/googletest/googlemock + ${_gRPC_PROTO_GENS_DIR} + ) + + target_link_libraries(httpscli_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc++_test_util + ) + + +endif() endif() if(gRPC_BUILD_TESTS) diff --git a/Makefile b/Makefile index 740f0fb05db..183e8a1db5e 100644 --- a/Makefile +++ b/Makefile @@ -1991,6 +1991,16 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/resource_quota/thread_quota.cc \ src/core/lib/resource_quota/trace.cc \ src/core/lib/security/authorization/authorization_policy_provider_null_vtable.cc \ + src/core/lib/security/context/security_context.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 \ + src/core/lib/security/security_connector/security_connector.cc \ + src/core/lib/security/transport/client_auth_filter.cc \ + src/core/lib/security/transport/secure_endpoint.cc \ + src/core/lib/security/transport/security_handshaker.cc \ + src/core/lib/security/transport/server_auth_filter.cc \ + src/core/lib/security/transport/tsi_error.cc \ src/core/lib/service_config/service_config.cc \ src/core/lib/service_config/service_config_parser.cc \ src/core/lib/slice/b64.cc \ @@ -2034,6 +2044,8 @@ LIBGRPC_UNSECURE_SRC = \ src/core/lib/transport/transport_op_string.cc \ src/core/lib/uri/uri_parser.cc \ src/core/plugin_registry/grpc_unsecure_plugin_registry.cc \ + src/core/tsi/transport_security.cc \ + src/core/tsi/transport_security_grpc.cc \ PUBLIC_HEADERS_C += \ include/grpc/byte_buffer.h \ @@ -2049,6 +2061,7 @@ PUBLIC_HEADERS_C += \ include/grpc/fork.h \ include/grpc/grpc.h \ include/grpc/grpc_posix.h \ + include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ include/grpc/load_reporting.h \ include/grpc/slice.h \ @@ -2984,7 +2997,6 @@ src/core/lib/security/authorization/grpc_authorization_engine.cc: $(OPENSSL_DEP) src/core/lib/security/authorization/matchers.cc: $(OPENSSL_DEP) src/core/lib/security/authorization/rbac_policy.cc: $(OPENSSL_DEP) src/core/lib/security/authorization/sdk_server_authz_filter.cc: $(OPENSSL_DEP) -src/core/lib/security/context/security_context.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/alts/alts_credentials.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/alts/check_gcp_environment.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc: $(OPENSSL_DEP) @@ -2993,8 +3005,6 @@ src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc: $(OPENS src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc: $(OPENSSL_DEP) -src/core/lib/security/credentials/composite/composite_credentials.cc: $(OPENSSL_DEP) -src/core/lib/security/credentials/credentials.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/external/aws_external_account_credentials.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/external/aws_request_signer.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/external/external_account_credentials.cc: $(OPENSSL_DEP) @@ -3010,7 +3020,6 @@ src/core/lib/security/credentials/jwt/jwt_credentials.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/jwt/jwt_verifier.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/local/local_credentials.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/oauth2/oauth2_credentials.cc: $(OPENSSL_DEP) -src/core/lib/security/credentials/plugin/plugin_credentials.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/ssl/ssl_credentials.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/tls/grpc_tls_certificate_distributor.cc: $(OPENSSL_DEP) src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.cc: $(OPENSSL_DEP) @@ -3025,16 +3034,10 @@ src/core/lib/security/security_connector/insecure/insecure_security_connector.cc src/core/lib/security/security_connector/load_system_roots_fallback.cc: $(OPENSSL_DEP) src/core/lib/security/security_connector/load_system_roots_linux.cc: $(OPENSSL_DEP) src/core/lib/security/security_connector/local/local_security_connector.cc: $(OPENSSL_DEP) -src/core/lib/security/security_connector/security_connector.cc: $(OPENSSL_DEP) src/core/lib/security/security_connector/ssl/ssl_security_connector.cc: $(OPENSSL_DEP) src/core/lib/security/security_connector/ssl_utils.cc: $(OPENSSL_DEP) src/core/lib/security/security_connector/ssl_utils_config.cc: $(OPENSSL_DEP) src/core/lib/security/security_connector/tls/tls_security_connector.cc: $(OPENSSL_DEP) -src/core/lib/security/transport/client_auth_filter.cc: $(OPENSSL_DEP) -src/core/lib/security/transport/secure_endpoint.cc: $(OPENSSL_DEP) -src/core/lib/security/transport/security_handshaker.cc: $(OPENSSL_DEP) -src/core/lib/security/transport/server_auth_filter.cc: $(OPENSSL_DEP) -src/core/lib/security/transport/tsi_error.cc: $(OPENSSL_DEP) src/core/lib/security/util/json_util.cc: $(OPENSSL_DEP) src/core/lib/surface/init_secure.cc: $(OPENSSL_DEP) src/core/plugin_registry/grpc_plugin_registry.cc: $(OPENSSL_DEP) @@ -3064,8 +3067,6 @@ src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc: $(OPENSSL_DEP) src/core/tsi/ssl/session_cache/ssl_session_cache.cc: $(OPENSSL_DEP) src/core/tsi/ssl/session_cache/ssl_session_openssl.cc: $(OPENSSL_DEP) src/core/tsi/ssl_transport_security.cc: $(OPENSSL_DEP) -src/core/tsi/transport_security.cc: $(OPENSSL_DEP) -src/core/tsi/transport_security_grpc.cc: $(OPENSSL_DEP) endif .PHONY: all strip tools dep_error openssl_dep_error openssl_dep_message git_update stop buildtests buildtests_c buildtests_cxx test test_c test_cxx install install_c install_cxx install_csharp install-static install-certs strip strip-shared strip-static strip_c strip-shared_c strip-static_c strip_cxx strip-shared_cxx strip-static_cxx dep_c dep_cxx bins_dep_c bins_dep_cxx clean diff --git a/bazel/grpc_build_system.bzl b/bazel/grpc_build_system.bzl index 6236419bdeb..36dd22151e2 100644 --- a/bazel/grpc_build_system.bzl +++ b/bazel/grpc_build_system.bzl @@ -90,6 +90,7 @@ def _update_visibility(visibility): "grpc_opencensus_plugin": PUBLIC, "grpc_resolver_fake": PRIVATE, "grpc++_test": PRIVATE, + "httpcli": PRIVATE, "public": PUBLIC, "ref_counted_ptr": PRIVATE, "trace": PRIVATE, diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index 2494fe6b435..a99057d31cb 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -764,6 +764,7 @@ libs: - src/core/lib/gprpp/table.h - src/core/lib/http/format_request.h - src/core/lib/http/httpcli.h + - src/core/lib/http/httpcli_ssl_credentials.h - src/core/lib/http/parser.h - src/core/lib/iomgr/block_annotate.h - src/core/lib/iomgr/buffer_list.h @@ -1747,6 +1748,7 @@ libs: - include/grpc/fork.h - include/grpc/grpc.h - include/grpc/grpc_posix.h + - include/grpc/grpc_security.h - include/grpc/grpc_security_constants.h - include/grpc/load_reporting.h - include/grpc/slice.h @@ -1984,6 +1986,15 @@ libs: - src/core/lib/resource_quota/resource_quota.h - src/core/lib/resource_quota/thread_quota.h - src/core/lib/resource_quota/trace.h + - src/core/lib/security/context/security_context.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 + - src/core/lib/security/security_connector/security_connector.h + - src/core/lib/security/transport/auth_filters.h + - src/core/lib/security/transport/secure_endpoint.h + - src/core/lib/security/transport/security_handshaker.h + - src/core/lib/security/transport/tsi_error.h - src/core/lib/service_config/service_config.h - src/core/lib/service_config/service_config_call_data.h - src/core/lib/service_config/service_config_parser.h @@ -2022,6 +2033,9 @@ libs: - src/core/lib/transport/transport.h - src/core/lib/transport/transport_impl.h - src/core/lib/uri/uri_parser.h + - src/core/tsi/transport_security.h + - src/core/tsi/transport_security_grpc.h + - src/core/tsi/transport_security_interface.h - third_party/xxhash/xxhash.h src: - src/core/ext/filters/census/grpc_context.cc @@ -2264,6 +2278,16 @@ libs: - src/core/lib/resource_quota/thread_quota.cc - src/core/lib/resource_quota/trace.cc - src/core/lib/security/authorization/authorization_policy_provider_null_vtable.cc + - src/core/lib/security/context/security_context.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 + - src/core/lib/security/security_connector/security_connector.cc + - src/core/lib/security/transport/client_auth_filter.cc + - src/core/lib/security/transport/secure_endpoint.cc + - src/core/lib/security/transport/security_handshaker.cc + - src/core/lib/security/transport/server_auth_filter.cc + - src/core/lib/security/transport/tsi_error.cc - src/core/lib/service_config/service_config.cc - src/core/lib/service_config/service_config_parser.cc - src/core/lib/slice/b64.cc @@ -2307,6 +2331,8 @@ libs: - src/core/lib/transport/transport_op_string.cc - src/core/lib/uri/uri_parser.cc - src/core/plugin_registry/grpc_unsecure_plugin_registry.cc + - src/core/tsi/transport_security.cc + - src/core/tsi/transport_security_grpc.cc deps: - absl/container:flat_hash_map - absl/container:inlined_vector @@ -3636,40 +3662,6 @@ targets: deps: - grpc_test_util uses_polling: false -- name: httpcli_test - build: test - language: c - headers: - - test/core/end2end/data/ssl_test_data.h - src: - - test/core/end2end/data/client_certs.cc - - test/core/end2end/data/server1_cert.cc - - test/core/end2end/data/server1_key.cc - - test/core/end2end/data/test_root_cert.cc - - test/core/http/httpcli_test.cc - deps: - - grpc_test_util - platforms: - - linux - - posix - - mac -- name: httpscli_test - build: test - language: c - headers: - - test/core/end2end/data/ssl_test_data.h - src: - - test/core/end2end/data/client_certs.cc - - test/core/end2end/data/server1_cert.cc - - test/core/end2end/data/server1_key.cc - - test/core/end2end/data/test_root_cert.cc - - test/core/http/httpscli_test.cc - deps: - - grpc_test_util - platforms: - - linux - - posix - - mac - name: inproc_callback_test build: test language: c @@ -6226,6 +6218,40 @@ targets: deps: - grpc++_test_config - grpc++_test_util +- name: httpcli_test + gtest: true + build: test + language: c++ + headers: + - test/core/http/httpcli_test_util.h + - test/core/util/fake_udp_and_tcp_server.h + src: + - test/core/http/httpcli_test.cc + - test/core/http/httpcli_test_util.cc + - test/core/util/fake_udp_and_tcp_server.cc + deps: + - grpc++_test_util + platforms: + - linux + - posix + - mac +- name: httpscli_test + gtest: true + build: test + language: c++ + headers: + - test/core/http/httpcli_test_util.h + - test/core/util/fake_udp_and_tcp_server.h + src: + - test/core/http/httpcli_test_util.cc + - test/core/http/httpscli_test.cc + - test/core/util/fake_udp_and_tcp_server.cc + deps: + - grpc++_test_util + platforms: + - linux + - posix + - mac - name: hybrid_end2end_test gtest: true build: test diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec index 570295f17fb..32e8f9f09e3 100644 --- a/gRPC-C++.podspec +++ b/gRPC-C++.podspec @@ -636,6 +636,7 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/time_util.h', 'src/core/lib/http/format_request.h', 'src/core/lib/http/httpcli.h', + 'src/core/lib/http/httpcli_ssl_credentials.h', 'src/core/lib/http/parser.h', 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', @@ -1372,6 +1373,7 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/time_util.h', 'src/core/lib/http/format_request.h', 'src/core/lib/http/httpcli.h', + 'src/core/lib/http/httpcli_ssl_credentials.h', 'src/core/lib/http/parser.h', 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 3e0c2daccf3..9b1a7fb83fa 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -987,6 +987,7 @@ Pod::Spec.new do |s| 'src/core/lib/http/httpcli.cc', 'src/core/lib/http/httpcli.h', 'src/core/lib/http/httpcli_security_connector.cc', + 'src/core/lib/http/httpcli_ssl_credentials.h', 'src/core/lib/http/parser.cc', 'src/core/lib/http/parser.h', 'src/core/lib/iomgr/block_annotate.h', @@ -1914,6 +1915,7 @@ Pod::Spec.new do |s| 'src/core/lib/gprpp/time_util.h', 'src/core/lib/http/format_request.h', 'src/core/lib/http/httpcli.h', + 'src/core/lib/http/httpcli_ssl_credentials.h', 'src/core/lib/http/parser.h', 'src/core/lib/iomgr/block_annotate.h', 'src/core/lib/iomgr/buffer_list.h', diff --git a/grpc.gemspec b/grpc.gemspec index 488450b4779..963f06e3c6b 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -906,6 +906,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/lib/http/httpcli.cc ) s.files += %w( src/core/lib/http/httpcli.h ) s.files += %w( src/core/lib/http/httpcli_security_connector.cc ) + s.files += %w( src/core/lib/http/httpcli_ssl_credentials.h ) s.files += %w( src/core/lib/http/parser.cc ) s.files += %w( src/core/lib/http/parser.h ) s.files += %w( src/core/lib/iomgr/block_annotate.h ) diff --git a/grpc.gyp b/grpc.gyp index 649f7723c72..09100a032c7 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -1411,6 +1411,16 @@ 'src/core/lib/resource_quota/thread_quota.cc', 'src/core/lib/resource_quota/trace.cc', 'src/core/lib/security/authorization/authorization_policy_provider_null_vtable.cc', + 'src/core/lib/security/context/security_context.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', + 'src/core/lib/security/security_connector/security_connector.cc', + 'src/core/lib/security/transport/client_auth_filter.cc', + 'src/core/lib/security/transport/secure_endpoint.cc', + 'src/core/lib/security/transport/security_handshaker.cc', + 'src/core/lib/security/transport/server_auth_filter.cc', + 'src/core/lib/security/transport/tsi_error.cc', 'src/core/lib/service_config/service_config.cc', 'src/core/lib/service_config/service_config_parser.cc', 'src/core/lib/slice/b64.cc', @@ -1454,6 +1464,8 @@ 'src/core/lib/transport/transport_op_string.cc', 'src/core/lib/uri/uri_parser.cc', 'src/core/plugin_registry/grpc_unsecure_plugin_registry.cc', + 'src/core/tsi/transport_security.cc', + 'src/core/tsi/transport_security_grpc.cc', ], }, { diff --git a/package.xml b/package.xml index 5568b43aa3c..61e8e4c5029 100644 --- a/package.xml +++ b/package.xml @@ -886,6 +886,7 @@ + diff --git a/src/core/ext/filters/client_channel/http_connect_handshaker.cc b/src/core/ext/filters/client_channel/http_connect_handshaker.cc index 57072f3205d..909f3baaf67 100644 --- a/src/core/ext/filters/client_channel/http_connect_handshaker.cc +++ b/src/core/ext/filters/client_channel/http_connect_handshaker.cc @@ -331,18 +331,15 @@ void HttpConnectHandshaker::DoHandshake(grpc_tcp_server_acceptor* /*acceptor*/, gpr_log(GPR_INFO, "Connecting to server %s via HTTP proxy %s", server_name, proxy_name.c_str()); // Construct HTTP CONNECT request. - grpc_httpcli_request request; - request.host = server_name; - request.ssl_host_override = nullptr; - request.http.method = const_cast("CONNECT"); - request.http.path = server_name; - request.http.version = GRPC_HTTP_HTTP10; // Set by OnReadDone - request.http.hdrs = headers; - request.http.hdr_count = num_headers; - request.http.body_length = 0; - request.http.body = nullptr; - request.handshaker = &grpc_httpcli_plaintext; - grpc_slice request_slice = grpc_httpcli_format_connect_request(&request); + grpc_http_request request; + request.method = const_cast("CONNECT"); + request.version = GRPC_HTTP_HTTP10; // Set by OnReadDone + request.hdrs = headers; + request.hdr_count = num_headers; + request.body_length = 0; + request.body = nullptr; + grpc_slice request_slice = + grpc_httpcli_format_connect_request(&request, server_name, server_name); grpc_slice_buffer_add(&write_buffer_, request_slice); // Clean up. gpr_free(headers); diff --git a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc index 08c67c4cf2f..27e696cb919 100644 --- a/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc +++ b/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc @@ -522,7 +522,9 @@ class AresDNSResolver : public DNSResolver { absl::MutexLock lock(&mu_); GRPC_CARES_TRACE_LOG("AresRequest:%p Orphan ares_request_:%p", this, ares_request_.get()); - grpc_cancel_ares_request(ares_request_.get()); + if (ares_request_ != nullptr) { + grpc_cancel_ares_request(ares_request_.get()); + } } Unref(); } diff --git a/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc b/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc index f813f7ec6f3..d9f856a038b 100644 --- a/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc +++ b/src/core/ext/filters/client_channel/resolver/google_c2p/google_c2p_resolver.cc @@ -24,6 +24,7 @@ #include "src/core/lib/http/httpcli.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/resolver/resolver_registry.h" +#include "src/core/lib/resource_quota/api.h" #include "src/core/lib/security/credentials/alts/check_gcp_environment.h" namespace grpc_core { @@ -61,7 +62,8 @@ class GoogleCloud2ProdResolver : public Resolver { grpc_error_handle error) = 0; RefCountedPtr resolver_; - grpc_httpcli_response response_; + OrphanablePtr http_request_; + grpc_http_response response_; grpc_closure on_done_; std::atomic on_done_called_{false}; }; @@ -94,6 +96,7 @@ class GoogleCloud2ProdResolver : public Resolver { void IPv6QueryDone(bool ipv6_supported); void StartXdsResolver(); + ResourceQuotaRefPtr resource_quota_; std::shared_ptr work_serializer_; grpc_polling_entity pollent_; bool using_dns_ = false; @@ -117,18 +120,26 @@ GoogleCloud2ProdResolver::MetadataQuery::MetadataQuery( // Start HTTP request. GRPC_CLOSURE_INIT(&on_done_, OnHttpRequestDone, this, nullptr); Ref().release(); // Ref held by callback. - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); + grpc_http_request request; + memset(&request, 0, sizeof(grpc_http_request)); grpc_http_header header = {const_cast("Metadata-Flavor"), const_cast("Google")}; - request.host = const_cast("metadata.google.internal"); - request.http.path = const_cast(path); - request.http.hdr_count = 1; - request.http.hdrs = &header; - // TODO(ctiller): share the quota from whomever instantiates this! - grpc_httpcli_get(pollent, ResourceQuota::Default(), &request, - ExecCtx::Get()->Now() + 10000, // 10s timeout - &on_done_, &response_); + request.hdr_count = 1; + request.hdrs = &header; + auto uri = URI::Create("http", "metadata.google.internal.", path, + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); // params are hardcoded + grpc_arg resource_quota_arg = grpc_channel_arg_pointer_create( + const_cast(GRPC_ARG_RESOURCE_QUOTA), + resolver_->resource_quota_.get(), grpc_resource_quota_arg_vtable()); + grpc_channel_args args = {1, &resource_quota_arg}; + http_request_ = + HttpRequest::Get(std::move(*uri), &args, pollent, &request, + ExecCtx::Get()->Now() + 10000, // 10s timeout + &on_done_, &response_, + RefCountedPtr( + grpc_insecure_credentials_create())); + http_request_->Start(); } GoogleCloud2ProdResolver::MetadataQuery::~MetadataQuery() { @@ -227,7 +238,8 @@ void GoogleCloud2ProdResolver::IPv6Query::OnDone( // GoogleCloud2ProdResolver::GoogleCloud2ProdResolver(ResolverArgs args) - : work_serializer_(std::move(args.work_serializer)), + : resource_quota_(ResourceQuotaFromChannelArgs(args.args)), + work_serializer_(std::move(args.work_serializer)), pollent_(grpc_polling_entity_create_from_pollset_set(args.pollset_set)) { absl::string_view name_to_resolve = absl::StripPrefix(args.uri.path(), "/"); // If we're not running on GCP, we can't use DirectPath, so delegate diff --git a/src/core/lib/http/format_request.cc b/src/core/lib/http/format_request.cc index 1f0a5cf5e21..49015a971f3 100644 --- a/src/core/lib/http/format_request.cc +++ b/src/core/lib/http/format_request.cc @@ -35,46 +35,47 @@ #include "src/core/lib/gpr/string.h" -static void fill_common_header(const grpc_httpcli_request* request, +static void fill_common_header(const grpc_http_request* request, + const char* host, const char* path, bool connection_close, std::vector* buf) { - buf->push_back(request->http.path); + buf->push_back(path); buf->push_back(" HTTP/1.0\r\n"); /* just in case some crazy server really expects HTTP/1.1 */ buf->push_back("Host: "); - buf->push_back(request->host); + buf->push_back(host); buf->push_back("\r\n"); if (connection_close) buf->push_back("Connection: close\r\n"); buf->push_back("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n"); /* user supplied headers */ - for (size_t i = 0; i < request->http.hdr_count; i++) { - buf->push_back(request->http.hdrs[i].key); + for (size_t i = 0; i < request->hdr_count; i++) { + buf->push_back(request->hdrs[i].key); buf->push_back(": "); - buf->push_back(request->http.hdrs[i].value); + buf->push_back(request->hdrs[i].value); buf->push_back("\r\n"); } } -grpc_slice grpc_httpcli_format_get_request( - const grpc_httpcli_request* request) { +grpc_slice grpc_httpcli_format_get_request(const grpc_http_request* request, + const char* host, const char* path) { std::vector out; out.push_back("GET "); - fill_common_header(request, true, &out); + fill_common_header(request, host, path, true, &out); out.push_back("\r\n"); std::string req = absl::StrJoin(out, ""); return grpc_slice_from_copied_buffer(req.data(), req.size()); } -grpc_slice grpc_httpcli_format_post_request(const grpc_httpcli_request* request, - const char* body_bytes, - size_t body_size) { +grpc_slice grpc_httpcli_format_post_request(const grpc_http_request* request, + const char* host, + const char* path) { std::vector out; out.push_back("POST "); - fill_common_header(request, true, &out); - if (body_bytes != nullptr) { + fill_common_header(request, host, path, true, &out); + if (request->body != nullptr) { bool has_content_type = false; - for (size_t i = 0; i < request->http.hdr_count; i++) { - if (strcmp(request->http.hdrs[i].key, "Content-Type") == 0) { + for (size_t i = 0; i < request->hdr_count; i++) { + if (strcmp(request->hdrs[i].key, "Content-Type") == 0) { has_content_type = true; break; } @@ -82,22 +83,25 @@ grpc_slice grpc_httpcli_format_post_request(const grpc_httpcli_request* request, if (!has_content_type) { out.push_back("Content-Type: text/plain\r\n"); } - out.push_back(absl::StrFormat("Content-Length: %lu\r\n", - static_cast(body_size))); + out.push_back( + absl::StrFormat("Content-Length: %lu\r\n", + static_cast(request->body_length))); } out.push_back("\r\n"); std::string req = absl::StrJoin(out, ""); - if (body_bytes != nullptr) { - absl::StrAppend(&req, absl::string_view(body_bytes, body_size)); + if (request->body != nullptr) { + absl::StrAppend(&req, + absl::string_view(request->body, request->body_length)); } return grpc_slice_from_copied_buffer(req.data(), req.size()); } -grpc_slice grpc_httpcli_format_connect_request( - const grpc_httpcli_request* request) { +grpc_slice grpc_httpcli_format_connect_request(const grpc_http_request* request, + const char* host, + const char* path) { std::vector out; out.push_back("CONNECT "); - fill_common_header(request, false, &out); + fill_common_header(request, host, path, false, &out); out.push_back("\r\n"); std::string req = absl::StrJoin(out, ""); return grpc_slice_from_copied_buffer(req.data(), req.size()); diff --git a/src/core/lib/http/format_request.h b/src/core/lib/http/format_request.h index 30c870fb692..440bde907e3 100644 --- a/src/core/lib/http/format_request.h +++ b/src/core/lib/http/format_request.h @@ -25,11 +25,12 @@ #include "src/core/lib/http/httpcli.h" -grpc_slice grpc_httpcli_format_get_request(const grpc_httpcli_request* request); -grpc_slice grpc_httpcli_format_post_request(const grpc_httpcli_request* request, - const char* body_bytes, - size_t body_size); -grpc_slice grpc_httpcli_format_connect_request( - const grpc_httpcli_request* request); +grpc_slice grpc_httpcli_format_get_request(const grpc_http_request* request, + const char* host, const char* path); +grpc_slice grpc_httpcli_format_post_request(const grpc_http_request* request, + const char* host, const char* path); +grpc_slice grpc_httpcli_format_connect_request(const grpc_http_request* request, + const char* host, + const char* path); #endif /* GRPC_CORE_LIB_HTTP_FORMAT_REQUEST_H */ diff --git a/src/core/lib/http/httpcli.cc b/src/core/lib/http/httpcli.cc index 826fd468cdf..0ab638b274b 100644 --- a/src/core/lib/http/httpcli.cc +++ b/src/core/lib/http/httpcli.cc @@ -48,272 +48,332 @@ #include "src/core/lib/transport/error_utils.h" namespace grpc_core { + namespace { -class InternalRequest { - public: - InternalRequest(const grpc_slice& request_text, - grpc_httpcli_response* response, - ResourceQuotaRefPtr resource_quota, absl::string_view host, - absl::string_view ssl_host_override, grpc_millis deadline, - const grpc_httpcli_handshaker* handshaker, - grpc_closure* on_done, grpc_polling_entity* pollent, - const char* name) - : request_text_(request_text), - resource_quota_(std::move(resource_quota)), - host_(host), - ssl_host_override_(ssl_host_override), - deadline_(deadline), - handshaker_(handshaker), - on_done_(on_done), - pollent_(pollent), - pollset_set_(grpc_pollset_set_create()) { - grpc_http_parser_init(&parser_, GRPC_HTTP_RESPONSE, response); - grpc_slice_buffer_init(&incoming_); - grpc_slice_buffer_init(&outgoing_); - grpc_iomgr_register_object(&iomgr_obj_, name); +grpc_httpcli_get_override g_get_override; +grpc_httpcli_post_override g_post_override; - GRPC_CLOSURE_INIT(&on_read_, OnRead, this, grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&done_write_, DoneWrite, this, grpc_schedule_on_exec_ctx); - GPR_ASSERT(pollent); - grpc_polling_entity_add_to_pollset_set(pollent, pollset_set_); - dns_request_ = GetDNSResolver()->ResolveName( - host_.c_str(), handshaker_->default_port, pollset_set_, - absl::bind_front(&InternalRequest::OnResolved, this)); - dns_request_->Start(); - } +} // namespace - ~InternalRequest() { - grpc_http_parser_destroy(&parser_); - if (ep_ != nullptr) { - grpc_endpoint_destroy(ep_); - } - grpc_slice_unref_internal(request_text_); - grpc_iomgr_unregister_object(&iomgr_obj_); - grpc_slice_buffer_destroy_internal(&incoming_); - grpc_slice_buffer_destroy_internal(&outgoing_); - GRPC_ERROR_UNREF(overall_error_); - grpc_pollset_set_destroy(pollset_set_); +OrphanablePtr HttpRequest::Get( + URI uri, const grpc_channel_args* channel_args, + grpc_polling_entity* pollent, const grpc_http_request* request, + grpc_millis deadline, grpc_closure* on_done, grpc_http_response* response, + RefCountedPtr channel_creds) { + absl::optional> test_only_generate_response; + if (g_get_override != nullptr) { + test_only_generate_response = [request, uri, deadline, on_done, + response]() { + // Note that capturing request here assumes it will remain alive + // until after Start is called. This avoids making a copy as this + // code path is only used for test mocks. + g_get_override(request, uri.authority().c_str(), uri.path().c_str(), + deadline, on_done, response); + }; } + std::string name = + absl::StrFormat("HTTP:GET:%s:%s", uri.authority(), uri.path()); + const grpc_slice request_text = grpc_httpcli_format_get_request( + request, uri.authority().c_str(), uri.path().c_str()); + return MakeOrphanable( + std::move(uri), request_text, response, deadline, channel_args, on_done, + pollent, name.c_str(), std::move(test_only_generate_response), + std::move(channel_creds)); +} - private: - void Finish(grpc_error_handle error) { - grpc_polling_entity_del_from_pollset_set(pollent_, pollset_set_); - ExecCtx::Run(DEBUG_LOCATION, on_done_, error); - delete this; +OrphanablePtr HttpRequest::Post( + URI uri, const grpc_channel_args* channel_args, + grpc_polling_entity* pollent, const grpc_http_request* request, + grpc_millis deadline, grpc_closure* on_done, grpc_http_response* response, + RefCountedPtr channel_creds) { + absl::optional> test_only_generate_response; + if (g_post_override != nullptr) { + test_only_generate_response = [request, uri, deadline, on_done, + response]() { + g_post_override(request, uri.authority().c_str(), uri.path().c_str(), + request->body, request->body_length, deadline, on_done, + response); + }; } + std::string name = + absl::StrFormat("HTTP:POST:%s:%s", uri.authority(), uri.path()); + const grpc_slice request_text = grpc_httpcli_format_post_request( + request, uri.authority().c_str(), uri.path().c_str()); + return MakeOrphanable( + std::move(uri), request_text, response, deadline, channel_args, on_done, + pollent, name.c_str(), std::move(test_only_generate_response), + std::move(channel_creds)); +} - void AppendError(grpc_error_handle error) { - if (overall_error_ == GRPC_ERROR_NONE) { - overall_error_ = - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed HTTP/1 client request"); - } - const grpc_resolved_address* addr = &addresses_[next_address_ - 1]; - std::string addr_text = grpc_sockaddr_to_uri(addr); - overall_error_ = grpc_error_add_child( - overall_error_, - grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, addr_text)); - } +void HttpRequest::SetOverride(grpc_httpcli_get_override get, + grpc_httpcli_post_override post) { + g_get_override = get; + g_post_override = post; +} - void DoRead() { - grpc_endpoint_read(ep_, &incoming_, &on_read_, /*urgent=*/true); - } +HttpRequest::HttpRequest( + URI uri, const grpc_slice& request_text, grpc_http_response* response, + grpc_millis deadline, const grpc_channel_args* channel_args, + grpc_closure* on_done, grpc_polling_entity* pollent, const char* name, + absl::optional> test_only_generate_response, + RefCountedPtr channel_creds) + : uri_(std::move(uri)), + request_text_(request_text), + deadline_(deadline), + channel_args_(CoreConfiguration::Get() + .channel_args_preconditioning() + .PreconditionChannelArgs(channel_args)), + channel_creds_(std::move(channel_creds)), + on_done_(on_done), + resource_quota_(ResourceQuotaFromChannelArgs(channel_args_)), + pollent_(pollent), + pollset_set_(grpc_pollset_set_create()), + test_only_generate_response_(std::move(test_only_generate_response)) { + grpc_http_parser_init(&parser_, GRPC_HTTP_RESPONSE, response); + grpc_slice_buffer_init(&incoming_); + grpc_slice_buffer_init(&outgoing_); + grpc_iomgr_register_object(&iomgr_obj_, name); + GRPC_CLOSURE_INIT(&on_read_, OnRead, this, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&continue_on_read_after_schedule_on_exec_ctx_, + ContinueOnReadAfterScheduleOnExecCtx, this, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&done_write_, DoneWrite, this, grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&continue_done_write_after_schedule_on_exec_ctx_, + ContinueDoneWriteAfterScheduleOnExecCtx, this, + grpc_schedule_on_exec_ctx); + GPR_ASSERT(pollent); + grpc_polling_entity_add_to_pollset_set(pollent, pollset_set_); + // Create the DNS resolver. We'll start resolving when Start is called. + dns_request_ = GetDNSResolver()->ResolveName( + uri_.authority(), uri_.scheme(), pollset_set_, + absl::bind_front(&HttpRequest::OnResolved, this)); +} - static void OnRead(void* user_data, grpc_error_handle error) { - InternalRequest* req = static_cast(user_data); - req->OnReadInternal(error); +HttpRequest::~HttpRequest() { + grpc_channel_args_destroy(channel_args_); + grpc_http_parser_destroy(&parser_); + if (own_endpoint_ && ep_ != nullptr) { + grpc_endpoint_destroy(ep_); } + grpc_slice_unref_internal(request_text_); + grpc_iomgr_unregister_object(&iomgr_obj_); + grpc_slice_buffer_destroy_internal(&incoming_); + grpc_slice_buffer_destroy_internal(&outgoing_); + GRPC_ERROR_UNREF(overall_error_); + grpc_pollset_set_destroy(pollset_set_); +} - void OnReadInternal(grpc_error_handle error) { - size_t i; +void HttpRequest::Start() { + MutexLock lock(&mu_); + if (test_only_generate_response_.has_value()) { + test_only_generate_response_.value()(); + return; + } + Ref().release(); // ref held by pending DNS resolution + dns_request_->Start(); +} - for (i = 0; i < incoming_.count; i++) { - if (GRPC_SLICE_LENGTH(incoming_.slices[i])) { - have_read_byte_ = 1; - grpc_error_handle err = - grpc_http_parser_parse(&parser_, incoming_.slices[i], nullptr); - if (err != GRPC_ERROR_NONE) { - Finish(err); - return; - } - } +void HttpRequest::Orphan() { + { + MutexLock lock(&mu_); + GPR_ASSERT(!cancelled_); + cancelled_ = true; + dns_request_.reset(); // cancel potentially pending DNS resolution + if (connecting_) { + // gRPC's TCP connection establishment API doesn't currently have + // a mechanism for cancellation. So invoke the user callback now. The TCP + // connection will eventually complete (at least within its deadline), and + // we'll simply unref ourselves at that point. + // TODO(apolcyn): fix this to cancel the TCP connection attempt when + // an API to do so exists. + Finish(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "HTTP request cancelled during TCP connection establishment", + &overall_error_, 1)); } - - if (error == GRPC_ERROR_NONE) { - DoRead(); - } else if (!have_read_byte_) { - NextAddress(GRPC_ERROR_REF(error)); - } else { - Finish(grpc_http_parser_eof(&parser_)); + if (handshake_mgr_ != nullptr) { + handshake_mgr_->Shutdown(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "HTTP request cancelled during security handshake")); } - } - - void OnWritten() { DoRead(); } - - static void DoneWrite(void* arg, grpc_error_handle error) { - InternalRequest* req = static_cast(arg); - if (error == GRPC_ERROR_NONE) { - req->OnWritten(); - } else { - req->NextAddress(GRPC_ERROR_REF(error)); + if (own_endpoint_ && ep_ != nullptr) { + grpc_endpoint_shutdown( + ep_, GRPC_ERROR_CREATE_FROM_STATIC_STRING("HTTP request cancelled")); } } + Unref(); +} - void StartWrite() { - grpc_slice_ref_internal(request_text_); - grpc_slice_buffer_add(&outgoing_, request_text_); - grpc_endpoint_write(ep_, &outgoing_, &done_write_, nullptr); - } - - static void OnHandshakeDone(void* arg, grpc_endpoint* ep) { - InternalRequest* req = static_cast(arg); - - if (!ep) { - req->NextAddress(GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Unexplained handshake failure")); - return; - } - - req->ep_ = ep; - req->StartWrite(); +void HttpRequest::AppendError(grpc_error_handle error) { + if (overall_error_ == GRPC_ERROR_NONE) { + overall_error_ = + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed HTTP/1 client request"); } + const grpc_resolved_address* addr = &addresses_[next_address_ - 1]; + std::string addr_text = grpc_sockaddr_to_uri(addr); + overall_error_ = grpc_error_add_child( + overall_error_, + grpc_error_set_str(error, GRPC_ERROR_STR_TARGET_ADDRESS, addr_text)); +} - static void OnConnected(void* arg, grpc_error_handle error) { - InternalRequest* req = static_cast(arg); - - if (!req->ep_) { - req->NextAddress(GRPC_ERROR_REF(error)); - return; +void HttpRequest::OnReadInternal(grpc_error_handle error) { + for (size_t i = 0; i < incoming_.count; i++) { + if (GRPC_SLICE_LENGTH(incoming_.slices[i])) { + have_read_byte_ = 1; + grpc_error_handle err = + grpc_http_parser_parse(&parser_, incoming_.slices[i], nullptr); + if (err != GRPC_ERROR_NONE) { + Finish(err); + return; + } } - req->handshaker_->handshake(req, req->ep_, - req->ssl_host_override_.empty() - ? req->host_.c_str() - : req->ssl_host_override_.c_str(), - req->deadline_, OnHandshakeDone); } - - void NextAddress(grpc_error_handle error) { - if (error != GRPC_ERROR_NONE) { - AppendError(error); - } - if (next_address_ == addresses_.size()) { - Finish(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Failed HTTP requests to all targets", &overall_error_, 1)); - return; - } - const grpc_resolved_address* addr = &addresses_[next_address_++]; - GRPC_CLOSURE_INIT(&connected_, OnConnected, this, - grpc_schedule_on_exec_ctx); - grpc_arg rq_arg = grpc_channel_arg_pointer_create( - const_cast(GRPC_ARG_RESOURCE_QUOTA), resource_quota_->c_ptr(), - grpc_resource_quota_arg_vtable()); - grpc_channel_args channel_args{1, &rq_arg}; - auto* args = CoreConfiguration::Get() - .channel_args_preconditioning() - .PreconditionChannelArgs(&channel_args); - grpc_tcp_client_connect(&connected_, &ep_, pollset_set_, args, addr, - deadline_); - grpc_channel_args_destroy(args); + if (cancelled_) { + Finish(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "HTTP1 request cancelled during read", &overall_error_, 1)); + } else if (error == GRPC_ERROR_NONE) { + DoRead(); + } else if (!have_read_byte_) { + NextAddress(GRPC_ERROR_REF(error)); + } else { + Finish(grpc_http_parser_eof(&parser_)); } +} - void OnResolved( - absl::StatusOr> addresses_or) { - dns_request_.reset(); - if (!addresses_or.ok()) { - Finish(absl_status_to_grpc_error(addresses_or.status())); - return; - } - addresses_ = std::move(*addresses_or); - next_address_ = 0; - NextAddress(GRPC_ERROR_NONE); +void HttpRequest::ContinueDoneWriteAfterScheduleOnExecCtx( + void* arg, grpc_error_handle error) { + RefCountedPtr req(static_cast(arg)); + MutexLock lock(&req->mu_); + if (error == GRPC_ERROR_NONE && !req->cancelled_) { + req->OnWritten(); + } else { + req->NextAddress(GRPC_ERROR_REF(error)); } - - grpc_slice request_text_; - grpc_http_parser parser_; - std::vector addresses_; - size_t next_address_ = 0; - grpc_endpoint* ep_ = nullptr; - ResourceQuotaRefPtr resource_quota_; - std::string host_; - std::string ssl_host_override_; - grpc_millis deadline_; - int have_read_byte_ = 0; - const grpc_httpcli_handshaker* handshaker_; - grpc_closure* on_done_; - grpc_polling_entity* pollent_; - grpc_pollset_set* pollset_set_; - grpc_iomgr_object iomgr_obj_; - grpc_slice_buffer incoming_; - grpc_slice_buffer outgoing_; - grpc_closure on_read_; - grpc_closure done_write_; - grpc_closure connected_; - grpc_error_handle overall_error_ = GRPC_ERROR_NONE; - OrphanablePtr dns_request_; -}; - -} // namespace -} // namespace grpc_core - -static grpc_httpcli_get_override g_get_override = nullptr; -static grpc_httpcli_post_override g_post_override = nullptr; - -static void plaintext_handshake(void* arg, grpc_endpoint* endpoint, - const char* /*host*/, grpc_millis /*deadline*/, - void (*on_done)(void* arg, - grpc_endpoint* endpoint)) { - on_done(arg, endpoint); } -const grpc_httpcli_handshaker grpc_httpcli_plaintext = {"http", - plaintext_handshake}; +void HttpRequest::StartWrite() { + grpc_slice_ref_internal(request_text_); + grpc_slice_buffer_add(&outgoing_, request_text_); + Ref().release(); // ref held by pending write + grpc_endpoint_write(ep_, &outgoing_, &done_write_, nullptr); +} -static void internal_request_begin( - grpc_polling_entity* pollent, grpc_core::ResourceQuotaRefPtr resource_quota, - const grpc_httpcli_request* request, grpc_millis deadline, - grpc_closure* on_done, grpc_httpcli_response* response, const char* name, - const grpc_slice& request_text) { - new grpc_core::InternalRequest( - request_text, response, std::move(resource_quota), request->host, - request->ssl_host_override, deadline, - request->handshaker ? request->handshaker : &grpc_httpcli_plaintext, - on_done, pollent, name); +void HttpRequest::OnHandshakeDone(void* arg, grpc_error_handle error) { + auto* args = static_cast(arg); + RefCountedPtr req(static_cast(args->user_data)); + MutexLock lock(&req->mu_); + req->own_endpoint_ = true; + if (error != GRPC_ERROR_NONE || req->cancelled_) { + gpr_log(GPR_ERROR, "Secure transport setup failed: %s", + grpc_error_std_string(error).c_str()); + req->NextAddress(GRPC_ERROR_REF(error)); + return; + } + grpc_channel_args_destroy(args->args); + grpc_slice_buffer_destroy_internal(args->read_buffer); + gpr_free(args->read_buffer); + req->ep_ = args->endpoint; + req->StartWrite(); } -void grpc_httpcli_get(grpc_polling_entity* pollent, - grpc_core::ResourceQuotaRefPtr resource_quota, - const grpc_httpcli_request* request, grpc_millis deadline, - grpc_closure* on_done, grpc_httpcli_response* response) { - if (g_get_override && g_get_override(request, deadline, on_done, response)) { +void HttpRequest::OnConnected(void* arg, grpc_error_handle error) { + RefCountedPtr req(static_cast(arg)); + MutexLock lock(&req->mu_); + req->connecting_ = false; + req->own_endpoint_ = true; + if (req->cancelled_) { + // since we were cancelled while connecting, Finish has already + // been called. return; } - std::string name = - absl::StrFormat("HTTP:GET:%s:%s", request->host, request->http.path); - internal_request_begin(pollent, std::move(resource_quota), request, deadline, - on_done, response, name.c_str(), - grpc_httpcli_format_get_request(request)); + if (!req->ep_) { + req->NextAddress(GRPC_ERROR_REF(error)); + return; + } + // TODO(yihuaz): treating nullptr channel_creds_ as insecure is + // a hack used to support the port server client (a test utility) in + // unsecure builds (when no definition of grpc_insecure_credentials_create + // exists). We can remove this hack and unconditionally assume a valid + // channel_creds_ object after unsecure builds are deleted, in + // https://github.com/grpc/grpc/pull/25586. + if (req->channel_creds_ == nullptr) { + gpr_log(GPR_DEBUG, + "HTTP request skipping handshake because creds are null"); + req->StartWrite(); + return; + } + // Create the security connector using the credentials and target name. + grpc_channel_args* new_args_from_connector = nullptr; + RefCountedPtr sc = + req->channel_creds_->create_security_connector( + nullptr /*call_creds*/, req->uri_.authority().c_str(), + req->channel_args_, &new_args_from_connector); + if (sc == nullptr) { + req->Finish(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "failed to create security connector", &req->overall_error_, 1)); + return; + } + grpc_arg security_connector_arg = grpc_security_connector_to_arg(sc.get()); + grpc_channel_args* new_args = grpc_channel_args_copy_and_add( + new_args_from_connector != nullptr ? new_args_from_connector + : req->channel_args_, + &security_connector_arg, 1); + grpc_channel_args_destroy(new_args_from_connector); + // Start the handshake + req->handshake_mgr_ = MakeRefCounted(); + CoreConfiguration::Get().handshaker_registry().AddHandshakers( + HANDSHAKER_CLIENT, new_args, req->pollset_set_, + req->handshake_mgr_.get()); + req->Ref().release(); // ref held by pending handshake + grpc_endpoint* ep = req->ep_; + req->ep_ = nullptr; + req->own_endpoint_ = false; + req->handshake_mgr_->DoHandshake(ep, new_args, req->deadline_, + /*acceptor=*/nullptr, OnHandshakeDone, + /*user_data=*/req.get()); + sc.reset(DEBUG_LOCATION, "httpcli"); + grpc_channel_args_destroy(new_args); } -void grpc_httpcli_post(grpc_polling_entity* pollent, - grpc_core::ResourceQuotaRefPtr resource_quota, - const grpc_httpcli_request* request, - const char* body_bytes, size_t body_size, - grpc_millis deadline, grpc_closure* on_done, - grpc_httpcli_response* response) { - if (g_post_override && g_post_override(request, body_bytes, body_size, - deadline, on_done, response)) { +void HttpRequest::NextAddress(grpc_error_handle error) { + if (error != GRPC_ERROR_NONE) { + AppendError(error); + } + if (cancelled_) { + Finish(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "HTTP request was cancelled", &overall_error_, 1)); return; } - std::string name = - absl::StrFormat("HTTP:POST:%s:%s", request->host, request->http.path); - internal_request_begin( - pollent, std::move(resource_quota), request, deadline, on_done, response, - name.c_str(), - grpc_httpcli_format_post_request(request, body_bytes, body_size)); + if (next_address_ == addresses_.size()) { + Finish(GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Failed HTTP requests to all targets", &overall_error_, 1)); + return; + } + const grpc_resolved_address* addr = &addresses_[next_address_++]; + GRPC_CLOSURE_INIT(&connected_, OnConnected, this, grpc_schedule_on_exec_ctx); + connecting_ = true; + own_endpoint_ = false; + Ref().release(); // ref held by pending connect + grpc_tcp_client_connect(&connected_, &ep_, pollset_set_, channel_args_, addr, + deadline_); } -void grpc_httpcli_set_override(grpc_httpcli_get_override get, - grpc_httpcli_post_override post) { - g_get_override = get; - g_post_override = post; +void HttpRequest::OnResolved( + absl::StatusOr> addresses_or) { + RefCountedPtr unreffer(this); + MutexLock lock(&mu_); + dns_request_.reset(); + if (!addresses_or.ok()) { + Finish(absl_status_to_grpc_error(addresses_or.status())); + return; + } + if (cancelled_) { + Finish(GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "cancelled during DNS resolution")); + return; + } + addresses_ = std::move(*addresses_or); + next_address_ = 0; + NextAddress(GRPC_ERROR_NONE); } + +} // namespace grpc_core diff --git a/src/core/lib/http/httpcli.h b/src/core/lib/http/httpcli.h index 8cd23d6a677..dc20afa0d09 100644 --- a/src/core/lib/http/httpcli.h +++ b/src/core/lib/http/httpcli.h @@ -25,94 +25,196 @@ #include +#include "src/core/lib/channel/handshaker.h" +#include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/iomgr_internal.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/iomgr/pollset_set.h" +#include "src/core/lib/iomgr/resolve_address.h" #include "src/core/lib/resource_quota/resource_quota.h" +#include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/uri/uri_parser.h" /* User agent this library reports */ #define GRPC_HTTPCLI_USER_AGENT "grpc-httpcli/0.0" -/* TODO(ctiller): allow caching and capturing multiple requests for the - same content and combining them */ -struct grpc_httpcli_handshaker { - const char* default_port; - void (*handshake)(void* arg, grpc_endpoint* endpoint, const char* host, - grpc_millis deadline, - void (*on_done)(void* arg, grpc_endpoint* endpoint)); -}; -extern const grpc_httpcli_handshaker grpc_httpcli_plaintext; -extern const grpc_httpcli_handshaker grpc_httpcli_ssl; - -/* A request */ -typedef struct grpc_httpcli_request { - /* The host name to connect to */ - char* host; - /* The host to verify in the SSL handshake (or NULL) */ - char* ssl_host_override; - /* The main part of the request - The following headers are supplied automatically and MUST NOT be set here: - Host, Connection, User-Agent */ - grpc_http_request http; - /* handshaker to use ssl for the request */ - const grpc_httpcli_handshaker* handshaker; -} grpc_httpcli_request; - -/* Expose the parser response type as a httpcli response too */ -typedef struct grpc_http_response grpc_httpcli_response; - -/* Asynchronously perform a HTTP GET. - 'pollent' indicates a grpc_polling_entity that is interested in the result - of the get - work on this entity may be used to progress the get - operation - 'resource_quota' allows the caller to specify the quota against which to - allocate - 'request' contains request parameters - these are caller owned and - can be destroyed once the call returns 'deadline' contains a deadline for the - request (or gpr_inf_future) - 'on_response' is a callback to report results to */ -void grpc_httpcli_get(grpc_polling_entity* pollent, - grpc_core::ResourceQuotaRefPtr resource_quota, - const grpc_httpcli_request* request, grpc_millis deadline, - grpc_closure* on_done, grpc_httpcli_response* response); - -/* Asynchronously perform a HTTP POST. - 'pollent' indicates a grpc_polling_entity that is interested in the result - of the post - work on this entity may be used to progress the post - operation - 'resource_quota' allows the caller to specify the quota against which to - allocate - 'request' contains request parameters - these are caller owned and can be - destroyed once the call returns - 'body_bytes' and 'body_size' specify the payload for the post. - When there is no body, pass in NULL as body_bytes. - 'deadline' contains a deadline for the request (or gpr_inf_future) - 'em' points to a caller owned event manager that must be alive for the - lifetime of the request - 'on_response' is a callback to report results to - Does not support ?var1=val1&var2=val2 in the path. */ -void grpc_httpcli_post(grpc_polling_entity* pollent, - grpc_core::ResourceQuotaRefPtr resource_quota, - const grpc_httpcli_request* request, - const char* body_bytes, size_t body_size, - grpc_millis deadline, grpc_closure* on_done, - grpc_httpcli_response* response); - /* override functions return 1 if they handled the request, 0 otherwise */ -typedef int (*grpc_httpcli_get_override)(const grpc_httpcli_request* request, +typedef int (*grpc_httpcli_get_override)(const grpc_http_request* request, + const char* host, const char* path, grpc_millis deadline, grpc_closure* on_complete, - grpc_httpcli_response* response); -typedef int (*grpc_httpcli_post_override)(const grpc_httpcli_request* request, - const char* body_bytes, - size_t body_size, - grpc_millis deadline, - grpc_closure* on_complete, - grpc_httpcli_response* response); - -void grpc_httpcli_set_override(grpc_httpcli_get_override get, - grpc_httpcli_post_override post); + grpc_http_response* response); +typedef int (*grpc_httpcli_post_override)( + const grpc_http_request* request, const char* host, const char* path, + const char* body_bytes, size_t body_size, grpc_millis deadline, + grpc_closure* on_complete, grpc_http_response* response); + +namespace grpc_core { + +// Tracks an in-progress GET or POST request. Calling \a Start() +// begins async work and calling \a Orphan() arranges for async work +// to be completed as sooon as possible (possibly aborting the request +// if it's in flight). +// TODO(ctiller): allow caching and capturing multiple requests for the +// same content and combining them +class HttpRequest : public InternallyRefCounted { + public: + // Asynchronously perform a HTTP GET. + // 'uri' is the target to make the request to. The scheme field is used to + // determine the port number. The authority field is the target host. The + // path field determines the path of the request. No other fields are used. + // 'args' are optional channel args for the request. + // 'pollent' indicates a grpc_polling_entity that is interested in the result + // of the get - work on this entity may be used to progress the get + // operation + // 'request' contains request parameters - these are caller owned and + // can be destroyed once the call returns + // 'deadline' contains a deadline for the request (or gpr_inf_future) + // 'on_done' is a callback to report results to + // 'channel_creds' are used to configurably secure the connection. + // For insecure requests, use grpc_insecure_credentials_create. + // For secure requests, use CreateHttpRequestSSLCredentials(). + // nullptr is treated as insecure credentials. + // TODO(yihuaz): disallow nullptr as a value after unsecure builds + // are removed. + static OrphanablePtr Get( + URI uri, const grpc_channel_args* args, grpc_polling_entity* pollent, + const grpc_http_request* request, grpc_millis deadline, + grpc_closure* on_done, grpc_http_response* response, + RefCountedPtr channel_creds) + GRPC_MUST_USE_RESULT; + + // Asynchronously perform a HTTP POST. + // 'uri' is the target to make the request to. The scheme field is used to + // determine the port number. The authority field is the target host. The + // path field determines the path of the request. No other fields are used. + // 'args' are optional channel args for the request. + // 'pollent' indicates a grpc_polling_entity that is interested in the result + // of the post - work on this entity may be used to progress the post + // operation + // 'request' contains request parameters - these are caller owned and can be + // destroyed once the call returns + // 'deadline' contains a deadline for the request (or gpr_inf_future) + // 'on_done' is a callback to report results to + // 'channel_creds' are used to configurably secure the connection. + // For insecure requests, use grpc_insecure_credentials_create. + // For secure requests, use CreateHttpRequestSSLCredentials(). + // nullptr is treated as insecure credentials. + // TODO(apolcyn): disallow nullptr as a value after unsecure builds + // are removed. + // Does not support ?var1=val1&var2=val2 in the path. + static OrphanablePtr Post( + URI uri, const grpc_channel_args* args, grpc_polling_entity* pollent, + const grpc_http_request* request, grpc_millis deadline, + grpc_closure* on_done, grpc_http_response* response, + RefCountedPtr channel_creds) + GRPC_MUST_USE_RESULT; + + HttpRequest(URI uri, const grpc_slice& request_text, + grpc_http_response* response, grpc_millis deadline, + const grpc_channel_args* channel_args, grpc_closure* on_done, + grpc_polling_entity* pollent, const char* name, + absl::optional> test_only_generate_response, + RefCountedPtr channel_creds); + + ~HttpRequest() override; + + void Start(); + + void Orphan() override; + + static void SetOverride(grpc_httpcli_get_override get, + grpc_httpcli_post_override post); + + private: + void Finish(grpc_error_handle error) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) { + grpc_polling_entity_del_from_pollset_set(pollent_, pollset_set_); + ExecCtx::Run(DEBUG_LOCATION, on_done_, error); + } + + void AppendError(grpc_error_handle error) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); + + void DoRead() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) { + Ref().release(); // ref held by pending read + grpc_endpoint_read(ep_, &incoming_, &on_read_, /*urgent=*/true); + } + + static void OnRead(void* user_data, grpc_error_handle error) { + HttpRequest* req = static_cast(user_data); + ExecCtx::Run(DEBUG_LOCATION, + &req->continue_on_read_after_schedule_on_exec_ctx_, + GRPC_ERROR_REF(error)); + } + + // Needed since OnRead may be called inline from grpc_endpoint_read + static void ContinueOnReadAfterScheduleOnExecCtx(void* user_data, + grpc_error_handle error) { + RefCountedPtr req(static_cast(user_data)); + MutexLock lock(&req->mu_); + req->OnReadInternal(error); + } + + void OnReadInternal(grpc_error_handle error) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); + + void OnWritten() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) { DoRead(); } + + static void DoneWrite(void* arg, grpc_error_handle error) { + HttpRequest* req = static_cast(arg); + ExecCtx::Run(DEBUG_LOCATION, + &req->continue_done_write_after_schedule_on_exec_ctx_, + GRPC_ERROR_REF(error)); + } + + // Needed since DoneWrite may be called inline from grpc_endpoint_write + static void ContinueDoneWriteAfterScheduleOnExecCtx(void* arg, + grpc_error_handle error); + + void StartWrite() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); + + static void OnHandshakeDone(void* arg, grpc_error_handle error); + + static void OnConnected(void* arg, grpc_error_handle error); + + void NextAddress(grpc_error_handle error) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_); + + void OnResolved( + absl::StatusOr> addresses_or); + + const URI uri_; + const grpc_slice request_text_; + const grpc_millis deadline_; + const grpc_channel_args* channel_args_; + RefCountedPtr channel_creds_; + grpc_closure on_read_; + grpc_closure continue_on_read_after_schedule_on_exec_ctx_; + grpc_closure done_write_; + grpc_closure continue_done_write_after_schedule_on_exec_ctx_; + grpc_closure connected_; + grpc_endpoint* ep_ = nullptr; + grpc_closure* on_done_; + ResourceQuotaRefPtr resource_quota_; + grpc_polling_entity* pollent_; + grpc_pollset_set* pollset_set_; + const absl::optional> test_only_generate_response_; + Mutex mu_; + RefCountedPtr handshake_mgr_ ABSL_GUARDED_BY(mu_); + bool own_endpoint_ ABSL_GUARDED_BY(mu_) = true; + bool cancelled_ ABSL_GUARDED_BY(mu_) = false; + bool connecting_ ABSL_GUARDED_BY(mu_) = false; + grpc_http_parser parser_ ABSL_GUARDED_BY(mu_); + std::vector addresses_ ABSL_GUARDED_BY(mu_); + size_t next_address_ ABSL_GUARDED_BY(mu_) = 0; + int have_read_byte_ ABSL_GUARDED_BY(mu_) = 0; + grpc_iomgr_object iomgr_obj_ ABSL_GUARDED_BY(mu_); + grpc_slice_buffer incoming_ ABSL_GUARDED_BY(mu_); + grpc_slice_buffer outgoing_ ABSL_GUARDED_BY(mu_); + grpc_error_handle overall_error_ ABSL_GUARDED_BY(mu_) = GRPC_ERROR_NONE; + OrphanablePtr dns_request_ ABSL_GUARDED_BY(mu_); +}; + +} // namespace grpc_core #endif /* GRPC_CORE_LIB_HTTP_HTTPCLI_H */ diff --git a/src/core/lib/http/httpcli_security_connector.cc b/src/core/lib/http/httpcli_security_connector.cc index 1efcf20db9b..0a63b57bc44 100644 --- a/src/core/lib/http/httpcli_security_connector.cc +++ b/src/core/lib/http/httpcli_security_connector.cc @@ -31,7 +31,6 @@ #include "src/core/lib/config/core_configuration.h" #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/ref_counted_ptr.h" -#include "src/core/lib/http/httpcli.h" #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/security_connector/ssl_utils.h" @@ -39,6 +38,10 @@ #include "src/core/lib/slice/slice_internal.h" #include "src/core/tsi/ssl_transport_security.h" +namespace grpc_core { + +namespace { + class grpc_httpcli_ssl_channel_security_connector final : public grpc_channel_security_connector { public: @@ -69,7 +72,7 @@ class grpc_httpcli_ssl_channel_security_connector final void add_handshakers(const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/, - grpc_core::HandshakeManager* handshake_mgr) override { + HandshakeManager* handshake_mgr) override { tsi_handshaker* handshaker = nullptr; if (handshaker_factory_ != nullptr) { tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker( @@ -79,8 +82,7 @@ class grpc_httpcli_ssl_channel_security_connector final tsi_result_to_string(result)); } } - handshake_mgr->Add( - grpc_core::SecurityHandshakerCreate(handshaker, this, args)); + handshake_mgr->Add(SecurityHandshakerCreate(handshaker, this, args)); } tsi_ssl_client_handshaker_factory* handshaker_factory() const { @@ -88,7 +90,7 @@ class grpc_httpcli_ssl_channel_security_connector final } void check_peer(tsi_peer peer, grpc_endpoint* /*ep*/, - grpc_core::RefCountedPtr* /*auth_context*/, + RefCountedPtr* /*auth_context*/, grpc_closure* on_peer_checked) override { grpc_error_handle error = GRPC_ERROR_NONE; @@ -98,7 +100,7 @@ class grpc_httpcli_ssl_channel_security_connector final error = GRPC_ERROR_CREATE_FROM_CPP_STRING(absl::StrCat( "Peer name ", secure_peer_name_, " is not in peer certificate")); } - grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); + ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error); tsi_peer_destruct(&peer); } @@ -134,17 +136,17 @@ class grpc_httpcli_ssl_channel_security_connector final char* secure_peer_name_; }; -static grpc_core::RefCountedPtr +RefCountedPtr httpcli_ssl_channel_security_connector_create( const char* pem_root_certs, const tsi_ssl_root_certs_store* root_store, - const char* secure_peer_name, grpc_channel_args* /*channel_args*/) { + const char* secure_peer_name) { if (secure_peer_name != nullptr && pem_root_certs == nullptr) { gpr_log(GPR_ERROR, "Cannot assert a secure peer name without a trust root."); return nullptr; } - grpc_core::RefCountedPtr c = - grpc_core::MakeRefCounted( + RefCountedPtr c = + MakeRefCounted( secure_peer_name == nullptr ? nullptr : gpr_strdup(secure_peer_name)); tsi_result result = c->InitHandshakerFactory(pem_root_certs, root_store); if (result != TSI_OK) { @@ -155,61 +157,45 @@ httpcli_ssl_channel_security_connector_create( return c; } -/* handshaker */ +class HttpRequestSSLCredentials : public grpc_channel_credentials { + public: + HttpRequestSSLCredentials() : grpc_channel_credentials("HttpRequestSSL") {} + ~HttpRequestSSLCredentials() override {} + + RefCountedPtr create_security_connector( + RefCountedPtr /*call_creds*/, const char* target, + const grpc_channel_args* args, + grpc_channel_args** /*new_args*/) override { + const char* pem_root_certs = DefaultSslRootStore::GetPemRootCerts(); + const tsi_ssl_root_certs_store* root_store = + DefaultSslRootStore::GetRootStore(); + if (root_store == nullptr) { + gpr_log(GPR_ERROR, "Could not get default pem root certs."); + return nullptr; + } + const char* ssl_host_override = + grpc_channel_args_find_string(args, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); + if (ssl_host_override != nullptr) { + target = ssl_host_override; + } + return httpcli_ssl_channel_security_connector_create(pem_root_certs, + root_store, target); + } -struct on_done_closure { - void (*func)(void* arg, grpc_endpoint* endpoint); - void* arg; - grpc_core::RefCountedPtr handshake_mgr; -}; -static void on_handshake_done(void* arg, grpc_error_handle error) { - auto* args = static_cast(arg); - on_done_closure* c = static_cast(args->user_data); - if (error != GRPC_ERROR_NONE) { - gpr_log(GPR_ERROR, "Secure transport setup failed: %s", - grpc_error_std_string(error).c_str()); - c->func(c->arg, nullptr); - } else { - grpc_channel_args_destroy(args->args); - grpc_slice_buffer_destroy_internal(args->read_buffer); - gpr_free(args->read_buffer); - c->func(c->arg, args->endpoint); + RefCountedPtr duplicate_without_call_credentials() + override { + return Ref(); } - delete c; -} -static void ssl_handshake(void* arg, grpc_endpoint* tcp, const char* host, - grpc_millis deadline, - void (*on_done)(void* arg, grpc_endpoint* endpoint)) { - auto* c = new on_done_closure(); - const char* pem_root_certs = - grpc_core::DefaultSslRootStore::GetPemRootCerts(); - const tsi_ssl_root_certs_store* root_store = - grpc_core::DefaultSslRootStore::GetRootStore(); - if (root_store == nullptr) { - gpr_log(GPR_ERROR, "Could not get default pem root certs."); - on_done(arg, nullptr); - gpr_free(c); - return; + grpc_channel_args* update_arguments(grpc_channel_args* args) override { + return args; } - c->func = on_done; - c->arg = arg; - grpc_core::RefCountedPtr sc = - httpcli_ssl_channel_security_connector_create( - pem_root_certs, root_store, host, - static_cast(arg)->args); - - GPR_ASSERT(sc != nullptr); - grpc_arg channel_arg = grpc_security_connector_to_arg(sc.get()); - grpc_channel_args args = {1, &channel_arg}; - c->handshake_mgr = grpc_core::MakeRefCounted(); - grpc_core::CoreConfiguration::Get().handshaker_registry().AddHandshakers( - grpc_core::HANDSHAKER_CLIENT, &args, - /*interested_parties=*/nullptr, c->handshake_mgr.get()); - c->handshake_mgr->DoHandshake(tcp, /*channel_args=*/nullptr, deadline, - /*acceptor=*/nullptr, on_handshake_done, - /*user_data=*/c); - sc.reset(DEBUG_LOCATION, "httpcli"); +}; + +} // namespace + +RefCountedPtr CreateHttpRequestSSLCredentials() { + return MakeRefCounted(); } -const grpc_httpcli_handshaker grpc_httpcli_ssl = {"https", ssl_handshake}; +} // namespace grpc_core diff --git a/src/core/lib/http/httpcli_ssl_credentials.h b/src/core/lib/http/httpcli_ssl_credentials.h new file mode 100644 index 00000000000..ef33662a28d --- /dev/null +++ b/src/core/lib/http/httpcli_ssl_credentials.h @@ -0,0 +1,37 @@ +// +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef GRPC_CORE_LIB_HTTP_HTTPCLI_SSL_CREDENTIALS_H +#define GRPC_CORE_LIB_HTTP_HTTPCLI_SSL_CREDENTIALS_H + +#include + +#include "src/core/lib/security/credentials/credentials.h" + +namespace grpc_core { + +// Creates a channel credentials suitable for use with the +// HttpRequest::Get and HttpRequest::Post APIs. Notably, this allows +// HTTP1 requests to use secure connections without ALPN (as the +// typical gRPC SSL credentials do). +// +// These credentials are NOT INTENDED FOR USE with gRPC channels, and +// MUST ONLY BE USED with the HttpRequest::Get and Post APIs. +RefCountedPtr CreateHttpRequestSSLCredentials(); + +} // namespace grpc_core + +#endif // GRPC_CORE_LIB_HTTP_HTTPCLI_SSL_CREDENTIALS_H diff --git a/src/core/lib/http/parser.h b/src/core/lib/http/parser.h index 1f8c3889b10..80147584e6f 100644 --- a/src/core/lib/http/parser.h +++ b/src/core/lib/http/parser.h @@ -56,7 +56,7 @@ typedef enum { typedef struct grpc_http_request { /* Method of the request (e.g. GET, POST) */ char* method; - /* The path of the resource to fetch */ + /* The path of the resource to fetch (only used for parsed requests) */ char* path; /* HTTP version to use */ grpc_http_version version; diff --git a/src/core/lib/security/credentials/credentials.cc b/src/core/lib/security/credentials/credentials.cc index 01e409cfffe..cd8e066d5cd 100644 --- a/src/core/lib/security/credentials/credentials.cc +++ b/src/core/lib/security/credentials/credentials.cc @@ -31,8 +31,6 @@ #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/gpr/string.h" -#include "src/core/lib/http/httpcli.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/executor.h" #include "src/core/lib/json/json.h" #include "src/core/lib/surface/api_trace.h" diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h index e102232745b..4a559382255 100644 --- a/src/core/lib/security/credentials/credentials.h +++ b/src/core/lib/security/credentials/credentials.h @@ -30,8 +30,6 @@ #include #include "src/core/lib/gprpp/ref_counted.h" -#include "src/core/lib/http/httpcli.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/security/security_connector/security_connector.h" #include "src/core/lib/transport/metadata_batch.h" @@ -253,29 +251,4 @@ grpc_server_credentials* grpc_server_credentials_from_arg(const grpc_arg* arg); grpc_server_credentials* grpc_find_server_credentials_in_args( const grpc_channel_args* args); -/* -- Credentials Metadata Request. -- */ - -struct grpc_credentials_metadata_request { - explicit grpc_credentials_metadata_request( - grpc_core::RefCountedPtr creds) - : creds(std::move(creds)) {} - ~grpc_credentials_metadata_request() { - grpc_http_response_destroy(&response); - } - - grpc_core::RefCountedPtr creds; - grpc_http_response response; -}; - -inline grpc_credentials_metadata_request* -grpc_credentials_metadata_request_create( - grpc_core::RefCountedPtr creds) { - return new grpc_credentials_metadata_request(std::move(creds)); -} - -inline void grpc_credentials_metadata_request_destroy( - grpc_credentials_metadata_request* r) { - delete r; -} - #endif /* GRPC_CORE_LIB_SECURITY_CREDENTIALS_CREDENTIALS_H */ diff --git a/src/core/lib/security/credentials/external/aws_external_account_credentials.cc b/src/core/lib/security/credentials/external/aws_external_account_credentials.cc index b262c320685..5d8a74fb5f0 100644 --- a/src/core/lib/security/credentials/external/aws_external_account_credentials.cc +++ b/src/core/lib/security/credentials/external/aws_external_account_credentials.cc @@ -22,6 +22,7 @@ #include "absl/strings/str_replace.h" #include "src/core/lib/gpr/env.h" +#include "src/core/lib/http/httpcli_ssl_credentials.h" namespace grpc_core { @@ -160,18 +161,24 @@ void AwsExternalAccountCredentials::RetrieveRegion() { "Invalid region url. %s", uri.status().ToString()))); return; } - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(uri->authority().c_str()); - request.http.path = gpr_strdup(uri->path().c_str()); - request.handshaker = - uri->scheme() == "https" ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; + grpc_http_request request; + memset(&request, 0, sizeof(grpc_http_request)); grpc_http_response_destroy(&ctx_->response); ctx_->response = {}; GRPC_CLOSURE_INIT(&ctx_->closure, OnRetrieveRegion, this, nullptr); - grpc_httpcli_get(ctx_->pollent, ResourceQuota::Default(), &request, - ctx_->deadline, &ctx_->closure, &ctx_->response); - grpc_http_request_destroy(&request.http); + RefCountedPtr http_request_creds; + if (uri->scheme() == "http") { + http_request_creds = RefCountedPtr( + grpc_insecure_credentials_create()); + } else { + http_request_creds = CreateHttpRequestSSLCredentials(); + } + http_request_ = + HttpRequest::Get(std::move(*uri), nullptr /* channel args */, + ctx_->pollent, &request, ctx_->deadline, &ctx_->closure, + &ctx_->response, std::move(http_request_creds)); + http_request_->Start(); + grpc_http_request_destroy(&request); } void AwsExternalAccountCredentials::OnRetrieveRegion(void* arg, @@ -206,19 +213,25 @@ void AwsExternalAccountCredentials::RetrieveRoleName() { absl::StrFormat("Invalid url: %s.", uri.status().ToString()))); return; } - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(uri->authority().c_str()); - request.http.path = gpr_strdup(uri->path().c_str()); - request.handshaker = - uri->scheme() == "https" ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; + grpc_http_request request; + memset(&request, 0, sizeof(grpc_http_request)); grpc_http_response_destroy(&ctx_->response); ctx_->response = {}; GRPC_CLOSURE_INIT(&ctx_->closure, OnRetrieveRoleName, this, nullptr); // TODO(ctiller): use the caller's resource quota. - grpc_httpcli_get(ctx_->pollent, ResourceQuota::Default(), &request, - ctx_->deadline, &ctx_->closure, &ctx_->response); - grpc_http_request_destroy(&request.http); + RefCountedPtr http_request_creds; + if (uri->scheme() == "http") { + http_request_creds = RefCountedPtr( + grpc_insecure_credentials_create()); + } else { + http_request_creds = CreateHttpRequestSSLCredentials(); + } + http_request_ = + HttpRequest::Get(std::move(*uri), nullptr /* channel args */, + ctx_->pollent, &request, ctx_->deadline, &ctx_->closure, + &ctx_->response, std::move(http_request_creds)); + http_request_->Start(); + grpc_http_request_destroy(&request); } void AwsExternalAccountCredentials::OnRetrieveRoleName( @@ -265,19 +278,25 @@ void AwsExternalAccountCredentials::RetrieveSigningKeys() { "Invalid url with role name: %s.", uri.status().ToString()))); return; } - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(uri->authority().c_str()); - request.http.path = gpr_strdup(uri->path().c_str()); - request.handshaker = - uri->scheme() == "https" ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; + grpc_http_request request; + memset(&request, 0, sizeof(grpc_http_request)); grpc_http_response_destroy(&ctx_->response); ctx_->response = {}; GRPC_CLOSURE_INIT(&ctx_->closure, OnRetrieveSigningKeys, this, nullptr); // TODO(ctiller): use the caller's resource quota. - grpc_httpcli_get(ctx_->pollent, ResourceQuota::Default(), &request, - ctx_->deadline, &ctx_->closure, &ctx_->response); - grpc_http_request_destroy(&request.http); + RefCountedPtr http_request_creds; + if (uri->scheme() == "http") { + http_request_creds = RefCountedPtr( + grpc_insecure_credentials_create()); + } else { + http_request_creds = CreateHttpRequestSSLCredentials(); + } + http_request_ = + HttpRequest::Get(std::move(*uri), nullptr /* channel args */, + ctx_->pollent, &request, ctx_->deadline, &ctx_->closure, + &ctx_->response, std::move(http_request_creds)); + http_request_->Start(); + grpc_http_request_destroy(&request); } void AwsExternalAccountCredentials::OnRetrieveSigningKeys( diff --git a/src/core/lib/security/credentials/external/aws_external_account_credentials.h b/src/core/lib/security/credentials/external/aws_external_account_credentials.h index bf232f2fca3..ee47270b6a6 100644 --- a/src/core/lib/security/credentials/external/aws_external_account_credentials.h +++ b/src/core/lib/security/credentials/external/aws_external_account_credentials.h @@ -56,6 +56,7 @@ class AwsExternalAccountCredentials final : public ExternalAccountCredentials { grpc_error_handle error); std::string audience_; + OrphanablePtr http_request_; // Fields of credential source std::string region_url_; diff --git a/src/core/lib/security/credentials/external/external_account_credentials.cc b/src/core/lib/security/credentials/external/external_account_credentials.cc index 0f78d6bb512..0ff86bb7ad8 100644 --- a/src/core/lib/security/credentials/external/external_account_credentials.cc +++ b/src/core/lib/security/credentials/external/external_account_credentials.cc @@ -25,6 +25,7 @@ #include "absl/time/clock.h" #include "absl/time/time.h" +#include "src/core/lib/http/httpcli_ssl_credentials.h" #include "src/core/lib/http/parser.h" #include "src/core/lib/security/credentials/external/aws_external_account_credentials.h" #include "src/core/lib/security/credentials/external/file_external_account_credentials.h" @@ -267,15 +268,13 @@ void ExternalAccountCredentials::ExchangeToken( uri.status().ToString()))); return; } - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(uri->authority().c_str()); - request.http.path = gpr_strdup(uri->path().c_str()); + grpc_http_request request; + memset(&request, 0, sizeof(grpc_http_request)); grpc_http_header* headers = nullptr; if (!options_.client_id.empty() && !options_.client_secret.empty()) { - request.http.hdr_count = 2; + request.hdr_count = 2; headers = static_cast( - gpr_malloc(sizeof(grpc_http_header) * request.http.hdr_count)); + gpr_malloc(sizeof(grpc_http_header) * request.hdr_count)); headers[0].key = gpr_strdup("Content-Type"); headers[0].value = gpr_strdup("application/x-www-form-urlencoded"); std::string raw_cred = @@ -287,15 +286,13 @@ void ExternalAccountCredentials::ExchangeToken( headers[1].value = gpr_strdup(str.c_str()); gpr_free(encoded_cred); } else { - request.http.hdr_count = 1; + request.hdr_count = 1; headers = static_cast( - gpr_malloc(sizeof(grpc_http_header) * request.http.hdr_count)); + gpr_malloc(sizeof(grpc_http_header) * request.hdr_count)); headers[0].key = gpr_strdup("Content-Type"); headers[0].value = gpr_strdup("application/x-www-form-urlencoded"); } - request.http.hdrs = headers; - request.handshaker = - uri->scheme() == "https" ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; + request.hdrs = headers; std::vector body_parts; body_parts.push_back( absl::StrFormat("audience=%s", UrlEncode(options_.audience).c_str())); @@ -323,13 +320,26 @@ void ExternalAccountCredentials::ExchangeToken( body_parts.push_back(absl::StrFormat( "options=%s", UrlEncode(addtional_options_json.Dump()).c_str())); std::string body = absl::StrJoin(body_parts, "&"); + request.body = const_cast(body.c_str()); + request.body_length = body.size(); grpc_http_response_destroy(&ctx_->response); ctx_->response = {}; GRPC_CLOSURE_INIT(&ctx_->closure, OnExchangeToken, this, nullptr); - grpc_httpcli_post(ctx_->pollent, ResourceQuota::Default(), &request, - body.c_str(), body.size(), ctx_->deadline, &ctx_->closure, - &ctx_->response); - grpc_http_request_destroy(&request.http); + GPR_ASSERT(http_request_ == nullptr); + RefCountedPtr http_request_creds; + if (uri->scheme() == "http") { + http_request_creds = RefCountedPtr( + grpc_insecure_credentials_create()); + } else { + http_request_creds = CreateHttpRequestSSLCredentials(); + } + http_request_ = + HttpRequest::Post(std::move(*uri), nullptr /* channel args */, + ctx_->pollent, &request, ctx_->deadline, &ctx_->closure, + &ctx_->response, std::move(http_request_creds)); + http_request_->Start(); + request.body = nullptr; + grpc_http_request_destroy(&request); } void ExternalAccountCredentials::OnExchangeToken(void* arg, @@ -341,6 +351,7 @@ void ExternalAccountCredentials::OnExchangeToken(void* arg, void ExternalAccountCredentials::OnExchangeTokenInternal( grpc_error_handle error) { + http_request_.reset(); if (error != GRPC_ERROR_NONE) { FinishTokenFetch(error); } else { @@ -390,31 +401,39 @@ void ExternalAccountCredentials::ImpersenateServiceAccount() { options_.service_account_impersonation_url, uri.status().ToString()))); return; } - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(uri->authority().c_str()); - request.http.path = gpr_strdup(uri->path().c_str()); - request.http.hdr_count = 2; + grpc_http_request request; + memset(&request, 0, sizeof(grpc_http_request)); + request.hdr_count = 2; grpc_http_header* headers = static_cast( - gpr_malloc(sizeof(grpc_http_header) * request.http.hdr_count)); + gpr_malloc(sizeof(grpc_http_header) * request.hdr_count)); headers[0].key = gpr_strdup("Content-Type"); headers[0].value = gpr_strdup("application/x-www-form-urlencoded"); std::string str = absl::StrFormat("Bearer %s", access_token); headers[1].key = gpr_strdup("Authorization"); headers[1].value = gpr_strdup(str.c_str()); - request.http.hdrs = headers; - request.handshaker = - uri->scheme() == "https" ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; + request.hdrs = headers; std::string scope = absl::StrJoin(scopes_, " "); std::string body = absl::StrFormat("scope=%s", scope); + request.body = const_cast(body.c_str()); + request.body_length = body.size(); grpc_http_response_destroy(&ctx_->response); ctx_->response = {}; GRPC_CLOSURE_INIT(&ctx_->closure, OnImpersenateServiceAccount, this, nullptr); // TODO(ctiller): Use the callers resource quota. - grpc_httpcli_post(ctx_->pollent, ResourceQuota::Default(), &request, - body.c_str(), body.size(), ctx_->deadline, &ctx_->closure, - &ctx_->response); - grpc_http_request_destroy(&request.http); + GPR_ASSERT(http_request_ == nullptr); + RefCountedPtr http_request_creds; + if (uri->scheme() == "http") { + http_request_creds = RefCountedPtr( + grpc_insecure_credentials_create()); + } else { + http_request_creds = CreateHttpRequestSSLCredentials(); + } + http_request_ = HttpRequest::Post( + std::move(*uri), nullptr, ctx_->pollent, &request, ctx_->deadline, + &ctx_->closure, &ctx_->response, std::move(http_request_creds)); + http_request_->Start(); + request.body = nullptr; + grpc_http_request_destroy(&request); } void ExternalAccountCredentials::OnImpersenateServiceAccount( @@ -426,6 +445,7 @@ void ExternalAccountCredentials::OnImpersenateServiceAccount( void ExternalAccountCredentials::OnImpersenateServiceAccountInternal( grpc_error_handle error) { + http_request_.reset(); if (error != GRPC_ERROR_NONE) { FinishTokenFetch(error); return; diff --git a/src/core/lib/security/credentials/external/external_account_credentials.h b/src/core/lib/security/credentials/external/external_account_credentials.h index 9076769639e..21f3c6747a7 100644 --- a/src/core/lib/security/credentials/external/external_account_credentials.h +++ b/src/core/lib/security/credentials/external/external_account_credentials.h @@ -107,6 +107,7 @@ class ExternalAccountCredentials Options options_; std::vector scopes_; + OrphanablePtr http_request_; HTTPRequestContext* ctx_ = nullptr; grpc_credentials_metadata_request* metadata_req_ = nullptr; grpc_iomgr_cb_func response_cb_ = nullptr; diff --git a/src/core/lib/security/credentials/external/url_external_account_credentials.cc b/src/core/lib/security/credentials/external/url_external_account_credentials.cc index 5f7adf3ff5c..b1a0512a01e 100644 --- a/src/core/lib/security/credentials/external/url_external_account_credentials.cc +++ b/src/core/lib/security/credentials/external/url_external_account_credentials.cc @@ -21,6 +21,9 @@ #include "absl/strings/str_format.h" #include "absl/strings/str_split.h" +#include "src/core/lib/http/httpcli_ssl_credentials.h" +#include "src/core/lib/transport/error_utils.h" + namespace grpc_core { RefCountedPtr @@ -120,31 +123,48 @@ void UrlExternalAccountCredentials::RetrieveSubjectToken( "Missing HTTPRequestContext to start subject token retrieval.")); return; } + auto url_for_request = + URI::Create(url_.scheme(), url_.authority(), url_full_path_, + {} /* query params */, "" /* fragment */); + if (!url_for_request.ok()) { + FinishRetrieveSubjectToken( + "", absl_status_to_grpc_error(url_for_request.status())); + return; + } ctx_ = ctx; cb_ = cb; - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(url_.authority().c_str()); - request.http.path = gpr_strdup(url_full_path_.c_str()); + grpc_http_request request; + memset(&request, 0, sizeof(grpc_http_request)); + request.path = gpr_strdup(url_full_path_.c_str()); grpc_http_header* headers = nullptr; - request.http.hdr_count = headers_.size(); + request.hdr_count = headers_.size(); headers = static_cast( - gpr_malloc(sizeof(grpc_http_header) * request.http.hdr_count)); + gpr_malloc(sizeof(grpc_http_header) * request.hdr_count)); int i = 0; for (auto const& header : headers_) { headers[i].key = gpr_strdup(header.first.c_str()); headers[i].value = gpr_strdup(header.second.c_str()); ++i; } - request.http.hdrs = headers; - request.handshaker = - url_.scheme() == "https" ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext; + request.hdrs = headers; grpc_http_response_destroy(&ctx_->response); ctx_->response = {}; GRPC_CLOSURE_INIT(&ctx_->closure, OnRetrieveSubjectToken, this, nullptr); - grpc_httpcli_get(ctx_->pollent, ResourceQuota::Default(), &request, - ctx_->deadline, &ctx_->closure, &ctx_->response); - grpc_http_request_destroy(&request.http); + GPR_ASSERT(http_request_ == nullptr); + RefCountedPtr http_request_creds; + if (url_.scheme() == "http") { + http_request_creds = RefCountedPtr( + grpc_insecure_credentials_create()); + } else { + http_request_creds = RefCountedPtr( + CreateHttpRequestSSLCredentials()); + } + http_request_ = + HttpRequest::Get(std::move(*url_for_request), nullptr /* channel args */, + ctx_->pollent, &request, ctx_->deadline, &ctx_->closure, + &ctx_->response, std::move(http_request_creds)); + http_request_->Start(); + grpc_http_request_destroy(&request); } void UrlExternalAccountCredentials::OnRetrieveSubjectToken( @@ -156,6 +176,7 @@ void UrlExternalAccountCredentials::OnRetrieveSubjectToken( void UrlExternalAccountCredentials::OnRetrieveSubjectTokenInternal( grpc_error_handle error) { + http_request_.reset(); if (error != GRPC_ERROR_NONE) { FinishRetrieveSubjectToken("", error); return; diff --git a/src/core/lib/security/credentials/external/url_external_account_credentials.h b/src/core/lib/security/credentials/external/url_external_account_credentials.h index eaf984c745f..ac07fca386a 100644 --- a/src/core/lib/security/credentials/external/url_external_account_credentials.h +++ b/src/core/lib/security/credentials/external/url_external_account_credentials.h @@ -51,6 +51,7 @@ class UrlExternalAccountCredentials final : public ExternalAccountCredentials { std::string format_type_; std::string format_subject_token_field_name_; + OrphanablePtr http_request_; HTTPRequestContext* ctx_ = nullptr; std::function cb_ = nullptr; }; diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.cc b/src/core/lib/security/credentials/google_default/google_default_credentials.cc index b13ba691a77..c8c47a531f5 100644 --- a/src/core/lib/security/credentials/google_default/google_default_credentials.cc +++ b/src/core/lib/security/credentials/google_default/google_default_credentials.cc @@ -171,7 +171,7 @@ static void destroy_pollset(void* p, grpc_error_handle /*e*/) { static int is_metadata_server_reachable() { metadata_server_detector detector; - grpc_httpcli_request request; + grpc_http_request request; grpc_closure destroy_closure; /* The http call is local. If it takes more than one sec, it is for sure not on compute engine. */ @@ -182,15 +182,20 @@ static int is_metadata_server_reachable() { detector.pollent = grpc_polling_entity_create_from_pollset(pollset); detector.is_done = 0; detector.success = 0; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(GRPC_COMPUTE_ENGINE_DETECTION_HOST); - request.http.path = const_cast("/"); - grpc_httpcli_get( - &detector.pollent, grpc_core::ResourceQuota::Default(), &request, + memset(&request, 0, sizeof(grpc_http_request)); + auto uri = + grpc_core::URI::Create("http", GRPC_COMPUTE_ENGINE_DETECTION_HOST, "/", + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); // params are hardcoded + auto http_request = grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, &detector.pollent, &request, grpc_core::ExecCtx::Get()->Now() + max_detection_delay, GRPC_CLOSURE_CREATE(on_metadata_server_detection_http_response, &detector, grpc_schedule_on_exec_ctx), - &detector.response); + &detector.response, + grpc_core::RefCountedPtr( + grpc_insecure_credentials_create())); + http_request->Start(); grpc_core::ExecCtx::Get()->Flush(); /* Block until we get the response. This is not ideal but this should only be called once for the lifetime of the process by the default credentials. */ @@ -206,6 +211,7 @@ static int is_metadata_server_reachable() { } } gpr_mu_unlock(g_polling_mu); + http_request.reset(); GRPC_CLOSURE_INIT(&destroy_closure, destroy_pollset, grpc_polling_entity_pollset(&detector.pollent), grpc_schedule_on_exec_ctx); diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.cc b/src/core/lib/security/credentials/jwt/jwt_verifier.cc index 7bc8726b1bd..bc29111d3a3 100644 --- a/src/core/lib/security/credentials/jwt/jwt_verifier.cc +++ b/src/core/lib/security/credentials/jwt/jwt_verifier.cc @@ -35,6 +35,7 @@ #include "src/core/lib/gpr/string.h" #include "src/core/lib/gprpp/manual_constructor.h" #include "src/core/lib/http/httpcli.h" +#include "src/core/lib/http/httpcli_ssl_credentials.h" #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/slice/b64.h" #include "src/core/lib/slice/slice_internal.h" @@ -344,6 +345,7 @@ struct verifier_cb_ctx { void* user_data; grpc_jwt_verification_done_cb user_cb; grpc_http_response responses[HTTP_RESPONSE_COUNT]; + grpc_core::OrphanablePtr http_request; }; /* Takes ownership of the header, claims and signature. */ static verifier_cb_ctx* verifier_cb_ctx_create( @@ -397,7 +399,7 @@ struct grpc_jwt_verifier { size_t allocated_mappings; }; -static Json json_from_http(const grpc_httpcli_response* response) { +static Json json_from_http(const grpc_http_response* response) { if (response == nullptr) { gpr_log(GPR_ERROR, "HTTP response is NULL."); return Json(); // JSON null @@ -666,9 +668,13 @@ static void on_openid_config_retrieved(void* user_data, verifier_cb_ctx* ctx = static_cast(user_data); const grpc_http_response* response = &ctx->responses[HTTP_RESPONSE_OPENID]; Json json = json_from_http(response); - grpc_httpcli_request req; + grpc_http_request req; + memset(&req, 0, sizeof(grpc_http_request)); const char* jwks_uri; const Json* cur; + absl::StatusOr uri; + char* host; + char* path; /* TODO(jboeuf): Cache the jwks_uri in order to avoid this hop next time. */ if (json.type() == Json::Type::JSON_NULL) goto error; @@ -684,24 +690,30 @@ static void on_openid_config_retrieved(void* user_data, goto error; } jwks_uri += 8; - req.handshaker = &grpc_httpcli_ssl; - req.host = gpr_strdup(jwks_uri); - req.http.path = const_cast(strchr(jwks_uri, '/')); - if (req.http.path == nullptr) { - req.http.path = const_cast(""); + host = gpr_strdup(jwks_uri); + path = const_cast(strchr(jwks_uri, '/')); + if (path == nullptr) { + path = const_cast(""); } else { - *(req.host + (req.http.path - jwks_uri)) = '\0'; + *(host + (path - jwks_uri)) = '\0'; } /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host channel. This would allow us to cancel an authentication query when under extreme memory pressure. */ - grpc_httpcli_get( - &ctx->pollent, grpc_core::ResourceQuota::Default(), &req, + uri = grpc_core::URI::Create("https", host, path, {} /* query params /*/, + "" /* fragment */); + if (!uri.ok()) { + goto error; + } + ctx->http_request = grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, &ctx->pollent, &req, grpc_core::ExecCtx::Get()->Now() + grpc_jwt_verifier_max_delay, GRPC_CLOSURE_CREATE(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx), - &ctx->responses[HTTP_RESPONSE_KEYS]); - gpr_free(req.host); + &ctx->responses[HTTP_RESPONSE_KEYS], + grpc_core::CreateHttpRequestSSLCredentials()); + ctx->http_request->Start(); + gpr_free(host); return; error: @@ -759,10 +771,12 @@ static void retrieve_key_and_verify(verifier_cb_ctx* ctx) { grpc_closure* http_cb; char* path_prefix = nullptr; const char* iss; - grpc_httpcli_request req; - memset(&req, 0, sizeof(grpc_httpcli_request)); - req.handshaker = &grpc_httpcli_ssl; + grpc_http_request req; + memset(&req, 0, sizeof(grpc_http_request)); http_response_index rsp_idx; + char* host; + char* path; + absl::StatusOr uri; GPR_ASSERT(ctx != nullptr && ctx->header != nullptr && ctx->claims != nullptr); @@ -790,26 +804,25 @@ static void retrieve_key_and_verify(verifier_cb_ctx* ctx) { gpr_log(GPR_ERROR, "Missing mapping for issuer email."); goto error; } - req.host = gpr_strdup(mapping->key_url_prefix); - path_prefix = strchr(req.host, '/'); + host = gpr_strdup(mapping->key_url_prefix); + path_prefix = strchr(host, '/'); if (path_prefix == nullptr) { - gpr_asprintf(&req.http.path, "/%s", iss); + gpr_asprintf(&path, "/%s", iss); } else { *(path_prefix++) = '\0'; - gpr_asprintf(&req.http.path, "/%s/%s", path_prefix, iss); + gpr_asprintf(&path, "/%s/%s", path_prefix, iss); } http_cb = GRPC_CLOSURE_CREATE(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx); rsp_idx = HTTP_RESPONSE_KEYS; } else { - req.host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss); - path_prefix = strchr(req.host, '/'); + host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss); + path_prefix = strchr(host, '/'); if (path_prefix == nullptr) { - req.http.path = gpr_strdup(GRPC_OPENID_CONFIG_URL_SUFFIX); + path = gpr_strdup(GRPC_OPENID_CONFIG_URL_SUFFIX); } else { *(path_prefix++) = 0; - gpr_asprintf(&req.http.path, "/%s%s", path_prefix, - GRPC_OPENID_CONFIG_URL_SUFFIX); + gpr_asprintf(&path, "/%s%s", path_prefix, GRPC_OPENID_CONFIG_URL_SUFFIX); } http_cb = GRPC_CLOSURE_CREATE(on_openid_config_retrieved, ctx, grpc_schedule_on_exec_ctx); @@ -819,12 +832,18 @@ static void retrieve_key_and_verify(verifier_cb_ctx* ctx) { /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host channel. This would allow us to cancel an authentication query when under extreme memory pressure. */ - grpc_httpcli_get( - &ctx->pollent, grpc_core::ResourceQuota::Default(), &req, + uri = grpc_core::URI::Create("https", host, path, {} /* query params */, + "" /* fragment */); + if (!uri.ok()) { + goto error; + } + ctx->http_request = grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, &ctx->pollent, &req, grpc_core::ExecCtx::Get()->Now() + grpc_jwt_verifier_max_delay, http_cb, - &ctx->responses[rsp_idx]); - gpr_free(req.host); - gpr_free(req.http.path); + &ctx->responses[rsp_idx], grpc_core::CreateHttpRequestSSLCredentials()); + ctx->http_request->Start(); + gpr_free(host); + gpr_free(path); return; error: diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc index 9fa1508820e..d712866dc3a 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc @@ -36,6 +36,7 @@ #include "src/core/lib/gpr/string.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" @@ -269,7 +270,7 @@ void grpc_oauth2_token_fetcher_credentials::on_http_response( gpr_free(prev); } Unref(); - grpc_credentials_metadata_request_destroy(r); + delete r; } bool grpc_oauth2_token_fetcher_credentials::get_request_metadata( @@ -315,8 +316,8 @@ bool grpc_oauth2_token_fetcher_credentials::get_request_metadata( gpr_mu_unlock(&mu_); if (start_fetch) { Ref().release(); - fetch_oauth2(grpc_credentials_metadata_request_create(this->Ref()), - &pollent_, on_oauth2_token_fetcher_http_response, + fetch_oauth2(new grpc_credentials_metadata_request(this->Ref()), &pollent_, + on_oauth2_token_fetcher_http_response, grpc_core::ExecCtx::Get()->Now() + refresh_threshold); } return false; @@ -380,21 +381,26 @@ class grpc_compute_engine_token_fetcher_credentials grpc_millis deadline) override { grpc_http_header header = {const_cast("Metadata-Flavor"), const_cast("Google")}; - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(GRPC_COMPUTE_ENGINE_METADATA_HOST); - request.http.path = - const_cast(GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH); - request.http.hdr_count = 1; - request.http.hdrs = &header; + grpc_http_request request; + memset(&request, 0, sizeof(grpc_http_request)); + request.hdr_count = 1; + request.hdrs = &header; /* TODO(ctiller): Carry the memory quota in ctx and share it with the host channel. This would allow us to cancel an authentication query when under extreme memory pressure. */ - grpc_httpcli_get(pollent, grpc_core::ResourceQuota::Default(), &request, - deadline, - GRPC_CLOSURE_INIT(&http_get_cb_closure_, response_cb, - metadata_req, grpc_schedule_on_exec_ctx), - &metadata_req->response); + auto uri = grpc_core::URI::Create("http", GRPC_COMPUTE_ENGINE_METADATA_HOST, + GRPC_COMPUTE_ENGINE_METADATA_TOKEN_PATH, + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); // params are hardcoded + http_request_ = grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, pollent, &request, + deadline, + GRPC_CLOSURE_INIT(&http_get_cb_closure_, response_cb, metadata_req, + grpc_schedule_on_exec_ctx), + &metadata_req->response, + grpc_core::RefCountedPtr( + grpc_insecure_credentials_create())); + http_request_->Start(); } std::string debug_string() override { @@ -405,6 +411,7 @@ class grpc_compute_engine_token_fetcher_credentials private: grpc_closure http_get_cb_closure_; + grpc_core::OrphanablePtr http_request_; }; } // namespace @@ -435,24 +442,28 @@ void grpc_google_refresh_token_credentials::fetch_oauth2( grpc_http_header header = { const_cast("Content-Type"), const_cast("application/x-www-form-urlencoded")}; - grpc_httpcli_request request; + grpc_http_request request; std::string body = absl::StrFormat( GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING, refresh_token_.client_id, refresh_token_.client_secret, refresh_token_.refresh_token); - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(GRPC_GOOGLE_OAUTH2_SERVICE_HOST); - request.http.path = const_cast(GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH); - request.http.hdr_count = 1; - request.http.hdrs = &header; - request.handshaker = &grpc_httpcli_ssl; + memset(&request, 0, sizeof(grpc_http_request)); + request.hdr_count = 1; + request.hdrs = &header; + request.body = const_cast(body.c_str()); + request.body_length = body.size(); /* TODO(ctiller): Carry the memory quota in ctx and share it with the host channel. This would allow us to cancel an authentication query when under extreme memory pressure. */ - grpc_httpcli_post(pollent, grpc_core::ResourceQuota::Default(), &request, - body.c_str(), body.size(), deadline, - GRPC_CLOSURE_INIT(&http_post_cb_closure_, response_cb, - metadata_req, grpc_schedule_on_exec_ctx), - &metadata_req->response); + auto uri = grpc_core::URI::Create("https", GRPC_GOOGLE_OAUTH2_SERVICE_HOST, + GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH, + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); // params are hardcoded + http_request_ = grpc_core::HttpRequest::Post( + std::move(*uri), nullptr /* channel args */, pollent, &request, deadline, + GRPC_CLOSURE_INIT(&http_post_cb_closure_, response_cb, metadata_req, + grpc_schedule_on_exec_ctx), + &metadata_req->response, grpc_core::CreateHttpRequestSSLCredentials()); + http_request_->Start(); } grpc_google_refresh_token_credentials::grpc_google_refresh_token_credentials( @@ -553,9 +564,9 @@ class StsTokenFetcherCredentials grpc_polling_entity* pollent, grpc_iomgr_cb_func response_cb, grpc_millis deadline) override { - char* body = nullptr; - size_t body_length = 0; - grpc_error_handle err = FillBody(&body, &body_length); + grpc_http_request request; + memset(&request, 0, sizeof(grpc_http_request)); + grpc_error_handle err = FillBody(&request.body, &request.body_length); if (err != GRPC_ERROR_NONE) { response_cb(metadata_req, err); GRPC_ERROR_UNREF(err); @@ -564,25 +575,25 @@ class StsTokenFetcherCredentials grpc_http_header header = { const_cast("Content-Type"), const_cast("application/x-www-form-urlencoded")}; - grpc_httpcli_request request; - memset(&request, 0, sizeof(grpc_httpcli_request)); - request.host = const_cast(sts_url_.authority().c_str()); - request.http.path = const_cast(sts_url_.path().c_str()); - request.http.hdr_count = 1; - request.http.hdrs = &header; - request.handshaker = (sts_url_.scheme() == "https") - ? &grpc_httpcli_ssl - : &grpc_httpcli_plaintext; + request.hdr_count = 1; + request.hdrs = &header; /* TODO(ctiller): Carry the memory quota in ctx and share it with the host channel. This would allow us to cancel an authentication query when under extreme memory pressure. */ - grpc_httpcli_post( - pollent, ResourceQuota::Default(), &request, body, body_length, - deadline, + RefCountedPtr http_request_creds; + if (sts_url_.scheme() == "http") { + http_request_creds = RefCountedPtr( + grpc_insecure_credentials_create()); + } else { + http_request_creds = CreateHttpRequestSSLCredentials(); + } + http_request_ = HttpRequest::Post( + sts_url_, nullptr /* channel args */, pollent, &request, deadline, GRPC_CLOSURE_INIT(&http_post_cb_closure_, response_cb, metadata_req, grpc_schedule_on_exec_ctx), - &metadata_req->response); - gpr_free(body); + &metadata_req->response, std::move(http_request_creds)); + http_request_->Start(); + gpr_free(request.body); } grpc_error_handle FillBody(char** body, size_t* body_length) { @@ -637,6 +648,7 @@ class StsTokenFetcherCredentials UniquePtr subject_token_type_; UniquePtr actor_token_path_; UniquePtr actor_token_type_; + OrphanablePtr http_request_; }; } // namespace diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h index a3676c7b822..beb8168bdf5 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.h +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.h @@ -25,6 +25,7 @@ #include +#include "src/core/lib/http/httpcli.h" #include "src/core/lib/json/json.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/uri/uri_parser.h" @@ -58,10 +59,19 @@ grpc_auth_refresh_token grpc_auth_refresh_token_create_from_json( /// Destructs the object. void grpc_auth_refresh_token_destruct(grpc_auth_refresh_token* refresh_token); -// -- Oauth2 Token Fetcher credentials -- -// -// This object is a base for credentials that need to acquire an oauth2 token -// from an http service. +// -- Credentials Metadata Request. -- + +struct grpc_credentials_metadata_request { + explicit grpc_credentials_metadata_request( + grpc_core::RefCountedPtr creds) + : creds(std::move(creds)) {} + ~grpc_credentials_metadata_request() { + grpc_http_response_destroy(&response); + } + + grpc_core::RefCountedPtr creds; + grpc_http_response response; +}; struct grpc_oauth2_pending_get_request_metadata { grpc_core::CredentialsMetadataArray* md_array; @@ -70,6 +80,11 @@ struct grpc_oauth2_pending_get_request_metadata { struct grpc_oauth2_pending_get_request_metadata* next; }; +// -- Oauth2 Token Fetcher credentials -- +// +// This object is a base for credentials that need to acquire an oauth2 token +// from an http service. + class grpc_oauth2_token_fetcher_credentials : public grpc_call_credentials { public: grpc_oauth2_token_fetcher_credentials(); @@ -125,6 +140,7 @@ class grpc_google_refresh_token_credentials final private: grpc_auth_refresh_token refresh_token_; grpc_closure http_post_cb_closure_; + grpc_core::OrphanablePtr http_request_; }; // Access token credentials. diff --git a/src/core/lib/surface/init.cc b/src/core/lib/surface/init.cc index 191ef4f0610..b1fe8e2e709 100644 --- a/src/core/lib/surface/init.cc +++ b/src/core/lib/surface/init.cc @@ -36,7 +36,6 @@ #include "src/core/lib/debug/trace.h" #include "src/core/lib/gprpp/fork.h" #include "src/core/lib/gprpp/sync.h" -#include "src/core/lib/http/parser.h" #include "src/core/lib/iomgr/call_combiner.h" #include "src/core/lib/iomgr/combiner.h" #include "src/core/lib/iomgr/exec_ctx.h" diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h index b3bde234a94..630bef321cf 100644 --- a/src/cpp/client/secure_credentials.h +++ b/src/cpp/client/secure_credentials.h @@ -37,6 +37,7 @@ class SecureChannelCredentials final : public ChannelCredentials { public: explicit SecureChannelCredentials(grpc_channel_credentials* c_creds); ~SecureChannelCredentials() override { + grpc_core::ExecCtx exec_ctx; if (c_creds_ != nullptr) c_creds_->Unref(); } grpc_channel_credentials* GetRawCreds() { return c_creds_; } @@ -59,6 +60,7 @@ class SecureCallCredentials final : public CallCredentials { public: explicit SecureCallCredentials(grpc_call_credentials* c_creds); ~SecureCallCredentials() override { + grpc_core::ExecCtx exec_ctx; if (c_creds_ != nullptr) c_creds_->Unref(); } grpc_call_credentials* GetRawCreds() { return c_creds_; } diff --git a/test/core/http/BUILD b/test/core/http/BUILD index 86852b1f1c2..ccf44e3ee17 100644 --- a/test/core/http/BUILD +++ b/test/core/http/BUILD @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package") +load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package") load("//test/core/util:grpc_fuzzer.bzl", "grpc_fuzzer") grpc_package(name = "test/core/http") @@ -61,6 +61,18 @@ grpc_fuzzer( licenses(["notice"]) +grpc_cc_library( + name = "httpcli_test_util", + testonly = True, + srcs = ["httpcli_test_util.cc"], + hdrs = ["httpcli_test_util.h"], + deps = [ + "//:gpr", + "//test/core/end2end:ssl_test_data", + "//test/core/util:grpc_test_util", + ], +) + grpc_cc_test( name = "httpcli_test", srcs = ["httpcli_test.cc"], @@ -70,13 +82,17 @@ grpc_cc_test( "//src/core/tsi/test_creds:server1.key", "//src/core/tsi/test_creds:server1.pem", ], + external_deps = ["gtest"], language = "C++", tags = ["no_windows"], deps = [ + ":httpcli_test_util", "//:gpr", "//:grpc", "//test/core/end2end:ssl_test_data", + "//test/core/util:fake_udp_and_tcp_server", "//test/core/util:grpc_test_util", + "//test/cpp/util:test_util", ], ) @@ -90,13 +106,17 @@ grpc_cc_test( "//src/core/tsi/test_creds:server1.key", "//src/core/tsi/test_creds:server1.pem", ], + external_deps = ["gtest"], language = "C++", tags = ["no_windows"], deps = [ + ":httpcli_test_util", "//:gpr", "//:grpc", "//test/core/end2end:ssl_test_data", + "//test/core/util:fake_udp_and_tcp_server", "//test/core/util:grpc_test_util", + "//test/cpp/util:test_util", ], ) diff --git a/test/core/http/format_request_test.cc b/test/core/http/format_request_test.cc index 24ee0014841..fd64f8723e6 100644 --- a/test/core/http/format_request_test.cc +++ b/test/core/http/format_request_test.cc @@ -27,16 +27,15 @@ static void test_format_get_request(void) { grpc_http_header hdr = {const_cast("x-yz"), const_cast("abc")}; - grpc_httpcli_request req; + grpc_http_request req; grpc_slice slice; + const char* host = "example.com"; memset(&req, 0, sizeof(req)); - req.host = const_cast("example.com"); - req.http.path = const_cast("/index.html"); - req.http.hdr_count = 1; - req.http.hdrs = &hdr; + req.hdr_count = 1; + req.hdrs = &hdr; - slice = grpc_httpcli_format_get_request(&req); + slice = grpc_httpcli_format_get_request(&req, host, "/index.html"); GPR_ASSERT(0 == grpc_slice_str_cmp(slice, "GET /index.html HTTP/1.0\r\n" @@ -52,18 +51,17 @@ static void test_format_get_request(void) { static void test_format_post_request(void) { grpc_http_header hdr = {const_cast("x-yz"), const_cast("abc")}; - grpc_httpcli_request req; + grpc_http_request req; grpc_slice slice; - char body_bytes[] = "fake body"; - size_t body_len = 9; + const char* host = "example.com"; memset(&req, 0, sizeof(req)); - req.host = const_cast("example.com"); - req.http.path = const_cast("/index.html"); - req.http.hdr_count = 1; - req.http.hdrs = &hdr; + req.hdr_count = 1; + req.hdrs = &hdr; + req.body = const_cast("fake body"); + req.body_length = 9; - slice = grpc_httpcli_format_post_request(&req, body_bytes, body_len); + slice = grpc_httpcli_format_post_request(&req, host, "/index.html"); GPR_ASSERT(0 == grpc_slice_str_cmp(slice, "POST /index.html HTTP/1.0\r\n" @@ -82,16 +80,15 @@ static void test_format_post_request(void) { static void test_format_post_request_no_body(void) { grpc_http_header hdr = {const_cast("x-yz"), const_cast("abc")}; - grpc_httpcli_request req; + grpc_http_request req; grpc_slice slice; + const char* host = "example.com"; memset(&req, 0, sizeof(req)); - req.host = const_cast("example.com"); - req.http.path = const_cast("/index.html"); - req.http.hdr_count = 1; - req.http.hdrs = &hdr; + req.hdr_count = 1; + req.hdrs = &hdr; - slice = grpc_httpcli_format_post_request(&req, nullptr, 0); + slice = grpc_httpcli_format_post_request(&req, host, "/index.html"); GPR_ASSERT(0 == grpc_slice_str_cmp(slice, "POST /index.html HTTP/1.0\r\n" @@ -107,22 +104,21 @@ static void test_format_post_request_no_body(void) { static void test_format_post_request_content_type_override(void) { grpc_http_header hdrs[2]; - grpc_httpcli_request req; + grpc_http_request req; grpc_slice slice; - char body_bytes[] = "fake%20body"; - size_t body_len = 11; + const char* host = "example.com"; hdrs[0].key = const_cast("x-yz"); hdrs[0].value = const_cast("abc"); hdrs[1].key = const_cast("Content-Type"); hdrs[1].value = const_cast("application/x-www-form-urlencoded"); memset(&req, 0, sizeof(req)); - req.host = const_cast("example.com"); - req.http.path = const_cast("/index.html"); - req.http.hdr_count = 2; - req.http.hdrs = hdrs; + req.hdr_count = 2; + req.hdrs = hdrs; + req.body = const_cast("fake%20body"); + req.body_length = 11; - slice = grpc_httpcli_format_post_request(&req, body_bytes, body_len); + slice = grpc_httpcli_format_post_request(&req, host, "/index.html"); GPR_ASSERT(0 == grpc_slice_str_cmp( slice, diff --git a/test/core/http/httpcli_test.cc b/test/core/http/httpcli_test.cc index 75fe78f59aa..714605ff363 100644 --- a/test/core/http/httpcli_test.cc +++ b/test/core/http/httpcli_test.cc @@ -20,194 +20,458 @@ #include +#include +#include + #include #include #include #include #include +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/lib/iomgr/iomgr.h" +#include "test/core/http/httpcli_test_util.h" +#include "test/core/util/fake_udp_and_tcp_server.h" #include "test/core/util/port.h" #include "test/core/util/subprocess.h" #include "test/core/util/test_config.h" -static int g_done = 0; -static gpr_mu* g_mu; -static grpc_polling_entity g_pops; +namespace { -static grpc_millis n_seconds_time(int seconds) { +grpc_millis NSecondsTime(int seconds) { return grpc_timespec_to_millis_round_up( grpc_timeout_seconds_to_deadline(seconds)); } -static void on_finish(void* arg, grpc_error_handle error) { - const char* expect = - "Hello world!" - "

This is a test

"; - grpc_http_response* response = static_cast(arg); - GPR_ASSERT(response); - gpr_log(GPR_INFO, "response status=%d error=%s", response->status, - grpc_error_std_string(error).c_str()); - GPR_ASSERT(response->status == 200); - GPR_ASSERT(response->body_length == strlen(expect)); - GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length)); - gpr_mu_lock(g_mu); - g_done = 1; - GPR_ASSERT(GRPC_LOG_IF_ERROR( - "pollset_kick", - grpc_pollset_kick(grpc_polling_entity_pollset(&g_pops), nullptr))); - gpr_mu_unlock(g_mu); +absl::Time AbslDeadlineSeconds(int s) { + return grpc_core::ToAbslTime(grpc_timeout_seconds_to_deadline(s)); } -static void test_get(int port) { - grpc_httpcli_request req; - char* host; - grpc_core::ExecCtx exec_ctx; - - g_done = 0; - gpr_log(GPR_INFO, "test_get"); +int g_argc; +char** g_argv; +int g_server_port; +gpr_subprocess* g_server; - gpr_asprintf(&host, "localhost:%d", port); - gpr_log(GPR_INFO, "requesting from %s", host); +class HttpRequestTest : public ::testing::Test { + public: + HttpRequestTest() { + grpc_init(); + grpc_core::ExecCtx exec_ctx; + grpc_pollset* pollset = + static_cast(gpr_zalloc(grpc_pollset_size())); + grpc_pollset_init(pollset, &mu_); + pops_ = grpc_polling_entity_create_from_pollset(pollset); + } + ~HttpRequestTest() override { + { + grpc_core::ExecCtx exec_ctx; + grpc_pollset_shutdown( + grpc_polling_entity_pollset(&pops_), + GRPC_CLOSURE_CREATE(DestroyPops, &pops_, grpc_schedule_on_exec_ctx)); + } + grpc_shutdown(); + } - memset(&req, 0, sizeof(req)); - req.host = host; - req.http.path = const_cast("/get"); - req.handshaker = &grpc_httpcli_plaintext; - - grpc_http_response response; - response = {}; - grpc_httpcli_get( - &g_pops, grpc_core::ResourceQuota::Default(), &req, n_seconds_time(15), - GRPC_CLOSURE_CREATE(on_finish, &response, grpc_schedule_on_exec_ctx), - &response); - gpr_mu_lock(g_mu); - while (!g_done) { - grpc_pollset_worker* worker = nullptr; + void RunAndKick(const std::function& f) { + grpc_core::MutexLockForGprMu lock(mu_); + f(); GPR_ASSERT(GRPC_LOG_IF_ERROR( - "pollset_work", grpc_pollset_work(grpc_polling_entity_pollset(&g_pops), - &worker, n_seconds_time(1)))); - gpr_mu_unlock(g_mu); + "pollset_kick", + grpc_pollset_kick(grpc_polling_entity_pollset(&pops_), nullptr))); + } - gpr_mu_lock(g_mu); + void PollUntil(const std::function& predicate, absl::Time deadline) { + gpr_mu_lock(mu_); + while (!predicate()) { + GPR_ASSERT(absl::Now() < deadline); + grpc_pollset_worker* worker = nullptr; + GPR_ASSERT(GRPC_LOG_IF_ERROR( + "pollset_work", grpc_pollset_work(grpc_polling_entity_pollset(&pops_), + &worker, NSecondsTime(1)))); + gpr_mu_unlock(mu_); + gpr_mu_lock(mu_); + } + gpr_mu_unlock(mu_); } - gpr_mu_unlock(g_mu); - gpr_free(host); - grpc_http_response_destroy(&response); -} -static void test_post(int port) { - grpc_httpcli_request req; - char* host; - grpc_core::ExecCtx exec_ctx; + grpc_polling_entity* pops() { return &pops_; } - g_done = 0; - gpr_log(GPR_INFO, "test_post"); + protected: + static void SetUpTestSuite() { + auto test_server = grpc_core::testing::StartHttpRequestTestServer( + g_argc, g_argv, false /* use_ssl */); + g_server = test_server.server; + g_server_port = test_server.port; + } - gpr_asprintf(&host, "localhost:%d", port); - gpr_log(GPR_INFO, "posting to %s", host); + static void TearDownTestSuite() { gpr_subprocess_destroy(g_server); } - memset(&req, 0, sizeof(req)); - req.host = host; - req.http.path = const_cast("/post"); - req.handshaker = &grpc_httpcli_plaintext; - - grpc_http_response response; - response = {}; - grpc_httpcli_post( - &g_pops, grpc_core::ResourceQuota::Default(), &req, "hello", 5, - n_seconds_time(15), - GRPC_CLOSURE_CREATE(on_finish, &response, grpc_schedule_on_exec_ctx), - &response); - gpr_mu_lock(g_mu); - while (!g_done) { - grpc_pollset_worker* worker = nullptr; - GPR_ASSERT(GRPC_LOG_IF_ERROR( - "pollset_work", grpc_pollset_work(grpc_polling_entity_pollset(&g_pops), - &worker, n_seconds_time(1)))); - gpr_mu_unlock(g_mu); + private: + static void DestroyPops(void* p, grpc_error_handle /*error*/) { + grpc_polling_entity* pops = static_cast(p); + grpc_pollset_destroy(grpc_polling_entity_pollset(pops)); + gpr_free(grpc_polling_entity_pollset(pops)); + } + + gpr_mu* mu_; + grpc_polling_entity pops_; +}; + +struct RequestState { + explicit RequestState(HttpRequestTest* test) : test(test) {} - gpr_mu_lock(g_mu); + ~RequestState() { + grpc_core::ExecCtx exec_ctx; + grpc_http_response_destroy(&response); + } + + HttpRequestTest* test; + bool done = false; + grpc_http_response response = {}; + grpc_pollset_set* pollset_set_to_destroy_eagerly = nullptr; +}; + +void OnFinish(void* arg, grpc_error_handle error) { + RequestState* request_state = static_cast(arg); + if (request_state->pollset_set_to_destroy_eagerly != nullptr) { + // Destroy the request's polling entity param. The goal is to try to catch a + // bug where we might still be referencing the polling entity by + // a pending TCP connect. + grpc_pollset_set_destroy(request_state->pollset_set_to_destroy_eagerly); } - gpr_mu_unlock(g_mu); - gpr_free(host); - grpc_http_response_destroy(&response); + const char* expect = + "Hello world!" + "

This is a test

"; + GPR_ASSERT(error == GRPC_ERROR_NONE); + grpc_http_response response = request_state->response; + gpr_log(GPR_INFO, "response status=%d error=%s", response.status, + grpc_error_std_string(error).c_str()); + GPR_ASSERT(response.status == 200); + GPR_ASSERT(response.body_length == strlen(expect)); + GPR_ASSERT(0 == memcmp(expect, response.body, response.body_length)); + request_state->test->RunAndKick( + [request_state]() { request_state->done = true; }); } -static void destroy_pops(void* p, grpc_error_handle /*error*/) { - grpc_pollset_destroy( - grpc_polling_entity_pollset(static_cast(p))); +void OnFinishExpectFailure(void* arg, grpc_error_handle error) { + RequestState* request_state = static_cast(arg); + if (request_state->pollset_set_to_destroy_eagerly != nullptr) { + // Destroy the request's polling entity param. The goal is to try to catch a + // bug where we might still be referencing the polling entity by + // a pending TCP connect. + grpc_pollset_set_destroy(request_state->pollset_set_to_destroy_eagerly); + } + grpc_http_response response = request_state->response; + gpr_log(GPR_INFO, "response status=%d error=%s", response.status, + grpc_error_std_string(error).c_str()); + GPR_ASSERT(error != GRPC_ERROR_NONE); + request_state->test->RunAndKick( + [request_state]() { request_state->done = true; }); } -int main(int argc, char** argv) { - gpr_subprocess* server; - grpc::testing::TestEnvironment env(argc, argv); - grpc_init(); - { - grpc_closure destroyed; - grpc_core::ExecCtx exec_ctx; - char* me = argv[0]; - char* lslash = strrchr(me, '/'); - char* args[4]; - int port = grpc_pick_unused_port_or_die(); - int arg_shift = 0; - /* figure out where we are */ - char* root; - if (lslash != nullptr) { - /* Hack for bazel target */ - if (static_cast(lslash - me) >= (sizeof("http") - 1) && - strncmp(me + (lslash - me) - sizeof("http") + 1, "http", - sizeof("http") - 1) == 0) { - lslash = me + (lslash - me) - sizeof("http"); - } - root = static_cast( - gpr_malloc(static_cast(lslash - me + sizeof("/../..")))); - memcpy(root, me, static_cast(lslash - me)); - memcpy(root + (lslash - me), "/../..", sizeof("/../..")); - } else { - root = gpr_strdup("."); - } +TEST_F(HttpRequestTest, Get) { + RequestState request_state(this); + grpc_http_request req; + grpc_core::ExecCtx exec_ctx; + std::string host = absl::StrFormat("localhost:%d", g_server_port); + gpr_log(GPR_INFO, "requesting from %s", host.c_str()); + memset(&req, 0, sizeof(req)); + auto uri = grpc_core::URI::Create("http", host, "/get", {} /* query params */, + "" /* fragment */); + GPR_ASSERT(uri.ok()); + grpc_core::OrphanablePtr http_request = + grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, pops(), &req, + NSecondsTime(15), + GRPC_CLOSURE_CREATE(OnFinish, &request_state, + grpc_schedule_on_exec_ctx), + &request_state.response, + grpc_core::RefCountedPtr( + grpc_insecure_credentials_create())); + http_request->Start(); + PollUntil([&request_state]() { return request_state.done; }, + AbslDeadlineSeconds(60)); +} - GPR_ASSERT(argc <= 2); - if (argc == 2) { - args[0] = gpr_strdup(argv[1]); - } else { - arg_shift = 1; - gpr_asprintf(&args[0], "%s/test/core/http/python_wrapper.sh", root); - gpr_asprintf(&args[1], "%s/test/core/http/test_server.py", root); - } +TEST_F(HttpRequestTest, Post) { + RequestState request_state(this); + grpc_http_request req; + grpc_core::ExecCtx exec_ctx; + std::string host = absl::StrFormat("localhost:%d", g_server_port); + gpr_log(GPR_INFO, "posting to %s", host.c_str()); + memset(&req, 0, sizeof(req)); + req.body = const_cast("hello"); + req.body_length = 5; + auto uri = grpc_core::URI::Create("http", host, "/post", + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); + grpc_core::OrphanablePtr http_request = + grpc_core::HttpRequest::Post( + std::move(*uri), nullptr /* channel args */, pops(), &req, + NSecondsTime(15), + GRPC_CLOSURE_CREATE(OnFinish, &request_state, + grpc_schedule_on_exec_ctx), + &request_state.response, + grpc_core::RefCountedPtr( + grpc_insecure_credentials_create())); + http_request->Start(); + PollUntil([&request_state]() { return request_state.done; }, + AbslDeadlineSeconds(60)); +} - /* start the server */ - args[1 + arg_shift] = const_cast("--port"); - gpr_asprintf(&args[2 + arg_shift], "%d", port); - server = - gpr_subprocess_create(3 + arg_shift, const_cast(args)); - GPR_ASSERT(server); - gpr_free(args[0]); - if (arg_shift) gpr_free(args[1]); - gpr_free(args[2 + arg_shift]); - gpr_free(root); +int g_fake_non_responsive_dns_server_port; - gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_seconds(5, GPR_TIMESPAN))); +void InjectNonResponsiveDNSServer(ares_channel channel) { + gpr_log(GPR_DEBUG, + "Injecting broken nameserver list. Bad server address:|[::1]:%d|.", + g_fake_non_responsive_dns_server_port); + // Configure a non-responsive DNS server at the front of c-ares's nameserver + // list. + struct ares_addr_port_node dns_server_addrs[1]; + dns_server_addrs[0].family = AF_INET6; + (reinterpret_cast(&dns_server_addrs[0].addr.addr6))[15] = 0x1; + dns_server_addrs[0].tcp_port = g_fake_non_responsive_dns_server_port; + dns_server_addrs[0].udp_port = g_fake_non_responsive_dns_server_port; + dns_server_addrs[0].next = nullptr; + GPR_ASSERT(ares_set_servers_ports(channel, dns_server_addrs) == ARES_SUCCESS); +} - grpc_pollset* pollset = - static_cast(gpr_zalloc(grpc_pollset_size())); - grpc_pollset_init(pollset, &g_mu); - g_pops = grpc_polling_entity_create_from_pollset(pollset); +TEST_F(HttpRequestTest, CancelGetDuringDNSResolution) { + // Inject an unresponsive DNS server into the resolver's DNS server config + grpc_core::testing::FakeUdpAndTcpServer fake_dns_server( + grpc_core::testing::FakeUdpAndTcpServer::AcceptMode:: + kWaitForClientToSendFirstBytes, + grpc_core::testing::FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer); + g_fake_non_responsive_dns_server_port = fake_dns_server.port(); + void (*prev_test_only_inject_config)(ares_channel channel) = + grpc_ares_test_only_inject_config; + grpc_ares_test_only_inject_config = InjectNonResponsiveDNSServer; + // Run the same test on several threads in parallel to try to trigger races + // etc. + int kNumThreads = 100; + std::vector threads; + threads.reserve(kNumThreads); + for (int i = 0; i < kNumThreads; i++) { + threads.push_back(std::thread([this]() { + RequestState request_state(this); + grpc_http_request req; + grpc_core::ExecCtx exec_ctx; + memset(&req, 0, sizeof(grpc_http_request)); + auto uri = grpc_core::URI::Create( + "http", "dont-care-since-wont-be-resolved.test.com:443", "/get", + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); + grpc_core::OrphanablePtr http_request = + grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, pops(), &req, + NSecondsTime(120), + GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state, + grpc_schedule_on_exec_ctx), + &request_state.response, + grpc_core::RefCountedPtr( + grpc_insecure_credentials_create())); + http_request->Start(); + std::thread cancel_thread([&http_request]() { + gpr_sleep_until(grpc_timeout_seconds_to_deadline(1)); + grpc_core::ExecCtx exec_ctx; + http_request.reset(); + }); + // Poll with a deadline explicitly lower than the request timeout, so + // that we know that the request timeout isn't just kicking in. + PollUntil([&request_state]() { return request_state.done; }, + AbslDeadlineSeconds(60)); + cancel_thread.join(); + })); + } + for (auto& t : threads) { + t.join(); + } + grpc_ares_test_only_inject_config = prev_test_only_inject_config; +} - test_get(port); - test_post(port); +TEST_F(HttpRequestTest, CancelGetWhileReadingResponse) { + // Start up a fake HTTP server which just accepts connections + // and then hangs, i.e. does not send back any bytes to the client. + // The goal here is to get the client to connect to this fake server + // and send a request, and then sit waiting for a response. Then, a + // separate thread will cancel the HTTP request, and that should let it + // complete. + grpc_core::testing::FakeUdpAndTcpServer fake_http_server( + grpc_core::testing::FakeUdpAndTcpServer::AcceptMode:: + kWaitForClientToSendFirstBytes, + grpc_core::testing::FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer); + // Run the same test on several threads in parallel to try to trigger races + // etc. + int kNumThreads = 100; + std::vector threads; + threads.reserve(kNumThreads); + for (int i = 0; i < kNumThreads; i++) { + grpc_core::testing::FakeUdpAndTcpServer* fake_http_server_ptr = + &fake_http_server; + threads.push_back(std::thread([this, fake_http_server_ptr]() { + RequestState request_state(this); + grpc_http_request req; + grpc_core::ExecCtx exec_ctx; + memset(&req, 0, sizeof(req)); + auto uri = grpc_core::URI::Create("http", fake_http_server_ptr->address(), + "/get", {} /* query params */, + "" /* fragment */); + GPR_ASSERT(uri.ok()); + grpc_core::OrphanablePtr http_request = + grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, pops(), &req, + NSecondsTime(120), + GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state, + grpc_schedule_on_exec_ctx), + &request_state.response, + grpc_core::RefCountedPtr( + grpc_insecure_credentials_create())); + http_request->Start(); + exec_ctx.Flush(); + std::thread cancel_thread([&http_request]() { + gpr_sleep_until(grpc_timeout_seconds_to_deadline(1)); + grpc_core::ExecCtx exec_ctx; + http_request.reset(); + }); + // Poll with a deadline explicitly lower than the request timeout, so + // that we know that the request timeout isn't just kicking in. + PollUntil([&request_state]() { return request_state.done; }, + AbslDeadlineSeconds(60)); + cancel_thread.join(); + })); + } + for (auto& t : threads) { + t.join(); + } +} - GRPC_CLOSURE_INIT(&destroyed, destroy_pops, &g_pops, - grpc_schedule_on_exec_ctx); - grpc_pollset_shutdown(grpc_polling_entity_pollset(&g_pops), &destroyed); +// The main point of this test is just to exercise the machinery around +// cancellation during TCP connection establishment, to make sure there are no +// crashes/races etc. This test doesn't actually verify that cancellation during +// TCP setup is happening, though. For that, we would need to induce packet loss +// in the test. +TEST_F(HttpRequestTest, CancelGetRacesWithConnectionFailure) { + // Grab an unoccupied port but don't listen on it. The goal + // here is just to have a server address that will reject + // TCP connection setups. + // Note that because the server is rejecting TCP connections, we + // don't really need to cancel the HTTP requests in this test case + // in order for them proceeed i.e. in order for them to pass. The test + // is still beneficial though because it can exercise the same code paths + // that would get taken if the HTTP request was cancelled while the TCP + // connect attempt was actually hanging. + int fake_server_port = grpc_pick_unused_port_or_die(); + std::string fake_server_address = + absl::StrCat("[::1]:", std::to_string(fake_server_port)); + // Run the same test on several threads in parallel to try to trigger races + // etc. + int kNumThreads = 100; + std::vector threads; + threads.reserve(kNumThreads); + for (int i = 0; i < kNumThreads; i++) { + threads.push_back(std::thread([this, fake_server_address]() { + RequestState request_state(this); + grpc_http_request req; + grpc_core::ExecCtx exec_ctx; + memset(&req, 0, sizeof(req)); + auto uri = + grpc_core::URI::Create("http", fake_server_address, "/get", + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); + grpc_core::OrphanablePtr http_request = + grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, pops(), &req, + NSecondsTime(120), + GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state, + grpc_schedule_on_exec_ctx), + &request_state.response, + grpc_core::RefCountedPtr( + grpc_insecure_credentials_create())); + // Start the HTTP request. We will ~immediately begin a TCP connect + // attempt because there's no name to resolve. + http_request->Start(); + exec_ctx.Flush(); + // Spawn a separate thread which ~immediately cancels the HTTP request. + // Note that even though the server is rejecting TCP connections, it can + // still take some time for the client to receive that rejection. So + // cancelling the request now can trigger the code paths that would get + // taken if the TCP connection was truly hanging e.g. from packet loss. + // The goal is just to make sure there are no crashes, races, etc. + std::thread cancel_thread([&http_request]() { + grpc_core::ExecCtx exec_ctx; + http_request.reset(); + }); + // Poll with a deadline explicitly lower than the request timeout, so + // that we know that the request timeout isn't just kicking in. + PollUntil([&request_state]() { return request_state.done; }, + AbslDeadlineSeconds(60)); + cancel_thread.join(); + })); } - grpc_shutdown(); + for (auto& t : threads) { + t.join(); + } +} - gpr_free(grpc_polling_entity_pollset(&g_pops)); +// The pollent parameter passed to HttpRequest::Get or Post is owned by +// the caller and must not be referenced by the HttpRequest after the +// requests's on_done callback is invoked. This test verifies that this +// isn't happening by destroying the request's pollset set within the +// on_done callback. +TEST_F(HttpRequestTest, CallerPollentsAreNotReferencedAfterCallbackIsRan) { + // Grab an unoccupied port but don't listen on it. The goal + // here is just to have a server address that will reject + // TCP connection setups. + // Note that we could have used a different server for this test case, e.g. + // one which accepts TCP connections. All we need here is something for the + // client to connect to, since it will be cancelled roughly during the + // connection attempt anyways. + int fake_server_port = grpc_pick_unused_port_or_die(); + std::string fake_server_address = + absl::StrCat("[::1]:", std::to_string(fake_server_port)); + RequestState request_state(this); + grpc_http_request req; + grpc_core::ExecCtx exec_ctx; + memset(&req, 0, sizeof(req)); + req.path = const_cast("/get"); + request_state.pollset_set_to_destroy_eagerly = grpc_pollset_set_create(); + grpc_polling_entity_add_to_pollset_set( + pops(), request_state.pollset_set_to_destroy_eagerly); + grpc_polling_entity wrapped_pollset_set_to_destroy_eagerly = + grpc_polling_entity_create_from_pollset_set( + request_state.pollset_set_to_destroy_eagerly); + auto uri = grpc_core::URI::Create("http", fake_server_address, "/get", + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); + grpc_core::OrphanablePtr http_request = + grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, + &wrapped_pollset_set_to_destroy_eagerly, &req, NSecondsTime(15), + GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state, + grpc_schedule_on_exec_ctx), + &request_state.response, + grpc_core::RefCountedPtr( + grpc_insecure_credentials_create())); + // Start the HTTP request. We'll start the TCP connect attempt right away. + http_request->Start(); + exec_ctx.Flush(); + http_request.reset(); // cancel the request + // Since the request was cancelled, the on_done callback should be flushed + // out on the ExecCtx flush below. When the on_done callback is ran, it will + // eagerly destroy 'request_state.pollset_set_to_destroy_eagerly'. Thus, we + // can't poll on that pollset here. + exec_ctx.Flush(); +} - gpr_subprocess_destroy(server); +} // namespace - return 0; +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + grpc::testing::TestEnvironment env(argc, argv); + // launch the test server later, so that --gtest_list_tests works + g_argc = argc; + g_argv = argv; + // run tests + return RUN_ALL_TESTS(); } diff --git a/test/core/http/httpcli_test_util.cc b/test/core/http/httpcli_test_util.cc new file mode 100644 index 00000000000..f7937cf7cb2 --- /dev/null +++ b/test/core/http/httpcli_test_util.cc @@ -0,0 +1,105 @@ +// +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include + +#include "test/core/http/httpcli_test_util.h" + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/lib/security/security_connector/ssl_utils_config.h" +#include "test/core/util/port.h" +#include "test/core/util/subprocess.h" +#include "test/core/util/test_config.h" + +namespace grpc_core { +namespace testing { + +HttpRequestTestServer StartHttpRequestTestServer(int argc, char** argv, + bool use_ssl) { + char* me = argv[0]; + char* lslash = strrchr(me, '/'); + std::vector args; + int server_port = grpc_pick_unused_port_or_die(); + // figure out where we are + char* root; + if (lslash != nullptr) { + // Hack for bazel target + if (static_cast(lslash - me) >= (sizeof("http") - 1) && + strncmp(me + (lslash - me) - sizeof("http") + 1, "http", + sizeof("http") - 1) == 0) { + lslash = me + (lslash - me) - sizeof("http"); + } + root = static_cast( + gpr_malloc(static_cast(lslash - me + sizeof("/../..")))); + memcpy(root, me, static_cast(lslash - me)); + memcpy(root + (lslash - me), "/../..", sizeof("/../..")); + } else { + root = gpr_strdup("."); + } + GPR_ASSERT(argc <= 2); + if (argc == 2) { + args.push_back(gpr_strdup(argv[1])); + } else { + char* python_wrapper_arg; + char* test_server_arg; + gpr_asprintf(&python_wrapper_arg, "%s/test/core/http/python_wrapper.sh", + root); + gpr_asprintf(&test_server_arg, "%s/test/core/http/test_server.py", root); + args.push_back(python_wrapper_arg); + args.push_back(test_server_arg); + } + // start the server + args.push_back(gpr_strdup("--port")); + char* server_port_str; + gpr_asprintf(&server_port_str, "%d", server_port); + args.push_back(server_port_str); + if (use_ssl) { + args.push_back(gpr_strdup("--ssl")); + // Set the environment variable for the SSL certificate file + char* pem_file; + gpr_asprintf(&pem_file, "%s/src/core/tsi/test_creds/ca.pem", root); + GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, pem_file); + gpr_free(pem_file); + } + gpr_log(GPR_INFO, "starting HttpRequest test server subprocess:"); + for (size_t i = 0; i < args.size(); i++) { + gpr_log(GPR_INFO, " HttpRequest test server subprocess argv[%ld]: %s", i, + args[i]); + } + gpr_subprocess* server = + gpr_subprocess_create(args.size(), const_cast(args.data())); + GPR_ASSERT(server); + for (size_t i = 0; i < args.size(); i++) { + gpr_free(args[i]); + } + gpr_free(root); + gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_seconds(5, GPR_TIMESPAN))); + return {server, server_port}; +} + +} // namespace testing +} // namespace grpc_core diff --git a/test/core/http/httpcli_test_util.h b/test/core/http/httpcli_test_util.h new file mode 100644 index 00000000000..e1ecebe7926 --- /dev/null +++ b/test/core/http/httpcli_test_util.h @@ -0,0 +1,38 @@ +// +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef GRPC_TEST_CORE_HTTP_HTTPCLI_TEST_UTIL_H +#define GRPC_TEST_CORE_HTTP_HTTPCLI_TEST_UTIL_H + +#include + +#include "test/core/util/subprocess.h" + +namespace grpc_core { +namespace testing { + +struct HttpRequestTestServer { + gpr_subprocess* server; + int port; +}; + +HttpRequestTestServer StartHttpRequestTestServer(int argc, char** argv, + bool use_ssl); + +} // namespace testing +} // namespace grpc_core + +#endif // GRPC_TEST_CORE_HTTP_HTTPCLI_TEST_UTIL_H diff --git a/test/core/http/httpscli_test.cc b/test/core/http/httpscli_test.cc index fb4910a3f30..f2d3b353a36 100644 --- a/test/core/http/httpscli_test.cc +++ b/test/core/http/httpscli_test.cc @@ -18,206 +18,271 @@ #include +#include +#include + #include -#include #include #include #include #include -#include "src/core/lib/gpr/env.h" +#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" #include "src/core/lib/http/httpcli.h" +#include "src/core/lib/http/httpcli_ssl_credentials.h" #include "src/core/lib/iomgr/iomgr.h" -#include "src/core/lib/security/security_connector/ssl_utils_config.h" +#include "test/core/http/httpcli_test_util.h" +#include "test/core/util/fake_udp_and_tcp_server.h" #include "test/core/util/port.h" #include "test/core/util/subprocess.h" #include "test/core/util/test_config.h" -static int g_done = 0; -static gpr_mu* g_mu; -static grpc_polling_entity g_pops; +namespace { -static grpc_millis n_seconds_time(int seconds) { +grpc_millis NSecondsTime(int seconds) { return grpc_timespec_to_millis_round_up( grpc_timeout_seconds_to_deadline(seconds)); } -static void on_finish(void* arg, grpc_error_handle error) { - const char* expect = - "Hello world!" - "

This is a test

"; - grpc_http_response* response = static_cast(arg); - GPR_ASSERT(response); - gpr_log(GPR_INFO, "response status=%d error=%s", response->status, - grpc_error_std_string(error).c_str()); - GPR_ASSERT(response->status == 200); - GPR_ASSERT(response->body_length == strlen(expect)); - GPR_ASSERT(0 == memcmp(expect, response->body, response->body_length)); - gpr_mu_lock(g_mu); - g_done = 1; - GPR_ASSERT(GRPC_LOG_IF_ERROR( - "pollset_kick", - grpc_pollset_kick(grpc_polling_entity_pollset(&g_pops), nullptr))); - gpr_mu_unlock(g_mu); +absl::Time AbslDeadlineSeconds(int s) { + return grpc_core::ToAbslTime(grpc_timeout_seconds_to_deadline(s)); } -static void test_get(int port) { - grpc_httpcli_request req; - char* host; - grpc_core::ExecCtx exec_ctx; - - g_done = 0; - gpr_log(GPR_INFO, "test_get"); +int g_argc; +char** g_argv; +int g_server_port; +gpr_subprocess* g_server; - gpr_asprintf(&host, "localhost:%d", port); - gpr_log(GPR_INFO, "requesting from %s", host); +class HttpsCliTest : public ::testing::Test { + public: + HttpsCliTest() { + grpc_init(); + grpc_core::ExecCtx exec_ctx; + grpc_pollset* pollset = + static_cast(gpr_zalloc(grpc_pollset_size())); + grpc_pollset_init(pollset, &mu_); + pops_ = grpc_polling_entity_create_from_pollset(pollset); + } + ~HttpsCliTest() override { + { + grpc_core::ExecCtx exec_ctx; + grpc_pollset_shutdown( + grpc_polling_entity_pollset(&pops_), + GRPC_CLOSURE_CREATE(DestroyPops, &pops_, grpc_schedule_on_exec_ctx)); + } + grpc_shutdown(); + } - memset(&req, 0, sizeof(req)); - req.host = host; - req.ssl_host_override = const_cast("foo.test.google.fr"); - req.http.path = const_cast("/get"); - req.handshaker = &grpc_httpcli_ssl; - - grpc_http_response response; - response = {}; - grpc_httpcli_get( - &g_pops, grpc_core::ResourceQuota::Default(), &req, n_seconds_time(15), - GRPC_CLOSURE_CREATE(on_finish, &response, grpc_schedule_on_exec_ctx), - &response); - gpr_mu_lock(g_mu); - while (!g_done) { - grpc_pollset_worker* worker = nullptr; + void RunAndKick(const std::function& f) { + grpc_core::MutexLockForGprMu lock(mu_); + f(); GPR_ASSERT(GRPC_LOG_IF_ERROR( - "pollset_work", grpc_pollset_work(grpc_polling_entity_pollset(&g_pops), - &worker, n_seconds_time(1)))); - gpr_mu_unlock(g_mu); - grpc_core::ExecCtx::Get()->Flush(); - gpr_mu_lock(g_mu); + "pollset_kick", + grpc_pollset_kick(grpc_polling_entity_pollset(&pops_), nullptr))); } - gpr_mu_unlock(g_mu); - gpr_free(host); - grpc_http_response_destroy(&response); -} - -static void test_post(int port) { - grpc_httpcli_request req; - char* host; - grpc_core::ExecCtx exec_ctx; - g_done = 0; - gpr_log(GPR_INFO, "test_post"); + void PollUntil(const std::function& predicate, absl::Time deadline) { + gpr_mu_lock(mu_); + while (!predicate()) { + GPR_ASSERT(absl::Now() < deadline); + grpc_pollset_worker* worker = nullptr; + GPR_ASSERT(GRPC_LOG_IF_ERROR( + "pollset_work", grpc_pollset_work(grpc_polling_entity_pollset(&pops_), + &worker, NSecondsTime(1)))); + gpr_mu_unlock(mu_); + gpr_mu_lock(mu_); + } + gpr_mu_unlock(mu_); + } - gpr_asprintf(&host, "localhost:%d", port); - gpr_log(GPR_INFO, "posting to %s", host); + grpc_polling_entity* pops() { return &pops_; } - memset(&req, 0, sizeof(req)); - req.host = host; - req.ssl_host_override = const_cast("foo.test.google.fr"); - req.http.path = const_cast("/post"); - req.handshaker = &grpc_httpcli_ssl; - - grpc_http_response response; - response = {}; - grpc_httpcli_post( - &g_pops, grpc_core::ResourceQuota::Default(), &req, "hello", 5, - n_seconds_time(15), - GRPC_CLOSURE_CREATE(on_finish, &response, grpc_schedule_on_exec_ctx), - &response); - gpr_mu_lock(g_mu); - while (!g_done) { - grpc_pollset_worker* worker = nullptr; - GPR_ASSERT(GRPC_LOG_IF_ERROR( - "pollset_work", grpc_pollset_work(grpc_polling_entity_pollset(&g_pops), - &worker, n_seconds_time(1)))); - gpr_mu_unlock(g_mu); - grpc_core::ExecCtx::Get()->Flush(); - gpr_mu_lock(g_mu); + protected: + static void SetUpTestSuite() { + auto test_server = grpc_core::testing::StartHttpRequestTestServer( + g_argc, g_argv, true /* use_ssl */); + g_server = test_server.server; + g_server_port = test_server.port; } - gpr_mu_unlock(g_mu); - gpr_free(host); - grpc_http_response_destroy(&response); -} -static void destroy_pops(void* p, grpc_error_handle /*error*/) { - grpc_pollset_destroy( - grpc_polling_entity_pollset(static_cast(p))); -} + static void TearDownTestSuite() { gpr_subprocess_destroy(g_server); } -int main(int argc, char** argv) { - grpc_closure destroyed; - gpr_subprocess* server; - char* me = argv[0]; - char* lslash = strrchr(me, '/'); - char* args[5]; - int port = grpc_pick_unused_port_or_die(); - int arg_shift = 0; - /* figure out where we are */ - char* root; - if (lslash != nullptr) { - /* Hack for bazel target */ - if (static_cast(lslash - me) >= (sizeof("http") - 1) && - strncmp(me + (lslash - me) - sizeof("http") + 1, "http", - sizeof("http") - 1) == 0) { - lslash = me + (lslash - me) - sizeof("http"); - } - root = static_cast( - gpr_malloc(static_cast(lslash - me + sizeof("/../..")))); - memcpy(root, me, static_cast(lslash - me)); - memcpy(root + (lslash - me), "/../..", sizeof("/../..")); - } else { - root = gpr_strdup("."); + private: + static void DestroyPops(void* p, grpc_error_handle /*error*/) { + grpc_polling_entity* pops = static_cast(p); + grpc_pollset_destroy(grpc_polling_entity_pollset(pops)); + gpr_free(grpc_polling_entity_pollset(pops)); } - GPR_ASSERT(argc <= 2); - if (argc == 2) { - args[0] = gpr_strdup(argv[1]); - } else { - arg_shift = 1; - gpr_asprintf(&args[0], "%s/test/core/http/python_wrapper.sh", root); - gpr_asprintf(&args[1], "%s/test/core/http/test_server.py", root); + gpr_mu* mu_; + grpc_polling_entity pops_; +}; + +struct RequestState { + explicit RequestState(HttpsCliTest* test) : test(test) {} + + ~RequestState() { + grpc_core::ExecCtx exec_ctx; + grpc_http_response_destroy(&response); } - /* Set the environment variable for the SSL certificate file */ - char* pem_file; - gpr_asprintf(&pem_file, "%s/src/core/tsi/test_creds/ca.pem", root); - GPR_GLOBAL_CONFIG_SET(grpc_default_ssl_roots_file_path, pem_file); - gpr_free(pem_file); - - /* start the server */ - args[1 + arg_shift] = const_cast("--port"); - gpr_asprintf(&args[2 + arg_shift], "%d", port); - args[3 + arg_shift] = const_cast("--ssl"); - server = gpr_subprocess_create(4 + arg_shift, const_cast(args)); - GPR_ASSERT(server); - gpr_free(args[0]); - if (arg_shift) gpr_free(args[1]); - gpr_free(args[2 + arg_shift]); - gpr_free(root); - - gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_seconds(5, GPR_TIMESPAN))); + HttpsCliTest* test; + bool done = false; + grpc_http_response response = {}; +}; - grpc::testing::TestEnvironment env(argc, argv); - grpc_init(); - grpc_pollset* pollset = - static_cast(gpr_zalloc(grpc_pollset_size())); - grpc_pollset_init(pollset, &g_mu); - g_pops = grpc_polling_entity_create_from_pollset(pollset); +void OnFinish(void* arg, grpc_error_handle error) { + RequestState* request_state = static_cast(arg); + const char* expect = + "Hello world!" + "

This is a test

"; + GPR_ASSERT(error == GRPC_ERROR_NONE); + grpc_http_response response = request_state->response; + gpr_log(GPR_INFO, "response status=%d error=%s", response.status, + grpc_error_std_string(error).c_str()); + GPR_ASSERT(response.status == 200); + GPR_ASSERT(response.body_length == strlen(expect)); + GPR_ASSERT(0 == memcmp(expect, response.body, response.body_length)); + request_state->test->RunAndKick( + [request_state]() { request_state->done = true; }); +} - test_get(port); - test_post(port); +void OnFinishExpectFailure(void* arg, grpc_error_handle error) { + RequestState* request_state = static_cast(arg); + grpc_http_response response = request_state->response; + gpr_log(GPR_INFO, "response status=%d error=%s", response.status, + grpc_error_std_string(error).c_str()); + GPR_ASSERT(error != GRPC_ERROR_NONE); + request_state->test->RunAndKick( + [request_state]() { request_state->done = true; }); +} - { - grpc_core::ExecCtx exec_ctx; - GRPC_CLOSURE_INIT(&destroyed, destroy_pops, &g_pops, - grpc_schedule_on_exec_ctx); - grpc_pollset_shutdown(grpc_polling_entity_pollset(&g_pops), &destroyed); - } - grpc_shutdown(); +TEST_F(HttpsCliTest, Get) { + RequestState request_state(this); + grpc_http_request req; + grpc_core::ExecCtx exec_ctx; + std::string host = absl::StrFormat("localhost:%d", g_server_port); + gpr_log(GPR_INFO, "requesting from %s", host.c_str()); + memset(&req, 0, sizeof(req)); + grpc_arg ssl_override_arg = grpc_channel_arg_string_create( + const_cast(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG), + const_cast("foo.test.google.fr")); + grpc_channel_args args = {1, &ssl_override_arg}; + auto uri = grpc_core::URI::Create("https", host, "/get", + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); + grpc_core::OrphanablePtr http_request = + grpc_core::HttpRequest::Get( + std::move(*uri), &args, pops(), &req, NSecondsTime(15), + GRPC_CLOSURE_CREATE(OnFinish, &request_state, + grpc_schedule_on_exec_ctx), + &request_state.response, + grpc_core::CreateHttpRequestSSLCredentials()); + http_request->Start(); + PollUntil([&request_state]() { return request_state.done; }, + AbslDeadlineSeconds(60)); +} + +TEST_F(HttpsCliTest, Post) { + RequestState request_state(this); + grpc_http_request req; + grpc_core::ExecCtx exec_ctx; + std::string host = absl::StrFormat("localhost:%d", g_server_port); + gpr_log(GPR_INFO, "posting to %s", host.c_str()); + memset(&req, 0, sizeof(req)); + req.body = const_cast("hello"); + req.body_length = 5; + grpc_arg ssl_override_arg = grpc_channel_arg_string_create( + const_cast(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG), + const_cast("foo.test.google.fr")); + grpc_channel_args args = {1, &ssl_override_arg}; + auto uri = grpc_core::URI::Create("https", host, "/post", + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); + grpc_core::OrphanablePtr http_request = + grpc_core::HttpRequest::Post( + std::move(*uri), &args /* channel args */, pops(), &req, + NSecondsTime(15), + GRPC_CLOSURE_CREATE(OnFinish, &request_state, + grpc_schedule_on_exec_ctx), + &request_state.response, + grpc_core::CreateHttpRequestSSLCredentials()); + http_request->Start(); + PollUntil([&request_state]() { return request_state.done; }, + AbslDeadlineSeconds(60)); +} - gpr_free(grpc_polling_entity_pollset(&g_pops)); +// The goal of this test is to make sure that we can cancel HTTP requests +// while they're waiting for a response from the server to finish their +// SSL handshakes. Note that the main focus of this test is to just exercise +// the relevant code paths and make sure there aren't any crashes etc., rather +// than to make sure that cancellation happens in a timely manner. +TEST_F(HttpsCliTest, CancelGetDuringSSLHandshake) { + // Start up a fake TCP server which accepts connections and then hangs, + // i.e. it won't send any bytes back to the client. + grpc_core::testing::FakeUdpAndTcpServer fake_http_server( + grpc_core::testing::FakeUdpAndTcpServer::AcceptMode:: + kWaitForClientToSendFirstBytes, + grpc_core::testing::FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer); + // Use multiple threads to try to trigger races etc. + int kNumThreads = 100; + std::vector threads; + threads.reserve(kNumThreads); + for (int i = 0; i < kNumThreads; i++) { + grpc_core::testing::FakeUdpAndTcpServer* fake_http_server_ptr = + &fake_http_server; + threads.push_back(std::thread([this, fake_http_server_ptr]() { + RequestState request_state(this); + grpc_http_request req; + grpc_core::ExecCtx exec_ctx; + memset(&req, 0, sizeof(req)); + grpc_arg ssl_override_arg = grpc_channel_arg_string_create( + const_cast(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG), + const_cast("foo.test.google.fr")); + grpc_channel_args args = {1, &ssl_override_arg}; + auto uri = grpc_core::URI::Create( + "https", fake_http_server_ptr->address(), "/get", + {} /* query params */, "" /* fragment */); + grpc_core::OrphanablePtr http_request = + grpc_core::HttpRequest::Get( + std::move(*uri), &args, pops(), &req, NSecondsTime(120), + GRPC_CLOSURE_CREATE(OnFinishExpectFailure, &request_state, + grpc_schedule_on_exec_ctx), + &request_state.response, + grpc_core::CreateHttpRequestSSLCredentials()); + // Start a request. It will establish a TCP connection to the + // server and then begin an SSL handshake. The server won't send + // anything back though, so it will be stuck in its SSL handshake, + // waiting for the firt response from the server. + http_request->Start(); + exec_ctx.Flush(); + std::thread cancel_thread([&http_request]() { + // Give one second to let the client get into the middle of its + // SSL handshake, and then cancel the request. + gpr_sleep_until(grpc_timeout_seconds_to_deadline(1)); + grpc_core::ExecCtx exec_ctx; + http_request.reset(); + }); + // Poll with a deadline explicitly lower than the request timeout, so + // that we know that the request timeout isn't just kicking in. + PollUntil([&request_state]() { return request_state.done; }, + AbslDeadlineSeconds(60)); + cancel_thread.join(); + })); + } + for (auto& t : threads) { + t.join(); + } +} - gpr_subprocess_destroy(server); +} // namespace - return 0; +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + grpc::testing::TestEnvironment env(argc, argv); + // launch the test server later, so that --gtest_list_tests works + g_argc = argc; + g_argv = argv; + // run tests + return RUN_ALL_TESTS(); } diff --git a/test/core/security/credentials_test.cc b/test/core/security/credentials_test.cc index 612a23de20a..f811ba82a95 100644 --- a/test/core/security/credentials_test.cc +++ b/test/core/security/credentials_test.cc @@ -296,8 +296,8 @@ static char* test_json_key_str(void) { return result; } -static grpc_httpcli_response http_response(int status, const char* body) { - grpc_httpcli_response response; +static grpc_http_response http_response(int status, const char* body) { + grpc_http_response response; response = {}; response.status = status; response.body = gpr_strdup(const_cast(body)); @@ -311,8 +311,7 @@ static void test_oauth2_token_fetcher_creds_parsing_ok(void) { grpc_core::ExecCtx exec_ctx; absl::optional token_value; grpc_millis token_lifetime; - grpc_httpcli_response response = - http_response(200, valid_oauth2_json_response); + grpc_http_response response = http_response(200, valid_oauth2_json_response); GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response( &response, &token_value, &token_lifetime) == GRPC_CREDENTIALS_OK); @@ -326,8 +325,7 @@ static void test_oauth2_token_fetcher_creds_parsing_bad_http_status(void) { grpc_core::ExecCtx exec_ctx; absl::optional token_value; grpc_millis token_lifetime; - grpc_httpcli_response response = - http_response(401, valid_oauth2_json_response); + grpc_http_response response = http_response(401, valid_oauth2_json_response); GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response( &response, &token_value, &token_lifetime) == GRPC_CREDENTIALS_ERROR); @@ -338,7 +336,7 @@ static void test_oauth2_token_fetcher_creds_parsing_empty_http_body(void) { grpc_core::ExecCtx exec_ctx; absl::optional token_value; grpc_millis token_lifetime; - grpc_httpcli_response response = http_response(200, ""); + grpc_http_response response = http_response(200, ""); GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response( &response, &token_value, &token_lifetime) == GRPC_CREDENTIALS_ERROR); @@ -349,7 +347,7 @@ static void test_oauth2_token_fetcher_creds_parsing_invalid_json(void) { grpc_core::ExecCtx exec_ctx; absl::optional token_value; grpc_millis token_lifetime; - grpc_httpcli_response response = + grpc_http_response response = http_response(200, "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\"," " \"expires_in\":3599, " @@ -364,10 +362,10 @@ static void test_oauth2_token_fetcher_creds_parsing_missing_token(void) { grpc_core::ExecCtx exec_ctx; absl::optional token_value; grpc_millis token_lifetime; - grpc_httpcli_response response = http_response(200, - "{" - " \"expires_in\":3599, " - " \"token_type\":\"Bearer\"}"); + grpc_http_response response = http_response(200, + "{" + " \"expires_in\":3599, " + " \"token_type\":\"Bearer\"}"); GPR_ASSERT(grpc_oauth2_token_fetcher_credentials_parse_server_response( &response, &token_value, &token_lifetime) == GRPC_CREDENTIALS_ERROR); @@ -378,7 +376,7 @@ static void test_oauth2_token_fetcher_creds_parsing_missing_token_type(void) { grpc_core::ExecCtx exec_ctx; absl::optional token_value; grpc_millis token_lifetime; - grpc_httpcli_response response = + grpc_http_response response = http_response(200, "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\"," " \"expires_in\":3599, " @@ -394,7 +392,7 @@ static void test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime( grpc_core::ExecCtx exec_ctx; absl::optional token_value; grpc_millis token_lifetime; - grpc_httpcli_response response = + grpc_http_response response = http_response(200, "{\"access_token\":\"ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_\"," " \"token_type\":\"Bearer\"}"); @@ -676,47 +674,50 @@ static void test_channel_oauth2_google_iam_composite_creds(void) { } static void validate_compute_engine_http_request( - const grpc_httpcli_request* request) { - GPR_ASSERT(request->handshaker != &grpc_httpcli_ssl); - GPR_ASSERT(strcmp(request->host, "metadata.google.internal.") == 0); + const grpc_http_request* request, const char* host, const char* path) { + GPR_ASSERT(strcmp(host, "metadata.google.internal.") == 0); GPR_ASSERT( - strcmp(request->http.path, + strcmp(path, "/computeMetadata/v1/instance/service-accounts/default/token") == 0); - GPR_ASSERT(request->http.hdr_count == 1); - GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Metadata-Flavor") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[0].value, "Google") == 0); + GPR_ASSERT(request->hdr_count == 1); + GPR_ASSERT(strcmp(request->hdrs[0].key, "Metadata-Flavor") == 0); + GPR_ASSERT(strcmp(request->hdrs[0].value, "Google") == 0); } static int compute_engine_httpcli_get_success_override( - const grpc_httpcli_request* request, grpc_millis /*deadline*/, - grpc_closure* on_done, grpc_httpcli_response* response) { - validate_compute_engine_http_request(request); + const grpc_http_request* request, const char* host, const char* path, + grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { + validate_compute_engine_http_request(request, host, path); *response = http_response(200, valid_oauth2_json_response); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; } static int compute_engine_httpcli_get_failure_override( - const grpc_httpcli_request* request, grpc_millis /*deadline*/, - grpc_closure* on_done, grpc_httpcli_response* response) { - validate_compute_engine_http_request(request); + const grpc_http_request* request, const char* host, const char* path, + grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { + validate_compute_engine_http_request(request, host, path); *response = http_response(403, "Not Authorized."); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; } static int httpcli_post_should_not_be_called( - const grpc_httpcli_request* /*request*/, const char* /*body_bytes*/, - size_t /*body_size*/, grpc_millis /*deadline*/, grpc_closure* /*on_done*/, - grpc_httpcli_response* /*response*/) { + const grpc_http_request* /*request*/, const char* /*host*/, + const char* /*path*/, const char* /*body_bytes*/, size_t /*body_size*/, + grpc_millis /*deadline*/, grpc_closure* /*on_done*/, + grpc_http_response* /*response*/) { GPR_ASSERT("HTTP POST should not be called" == nullptr); return 1; } static int httpcli_get_should_not_be_called( - const grpc_httpcli_request* /*request*/, grpc_millis /*deadline*/, - grpc_closure* /*on_done*/, grpc_httpcli_response* /*response*/) { + const grpc_http_request* /*request*/, const char* /*host*/, + const char* /*path*/, grpc_millis /*deadline*/, grpc_closure* /*on_done*/, + grpc_http_response* /*response*/) { GPR_ASSERT("HTTP GET should not be called" == nullptr); return 1; } @@ -738,22 +739,23 @@ static void test_compute_engine_creds_success() { /* First request: http get should be called. */ RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride( + compute_engine_httpcli_get_success_override, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); /* Second request: the cached token should be served directly. */ state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); GPR_ASSERT( strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0); creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_compute_engine_creds_failure(void) { @@ -769,17 +771,19 @@ static void test_compute_engine_creds_failure(void) { nullptr, nullptr}; grpc_call_credentials* creds = grpc_google_compute_engine_credentials_create(nullptr); - grpc_httpcli_set_override(compute_engine_httpcli_get_failure_override, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride( + compute_engine_httpcli_get_failure_override, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds, auth_md_ctx); GPR_ASSERT( strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0); creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void validate_refresh_token_http_request( - const grpc_httpcli_request* request, const char* body, size_t body_size) { + const grpc_http_request* request, const char* host, const char* path, + const char* body, size_t body_size) { /* The content of the assertion is tested extensively in json_token_test. */ GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); @@ -789,32 +793,29 @@ static void validate_refresh_token_http_request( "1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42"); GPR_ASSERT(expected_body.size() == body_size); GPR_ASSERT(memcmp(expected_body.data(), body, body_size) == 0); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); - GPR_ASSERT(strcmp(request->host, GRPC_GOOGLE_OAUTH2_SERVICE_HOST) == 0); + GPR_ASSERT(strcmp(host, GRPC_GOOGLE_OAUTH2_SERVICE_HOST) == 0); + GPR_ASSERT(strcmp(path, GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH) == 0); + GPR_ASSERT(request->hdr_count == 1); + GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0); GPR_ASSERT( - strcmp(request->http.path, GRPC_GOOGLE_OAUTH2_SERVICE_TOKEN_PATH) == 0); - GPR_ASSERT(request->http.hdr_count == 1); - GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[0].value, - "application/x-www-form-urlencoded") == 0); + strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0); } static int refresh_token_httpcli_post_success( - const grpc_httpcli_request* request, const char* body, size_t body_size, - grpc_millis /*deadline*/, grpc_closure* on_done, - grpc_httpcli_response* response) { - validate_refresh_token_http_request(request, body, body_size); + const grpc_http_request* request, const char* host, const char* path, + const char* body, size_t body_size, grpc_millis /*deadline*/, + grpc_closure* on_done, grpc_http_response* response) { + validate_refresh_token_http_request(request, host, path, body, body_size); *response = http_response(200, valid_oauth2_json_response); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; } -static int token_httpcli_post_failure(const grpc_httpcli_request* /*request*/, - const char* /*body*/, - size_t /*body_size*/, - grpc_millis /*deadline*/, - grpc_closure* on_done, - grpc_httpcli_response* response) { +static int token_httpcli_post_failure( + const grpc_http_request* /*request*/, const char* /*host*/, + const char* /*path*/, const char* /*body*/, size_t /*body_size*/, + grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { *response = http_response(403, "Not Authorized."); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; @@ -838,22 +839,22 @@ static void test_refresh_token_creds_success(void) { /* First request: http put should be called. */ RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - refresh_token_httpcli_post_success); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + refresh_token_httpcli_post_success); state->RunRequestMetadataTest(creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); /* Second request: the cached token should be served directly. */ state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); GPR_ASSERT( strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0); creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_refresh_token_creds_failure(void) { @@ -869,14 +870,14 @@ static void test_refresh_token_creds_failure(void) { nullptr, nullptr}; grpc_call_credentials* creds = grpc_google_refresh_token_credentials_create( test_refresh_token_str, nullptr); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - token_httpcli_post_failure); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + token_httpcli_post_failure); state->RunRequestMetadataTest(creds, auth_md_ctx); GPR_ASSERT( strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0); creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_valid_sts_creds_options(void) { @@ -990,13 +991,13 @@ static void assert_query_parameters(const grpc_core::URI& uri, GPR_ASSERT(it->second == expected_val); } -static void validate_sts_token_http_request(const grpc_httpcli_request* request, +static void validate_sts_token_http_request(const grpc_http_request* request, + const char* host, const char* path, const char* body, size_t body_size, bool expect_actor_token) { // Check that the body is constructed properly. GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); std::string get_url_equivalent = absl::StrFormat("%s?%s", test_sts_endpoint_url, body); absl::StatusOr url = @@ -1024,30 +1025,31 @@ static void validate_sts_token_http_request(const grpc_httpcli_request* request, } // Check the rest of the request. - GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0); - GPR_ASSERT(strcmp(request->http.path, "/v1/token-exchange") == 0); - GPR_ASSERT(request->http.hdr_count == 1); - GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[0].value, - "application/x-www-form-urlencoded") == 0); + GPR_ASSERT(strcmp(host, "foo.com:5555") == 0); + GPR_ASSERT(strcmp(path, "/v1/token-exchange") == 0); + GPR_ASSERT(request->hdr_count == 1); + GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0); + GPR_ASSERT( + strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0); } -static int sts_token_httpcli_post_success(const grpc_httpcli_request* request, +static int sts_token_httpcli_post_success(const grpc_http_request* request, + const char* host, const char* path, const char* body, size_t body_size, grpc_millis /*deadline*/, grpc_closure* on_done, - grpc_httpcli_response* response) { - validate_sts_token_http_request(request, body, body_size, true); + grpc_http_response* response) { + validate_sts_token_http_request(request, host, path, body, body_size, true); *response = http_response(200, valid_sts_json_response); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; } static int sts_token_httpcli_post_success_no_actor_token( - const grpc_httpcli_request* request, const char* body, size_t body_size, - grpc_millis /*deadline*/, grpc_closure* on_done, - grpc_httpcli_response* response) { - validate_sts_token_http_request(request, body, body_size, false); + const grpc_http_request* request, const char* host, const char* path, + const char* body, size_t body_size, grpc_millis /*deadline*/, + grpc_closure* on_done, grpc_http_response* response) { + validate_sts_token_http_request(request, host, path, body, body_size, false); *response = http_response(200, valid_sts_json_response); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; @@ -1095,22 +1097,22 @@ static void test_sts_creds_success(void) { /* First request: http put should be called. */ RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - sts_token_httpcli_post_success); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + sts_token_httpcli_post_success); state->RunRequestMetadataTest(creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); /* Second request: the cached token should be served directly. */ state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); GPR_ASSERT( strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0); creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_free(subject_token_path); gpr_free(actor_token_path); } @@ -1140,14 +1142,14 @@ static void test_sts_creds_token_file_not_found(void) { GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Error occurred when fetching oauth2 token."), {}); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); /* Cleanup. */ creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_sts_creds_no_actor_token_success(void) { @@ -1180,22 +1182,23 @@ static void test_sts_creds_no_actor_token_success(void) { /* First request: http put should be called. */ RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - sts_token_httpcli_post_success_no_actor_token); + grpc_core::HttpRequest::SetOverride( + httpcli_get_should_not_be_called, + sts_token_httpcli_post_success_no_actor_token); state->RunRequestMetadataTest(creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); /* Second request: the cached token should be served directly. */ state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); GPR_ASSERT( strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0); creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_free(subject_token_path); } @@ -1223,14 +1226,14 @@ static void test_sts_creds_load_token_failure(void) { nullptr // actor_token_type }; grpc_call_credentials* creds = grpc_sts_credentials_create(&options, nullptr); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds, auth_md_ctx); GPR_ASSERT( strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0); creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_free(test_signed_jwt_path); } @@ -1259,13 +1262,13 @@ static void test_sts_creds_http_failure(void) { }; grpc_call_credentials* creds = grpc_sts_credentials_create(&valid_options, nullptr); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - token_httpcli_post_failure); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + token_httpcli_post_failure); state->RunRequestMetadataTest(creds, auth_md_ctx); GPR_ASSERT( strcmp(creds->debug_string().c_str(), expected_creds_debug_string) == 0); creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_free(test_signed_jwt_path); } @@ -1584,8 +1587,9 @@ test_google_default_creds_external_account_credentials_multi_pattern_iam(void) { } static int default_creds_metadata_server_detection_httpcli_get_success_override( - const grpc_httpcli_request* request, grpc_millis /*deadline*/, - grpc_closure* on_done, grpc_httpcli_response* response) { + const grpc_http_request* /*request*/, const char* host, const char* path, + grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { *response = http_response(200, ""); grpc_http_header* headers = static_cast(gpr_malloc(sizeof(*headers) * 1)); @@ -1593,8 +1597,8 @@ static int default_creds_metadata_server_detection_httpcli_get_success_override( headers[0].value = gpr_strdup("Google"); response->hdr_count = 1; response->hdrs = headers; - GPR_ASSERT(strcmp(request->http.path, "/") == 0); - GPR_ASSERT(strcmp(request->host, "metadata.google.internal.") == 0); + GPR_ASSERT(strcmp(path, "/") == 0); + GPR_ASSERT(strcmp(host, "metadata.google.internal.") == 0); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; } @@ -1625,8 +1629,9 @@ static void test_google_default_creds_gce(void) { /* Verify that the default creds actually embeds a GCE creds. */ GPR_ASSERT(creds != nullptr); GPR_ASSERT(creds->call_creds() != nullptr); - grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride( + compute_engine_httpcli_get_success_override, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds->mutable_call_creds(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); @@ -1634,7 +1639,7 @@ static void test_google_default_creds_gce(void) { /* Cleanup. */ creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); grpc_override_well_known_credentials_path_getter(nullptr); } @@ -1654,7 +1659,7 @@ static void test_google_default_creds_non_gce(void) { g_test_gce_tenancy_checker_called = false; g_test_is_on_gce = false; /* Simulate a successful detection of metadata server. */ - grpc_httpcli_set_override( + grpc_core::HttpRequest::SetOverride( default_creds_metadata_server_detection_httpcli_get_success_override, httpcli_post_should_not_be_called); grpc_composite_channel_credentials* creds = @@ -1663,23 +1668,25 @@ static void test_google_default_creds_non_gce(void) { /* Verify that the default creds actually embeds a GCE creds. */ GPR_ASSERT(creds != nullptr); GPR_ASSERT(creds->call_creds() != nullptr); - grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride( + compute_engine_httpcli_get_success_override, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(creds->mutable_call_creds(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); GPR_ASSERT(g_test_gce_tenancy_checker_called == true); /* Cleanup. */ creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); grpc_override_well_known_credentials_path_getter(nullptr); } static int default_creds_gce_detection_httpcli_get_failure_override( - const grpc_httpcli_request* request, grpc_millis /*deadline*/, - grpc_closure* on_done, grpc_httpcli_response* response) { + const grpc_http_request* /*request*/, const char* host, const char* path, + grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { /* No magic header. */ - GPR_ASSERT(strcmp(request->http.path, "/") == 0); - GPR_ASSERT(strcmp(request->host, "metadata.google.internal.") == 0); + GPR_ASSERT(strcmp(path, "/") == 0); + GPR_ASSERT(strcmp(host, "metadata.google.internal.") == 0); *response = http_response(200, ""); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; @@ -1693,7 +1700,7 @@ static void test_no_google_default_creds(void) { set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker); g_test_gce_tenancy_checker_called = false; g_test_is_on_gce = false; - grpc_httpcli_set_override( + grpc_core::HttpRequest::SetOverride( default_creds_gce_detection_httpcli_get_failure_override, httpcli_post_should_not_be_called); /* Simulate a successful detection of GCE. */ @@ -1704,7 +1711,7 @@ static void test_no_google_default_creds(void) { GPR_ASSERT(g_test_gce_tenancy_checker_called == true); /* Cleanup. */ grpc_override_well_known_credentials_path_getter(nullptr); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_google_default_creds_call_creds_specified(void) { @@ -1721,7 +1728,7 @@ static void test_google_default_creds_call_creds_specified(void) { set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker); g_test_gce_tenancy_checker_called = false; g_test_is_on_gce = true; - grpc_httpcli_set_override( + grpc_core::HttpRequest::SetOverride( default_creds_metadata_server_detection_httpcli_get_success_override, httpcli_post_should_not_be_called); grpc_composite_channel_credentials* channel_creds = @@ -1730,14 +1737,15 @@ static void test_google_default_creds_call_creds_specified(void) { GPR_ASSERT(g_test_gce_tenancy_checker_called == false); GPR_ASSERT(channel_creds != nullptr); GPR_ASSERT(channel_creds->call_creds() != nullptr); - grpc_httpcli_set_override(compute_engine_httpcli_get_success_override, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride( + compute_engine_httpcli_get_success_override, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(channel_creds->mutable_call_creds(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); channel_creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } struct fake_call_creds : public grpc_call_credentials { @@ -1772,7 +1780,7 @@ static void test_google_default_creds_not_default(void) { set_gce_tenancy_checker_for_testing(test_gce_tenancy_checker); g_test_gce_tenancy_checker_called = false; g_test_is_on_gce = true; - grpc_httpcli_set_override( + grpc_core::HttpRequest::SetOverride( default_creds_metadata_server_detection_httpcli_get_success_override, httpcli_post_should_not_be_called); grpc_composite_channel_credentials* channel_creds = @@ -1785,7 +1793,7 @@ static void test_google_default_creds_not_default(void) { auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); channel_creds->Unref(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } typedef enum { @@ -2058,12 +2066,11 @@ static void test_auth_metadata_context(void) { } static void validate_external_account_creds_token_exchage_request( - const grpc_httpcli_request* request, const char* body, size_t body_size, - bool /*expect_actor_token*/) { + const grpc_http_request* request, const char* host, const char* path, + const char* body, size_t body_size, bool /*expect_actor_token*/) { // Check that the body is constructed properly. GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); std::string get_url_equivalent = absl::StrFormat("%s?%s", "https://foo.com:5555/token", body); absl::StatusOr uri = @@ -2083,25 +2090,24 @@ static void validate_external_account_creds_token_exchage_request( "https://www.googleapis.com/auth/cloud-platform"); // Check the rest of the request. - GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0); - GPR_ASSERT(strcmp(request->http.path, "/token") == 0); - GPR_ASSERT(request->http.hdr_count == 2); - GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[0].value, - "application/x-www-form-urlencoded") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[1].key, "Authorization") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[1].value, + GPR_ASSERT(strcmp(host, "foo.com:5555") == 0); + GPR_ASSERT(strcmp(path, "/token") == 0); + GPR_ASSERT(request->hdr_count == 2); + GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0); + GPR_ASSERT( + strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0); + GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0); + GPR_ASSERT(strcmp(request->hdrs[1].value, "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0); } static void validate_external_account_creds_token_exchage_request_with_url_encode( - const grpc_httpcli_request* request, const char* body, size_t body_size, - bool /*expect_actor_token*/) { + const grpc_http_request* request, const char* host, const char* path, + const char* body, size_t body_size, bool /*expect_actor_token*/) { // Check that the body is constructed properly. GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); GPR_ASSERT( strcmp( std::string(body, body_size).c_str(), @@ -2113,57 +2119,55 @@ validate_external_account_creds_token_exchage_request_with_url_encode( "options=%7B%7D") == 0); // Check the rest of the request. - GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0); - GPR_ASSERT(strcmp(request->http.path, "/token_url_encode") == 0); - GPR_ASSERT(request->http.hdr_count == 2); - GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[0].value, - "application/x-www-form-urlencoded") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[1].key, "Authorization") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[1].value, + GPR_ASSERT(strcmp(host, "foo.com:5555") == 0); + GPR_ASSERT(strcmp(path, "/token_url_encode") == 0); + GPR_ASSERT(request->hdr_count == 2); + GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0); + GPR_ASSERT( + strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0); + GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0); + GPR_ASSERT(strcmp(request->hdrs[1].value, "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0); } static void validate_external_account_creds_service_account_impersonation_request( - const grpc_httpcli_request* request, const char* body, size_t body_size, - bool /*expect_actor_token*/) { + const grpc_http_request* request, const char* host, const char* path, + const char* body, size_t body_size, bool /*expect_actor_token*/) { // Check that the body is constructed properly. GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); GPR_ASSERT(strcmp(body, "scope=scope_1 scope_2") == 0); // Check the rest of the request. - GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0); - GPR_ASSERT(strcmp(request->http.path, "/service_account_impersonation") == 0); - GPR_ASSERT(request->http.hdr_count == 2); - GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[0].value, - "application/x-www-form-urlencoded") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[1].key, "Authorization") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[1].value, + GPR_ASSERT(strcmp(host, "foo.com:5555") == 0); + GPR_ASSERT(strcmp(path, "/service_account_impersonation") == 0); + GPR_ASSERT(request->hdr_count == 2); + GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0); + GPR_ASSERT( + strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0); + GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0); + GPR_ASSERT(strcmp(request->hdrs[1].value, "Bearer token_exchange_access_token") == 0); } static int external_account_creds_httpcli_post_success( - const grpc_httpcli_request* request, const char* body, size_t body_size, - grpc_millis /*deadline*/, grpc_closure* on_done, - grpc_httpcli_response* response) { - if (strcmp(request->http.path, "/token") == 0) { - validate_external_account_creds_token_exchage_request(request, body, - body_size, true); + const grpc_http_request* request, const char* host, const char* path, + const char* body, size_t body_size, grpc_millis /*deadline*/, + grpc_closure* on_done, grpc_http_response* response) { + if (strcmp(path, "/token") == 0) { + validate_external_account_creds_token_exchage_request( + request, host, path, body, body_size, true); *response = http_response( 200, valid_external_account_creds_token_exchange_response); - } else if (strcmp(request->http.path, "/service_account_impersonation") == - 0) { + } else if (strcmp(path, "/service_account_impersonation") == 0) { validate_external_account_creds_service_account_impersonation_request( - request, body, body_size, true); + request, host, path, body, body_size, true); *response = http_response( 200, valid_external_account_creds_service_account_impersonation_response); - } else if (strcmp(request->http.path, "/token_url_encode") == 0) { + } else if (strcmp(path, "/token_url_encode") == 0) { validate_external_account_creds_token_exchage_request_with_url_encode( - request, body, body_size, true); + request, host, path, body, body_size, true); *response = http_response( 200, valid_external_account_creds_token_exchange_response); } @@ -2173,16 +2177,16 @@ static int external_account_creds_httpcli_post_success( static int external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token( - const grpc_httpcli_request* request, const char* /*body*/, - size_t /*body_size*/, grpc_millis /*deadline*/, grpc_closure* on_done, - grpc_httpcli_response* response) { - if (strcmp(request->http.path, "/token") == 0) { + const grpc_http_request* /*request*/, const char* /*host*/, + const char* path, const char* /*body*/, size_t /*body_size*/, + grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { + if (strcmp(path, "/token") == 0) { *response = http_response(200, "{\"not_access_token\":\"not_access_token\"," "\"expires_in\":3599," " \"token_type\":\"Bearer\"}"); - } else if (strcmp(request->http.path, "/service_account_impersonation") == - 0) { + } else if (strcmp(path, "/service_account_impersonation") == 0) { *response = http_response( 200, valid_external_account_creds_service_account_impersonation_response); @@ -2192,19 +2196,18 @@ external_account_creds_httpcli_post_failure_token_exchange_response_missing_acce } static int url_external_account_creds_httpcli_get_success( - const grpc_httpcli_request* request, grpc_millis /*deadline*/, - grpc_closure* on_done, grpc_httpcli_response* response) { - if (strcmp(request->http.path, "/generate_subject_token_format_text") == 0) { + const grpc_http_request* /*request*/, const char* /*host*/, + const char* path, grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { + if (strcmp(path, "/generate_subject_token_format_text") == 0) { *response = http_response( 200, valid_url_external_account_creds_retrieve_subject_token_response_format_text); - } else if (strcmp(request->http.path, "/path/to/url/creds?p1=v1&p2=v2") == - 0) { + } else if (strcmp(path, "/path/to/url/creds?p1=v1&p2=v2") == 0) { *response = http_response( 200, valid_url_external_account_creds_retrieve_subject_token_response_format_text); - } else if (strcmp(request->http.path, - "/generate_subject_token_format_json") == 0) { + } else if (strcmp(path, "/generate_subject_token_format_json") == 0) { *response = http_response( 200, valid_url_external_account_creds_retrieve_subject_token_response_format_json); @@ -2214,15 +2217,14 @@ static int url_external_account_creds_httpcli_get_success( } static void validate_aws_external_account_creds_token_exchage_request( - const grpc_httpcli_request* request, const char* body, size_t body_size, - bool /*expect_actor_token*/) { + const grpc_http_request* request, const char* host, const char* path, + const char* body, size_t body_size, bool /*expect_actor_token*/) { // Check that the body is constructed properly. GPR_ASSERT(body != nullptr); GPR_ASSERT(body_size != 0); // Check that the regional_cred_verification_url got constructed // with the correct AWS Region ("test_regionz" or "test_region"). GPR_ASSERT(strstr(body, "regional_cred_verification_url_test_region")); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); std::string get_url_equivalent = absl::StrFormat("%s?%s", "https://foo.com:5555/token", body); absl::StatusOr uri = @@ -2237,27 +2239,28 @@ static void validate_aws_external_account_creds_token_exchage_request( assert_query_parameters(*uri, "scope", "https://www.googleapis.com/auth/cloud-platform"); // Check the rest of the request. - GPR_ASSERT(strcmp(request->host, "foo.com:5555") == 0); - GPR_ASSERT(strcmp(request->http.path, "/token") == 0); - GPR_ASSERT(request->http.hdr_count == 2); - GPR_ASSERT(strcmp(request->http.hdrs[0].key, "Content-Type") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[0].value, - "application/x-www-form-urlencoded") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[1].key, "Authorization") == 0); - GPR_ASSERT(strcmp(request->http.hdrs[1].value, + GPR_ASSERT(strcmp(host, "foo.com:5555") == 0); + GPR_ASSERT(strcmp(path, "/token") == 0); + GPR_ASSERT(request->hdr_count == 2); + GPR_ASSERT(strcmp(request->hdrs[0].key, "Content-Type") == 0); + GPR_ASSERT( + strcmp(request->hdrs[0].value, "application/x-www-form-urlencoded") == 0); + GPR_ASSERT(strcmp(request->hdrs[1].key, "Authorization") == 0); + GPR_ASSERT(strcmp(request->hdrs[1].value, "Basic Y2xpZW50X2lkOmNsaWVudF9zZWNyZXQ=") == 0); } static int aws_external_account_creds_httpcli_get_success( - const grpc_httpcli_request* request, grpc_millis /*deadline*/, - grpc_closure* on_done, grpc_httpcli_response* response) { - if (strcmp(request->http.path, "/region_url") == 0) { + const grpc_http_request* /*request*/, const char* /*host*/, + const char* path, grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { + if (strcmp(path, "/region_url") == 0) { *response = http_response(200, "test_regionz"); - } else if (strcmp(request->http.path, "/url") == 0) { + } else if (strcmp(path, "/url") == 0) { *response = http_response(200, "test_role_name"); - } else if (strcmp(request->http.path, "/url_no_role_name") == 0) { + } else if (strcmp(path, "/url_no_role_name") == 0) { *response = http_response(200, ""); - } else if (strcmp(request->http.path, "/url/test_role_name") == 0) { + } else if (strcmp(path, "/url/test_role_name") == 0) { *response = http_response( 200, valid_aws_external_account_creds_retrieve_signing_keys_response); } @@ -2266,12 +2269,12 @@ static int aws_external_account_creds_httpcli_get_success( } static int aws_external_account_creds_httpcli_post_success( - const grpc_httpcli_request* request, const char* body, size_t body_size, - grpc_millis /*deadline*/, grpc_closure* on_done, - grpc_httpcli_response* response) { - if (strcmp(request->http.path, "/token") == 0) { - validate_aws_external_account_creds_token_exchage_request(request, body, - body_size, true); + const grpc_http_request* request, const char* host, const char* path, + const char* body, size_t body_size, grpc_millis /*deadline*/, + grpc_closure* on_done, grpc_http_response* response) { + if (strcmp(path, "/token") == 0) { + validate_aws_external_account_creds_token_exchage_request( + request, host, path, body, body_size, true); *response = http_response( 200, valid_external_account_creds_token_exchange_response); } @@ -2323,17 +2326,18 @@ static void test_external_account_creds_success(void) { /* First request: http put should be called. */ RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + httpcli_get_should_not_be_called, + external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(&creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); /* Second request: the cached token should be served directly. */ state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); state->RunRequestMetadataTest(&creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_external_account_creds_success_with_url_encode(void) { @@ -2359,11 +2363,12 @@ static void test_external_account_creds_success_with_url_encode(void) { TestExternalAccountCredentials creds(options, {}); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + httpcli_get_should_not_be_called, + external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(&creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void @@ -2393,11 +2398,12 @@ test_external_account_creds_success_with_service_account_impersonation(void) { /* First request: http put should be called. */ RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + httpcli_get_should_not_be_called, + external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(&creds, auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_external_account_creds_failure_invalid_token_url(void) { @@ -2419,8 +2425,8 @@ static void test_external_account_creds_failure_invalid_token_url(void) { "", // workforce_pool_user_project; }; TestExternalAccountCredentials creds(options, {}); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Invalid token url: invalid_token_url."); grpc_error_handle expected_error = @@ -2431,7 +2437,7 @@ static void test_external_account_creds_failure_invalid_token_url(void) { state->RunRequestMetadataTest(&creds, auth_md_ctx); GRPC_ERROR_UNREF(error); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void @@ -2455,8 +2461,9 @@ test_external_account_creds_failure_invalid_service_account_impersonation_url( "", // workforce_pool_user_project; }; TestExternalAccountCredentials creds(options, {}); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + httpcli_get_should_not_be_called, + external_account_creds_httpcli_post_success); grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Invalid service account impersonation url: " "invalid_service_account_impersonation_url."); @@ -2468,7 +2475,7 @@ test_external_account_creds_failure_invalid_service_account_impersonation_url( state->RunRequestMetadataTest(&creds, auth_md_ctx); GRPC_ERROR_UNREF(error); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void @@ -2492,7 +2499,7 @@ test_external_account_creds_failure_token_exchange_response_missing_access_token "", // workforce_pool_user_project; }; TestExternalAccountCredentials creds(options, {}); - grpc_httpcli_set_override( + grpc_core::HttpRequest::SetOverride( httpcli_get_should_not_be_called, external_account_creds_httpcli_post_failure_token_exchange_response_missing_access_token); grpc_error_handle error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( @@ -2507,7 +2514,7 @@ test_external_account_creds_failure_token_exchange_response_missing_access_token state->RunRequestMetadataTest(&creds, auth_md_ctx); GRPC_ERROR_UNREF(error); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_url_external_account_creds_success_format_text(void) { @@ -2541,11 +2548,12 @@ static void test_url_external_account_creds_success_format_text(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(url_external_account_creds_httpcli_get_success, - external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + url_external_account_creds_httpcli_get_success, + external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void @@ -2580,11 +2588,12 @@ test_url_external_account_creds_success_with_qurey_params_format_text(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(url_external_account_creds_httpcli_get_success, - external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + url_external_account_creds_httpcli_get_success, + external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_url_external_account_creds_success_format_json(void) { @@ -2618,11 +2627,12 @@ static void test_url_external_account_creds_success_format_json(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(url_external_account_creds_httpcli_get_success, - external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + url_external_account_creds_httpcli_get_success, + external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void @@ -2688,11 +2698,12 @@ static void test_file_external_account_creds_success_format_text(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + httpcli_get_should_not_be_called, + external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); GRPC_ERROR_UNREF(error); gpr_free(subject_token_path); } @@ -2739,11 +2750,12 @@ static void test_file_external_account_creds_success_format_json(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + httpcli_get_should_not_be_called, + external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); GRPC_ERROR_UNREF(error); gpr_free(subject_token_path); } @@ -2773,8 +2785,8 @@ static void test_file_external_account_creds_failure_file_not_found(void) { grpc_core::FileExternalAccountCredentials::Create(options, {}, &error); GPR_ASSERT(creds != nullptr); GPR_ASSERT(error == GRPC_ERROR_NONE); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Failed to load file"); grpc_error_handle expected_error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( @@ -2783,7 +2795,7 @@ static void test_file_external_account_creds_failure_file_not_found(void) { RequestMetadataState::NewInstance(expected_error, {}); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); GRPC_ERROR_UNREF(error); } @@ -2824,8 +2836,8 @@ static void test_file_external_account_creds_failure_invalid_json_content( grpc_core::FileExternalAccountCredentials::Create(options, {}, &error); GPR_ASSERT(creds != nullptr); GPR_ASSERT(error == GRPC_ERROR_NONE); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( "The content of the file is not a valid json object."); grpc_error_handle expected_error = @@ -2835,7 +2847,7 @@ static void test_file_external_account_creds_failure_invalid_json_content( RequestMetadataState::NewInstance(expected_error, {}); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); GRPC_ERROR_UNREF(error); gpr_free(subject_token_path); } @@ -2870,11 +2882,12 @@ static void test_aws_external_account_creds_success(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_aws_external_account_creds_success_path_region_env_keys_url( @@ -2909,11 +2922,12 @@ static void test_aws_external_account_creds_success_path_region_env_keys_url( GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_unsetenv("AWS_REGION"); } @@ -2949,11 +2963,12 @@ test_aws_external_account_creds_success_path_default_region_env_keys_url(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_unsetenv("AWS_DEFAULT_REGION"); } @@ -2992,11 +3007,12 @@ test_aws_external_account_creds_success_path_duplicate_region_env_keys_url( GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_unsetenv("AWS_REGION"); gpr_unsetenv("AWS_DEFAULT_REGION"); } @@ -3035,11 +3051,12 @@ static void test_aws_external_account_creds_success_path_region_url_keys_env( GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_unsetenv("AWS_ACCESS_KEY_ID"); gpr_unsetenv("AWS_SECRET_ACCESS_KEY"); gpr_unsetenv("AWS_SESSION_TOKEN"); @@ -3080,11 +3097,12 @@ static void test_aws_external_account_creds_success_path_region_env_keys_env( GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_unsetenv("AWS_REGION"); gpr_unsetenv("AWS_ACCESS_KEY_ID"); gpr_unsetenv("AWS_SECRET_ACCESS_KEY"); @@ -3126,11 +3144,12 @@ test_aws_external_account_creds_success_path_default_region_env_keys_env(void) { GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_unsetenv("AWS_DEFAULT_REGION"); gpr_unsetenv("AWS_ACCESS_KEY_ID"); gpr_unsetenv("AWS_SECRET_ACCESS_KEY"); @@ -3175,11 +3194,12 @@ test_aws_external_account_creds_success_path_duplicate_region_env_keys_env( GPR_ASSERT(creds->min_security_level() == GRPC_PRIVACY_AND_INTEGRITY); RequestMetadataState* state = RequestMetadataState::NewInstance(GRPC_ERROR_NONE, emd); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); gpr_unsetenv("AWS_REGION"); gpr_unsetenv("AWS_DEFAULT_REGION"); gpr_unsetenv("AWS_ACCESS_KEY_ID"); @@ -3252,11 +3272,12 @@ static void test_aws_external_account_creds_failure_invalid_region_url(void) { "Error occurred when fetching oauth2 token.", &error, 1); RequestMetadataState* state = RequestMetadataState::NewInstance(expected_error, {}); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); GRPC_ERROR_UNREF(error); } @@ -3293,11 +3314,12 @@ static void test_aws_external_account_creds_failure_invalid_url(void) { "Error occurred when fetching oauth2 token.", &error, 1); RequestMetadataState* state = RequestMetadataState::NewInstance(expected_error, {}); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); GRPC_ERROR_UNREF(error); } @@ -3335,11 +3357,12 @@ static void test_aws_external_account_creds_failure_missing_role_name(void) { "Error occurred when fetching oauth2 token.", &error, 1); RequestMetadataState* state = RequestMetadataState::NewInstance(expected_error, {}); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); GRPC_ERROR_UNREF(error); } @@ -3379,11 +3402,12 @@ test_aws_external_account_creds_failure_invalid_regional_cred_verification_url( "Error occurred when fetching oauth2 token.", &error, 1); RequestMetadataState* state = RequestMetadataState::NewInstance(expected_error, {}); - grpc_httpcli_set_override(aws_external_account_creds_httpcli_get_success, - aws_external_account_creds_httpcli_post_success); + grpc_core::HttpRequest::SetOverride( + aws_external_account_creds_httpcli_get_success, + aws_external_account_creds_httpcli_post_success); state->RunRequestMetadataTest(creds.get(), auth_md_ctx); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); GRPC_ERROR_UNREF(error); } diff --git a/test/core/security/jwt_verifier_test.cc b/test/core/security/jwt_verifier_test.cc index 933c413a9a0..24846cb8eaf 100644 --- a/test/core/security/jwt_verifier_test.cc +++ b/test/core/security/jwt_verifier_test.cc @@ -330,8 +330,8 @@ static char* good_google_email_keys(void) { return result; } -static grpc_httpcli_response http_response(int status, char* body) { - grpc_httpcli_response response; +static grpc_http_response http_response(int status, char* body) { + grpc_http_response response; response = {}; response.status = status; response.body = body; @@ -340,20 +340,21 @@ static grpc_httpcli_response http_response(int status, char* body) { } static int httpcli_post_should_not_be_called( - const grpc_httpcli_request* /*request*/, const char* /*body_bytes*/, - size_t /*body_size*/, grpc_millis /*deadline*/, grpc_closure* /*on_done*/, - grpc_httpcli_response* /*response*/) { + const grpc_http_request* /*request*/, const char* /*host*/, + const char* /*path*/, const char* /*body_bytes*/, size_t /*body_size*/, + grpc_millis /*deadline*/, grpc_closure* /*on_done*/, + grpc_http_response* /*response*/) { GPR_ASSERT("HTTP POST should not be called" == nullptr); return 1; } static int httpcli_get_google_keys_for_email( - const grpc_httpcli_request* request, grpc_millis /*deadline*/, - grpc_closure* on_done, grpc_httpcli_response* response) { + const grpc_http_request* /*request*/, const char* host, const char* path, + grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { *response = http_response(200, good_google_email_keys()); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); - GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0); - GPR_ASSERT(strcmp(request->http.path, + GPR_ASSERT(strcmp(host, "www.googleapis.com") == 0); + GPR_ASSERT(strcmp(path, "/robot/v1/metadata/x509/" "777-abaslkan11hlb6nmim3bpspl31ud@developer." "gserviceaccount.com") == 0); @@ -379,8 +380,8 @@ static void test_jwt_verifier_google_email_issuer_success(void) { grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); gpr_free(key_str); GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); - grpc_httpcli_set_override(httpcli_get_google_keys_for_email, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_google_keys_for_email, + httpcli_post_should_not_be_called); jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, nullptr); grpc_auth_json_key_destruct(&key); @@ -391,16 +392,16 @@ static void test_jwt_verifier_google_email_issuer_success(void) { grpc_jwt_verifier_destroy(verifier); grpc_core::ExecCtx::Get()->Flush(); gpr_free(jwt); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static int httpcli_get_custom_keys_for_email( - const grpc_httpcli_request* request, grpc_millis /*deadline*/, - grpc_closure* on_done, grpc_httpcli_response* response) { + const grpc_http_request* /*request*/, const char* host, const char* path, + grpc_millis /*deadline*/, grpc_closure* on_done, + grpc_http_response* response) { *response = http_response(200, gpr_strdup(good_jwk_set)); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); - GPR_ASSERT(strcmp(request->host, "keys.bar.com") == 0); - GPR_ASSERT(strcmp(request->http.path, "/jwk/foo@bar.com") == 0); + GPR_ASSERT(strcmp(host, "keys.bar.com") == 0); + GPR_ASSERT(strcmp(path, "/jwk/foo@bar.com") == 0); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; } @@ -413,8 +414,8 @@ static void test_jwt_verifier_custom_email_issuer_success(void) { grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); gpr_free(key_str); GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); - grpc_httpcli_set_override(httpcli_get_custom_keys_for_email, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_custom_keys_for_email, + httpcli_post_should_not_be_called); jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, nullptr); grpc_auth_json_key_destruct(&key); @@ -425,30 +426,30 @@ static void test_jwt_verifier_custom_email_issuer_success(void) { grpc_jwt_verifier_destroy(verifier); grpc_core::ExecCtx::Get()->Flush(); gpr_free(jwt); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } -static int httpcli_get_jwk_set(const grpc_httpcli_request* request, +static int httpcli_get_jwk_set(const grpc_http_request* /*request*/, + const char* host, const char* path, grpc_millis /*deadline*/, grpc_closure* on_done, - grpc_httpcli_response* response) { + grpc_http_response* response) { *response = http_response(200, gpr_strdup(good_jwk_set)); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); - GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0); - GPR_ASSERT(strcmp(request->http.path, "/oauth2/v3/certs") == 0); + GPR_ASSERT(strcmp(host, "www.googleapis.com") == 0); + GPR_ASSERT(strcmp(path, "/oauth2/v3/certs") == 0); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; } -static int httpcli_get_openid_config(const grpc_httpcli_request* request, +static int httpcli_get_openid_config(const grpc_http_request* /*request*/, + const char* host, const char* path, grpc_millis /*deadline*/, grpc_closure* on_done, - grpc_httpcli_response* response) { + grpc_http_response* response) { *response = http_response(200, gpr_strdup(good_openid_config)); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); - GPR_ASSERT(strcmp(request->host, "accounts.google.com") == 0); - GPR_ASSERT(strcmp(request->http.path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0); - grpc_httpcli_set_override(httpcli_get_jwk_set, - httpcli_post_should_not_be_called); + GPR_ASSERT(strcmp(host, "accounts.google.com") == 0); + GPR_ASSERT(strcmp(path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0); + grpc_core::HttpRequest::SetOverride(httpcli_get_jwk_set, + httpcli_post_should_not_be_called); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; } @@ -461,8 +462,8 @@ static void test_jwt_verifier_url_issuer_success(void) { grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); gpr_free(key_str); GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); - grpc_httpcli_set_override(httpcli_get_openid_config, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_openid_config, + httpcli_post_should_not_be_called); jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, nullptr); grpc_auth_json_key_destruct(&key); @@ -473,7 +474,7 @@ static void test_jwt_verifier_url_issuer_success(void) { grpc_jwt_verifier_destroy(verifier); grpc_core::ExecCtx::Get()->Flush(); gpr_free(jwt); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void on_verification_key_retrieval_error(void* user_data, @@ -484,11 +485,11 @@ static void on_verification_key_retrieval_error(void* user_data, GPR_ASSERT(user_data == (void*)expected_user_data); } -static int httpcli_get_bad_json(const grpc_httpcli_request* request, +static int httpcli_get_bad_json(const grpc_http_request* /* request */, + const char* /*host*/, const char* /*path*/, grpc_millis /*deadline*/, grpc_closure* on_done, - grpc_httpcli_response* response) { + grpc_http_response* response) { *response = http_response(200, gpr_strdup("{\"bad\": \"stuff\"}")); - GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl); grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_done, GRPC_ERROR_NONE); return 1; } @@ -501,8 +502,8 @@ static void test_jwt_verifier_url_issuer_bad_config(void) { grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); gpr_free(key_str); GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); - grpc_httpcli_set_override(httpcli_get_bad_json, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_bad_json, + httpcli_post_should_not_be_called); jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, nullptr); grpc_auth_json_key_destruct(&key); @@ -513,7 +514,7 @@ static void test_jwt_verifier_url_issuer_bad_config(void) { grpc_jwt_verifier_destroy(verifier); grpc_core::ExecCtx::Get()->Flush(); gpr_free(jwt); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void test_jwt_verifier_bad_json_key(void) { @@ -524,8 +525,8 @@ static void test_jwt_verifier_bad_json_key(void) { grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); gpr_free(key_str); GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); - grpc_httpcli_set_override(httpcli_get_bad_json, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_bad_json, + httpcli_post_should_not_be_called); jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, nullptr); grpc_auth_json_key_destruct(&key); @@ -536,7 +537,7 @@ static void test_jwt_verifier_bad_json_key(void) { grpc_jwt_verifier_destroy(verifier); grpc_core::ExecCtx::Get()->Flush(); gpr_free(jwt); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static void corrupt_jwt_sig(char* jwt) { @@ -575,8 +576,8 @@ static void test_jwt_verifier_bad_signature(void) { grpc_auth_json_key key = grpc_auth_json_key_create_from_string(key_str); gpr_free(key_str); GPR_ASSERT(grpc_auth_json_key_is_valid(&key)); - grpc_httpcli_set_override(httpcli_get_openid_config, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_openid_config, + httpcli_post_should_not_be_called); jwt = grpc_jwt_encode_and_sign(&key, expected_audience, expected_lifetime, nullptr); grpc_auth_json_key_destruct(&key); @@ -588,12 +589,13 @@ static void test_jwt_verifier_bad_signature(void) { gpr_free(jwt); grpc_jwt_verifier_destroy(verifier); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } static int httpcli_get_should_not_be_called( - const grpc_httpcli_request* /*request*/, grpc_millis /*deadline*/, - grpc_closure* /*on_done*/, grpc_httpcli_response* /*response*/) { + const grpc_http_request* /*request*/, const char* /*host*/, + const char* /*path*/, grpc_millis /*deadline*/, grpc_closure* /*on_done*/, + grpc_http_response* /*response*/) { GPR_ASSERT(0); return 1; } @@ -609,14 +611,14 @@ static void on_verification_bad_format(void* user_data, static void test_jwt_verifier_bad_format(void) { grpc_core::ExecCtx exec_ctx; grpc_jwt_verifier* verifier = grpc_jwt_verifier_create(nullptr, 0); - grpc_httpcli_set_override(httpcli_get_should_not_be_called, - httpcli_post_should_not_be_called); + grpc_core::HttpRequest::SetOverride(httpcli_get_should_not_be_called, + httpcli_post_should_not_be_called); grpc_jwt_verifier_verify(verifier, nullptr, "bad jwt", expected_audience, on_verification_bad_format, const_cast(expected_user_data)); grpc_jwt_verifier_destroy(verifier); grpc_core::ExecCtx::Get()->Flush(); - grpc_httpcli_set_override(nullptr, nullptr); + grpc_core::HttpRequest::SetOverride(nullptr, nullptr); } /* find verification key: bad jks, cannot find key in jks */ diff --git a/test/core/util/evaluate_args_test_util.h b/test/core/util/evaluate_args_test_util.h index 6beadf56860..60a0842ca9b 100644 --- a/test/core/util/evaluate_args_test_util.h +++ b/test/core/util/evaluate_args_test_util.h @@ -21,6 +21,7 @@ #include +#include "src/core/lib/resource_quota/resource_quota.h" #include "src/core/lib/security/authorization/evaluate_args.h" #include "test/core/util/mock_authorization_endpoint.h" diff --git a/test/core/util/fake_udp_and_tcp_server.cc b/test/core/util/fake_udp_and_tcp_server.cc index 44193fee76c..858ebc3417d 100644 --- a/test/core/util/fake_udp_and_tcp_server.cc +++ b/test/core/util/fake_udp_and_tcp_server.cc @@ -30,17 +30,31 @@ #include "src/core/lib/iomgr/tcp_windows.h" #define BAD_SOCKET_RETURN_VAL INVALID_SOCKET #define CLOSE_SOCKET closesocket +#define ERRNO WSAGetLastError() #else #include #include "src/core/lib/iomgr/sockaddr_posix.h" #define BAD_SOCKET_RETURN_VAL (-1) #define CLOSE_SOCKET close +#define ERRNO errno #endif namespace grpc_core { namespace testing { +namespace { + +bool ErrorIsRetryable(int error) { +#ifdef GPR_WINDOWS + return error == WSAEWOULDBLOCK || error == WSAEINPROGRESS; +#else + return error == EWOULDBLOCK || error == EAGAIN; +#endif +} + +} // namespace + FakeUdpAndTcpServer::FakeUdpAndTcpServer( AcceptMode accept_mode, std::function @@ -49,13 +63,13 @@ FakeUdpAndTcpServer::FakeUdpAndTcpServer( port_ = grpc_pick_unused_port_or_die(); udp_socket_ = socket(AF_INET6, SOCK_DGRAM, 0); if (udp_socket_ == BAD_SOCKET_RETURN_VAL) { - gpr_log(GPR_DEBUG, "Failed to create UDP ipv6 socket: %d", errno); + gpr_log(GPR_DEBUG, "Failed to create UDP ipv6 socket: %d", ERRNO); GPR_ASSERT(0); } accept_socket_ = socket(AF_INET6, SOCK_STREAM, 0); - address_ = absl::StrCat("[::]:", port_); + address_ = absl::StrCat("[::1]:", port_); if (accept_socket_ == BAD_SOCKET_RETURN_VAL) { - gpr_log(GPR_ERROR, "Failed to create TCP IPv6 socket: %d", errno); + gpr_log(GPR_ERROR, "Failed to create TCP IPv6 socket: %d", ERRNO); GPR_ASSERT(0); } #ifdef GPR_WINDOWS @@ -65,7 +79,7 @@ FakeUdpAndTcpServer::FakeUdpAndTcpServer( gpr_log(GPR_DEBUG, "Failed to set SO_REUSEADDR on TCP ipv6 socket to [::1]:%d, " "errno: %d", - port_, errno); + port_, ERRNO); GPR_ASSERT(0); } grpc_error_handle set_non_block_error; @@ -89,11 +103,11 @@ FakeUdpAndTcpServer::FakeUdpAndTcpServer( GPR_ASSERT(0); } if (fcntl(udp_socket_, F_SETFL, O_NONBLOCK) != 0) { - gpr_log(GPR_ERROR, "Failed to set O_NONBLOCK on socket: %d", errno); + gpr_log(GPR_ERROR, "Failed to set O_NONBLOCK on socket: %d", ERRNO); GPR_ASSERT(0); } if (fcntl(accept_socket_, F_SETFL, O_NONBLOCK) != 0) { - gpr_log(GPR_ERROR, "Failed to set O_NONBLOCK on socket: %d", errno); + gpr_log(GPR_ERROR, "Failed to set O_NONBLOCK on socket: %d", ERRNO); GPR_ASSERT(0); } #endif @@ -110,12 +124,12 @@ FakeUdpAndTcpServer::FakeUdpAndTcpServer( if (bind(accept_socket_, reinterpret_cast(&addr), sizeof(addr)) != 0) { gpr_log(GPR_ERROR, "Failed to bind TCP socket to [::1]:%d : %d", port_, - errno); + ERRNO); GPR_ASSERT(0); } if (listen(accept_socket_, 100)) { gpr_log(GPR_ERROR, "Failed to listen on socket bound to [::1]:%d : %d", - port_, errno); + port_, ERRNO); GPR_ASSERT(0); } gpr_event_init(&stop_ev_); @@ -139,10 +153,9 @@ FakeUdpAndTcpServer::~FakeUdpAndTcpServer() { FakeUdpAndTcpServer::ProcessReadResult FakeUdpAndTcpServer::CloseSocketUponReceivingBytesFromPeer( int bytes_received_size, int read_error, int s) { - if (bytes_received_size < 0 && read_error != EAGAIN && - read_error != EWOULDBLOCK) { + if (bytes_received_size < 0 && !ErrorIsRetryable(read_error)) { gpr_log(GPR_ERROR, "Failed to receive from peer socket: %d. errno: %d", s, - errno); + read_error); GPR_ASSERT(0); } if (bytes_received_size >= 0) { @@ -159,10 +172,9 @@ FakeUdpAndTcpServer::CloseSocketUponReceivingBytesFromPeer( FakeUdpAndTcpServer::ProcessReadResult FakeUdpAndTcpServer::CloseSocketUponCloseFromPeer(int bytes_received_size, int read_error, int s) { - if (bytes_received_size < 0 && read_error != EAGAIN && - read_error != EWOULDBLOCK) { + if (bytes_received_size < 0 && !ErrorIsRetryable(read_error)) { gpr_log(GPR_ERROR, "Failed to receive from peer socket: %d. errno: %d", s, - errno); + read_error); GPR_ASSERT(0); } if (bytes_received_size == 0) { @@ -198,11 +210,11 @@ void FakeUdpAndTcpServer::FakeUdpAndTcpServerPeer:: int bytes_sent = send(fd_, kEmptyHttp2SettingsFrame.data() + total_bytes_sent_, bytes_to_send, 0); - if (bytes_sent < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + if (bytes_sent < 0 && !ErrorIsRetryable(ERRNO)) { gpr_log(GPR_ERROR, - "Fake TCP server encountered unexpected error:%d |%s| " + "Fake TCP server encountered unexpected error:%d " "sending %d bytes on fd:%d", - errno, strerror(errno), bytes_to_send, fd_); + ERRNO, bytes_to_send, fd_); GPR_ASSERT(0); } else if (bytes_sent > 0) { total_bytes_sent_ += bytes_sent; @@ -234,7 +246,7 @@ void FakeUdpAndTcpServer::RunServerLoop() { #else if (fcntl(p, F_SETFL, O_NONBLOCK) != 0) { gpr_log(GPR_ERROR, "Failed to configure non-blocking socket, errno: %d", - errno); + ERRNO); GPR_ASSERT(0); } #endif @@ -249,7 +261,7 @@ void FakeUdpAndTcpServer::RunServerLoop() { char buf[100]; int bytes_received_size = recv(peer->fd(), buf, 100, 0); FakeUdpAndTcpServer::ProcessReadResult r = - process_read_cb_(bytes_received_size, errno, peer->fd()); + process_read_cb_(bytes_received_size, ERRNO, peer->fd()); if (r == FakeUdpAndTcpServer::ProcessReadResult::kCloseSocket) { it = peers.erase(it); } else { diff --git a/test/core/util/port_server_client.cc b/test/core/util/port_server_client.cc index f5b5e28f953..385f9c2685a 100644 --- a/test/core/util/port_server_client.cc +++ b/test/core/util/port_server_client.cc @@ -24,6 +24,8 @@ #include #include +#include "absl/strings/str_format.h" + #include #include #include @@ -58,10 +60,9 @@ static void freed_port_from_server(void* arg, grpc_error_handle /*error*/) { } void grpc_free_port_using_server(int port) { - grpc_httpcli_request req; - grpc_httpcli_response rsp; + grpc_http_request req; + grpc_http_response rsp; freereq pr; - char* path; grpc_closure* shutdown_closure; grpc_init(); @@ -79,15 +80,19 @@ void grpc_free_port_using_server(int port) { shutdown_closure = GRPC_CLOSURE_CREATE(destroy_pops_and_shutdown, &pr.pops, grpc_schedule_on_exec_ctx); - req.host = const_cast(GRPC_PORT_SERVER_ADDRESS); - gpr_asprintf(&path, "/drop/%d", port); - req.http.path = path; - - grpc_httpcli_get(&pr.pops, grpc_core::ResourceQuota::Default(), &req, - grpc_core::ExecCtx::Get()->Now() + 30 * GPR_MS_PER_SEC, - GRPC_CLOSURE_CREATE(freed_port_from_server, &pr, - grpc_schedule_on_exec_ctx), - &rsp); + std::string path = absl::StrFormat("/drop/%d", port); + auto uri = grpc_core::URI::Create("https", GRPC_PORT_SERVER_ADDRESS, path, + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); + auto http_request = grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, &pr.pops, &req, + grpc_core::ExecCtx::Get()->Now() + 30 * GPR_MS_PER_SEC, + GRPC_CLOSURE_CREATE(freed_port_from_server, &pr, + grpc_schedule_on_exec_ctx), + &rsp, + grpc_core::RefCountedPtr( + nullptr /* insecure credentials */)); + http_request->Start(); grpc_core::ExecCtx::Get()->Flush(); gpr_mu_lock(pr.mu); while (!pr.done) { @@ -105,7 +110,6 @@ void grpc_free_port_using_server(int port) { grpc_pollset_shutdown(grpc_polling_entity_pollset(&pr.pops), shutdown_closure); - gpr_free(path); grpc_http_response_destroy(&rsp); } grpc_shutdown(); @@ -117,15 +121,17 @@ typedef struct portreq { int port = 0; int retries = 0; char* server = nullptr; - grpc_httpcli_response response = {}; + grpc_http_response response = {}; + grpc_core::OrphanablePtr http_request; } portreq; static void got_port_from_server(void* arg, grpc_error_handle error) { size_t i; int port = 0; portreq* pr = static_cast(arg); + pr->http_request.reset(); int failed = 0; - grpc_httpcli_response* response = &pr->response; + grpc_http_response* response = &pr->response; if (error != GRPC_ERROR_NONE) { failed = 1; @@ -138,7 +144,7 @@ static void got_port_from_server(void* arg, grpc_error_handle error) { } if (failed) { - grpc_httpcli_request req; + grpc_http_request req; memset(&req, 0, sizeof(req)); if (pr->retries >= 5) { gpr_mu_lock(pr->mu); @@ -157,15 +163,20 @@ static void got_port_from_server(void* arg, grpc_error_handle error) { 1000.0 * (1 + pow(1.3, pr->retries) * rand() / RAND_MAX)), GPR_TIMESPAN))); pr->retries++; - req.host = pr->server; - req.http.path = const_cast("/get"); grpc_http_response_destroy(&pr->response); pr->response = {}; - grpc_httpcli_get(&pr->pops, grpc_core::ResourceQuota::Default(), &req, - grpc_core::ExecCtx::Get()->Now() + 30 * GPR_MS_PER_SEC, - GRPC_CLOSURE_CREATE(got_port_from_server, pr, - grpc_schedule_on_exec_ctx), - &pr->response); + auto uri = grpc_core::URI::Create("http", pr->server, "/get", + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); + pr->http_request = grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, &pr->pops, &req, + grpc_core::ExecCtx::Get()->Now() + 30 * GPR_MS_PER_SEC, + GRPC_CLOSURE_CREATE(got_port_from_server, pr, + grpc_schedule_on_exec_ctx), + &pr->response, + grpc_core::RefCountedPtr( + nullptr /* insecure credentials */)); + pr->http_request->Start(); return; } GPR_ASSERT(response); @@ -184,7 +195,7 @@ static void got_port_from_server(void* arg, grpc_error_handle error) { } int grpc_pick_port_using_server(void) { - grpc_httpcli_request req; + grpc_http_request req; portreq pr; grpc_closure* shutdown_closure; @@ -201,15 +212,18 @@ int grpc_pick_port_using_server(void) { grpc_schedule_on_exec_ctx); pr.port = -1; pr.server = const_cast(GRPC_PORT_SERVER_ADDRESS); - - req.host = const_cast(GRPC_PORT_SERVER_ADDRESS); - req.http.path = const_cast("/get"); - - grpc_httpcli_get(&pr.pops, grpc_core::ResourceQuota::Default(), &req, - grpc_core::ExecCtx::Get()->Now() + 30 * GPR_MS_PER_SEC, - GRPC_CLOSURE_CREATE(got_port_from_server, &pr, - grpc_schedule_on_exec_ctx), - &pr.response); + auto uri = grpc_core::URI::Create("http", GRPC_PORT_SERVER_ADDRESS, "/get", + {} /* query params */, "" /* fragment */); + GPR_ASSERT(uri.ok()); + auto http_request = grpc_core::HttpRequest::Get( + std::move(*uri), nullptr /* channel args */, &pr.pops, &req, + grpc_core::ExecCtx::Get()->Now() + 30 * GPR_MS_PER_SEC, + GRPC_CLOSURE_CREATE(got_port_from_server, &pr, + grpc_schedule_on_exec_ctx), + &pr.response, + grpc_core::RefCountedPtr( + nullptr /*insecure credentials*/)); + http_request->Start(); grpc_core::ExecCtx::Get()->Flush(); gpr_mu_lock(pr.mu); while (pr.port == -1) { diff --git a/test/cpp/ext/filters/census/BUILD b/test/cpp/ext/filters/census/BUILD index 94ec048dfdf..0a243484168 100644 --- a/test/cpp/ext/filters/census/BUILD +++ b/test/cpp/ext/filters/census/BUILD @@ -30,6 +30,7 @@ grpc_cc_test( "opencensus-with-tag-map", ], language = "C++", + linkstatic = True, tags = ["no_windows"], # TODO(jtattermusch): fix test on windows deps = [ "//:grpc++", diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 07e0ca9bd13..99cacf1f6e5 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -1885,6 +1885,7 @@ src/core/lib/http/format_request.h \ src/core/lib/http/httpcli.cc \ src/core/lib/http/httpcli.h \ src/core/lib/http/httpcli_security_connector.cc \ +src/core/lib/http/httpcli_ssl_credentials.h \ src/core/lib/http/parser.cc \ src/core/lib/http/parser.h \ src/core/lib/iomgr/block_annotate.h \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index d60c66ce819..61d6a3f0005 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -1683,6 +1683,7 @@ src/core/lib/http/format_request.h \ src/core/lib/http/httpcli.cc \ src/core/lib/http/httpcli.h \ src/core/lib/http/httpcli_security_connector.cc \ +src/core/lib/http/httpcli_ssl_credentials.h \ src/core/lib/http/parser.cc \ src/core/lib/http/parser.h \ src/core/lib/iomgr/README.md \ diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 83cb3139f86..89c570f6997 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -1421,50 +1421,6 @@ ], "uses_polling": false }, - { - "args": [], - "benchmark": false, - "ci_platforms": [ - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "gtest": false, - "language": "c", - "name": "httpcli_test", - "platforms": [ - "linux", - "mac", - "posix" - ], - "uses_polling": true - }, - { - "args": [], - "benchmark": false, - "ci_platforms": [ - "linux", - "mac", - "posix" - ], - "cpu_cost": 1.0, - "exclude_configs": [], - "exclude_iomgrs": [], - "flaky": false, - "gtest": false, - "language": "c", - "name": "httpscli_test", - "platforms": [ - "linux", - "mac", - "posix" - ], - "uses_polling": true - }, { "args": [], "benchmark": false, @@ -4831,6 +4787,50 @@ ], "uses_polling": false }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "httpcli_test", + "platforms": [ + "linux", + "mac", + "posix" + ], + "uses_polling": true + }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "httpscli_test", + "platforms": [ + "linux", + "mac", + "posix" + ], + "uses_polling": true + }, { "args": [], "benchmark": false,