Skip to content

Commit ba7ef7d

Browse files
authored
Delay failed setup cb until channel shutdown completes (#76)
Edge case was: channel setup succeeded, but something goes wrong creating the HTTP handler. The on_setup() callback should not be invoked until the channel finishes shutting down.
1 parent 5103f2b commit ba7ef7d

File tree

1 file changed

+42
-26
lines changed

1 file changed

+42
-26
lines changed

source/connection.c

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -465,18 +465,23 @@ static void s_client_bootstrap_on_channel_setup(
465465
AWS_ASSERT(user_data);
466466
struct aws_http_client_bootstrap *http_bootstrap = user_data;
467467

468+
/* Contract for setup callbacks is: channel is NULL if error_code is non-zero. */
469+
AWS_FATAL_ASSERT((error_code != 0) == (channel == NULL));
470+
468471
if (error_code) {
469472
AWS_LOGF_ERROR(
470473
AWS_LS_HTTP_CONNECTION,
471474
"static: Client connection failed with error %d (%s).",
472475
error_code,
473476
aws_error_name(error_code));
474-
goto error;
475-
}
476477

477-
if (!channel) {
478-
AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: Client connection did not produce a channel");
479-
goto error;
478+
/* Immediately tell user of failed connection.
479+
* No channel exists, so there will be no channel_shutdown callback. */
480+
http_bootstrap->on_setup(NULL, error_code, http_bootstrap->user_data);
481+
482+
/* Clean up the http_bootstrap, it has no more work to do. */
483+
aws_mem_release(http_bootstrap->alloc, http_bootstrap);
484+
return;
480485
}
481486

482487
AWS_LOGF_TRACE(AWS_LS_HTTP_CONNECTION, "static: Socket connected, creating client connection object.");
@@ -499,31 +504,20 @@ static void s_client_bootstrap_on_channel_setup(
499504
(void *)http_bootstrap->connection,
500505
AWS_BYTE_CURSOR_PRI(aws_http_version_to_str(http_bootstrap->connection->http_version)));
501506

502-
/* Tell user of successful connection. */
507+
/* Tell user of successful connection.
508+
* Then clear the on_setup callback so that we know it's been called */
503509
http_bootstrap->on_setup(http_bootstrap->connection, AWS_ERROR_SUCCESS, http_bootstrap->user_data);
510+
http_bootstrap->on_setup = NULL;
511+
504512
return;
505513

506514
error:
507-
if (!error_code) {
508-
error_code = aws_last_error();
509-
}
510-
511-
/* Tell user of failed connection */
512-
http_bootstrap->on_setup(NULL, error_code, http_bootstrap->user_data);
513-
514-
/* on_shutdown isn't allowed to be called if on_setup reports an error */
515-
http_bootstrap->on_shutdown = NULL;
516-
517-
if (channel) {
518-
/* If channel exists, invoke shutdown. http_bootstrap must stay alive until channel shutdown completes. */
519-
aws_channel_shutdown(channel, error_code);
520-
} else {
521-
/* If channel does not exist, clean up the http_bootstrap. It has no more work to do. */
522-
aws_mem_release(http_bootstrap->alloc, http_bootstrap);
523-
}
515+
/* Something went wrong. Invoke channel shutdown. Then wait for channel shutdown to complete
516+
* before informing the user that setup failed and cleaning up the http_bootstrap.*/
517+
aws_channel_shutdown(channel, aws_last_error());
524518
}
525519

526-
/* At this point, the channel for a client connection has complete shutdown, but hasn't been destroyed yet. */
520+
/* At this point, the channel for a client connection has completed its shutdown */
527521
static void s_client_bootstrap_on_channel_shutdown(
528522
struct aws_client_bootstrap *channel_bootstrap,
529523
int error_code,
@@ -536,8 +530,30 @@ static void s_client_bootstrap_on_channel_shutdown(
536530
AWS_ASSERT(user_data);
537531
struct aws_http_client_bootstrap *http_bootstrap = user_data;
538532

539-
/* Tell user about shutdown */
540-
if (http_bootstrap->on_shutdown) {
533+
/* If on_setup hasn't been called yet, inform user of failed setup.
534+
* If on_setup was already called, inform user that it's shut down now. */
535+
if (http_bootstrap->on_setup) {
536+
/* make super duper sure that failed setup receives a non-zero error_code */
537+
if (error_code == 0) {
538+
error_code = AWS_ERROR_UNKNOWN;
539+
}
540+
541+
AWS_LOGF_ERROR(
542+
AWS_LS_HTTP_CONNECTION,
543+
"static: Client setup failed with error %d (%s).",
544+
error_code,
545+
aws_error_name(error_code));
546+
547+
http_bootstrap->on_setup(NULL, error_code, http_bootstrap->user_data);
548+
549+
} else if (http_bootstrap->on_shutdown) {
550+
AWS_LOGF_ERROR(
551+
AWS_LS_HTTP_CONNECTION,
552+
"%p: Client shutdown completed with error %d (%s).",
553+
(void *)http_bootstrap->connection,
554+
error_code,
555+
aws_error_name(error_code));
556+
541557
http_bootstrap->on_shutdown(http_bootstrap->connection, error_code, http_bootstrap->user_data);
542558
}
543559

0 commit comments

Comments
 (0)