|
|
|
@ -41,6 +41,7 @@ |
|
|
|
|
#include <grpc/support/string_util.h> |
|
|
|
|
|
|
|
|
|
#include "src/core/ext/client_channel/uri_parser.h" |
|
|
|
|
#include "src/core/lib/channel/channel_args.h" |
|
|
|
|
#include "src/core/lib/http/format_request.h" |
|
|
|
|
#include "src/core/lib/http/parser.h" |
|
|
|
|
#include "src/core/lib/support/env.h" |
|
|
|
@ -55,9 +56,12 @@ typedef struct http_connect_handshaker { |
|
|
|
|
gpr_refcount refcount; |
|
|
|
|
gpr_mu mu; |
|
|
|
|
|
|
|
|
|
bool shutdown; |
|
|
|
|
// Endpoint and read buffer to destroy after a shutdown.
|
|
|
|
|
grpc_endpoint* endpoint_to_destroy; |
|
|
|
|
grpc_slice_buffer* read_buffer_to_destroy; |
|
|
|
|
|
|
|
|
|
// State saved while performing the handshake.
|
|
|
|
|
// args will be NULL when either there is no handshake in progress or
|
|
|
|
|
// when the handshaker is shutting down.
|
|
|
|
|
grpc_handshaker_args* args; |
|
|
|
|
grpc_closure* on_handshake_done; |
|
|
|
|
|
|
|
|
@ -70,9 +74,17 @@ typedef struct http_connect_handshaker { |
|
|
|
|
} http_connect_handshaker; |
|
|
|
|
|
|
|
|
|
// Unref and clean up handshaker.
|
|
|
|
|
static void http_connect_handshaker_unref(http_connect_handshaker* handshaker) { |
|
|
|
|
static void http_connect_handshaker_unref(grpc_exec_ctx* exec_ctx, |
|
|
|
|
http_connect_handshaker* handshaker) { |
|
|
|
|
if (gpr_unref(&handshaker->refcount)) { |
|
|
|
|
gpr_mu_destroy(&handshaker->mu); |
|
|
|
|
if (handshaker->endpoint_to_destroy != NULL) { |
|
|
|
|
grpc_endpoint_destroy(exec_ctx, handshaker->endpoint_to_destroy); |
|
|
|
|
} |
|
|
|
|
if (handshaker->read_buffer_to_destroy != NULL) { |
|
|
|
|
grpc_slice_buffer_destroy(handshaker->read_buffer_to_destroy); |
|
|
|
|
gpr_free(handshaker->read_buffer_to_destroy); |
|
|
|
|
} |
|
|
|
|
gpr_free(handshaker->proxy_server); |
|
|
|
|
gpr_free(handshaker->server_name); |
|
|
|
|
grpc_slice_buffer_destroy(&handshaker->write_buffer); |
|
|
|
@ -82,18 +94,42 @@ static void http_connect_handshaker_unref(http_connect_handshaker* handshaker) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Set args fields to NULL, saving the endpoint and read buffer for
|
|
|
|
|
// later destruction.
|
|
|
|
|
static void cleanup_args_for_failure_locked( |
|
|
|
|
http_connect_handshaker* handshaker) { |
|
|
|
|
handshaker->endpoint_to_destroy = handshaker->args->endpoint; |
|
|
|
|
handshaker->args->endpoint = NULL; |
|
|
|
|
handshaker->read_buffer_to_destroy = handshaker->args->read_buffer; |
|
|
|
|
handshaker->args->read_buffer = NULL; |
|
|
|
|
grpc_channel_args_destroy(handshaker->args->args); |
|
|
|
|
handshaker->args->args = NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Callback invoked when finished writing HTTP CONNECT request.
|
|
|
|
|
static void on_write_done(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
|
grpc_error* error) { |
|
|
|
|
http_connect_handshaker* handshaker = arg; |
|
|
|
|
gpr_mu_lock(&handshaker->mu); |
|
|
|
|
if (error != GRPC_ERROR_NONE || handshaker->args == NULL) { |
|
|
|
|
// If the write failed, invoke the callback immediately with the error.
|
|
|
|
|
grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, |
|
|
|
|
GRPC_ERROR_REF(error), NULL); |
|
|
|
|
handshaker->args = NULL; |
|
|
|
|
if (error != GRPC_ERROR_NONE || handshaker->shutdown) { |
|
|
|
|
// If the write failed or we're shutting down, clean up and invoke the
|
|
|
|
|
// callback with the error.
|
|
|
|
|
if (error == GRPC_ERROR_NONE) { |
|
|
|
|
// If we were shut down after the write succeeded but before this
|
|
|
|
|
// callback was invoked, we need to generate our own error.
|
|
|
|
|
error = GRPC_ERROR_CREATE("Handshaker shutdown"); |
|
|
|
|
} else { |
|
|
|
|
GRPC_ERROR_REF(error); // Take ref for the handshake-done callback.
|
|
|
|
|
} |
|
|
|
|
if (!handshaker->shutdown) { |
|
|
|
|
// Not shutting down, so the write failed. Clean up before
|
|
|
|
|
// invoking the callback.
|
|
|
|
|
cleanup_args_for_failure_locked(handshaker); |
|
|
|
|
} |
|
|
|
|
// Invoke callback.
|
|
|
|
|
grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL); |
|
|
|
|
gpr_mu_unlock(&handshaker->mu); |
|
|
|
|
http_connect_handshaker_unref(handshaker); |
|
|
|
|
http_connect_handshaker_unref(exec_ctx, handshaker); |
|
|
|
|
} else { |
|
|
|
|
// Otherwise, read the response.
|
|
|
|
|
// The read callback inherits our ref to the handshaker.
|
|
|
|
@ -109,8 +145,21 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
|
grpc_error* error) { |
|
|
|
|
http_connect_handshaker* handshaker = arg; |
|
|
|
|
gpr_mu_lock(&handshaker->mu); |
|
|
|
|
if (error != GRPC_ERROR_NONE || handshaker->args == NULL) { |
|
|
|
|
GRPC_ERROR_REF(error); // Take ref to pass to the handshake-done callback.
|
|
|
|
|
if (error != GRPC_ERROR_NONE || handshaker->shutdown) { |
|
|
|
|
// If the write failed or we're shutting down, clean up and invoke the
|
|
|
|
|
// callback with the error.
|
|
|
|
|
if (error == GRPC_ERROR_NONE) { |
|
|
|
|
// If we were shut down after the write succeeded but before this
|
|
|
|
|
// callback was invoked, we need to generate our own error.
|
|
|
|
|
error = GRPC_ERROR_CREATE("Handshaker shutdown"); |
|
|
|
|
} else { |
|
|
|
|
GRPC_ERROR_REF(error); // Take ref for the handshake-done callback.
|
|
|
|
|
} |
|
|
|
|
if (!handshaker->shutdown) { |
|
|
|
|
// Not shutting down, so the write failed. Clean up before
|
|
|
|
|
// invoking the callback.
|
|
|
|
|
cleanup_args_for_failure_locked(handshaker); |
|
|
|
|
} |
|
|
|
|
goto done; |
|
|
|
|
} |
|
|
|
|
// Add buffer to parser.
|
|
|
|
@ -172,10 +221,9 @@ static void on_read_done(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
|
} |
|
|
|
|
done: |
|
|
|
|
// Invoke handshake-done callback.
|
|
|
|
|
handshaker->args = NULL; |
|
|
|
|
grpc_exec_ctx_sched(exec_ctx, handshaker->on_handshake_done, error, NULL); |
|
|
|
|
gpr_mu_unlock(&handshaker->mu); |
|
|
|
|
http_connect_handshaker_unref(handshaker); |
|
|
|
|
http_connect_handshaker_unref(exec_ctx, handshaker); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
@ -185,16 +233,17 @@ done: |
|
|
|
|
static void http_connect_handshaker_destroy(grpc_exec_ctx* exec_ctx, |
|
|
|
|
grpc_handshaker* handshaker_in) { |
|
|
|
|
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in; |
|
|
|
|
http_connect_handshaker_unref(handshaker); |
|
|
|
|
http_connect_handshaker_unref(exec_ctx, handshaker); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void http_connect_handshaker_shutdown(grpc_exec_ctx* exec_ctx, |
|
|
|
|
grpc_handshaker* handshaker_in) { |
|
|
|
|
http_connect_handshaker* handshaker = (http_connect_handshaker*)handshaker_in; |
|
|
|
|
gpr_mu_lock(&handshaker->mu); |
|
|
|
|
if (handshaker->args != NULL) { |
|
|
|
|
if (!handshaker->shutdown) { |
|
|
|
|
handshaker->shutdown = true; |
|
|
|
|
grpc_endpoint_shutdown(exec_ctx, handshaker->args->endpoint); |
|
|
|
|
handshaker->args = NULL; |
|
|
|
|
cleanup_args_for_failure_locked(handshaker); |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&handshaker->mu); |
|
|
|
|
} |
|
|
|
|