connection.c 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/http/private/connection_impl.h>
  6. #include <aws/http/private/connection_monitor.h>
  7. #include <aws/http/private/h1_connection.h>
  8. #include <aws/http/private/h2_connection.h>
  9. #include <aws/http/private/proxy_impl.h>
  10. #include <aws/common/hash_table.h>
  11. #include <aws/common/mutex.h>
  12. #include <aws/common/string.h>
  13. #include <aws/http/request_response.h>
  14. #include <aws/io/channel_bootstrap.h>
  15. #include <aws/io/logging.h>
  16. #include <aws/io/socket.h>
  17. #include <aws/io/tls_channel_handler.h>
  18. #ifdef _MSC_VER
  19. # pragma warning(disable : 4204) /* non-constant aggregate initializer */
  20. # pragma warning(disable : 4232) /* function pointer to dll symbol */
  21. #endif
  22. static struct aws_http_connection_system_vtable s_default_system_vtable = {
  23. .new_socket_channel = aws_client_bootstrap_new_socket_channel,
  24. };
  25. static const struct aws_http_connection_system_vtable *s_system_vtable_ptr = &s_default_system_vtable;
  26. void aws_http_client_bootstrap_destroy(struct aws_http_client_bootstrap *bootstrap) {
  27. /* During allocating, the underlying stuctures should be allocated with the bootstrap by aws_mem_acquire_many. Thus,
  28. * we only need to clean up the first pointer which is the bootstrap */
  29. if (bootstrap->alpn_string_map) {
  30. aws_hash_table_clean_up(bootstrap->alpn_string_map);
  31. }
  32. aws_mem_release(bootstrap->alloc, bootstrap);
  33. }
  34. void aws_http_connection_set_system_vtable(const struct aws_http_connection_system_vtable *system_vtable) {
  35. s_system_vtable_ptr = system_vtable;
  36. }
  37. AWS_STATIC_STRING_FROM_LITERAL(s_alpn_protocol_http_1_1, "http/1.1");
  38. AWS_STATIC_STRING_FROM_LITERAL(s_alpn_protocol_http_2, "h2");
  39. struct aws_http_server {
  40. struct aws_allocator *alloc;
  41. struct aws_server_bootstrap *bootstrap;
  42. bool is_using_tls;
  43. bool manual_window_management;
  44. size_t initial_window_size;
  45. void *user_data;
  46. aws_http_server_on_incoming_connection_fn *on_incoming_connection;
  47. aws_http_server_on_destroy_fn *on_destroy_complete;
  48. struct aws_socket *socket;
  49. /* Any thread may touch this data, but the lock must be held */
  50. struct {
  51. struct aws_mutex lock;
  52. bool is_shutting_down;
  53. struct aws_hash_table channel_to_connection_map;
  54. } synced_data;
  55. };
  56. static void s_server_lock_synced_data(struct aws_http_server *server) {
  57. int err = aws_mutex_lock(&server->synced_data.lock);
  58. AWS_ASSERT(!err);
  59. (void)err;
  60. }
  61. static void s_server_unlock_synced_data(struct aws_http_server *server) {
  62. int err = aws_mutex_unlock(&server->synced_data.lock);
  63. AWS_ASSERT(!err);
  64. (void)err;
  65. }
  66. /* Determine the http-version, create appropriate type of connection, and insert it into the channel. */
  67. struct aws_http_connection *aws_http_connection_new_channel_handler(
  68. struct aws_allocator *alloc,
  69. struct aws_channel *channel,
  70. bool is_server,
  71. bool is_using_tls,
  72. bool manual_window_management,
  73. bool prior_knowledge_http2,
  74. size_t initial_window_size,
  75. const struct aws_hash_table *alpn_string_map,
  76. const struct aws_http1_connection_options *http1_options,
  77. const struct aws_http2_connection_options *http2_options,
  78. void *connection_user_data) {
  79. struct aws_channel_slot *connection_slot = NULL;
  80. struct aws_http_connection *connection = NULL;
  81. /* Create slot for connection. */
  82. connection_slot = aws_channel_slot_new(channel);
  83. if (!connection_slot) {
  84. AWS_LOGF_ERROR(
  85. AWS_LS_HTTP_CONNECTION,
  86. "static: Failed to create slot in channel %p, error %d (%s).",
  87. (void *)channel,
  88. aws_last_error(),
  89. aws_error_name(aws_last_error()));
  90. goto error;
  91. }
  92. int err = aws_channel_slot_insert_end(channel, connection_slot);
  93. if (err) {
  94. AWS_LOGF_ERROR(
  95. AWS_LS_HTTP_CONNECTION,
  96. "static: Failed to insert slot into channel %p, error %d (%s).",
  97. (void *)channel,
  98. aws_last_error(),
  99. aws_error_name(aws_last_error()));
  100. goto error;
  101. }
  102. /* Determine HTTP version */
  103. enum aws_http_version version = AWS_HTTP_VERSION_1_1;
  104. if (is_using_tls) {
  105. /* Query TLS channel handler (immediately to left in the channel) for negotiated ALPN protocol */
  106. if (!connection_slot->adj_left || !connection_slot->adj_left->handler) {
  107. aws_raise_error(AWS_ERROR_INVALID_STATE);
  108. AWS_LOGF_ERROR(
  109. AWS_LS_HTTP_CONNECTION, "static: Failed to find TLS handler in channel %p.", (void *)channel);
  110. goto error;
  111. }
  112. struct aws_channel_slot *tls_slot = connection_slot->adj_left;
  113. struct aws_channel_handler *tls_handler = tls_slot->handler;
  114. struct aws_byte_buf protocol = aws_tls_handler_protocol(tls_handler);
  115. if (protocol.len) {
  116. bool customized = false;
  117. if (alpn_string_map) {
  118. customized = true;
  119. struct aws_string *negotiated_result = aws_string_new_from_buf(alloc, &protocol);
  120. struct aws_hash_element *found = NULL;
  121. aws_hash_table_find(alpn_string_map, (void *)negotiated_result, &found);
  122. if (found) {
  123. version = (enum aws_http_version)(size_t)found->value;
  124. AWS_LOGF_DEBUG(
  125. AWS_LS_HTTP_CONNECTION,
  126. "static: Customized ALPN protocol " PRInSTR " used. " PRInSTR " client connection established.",
  127. AWS_BYTE_BUF_PRI(protocol),
  128. AWS_BYTE_CURSOR_PRI(aws_http_version_to_str(version)));
  129. } else {
  130. AWS_LOGF_ERROR(
  131. AWS_LS_HTTP_CONNECTION,
  132. "static: Customized ALPN protocol " PRInSTR
  133. " used. However the it's not found in the ALPN map provided.",
  134. AWS_BYTE_BUF_PRI(protocol));
  135. version = AWS_HTTP_VERSION_UNKNOWN;
  136. }
  137. aws_string_destroy(negotiated_result);
  138. }
  139. if (customized) {
  140. /* Do nothing */
  141. } else if (aws_string_eq_byte_buf(s_alpn_protocol_http_1_1, &protocol)) {
  142. version = AWS_HTTP_VERSION_1_1;
  143. } else if (aws_string_eq_byte_buf(s_alpn_protocol_http_2, &protocol)) {
  144. version = AWS_HTTP_VERSION_2;
  145. } else {
  146. AWS_LOGF_WARN(AWS_LS_HTTP_CONNECTION, "static: Unrecognized ALPN protocol. Assuming HTTP/1.1");
  147. AWS_LOGF_DEBUG(
  148. AWS_LS_HTTP_CONNECTION, "static: Unrecognized ALPN protocol " PRInSTR, AWS_BYTE_BUF_PRI(protocol));
  149. version = AWS_HTTP_VERSION_1_1;
  150. }
  151. }
  152. } else {
  153. if (prior_knowledge_http2) {
  154. AWS_LOGF_TRACE(AWS_LS_HTTP_CONNECTION, "Using prior knowledge to start HTTP/2 connection");
  155. version = AWS_HTTP_VERSION_2;
  156. }
  157. }
  158. /* Create connection/handler */
  159. switch (version) {
  160. case AWS_HTTP_VERSION_1_1:
  161. if (is_server) {
  162. connection = aws_http_connection_new_http1_1_server(
  163. alloc, manual_window_management, initial_window_size, http1_options);
  164. } else {
  165. connection = aws_http_connection_new_http1_1_client(
  166. alloc, manual_window_management, initial_window_size, http1_options);
  167. }
  168. break;
  169. case AWS_HTTP_VERSION_2:
  170. if (is_server) {
  171. connection = aws_http_connection_new_http2_server(alloc, manual_window_management, http2_options);
  172. } else {
  173. connection = aws_http_connection_new_http2_client(alloc, manual_window_management, http2_options);
  174. }
  175. break;
  176. default:
  177. AWS_LOGF_ERROR(
  178. AWS_LS_HTTP_CONNECTION,
  179. "static: Unsupported version " PRInSTR,
  180. AWS_BYTE_CURSOR_PRI(aws_http_version_to_str(version)));
  181. aws_raise_error(AWS_ERROR_HTTP_UNSUPPORTED_PROTOCOL);
  182. goto error;
  183. }
  184. if (!connection) {
  185. AWS_LOGF_ERROR(
  186. AWS_LS_HTTP_CONNECTION,
  187. "static: Failed to create " PRInSTR " %s connection object, error %d (%s).",
  188. AWS_BYTE_CURSOR_PRI(aws_http_version_to_str(version)),
  189. is_server ? "server" : "client",
  190. aws_last_error(),
  191. aws_error_name(aws_last_error()));
  192. goto error;
  193. }
  194. connection->user_data = connection_user_data;
  195. /* Connect handler and slot */
  196. if (aws_channel_slot_set_handler(connection_slot, &connection->channel_handler)) {
  197. AWS_LOGF_ERROR(
  198. AWS_LS_HTTP_CONNECTION,
  199. "static: Failed to set HTTP handler into slot on channel %p, error %d (%s).",
  200. (void *)channel,
  201. aws_last_error(),
  202. aws_error_name(aws_last_error()));
  203. goto error;
  204. }
  205. /* Success! Inform connection that installation is complete */
  206. connection->vtable->on_channel_handler_installed(&connection->channel_handler, connection_slot);
  207. return connection;
  208. error:
  209. if (connection_slot) {
  210. if (!connection_slot->handler && connection) {
  211. aws_channel_handler_destroy(&connection->channel_handler);
  212. }
  213. aws_channel_slot_remove(connection_slot);
  214. }
  215. return NULL;
  216. }
  217. void aws_http_connection_close(struct aws_http_connection *connection) {
  218. AWS_ASSERT(connection);
  219. connection->vtable->close(connection);
  220. }
  221. void aws_http_connection_stop_new_requests(struct aws_http_connection *connection) {
  222. AWS_ASSERT(connection);
  223. connection->vtable->stop_new_requests(connection);
  224. }
  225. bool aws_http_connection_is_open(const struct aws_http_connection *connection) {
  226. AWS_ASSERT(connection);
  227. return connection->vtable->is_open(connection);
  228. }
  229. bool aws_http_connection_new_requests_allowed(const struct aws_http_connection *connection) {
  230. AWS_ASSERT(connection);
  231. return connection->vtable->new_requests_allowed(connection);
  232. }
  233. bool aws_http_connection_is_client(const struct aws_http_connection *connection) {
  234. return connection->client_data;
  235. }
  236. bool aws_http_connection_is_server(const struct aws_http_connection *connection) {
  237. return connection->server_data;
  238. }
  239. int aws_http2_connection_change_settings(
  240. struct aws_http_connection *http2_connection,
  241. const struct aws_http2_setting *settings_array,
  242. size_t num_settings,
  243. aws_http2_on_change_settings_complete_fn *on_completed,
  244. void *user_data) {
  245. AWS_ASSERT(http2_connection);
  246. AWS_PRECONDITION(http2_connection->vtable);
  247. AWS_FATAL_ASSERT(http2_connection->http_version == AWS_HTTP_VERSION_2);
  248. return http2_connection->vtable->change_settings(
  249. http2_connection, settings_array, num_settings, on_completed, user_data);
  250. }
  251. int aws_http2_connection_ping(
  252. struct aws_http_connection *http2_connection,
  253. const struct aws_byte_cursor *optional_opaque_data,
  254. aws_http2_on_ping_complete_fn *on_ack,
  255. void *user_data) {
  256. AWS_ASSERT(http2_connection);
  257. AWS_PRECONDITION(http2_connection->vtable);
  258. AWS_FATAL_ASSERT(http2_connection->http_version == AWS_HTTP_VERSION_2);
  259. return http2_connection->vtable->send_ping(http2_connection, optional_opaque_data, on_ack, user_data);
  260. }
  261. void aws_http2_connection_send_goaway(
  262. struct aws_http_connection *http2_connection,
  263. uint32_t http2_error,
  264. bool allow_more_streams,
  265. const struct aws_byte_cursor *optional_debug_data) {
  266. AWS_ASSERT(http2_connection);
  267. AWS_PRECONDITION(http2_connection->vtable);
  268. AWS_FATAL_ASSERT(http2_connection->http_version == AWS_HTTP_VERSION_2);
  269. http2_connection->vtable->send_goaway(http2_connection, http2_error, allow_more_streams, optional_debug_data);
  270. }
  271. int aws_http2_connection_get_sent_goaway(
  272. struct aws_http_connection *http2_connection,
  273. uint32_t *out_http2_error,
  274. uint32_t *out_last_stream_id) {
  275. AWS_ASSERT(http2_connection);
  276. AWS_PRECONDITION(out_http2_error);
  277. AWS_PRECONDITION(out_last_stream_id);
  278. AWS_PRECONDITION(http2_connection->vtable);
  279. AWS_FATAL_ASSERT(http2_connection->http_version == AWS_HTTP_VERSION_2);
  280. return http2_connection->vtable->get_sent_goaway(http2_connection, out_http2_error, out_last_stream_id);
  281. }
  282. int aws_http2_connection_get_received_goaway(
  283. struct aws_http_connection *http2_connection,
  284. uint32_t *out_http2_error,
  285. uint32_t *out_last_stream_id) {
  286. AWS_ASSERT(http2_connection);
  287. AWS_PRECONDITION(out_http2_error);
  288. AWS_PRECONDITION(out_last_stream_id);
  289. AWS_PRECONDITION(http2_connection->vtable);
  290. AWS_FATAL_ASSERT(http2_connection->http_version == AWS_HTTP_VERSION_2);
  291. return http2_connection->vtable->get_received_goaway(http2_connection, out_http2_error, out_last_stream_id);
  292. }
  293. void aws_http2_connection_get_local_settings(
  294. const struct aws_http_connection *http2_connection,
  295. struct aws_http2_setting out_settings[AWS_HTTP2_SETTINGS_COUNT]) {
  296. AWS_ASSERT(http2_connection);
  297. AWS_PRECONDITION(http2_connection->vtable);
  298. AWS_FATAL_ASSERT(http2_connection->http_version == AWS_HTTP_VERSION_2);
  299. http2_connection->vtable->get_local_settings(http2_connection, out_settings);
  300. }
  301. void aws_http2_connection_get_remote_settings(
  302. const struct aws_http_connection *http2_connection,
  303. struct aws_http2_setting out_settings[AWS_HTTP2_SETTINGS_COUNT]) {
  304. AWS_ASSERT(http2_connection);
  305. AWS_PRECONDITION(http2_connection->vtable);
  306. AWS_FATAL_ASSERT(http2_connection->http_version == AWS_HTTP_VERSION_2);
  307. http2_connection->vtable->get_remote_settings(http2_connection, out_settings);
  308. }
  309. void aws_http2_connection_update_window(struct aws_http_connection *http2_connection, uint32_t increment_size) {
  310. AWS_ASSERT(http2_connection);
  311. AWS_PRECONDITION(http2_connection->vtable);
  312. AWS_FATAL_ASSERT(http2_connection->http_version == AWS_HTTP_VERSION_2);
  313. http2_connection->vtable->update_window(http2_connection, increment_size);
  314. }
  315. struct aws_channel *aws_http_connection_get_channel(struct aws_http_connection *connection) {
  316. AWS_ASSERT(connection);
  317. return connection->channel_slot->channel;
  318. }
  319. int aws_http_alpn_map_init(struct aws_allocator *allocator, struct aws_hash_table *map) {
  320. AWS_ASSERT(allocator);
  321. AWS_ASSERT(map);
  322. int result = aws_hash_table_init(
  323. map,
  324. allocator,
  325. 5 /* initial size */,
  326. aws_hash_string,
  327. aws_hash_callback_string_eq,
  328. aws_hash_callback_string_destroy,
  329. NULL);
  330. if (result) {
  331. /* OOM will crash */
  332. int error_code = aws_last_error();
  333. AWS_LOGF_ERROR(
  334. AWS_LS_HTTP_CONNECTION,
  335. "Failed to initialize ALPN map with error code %d (%s)",
  336. error_code,
  337. aws_error_name(error_code));
  338. }
  339. return result;
  340. }
  341. void aws_http_connection_acquire(struct aws_http_connection *connection) {
  342. AWS_ASSERT(connection);
  343. aws_atomic_fetch_add(&connection->refcount, 1);
  344. }
  345. void aws_http_connection_release(struct aws_http_connection *connection) {
  346. if (!connection) {
  347. return;
  348. }
  349. size_t prev_refcount = aws_atomic_fetch_sub(&connection->refcount, 1);
  350. if (prev_refcount == 1) {
  351. AWS_LOGF_TRACE(
  352. AWS_LS_HTTP_CONNECTION,
  353. "id=%p: Final connection refcount released, shut down if necessary.",
  354. (void *)connection);
  355. /* Channel might already be shut down, but make sure */
  356. aws_channel_shutdown(connection->channel_slot->channel, AWS_ERROR_SUCCESS);
  357. /* When the channel's refcount reaches 0, it destroys its slots/handlers, which will destroy the connection */
  358. aws_channel_release_hold(connection->channel_slot->channel);
  359. } else {
  360. AWS_FATAL_ASSERT(prev_refcount != 0);
  361. AWS_LOGF_TRACE(
  362. AWS_LS_HTTP_CONNECTION,
  363. "id=%p: Connection refcount released, %zu remaining.",
  364. (void *)connection,
  365. prev_refcount - 1);
  366. }
  367. }
  368. /* At this point, the server bootstrapper has accepted an incoming connection from a client and set up a channel.
  369. * Now we need to create an aws_http_connection and insert it into the channel as a channel-handler.
  370. * Note: Be careful not to access server->socket until lock is acquired to avoid race conditions */
  371. static void s_server_bootstrap_on_accept_channel_setup(
  372. struct aws_server_bootstrap *bootstrap,
  373. int error_code,
  374. struct aws_channel *channel,
  375. void *user_data) {
  376. (void)bootstrap;
  377. AWS_ASSERT(user_data);
  378. struct aws_http_server *server = user_data;
  379. bool user_cb_invoked = false;
  380. struct aws_http_connection *connection = NULL;
  381. if (error_code) {
  382. AWS_LOGF_ERROR(
  383. AWS_LS_HTTP_SERVER,
  384. "%p: Incoming connection failed with error code %d (%s)",
  385. (void *)server,
  386. error_code,
  387. aws_error_name(error_code));
  388. goto error;
  389. }
  390. /* Create connection */
  391. /* TODO: expose http1/2 options to server API */
  392. struct aws_http1_connection_options http1_options;
  393. AWS_ZERO_STRUCT(http1_options);
  394. struct aws_http2_connection_options http2_options;
  395. AWS_ZERO_STRUCT(http2_options);
  396. connection = aws_http_connection_new_channel_handler(
  397. server->alloc,
  398. channel,
  399. true,
  400. server->is_using_tls,
  401. server->manual_window_management,
  402. false, /* prior_knowledge_http2 */
  403. server->initial_window_size,
  404. NULL, /* alpn_string_map */
  405. &http1_options,
  406. &http2_options,
  407. NULL /* connection_user_data */);
  408. if (!connection) {
  409. AWS_LOGF_ERROR(
  410. AWS_LS_HTTP_SERVER,
  411. "%p: Failed to create connection object, error %d (%s).",
  412. (void *)server,
  413. aws_last_error(),
  414. aws_error_name(aws_last_error()));
  415. goto error;
  416. }
  417. int put_err = 0;
  418. /* BEGIN CRITICAL SECTION */
  419. s_server_lock_synced_data(server);
  420. if (server->synced_data.is_shutting_down) {
  421. error_code = AWS_ERROR_HTTP_CONNECTION_CLOSED;
  422. }
  423. if (!error_code) {
  424. put_err = aws_hash_table_put(&server->synced_data.channel_to_connection_map, channel, connection, NULL);
  425. }
  426. s_server_unlock_synced_data(server);
  427. /* END CRITICAL SECTION */
  428. if (error_code) {
  429. AWS_LOGF_ERROR(
  430. AWS_ERROR_HTTP_SERVER_CLOSED,
  431. "id=%p: Incoming connection failed. The server is shutting down.",
  432. (void *)server);
  433. goto error;
  434. }
  435. if (put_err) {
  436. AWS_LOGF_ERROR(
  437. AWS_LS_HTTP_SERVER,
  438. "%p: %s:%d: Failed to store connection object, error %d (%s).",
  439. (void *)server,
  440. server->socket->local_endpoint.address,
  441. server->socket->local_endpoint.port,
  442. aws_last_error(),
  443. aws_error_name(aws_last_error()));
  444. goto error;
  445. }
  446. /* Tell user of successful connection. */
  447. AWS_LOGF_INFO(
  448. AWS_LS_HTTP_CONNECTION,
  449. "id=%p: " PRInSTR " server connection established at %p %s:%d.",
  450. (void *)connection,
  451. AWS_BYTE_CURSOR_PRI(aws_http_version_to_str(connection->http_version)),
  452. (void *)server,
  453. server->socket->local_endpoint.address,
  454. server->socket->local_endpoint.port);
  455. server->on_incoming_connection(server, connection, AWS_ERROR_SUCCESS, server->user_data);
  456. user_cb_invoked = true;
  457. /* If user failed to configure the server during callback, shut down the channel. */
  458. if (!connection->server_data->on_incoming_request) {
  459. AWS_LOGF_ERROR(
  460. AWS_LS_HTTP_CONNECTION,
  461. "id=%p: Caller failed to invoke aws_http_connection_configure_server() during on_incoming_connection "
  462. "callback, closing connection.",
  463. (void *)connection);
  464. aws_raise_error(AWS_ERROR_HTTP_REACTION_REQUIRED);
  465. goto error;
  466. }
  467. return;
  468. error:
  469. if (!error_code) {
  470. error_code = aws_last_error();
  471. }
  472. if (!user_cb_invoked) {
  473. server->on_incoming_connection(server, NULL, error_code, server->user_data);
  474. }
  475. if (channel) {
  476. aws_channel_shutdown(channel, error_code);
  477. }
  478. if (connection) {
  479. /* release the ref count for the user side */
  480. aws_http_connection_release(connection);
  481. }
  482. }
  483. /* clean the server memory up */
  484. static void s_http_server_clean_up(struct aws_http_server *server) {
  485. if (!server) {
  486. return;
  487. }
  488. aws_server_bootstrap_release(server->bootstrap);
  489. /* invoke the user callback */
  490. if (server->on_destroy_complete) {
  491. server->on_destroy_complete(server->user_data);
  492. }
  493. aws_hash_table_clean_up(&server->synced_data.channel_to_connection_map);
  494. aws_mutex_clean_up(&server->synced_data.lock);
  495. aws_mem_release(server->alloc, server);
  496. }
  497. /* At this point, the channel for a server connection has completed shutdown, but hasn't been destroyed yet. */
  498. static void s_server_bootstrap_on_accept_channel_shutdown(
  499. struct aws_server_bootstrap *bootstrap,
  500. int error_code,
  501. struct aws_channel *channel,
  502. void *user_data) {
  503. (void)bootstrap;
  504. AWS_ASSERT(user_data);
  505. struct aws_http_server *server = user_data;
  506. /* Figure out which connection this was, and remove that entry from the map.
  507. * It won't be in the map if something went wrong while setting up the connection. */
  508. struct aws_hash_element map_elem;
  509. int was_present;
  510. /* BEGIN CRITICAL SECTION */
  511. s_server_lock_synced_data(server);
  512. int remove_err =
  513. aws_hash_table_remove(&server->synced_data.channel_to_connection_map, channel, &map_elem, &was_present);
  514. s_server_unlock_synced_data(server);
  515. /* END CRITICAL SECTION */
  516. if (!remove_err && was_present) {
  517. struct aws_http_connection *connection = map_elem.value;
  518. AWS_LOGF_INFO(AWS_LS_HTTP_CONNECTION, "id=%p: Server connection shut down.", (void *)connection);
  519. /* Tell user about shutdown */
  520. if (connection->server_data->on_shutdown) {
  521. connection->server_data->on_shutdown(connection, error_code, connection->user_data);
  522. }
  523. }
  524. }
  525. /* the server listener has finished the destroy process, no existing connections
  526. * finally safe to clean the server up */
  527. static void s_server_bootstrap_on_server_listener_destroy(struct aws_server_bootstrap *bootstrap, void *user_data) {
  528. (void)bootstrap;
  529. AWS_ASSERT(user_data);
  530. struct aws_http_server *server = user_data;
  531. s_http_server_clean_up(server);
  532. }
  533. struct aws_http_server *aws_http_server_new(const struct aws_http_server_options *options) {
  534. aws_http_fatal_assert_library_initialized();
  535. struct aws_http_server *server = NULL;
  536. if (!options || options->self_size == 0 || !options->allocator || !options->bootstrap || !options->socket_options ||
  537. !options->on_incoming_connection || !options->endpoint) {
  538. AWS_LOGF_ERROR(AWS_LS_HTTP_SERVER, "static: Invalid options, cannot create server.");
  539. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  540. /* nothing to clean up */
  541. return NULL;
  542. }
  543. server = aws_mem_calloc(options->allocator, 1, sizeof(struct aws_http_server));
  544. if (!server) {
  545. /* nothing to clean up */
  546. return NULL;
  547. }
  548. server->alloc = options->allocator;
  549. server->bootstrap = aws_server_bootstrap_acquire(options->bootstrap);
  550. server->is_using_tls = options->tls_options != NULL;
  551. server->initial_window_size = options->initial_window_size;
  552. server->user_data = options->server_user_data;
  553. server->on_incoming_connection = options->on_incoming_connection;
  554. server->on_destroy_complete = options->on_destroy_complete;
  555. server->manual_window_management = options->manual_window_management;
  556. int err = aws_mutex_init(&server->synced_data.lock);
  557. if (err) {
  558. AWS_LOGF_ERROR(
  559. AWS_LS_HTTP_SERVER, "static: Failed to initialize mutex, error %d (%s).", err, aws_error_name(err));
  560. goto mutex_error;
  561. }
  562. err = aws_hash_table_init(
  563. &server->synced_data.channel_to_connection_map, server->alloc, 16, aws_hash_ptr, aws_ptr_eq, NULL, NULL);
  564. if (err) {
  565. AWS_LOGF_ERROR(
  566. AWS_LS_HTTP_SERVER,
  567. "static: Cannot create server, error %d (%s).",
  568. aws_last_error(),
  569. aws_error_name(aws_last_error()));
  570. goto hash_table_error;
  571. }
  572. /* Protect against callbacks firing before server->socket is set */
  573. s_server_lock_synced_data(server);
  574. if (options->tls_options) {
  575. server->is_using_tls = true;
  576. }
  577. struct aws_server_socket_channel_bootstrap_options bootstrap_options = {
  578. .enable_read_back_pressure = options->manual_window_management,
  579. .tls_options = options->tls_options,
  580. .bootstrap = options->bootstrap,
  581. .socket_options = options->socket_options,
  582. .incoming_callback = s_server_bootstrap_on_accept_channel_setup,
  583. .shutdown_callback = s_server_bootstrap_on_accept_channel_shutdown,
  584. .destroy_callback = s_server_bootstrap_on_server_listener_destroy,
  585. .host_name = options->endpoint->address,
  586. .port = options->endpoint->port,
  587. .user_data = server,
  588. };
  589. server->socket = aws_server_bootstrap_new_socket_listener(&bootstrap_options);
  590. s_server_unlock_synced_data(server);
  591. if (!server->socket) {
  592. AWS_LOGF_ERROR(
  593. AWS_LS_HTTP_SERVER,
  594. "static: Failed creating new socket listener, error %d (%s). Cannot create server.",
  595. aws_last_error(),
  596. aws_error_name(aws_last_error()));
  597. goto socket_error;
  598. }
  599. AWS_LOGF_INFO(
  600. AWS_LS_HTTP_SERVER,
  601. "%p %s:%d: Server setup complete, listening for incoming connections.",
  602. (void *)server,
  603. server->socket->local_endpoint.address,
  604. server->socket->local_endpoint.port);
  605. return server;
  606. socket_error:
  607. aws_hash_table_clean_up(&server->synced_data.channel_to_connection_map);
  608. hash_table_error:
  609. aws_mutex_clean_up(&server->synced_data.lock);
  610. mutex_error:
  611. aws_mem_release(server->alloc, server);
  612. return NULL;
  613. }
  614. void aws_http_server_release(struct aws_http_server *server) {
  615. if (!server) {
  616. return;
  617. }
  618. bool already_shutting_down = false;
  619. /* BEGIN CRITICAL SECTION */
  620. s_server_lock_synced_data(server);
  621. if (server->synced_data.is_shutting_down) {
  622. already_shutting_down = true;
  623. } else {
  624. server->synced_data.is_shutting_down = true;
  625. }
  626. if (!already_shutting_down) {
  627. /* shutdown all existing channels */
  628. for (struct aws_hash_iter iter = aws_hash_iter_begin(&server->synced_data.channel_to_connection_map);
  629. !aws_hash_iter_done(&iter);
  630. aws_hash_iter_next(&iter)) {
  631. struct aws_channel *channel = (struct aws_channel *)iter.element.key;
  632. aws_channel_shutdown(channel, AWS_ERROR_HTTP_CONNECTION_CLOSED);
  633. }
  634. }
  635. s_server_unlock_synced_data(server);
  636. /* END CRITICAL SECTION */
  637. if (already_shutting_down) {
  638. /* The service is already shutting down, not shutting it down again */
  639. AWS_LOGF_TRACE(AWS_LS_HTTP_SERVER, "id=%p: The server is already shutting down", (void *)server);
  640. return;
  641. }
  642. /* stop listening, clean up the socket, after all existing connections finish shutting down, the
  643. * s_server_bootstrap_on_server_listener_destroy will be invoked, clean up of the server will be there */
  644. AWS_LOGF_INFO(
  645. AWS_LS_HTTP_SERVER,
  646. "%p %s:%d: Shutting down the server.",
  647. (void *)server,
  648. server->socket->local_endpoint.address,
  649. server->socket->local_endpoint.port);
  650. aws_server_bootstrap_destroy_socket_listener(server->bootstrap, server->socket);
  651. /* wait for connections to finish shutting down
  652. * clean up will be called from eventloop */
  653. }
  654. /* At this point, the channel bootstrapper has established a connection to the server and set up a channel.
  655. * Now we need to create the aws_http_connection and insert it into the channel as a channel-handler. */
  656. static void s_client_bootstrap_on_channel_setup(
  657. struct aws_client_bootstrap *channel_bootstrap,
  658. int error_code,
  659. struct aws_channel *channel,
  660. void *user_data) {
  661. (void)channel_bootstrap;
  662. AWS_ASSERT(user_data);
  663. struct aws_http_client_bootstrap *http_bootstrap = user_data;
  664. /* Contract for setup callbacks is: channel is NULL if error_code is non-zero. */
  665. AWS_FATAL_ASSERT((error_code != 0) == (channel == NULL));
  666. if (error_code) {
  667. AWS_LOGF_ERROR(
  668. AWS_LS_HTTP_CONNECTION,
  669. "static: Client connection failed with error %d (%s).",
  670. error_code,
  671. aws_error_name(error_code));
  672. /* Immediately tell user of failed connection.
  673. * No channel exists, so there will be no channel_shutdown callback. */
  674. http_bootstrap->on_setup(NULL, error_code, http_bootstrap->user_data);
  675. /* Clean up the http_bootstrap, it has no more work to do. */
  676. aws_http_client_bootstrap_destroy(http_bootstrap);
  677. return;
  678. }
  679. AWS_LOGF_TRACE(AWS_LS_HTTP_CONNECTION, "static: Socket connected, creating client connection object.");
  680. http_bootstrap->connection = aws_http_connection_new_channel_handler(
  681. http_bootstrap->alloc,
  682. channel,
  683. false,
  684. http_bootstrap->is_using_tls,
  685. http_bootstrap->stream_manual_window_management,
  686. http_bootstrap->prior_knowledge_http2,
  687. http_bootstrap->initial_window_size,
  688. http_bootstrap->alpn_string_map,
  689. &http_bootstrap->http1_options,
  690. &http_bootstrap->http2_options,
  691. http_bootstrap->user_data);
  692. if (!http_bootstrap->connection) {
  693. AWS_LOGF_ERROR(
  694. AWS_LS_HTTP_CONNECTION,
  695. "static: Failed to create the client connection object, error %d (%s).",
  696. aws_last_error(),
  697. aws_error_name(aws_last_error()));
  698. goto error;
  699. }
  700. if (aws_http_connection_monitoring_options_is_valid(&http_bootstrap->monitoring_options)) {
  701. /*
  702. * On creation we validate monitoring options, if they exist, and fail if they're not
  703. * valid. So at this point, is_valid() functions as an is-monitoring-on? check. A false
  704. * value here is not an error, it's just not enabled.
  705. */
  706. struct aws_crt_statistics_handler *http_connection_monitor =
  707. aws_crt_statistics_handler_new_http_connection_monitor(
  708. http_bootstrap->alloc, &http_bootstrap->monitoring_options);
  709. if (http_connection_monitor == NULL) {
  710. goto error;
  711. }
  712. aws_channel_set_statistics_handler(channel, http_connection_monitor);
  713. }
  714. http_bootstrap->connection->proxy_request_transform = http_bootstrap->proxy_request_transform;
  715. AWS_LOGF_INFO(
  716. AWS_LS_HTTP_CONNECTION,
  717. "id=%p: " PRInSTR " client connection established.",
  718. (void *)http_bootstrap->connection,
  719. AWS_BYTE_CURSOR_PRI(aws_http_version_to_str(http_bootstrap->connection->http_version)));
  720. /* Tell user of successful connection.
  721. * Then clear the on_setup callback so that we know it's been called */
  722. http_bootstrap->on_setup(http_bootstrap->connection, AWS_ERROR_SUCCESS, http_bootstrap->user_data);
  723. http_bootstrap->on_setup = NULL;
  724. return;
  725. error:
  726. /* Something went wrong. Invoke channel shutdown. Then wait for channel shutdown to complete
  727. * before informing the user that setup failed and cleaning up the http_bootstrap.*/
  728. aws_channel_shutdown(channel, aws_last_error());
  729. }
  730. /* At this point, the channel for a client connection has completed its shutdown */
  731. static void s_client_bootstrap_on_channel_shutdown(
  732. struct aws_client_bootstrap *channel_bootstrap,
  733. int error_code,
  734. struct aws_channel *channel,
  735. void *user_data) {
  736. (void)channel_bootstrap;
  737. (void)channel;
  738. AWS_ASSERT(user_data);
  739. struct aws_http_client_bootstrap *http_bootstrap = user_data;
  740. /* If on_setup hasn't been called yet, inform user of failed setup.
  741. * If on_setup was already called, inform user that it's shut down now. */
  742. if (http_bootstrap->on_setup) {
  743. /* make super duper sure that failed setup receives a non-zero error_code */
  744. if (error_code == 0) {
  745. error_code = AWS_ERROR_UNKNOWN;
  746. }
  747. AWS_LOGF_ERROR(
  748. AWS_LS_HTTP_CONNECTION,
  749. "static: Client setup failed with error %d (%s).",
  750. error_code,
  751. aws_error_name(error_code));
  752. http_bootstrap->on_setup(NULL, error_code, http_bootstrap->user_data);
  753. } else if (http_bootstrap->on_shutdown) {
  754. AWS_LOGF_INFO(
  755. AWS_LS_HTTP_CONNECTION,
  756. "%p: Client shutdown completed with error %d (%s).",
  757. (void *)http_bootstrap->connection,
  758. error_code,
  759. aws_error_name(error_code));
  760. http_bootstrap->on_shutdown(http_bootstrap->connection, error_code, http_bootstrap->user_data);
  761. }
  762. /* Clean up bootstrapper */
  763. aws_http_client_bootstrap_destroy(http_bootstrap);
  764. }
  765. int s_validate_http_client_connection_options(const struct aws_http_client_connection_options *options) {
  766. if (options->self_size == 0) {
  767. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: Invalid connection options, self size not initialized");
  768. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  769. }
  770. if (!options->allocator) {
  771. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: Invalid connection options, no allocator supplied");
  772. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  773. }
  774. if (options->host_name.len == 0) {
  775. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: Invalid connection options, empty host name.");
  776. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  777. }
  778. if (!options->socket_options) {
  779. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: Invalid connection options, socket options are null.");
  780. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  781. }
  782. if (!options->on_setup) {
  783. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: Invalid connection options, setup callback is null");
  784. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  785. }
  786. /* http2_options cannot be NULL here, calling function adds them if they were missing */
  787. if (options->http2_options->num_initial_settings > 0 && options->http2_options->initial_settings_array) {
  788. AWS_LOGF_ERROR(
  789. AWS_LS_HTTP_CONNECTION,
  790. "static: Invalid connection options, h2 settings count is non-zero but settings array is null");
  791. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  792. }
  793. if (options->monitoring_options && !aws_http_connection_monitoring_options_is_valid(options->monitoring_options)) {
  794. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: Invalid connection options, invalid monitoring options");
  795. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  796. }
  797. if (options->prior_knowledge_http2 && options->tls_options) {
  798. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: HTTP/2 prior knowledge only works with cleartext TCP.");
  799. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  800. }
  801. return AWS_OP_SUCCESS;
  802. }
  803. struct s_copy_alpn_string_map_context {
  804. struct aws_hash_table *map;
  805. struct aws_allocator *allocator;
  806. };
  807. /* put every item into the source to make a deep copy of the map */
  808. static int s_copy_alpn_string_map(void *context, struct aws_hash_element *item) {
  809. struct s_copy_alpn_string_map_context *func_context = context;
  810. struct aws_hash_table *dest = func_context->map;
  811. /* make a deep copy of the string and hash map will own the copy */
  812. struct aws_string *key_copy = aws_string_new_from_string(func_context->allocator, item->key);
  813. int was_created;
  814. if (aws_hash_table_put(dest, key_copy, item->value, &was_created)) {
  815. int error_code = aws_last_error();
  816. AWS_LOGF_ERROR(
  817. AWS_LS_HTTP_CONNECTION,
  818. "Failed to copy ALPN map with error code %d (%s)",
  819. error_code,
  820. aws_error_name(error_code));
  821. /* failed to put into the table, we need to clean up the copy ourselves */
  822. aws_string_destroy(key_copy);
  823. /* return error to stop iteration */
  824. return AWS_COMMON_HASH_TABLE_ITER_ERROR;
  825. }
  826. if (!was_created) {
  827. /* no new entry created, clean up the copy ourselves */
  828. aws_string_destroy(key_copy);
  829. }
  830. return AWS_COMMON_HASH_TABLE_ITER_CONTINUE;
  831. }
  832. int aws_http_alpn_map_init_copy(
  833. struct aws_allocator *allocator,
  834. struct aws_hash_table *dest,
  835. struct aws_hash_table *src) {
  836. if (!src) {
  837. AWS_ZERO_STRUCT(*dest);
  838. return AWS_OP_SUCCESS;
  839. }
  840. if (!src->p_impl) {
  841. AWS_ZERO_STRUCT(*dest);
  842. return AWS_OP_SUCCESS;
  843. }
  844. if (aws_http_alpn_map_init(allocator, dest)) {
  845. return AWS_OP_ERR;
  846. }
  847. struct s_copy_alpn_string_map_context context;
  848. context.allocator = allocator;
  849. context.map = dest;
  850. /* make a deep copy of the map */
  851. if (aws_hash_table_foreach(src, s_copy_alpn_string_map, &context)) {
  852. int error_code = aws_last_error();
  853. AWS_LOGF_ERROR(
  854. AWS_LS_HTTP_CONNECTION,
  855. "Failed to copy ALPN map with error code %d (%s)",
  856. error_code,
  857. aws_error_name(error_code));
  858. aws_hash_table_clean_up(dest);
  859. return AWS_OP_ERR;
  860. }
  861. return AWS_OP_SUCCESS;
  862. }
  863. int aws_http_client_connect_internal(
  864. const struct aws_http_client_connection_options *orig_options,
  865. aws_http_proxy_request_transform_fn *proxy_request_transform) {
  866. if (!orig_options) {
  867. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: http connection options are null.");
  868. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  869. }
  870. struct aws_http_client_bootstrap *http_bootstrap = NULL;
  871. struct aws_string *host_name = NULL;
  872. int err = 0;
  873. /* make copy of options, and add defaults for missing optional structs */
  874. struct aws_http_client_connection_options options = *orig_options;
  875. struct aws_http1_connection_options default_http1_options;
  876. AWS_ZERO_STRUCT(default_http1_options);
  877. if (options.http1_options == NULL) {
  878. options.http1_options = &default_http1_options;
  879. }
  880. struct aws_http2_connection_options default_http2_options;
  881. AWS_ZERO_STRUCT(default_http2_options);
  882. if (options.http2_options == NULL) {
  883. options.http2_options = &default_http2_options;
  884. }
  885. /* validate options */
  886. if (s_validate_http_client_connection_options(&options)) {
  887. goto error;
  888. }
  889. AWS_FATAL_ASSERT(options.proxy_options == NULL);
  890. /* bootstrap_new() functions requires a null-terminated c-str */
  891. host_name = aws_string_new_from_cursor(options.allocator, &options.host_name);
  892. if (!host_name) {
  893. goto error;
  894. }
  895. struct aws_http2_setting *setting_array = NULL;
  896. struct aws_hash_table *alpn_string_map = NULL;
  897. aws_mem_acquire_many(
  898. options.allocator,
  899. 3,
  900. &http_bootstrap,
  901. sizeof(struct aws_http_client_bootstrap),
  902. &setting_array,
  903. options.http2_options->num_initial_settings * sizeof(struct aws_http2_setting),
  904. &alpn_string_map,
  905. sizeof(struct aws_hash_table));
  906. AWS_ZERO_STRUCT(*http_bootstrap);
  907. http_bootstrap->alloc = options.allocator;
  908. http_bootstrap->is_using_tls = options.tls_options != NULL;
  909. http_bootstrap->stream_manual_window_management = options.manual_window_management;
  910. http_bootstrap->prior_knowledge_http2 = options.prior_knowledge_http2;
  911. http_bootstrap->initial_window_size = options.initial_window_size;
  912. http_bootstrap->user_data = options.user_data;
  913. http_bootstrap->on_setup = options.on_setup;
  914. http_bootstrap->on_shutdown = options.on_shutdown;
  915. http_bootstrap->proxy_request_transform = proxy_request_transform;
  916. http_bootstrap->http1_options = *options.http1_options;
  917. http_bootstrap->http2_options = *options.http2_options;
  918. /* keep a copy of the settings array if it's not NULL */
  919. if (options.http2_options->num_initial_settings > 0) {
  920. memcpy(
  921. setting_array,
  922. options.http2_options->initial_settings_array,
  923. options.http2_options->num_initial_settings * sizeof(struct aws_http2_setting));
  924. http_bootstrap->http2_options.initial_settings_array = setting_array;
  925. }
  926. if (options.alpn_string_map) {
  927. if (aws_http_alpn_map_init_copy(options.allocator, alpn_string_map, options.alpn_string_map)) {
  928. goto error;
  929. }
  930. http_bootstrap->alpn_string_map = alpn_string_map;
  931. }
  932. if (options.monitoring_options) {
  933. http_bootstrap->monitoring_options = *options.monitoring_options;
  934. }
  935. AWS_LOGF_TRACE(
  936. AWS_LS_HTTP_CONNECTION,
  937. "static: attempting to initialize a new client channel to %s:%d",
  938. aws_string_c_str(host_name),
  939. (int)options.port);
  940. struct aws_socket_channel_bootstrap_options channel_options = {
  941. .bootstrap = options.bootstrap,
  942. .host_name = aws_string_c_str(host_name),
  943. .port = options.port,
  944. .socket_options = options.socket_options,
  945. .tls_options = options.tls_options,
  946. .setup_callback = s_client_bootstrap_on_channel_setup,
  947. .shutdown_callback = s_client_bootstrap_on_channel_shutdown,
  948. .enable_read_back_pressure = options.manual_window_management,
  949. .user_data = http_bootstrap,
  950. .requested_event_loop = options.requested_event_loop,
  951. };
  952. err = s_system_vtable_ptr->new_socket_channel(&channel_options);
  953. if (err) {
  954. AWS_LOGF_ERROR(
  955. AWS_LS_HTTP_CONNECTION,
  956. "static: Failed to initiate socket channel for new client connection, error %d (%s).",
  957. aws_last_error(),
  958. aws_error_name(aws_last_error()));
  959. goto error;
  960. }
  961. aws_string_destroy(host_name);
  962. return AWS_OP_SUCCESS;
  963. error:
  964. if (http_bootstrap) {
  965. aws_http_client_bootstrap_destroy(http_bootstrap);
  966. }
  967. if (host_name) {
  968. aws_string_destroy(host_name);
  969. }
  970. return AWS_OP_ERR;
  971. }
  972. int aws_http_client_connect(const struct aws_http_client_connection_options *options) {
  973. aws_http_fatal_assert_library_initialized();
  974. if (options->prior_knowledge_http2 && options->tls_options) {
  975. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "static: HTTP/2 prior knowledge only works with cleartext TCP.");
  976. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  977. }
  978. if (options->proxy_options != NULL) {
  979. return aws_http_client_connect_via_proxy(options);
  980. } else {
  981. if (!options->proxy_ev_settings || options->proxy_ev_settings->env_var_type != AWS_HPEV_ENABLE) {
  982. return aws_http_client_connect_internal(options, NULL);
  983. } else {
  984. /* Proxy through envrionment variable is enabled */
  985. return aws_http_client_connect_via_proxy(options);
  986. }
  987. }
  988. }
  989. enum aws_http_version aws_http_connection_get_version(const struct aws_http_connection *connection) {
  990. return connection->http_version;
  991. }
  992. int aws_http_connection_configure_server(
  993. struct aws_http_connection *connection,
  994. const struct aws_http_server_connection_options *options) {
  995. if (!connection || !options || !options->on_incoming_request) {
  996. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "id=%p: Invalid server configuration options.", (void *)connection);
  997. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  998. }
  999. if (!connection->server_data) {
  1000. AWS_LOGF_WARN(
  1001. AWS_LS_HTTP_CONNECTION,
  1002. "id=%p: Server-only function invoked on client, ignoring call.",
  1003. (void *)connection);
  1004. return aws_raise_error(AWS_ERROR_INVALID_STATE);
  1005. }
  1006. if (connection->server_data->on_incoming_request) {
  1007. AWS_LOGF_WARN(
  1008. AWS_LS_HTTP_CONNECTION, "id=%p: Connection is already configured, ignoring call.", (void *)connection);
  1009. return aws_raise_error(AWS_ERROR_INVALID_STATE);
  1010. }
  1011. connection->user_data = options->connection_user_data;
  1012. connection->server_data->on_incoming_request = options->on_incoming_request;
  1013. connection->server_data->on_shutdown = options->on_shutdown;
  1014. return AWS_OP_SUCCESS;
  1015. }
  1016. /* Stream IDs are only 31 bits [5.1.1] */
  1017. static const uint32_t MAX_STREAM_ID = UINT32_MAX >> 1;
  1018. uint32_t aws_http_connection_get_next_stream_id(struct aws_http_connection *connection) {
  1019. uint32_t next_id = connection->next_stream_id;
  1020. if (AWS_UNLIKELY(next_id > MAX_STREAM_ID)) {
  1021. AWS_LOGF_INFO(AWS_LS_HTTP_CONNECTION, "id=%p: All available stream ids are gone", (void *)connection);
  1022. next_id = 0;
  1023. aws_raise_error(AWS_ERROR_HTTP_STREAM_IDS_EXHAUSTED);
  1024. } else {
  1025. connection->next_stream_id += 2;
  1026. }
  1027. return next_id;
  1028. }