Skip to content

Commit 1550f23

Browse files
authored
Merge pull request #125 from awslabs/h1b
Merge H1B to master
2 parents 92655c4 + 4b0f557 commit 1550f23

37 files changed

+5488
-2200
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
cmake_minimum_required(VERSION 3.1)
22
project(aws-c-http C)
33

4+
option(ENABLE_PROXY_INTEGRATION_TESTS "Whether to run the proxy integration tests that rely on a proxy server installed and running locally" OFF)
5+
46
if (DEFINED CMAKE_PREFIX_PATH)
57
file(TO_CMAKE_PATH ${CMAKE_PREFIX_PATH} CMAKE_PREFIX_PATH)
68
endif()

bin/elasticurl/main.c

Lines changed: 58 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,13 @@ struct elasticurl_ctx {
5959
size_t header_line_count;
6060
FILE *input_file;
6161
struct aws_input_stream *input_body;
62+
struct aws_http_message *request;
63+
struct aws_http_connection *connection;
6264
const char *signing_library_path;
6365
struct aws_shared_library signing_library;
6466
const char *signing_function_name;
6567
struct aws_hash_table signing_context;
66-
aws_transform_http_request_fn *signing_function;
68+
aws_http_message_transform_fn *signing_function;
6769
bool include_headers;
6870
bool insecure;
6971
FILE *output;
@@ -320,48 +322,17 @@ static void s_parse_options(int argc, char **argv, struct elasticurl_ctx *ctx) {
320322
}
321323
}
322324

323-
static void s_on_incoming_body_fn(
324-
struct aws_http_stream *stream,
325-
const struct aws_byte_cursor *data,
326-
/* NOLINTNEXTLINE(readability-non-const-parameter) */
327-
size_t *out_window_update_size,
328-
void *user_data) {
325+
static int s_on_incoming_body_fn(struct aws_http_stream *stream, const struct aws_byte_cursor *data, void *user_data) {
329326

330327
(void)stream;
331-
(void)out_window_update_size;
332328
struct elasticurl_ctx *app_ctx = user_data;
333329

334330
fwrite(data->ptr, 1, data->len, app_ctx->output);
335-
}
336-
337-
enum aws_http_outgoing_body_state s_stream_outgoing_body_fn(
338-
struct aws_http_stream *stream,
339-
struct aws_byte_buf *buf,
340-
void *user_data) {
341-
(void)stream;
342-
struct elasticurl_ctx *app_ctx = user_data;
343-
344-
if (!app_ctx->input_body) {
345-
return AWS_HTTP_OUTGOING_BODY_DONE;
346-
}
347331

348-
struct aws_stream_status status;
349-
if (aws_input_stream_get_status(app_ctx->input_body, &status)) {
350-
return AWS_HTTP_OUTGOING_BODY_DONE;
351-
}
352-
353-
if (status.is_end_of_stream || !status.is_valid) {
354-
return AWS_HTTP_OUTGOING_BODY_DONE;
355-
}
356-
357-
if (aws_input_stream_read(app_ctx->input_body, buf)) {
358-
return AWS_HTTP_OUTGOING_BODY_DONE;
359-
}
360-
361-
return AWS_HTTP_OUTGOING_BODY_IN_PROGRESS;
332+
return AWS_OP_SUCCESS;
362333
}
363334

364-
static void s_on_incoming_headers_fn(
335+
static int s_on_incoming_headers_fn(
365336
struct aws_http_stream *stream,
366337
const struct aws_http_header *header_array,
367338
size_t num_headers,
@@ -385,12 +356,16 @@ static void s_on_incoming_headers_fn(
385356
fprintf(stdout, "\n");
386357
}
387358
}
359+
360+
return AWS_OP_SUCCESS;
388361
}
389362

390-
static void s_on_incoming_header_block_done_fn(struct aws_http_stream *stream, bool has_body, void *user_data) {
363+
static int s_on_incoming_header_block_done_fn(struct aws_http_stream *stream, bool has_body, void *user_data) {
391364
(void)stream;
392365
(void)has_body;
393366
(void)user_data;
367+
368+
return AWS_OP_SUCCESS;
394369
}
395370

396371
static void s_on_stream_complete_fn(struct aws_http_stream *stream, int error_code, void *user_data) {
@@ -399,28 +374,26 @@ static void s_on_stream_complete_fn(struct aws_http_stream *stream, int error_co
399374
aws_http_stream_release(stream);
400375
}
401376

402-
static struct aws_http_request *s_build_http_request(struct elasticurl_ctx *app_ctx) {
403-
struct aws_http_request *request = aws_http_request_new(app_ctx->allocator);
377+
static struct aws_http_message *s_build_http_request(struct elasticurl_ctx *app_ctx) {
378+
struct aws_http_message *request = aws_http_message_new_request(app_ctx->allocator);
404379
if (request == NULL) {
405380
fprintf(stderr, "failed to allocate request\n");
406381
exit(1);
407382
}
408383

409-
aws_http_request_set_method(request, aws_byte_cursor_from_c_str(app_ctx->verb));
410-
aws_http_request_set_path(request, app_ctx->uri.path_and_query);
411-
aws_http_request_set_body_stream(request, app_ctx->input_body);
412-
384+
aws_http_message_set_request_method(request, aws_byte_cursor_from_c_str(app_ctx->verb));
385+
aws_http_message_set_request_path(request, app_ctx->uri.path_and_query);
413386
struct aws_http_header accept_header = {.name = aws_byte_cursor_from_c_str("accept"),
414387
.value = aws_byte_cursor_from_c_str("*/*")};
415-
aws_http_request_add_header(request, accept_header);
388+
aws_http_message_add_header(request, accept_header);
416389

417390
struct aws_http_header host_header = {.name = aws_byte_cursor_from_c_str("host"), .value = app_ctx->uri.host_name};
418-
aws_http_request_add_header(request, host_header);
391+
aws_http_message_add_header(request, host_header);
419392

420393
struct aws_http_header user_agent_header = {
421394
.name = aws_byte_cursor_from_c_str("user-agent"),
422395
.value = aws_byte_cursor_from_c_str("elasticurl 1.0, Powered by the AWS Common Runtime.")};
423-
aws_http_request_add_header(request, user_agent_header);
396+
aws_http_message_add_header(request, user_agent_header);
424397

425398
if (app_ctx->input_body) {
426399
int64_t data_len = 0;
@@ -435,7 +408,8 @@ static struct aws_http_request *s_build_http_request(struct elasticurl_ctx *app_
435408
sprintf(content_length, "%" PRIi64, data_len);
436409
struct aws_http_header content_length_header = {.name = aws_byte_cursor_from_c_str("content-length"),
437410
.value = aws_byte_cursor_from_c_str(content_length)};
438-
aws_http_request_add_header(request, content_length_header);
411+
aws_http_message_add_header(request, content_length_header);
412+
aws_http_message_set_body_stream(request, app_ctx->input_body);
439413
}
440414
}
441415

@@ -451,12 +425,14 @@ static struct aws_http_request *s_build_http_request(struct elasticurl_ctx *app_
451425
struct aws_http_header custom_header = {
452426
.name = aws_byte_cursor_from_array(app_ctx->header_lines[i], delimiter - app_ctx->header_lines[i]),
453427
.value = aws_byte_cursor_from_c_str(delimiter + 1)};
454-
aws_http_request_add_header(request, custom_header);
428+
aws_http_message_add_header(request, custom_header);
455429
}
456430

457431
return request;
458432
}
459433

434+
static void s_on_signing_complete(struct aws_http_message *request, int error_code, void *user_data);
435+
460436
static void s_on_client_connection_setup(struct aws_http_connection *connection, int error_code, void *user_data) {
461437
struct elasticurl_ctx *app_ctx = user_data;
462438

@@ -469,52 +445,58 @@ static void s_on_client_connection_setup(struct aws_http_connection *connection,
469445
return;
470446
}
471447

472-
struct aws_http_request *request = s_build_http_request(app_ctx);
448+
app_ctx->connection = connection;
449+
app_ctx->request = s_build_http_request(app_ctx);
473450

451+
/* If async signing function is set, invoke it. It must invoke the signing complete callback when it's done. */
474452
if (app_ctx->signing_function) {
475-
if (app_ctx->signing_function(request, app_ctx->allocator, &app_ctx->signing_context)) {
476-
fprintf(stderr, "Signing failure\n");
477-
exit(1);
478-
}
453+
app_ctx->signing_function(app_ctx->request, &app_ctx->signing_context, s_on_signing_complete, app_ctx);
454+
} else {
455+
/* If no signing function, proceed immediately to next step. */
456+
s_on_signing_complete(app_ctx->request, AWS_ERROR_SUCCESS, app_ctx);
479457
}
458+
}
480459

481-
size_t final_header_count = aws_http_request_get_header_count(request);
460+
static void s_on_signing_complete(struct aws_http_message *request, int error_code, void *user_data) {
461+
struct elasticurl_ctx *app_ctx = user_data;
462+
463+
AWS_FATAL_ASSERT(request == app_ctx->request);
464+
465+
if (error_code) {
466+
fprintf(stderr, "Signing failure\n");
467+
exit(1);
468+
}
469+
470+
size_t final_header_count = aws_http_message_get_header_count(app_ctx->request);
482471

483472
struct aws_http_header headers[20];
484473
AWS_ASSERT(final_header_count <= AWS_ARRAY_SIZE(headers));
485474
AWS_ZERO_ARRAY(headers);
486475
for (size_t i = 0; i < final_header_count; ++i) {
487-
aws_http_request_get_header(request, &headers[i], i);
476+
aws_http_message_get_header(app_ctx->request, &headers[i], i);
488477
}
489478

490-
struct aws_http_request_options final_request;
491-
AWS_ZERO_STRUCT(final_request);
492-
final_request.self_size = sizeof(struct aws_http_request_options);
493-
final_request.uri = app_ctx->uri.path_and_query;
494-
final_request.user_data = app_ctx;
495-
final_request.client_connection = connection;
496-
final_request.method = aws_byte_cursor_from_c_str(app_ctx->verb);
497-
final_request.header_array = headers;
498-
final_request.num_headers = aws_http_request_get_header_count(request);
499-
final_request.on_response_headers = s_on_incoming_headers_fn;
500-
final_request.on_response_header_block_done = s_on_incoming_header_block_done_fn;
501-
final_request.on_response_body = s_on_incoming_body_fn;
502-
final_request.on_complete = s_on_stream_complete_fn;
503-
if (app_ctx->input_body) {
504-
final_request.stream_outgoing_body = s_stream_outgoing_body_fn;
505-
}
479+
struct aws_http_make_request_options final_request = {
480+
.self_size = sizeof(final_request),
481+
.user_data = app_ctx,
482+
.request = app_ctx->request,
483+
.on_response_headers = s_on_incoming_headers_fn,
484+
.on_response_header_block_done = s_on_incoming_header_block_done_fn,
485+
.on_response_body = s_on_incoming_body_fn,
486+
.on_complete = s_on_stream_complete_fn,
487+
};
506488

507489
app_ctx->response_code_written = false;
508490

509-
struct aws_http_stream *stream = aws_http_stream_new_client_request(&final_request);
491+
struct aws_http_stream *stream = aws_http_connection_make_request(app_ctx->connection, &final_request);
510492
if (!stream) {
511493
fprintf(stderr, "failed to create request.");
512494
exit(1);
513495
}
514496

515-
aws_http_connection_release(connection);
516-
517-
aws_http_request_destroy(request);
497+
/* Connection will stay alive until stream completes */
498+
aws_http_connection_release(app_ctx->connection);
499+
app_ctx->connection = NULL;
518500
}
519501

520502
static void s_on_client_connection_shutdown(struct aws_http_connection *connection, int error_code, void *user_data) {
@@ -728,6 +710,8 @@ int main(int argc, char **argv) {
728710

729711
aws_uri_clean_up(&app_ctx.uri);
730712

713+
aws_http_message_destroy(app_ctx.request);
714+
731715
aws_shared_library_clean_up(&app_ctx.signing_library);
732716

733717
if (app_ctx.output != stdout) {

codebuild/common-posix.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ function install_library {
4040
if [ "$TRAVIS_OS_NAME" != "osx" ]; then
4141
sudo apt-get install libssl-dev -y
4242
install_library s2n 7c9069618e68214802ac7fbf45705d5f8b53135f
43+
44+
# Enable squid-based integration tests
45+
# These steps are very specific to ubuntu 14.
46+
sudo apt-get -y install squid
47+
squid3 -v
48+
find / -name 'squid*'
49+
squid3 -YC -f /etc/squid3/squid.conf
50+
51+
CMAKE_ARGS="$CMAKE_ARGS -DENABLE_PROXY_INTEGRATION_TESTS=ON"
4352
fi
4453
install_library aws-c-common
4554
install_library aws-c-io

include/aws/http/connection.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,54 @@ typedef void(
3535
typedef void(
3636
aws_http_on_client_connection_shutdown_fn)(struct aws_http_connection *connection, int error_code, void *user_data);
3737

38+
/**
39+
* Supported proxy authentication modes
40+
*/
41+
enum aws_http_proxy_authentication_type {
42+
AWS_HPAT_NONE = 0,
43+
AWS_HPAT_BASIC,
44+
};
45+
46+
/**
47+
* Options for http proxy server usage
48+
*/
49+
struct aws_http_proxy_options {
50+
51+
/**
52+
* Proxy host to connect to, in lieu of actual target
53+
*/
54+
struct aws_byte_cursor host;
55+
56+
/**
57+
* Port to make the proxy connection to
58+
*/
59+
uint16_t port;
60+
61+
/**
62+
* Optional.
63+
* TLS configuration for the Local <-> Proxy connection
64+
* Must be distinct from the the TLS options in the parent aws_http_connection_options struct
65+
*/
66+
struct aws_tls_connection_options *tls_options;
67+
68+
/**
69+
* What type of proxy authentication to use, if any
70+
*/
71+
enum aws_http_proxy_authentication_type auth_type;
72+
73+
/**
74+
* Optional
75+
* User name to use for authentication, basic only
76+
*/
77+
struct aws_byte_cursor auth_username;
78+
79+
/**
80+
* Optional
81+
* Password to use for authentication, basic only
82+
*/
83+
struct aws_byte_cursor auth_password;
84+
};
85+
3886
/**
3987
* Options for creating an HTTP client connection.
4088
* Initialize with AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT to set default values.
@@ -82,6 +130,13 @@ struct aws_http_client_connection_options {
82130
*/
83131
struct aws_tls_connection_options *tls_options;
84132

133+
/**
134+
* Optional
135+
* Configuration options related to http proxy usage.
136+
* Relevant fields are copied internally.
137+
*/
138+
struct aws_http_proxy_options *proxy_options;
139+
85140
/**
86141
* Optional.
87142
* A default size is set by AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT.
@@ -159,6 +214,18 @@ void aws_http_connection_close(struct aws_http_connection *connection);
159214
AWS_HTTP_API
160215
bool aws_http_connection_is_open(const struct aws_http_connection *connection);
161216

217+
/**
218+
* Returns true if this is a client connection.
219+
*/
220+
AWS_HTTP_API
221+
bool aws_http_connection_is_client(const struct aws_http_connection *connection);
222+
223+
/**
224+
* Increments the connection-wide read window by the value specified.
225+
*/
226+
AWS_HTTP_API
227+
void aws_http_connection_update_window(struct aws_http_connection *connection, size_t increment_size);
228+
162229
AWS_HTTP_API
163230
enum aws_http_version aws_http_connection_get_version(const struct aws_http_connection *connection);
164231

0 commit comments

Comments
 (0)