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