Merge pull request #14112 from yashykt/badclient

Bad client changes Part I
pull/12820/merge
Yash Tibrewal 7 years ago committed by GitHub
commit a984e458bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      CMakeLists.txt
  2. 24
      Makefile
  3. 299
      test/core/bad_client/bad_client.cc
  4. 63
      test/core/bad_client/bad_client.h
  5. 2
      test/core/bad_client/gen_build_yaml.py
  6. 2
      test/core/bad_client/generate_tests.bzl
  7. 3
      test/core/bad_client/tests/head_of_line_blocking.cc
  8. 119
      test/core/bad_client/tests/large_metadata.cc
  9. 11
      test/core/bad_client/tests/window_overflow.cc
  10. 18
      tools/run_tests/generated/sources_and_headers.json
  11. 26
      tools/run_tests/generated/tests.json

@ -392,6 +392,7 @@ add_dependencies(buildtests_c connection_prefix_bad_client_test)
add_dependencies(buildtests_c head_of_line_blocking_bad_client_test) add_dependencies(buildtests_c head_of_line_blocking_bad_client_test)
add_dependencies(buildtests_c headers_bad_client_test) add_dependencies(buildtests_c headers_bad_client_test)
add_dependencies(buildtests_c initial_settings_frame_bad_client_test) add_dependencies(buildtests_c initial_settings_frame_bad_client_test)
add_dependencies(buildtests_c large_metadata_bad_client_test)
add_dependencies(buildtests_c server_registered_method_bad_client_test) add_dependencies(buildtests_c server_registered_method_bad_client_test)
add_dependencies(buildtests_c simple_request_bad_client_test) add_dependencies(buildtests_c simple_request_bad_client_test)
add_dependencies(buildtests_c unknown_frame_bad_client_test) add_dependencies(buildtests_c unknown_frame_bad_client_test)
@ -12455,6 +12456,35 @@ target_link_libraries(initial_settings_frame_bad_client_test
endif (gRPC_BUILD_TESTS) endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS)
add_executable(large_metadata_bad_client_test
test/core/bad_client/tests/large_metadata.cc
)
target_include_directories(large_metadata_bad_client_test
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${_gRPC_SSL_INCLUDE_DIR}
PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR}
PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR}
PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR}
PRIVATE ${_gRPC_CARES_INCLUDE_DIR}
PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR}
)
target_link_libraries(large_metadata_bad_client_test
${_gRPC_SSL_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
bad_client_test
grpc_test_util_unsecure
grpc_unsecure
gpr_test_util
gpr
)
endif (gRPC_BUILD_TESTS)
if (gRPC_BUILD_TESTS)
add_executable(server_registered_method_bad_client_test add_executable(server_registered_method_bad_client_test
test/core/bad_client/tests/server_registered_method.cc test/core/bad_client/tests/server_registered_method.cc
) )

@ -1237,6 +1237,7 @@ connection_prefix_bad_client_test: $(BINDIR)/$(CONFIG)/connection_prefix_bad_cli
head_of_line_blocking_bad_client_test: $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test head_of_line_blocking_bad_client_test: $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test
headers_bad_client_test: $(BINDIR)/$(CONFIG)/headers_bad_client_test headers_bad_client_test: $(BINDIR)/$(CONFIG)/headers_bad_client_test
initial_settings_frame_bad_client_test: $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test initial_settings_frame_bad_client_test: $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test
large_metadata_bad_client_test: $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test
server_registered_method_bad_client_test: $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test server_registered_method_bad_client_test: $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test
simple_request_bad_client_test: $(BINDIR)/$(CONFIG)/simple_request_bad_client_test simple_request_bad_client_test: $(BINDIR)/$(CONFIG)/simple_request_bad_client_test
unknown_frame_bad_client_test: $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test unknown_frame_bad_client_test: $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test
@ -1489,6 +1490,7 @@ buildtests_c: privatelibs_c \
$(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \ $(BINDIR)/$(CONFIG)/head_of_line_blocking_bad_client_test \
$(BINDIR)/$(CONFIG)/headers_bad_client_test \ $(BINDIR)/$(CONFIG)/headers_bad_client_test \
$(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test \ $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test \
$(BINDIR)/$(CONFIG)/large_metadata_bad_client_test \
$(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test \ $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test \
$(BINDIR)/$(CONFIG)/simple_request_bad_client_test \ $(BINDIR)/$(CONFIG)/simple_request_bad_client_test \
$(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test \ $(BINDIR)/$(CONFIG)/unknown_frame_bad_client_test \
@ -2032,6 +2034,8 @@ test_c: buildtests_c
$(Q) $(BINDIR)/$(CONFIG)/headers_bad_client_test || ( echo test headers_bad_client_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/headers_bad_client_test || ( echo test headers_bad_client_test failed ; exit 1 )
$(E) "[RUN] Testing initial_settings_frame_bad_client_test" $(E) "[RUN] Testing initial_settings_frame_bad_client_test"
$(Q) $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test || ( echo test initial_settings_frame_bad_client_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/initial_settings_frame_bad_client_test || ( echo test initial_settings_frame_bad_client_test failed ; exit 1 )
$(E) "[RUN] Testing large_metadata_bad_client_test"
$(Q) $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test || ( echo test large_metadata_bad_client_test failed ; exit 1 )
$(E) "[RUN] Testing server_registered_method_bad_client_test" $(E) "[RUN] Testing server_registered_method_bad_client_test"
$(Q) $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test || ( echo test server_registered_method_bad_client_test failed ; exit 1 ) $(Q) $(BINDIR)/$(CONFIG)/server_registered_method_bad_client_test || ( echo test server_registered_method_bad_client_test failed ; exit 1 )
$(E) "[RUN] Testing simple_request_bad_client_test" $(E) "[RUN] Testing simple_request_bad_client_test"
@ -18851,6 +18855,26 @@ ifneq ($(NO_DEPS),true)
endif endif
LARGE_METADATA_BAD_CLIENT_TEST_SRC = \
test/core/bad_client/tests/large_metadata.cc \
LARGE_METADATA_BAD_CLIENT_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LARGE_METADATA_BAD_CLIENT_TEST_SRC))))
$(BINDIR)/$(CONFIG)/large_metadata_bad_client_test: $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
$(E) "[LD] Linking $@"
$(Q) mkdir -p `dirname $@`
$(Q) $(LD) $(LDFLAGS) $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) -o $(BINDIR)/$(CONFIG)/large_metadata_bad_client_test
$(OBJDIR)/$(CONFIG)/test/core/bad_client/tests/large_metadata.o: $(LIBDIR)/$(CONFIG)/libbad_client_test.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util_unsecure.a $(LIBDIR)/$(CONFIG)/libgrpc_unsecure.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a
deps_large_metadata_bad_client_test: $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS:.o=.dep)
ifneq ($(NO_DEPS),true)
-include $(LARGE_METADATA_BAD_CLIENT_TEST_OBJS:.o=.dep)
endif
SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_SRC = \ SERVER_REGISTERED_METHOD_BAD_CLIENT_TEST_SRC = \
test/core/bad_client/tests/server_registered_method.cc \ test/core/bad_client/tests/server_registered_method.cc \

@ -34,25 +34,32 @@
#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_internal.h"
#include "src/core/lib/surface/completion_queue.h" #include "src/core/lib/surface/completion_queue.h"
#include "src/core/lib/surface/server.h" #include "src/core/lib/surface/server.h"
#include "test/core/end2end/cq_verifier.h"
#define MIN_HTTP2_FRAME_SIZE 9
/* Args to provide to thread running server side validator */
typedef struct { typedef struct {
grpc_server* server; grpc_server* server;
grpc_completion_queue* cq; grpc_completion_queue* cq;
grpc_bad_client_server_side_validator validator; grpc_bad_client_server_side_validator validator;
void* registered_method; void* registered_method;
gpr_event done_thd; gpr_event done_thd;
gpr_event done_write;
} thd_args; } thd_args;
/* Run the server side validator and set done_thd once done */
static void thd_func(void* arg) { static void thd_func(void* arg) {
thd_args* a = (thd_args*)arg; thd_args* a = (thd_args*)arg;
a->validator(a->server, a->cq, a->registered_method); if (a->validator != nullptr) {
a->validator(a->server, a->cq, a->registered_method);
}
gpr_event_set(&a->done_thd, (void*)1); gpr_event_set(&a->done_thd, (void*)1);
} }
static void done_write(void* arg, grpc_error* error) { /* Sets the done_write event */
thd_args* a = (thd_args*)arg; static void set_done_write(void* arg, grpc_error* error) {
gpr_event_set(&a->done_write, (void*)1); gpr_event* done_write = (gpr_event*)arg;
gpr_event_set(done_write, (void*)1);
} }
static void server_setup_transport(void* ts, grpc_transport* transport) { static void server_setup_transport(void* ts, grpc_transport* transport) {
@ -62,136 +69,172 @@ static void server_setup_transport(void* ts, grpc_transport* transport) {
grpc_server_get_channel_args(a->server)); grpc_server_get_channel_args(a->server));
} }
static void read_done(void* arg, grpc_error* error) { /* Sets the read_done event */
static void set_read_done(void* arg, grpc_error* error) {
gpr_event* read_done = (gpr_event*)arg; gpr_event* read_done = (gpr_event*)arg;
gpr_event_set(read_done, (void*)1); gpr_event_set(read_done, (void*)1);
} }
void grpc_run_bad_client_test( /* shutdown client */
grpc_bad_client_server_side_validator server_validator, static void shutdown_client(grpc_endpoint** client_fd) {
grpc_bad_client_client_stream_validator client_validator, if (*client_fd != nullptr) {
const char* client_payload, size_t client_payload_length, uint32_t flags) { grpc_endpoint_shutdown(
grpc_endpoint_pair sfd; *client_fd, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Disconnect"));
thd_args a; grpc_endpoint_destroy(*client_fd);
gpr_thd_id id; grpc_core::ExecCtx::Get()->Flush();
char* hex; *client_fd = nullptr;
grpc_transport* transport; }
grpc_slice slice = }
grpc_slice_from_copied_buffer(client_payload, client_payload_length);
grpc_slice_buffer outgoing;
grpc_closure done_write_closure;
grpc_core::ExecCtx exec_ctx;
grpc_completion_queue* shutdown_cq;
if (client_payload_length < 4 * 1024) { /* Runs client side validator */
hex = gpr_dump(client_payload, client_payload_length, void grpc_run_client_side_validator(grpc_bad_client_arg* arg, uint32_t flags,
grpc_endpoint_pair* sfd,
grpc_completion_queue* client_cq) {
char* hex;
gpr_event done_write;
if (arg->client_payload_length < 4 * 1024) {
hex = gpr_dump(arg->client_payload, arg->client_payload_length,
GPR_DUMP_HEX | GPR_DUMP_ASCII); GPR_DUMP_HEX | GPR_DUMP_ASCII);
/* Add a debug log */ /* Add a debug log */
gpr_log(GPR_INFO, "TEST: %s", hex); gpr_log(GPR_INFO, "TEST: %s", hex);
gpr_free(hex); gpr_free(hex);
} else { } else {
gpr_log(GPR_INFO, "TEST: (%" PRIdPTR " byte long string)", gpr_log(GPR_INFO, "TEST: (%" PRIdPTR " byte long string)",
client_payload_length); arg->client_payload_length);
} }
/* Init grpc */ grpc_slice slice = grpc_slice_from_copied_buffer(arg->client_payload,
grpc_init(); arg->client_payload_length);
grpc_slice_buffer outgoing;
/* Create endpoints */ grpc_closure done_write_closure;
sfd = grpc_iomgr_create_endpoint_pair("fixture", nullptr); gpr_event_init(&done_write);
/* Create server, completion events */
a.server = grpc_server_create(nullptr, nullptr);
a.cq = grpc_completion_queue_create_for_next(nullptr);
gpr_event_init(&a.done_thd);
gpr_event_init(&a.done_write);
a.validator = server_validator;
grpc_server_register_completion_queue(a.server, a.cq, nullptr);
a.registered_method =
grpc_server_register_method(a.server, GRPC_BAD_CLIENT_REGISTERED_METHOD,
GRPC_BAD_CLIENT_REGISTERED_HOST,
GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER, 0);
grpc_server_start(a.server);
transport = grpc_create_chttp2_transport(nullptr, sfd.server, false);
server_setup_transport(&a, transport);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
/* Bind everything into the same pollset */
grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(a.cq));
grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq));
/* Check a ground truth */
GPR_ASSERT(grpc_server_has_open_connections(a.server));
/* Start validator */
gpr_thd_new(&id, "grpc_bad_client", thd_func, &a, nullptr);
grpc_slice_buffer_init(&outgoing); grpc_slice_buffer_init(&outgoing);
grpc_slice_buffer_add(&outgoing, slice); grpc_slice_buffer_add(&outgoing, slice);
GRPC_CLOSURE_INIT(&done_write_closure, done_write, &a, GRPC_CLOSURE_INIT(&done_write_closure, set_done_write, &done_write,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
/* Write data */ /* Write data */
grpc_endpoint_write(sfd.client, &outgoing, &done_write_closure); grpc_endpoint_write(sfd->client, &outgoing, &done_write_closure);
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
/* Await completion, unless the request is large and write may not finish /* Await completion, unless the request is large and write may not finish
* before the peer shuts down. */ * before the peer shuts down. */
if (!(flags & GRPC_BAD_CLIENT_LARGE_REQUEST)) { if (!(flags & GRPC_BAD_CLIENT_LARGE_REQUEST)) {
GPR_ASSERT( GPR_ASSERT(
gpr_event_wait(&a.done_write, grpc_timeout_seconds_to_deadline(5))); gpr_event_wait(&done_write, grpc_timeout_seconds_to_deadline(5)));
} }
if (flags & GRPC_BAD_CLIENT_DISCONNECT) { if (flags & GRPC_BAD_CLIENT_DISCONNECT) {
grpc_endpoint_shutdown( shutdown_client(&sfd->client);
sfd.client, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Forced Disconnect"));
grpc_endpoint_destroy(sfd.client);
grpc_core::ExecCtx::Get()->Flush();
sfd.client = nullptr;
} }
GPR_ASSERT(gpr_event_wait(&a.done_thd, grpc_timeout_seconds_to_deadline(5))); if (sfd->client != nullptr) {
/* Validate client stream, if requested. */
if (sfd.client != nullptr) { if (arg->client_validator != nullptr) {
// Validate client stream, if requested.
if (client_validator != nullptr) {
gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5); gpr_timespec deadline = grpc_timeout_seconds_to_deadline(5);
grpc_slice_buffer incoming; grpc_slice_buffer incoming;
grpc_slice_buffer_init(&incoming); grpc_slice_buffer_init(&incoming);
// We may need to do multiple reads to read the complete server response. /* We may need to do multiple reads to read the complete server
* response. */
while (true) { while (true) {
gpr_event read_done_event; gpr_event read_done_event;
gpr_event_init(&read_done_event); gpr_event_init(&read_done_event);
grpc_closure read_done_closure; grpc_closure read_done_closure;
GRPC_CLOSURE_INIT(&read_done_closure, read_done, &read_done_event, GRPC_CLOSURE_INIT(&read_done_closure, set_read_done, &read_done_event,
grpc_schedule_on_exec_ctx); grpc_schedule_on_exec_ctx);
grpc_endpoint_read(sfd.client, &incoming, &read_done_closure); grpc_endpoint_read(sfd->client, &incoming, &read_done_closure);
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
do { do {
GPR_ASSERT(gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0); GPR_ASSERT(gpr_time_cmp(deadline, gpr_now(deadline.clock_type)) > 0);
GPR_ASSERT( /* Perform a cq next just to provide a thread that can read incoming
grpc_completion_queue_next( bytes on the client fd */
a.cq, grpc_timeout_milliseconds_to_deadline(100), nullptr) GPR_ASSERT(grpc_completion_queue_next(
.type == GRPC_QUEUE_TIMEOUT); client_cq, grpc_timeout_milliseconds_to_deadline(100),
nullptr)
.type == GRPC_QUEUE_TIMEOUT);
} while (!gpr_event_get(&read_done_event)); } while (!gpr_event_get(&read_done_event));
if (client_validator(&incoming)) break; if (arg->client_validator(&incoming, arg->client_validator_arg)) break;
gpr_log(GPR_INFO, gpr_log(GPR_INFO,
"client validator failed; trying additional read " "client validator failed; trying additional read "
"in case we didn't get all the data"); "in case we didn't get all the data");
} }
grpc_slice_buffer_destroy_internal(&incoming); grpc_slice_buffer_destroy_internal(&incoming);
} }
// Shutdown.
grpc_endpoint_shutdown(
sfd.client, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Test Shutdown"));
grpc_endpoint_destroy(sfd.client);
grpc_core::ExecCtx::Get()->Flush(); grpc_core::ExecCtx::Get()->Flush();
} }
GPR_ASSERT( /* If the request was too large, then we need to forcefully shut down the
gpr_event_wait(&a.done_write, grpc_timeout_seconds_to_deadline(1))); * client, so that the write can be considered completed */
if (flags & GRPC_BAD_CLIENT_LARGE_REQUEST) {
shutdown_client(&sfd->client);
}
/* Make sure that the client is done writing */
while (!gpr_event_get(&done_write)) {
GPR_ASSERT(
grpc_completion_queue_next(
client_cq, grpc_timeout_milliseconds_to_deadline(100), nullptr)
.type == GRPC_QUEUE_TIMEOUT);
}
grpc_slice_buffer_destroy_internal(&outgoing);
grpc_core::ExecCtx::Get()->Flush();
}
void grpc_run_bad_client_test(
grpc_bad_client_server_side_validator server_validator,
grpc_bad_client_arg args[], int num_args, uint32_t flags) {
grpc_endpoint_pair sfd;
thd_args a;
grpc_transport* transport;
grpc_core::ExecCtx exec_ctx;
grpc_completion_queue* shutdown_cq;
grpc_completion_queue* client_cq;
/* Init grpc */
grpc_init();
/* Create endpoints */
sfd = grpc_iomgr_create_endpoint_pair("fixture", nullptr);
/* Create server, completion events */
a.server = grpc_server_create(nullptr, nullptr);
a.cq = grpc_completion_queue_create_for_next(nullptr);
client_cq = grpc_completion_queue_create_for_next(nullptr);
grpc_server_register_completion_queue(a.server, a.cq, nullptr);
a.registered_method =
grpc_server_register_method(a.server, GRPC_BAD_CLIENT_REGISTERED_METHOD,
GRPC_BAD_CLIENT_REGISTERED_HOST,
GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER, 0);
grpc_server_start(a.server);
transport = grpc_create_chttp2_transport(nullptr, sfd.server, false);
server_setup_transport(&a, transport);
grpc_chttp2_transport_start_reading(transport, nullptr, nullptr);
/* Bind fds to pollsets */
grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(client_cq));
grpc_endpoint_add_to_pollset(sfd.server, grpc_cq_pollset(a.cq));
/* Check a ground truth */
GPR_ASSERT(grpc_server_has_open_connections(a.server));
gpr_thd_id id;
gpr_event_init(&a.done_thd);
a.validator = server_validator;
/* Start validator */
gpr_thd_new(&id, "grpc_bad_client", thd_func, &a, nullptr);
for (int i = 0; i < num_args; i++) {
grpc_run_client_side_validator(&args[i], i == (num_args - 1) ? flags : 0,
&sfd, client_cq);
}
/* Wait for server thread to finish */
GPR_ASSERT(gpr_event_wait(&a.done_thd, grpc_timeout_seconds_to_deadline(1)));
/* Shutdown. */
shutdown_client(&sfd.client);
shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr); shutdown_cq = grpc_completion_queue_create_for_pluck(nullptr);
grpc_server_shutdown_and_notify(a.server, shutdown_cq, nullptr); grpc_server_shutdown_and_notify(a.server, shutdown_cq, nullptr);
GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, nullptr, GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, nullptr,
@ -201,7 +244,91 @@ void grpc_run_bad_client_test(
grpc_completion_queue_destroy(shutdown_cq); grpc_completion_queue_destroy(shutdown_cq);
grpc_server_destroy(a.server); grpc_server_destroy(a.server);
grpc_completion_queue_destroy(a.cq); grpc_completion_queue_destroy(a.cq);
grpc_slice_buffer_destroy_internal(&outgoing); grpc_completion_queue_destroy(client_cq);
grpc_shutdown(); grpc_shutdown();
} }
bool client_connection_preface_validator(grpc_slice_buffer* incoming,
void* arg) {
if (incoming->count < 1) {
return false;
}
grpc_slice slice = incoming->slices[0];
/* There should be atleast a settings frame present */
if (GRPC_SLICE_LENGTH(slice) < MIN_HTTP2_FRAME_SIZE) {
return false;
}
const uint8_t* p = GRPC_SLICE_START_PTR(slice);
/* Check the frame type (SETTINGS) */
if (*(p + 3) != 4) {
return false;
}
return true;
}
/* connection preface and settings frame to be sent by the client */
#define CONNECTION_PREFACE_FROM_CLIENT \
"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \
"\x00\x00\x00\x04\x00\x00\x00\x00\x00"
grpc_bad_client_arg connection_preface_arg = {
client_connection_preface_validator, nullptr,
CONNECTION_PREFACE_FROM_CLIENT, sizeof(CONNECTION_PREFACE_FROM_CLIENT) - 1};
bool rst_stream_client_validator(grpc_slice_buffer* incoming, void* arg) {
// Get last frame from incoming slice buffer.
grpc_slice_buffer last_frame_buffer;
grpc_slice_buffer_init(&last_frame_buffer);
grpc_slice_buffer_trim_end(incoming, 13, &last_frame_buffer);
GPR_ASSERT(last_frame_buffer.count == 1);
grpc_slice last_frame = last_frame_buffer.slices[0];
const uint8_t* p = GRPC_SLICE_START_PTR(last_frame);
bool success =
// Length == 4
*p++ != 0 || *p++ != 0 || *p++ != 4 ||
// Frame type (RST_STREAM)
*p++ != 3 ||
// Flags
*p++ != 0 ||
// Stream ID.
*p++ != 0 || *p++ != 0 || *p++ != 0 || *p++ != 1 ||
// Payload (error code)
*p++ == 0 || *p++ == 0 || *p++ == 0 || *p == 0 || *p == 11;
if (!success) {
gpr_log(GPR_INFO, "client expected RST_STREAM frame, not found");
}
grpc_slice_buffer_destroy(&last_frame_buffer);
return success;
}
static void* tag(intptr_t t) { return (void*)t; }
void server_verifier_request_call(grpc_server* server,
grpc_completion_queue* cq,
void* registered_method) {
grpc_call_error error;
grpc_call* s;
grpc_call_details call_details;
cq_verifier* cqv = cq_verifier_create(cq);
grpc_metadata_array request_metadata_recv;
grpc_call_details_init(&call_details);
grpc_metadata_array_init(&request_metadata_recv);
error = grpc_server_request_call(server, &s, &call_details,
&request_metadata_recv, cq, cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
cq_verify(cqv);
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.host, "localhost"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo/bar"));
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
}

@ -28,30 +28,69 @@
#define GRPC_BAD_CLIENT_REGISTERED_METHOD "/registered/bar" #define GRPC_BAD_CLIENT_REGISTERED_METHOD "/registered/bar"
#define GRPC_BAD_CLIENT_REGISTERED_HOST "localhost" #define GRPC_BAD_CLIENT_REGISTERED_HOST "localhost"
/* The server side validator function to run */
typedef void (*grpc_bad_client_server_side_validator)(grpc_server* server, typedef void (*grpc_bad_client_server_side_validator)(grpc_server* server,
grpc_completion_queue* cq, grpc_completion_queue* cq,
void* registered_method); void* registered_method);
// Returns false if we need to read more data. /* Returns false if we need to read more data. */
typedef bool (*grpc_bad_client_client_stream_validator)( typedef bool (*grpc_bad_client_client_stream_validator)(
grpc_slice_buffer* incoming); grpc_slice_buffer* incoming, void* arg);
struct grpc_bad_client_arg {
grpc_bad_client_client_stream_validator client_validator;
void* client_validator_arg;
const char* client_payload;
size_t client_payload_length;
};
/* Flags for grpc_run_bad_client_test */
#define GRPC_BAD_CLIENT_DISCONNECT 1 #define GRPC_BAD_CLIENT_DISCONNECT 1
#define GRPC_BAD_CLIENT_LARGE_REQUEST 2 #define GRPC_BAD_CLIENT_LARGE_REQUEST 2
/* Test runner. /* Test runner.
*
Create a server, and send client_payload to it as bytes from a client. * Create a server, and for each arg in \a args send client_payload. For each
Execute server_validator in a separate thread to assert that the bytes are * payload, run client_validator to make sure that the response is as expected.
handled as expected. */ * Also execute \a server_validator in a separate thread to assert that the
* bytes are handled as expected.
*
* The flags are only applicable to the last validator in the array. (This can
* be changed in the future if necessary)
*/
void grpc_run_bad_client_test( void grpc_run_bad_client_test(
grpc_bad_client_server_side_validator server_validator, grpc_bad_client_server_side_validator server_validator,
grpc_bad_client_client_stream_validator client_validator, grpc_bad_client_arg args[], int num_args, uint32_t flags);
const char* client_payload, size_t client_payload_length, uint32_t flags);
/* A hack to let old tests work as before. In these tests, instead of an array,
* the tests provide a single client_validator and payload
*/
#define COMBINE1(X, Y) X##Y
#define COMBINE(X, Y) COMBINE1(X, Y)
#define GRPC_RUN_BAD_CLIENT_TEST(server_validator, client_validator, payload, \
flags) \
grpc_bad_client_arg COMBINE(bca, __LINE__) = {client_validator, nullptr, \
payload, sizeof(payload) - 1}; \
grpc_run_bad_client_test(server_validator, &COMBINE(bca, __LINE__), 1, flags)
/* Helper validator functions */
/* Client side validator for connection preface from server. \a arg is unused */
bool client_connection_preface_validator(grpc_slice_buffer* incoming,
void* arg);
/* Client side validator for checking if reset stream is present at the end
* of the buffer. \a arg is unused.
*/
bool rst_stream_client_validator(grpc_slice_buffer* incoming, void* arg);
#define GRPC_RUN_BAD_CLIENT_TEST(server_validator, client_validator, payload, \ /* Helper grpc_bad_client_arg arguments for direct use */
flags) \ /* Sends a connection preface from the client with an empty settings frame */
grpc_run_bad_client_test(server_validator, client_validator, payload, \ extern grpc_bad_client_arg connection_preface_arg;
sizeof(payload) - 1, flags)
/* Server side verifier function that performs a
* single grpc_server_request_call */
void server_verifier_request_call(grpc_server* server,
grpc_completion_queue* cq,
void* registered_method);
#endif /* GRPC_TEST_CORE_BAD_CLIENT_BAD_CLIENT_H */ #endif /* GRPC_TEST_CORE_BAD_CLIENT_BAD_CLIENT_H */

@ -30,7 +30,7 @@ BAD_CLIENT_TESTS = {
'headers': default_test_options._replace(cpu_cost=0.2), 'headers': default_test_options._replace(cpu_cost=0.2),
'initial_settings_frame': default_test_options._replace(cpu_cost=0.2), 'initial_settings_frame': default_test_options._replace(cpu_cost=0.2),
'head_of_line_blocking': default_test_options, 'head_of_line_blocking': default_test_options,
# 'large_metadata': default_test_options, #disabling as per issue #11745 'large_metadata': default_test_options,
'server_registered_method': default_test_options, 'server_registered_method': default_test_options,
'simple_request': default_test_options, 'simple_request': default_test_options,
'window_overflow': default_test_options, 'window_overflow': default_test_options,

@ -28,7 +28,7 @@ BAD_CLIENT_TESTS = {
'headers': test_options(), 'headers': test_options(),
'initial_settings_frame': test_options(), 'initial_settings_frame': test_options(),
'head_of_line_blocking': test_options(), 'head_of_line_blocking': test_options(),
# 'large_metadata': test_options(), # disabling as per issue #11745 'large_metadata': test_options(),
'server_registered_method': test_options(), 'server_registered_method': test_options(),
'simple_request': test_options(), 'simple_request': test_options(),
'window_overflow': test_options(), 'window_overflow': test_options(),

@ -131,7 +131,8 @@ int main(int argc, char** argv) {
addbuf(hdr, sizeof(hdr)); addbuf(hdr, sizeof(hdr));
addbuf(msg, FRAME_SIZE); addbuf(msg, FRAME_SIZE);
} }
grpc_run_bad_client_test(verifier, nullptr, g_buffer, g_count, 0); grpc_bad_client_arg bca = {nullptr, nullptr, g_buffer, g_count};
grpc_run_bad_client_test(verifier, &bca, 1, 0);
gpr_free(g_buffer); gpr_free(g_buffer);
grpc_shutdown(); grpc_shutdown();

@ -31,23 +31,20 @@
// be longer than the C99 string literal limit. Instead, we dynamically // be longer than the C99 string literal limit. Instead, we dynamically
// construct it by adding the large headers one at a time. // construct it by adding the large headers one at a time.
#define PFX_TOO_MUCH_METADATA_FROM_CLIENT_PREFIX_STR \ /* headers: generated from large_metadata.headers in this directory */
"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" /* settings frame */ \ #define PFX_TOO_MUCH_METADATA_FROM_CLIENT_REQUEST \
"\x00\x00\x00\x04\x00\x00\x00\x00\x00" /* headers: generated from \ "\x00\x00\x00\x04\x01\x00\x00\x00\x00" \
large_metadata.headers in this \ "\x00" \
directory */ \ "5{\x01\x05\x00\x00\x00\x01" \
"\x00\x00\x00\x04\x01\x00\x00\x00\x00" \ "\x10\x05:path\x08/foo/bar" \
"\x00" \ "\x10\x07:scheme\x04http" \
"5{\x01\x05\x00\x00\x00\x01" \ "\x10\x07:method\x04POST" \
"\x10\x05:path\x08/foo/bar" \ "\x10\x0a:authority\x09localhost" \
"\x10\x07:scheme\x04http" \ "\x10\x0c" \
"\x10\x07:method\x04POST" \ "content-type\x10" \
"\x10\x0a:authority\x09localhost" \ "application/grpc" \
"\x10\x0c" \ "\x10\x14grpc-accept-encoding\x15identity,deflate,gzip" \
"content-type\x10" \ "\x10\x02te\x08trailers" \
"application/grpc" \
"\x10\x14grpc-accept-encoding\x15identity,deflate,gzip" \
"\x10\x02te\x08trailers" \
"\x10\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)" "\x10\x0auser-agent\"bad-client grpc-c/0.12.0.0 (linux)"
// Each large-metadata header is constructed from these start and end // Each large-metadata header is constructed from these start and end
@ -65,8 +62,8 @@
// The number of headers we're adding and the total size of the client // The number of headers we're adding and the total size of the client
// payload. // payload.
#define NUM_HEADERS 46 #define NUM_HEADERS 46
#define PFX_TOO_MUCH_METADATA_FROM_CLIENT_PAYLOAD_SIZE \ #define TOO_MUCH_METADATA_FROM_CLIENT_REQUEST_SIZE \
((sizeof(PFX_TOO_MUCH_METADATA_FROM_CLIENT_PREFIX_STR) - 1) + \ ((sizeof(PFX_TOO_MUCH_METADATA_FROM_CLIENT_REQUEST) - 1) + \
(NUM_HEADERS * PFX_TOO_MUCH_METADATA_FROM_CLIENT_HEADER_SIZE) + 1) (NUM_HEADERS * PFX_TOO_MUCH_METADATA_FROM_CLIENT_HEADER_SIZE) + 1)
#define PFX_TOO_MUCH_METADATA_FROM_SERVER_STR \ #define PFX_TOO_MUCH_METADATA_FROM_SERVER_STR \
@ -95,32 +92,6 @@
static void* tag(intptr_t t) { return (void*)t; } static void* tag(intptr_t t) { return (void*)t; }
static void server_verifier(grpc_server* server, grpc_completion_queue* cq,
void* registered_method) {
grpc_call_error error;
grpc_call* s;
grpc_call_details call_details;
cq_verifier* cqv = cq_verifier_create(cq);
grpc_metadata_array request_metadata_recv;
grpc_call_details_init(&call_details);
grpc_metadata_array_init(&request_metadata_recv);
error = grpc_server_request_call(server, &s, &call_details,
&request_metadata_recv, cq, cq, tag(101));
GPR_ASSERT(GRPC_CALL_OK == error);
CQ_EXPECT_COMPLETION(cqv, tag(101), 1);
cq_verify(cqv);
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.host, "localhost"));
GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo/bar"));
grpc_metadata_array_destroy(&request_metadata_recv);
grpc_call_details_destroy(&call_details);
grpc_call_unref(s);
cq_verifier_destroy(cqv);
}
static void server_verifier_sends_too_much_metadata(grpc_server* server, static void server_verifier_sends_too_much_metadata(grpc_server* server,
grpc_completion_queue* cq, grpc_completion_queue* cq,
void* registered_method) { void* registered_method) {
@ -167,43 +138,6 @@ static void server_verifier_sends_too_much_metadata(grpc_server* server,
cq_verifier_destroy(cqv); cq_verifier_destroy(cqv);
} }
static bool client_validator(grpc_slice_buffer* incoming) {
for (size_t i = 0; i < incoming->count; ++i) {
const char* s = (const char*)GRPC_SLICE_START_PTR(incoming->slices[i]);
char* hex = gpr_dump(s, GRPC_SLICE_LENGTH(incoming->slices[i]),
GPR_DUMP_HEX | GPR_DUMP_ASCII);
gpr_log(GPR_INFO, "RESPONSE SLICE %" PRIdPTR ": %s", i, hex);
gpr_free(hex);
}
// Get last frame from incoming slice buffer.
grpc_slice_buffer last_frame_buffer;
grpc_slice_buffer_init(&last_frame_buffer);
grpc_slice_buffer_trim_end(incoming, 13, &last_frame_buffer);
GPR_ASSERT(last_frame_buffer.count == 1);
grpc_slice last_frame = last_frame_buffer.slices[0];
const uint8_t* p = GRPC_SLICE_START_PTR(last_frame);
bool success =
// Length == 4
*p++ != 0 || *p++ != 0 || *p++ != 4 ||
// Frame type (RST_STREAM)
*p++ != 3 ||
// Flags
*p++ != 0 ||
// Stream ID.
*p++ != 0 || *p++ != 0 || *p++ != 0 || *p++ != 1 ||
// Payload (error code)
*p++ == 0 || *p++ == 0 || *p++ == 0 || *p == 0 || *p == 11;
if (!success) {
gpr_log(GPR_INFO, "client expected RST_STREAM frame, not found");
}
grpc_slice_buffer_destroy(&last_frame_buffer);
return success;
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
int i; int i;
@ -222,19 +156,22 @@ int main(int argc, char** argv) {
size_t headers_len; size_t headers_len;
const char* client_headers = gpr_strvec_flatten(&headers, &headers_len); const char* client_headers = gpr_strvec_flatten(&headers, &headers_len);
gpr_strvec_destroy(&headers); gpr_strvec_destroy(&headers);
char client_payload[PFX_TOO_MUCH_METADATA_FROM_CLIENT_PAYLOAD_SIZE] = char client_payload[TOO_MUCH_METADATA_FROM_CLIENT_REQUEST_SIZE] =
PFX_TOO_MUCH_METADATA_FROM_CLIENT_PREFIX_STR; PFX_TOO_MUCH_METADATA_FROM_CLIENT_REQUEST;
memcpy( memcpy(client_payload + sizeof(PFX_TOO_MUCH_METADATA_FROM_CLIENT_REQUEST) - 1,
client_payload + sizeof(PFX_TOO_MUCH_METADATA_FROM_CLIENT_PREFIX_STR) - 1, client_headers, headers_len);
client_headers, headers_len); grpc_bad_client_arg args[2];
GRPC_RUN_BAD_CLIENT_TEST(server_verifier, client_validator, client_payload, args[0] = connection_preface_arg;
0); args[1].client_validator = rst_stream_client_validator;
args[1].client_payload = client_payload;
args[1].client_payload_length = sizeof(client_payload) - 1;
grpc_run_bad_client_test(server_verifier_request_call, args, 2, 0);
gpr_free((void*)client_headers); gpr_free((void*)client_headers);
// Test sending more metadata than the client will accept. // Test sending more metadata than the client will accept.
GRPC_RUN_BAD_CLIENT_TEST(server_verifier_sends_too_much_metadata, GRPC_RUN_BAD_CLIENT_TEST(server_verifier_sends_too_much_metadata,
client_validator, rst_stream_client_validator,
PFX_TOO_MUCH_METADATA_FROM_SERVER_STR, 0); PFX_TOO_MUCH_METADATA_FROM_SERVER_STR, 0);
return 0; return 0;
} }

@ -26,8 +26,7 @@
#include "src/core/lib/surface/server.h" #include "src/core/lib/surface/server.h"
#define PFX_STR \ #define PFX_STR \
"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" \ "\x00\x00\x00\x04\x01\x00\x00\x00\x00" \
"\x00\x00\x00\x04\x00\x00\x00\x00\x00" /* settings frame */ \
"\x00\x00\xc9\x01\x04\x00\x00\x00\x01" /* headers: generated from \ "\x00\x00\xc9\x01\x04\x00\x00\x00\x01" /* headers: generated from \
simple_request.headers in this \ simple_request.headers in this \
directory */ \ directory */ \
@ -70,7 +69,7 @@ int main(int argc, char** argv) {
#define MAX_FRAME_SIZE 16384 #define MAX_FRAME_SIZE 16384
#define MESSAGES_PER_FRAME (MAX_FRAME_SIZE / 5) #define MESSAGES_PER_FRAME (MAX_FRAME_SIZE / 5)
#define FRAME_SIZE (MESSAGES_PER_FRAME * 5) #define FRAME_SIZE (MESSAGES_PER_FRAME * 5)
#define SEND_SIZE (6 * 1024 * 1024) #define SEND_SIZE (4 * 1024 * 1024)
#define NUM_FRAMES (SEND_SIZE / FRAME_SIZE + 1) #define NUM_FRAMES (SEND_SIZE / FRAME_SIZE + 1)
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
grpc_init(); grpc_init();
@ -92,8 +91,10 @@ int main(int argc, char** argv) {
addbuf(message, sizeof(message)); addbuf(message, sizeof(message));
} }
} }
grpc_run_bad_client_test(verifier, nullptr, g_buffer, g_count, grpc_bad_client_arg bca[2];
GRPC_BAD_CLIENT_LARGE_REQUEST); bca[0] = connection_preface_arg;
bca[1] = {rst_stream_client_validator, nullptr, g_buffer, g_count};
grpc_run_bad_client_test(verifier, bca, 2, GRPC_BAD_CLIENT_LARGE_REQUEST);
gpr_free(g_buffer); gpr_free(g_buffer);
grpc_shutdown(); grpc_shutdown();

@ -5033,6 +5033,24 @@
"third_party": false, "third_party": false,
"type": "target" "type": "target"
}, },
{
"deps": [
"bad_client_test",
"gpr",
"gpr_test_util",
"grpc_test_util_unsecure",
"grpc_unsecure"
],
"headers": [],
"is_filegroup": false,
"language": "c",
"name": "large_metadata_bad_client_test",
"src": [
"test/core/bad_client/tests/large_metadata.cc"
],
"third_party": false,
"type": "target"
},
{ {
"deps": [ "deps": [
"bad_client_test", "bad_client_test",

@ -4776,6 +4776,32 @@
], ],
"uses_polling": true "uses_polling": true
}, },
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [
"uv"
],
"flaky": false,
"gtest": false,
"language": "c",
"name": "large_metadata_bad_client_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{ {
"args": [], "args": [],
"benchmark": false, "benchmark": false,

Loading…
Cancel
Save