in source/h1_connection.c [847:941]
static void s_write_outgoing_stream(struct aws_h1_connection *connection, bool first_try) {
AWS_PRECONDITION(aws_channel_thread_is_callers_thread(connection->base.channel_slot->channel));
AWS_PRECONDITION(connection->thread_data.is_outgoing_stream_task_active);
/* Just stop if we're no longer writing stream data */
if (connection->thread_data.is_writing_stopped || connection->thread_data.has_switched_protocols) {
return;
}
/* Determine whether we have data available to send, and end task immediately if there's not.
* The outgoing stream task will be kicked off again when user adds more data (new stream, new chunk, etc) */
struct aws_h1_stream *outgoing_stream = s_update_outgoing_stream_ptr(connection);
bool waiting_for_chunks = aws_h1_encoder_is_waiting_for_chunks(&connection->thread_data.encoder);
if (!outgoing_stream || waiting_for_chunks) {
if (!first_try) {
AWS_LOGF_TRACE(
AWS_LS_HTTP_CONNECTION,
"id=%p: Outgoing stream task stopped. outgoing_stream=%p waiting_for_chunks:%d",
(void *)&connection->base,
outgoing_stream ? (void *)&outgoing_stream->base : NULL,
waiting_for_chunks);
}
connection->thread_data.is_outgoing_stream_task_active = false;
return;
}
if (first_try) {
AWS_LOGF_TRACE(AWS_LS_HTTP_CONNECTION, "id=%p: Outgoing stream task has begun.", (void *)&connection->base);
}
struct aws_io_message *msg = aws_channel_slot_acquire_max_message_for_write(connection->base.channel_slot);
if (!msg) {
AWS_LOGF_ERROR(
AWS_LS_HTTP_CONNECTION,
"id=%p: Failed to acquire message from pool, error %d (%s). Closing connection.",
(void *)&connection->base,
aws_last_error(),
aws_error_name(aws_last_error()));
goto error;
}
/* Set up callback so we can send another message when this one completes */
msg->on_completion = s_on_channel_write_complete;
msg->user_data = connection;
/*
* Fill message data from the outgoing stream.
* Note that we might be resuming work on a stream from a previous run of this task.
*/
if (AWS_OP_SUCCESS != aws_h1_encoder_process(&connection->thread_data.encoder, &msg->message_data)) {
/* Error sending data, abandon ship */
goto error;
}
if (msg->message_data.len > 0) {
AWS_LOGF_TRACE(
AWS_LS_HTTP_CONNECTION,
"id=%p: Outgoing stream task is sending message of size %zu.",
(void *)&connection->base,
msg->message_data.len);
if (aws_channel_slot_send_message(connection->base.channel_slot, msg, AWS_CHANNEL_DIR_WRITE)) {
AWS_LOGF_ERROR(
AWS_LS_HTTP_CONNECTION,
"id=%p: Failed to send message in write direction, error %d (%s). Closing connection.",
(void *)&connection->base,
aws_last_error(),
aws_error_name(aws_last_error()));
goto error;
}
} else {
/* If message is empty, warn that no work is being done
* and reschedule the task to try again next tick.
* It's likely that body isn't ready, so body streaming function has no data to write yet.
* If this scenario turns out to be common we should implement a "pause" feature. */
AWS_LOGF_WARN(
AWS_LS_HTTP_CONNECTION,
"id=%p: Current outgoing stream %p sent no data, will try again next tick.",
(void *)&connection->base,
outgoing_stream ? (void *)&outgoing_stream->base : NULL);
aws_mem_release(msg->allocator, msg);
aws_channel_schedule_task_now(connection->base.channel_slot->channel, &connection->outgoing_stream_task);
}
return;
error:
if (msg) {
aws_mem_release(msg->allocator, msg);
}
s_shutdown_due_to_error(connection, aws_last_error());
}