int aws_http_client_connect_internal()

in source/connection.c [980:1115]


int aws_http_client_connect_internal(
    const struct aws_http_client_connection_options *orig_options,
    aws_http_proxy_request_transform_fn *proxy_request_transform) {

    if (!orig_options) {
        AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: http connection options are null.");
        return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
    }
    struct aws_http_client_bootstrap *http_bootstrap = NULL;
    struct aws_string *host_name = NULL;
    int err = 0;

    /* make copy of options, and add defaults for missing optional structs */
    struct aws_http_client_connection_options options = *orig_options;
    if (options.prior_knowledge_http2 && options.tls_options) {
        AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: HTTP/2 prior knowledge only works with cleartext TCP.");
        return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
    }

    struct aws_http1_connection_options default_http1_options;
    AWS_ZERO_STRUCT(default_http1_options);
    if (options.http1_options == NULL) {
        options.http1_options = &default_http1_options;
    }

    struct aws_http2_connection_options default_http2_options;
    AWS_ZERO_STRUCT(default_http2_options);
    if (options.http2_options == NULL) {
        options.http2_options = &default_http2_options;
    }

    /* validate options */
    if (s_validate_http_client_connection_options(&options)) {
        goto error;
    }

    AWS_FATAL_ASSERT(options.proxy_options == NULL);

    /* bootstrap_new() functions requires a null-terminated c-str */
    host_name = aws_string_new_from_cursor(options.allocator, &options.host_name);
    if (!host_name) {
        goto error;
    }

    struct aws_http2_setting *setting_array = NULL;
    struct aws_hash_table *alpn_string_map = NULL;
    if (!aws_mem_acquire_many(
            options.allocator,
            3,
            &http_bootstrap,
            sizeof(struct aws_http_client_bootstrap),
            &setting_array,
            options.http2_options->num_initial_settings * sizeof(struct aws_http2_setting),
            &alpn_string_map,
            sizeof(struct aws_hash_table))) {
        goto error;
    }

    AWS_ZERO_STRUCT(*http_bootstrap);

    http_bootstrap->alloc = options.allocator;
    http_bootstrap->is_using_tls = options.tls_options != NULL;
    http_bootstrap->stream_manual_window_management = options.manual_window_management;
    http_bootstrap->prior_knowledge_http2 = options.prior_knowledge_http2;
    http_bootstrap->initial_window_size = options.initial_window_size;
    http_bootstrap->user_data = options.user_data;
    http_bootstrap->on_setup = options.on_setup;
    http_bootstrap->on_shutdown = options.on_shutdown;
    http_bootstrap->proxy_request_transform = proxy_request_transform;
    http_bootstrap->http1_options = *options.http1_options;
    http_bootstrap->http2_options = *options.http2_options;

    /* keep a copy of the settings array if it's not NULL */
    if (options.http2_options->num_initial_settings > 0) {
        memcpy(
            setting_array,
            options.http2_options->initial_settings_array,
            options.http2_options->num_initial_settings * sizeof(struct aws_http2_setting));
        http_bootstrap->http2_options.initial_settings_array = setting_array;
    }

    if (options.alpn_string_map) {
        if (aws_http_alpn_map_init_copy(options.allocator, alpn_string_map, options.alpn_string_map)) {
            goto error;
        }
        http_bootstrap->alpn_string_map = alpn_string_map;
    }

    if (options.monitoring_options) {
        http_bootstrap->monitoring_options = *options.monitoring_options;
    }

    AWS_LOGF_TRACE(
        AWS_LS_HTTP_CONNECTION,
        "static: attempting to initialize a new client channel to %s:%d",
        aws_string_c_str(host_name),
        (int)options.port);

    struct aws_socket_channel_bootstrap_options channel_options = {
        .bootstrap = options.bootstrap,
        .host_name = aws_string_c_str(host_name),
        .port = options.port,
        .socket_options = options.socket_options,
        .tls_options = options.tls_options,
        .setup_callback = s_client_bootstrap_on_channel_setup,
        .shutdown_callback = s_client_bootstrap_on_channel_shutdown,
        .enable_read_back_pressure = options.manual_window_management,
        .user_data = http_bootstrap,
    };

    err = s_system_vtable_ptr->new_socket_channel(&channel_options);

    if (err) {
        AWS_LOGF_ERROR(
            AWS_LS_HTTP_CONNECTION,
            "static: Failed to initiate socket channel for new client connection, error %d (%s).",
            aws_last_error(),
            aws_error_name(aws_last_error()));

        goto error;
    }

    aws_string_destroy(host_name);
    return AWS_OP_SUCCESS;

error:
    if (http_bootstrap) {
        aws_http_client_bootstrap_destroy(http_bootstrap);
    }

    if (host_name) {
        aws_string_destroy(host_name);
    }

    return AWS_OP_ERR;
}