Skip to content

Commit eeb0597

Browse files
authored
Misc cleanup of aws-c-http (#30)
- Remove "TODO" comments that exist as tasks on our planning board. - Write unit tests to address some TODO comments. - Check for overflow when summing numbers. - Don't log contents of bad data at the ERROR level, log it at DEBUG. This is to avoid log injection attacks.
1 parent 753650c commit eeb0597

File tree

6 files changed

+325
-80
lines changed

6 files changed

+325
-80
lines changed

source/connection.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ static struct aws_http_connection *s_connection_new(
6868
AWS_LS_HTTP_CONNECTION,
6969
"static: Failed to insert slot into channel %p, error %d (%s).",
7070
(void *)channel,
71-
err,
72-
aws_error_name(err));
71+
aws_last_error(),
72+
aws_error_name(aws_last_error()));
7373
goto error;
7474
}
7575

@@ -143,8 +143,8 @@ static struct aws_http_connection *s_connection_new(
143143
AWS_LS_HTTP_CONNECTION,
144144
"static: Failed to setting HTTP handler into slot on channel %p, error %d (%s).",
145145
(void *)channel,
146-
err,
147-
aws_error_name(err));
146+
aws_last_error(),
147+
aws_error_name(aws_last_error()));
148148

149149
goto error;
150150
}
@@ -527,8 +527,8 @@ int aws_http_client_connect(const struct aws_http_client_connection_options *opt
527527
AWS_LOGF_ERROR(
528528
AWS_LS_HTTP_CONNECTION,
529529
"static: Failed to initiate socket channel for new client connection, error %d (%s).",
530-
err,
531-
aws_error_name(err));
530+
aws_last_error(),
531+
aws_error_name(aws_last_error()));
532532

533533
goto error;
534534
}

source/connection_h1.c

+85-35
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ enum stream_type {
166166

167167
enum stream_outgoing_state {
168168
STREAM_OUTGOING_STATE_HEAD,
169-
STREAM_OUTGOING_STATE_BODY, /* TODO: support 100-continue */
169+
STREAM_OUTGOING_STATE_BODY,
170170
STREAM_OUTGOING_STATE_DONE,
171171
};
172172

@@ -278,7 +278,7 @@ static int s_stream_scan_outgoing_headers(
278278
size_t num_headers,
279279
size_t *out_header_lines_len) {
280280

281-
*out_header_lines_len = 0;
281+
size_t total = 0;
282282

283283
for (size_t i = 0; i < num_headers; ++i) {
284284
struct aws_http_header header = header_array[i];
@@ -288,20 +288,25 @@ static int s_stream_scan_outgoing_headers(
288288
if (header.name.len > 0) {
289289
name_enum = aws_http_str_to_header_name(header.name);
290290
} else {
291-
AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "static: No name set for header[%zu].", i);
291+
AWS_LOGF_ERROR(
292+
AWS_LS_HTTP_CONNECTION,
293+
"id=%p: Failed to create stream, no name set for header[%zu].",
294+
(void *)stream->base.owning_connection,
295+
i);
292296
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
293297
}
294298

295299
switch (name_enum) {
296300
case AWS_HTTP_HEADER_CONTENT_LENGTH:
297301
case AWS_HTTP_HEADER_TRANSFER_ENCODING:
298-
/* TODO: actually process the values in these headers*/
299302
stream->has_outgoing_body = true;
300303

301304
if (!stream->base.stream_outgoing_body) {
302305
AWS_LOGF_ERROR(
303-
AWS_LS_HTTP_STREAM,
304-
"static: '" PRInSTR "' header specified, but body-streaming callback is not set.",
306+
AWS_LS_HTTP_CONNECTION,
307+
"id=%p: Failed to create stream, '" PRInSTR
308+
"' header specified but body-streaming callback is not set.",
309+
(void *)stream->base.owning_connection,
305310
AWS_BYTE_CURSOR_PRI(header.name));
306311

307312
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
@@ -312,11 +317,22 @@ static int s_stream_scan_outgoing_headers(
312317
}
313318

314319
/* header-line: "{name}: {value}\r\n" */
315-
*out_header_lines_len += header.name.len + 2 + header.value.len + 2;
316-
317-
/* TODO: check for overflows anywhere we do addition/subtraction? */
320+
int err = 0;
321+
err |= aws_add_size_checked(header.name.len, total, &total);
322+
err |= aws_add_size_checked(header.value.len, total, &total);
323+
err |= aws_add_size_checked(4, total, &total); /* ": " + "\r\n" */
324+
if (err) {
325+
AWS_LOGF_ERROR(
326+
AWS_LS_HTTP_CONNECTION,
327+
"id=%p: Failed to create stream, header size calculation produced error %d (%s)'",
328+
(void *)stream->base.owning_connection,
329+
aws_last_error(),
330+
aws_error_name(aws_last_error()));
331+
return AWS_OP_ERR;
332+
}
318333
}
319334

335+
*out_header_lines_len = total;
320336
return AWS_OP_SUCCESS;
321337
}
322338

@@ -339,7 +355,10 @@ static void s_write_headers(struct aws_byte_buf *dst, const struct aws_http_head
339355

340356
struct aws_http_stream *s_new_client_request_stream(const struct aws_http_request_options *options) {
341357
if (options->uri.len == 0 || options->method.len == 0) {
342-
AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: Invalid options, cannot create client request.");
358+
AWS_LOGF_ERROR(
359+
AWS_LS_HTTP_CONNECTION,
360+
"id=%p: Cannot create client request, options are invalid.",
361+
(void *)options->client_connection);
343362
aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
344363
return NULL;
345364
}
@@ -368,24 +387,48 @@ struct aws_http_stream *s_new_client_request_stream(const struct aws_http_reques
368387

369388
/**
370389
* Calculate total size needed for outgoing_head_buffer, then write to buffer.
371-
* The head will look like this:
372-
* request-line: "{method} {uri} {version}\r\n"
373-
* header-line: "{name}: {value}\r\n"
374-
* head-end: "\r\n"
375390
*/
376-
size_t request_line_len = options->method.len + 1 + options->uri.len + 1 + version.len + 2;
391+
377392
size_t header_lines_len;
378393
int err = s_stream_scan_outgoing_headers(stream, options->header_array, options->num_headers, &header_lines_len);
379394
if (err) {
380-
goto error;
395+
/* errors already logged by scan_outgoing_headers() function */
396+
goto error_scanning_headers;
381397
}
382398

399+
/* request-line: "{method} {uri} {version}\r\n" */
400+
size_t request_line_len = 4; /* 2 spaces + "\r\n" */
401+
err |= aws_add_size_checked(options->method.len, request_line_len, &request_line_len);
402+
err |= aws_add_size_checked(options->uri.len, request_line_len, &request_line_len);
403+
err |= aws_add_size_checked(version.len, request_line_len, &request_line_len);
404+
405+
/* head-end: "\r\n" */
383406
size_t head_end_len = 2;
384407

385-
size_t head_total_len = request_line_len + header_lines_len + head_end_len;
408+
size_t head_total_len = request_line_len;
409+
err |= aws_add_size_checked(header_lines_len, head_total_len, &head_total_len);
410+
err |= aws_add_size_checked(head_end_len, head_total_len, &head_total_len);
411+
412+
if (err) {
413+
AWS_LOGF_ERROR(
414+
AWS_LS_HTTP_CONNECTION,
415+
"id=%p: Failed to create request, size calculation had error %d (%s).",
416+
(void *)options->client_connection,
417+
aws_last_error(),
418+
aws_error_name(aws_last_error()));
419+
goto error_calculating_size;
420+
}
421+
386422
err = aws_byte_buf_init(&stream->outgoing_head_buf, stream->base.alloc, head_total_len);
387423
if (err) {
388-
goto error;
424+
AWS_LOGF_ERROR(
425+
AWS_LS_HTTP_CONNECTION,
426+
"id=%p: Failed to create request, buffer initialization had error %d (%s).",
427+
(void *)options->client_connection,
428+
aws_last_error(),
429+
aws_error_name(aws_last_error()));
430+
431+
goto error_initializing_buf;
389432
}
390433

391434
bool wrote_all = true;
@@ -430,18 +473,19 @@ struct aws_http_stream *s_new_client_request_stream(const struct aws_http_reques
430473

431474
if (is_shutting_down) {
432475
AWS_LOGF_ERROR(
433-
AWS_LS_HTTP_STREAM,
434-
"static: Connection is closed, cannot create " PRInSTR " request.",
435-
AWS_BYTE_CURSOR_PRI(options->method));
476+
AWS_LS_HTTP_CONNECTION,
477+
"id=%p: Connection is closed, cannot create request.",
478+
(void *)options->client_connection);
436479

437480
aws_raise_error(AWS_ERROR_HTTP_CONNECTION_CLOSED);
438-
goto error;
481+
goto error_connection_closed;
439482
}
440483

441484
AWS_LOGF_DEBUG(
442485
AWS_LS_HTTP_STREAM,
443-
"id=%p: Created client request: " PRInSTR " " PRInSTR " " PRInSTR,
486+
"id=%p: Created client request on connection=%p: " PRInSTR " " PRInSTR " " PRInSTR,
444487
(void *)&stream->base,
488+
(void *)options->client_connection,
445489
AWS_BYTE_CURSOR_PRI(options->method),
446490
AWS_BYTE_CURSOR_PRI(options->uri),
447491
AWS_BYTE_CURSOR_PRI(aws_http_version_to_str(connection->base.http_version)));
@@ -453,8 +497,11 @@ struct aws_http_stream *s_new_client_request_stream(const struct aws_http_reques
453497

454498
return &stream->base;
455499

456-
error:
500+
error_connection_closed:
457501
aws_byte_buf_clean_up(&stream->outgoing_head_buf);
502+
error_initializing_buf:
503+
error_calculating_size:
504+
error_scanning_headers:
458505
aws_mem_release(stream->base.alloc, stream);
459506
return NULL;
460507
}
@@ -472,7 +519,14 @@ static void s_stream_destroy(struct aws_http_stream *stream_base) {
472519
static void s_update_window_action(struct h1_connection *connection, size_t increment_size) {
473520
int err = aws_channel_slot_increment_read_window(connection->base.channel_slot, increment_size);
474521
if (err) {
475-
/* TODO: log warning OR remove error code from aws_channel_slot_increment_read_window */
522+
AWS_LOGF_ERROR(
523+
AWS_LS_HTTP_CONNECTION,
524+
"id=%p: Failed to increment read window, error %d (%s). Closing connection.",
525+
(void *)&connection->base,
526+
aws_last_error(),
527+
aws_error_name(aws_last_error()));
528+
529+
s_shutdown_connection(connection, aws_last_error());
476530
}
477531
}
478532

@@ -856,8 +910,8 @@ static void s_outgoing_stream_task(struct aws_channel_task *task, void *arg, enu
856910
AWS_LS_HTTP_CONNECTION,
857911
"id=%p: Failed to send message up channel, error %d (%s). Closing connection.",
858912
(void *)&connection->base,
859-
err,
860-
aws_error_name(err));
913+
aws_last_error(),
914+
aws_error_name(aws_last_error()));
861915

862916
goto error;
863917
}
@@ -914,8 +968,6 @@ static int s_decoder_on_request(
914968
AWS_BYTE_CURSOR_PRI(*method_str),
915969
AWS_BYTE_CURSOR_PRI(*uri));
916970

917-
/* TODO: Limit on lengths of incoming data https://httpwg.org/specs/rfc7230.html#attack.protocol.element.length */
918-
919971
/* Copy strings to internal buffer */
920972
struct aws_byte_buf *storage_buf = &incoming_stream->incoming_storage_buf;
921973
assert(storage_buf->capacity == 0);
@@ -976,8 +1028,6 @@ static int s_decoder_on_header(const struct aws_http_decoded_header *header, voi
9761028
AWS_BYTE_CURSOR_PRI(header->name_data),
9771029
AWS_BYTE_CURSOR_PRI(header->value_data));
9781030

979-
/* TODO? how to support trailing headers? distinct cb? invoke same cb again? */
980-
9811031
if (incoming_stream->base.on_incoming_headers) {
9821032
struct aws_http_header deliver = {
9831033
.name = header->name_data,
@@ -1263,8 +1313,8 @@ static int s_handler_process_read_message(
12631313
AWS_LS_HTTP_CONNECTION,
12641314
"id=%p: Message processing failed, error %d (%s). Closing connection.",
12651315
(void *)&connection->base,
1266-
err,
1267-
aws_error_name(err));
1316+
aws_last_error(),
1317+
aws_error_name(aws_last_error()));
12681318

12691319
goto error;
12701320
}
@@ -1282,8 +1332,8 @@ static int s_handler_process_read_message(
12821332
AWS_LS_HTTP_CONNECTION,
12831333
"id=%p: Failed to increment read window, error %d (%s). Closing connection.",
12841334
(void *)&connection->base,
1285-
err,
1286-
aws_error_name(err));
1335+
aws_last_error(),
1336+
aws_error_name(aws_last_error()));
12871337

12881338
goto error;
12891339
}

0 commit comments

Comments
 (0)