15
15
#include <aws/http/connection.h>
16
16
#include <aws/http/request_response.h>
17
17
18
+ #include <aws/common/command_line_parser.h>
18
19
#include <aws/common/condition_variable.h>
19
20
#include <aws/common/mutex.h>
20
21
#include <aws/common/string.h>
29
30
#include <aws/io/tls_channel_handler.h>
30
31
#include <aws/io/uri.h>
31
32
32
- #include <getopt.h>
33
+ #ifdef _MSC_VER
34
+ # pragma warning(disable : 4996) /* Disable warnings about fopen() being insecure */
35
+ # pragma warning(disable : 4204) /* Declared initializers */
36
+ # pragma warning(disable : 4221) /* Local var in declared initializer */
37
+ #endif
33
38
34
39
struct elasticurl_ctx {
35
40
struct aws_allocator * allocator ;
36
41
const char * verb ;
37
42
struct aws_uri uri ;
43
+ struct aws_mutex mutex ;
38
44
struct aws_condition_variable c_var ;
39
45
bool response_code_written ;
40
46
const char * cacert ;
@@ -51,6 +57,7 @@ struct elasticurl_ctx {
51
57
FILE * output ;
52
58
const char * trace_file ;
53
59
enum aws_log_level log_level ;
60
+ bool exchange_completed ;
54
61
};
55
62
56
63
static void s_usage (void ) {
@@ -80,33 +87,33 @@ static void s_usage(void) {
80
87
exit (1 );
81
88
}
82
89
83
- static struct option s_long_options [] = {
84
- {"cacert" , required_argument , NULL , 'a' },
85
- {"capath" , required_argument , NULL , 'b' },
86
- {"cert" , required_argument , NULL , 'c' },
87
- {"key" , required_argument , NULL , 'e' },
88
- {"connect-timeout" , required_argument , NULL , 'f' },
89
- {"header" , required_argument , NULL , 'H' },
90
- {"data" , required_argument , NULL , 'd' },
91
- {"data-file" , required_argument , NULL , 'g' },
92
- {"method" , required_argument , NULL , 'M' },
93
- {"get" , no_argument , NULL , 'G' },
94
- {"post" , no_argument , NULL , 'P' },
95
- {"head" , no_argument , NULL , 'I' },
96
- {"include" , no_argument , NULL , 'i' },
97
- {"insecure" , no_argument , NULL , 'k' },
98
- {"output" , required_argument , NULL , 'o' },
99
- {"trace" , required_argument , NULL , 't' },
100
- {"verbose" , required_argument , NULL , 'v' },
101
- {"help" , no_argument , NULL , 'h' },
90
+ static struct aws_cli_option s_long_options [] = {
91
+ {"cacert" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'a' },
92
+ {"capath" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'b' },
93
+ {"cert" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'c' },
94
+ {"key" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'e' },
95
+ {"connect-timeout" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'f' },
96
+ {"header" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'H' },
97
+ {"data" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'd' },
98
+ {"data-file" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'g' },
99
+ {"method" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'M' },
100
+ {"get" , AWS_CLI_OPTIONS_NO_ARGUMENT , NULL , 'G' },
101
+ {"post" , AWS_CLI_OPTIONS_NO_ARGUMENT , NULL , 'P' },
102
+ {"head" , AWS_CLI_OPTIONS_NO_ARGUMENT , NULL , 'I' },
103
+ {"include" , AWS_CLI_OPTIONS_NO_ARGUMENT , NULL , 'i' },
104
+ {"insecure" , AWS_CLI_OPTIONS_NO_ARGUMENT , NULL , 'k' },
105
+ {"output" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'o' },
106
+ {"trace" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 't' },
107
+ {"verbose" , AWS_CLI_OPTIONS_REQUIRED_ARGUMENT , NULL , 'v' },
108
+ {"help" , AWS_CLI_OPTIONS_NO_ARGUMENT , NULL , 'h' },
102
109
/* Per getopt(3) the last element of the array has to be filled with all zeros */
103
- {NULL , no_argument , NULL , 0 },
110
+ {NULL , AWS_CLI_OPTIONS_NO_ARGUMENT , NULL , 0 },
104
111
};
105
112
106
113
static void s_parse_options (int argc , char * * argv , struct elasticurl_ctx * ctx ) {
107
114
while (true) {
108
115
int option_index = 0 ;
109
- int c = getopt_long (argc , argv , "a:b:c:e:f:H:d:g:M:GPHiko:t:v:h" , s_long_options , & option_index );
116
+ int c = aws_cli_getopt_long (argc , argv , "a:b:c:e:f:H:d:g:M:GPHiko:t:v:h" , s_long_options , & option_index );
110
117
if (c == -1 ) {
111
118
break ;
112
119
}
@@ -116,42 +123,40 @@ static void s_parse_options(int argc, char **argv, struct elasticurl_ctx *ctx) {
116
123
/* getopt_long() returns 0 if an option.flag is non-null */
117
124
break ;
118
125
case 'a' :
119
- ctx -> cacert = optarg ;
126
+ ctx -> cacert = aws_cli_optarg ;
120
127
break ;
121
128
case 'b' :
122
- ctx -> capath = optarg ;
129
+ ctx -> capath = aws_cli_optarg ;
123
130
break ;
124
131
case 'c' :
125
- ctx -> cert = optarg ;
132
+ ctx -> cert = aws_cli_optarg ;
126
133
break ;
127
134
case 'e' :
128
- ctx -> key = optarg ;
135
+ ctx -> key = aws_cli_optarg ;
129
136
break ;
130
137
case 'f' :
131
- ctx -> connect_timeout = atoi (optarg );
138
+ ctx -> connect_timeout = atoi (aws_cli_optarg );
132
139
break ;
133
140
case 'H' :
134
141
if (ctx -> header_line_count >= sizeof (ctx -> header_lines ) / sizeof (const char * )) {
135
142
fprintf (stderr , "currently only 10 header lines are supported.\n" );
136
143
s_usage ();
137
- exit (1 );
138
144
}
139
- ctx -> header_lines [ctx -> header_line_count ++ ] = optarg ;
145
+ ctx -> header_lines [ctx -> header_line_count ++ ] = aws_cli_optarg ;
140
146
break ;
141
147
case 'd' :
142
- ctx -> data = aws_byte_cursor_from_c_str (optarg );
148
+ ctx -> data = aws_byte_cursor_from_c_str (aws_cli_optarg );
143
149
break ;
144
150
case 'g' :
145
151
146
- ctx -> data_file = fopen (optarg , "r " );
152
+ ctx -> data_file = fopen (aws_cli_optarg , "rb " );
147
153
if (!ctx -> data_file ) {
148
- fprintf (stderr , "unable to open file %s.\n" , optarg );
154
+ fprintf (stderr , "unable to open file %s.\n" , aws_cli_optarg );
149
155
s_usage ();
150
- exit (1 );
151
156
}
152
157
break ;
153
158
case 'M' :
154
- ctx -> verb = optarg ;
159
+ ctx -> verb = aws_cli_optarg ;
155
160
break ;
156
161
case 'G' :
157
162
ctx -> verb = "GET" ;
@@ -169,44 +174,41 @@ static void s_parse_options(int argc, char **argv, struct elasticurl_ctx *ctx) {
169
174
ctx -> insecure = true;
170
175
break ;
171
176
case 'o' :
172
- ctx -> output = fopen (optarg , "w " );
177
+ ctx -> output = fopen (aws_cli_optarg , "wb " );
173
178
174
179
if (!ctx -> output ) {
175
- fprintf (stderr , "unable to open file %s.\n" , optarg );
180
+ fprintf (stderr , "unable to open file %s.\n" , aws_cli_optarg );
176
181
s_usage ();
177
- exit (1 );
178
182
}
179
183
break ;
180
184
case 't' :
181
- ctx -> trace_file = optarg ;
185
+ ctx -> trace_file = aws_cli_optarg ;
182
186
break ;
183
187
case 'v' :
184
- if (!strcmp (optarg , "TRACE" )) {
188
+ if (!strcmp (aws_cli_optarg , "TRACE" )) {
185
189
ctx -> log_level = AWS_LL_TRACE ;
186
- } else if (!strcmp (optarg , "INFO" )) {
190
+ } else if (!strcmp (aws_cli_optarg , "INFO" )) {
187
191
ctx -> log_level = AWS_LL_INFO ;
188
- } else if (!strcmp (optarg , "DEBUG" )) {
192
+ } else if (!strcmp (aws_cli_optarg , "DEBUG" )) {
189
193
ctx -> log_level = AWS_LL_DEBUG ;
190
- } else if (!strcmp (optarg , "ERROR" )) {
194
+ } else if (!strcmp (aws_cli_optarg , "ERROR" )) {
191
195
ctx -> log_level = AWS_LL_ERROR ;
192
196
} else {
193
- fprintf (stderr , "unsupported log level %s.\n" , optarg );
197
+ fprintf (stderr , "unsupported log level %s.\n" , aws_cli_optarg );
194
198
s_usage ();
195
- exit (1 );
196
199
}
197
200
break ;
198
201
case 'h' :
199
202
s_usage ();
200
- exit ( 1 ) ;
203
+ break ;
201
204
default :
202
205
fprintf (stderr , "Unknown option\n" );
203
206
s_usage ();
204
- exit (1 );
205
207
}
206
208
}
207
209
208
- if (optind < argc ) {
209
- struct aws_byte_cursor uri_cursor = aws_byte_cursor_from_c_str (argv [optind ++ ]);
210
+ if (aws_cli_optind < argc ) {
211
+ struct aws_byte_cursor uri_cursor = aws_byte_cursor_from_c_str (argv [aws_cli_optind ++ ]);
210
212
211
213
if (aws_uri_init_parse (& ctx -> uri , ctx -> allocator , & uri_cursor )) {
212
214
fprintf (
@@ -215,12 +217,10 @@ static void s_parse_options(int argc, char **argv, struct elasticurl_ctx *ctx) {
215
217
(char * )uri_cursor .ptr ,
216
218
aws_error_debug_str (aws_last_error ()));
217
219
s_usage ();
218
- exit (1 );
219
220
};
220
221
} else {
221
222
fprintf (stderr , "A URI for the request must be supplied.\n" );
222
223
s_usage ();
223
- exit (1 );
224
224
}
225
225
}
226
226
@@ -260,7 +260,12 @@ enum aws_http_outgoing_body_state s_stream_outgoing_body_fn(
260
260
}
261
261
262
262
if (app_ctx -> data_file ) {
263
+ #ifdef _WIN32
264
+ size_t read_val = fread (buf -> buffer , 1 , buf -> len , app_ctx -> data_file );
265
+ long long read = read_val == 0 ? ferror (app_ctx -> data_file ) : (long long )read_val ;
266
+ #else
263
267
ssize_t read = fread (buf -> buffer , 1 , buf -> len , app_ctx -> data_file );
268
+ #endif
264
269
265
270
/* if any data is left in the buffer, tell the client that we're still in progress,
266
271
* otherwise say we're done. */
@@ -317,6 +322,9 @@ static void s_on_client_connection_setup(struct aws_http_connection *connection,
317
322
318
323
if (error_code ) {
319
324
fprintf (stderr , "Connection failed with error %s\n" , aws_error_debug_str (error_code ));
325
+ aws_mutex_lock (& app_ctx -> mutex );
326
+ app_ctx -> exchange_completed = true;
327
+ aws_mutex_unlock (& app_ctx -> mutex );
320
328
aws_condition_variable_notify_all (& app_ctx -> c_var );
321
329
return ;
322
330
}
@@ -399,7 +407,6 @@ static void s_on_client_connection_setup(struct aws_http_connection *connection,
399
407
exit (1 );
400
408
}
401
409
402
- /* Release hold on connection, it will clean itself up once stream completes */
403
410
aws_http_connection_release (connection );
404
411
}
405
412
@@ -408,9 +415,17 @@ static void s_on_client_connection_shutdown(struct aws_http_connection *connecti
408
415
(void )connection ;
409
416
struct elasticurl_ctx * app_ctx = user_data ;
410
417
418
+ aws_mutex_lock (& app_ctx -> mutex );
419
+ app_ctx -> exchange_completed = true;
420
+ aws_mutex_unlock (& app_ctx -> mutex );
411
421
aws_condition_variable_notify_all (& app_ctx -> c_var );
412
422
}
413
423
424
+ static bool s_completion_predicate (void * arg ) {
425
+ struct elasticurl_ctx * app_ctx = arg ;
426
+ return app_ctx -> exchange_completed ;
427
+ }
428
+
414
429
AWS_STATIC_STRING_FROM_LITERAL (http_cmp1 , "http" );
415
430
AWS_STATIC_STRING_FROM_LITERAL (http_cmp2 , "Http" );
416
431
AWS_STATIC_STRING_FROM_LITERAL (http_cmp3 , "HTTP" );
@@ -428,17 +443,13 @@ int main(int argc, char **argv) {
428
443
app_ctx .connect_timeout = 3000 ;
429
444
app_ctx .output = stdout ;
430
445
app_ctx .verb = "GET" ;
446
+ aws_mutex_init (& app_ctx .mutex );
431
447
432
448
s_parse_options (argc , argv , & app_ctx );
433
449
434
450
struct aws_logger logger ;
435
451
AWS_ZERO_STRUCT (logger );
436
- struct aws_log_writer log_writer ;
437
- AWS_ZERO_STRUCT (log_writer );
438
- struct aws_log_formatter log_formatter ;
439
- AWS_ZERO_STRUCT (log_formatter );
440
- struct aws_log_channel log_channel ;
441
- AWS_ZERO_STRUCT (log_channel );
452
+
442
453
if (app_ctx .log_level ) {
443
454
aws_io_load_log_subject_strings ();
444
455
aws_http_load_log_subject_strings ();
@@ -577,10 +588,9 @@ int main(int argc, char **argv) {
577
588
.on_shutdown = s_on_client_connection_shutdown ,
578
589
};
579
590
580
- struct aws_mutex semaphore_mutex = AWS_MUTEX_INIT ;
581
591
aws_http_client_connect (& http_client_options );
582
- aws_mutex_lock (& semaphore_mutex );
583
- aws_condition_variable_wait (& app_ctx .c_var , & semaphore_mutex );
592
+ aws_mutex_lock (& app_ctx . mutex );
593
+ aws_condition_variable_wait_pred (& app_ctx .c_var , & app_ctx . mutex , s_completion_predicate , & app_ctx );
584
594
585
595
aws_client_bootstrap_destroy (bootstrap );
586
596
aws_event_loop_group_clean_up (& el_group );
0 commit comments