proxy_connection.c 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  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/proxy_impl.h>
  6. #include <aws/common/encoding.h>
  7. #include <aws/common/environment.h>
  8. #include <aws/common/hash_table.h>
  9. #include <aws/common/string.h>
  10. #include <aws/http/connection_manager.h>
  11. #include <aws/http/private/connection_impl.h>
  12. #include <aws/http/proxy.h>
  13. #include <aws/http/request_response.h>
  14. #include <aws/io/channel.h>
  15. #include <aws/io/logging.h>
  16. #include <aws/io/tls_channel_handler.h>
  17. #include <aws/io/uri.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. AWS_STATIC_STRING_FROM_LITERAL(s_host_header_name, "Host");
  23. AWS_STATIC_STRING_FROM_LITERAL(s_proxy_connection_header_name, "Proxy-Connection");
  24. AWS_STATIC_STRING_FROM_LITERAL(s_proxy_connection_header_value, "Keep-Alive");
  25. AWS_STATIC_STRING_FROM_LITERAL(s_options_method, "OPTIONS");
  26. AWS_STATIC_STRING_FROM_LITERAL(s_star_path, "*");
  27. AWS_STATIC_STRING_FROM_LITERAL(s_http_proxy_env_var, "HTTP_PROXY");
  28. AWS_STATIC_STRING_FROM_LITERAL(s_http_proxy_env_var_low, "http_proxy");
  29. AWS_STATIC_STRING_FROM_LITERAL(s_https_proxy_env_var, "HTTPS_PROXY");
  30. AWS_STATIC_STRING_FROM_LITERAL(s_https_proxy_env_var_low, "https_proxy");
  31. #ifndef BYO_CRYPTO
  32. AWS_STATIC_STRING_FROM_LITERAL(s_proxy_no_verify_peer_env_var, "AWS_PROXY_NO_VERIFY_PEER");
  33. #endif
  34. static struct aws_http_proxy_system_vtable s_default_vtable = {
  35. .setup_client_tls = &aws_channel_setup_client_tls,
  36. };
  37. static struct aws_http_proxy_system_vtable *s_vtable = &s_default_vtable;
  38. void aws_http_proxy_system_set_vtable(struct aws_http_proxy_system_vtable *vtable) {
  39. s_vtable = vtable;
  40. }
  41. void aws_http_proxy_user_data_destroy(struct aws_http_proxy_user_data *user_data) {
  42. if (user_data == NULL) {
  43. return;
  44. }
  45. aws_hash_table_clean_up(&user_data->alpn_string_map);
  46. /*
  47. * For tunneling connections, this is now internal and never surfaced to the user, so it's our responsibility
  48. * to clean up the last reference.
  49. */
  50. if (user_data->proxy_connection != NULL && user_data->proxy_config->connection_type == AWS_HPCT_HTTP_TUNNEL) {
  51. aws_http_connection_release(user_data->proxy_connection);
  52. user_data->proxy_connection = NULL;
  53. }
  54. aws_string_destroy(user_data->original_host);
  55. if (user_data->proxy_config) {
  56. aws_http_proxy_config_destroy(user_data->proxy_config);
  57. }
  58. if (user_data->original_tls_options) {
  59. aws_tls_connection_options_clean_up(user_data->original_tls_options);
  60. aws_mem_release(user_data->allocator, user_data->original_tls_options);
  61. }
  62. aws_http_proxy_negotiator_release(user_data->proxy_negotiator);
  63. aws_client_bootstrap_release(user_data->original_bootstrap);
  64. aws_mem_release(user_data->allocator, user_data);
  65. }
  66. struct aws_http_proxy_user_data *aws_http_proxy_user_data_new(
  67. struct aws_allocator *allocator,
  68. const struct aws_http_client_connection_options *orig_options,
  69. aws_client_bootstrap_on_channel_event_fn *on_channel_setup,
  70. aws_client_bootstrap_on_channel_event_fn *on_channel_shutdown) {
  71. AWS_FATAL_ASSERT(orig_options->proxy_options != NULL);
  72. /* make copy of options, and add defaults for missing optional structs */
  73. struct aws_http_client_connection_options options = *orig_options;
  74. struct aws_http1_connection_options default_http1_options;
  75. AWS_ZERO_STRUCT(default_http1_options);
  76. if (options.http1_options == NULL) {
  77. options.http1_options = &default_http1_options;
  78. }
  79. struct aws_http2_connection_options default_http2_options;
  80. AWS_ZERO_STRUCT(default_http2_options);
  81. if (options.http2_options == NULL) {
  82. options.http2_options = &default_http2_options;
  83. }
  84. struct aws_http2_setting *setting_array = NULL;
  85. struct aws_http_proxy_user_data *user_data = NULL;
  86. aws_mem_acquire_many(
  87. options.allocator,
  88. 2,
  89. &user_data,
  90. sizeof(struct aws_http_proxy_user_data),
  91. &setting_array,
  92. options.http2_options->num_initial_settings * sizeof(struct aws_http2_setting));
  93. AWS_ZERO_STRUCT(*user_data);
  94. user_data->allocator = allocator;
  95. user_data->state = AWS_PBS_SOCKET_CONNECT;
  96. user_data->error_code = AWS_ERROR_SUCCESS;
  97. user_data->connect_status_code = AWS_HTTP_STATUS_CODE_UNKNOWN;
  98. user_data->original_bootstrap = aws_client_bootstrap_acquire(options.bootstrap);
  99. if (options.socket_options != NULL) {
  100. user_data->original_socket_options = *options.socket_options;
  101. }
  102. user_data->original_manual_window_management = options.manual_window_management;
  103. user_data->original_initial_window_size = options.initial_window_size;
  104. user_data->original_host = aws_string_new_from_cursor(allocator, &options.host_name);
  105. if (user_data->original_host == NULL) {
  106. goto on_error;
  107. }
  108. user_data->original_port = options.port;
  109. user_data->proxy_config = aws_http_proxy_config_new_from_connection_options(allocator, &options);
  110. if (user_data->proxy_config == NULL) {
  111. goto on_error;
  112. }
  113. user_data->proxy_negotiator =
  114. aws_http_proxy_strategy_create_negotiator(user_data->proxy_config->proxy_strategy, allocator);
  115. if (user_data->proxy_negotiator == NULL) {
  116. goto on_error;
  117. }
  118. if (options.tls_options) {
  119. /* clone tls options, but redirect user data to what we're creating */
  120. user_data->original_tls_options = aws_mem_calloc(allocator, 1, sizeof(struct aws_tls_connection_options));
  121. if (user_data->original_tls_options == NULL ||
  122. aws_tls_connection_options_copy(user_data->original_tls_options, options.tls_options)) {
  123. goto on_error;
  124. }
  125. user_data->original_tls_options->user_data = user_data;
  126. }
  127. if (aws_http_alpn_map_init_copy(options.allocator, &user_data->alpn_string_map, options.alpn_string_map)) {
  128. goto on_error;
  129. }
  130. user_data->original_http_on_setup = options.on_setup;
  131. user_data->original_http_on_shutdown = options.on_shutdown;
  132. user_data->original_channel_on_setup = on_channel_setup;
  133. user_data->original_channel_on_shutdown = on_channel_shutdown;
  134. user_data->requested_event_loop = options.requested_event_loop;
  135. user_data->prior_knowledge_http2 = options.prior_knowledge_http2;
  136. /* one and only one setup callback must be valid */
  137. AWS_FATAL_ASSERT((user_data->original_http_on_setup == NULL) != (user_data->original_channel_on_setup == NULL));
  138. /* one and only one shutdown callback must be valid */
  139. AWS_FATAL_ASSERT(
  140. (user_data->original_http_on_shutdown == NULL) != (user_data->original_channel_on_shutdown == NULL));
  141. /* callback set must be self-consistent. Technically the second check is redundant given the previous checks */
  142. AWS_FATAL_ASSERT((user_data->original_http_on_setup == NULL) == (user_data->original_http_on_shutdown == NULL));
  143. AWS_FATAL_ASSERT(
  144. (user_data->original_channel_on_setup == NULL) == (user_data->original_channel_on_shutdown == NULL));
  145. user_data->original_user_data = options.user_data;
  146. user_data->original_http1_options = *options.http1_options;
  147. user_data->original_http2_options = *options.http2_options;
  148. /* keep a copy of the settings array if it's not NULL */
  149. if (options.http2_options->num_initial_settings > 0) {
  150. memcpy(
  151. setting_array,
  152. options.http2_options->initial_settings_array,
  153. options.http2_options->num_initial_settings * sizeof(struct aws_http2_setting));
  154. user_data->original_http2_options.initial_settings_array = setting_array;
  155. }
  156. return user_data;
  157. on_error:
  158. AWS_LOGF_ERROR(
  159. AWS_LS_HTTP_CONNECTION,
  160. "(STATIC) Proxy connection failed to create user data with error %d(%s)",
  161. aws_last_error(),
  162. aws_error_str(aws_last_error()));
  163. aws_http_proxy_user_data_destroy(user_data);
  164. return NULL;
  165. }
  166. struct aws_http_proxy_user_data *aws_http_proxy_user_data_new_reset_clone(
  167. struct aws_allocator *allocator,
  168. struct aws_http_proxy_user_data *old_user_data) {
  169. AWS_FATAL_ASSERT(old_user_data != NULL);
  170. struct aws_http2_setting *setting_array = NULL;
  171. struct aws_http_proxy_user_data *user_data = NULL;
  172. aws_mem_acquire_many(
  173. allocator,
  174. 2,
  175. &user_data,
  176. sizeof(struct aws_http_proxy_user_data),
  177. &setting_array,
  178. old_user_data->original_http2_options.num_initial_settings * sizeof(struct aws_http2_setting));
  179. AWS_ZERO_STRUCT(*user_data);
  180. user_data->allocator = allocator;
  181. user_data->state = AWS_PBS_SOCKET_CONNECT;
  182. user_data->error_code = AWS_ERROR_SUCCESS;
  183. user_data->connect_status_code = AWS_HTTP_STATUS_CODE_UNKNOWN;
  184. user_data->original_bootstrap = aws_client_bootstrap_acquire(old_user_data->original_bootstrap);
  185. user_data->original_socket_options = old_user_data->original_socket_options;
  186. user_data->original_manual_window_management = old_user_data->original_manual_window_management;
  187. user_data->original_initial_window_size = old_user_data->original_initial_window_size;
  188. user_data->prior_knowledge_http2 = old_user_data->prior_knowledge_http2;
  189. user_data->original_host = aws_string_new_from_string(allocator, old_user_data->original_host);
  190. if (user_data->original_host == NULL) {
  191. goto on_error;
  192. }
  193. user_data->original_port = old_user_data->original_port;
  194. user_data->proxy_config = aws_http_proxy_config_new_clone(allocator, old_user_data->proxy_config);
  195. if (user_data->proxy_config == NULL) {
  196. goto on_error;
  197. }
  198. user_data->proxy_negotiator = aws_http_proxy_negotiator_acquire(old_user_data->proxy_negotiator);
  199. if (user_data->proxy_negotiator == NULL) {
  200. goto on_error;
  201. }
  202. if (old_user_data->original_tls_options) {
  203. /* clone tls options, but redirect user data to what we're creating */
  204. user_data->original_tls_options = aws_mem_calloc(allocator, 1, sizeof(struct aws_tls_connection_options));
  205. if (user_data->original_tls_options == NULL ||
  206. aws_tls_connection_options_copy(user_data->original_tls_options, old_user_data->original_tls_options)) {
  207. goto on_error;
  208. }
  209. user_data->original_tls_options->user_data = user_data;
  210. }
  211. if (aws_http_alpn_map_init_copy(allocator, &user_data->alpn_string_map, &old_user_data->alpn_string_map)) {
  212. goto on_error;
  213. }
  214. user_data->original_http_on_setup = old_user_data->original_http_on_setup;
  215. user_data->original_http_on_shutdown = old_user_data->original_http_on_shutdown;
  216. user_data->original_channel_on_setup = old_user_data->original_channel_on_setup;
  217. user_data->original_channel_on_shutdown = old_user_data->original_channel_on_shutdown;
  218. user_data->original_user_data = old_user_data->original_user_data;
  219. user_data->original_http1_options = old_user_data->original_http1_options;
  220. user_data->original_http2_options = old_user_data->original_http2_options;
  221. /* keep a copy of the settings array if it's not NULL */
  222. if (old_user_data->original_http2_options.num_initial_settings > 0) {
  223. memcpy(
  224. setting_array,
  225. old_user_data->original_http2_options.initial_settings_array,
  226. old_user_data->original_http2_options.num_initial_settings * sizeof(struct aws_http2_setting));
  227. user_data->original_http2_options.initial_settings_array = setting_array;
  228. }
  229. return user_data;
  230. on_error:
  231. AWS_LOGF_ERROR(
  232. AWS_LS_HTTP_CONNECTION,
  233. "(STATIC) Proxy connection failed to create user data with error %d(%s)",
  234. aws_last_error(),
  235. aws_error_str(aws_last_error()));
  236. aws_http_proxy_user_data_destroy(user_data);
  237. return NULL;
  238. }
  239. /*
  240. * Examines the proxy user data state and determines whether to make an http-interface setup callback
  241. * or a raw channel setup callback
  242. */
  243. static void s_do_on_setup_callback(
  244. struct aws_http_proxy_user_data *proxy_ud,
  245. struct aws_http_connection *connection,
  246. int error_code) {
  247. if (proxy_ud->original_http_on_setup) {
  248. proxy_ud->original_http_on_setup(connection, error_code, proxy_ud->original_user_data);
  249. proxy_ud->original_http_on_setup = NULL;
  250. }
  251. if (proxy_ud->original_channel_on_setup) {
  252. struct aws_channel *channel = NULL;
  253. if (connection != NULL) {
  254. channel = aws_http_connection_get_channel(connection);
  255. }
  256. proxy_ud->original_channel_on_setup(
  257. proxy_ud->original_bootstrap, error_code, channel, proxy_ud->original_user_data);
  258. proxy_ud->original_channel_on_setup = NULL;
  259. }
  260. }
  261. /*
  262. * Examines the proxy user data state and determines whether to make an http-interface shutdown callback
  263. * or a raw channel shutdown callback
  264. */
  265. static void s_do_on_shutdown_callback(struct aws_http_proxy_user_data *proxy_ud, int error_code) {
  266. AWS_FATAL_ASSERT(proxy_ud->proxy_connection);
  267. if (proxy_ud->original_http_on_shutdown) {
  268. AWS_FATAL_ASSERT(proxy_ud->final_connection);
  269. proxy_ud->original_http_on_shutdown(proxy_ud->final_connection, error_code, proxy_ud->original_user_data);
  270. proxy_ud->original_http_on_shutdown = NULL;
  271. }
  272. if (proxy_ud->original_channel_on_shutdown) {
  273. struct aws_channel *channel = aws_http_connection_get_channel(proxy_ud->proxy_connection);
  274. proxy_ud->original_channel_on_shutdown(
  275. proxy_ud->original_bootstrap, error_code, channel, proxy_ud->original_user_data);
  276. proxy_ud->original_channel_on_shutdown = NULL;
  277. }
  278. }
  279. /*
  280. * Connection callback used ONLY by forwarding http proxy connections. After this,
  281. * the connection is live and the user is notified
  282. */
  283. static void s_aws_http_on_client_connection_http_forwarding_proxy_setup_fn(
  284. struct aws_http_connection *connection,
  285. int error_code,
  286. void *user_data) {
  287. struct aws_http_proxy_user_data *proxy_ud = user_data;
  288. s_do_on_setup_callback(proxy_ud, connection, error_code);
  289. if (error_code != AWS_ERROR_SUCCESS) {
  290. aws_http_proxy_user_data_destroy(user_data);
  291. } else {
  292. /*
  293. * The proxy connection and final connection are the same in forwarding proxy connections. This lets
  294. * us unconditionally use fatal asserts on these being non-null regardless of proxy configuration.
  295. */
  296. proxy_ud->proxy_connection = connection;
  297. proxy_ud->final_connection = connection;
  298. proxy_ud->state = AWS_PBS_SUCCESS;
  299. }
  300. }
  301. /*
  302. * Connection shutdown callback used by both http and https proxy connections. Only invokes
  303. * user shutdown if the connection was successfully established. Otherwise, it invokes
  304. * the user setup function with an error.
  305. */
  306. static void s_aws_http_on_client_connection_http_proxy_shutdown_fn(
  307. struct aws_http_connection *connection,
  308. int error_code,
  309. void *user_data) {
  310. struct aws_http_proxy_user_data *proxy_ud = user_data;
  311. if (proxy_ud->state == AWS_PBS_SUCCESS) {
  312. AWS_LOGF_INFO(
  313. AWS_LS_HTTP_CONNECTION,
  314. "(%p) Proxy connection (channel %p) shutting down.",
  315. (void *)connection,
  316. (void *)aws_http_connection_get_channel(connection));
  317. s_do_on_shutdown_callback(proxy_ud, error_code);
  318. } else {
  319. int ec = error_code;
  320. if (ec == AWS_ERROR_SUCCESS) {
  321. ec = proxy_ud->error_code;
  322. }
  323. if (ec == AWS_ERROR_SUCCESS) {
  324. ec = AWS_ERROR_UNKNOWN;
  325. }
  326. AWS_LOGF_WARN(
  327. AWS_LS_HTTP_CONNECTION,
  328. "(%p) Error %d while connecting to \"%s\" via proxy.",
  329. (void *)connection,
  330. ec,
  331. (char *)proxy_ud->original_host->bytes);
  332. s_do_on_setup_callback(proxy_ud, NULL, ec);
  333. }
  334. aws_http_proxy_user_data_destroy(user_data);
  335. }
  336. /*
  337. * On-any-error entry point that releases all resources involved in establishing the proxy connection.
  338. * This must not be invoked any time after a successful setup callback.
  339. */
  340. static void s_aws_http_proxy_user_data_shutdown(struct aws_http_proxy_user_data *user_data) {
  341. user_data->state = AWS_PBS_FAILURE;
  342. if (user_data->proxy_connection == NULL) {
  343. s_do_on_setup_callback(user_data, NULL, user_data->error_code);
  344. aws_http_proxy_user_data_destroy(user_data);
  345. return;
  346. }
  347. if (user_data->connect_stream) {
  348. aws_http_stream_release(user_data->connect_stream);
  349. user_data->connect_stream = NULL;
  350. }
  351. if (user_data->connect_request) {
  352. aws_http_message_destroy(user_data->connect_request);
  353. user_data->connect_request = NULL;
  354. }
  355. struct aws_http_connection *http_connection = user_data->proxy_connection;
  356. user_data->proxy_connection = NULL;
  357. aws_channel_shutdown(http_connection->channel_slot->channel, user_data->error_code);
  358. aws_http_connection_release(http_connection);
  359. }
  360. static struct aws_http_message *s_build_h1_proxy_connect_request(struct aws_http_proxy_user_data *user_data) {
  361. struct aws_http_message *request = aws_http_message_new_request(user_data->allocator);
  362. if (request == NULL) {
  363. return NULL;
  364. }
  365. struct aws_byte_buf path_buffer;
  366. AWS_ZERO_STRUCT(path_buffer);
  367. if (aws_http_message_set_request_method(request, aws_http_method_connect)) {
  368. goto on_error;
  369. }
  370. if (aws_byte_buf_init(&path_buffer, user_data->allocator, user_data->original_host->len + 10)) {
  371. goto on_error;
  372. }
  373. struct aws_byte_cursor host_cursor = aws_byte_cursor_from_string(user_data->original_host);
  374. if (aws_byte_buf_append(&path_buffer, &host_cursor)) {
  375. goto on_error;
  376. }
  377. struct aws_byte_cursor colon_cursor = aws_byte_cursor_from_c_str(":");
  378. if (aws_byte_buf_append(&path_buffer, &colon_cursor)) {
  379. goto on_error;
  380. }
  381. char port_str[20] = "\0";
  382. snprintf(port_str, sizeof(port_str), "%d", (int)user_data->original_port);
  383. struct aws_byte_cursor port_cursor = aws_byte_cursor_from_c_str(port_str);
  384. if (aws_byte_buf_append(&path_buffer, &port_cursor)) {
  385. goto on_error;
  386. }
  387. struct aws_byte_cursor path_cursor = aws_byte_cursor_from_array(path_buffer.buffer, path_buffer.len);
  388. if (aws_http_message_set_request_path(request, path_cursor)) {
  389. goto on_error;
  390. }
  391. struct aws_http_header host_header = {
  392. .name = aws_byte_cursor_from_string(s_host_header_name),
  393. .value = aws_byte_cursor_from_array(path_buffer.buffer, path_buffer.len),
  394. };
  395. if (aws_http_message_add_header(request, host_header)) {
  396. goto on_error;
  397. }
  398. struct aws_http_header keep_alive_header = {
  399. .name = aws_byte_cursor_from_string(s_proxy_connection_header_name),
  400. .value = aws_byte_cursor_from_string(s_proxy_connection_header_value),
  401. };
  402. if (aws_http_message_add_header(request, keep_alive_header)) {
  403. goto on_error;
  404. }
  405. aws_byte_buf_clean_up(&path_buffer);
  406. return request;
  407. on_error:
  408. AWS_LOGF_ERROR(
  409. AWS_LS_HTTP_CONNECTION,
  410. "(%p) TLS proxy connection failed to build CONNECT request with error %d(%s)",
  411. (void *)user_data->proxy_connection,
  412. aws_last_error(),
  413. aws_error_str(aws_last_error()));
  414. aws_byte_buf_clean_up(&path_buffer);
  415. aws_http_message_destroy(request);
  416. return NULL;
  417. }
  418. /*
  419. * Builds the CONNECT request issued after proxy connection establishment, during the creation of
  420. * tls-enabled proxy connections.
  421. */
  422. static struct aws_http_message *s_build_proxy_connect_request(struct aws_http_proxy_user_data *user_data) {
  423. struct aws_http_connection *proxy_connection = user_data->proxy_connection;
  424. switch (proxy_connection->http_version) {
  425. case AWS_HTTP_VERSION_1_1:
  426. return s_build_h1_proxy_connect_request(user_data);
  427. default:
  428. aws_raise_error(AWS_ERROR_HTTP_UNSUPPORTED_PROTOCOL);
  429. return NULL;
  430. }
  431. }
  432. static int s_aws_http_on_incoming_body_tunnel_proxy(
  433. struct aws_http_stream *stream,
  434. const struct aws_byte_cursor *data,
  435. void *user_data) {
  436. (void)stream;
  437. struct aws_http_proxy_user_data *context = user_data;
  438. aws_http_proxy_negotiator_connect_on_incoming_body_fn *on_incoming_body =
  439. context->proxy_negotiator->strategy_vtable.tunnelling_vtable->on_incoming_body_callback;
  440. if (on_incoming_body != NULL) {
  441. (*on_incoming_body)(context->proxy_negotiator, data);
  442. }
  443. aws_http_stream_update_window(stream, data->len);
  444. return AWS_OP_SUCCESS;
  445. }
  446. static int s_aws_http_on_response_headers_tunnel_proxy(
  447. struct aws_http_stream *stream,
  448. enum aws_http_header_block header_block,
  449. const struct aws_http_header *header_array,
  450. size_t num_headers,
  451. void *user_data) {
  452. (void)stream;
  453. struct aws_http_proxy_user_data *context = user_data;
  454. aws_http_proxy_negotiation_connect_on_incoming_headers_fn *on_incoming_headers =
  455. context->proxy_negotiator->strategy_vtable.tunnelling_vtable->on_incoming_headers_callback;
  456. if (on_incoming_headers != NULL) {
  457. (*on_incoming_headers)(context->proxy_negotiator, header_block, header_array, num_headers);
  458. }
  459. return AWS_OP_SUCCESS;
  460. }
  461. /*
  462. * Headers done callback for the CONNECT request made during tls proxy connections
  463. */
  464. static int s_aws_http_on_incoming_header_block_done_tunnel_proxy(
  465. struct aws_http_stream *stream,
  466. enum aws_http_header_block header_block,
  467. void *user_data) {
  468. struct aws_http_proxy_user_data *context = user_data;
  469. if (header_block == AWS_HTTP_HEADER_BLOCK_MAIN) {
  470. int status_code = AWS_HTTP_STATUS_CODE_UNKNOWN;
  471. aws_http_stream_get_incoming_response_status(stream, &status_code);
  472. context->connect_status_code = (enum aws_http_status_code)status_code;
  473. if (context->connect_status_code != AWS_HTTP_STATUS_CODE_200_OK) {
  474. AWS_LOGF_ERROR(
  475. AWS_LS_HTTP_CONNECTION,
  476. "(%p) Proxy CONNECT request failed with status code %d",
  477. (void *)context->proxy_connection,
  478. context->connect_status_code);
  479. context->error_code = AWS_ERROR_HTTP_PROXY_CONNECT_FAILED;
  480. }
  481. aws_http_proxy_negotiator_connect_status_fn *on_status =
  482. context->proxy_negotiator->strategy_vtable.tunnelling_vtable->on_status_callback;
  483. if (on_status != NULL) {
  484. (*on_status)(context->proxy_negotiator, context->connect_status_code);
  485. }
  486. }
  487. return AWS_OP_SUCCESS;
  488. }
  489. static int s_aws_http_apply_http_connection_to_proxied_channel(struct aws_http_proxy_user_data *context) {
  490. AWS_FATAL_ASSERT(context->proxy_connection != NULL);
  491. AWS_FATAL_ASSERT(context->original_http_on_setup != NULL);
  492. struct aws_channel *channel = aws_http_connection_get_channel(context->proxy_connection);
  493. struct aws_http_connection *connection = aws_http_connection_new_channel_handler(
  494. context->allocator,
  495. channel,
  496. false,
  497. context->original_tls_options != NULL,
  498. context->original_manual_window_management,
  499. context->prior_knowledge_http2,
  500. context->original_initial_window_size,
  501. context->alpn_string_map.p_impl == NULL ? NULL : &context->alpn_string_map,
  502. &context->original_http1_options,
  503. &context->original_http2_options,
  504. context->original_user_data);
  505. if (connection == NULL) {
  506. AWS_LOGF_ERROR(
  507. AWS_LS_HTTP_CONNECTION,
  508. "static: Failed to create the client connection object, error %d (%s).",
  509. aws_last_error(),
  510. aws_error_name(aws_last_error()));
  511. return AWS_OP_ERR;
  512. }
  513. AWS_LOGF_INFO(
  514. AWS_LS_HTTP_CONNECTION,
  515. "id=%p: " PRInSTR " client connection established.",
  516. (void *)connection,
  517. AWS_BYTE_CURSOR_PRI(aws_http_version_to_str(connection->http_version)));
  518. context->final_connection = connection;
  519. return AWS_OP_SUCCESS;
  520. }
  521. static void s_do_final_proxied_channel_setup(struct aws_http_proxy_user_data *proxy_ud) {
  522. if (proxy_ud->original_http_on_setup != NULL) {
  523. /*
  524. * If we're transitioning to http with http setup/shutdown callbacks, try to apply a new http connection to
  525. * the channel
  526. */
  527. if (s_aws_http_apply_http_connection_to_proxied_channel(proxy_ud)) {
  528. proxy_ud->error_code = aws_last_error();
  529. s_aws_http_proxy_user_data_shutdown(proxy_ud);
  530. return;
  531. }
  532. s_do_on_setup_callback(proxy_ud, proxy_ud->final_connection, AWS_ERROR_SUCCESS);
  533. } else {
  534. /*
  535. * Otherwise invoke setup directly (which will end up being channel setup)
  536. */
  537. s_do_on_setup_callback(proxy_ud, proxy_ud->proxy_connection, AWS_ERROR_SUCCESS);
  538. }
  539. /* Tell user of successful connection. */
  540. proxy_ud->state = AWS_PBS_SUCCESS;
  541. }
  542. /*
  543. * Tls negotiation callback for tls proxy connections
  544. */
  545. static void s_on_origin_server_tls_negotation_result(
  546. struct aws_channel_handler *handler,
  547. struct aws_channel_slot *slot,
  548. int error_code,
  549. void *user_data) {
  550. (void)handler;
  551. (void)slot;
  552. struct aws_http_proxy_user_data *context = user_data;
  553. if (error_code != AWS_ERROR_SUCCESS) {
  554. AWS_LOGF_ERROR(
  555. AWS_LS_HTTP_CONNECTION,
  556. "(%p) Proxy connection failed origin server TLS negotiation with error %d(%s)",
  557. (void *)context->proxy_connection,
  558. error_code,
  559. aws_error_str(error_code));
  560. context->error_code = error_code;
  561. s_aws_http_proxy_user_data_shutdown(context);
  562. return;
  563. }
  564. s_do_final_proxied_channel_setup(context);
  565. }
  566. static int s_create_tunneling_connection(struct aws_http_proxy_user_data *user_data);
  567. static int s_make_proxy_connect_request(struct aws_http_proxy_user_data *user_data);
  568. static void s_zero_callbacks(struct aws_http_proxy_user_data *proxy_ud) {
  569. proxy_ud->original_http_on_shutdown = NULL;
  570. proxy_ud->original_http_on_setup = NULL;
  571. proxy_ud->original_channel_on_shutdown = NULL;
  572. proxy_ud->original_channel_on_setup = NULL;
  573. }
  574. /*
  575. * Stream done callback for the CONNECT request made during tls proxy connections
  576. */
  577. static void s_aws_http_on_stream_complete_tunnel_proxy(
  578. struct aws_http_stream *stream,
  579. int error_code,
  580. void *user_data) {
  581. struct aws_http_proxy_user_data *context = user_data;
  582. AWS_FATAL_ASSERT(stream == context->connect_stream);
  583. if (context->error_code == AWS_ERROR_SUCCESS && error_code != AWS_ERROR_SUCCESS) {
  584. context->error_code = error_code;
  585. }
  586. if (context->error_code != AWS_ERROR_SUCCESS) {
  587. context->error_code = AWS_ERROR_HTTP_PROXY_CONNECT_FAILED;
  588. if (context->connect_status_code == AWS_HTTP_STATUS_CODE_407_PROXY_AUTHENTICATION_REQUIRED) {
  589. enum aws_http_proxy_negotiation_retry_directive retry_directive =
  590. aws_http_proxy_negotiator_get_retry_directive(context->proxy_negotiator);
  591. if (retry_directive == AWS_HPNRD_NEW_CONNECTION) {
  592. struct aws_http_proxy_user_data *new_context =
  593. aws_http_proxy_user_data_new_reset_clone(context->allocator, context);
  594. if (new_context != NULL && s_create_tunneling_connection(new_context) == AWS_OP_SUCCESS) {
  595. /*
  596. * We successfully kicked off a new connection. By NULLing the callbacks on the old one, we can
  597. * shut it down quietly without the user being notified. The new connection will notify the user
  598. * based on its success or failure.
  599. */
  600. s_zero_callbacks(context);
  601. context->error_code = AWS_ERROR_HTTP_PROXY_CONNECT_FAILED_RETRYABLE;
  602. }
  603. } else if (retry_directive == AWS_HPNRD_CURRENT_CONNECTION) {
  604. context->error_code = AWS_ERROR_SUCCESS;
  605. if (s_make_proxy_connect_request(context) == AWS_OP_SUCCESS) {
  606. return;
  607. }
  608. }
  609. }
  610. s_aws_http_proxy_user_data_shutdown(context);
  611. return;
  612. }
  613. AWS_LOGF_INFO(
  614. AWS_LS_HTTP_CONNECTION,
  615. "(%p) Proxy connection made successful CONNECT request to \"%s\" via proxy",
  616. (void *)context->proxy_connection,
  617. context->original_host->bytes);
  618. /*
  619. * We're finished with these, let's release
  620. */
  621. aws_http_stream_release(stream);
  622. context->connect_stream = NULL;
  623. aws_http_message_destroy(context->connect_request);
  624. context->connect_request = NULL;
  625. AWS_LOGF_INFO(
  626. AWS_LS_HTTP_CONNECTION, "(%p) Beginning TLS negotiation through proxy", (void *)context->proxy_connection);
  627. if (context->original_tls_options != NULL) {
  628. /*
  629. * Perform TLS negotiation to the origin server through proxy
  630. */
  631. context->original_tls_options->on_negotiation_result = s_on_origin_server_tls_negotation_result;
  632. context->state = AWS_PBS_TLS_NEGOTIATION;
  633. struct aws_channel *channel = aws_http_connection_get_channel(context->proxy_connection);
  634. struct aws_channel_slot *last_slot = aws_channel_get_first_slot(channel);
  635. while (last_slot->adj_right != NULL) {
  636. last_slot = last_slot->adj_right;
  637. }
  638. if (s_vtable->setup_client_tls(last_slot, context->original_tls_options)) {
  639. AWS_LOGF_ERROR(
  640. AWS_LS_HTTP_CONNECTION,
  641. "(%p) Proxy connection failed to start TLS negotiation with error %d(%s)",
  642. (void *)context->proxy_connection,
  643. aws_last_error(),
  644. aws_error_str(aws_last_error()));
  645. s_aws_http_proxy_user_data_shutdown(context);
  646. return;
  647. }
  648. } else {
  649. s_do_final_proxied_channel_setup(context);
  650. }
  651. }
  652. static void s_terminate_tunneling_connect(
  653. struct aws_http_message *message,
  654. int error_code,
  655. void *internal_proxy_user_data) {
  656. (void)message;
  657. struct aws_http_proxy_user_data *proxy_ud = internal_proxy_user_data;
  658. AWS_LOGF_ERROR(
  659. AWS_LS_HTTP_CONNECTION,
  660. "(%p) Tunneling proxy connection failed to create request stream for CONNECT request with error %d(%s)",
  661. (void *)proxy_ud->proxy_connection,
  662. error_code,
  663. aws_error_str(error_code));
  664. proxy_ud->error_code = error_code;
  665. s_aws_http_proxy_user_data_shutdown(proxy_ud);
  666. }
  667. static void s_continue_tunneling_connect(struct aws_http_message *message, void *internal_proxy_user_data) {
  668. struct aws_http_proxy_user_data *proxy_ud = internal_proxy_user_data;
  669. struct aws_http_make_request_options request_options = {
  670. .self_size = sizeof(request_options),
  671. .request = message,
  672. .user_data = proxy_ud,
  673. .on_response_headers = s_aws_http_on_response_headers_tunnel_proxy,
  674. .on_response_header_block_done = s_aws_http_on_incoming_header_block_done_tunnel_proxy,
  675. .on_response_body = s_aws_http_on_incoming_body_tunnel_proxy,
  676. .on_complete = s_aws_http_on_stream_complete_tunnel_proxy,
  677. };
  678. if (proxy_ud->connect_stream != NULL) {
  679. aws_http_stream_release(proxy_ud->connect_stream);
  680. }
  681. proxy_ud->connect_stream = aws_http_connection_make_request(proxy_ud->proxy_connection, &request_options);
  682. if (proxy_ud->connect_stream == NULL) {
  683. goto on_error;
  684. }
  685. aws_http_stream_activate(proxy_ud->connect_stream);
  686. return;
  687. on_error:
  688. s_aws_http_proxy_user_data_shutdown(proxy_ud);
  689. }
  690. /*
  691. * Issues a CONNECT request on an http connection
  692. */
  693. static int s_make_proxy_connect_request(struct aws_http_proxy_user_data *user_data) {
  694. if (user_data->connect_request != NULL) {
  695. aws_http_message_destroy(user_data->connect_request);
  696. user_data->connect_request = NULL;
  697. }
  698. user_data->connect_request = s_build_proxy_connect_request(user_data);
  699. if (user_data->connect_request == NULL) {
  700. return AWS_OP_ERR;
  701. }
  702. (*user_data->proxy_negotiator->strategy_vtable.tunnelling_vtable->connect_request_transform)(
  703. user_data->proxy_negotiator,
  704. user_data->connect_request,
  705. s_terminate_tunneling_connect,
  706. s_continue_tunneling_connect,
  707. user_data);
  708. return AWS_OP_SUCCESS;
  709. }
  710. /*
  711. * Connection setup callback for tunneling proxy connections.
  712. */
  713. static void s_aws_http_on_client_connection_http_tunneling_proxy_setup_fn(
  714. struct aws_http_connection *connection,
  715. int error_code,
  716. void *user_data) {
  717. struct aws_http_proxy_user_data *proxy_ud = user_data;
  718. proxy_ud->error_code = error_code;
  719. if (error_code != AWS_ERROR_SUCCESS) {
  720. goto on_error;
  721. }
  722. AWS_LOGF_INFO(AWS_LS_HTTP_CONNECTION, "(%p) Making CONNECT request to proxy", (void *)proxy_ud->proxy_connection);
  723. proxy_ud->proxy_connection = connection;
  724. proxy_ud->state = AWS_PBS_HTTP_CONNECT;
  725. if (s_make_proxy_connect_request(proxy_ud)) {
  726. goto on_error;
  727. }
  728. return;
  729. on_error:
  730. s_aws_http_proxy_user_data_shutdown(proxy_ud);
  731. }
  732. /*
  733. * Checks for the special case when a request is an OPTIONS request with *
  734. * path and no query params
  735. */
  736. static bool s_is_star_path_options_method(const struct aws_http_message *request) {
  737. struct aws_byte_cursor method_cursor;
  738. if (aws_http_message_get_request_method(request, &method_cursor)) {
  739. return false;
  740. }
  741. struct aws_byte_cursor options_cursor = aws_byte_cursor_from_string(s_options_method);
  742. if (!aws_byte_cursor_eq_ignore_case(&method_cursor, &options_cursor)) {
  743. return false;
  744. }
  745. struct aws_byte_cursor path_cursor;
  746. if (aws_http_message_get_request_path(request, &path_cursor)) {
  747. return false;
  748. }
  749. struct aws_byte_cursor star_cursor = aws_byte_cursor_from_string(s_star_path);
  750. if (!aws_byte_cursor_eq_ignore_case(&path_cursor, &star_cursor)) {
  751. return false;
  752. }
  753. return true;
  754. }
  755. /*
  756. * Modifies a requests uri by transforming it to absolute form according to
  757. * section 5.3.2 of rfc 7230
  758. *
  759. * We do this by parsing the existing uri and then rebuilding it as an
  760. * absolute resource path (using the original connection options)
  761. */
  762. int aws_http_rewrite_uri_for_proxy_request(
  763. struct aws_http_message *request,
  764. struct aws_http_proxy_user_data *proxy_user_data) {
  765. int result = AWS_OP_ERR;
  766. struct aws_uri target_uri;
  767. AWS_ZERO_STRUCT(target_uri);
  768. struct aws_byte_cursor path_cursor;
  769. AWS_ZERO_STRUCT(path_cursor);
  770. if (aws_http_message_get_request_path(request, &path_cursor)) {
  771. goto done;
  772. }
  773. /* Pull out the original path/query */
  774. struct aws_uri uri;
  775. if (aws_uri_init_parse(&uri, proxy_user_data->allocator, &path_cursor)) {
  776. goto done;
  777. }
  778. const struct aws_byte_cursor *actual_path_cursor = aws_uri_path(&uri);
  779. const struct aws_byte_cursor *actual_query_cursor = aws_uri_query_string(&uri);
  780. /* now rebuild the uri with scheme, host and port subbed in from the original connection options */
  781. struct aws_uri_builder_options target_uri_builder;
  782. AWS_ZERO_STRUCT(target_uri_builder);
  783. target_uri_builder.scheme = aws_http_scheme_http;
  784. target_uri_builder.path = *actual_path_cursor;
  785. target_uri_builder.host_name = aws_byte_cursor_from_string(proxy_user_data->original_host);
  786. target_uri_builder.port = proxy_user_data->original_port;
  787. target_uri_builder.query_string = *actual_query_cursor;
  788. if (aws_uri_init_from_builder_options(&target_uri, proxy_user_data->allocator, &target_uri_builder)) {
  789. goto done;
  790. }
  791. struct aws_byte_cursor full_target_uri =
  792. aws_byte_cursor_from_array(target_uri.uri_str.buffer, target_uri.uri_str.len);
  793. /*
  794. * By rfc 7230, Section 5.3.4, a star-pathed options request made through a proxy MUST be transformed (at the last
  795. * proxy) back into a star-pathed request if the proxy request has an empty path and no query string. This
  796. * is behavior we want to support. So from our side, we need to make sure that star-pathed options requests
  797. * get translated into options requests with the authority as the uri and an empty path-query.
  798. *
  799. * Our URI transform always ends with a '/' which is technically not an empty path. To address this,
  800. * the easiest thing to do is just detect if this was originally a star-pathed options request
  801. * and drop the final '/' from the path.
  802. */
  803. if (s_is_star_path_options_method(request)) {
  804. if (full_target_uri.len > 0 && *(full_target_uri.ptr + full_target_uri.len - 1) == '/') {
  805. full_target_uri.len -= 1;
  806. }
  807. }
  808. /* mutate the request with the new path value */
  809. if (aws_http_message_set_request_path(request, full_target_uri)) {
  810. goto done;
  811. }
  812. result = AWS_OP_SUCCESS;
  813. done:
  814. aws_uri_clean_up(&target_uri);
  815. aws_uri_clean_up(&uri);
  816. return result;
  817. }
  818. /*
  819. * Plaintext proxy request transformation function
  820. *
  821. * Rewrites the target uri to absolute form and injects any desired headers
  822. */
  823. static int s_proxy_http_request_transform(struct aws_http_message *request, void *user_data) {
  824. struct aws_http_proxy_user_data *proxy_ud = user_data;
  825. if (aws_http_rewrite_uri_for_proxy_request(request, proxy_ud)) {
  826. return AWS_OP_ERR;
  827. }
  828. if ((*proxy_ud->proxy_negotiator->strategy_vtable.forwarding_vtable->forward_request_transform)(
  829. proxy_ud->proxy_negotiator, request)) {
  830. return AWS_OP_ERR;
  831. }
  832. return AWS_OP_SUCCESS;
  833. }
  834. /*
  835. * Top-level function to route a connection request through a proxy server, with no channel security
  836. */
  837. static int s_aws_http_client_connect_via_forwarding_proxy(const struct aws_http_client_connection_options *options) {
  838. AWS_FATAL_ASSERT(options->tls_options == NULL);
  839. AWS_LOGF_INFO(
  840. AWS_LS_HTTP_CONNECTION,
  841. "(STATIC) Connecting to \"" PRInSTR "\" via proxy \"" PRInSTR "\"",
  842. AWS_BYTE_CURSOR_PRI(options->host_name),
  843. AWS_BYTE_CURSOR_PRI(options->proxy_options->host));
  844. /* Create a wrapper user data that contains all proxy-related information, state, and user-facing callbacks */
  845. struct aws_http_proxy_user_data *proxy_user_data =
  846. aws_http_proxy_user_data_new(options->allocator, options, NULL, NULL);
  847. if (proxy_user_data == NULL) {
  848. return AWS_OP_ERR;
  849. }
  850. AWS_FATAL_ASSERT(options->proxy_options != NULL);
  851. /* Fill in a new connection options pointing at the proxy */
  852. struct aws_http_client_connection_options options_copy = *options;
  853. options_copy.proxy_options = NULL;
  854. options_copy.host_name = options->proxy_options->host;
  855. options_copy.port = options->proxy_options->port;
  856. options_copy.user_data = proxy_user_data;
  857. options_copy.on_setup = s_aws_http_on_client_connection_http_forwarding_proxy_setup_fn;
  858. options_copy.on_shutdown = s_aws_http_on_client_connection_http_proxy_shutdown_fn;
  859. options_copy.tls_options = options->proxy_options->tls_options;
  860. options_copy.requested_event_loop = options->requested_event_loop;
  861. options_copy.prior_knowledge_http2 = false; /* ToDo, expose the protocol specific config for proxy connection. */
  862. int result = aws_http_client_connect_internal(&options_copy, s_proxy_http_request_transform);
  863. if (result == AWS_OP_ERR) {
  864. AWS_LOGF_ERROR(
  865. AWS_LS_HTTP_CONNECTION,
  866. "(STATIC) Proxy http connection failed client connect with error %d(%s)",
  867. aws_last_error(),
  868. aws_error_str(aws_last_error()));
  869. aws_http_proxy_user_data_destroy(proxy_user_data);
  870. }
  871. return result;
  872. }
  873. static int s_create_tunneling_connection(struct aws_http_proxy_user_data *user_data) {
  874. struct aws_http_client_connection_options connect_options;
  875. AWS_ZERO_STRUCT(connect_options);
  876. connect_options.self_size = sizeof(struct aws_http_client_connection_options);
  877. connect_options.allocator = user_data->allocator;
  878. connect_options.bootstrap = user_data->original_bootstrap;
  879. connect_options.host_name = aws_byte_cursor_from_buf(&user_data->proxy_config->host);
  880. connect_options.port = user_data->proxy_config->port;
  881. connect_options.socket_options = &user_data->original_socket_options;
  882. connect_options.tls_options = user_data->proxy_config->tls_options;
  883. connect_options.monitoring_options = NULL; /* ToDo */
  884. connect_options.manual_window_management = user_data->original_manual_window_management;
  885. connect_options.initial_window_size = user_data->original_initial_window_size;
  886. connect_options.user_data = user_data;
  887. connect_options.on_setup = s_aws_http_on_client_connection_http_tunneling_proxy_setup_fn;
  888. connect_options.on_shutdown = s_aws_http_on_client_connection_http_proxy_shutdown_fn;
  889. connect_options.http1_options = NULL; /* ToDo, expose the protocol specific config for proxy connection. */
  890. connect_options.http2_options = NULL; /* ToDo */
  891. connect_options.requested_event_loop = user_data->requested_event_loop;
  892. int result = aws_http_client_connect(&connect_options);
  893. if (result == AWS_OP_ERR) {
  894. AWS_LOGF_ERROR(
  895. AWS_LS_HTTP_CONNECTION,
  896. "(STATIC) Proxy tunnel connection failed client connect with error %d(%s)",
  897. aws_last_error(),
  898. aws_error_str(aws_last_error()));
  899. aws_http_proxy_user_data_destroy(user_data);
  900. }
  901. return result;
  902. }
  903. /*
  904. * Top-level function to route a connection through a proxy server via a CONNECT request
  905. */
  906. static int s_aws_http_client_connect_via_tunneling_proxy(
  907. const struct aws_http_client_connection_options *options,
  908. aws_client_bootstrap_on_channel_event_fn *on_channel_setup,
  909. aws_client_bootstrap_on_channel_event_fn *on_channel_shutdown) {
  910. AWS_FATAL_ASSERT(options->proxy_options != NULL);
  911. AWS_LOGF_INFO(
  912. AWS_LS_HTTP_CONNECTION,
  913. "(STATIC) Connecting to \"" PRInSTR "\" through a tunnel via proxy \"" PRInSTR "\"",
  914. AWS_BYTE_CURSOR_PRI(options->host_name),
  915. AWS_BYTE_CURSOR_PRI(options->proxy_options->host));
  916. /* Create a wrapper user data that contains all proxy-related information, state, and user-facing callbacks */
  917. struct aws_http_proxy_user_data *user_data =
  918. aws_http_proxy_user_data_new(options->allocator, options, on_channel_setup, on_channel_shutdown);
  919. if (user_data == NULL) {
  920. return AWS_OP_ERR;
  921. }
  922. return s_create_tunneling_connection(user_data);
  923. }
  924. static enum aws_http_proxy_connection_type s_determine_proxy_connection_type(
  925. enum aws_http_proxy_connection_type proxy_connection_type,
  926. bool is_tls_connection) {
  927. if (proxy_connection_type != AWS_HPCT_HTTP_LEGACY) {
  928. return proxy_connection_type;
  929. }
  930. if (is_tls_connection) {
  931. return AWS_HPCT_HTTP_TUNNEL;
  932. } else {
  933. return AWS_HPCT_HTTP_FORWARD;
  934. }
  935. }
  936. static int s_proxy_uri_init_from_env_variable(
  937. struct aws_allocator *allocator,
  938. const struct aws_http_client_connection_options *options,
  939. struct aws_uri *proxy_uri,
  940. bool *found) {
  941. struct aws_string *proxy_uri_string = NULL;
  942. *found = false;
  943. if (options->tls_options) {
  944. if (aws_get_environment_value(allocator, s_https_proxy_env_var_low, &proxy_uri_string) == AWS_OP_SUCCESS &&
  945. proxy_uri_string != NULL) {
  946. AWS_LOGF_DEBUG(AWS_LS_HTTP_CONNECTION, "https_proxy environment found");
  947. } else if (
  948. aws_get_environment_value(allocator, s_https_proxy_env_var, &proxy_uri_string) == AWS_OP_SUCCESS &&
  949. proxy_uri_string != NULL) {
  950. AWS_LOGF_DEBUG(AWS_LS_HTTP_CONNECTION, "HTTPS_PROXY environment found");
  951. } else {
  952. return AWS_OP_SUCCESS;
  953. }
  954. } else {
  955. if (aws_get_environment_value(allocator, s_http_proxy_env_var_low, &proxy_uri_string) == AWS_OP_SUCCESS &&
  956. proxy_uri_string != NULL) {
  957. AWS_LOGF_DEBUG(AWS_LS_HTTP_CONNECTION, "http_proxy environment found");
  958. } else if (
  959. aws_get_environment_value(allocator, s_http_proxy_env_var, &proxy_uri_string) == AWS_OP_SUCCESS &&
  960. proxy_uri_string != NULL) {
  961. AWS_LOGF_DEBUG(AWS_LS_HTTP_CONNECTION, "HTTP_PROXY environment found");
  962. } else {
  963. return AWS_OP_SUCCESS;
  964. }
  965. }
  966. struct aws_byte_cursor proxy_uri_cursor = aws_byte_cursor_from_string(proxy_uri_string);
  967. if (aws_uri_init_parse(proxy_uri, allocator, &proxy_uri_cursor)) {
  968. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "Could not parse found proxy URI.");
  969. aws_string_destroy(proxy_uri_string);
  970. return AWS_OP_ERR;
  971. }
  972. *found = true;
  973. aws_string_destroy(proxy_uri_string);
  974. return AWS_OP_SUCCESS;
  975. }
  976. static int s_connect_proxy(const struct aws_http_client_connection_options *options) {
  977. if (aws_http_options_validate_proxy_configuration(options)) {
  978. return AWS_OP_ERR;
  979. }
  980. enum aws_http_proxy_connection_type proxy_connection_type =
  981. s_determine_proxy_connection_type(options->proxy_options->connection_type, options->tls_options != NULL);
  982. switch (proxy_connection_type) {
  983. case AWS_HPCT_HTTP_FORWARD:
  984. return s_aws_http_client_connect_via_forwarding_proxy(options);
  985. case AWS_HPCT_HTTP_TUNNEL:
  986. return s_aws_http_client_connect_via_tunneling_proxy(options, NULL, NULL);
  987. default:
  988. return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
  989. }
  990. }
  991. static int s_setup_proxy_tls_env_variable(
  992. const struct aws_http_client_connection_options *options,
  993. struct aws_tls_connection_options *default_tls_connection_options,
  994. struct aws_http_proxy_options *proxy_options,
  995. struct aws_uri *proxy_uri) {
  996. (void)default_tls_connection_options;
  997. (void)proxy_uri;
  998. if (options->proxy_ev_settings->tls_options) {
  999. proxy_options->tls_options = options->proxy_ev_settings->tls_options;
  1000. } else {
  1001. #ifdef BYO_CRYPTO
  1002. AWS_LOGF_ERROR(
  1003. AWS_LS_HTTP_CONNECTION,
  1004. "Failed making default TLS context because of BYO_CRYPTO, set up the tls_options for proxy_env_settings to "
  1005. "make it work.");
  1006. return AWS_OP_ERR;
  1007. #else
  1008. struct aws_tls_ctx *tls_ctx = NULL;
  1009. struct aws_tls_ctx_options tls_ctx_options;
  1010. AWS_ZERO_STRUCT(tls_ctx_options);
  1011. /* create a default tls options */
  1012. aws_tls_ctx_options_init_default_client(&tls_ctx_options, options->allocator);
  1013. struct aws_string *proxy_no_verify_peer_string = NULL;
  1014. if (aws_get_environment_value(
  1015. options->allocator, s_proxy_no_verify_peer_env_var, &proxy_no_verify_peer_string) == AWS_OP_SUCCESS &&
  1016. proxy_no_verify_peer_string != NULL) {
  1017. /* turn off the peer verification, if setup from envrionment variable. Mostly for testing. */
  1018. aws_tls_ctx_options_set_verify_peer(&tls_ctx_options, false);
  1019. aws_string_destroy(proxy_no_verify_peer_string);
  1020. }
  1021. tls_ctx = aws_tls_client_ctx_new(options->allocator, &tls_ctx_options);
  1022. aws_tls_ctx_options_clean_up(&tls_ctx_options);
  1023. if (!tls_ctx) {
  1024. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "Failed to create default TLS context.");
  1025. return AWS_OP_ERR;
  1026. }
  1027. aws_tls_connection_options_init_from_ctx(default_tls_connection_options, tls_ctx);
  1028. /* tls options hold a ref to the ctx */
  1029. aws_tls_ctx_release(tls_ctx);
  1030. if (aws_tls_connection_options_set_server_name(
  1031. default_tls_connection_options, options->allocator, &proxy_uri->host_name)) {
  1032. AWS_LOGF_ERROR(AWS_LS_HTTP_CONNECTION, "Failed set server name for TLS connection options.");
  1033. return AWS_OP_ERR;
  1034. }
  1035. proxy_options->tls_options = default_tls_connection_options;
  1036. #endif
  1037. }
  1038. return AWS_OP_SUCCESS;
  1039. }
  1040. static int s_connect_proxy_via_env_variable(const struct aws_http_client_connection_options *options) {
  1041. struct aws_http_proxy_options proxy_options;
  1042. AWS_ZERO_STRUCT(proxy_options);
  1043. struct aws_uri proxy_uri;
  1044. AWS_ZERO_STRUCT(proxy_uri);
  1045. struct aws_tls_connection_options default_tls_connection_options;
  1046. AWS_ZERO_STRUCT(default_tls_connection_options);
  1047. bool found = false;
  1048. bool success = false;
  1049. if (s_proxy_uri_init_from_env_variable(options->allocator, options, &proxy_uri, &found)) {
  1050. /* Envrionment is set but failed to parse it */
  1051. goto done;
  1052. }
  1053. if (found) {
  1054. proxy_options.host = proxy_uri.host_name;
  1055. proxy_options.port = proxy_uri.port;
  1056. proxy_options.connection_type = options->proxy_ev_settings->connection_type;
  1057. if (proxy_options.connection_type == AWS_HPCT_HTTP_LEGACY) {
  1058. if (options->tls_options) {
  1059. /* Use tunneling when main connection use TLS. */
  1060. proxy_options.connection_type = AWS_HPCT_HTTP_TUNNEL;
  1061. } else {
  1062. /* Use forwarding proxy when main connection use clear text. */
  1063. proxy_options.connection_type = AWS_HPCT_HTTP_FORWARD;
  1064. }
  1065. }
  1066. if (aws_byte_cursor_eq_ignore_case(&proxy_uri.scheme, &aws_http_scheme_https)) {
  1067. if (s_setup_proxy_tls_env_variable(options, &default_tls_connection_options, &proxy_options, &proxy_uri)) {
  1068. goto done;
  1069. }
  1070. }
  1071. /* Support basic authentication. */
  1072. if (proxy_uri.password.len) {
  1073. /* Has no empty password set */
  1074. struct aws_http_proxy_strategy_basic_auth_options config = {
  1075. .proxy_connection_type = proxy_options.connection_type,
  1076. .user_name = proxy_uri.user,
  1077. .password = proxy_uri.password,
  1078. };
  1079. proxy_options.proxy_strategy = aws_http_proxy_strategy_new_basic_auth(options->allocator, &config);
  1080. }
  1081. } else {
  1082. success = true;
  1083. goto done;
  1084. }
  1085. struct aws_http_client_connection_options copied_options = *options;
  1086. copied_options.proxy_options = &proxy_options;
  1087. if (s_connect_proxy(&copied_options)) {
  1088. goto done;
  1089. }
  1090. success = true;
  1091. done:
  1092. aws_tls_connection_options_clean_up(&default_tls_connection_options);
  1093. aws_http_proxy_strategy_release(proxy_options.proxy_strategy);
  1094. aws_uri_clean_up(&proxy_uri);
  1095. if (success && !found) {
  1096. /* Successfully, but no envrionment variable found. Connect without proxy */
  1097. return aws_http_client_connect_internal(options, NULL);
  1098. }
  1099. return success ? AWS_OP_SUCCESS : AWS_OP_ERR;
  1100. }
  1101. /*
  1102. * Dispatches a proxy-enabled connection request to the appropriate top-level connection function
  1103. */
  1104. int aws_http_client_connect_via_proxy(const struct aws_http_client_connection_options *options) {
  1105. if (options->proxy_options == NULL && options->proxy_ev_settings &&
  1106. options->proxy_ev_settings->env_var_type == AWS_HPEV_ENABLE) {
  1107. return s_connect_proxy_via_env_variable(options);
  1108. }
  1109. return s_connect_proxy(options);
  1110. }
  1111. static struct aws_http_proxy_config *s_aws_http_proxy_config_new(
  1112. struct aws_allocator *allocator,
  1113. const struct aws_http_proxy_options *proxy_options,
  1114. enum aws_http_proxy_connection_type override_proxy_connection_type) {
  1115. AWS_FATAL_ASSERT(proxy_options != NULL);
  1116. struct aws_http_proxy_config *config = aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_config));
  1117. if (config == NULL) {
  1118. return NULL;
  1119. }
  1120. config->allocator = allocator;
  1121. config->connection_type = override_proxy_connection_type;
  1122. if (aws_byte_buf_init_copy_from_cursor(&config->host, allocator, proxy_options->host)) {
  1123. goto on_error;
  1124. }
  1125. if (proxy_options->tls_options) {
  1126. config->tls_options = aws_mem_calloc(allocator, 1, sizeof(struct aws_tls_connection_options));
  1127. if (aws_tls_connection_options_copy(config->tls_options, proxy_options->tls_options)) {
  1128. goto on_error;
  1129. }
  1130. }
  1131. config->port = proxy_options->port;
  1132. if (proxy_options->proxy_strategy != NULL) {
  1133. config->proxy_strategy = aws_http_proxy_strategy_acquire(proxy_options->proxy_strategy);
  1134. } else if (proxy_options->auth_type == AWS_HPAT_BASIC) {
  1135. struct aws_http_proxy_strategy_basic_auth_options basic_config;
  1136. AWS_ZERO_STRUCT(basic_config);
  1137. basic_config.proxy_connection_type = override_proxy_connection_type;
  1138. basic_config.user_name = proxy_options->auth_username;
  1139. basic_config.password = proxy_options->auth_password;
  1140. config->proxy_strategy = aws_http_proxy_strategy_new_basic_auth(allocator, &basic_config);
  1141. }
  1142. if (config->proxy_strategy == NULL) {
  1143. switch (override_proxy_connection_type) {
  1144. case AWS_HPCT_HTTP_FORWARD:
  1145. config->proxy_strategy = aws_http_proxy_strategy_new_forwarding_identity(allocator);
  1146. break;
  1147. case AWS_HPCT_HTTP_TUNNEL:
  1148. config->proxy_strategy = aws_http_proxy_strategy_new_tunneling_one_time_identity(allocator);
  1149. break;
  1150. default:
  1151. break;
  1152. }
  1153. if (config->proxy_strategy == NULL) {
  1154. goto on_error;
  1155. }
  1156. }
  1157. return config;
  1158. on_error:
  1159. aws_http_proxy_config_destroy(config);
  1160. return NULL;
  1161. }
  1162. struct aws_http_proxy_config *aws_http_proxy_config_new_from_connection_options(
  1163. struct aws_allocator *allocator,
  1164. const struct aws_http_client_connection_options *options) {
  1165. AWS_FATAL_ASSERT(options != NULL);
  1166. AWS_FATAL_ASSERT(options->proxy_options != NULL);
  1167. return s_aws_http_proxy_config_new(
  1168. allocator,
  1169. options->proxy_options,
  1170. s_determine_proxy_connection_type(options->proxy_options->connection_type, options->tls_options != NULL));
  1171. }
  1172. struct aws_http_proxy_config *aws_http_proxy_config_new_from_manager_options(
  1173. struct aws_allocator *allocator,
  1174. const struct aws_http_connection_manager_options *options) {
  1175. AWS_FATAL_ASSERT(options != NULL);
  1176. AWS_FATAL_ASSERT(options->proxy_options != NULL);
  1177. return s_aws_http_proxy_config_new(
  1178. allocator,
  1179. options->proxy_options,
  1180. s_determine_proxy_connection_type(
  1181. options->proxy_options->connection_type, options->tls_connection_options != NULL));
  1182. }
  1183. struct aws_http_proxy_config *aws_http_proxy_config_new_tunneling_from_proxy_options(
  1184. struct aws_allocator *allocator,
  1185. const struct aws_http_proxy_options *proxy_options) {
  1186. return s_aws_http_proxy_config_new(allocator, proxy_options, AWS_HPCT_HTTP_TUNNEL);
  1187. }
  1188. struct aws_http_proxy_config *aws_http_proxy_config_new_from_proxy_options(
  1189. struct aws_allocator *allocator,
  1190. const struct aws_http_proxy_options *proxy_options) {
  1191. if (proxy_options->connection_type == AWS_HPCT_HTTP_LEGACY) {
  1192. AWS_LOGF_ERROR(AWS_LS_HTTP_PROXY_NEGOTIATION, "LEGACY type is not supported to create proxy config");
  1193. return NULL;
  1194. }
  1195. return s_aws_http_proxy_config_new(allocator, proxy_options, proxy_options->connection_type);
  1196. }
  1197. struct aws_http_proxy_config *aws_http_proxy_config_new_from_proxy_options_with_tls_info(
  1198. struct aws_allocator *allocator,
  1199. const struct aws_http_proxy_options *proxy_options,
  1200. bool is_tls_connection) {
  1201. AWS_FATAL_ASSERT(proxy_options != NULL);
  1202. return s_aws_http_proxy_config_new(
  1203. allocator, proxy_options, s_determine_proxy_connection_type(proxy_options->connection_type, is_tls_connection));
  1204. }
  1205. struct aws_http_proxy_config *aws_http_proxy_config_new_clone(
  1206. struct aws_allocator *allocator,
  1207. const struct aws_http_proxy_config *proxy_config) {
  1208. AWS_FATAL_ASSERT(proxy_config != NULL);
  1209. struct aws_http_proxy_config *config = aws_mem_calloc(allocator, 1, sizeof(struct aws_http_proxy_config));
  1210. if (config == NULL) {
  1211. return NULL;
  1212. }
  1213. config->connection_type = proxy_config->connection_type;
  1214. if (aws_byte_buf_init_copy_from_cursor(&config->host, allocator, aws_byte_cursor_from_buf(&proxy_config->host))) {
  1215. goto on_error;
  1216. }
  1217. if (proxy_config->tls_options) {
  1218. config->tls_options = aws_mem_calloc(allocator, 1, sizeof(struct aws_tls_connection_options));
  1219. if (aws_tls_connection_options_copy(config->tls_options, proxy_config->tls_options)) {
  1220. goto on_error;
  1221. }
  1222. }
  1223. config->allocator = allocator;
  1224. config->port = proxy_config->port;
  1225. config->proxy_strategy = aws_http_proxy_strategy_acquire(proxy_config->proxy_strategy);
  1226. return config;
  1227. on_error:
  1228. aws_http_proxy_config_destroy(config);
  1229. return NULL;
  1230. }
  1231. void aws_http_proxy_config_destroy(struct aws_http_proxy_config *config) {
  1232. if (config == NULL) {
  1233. return;
  1234. }
  1235. aws_byte_buf_clean_up(&config->host);
  1236. if (config->tls_options) {
  1237. aws_tls_connection_options_clean_up(config->tls_options);
  1238. aws_mem_release(config->allocator, config->tls_options);
  1239. }
  1240. aws_http_proxy_strategy_release(config->proxy_strategy);
  1241. aws_mem_release(config->allocator, config);
  1242. }
  1243. void aws_http_proxy_options_init_from_config(
  1244. struct aws_http_proxy_options *options,
  1245. const struct aws_http_proxy_config *config) {
  1246. AWS_FATAL_ASSERT(options && config);
  1247. options->connection_type = config->connection_type;
  1248. options->host = aws_byte_cursor_from_buf(&config->host);
  1249. options->port = config->port;
  1250. options->tls_options = config->tls_options;
  1251. options->proxy_strategy = config->proxy_strategy;
  1252. }
  1253. int aws_http_options_validate_proxy_configuration(const struct aws_http_client_connection_options *options) {
  1254. if (options == NULL || options->proxy_options == NULL) {
  1255. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  1256. }
  1257. enum aws_http_proxy_connection_type proxy_type = options->proxy_options->connection_type;
  1258. if (proxy_type == AWS_HPCT_HTTP_FORWARD && options->tls_options != NULL) {
  1259. return aws_raise_error(AWS_ERROR_INVALID_STATE);
  1260. }
  1261. struct aws_http_proxy_strategy *proxy_strategy = options->proxy_options->proxy_strategy;
  1262. if (proxy_strategy != NULL) {
  1263. if (proxy_strategy->proxy_connection_type != proxy_type) {
  1264. return aws_raise_error(AWS_ERROR_INVALID_STATE);
  1265. }
  1266. }
  1267. return AWS_OP_SUCCESS;
  1268. }
  1269. struct aws_proxied_socket_channel_user_data {
  1270. struct aws_allocator *allocator;
  1271. struct aws_client_bootstrap *bootstrap;
  1272. struct aws_channel *channel;
  1273. aws_client_bootstrap_on_channel_event_fn *original_setup_callback;
  1274. aws_client_bootstrap_on_channel_event_fn *original_shutdown_callback;
  1275. void *original_user_data;
  1276. };
  1277. static void s_proxied_socket_channel_user_data_destroy(struct aws_proxied_socket_channel_user_data *user_data) {
  1278. if (user_data == NULL) {
  1279. return;
  1280. }
  1281. aws_client_bootstrap_release(user_data->bootstrap);
  1282. aws_mem_release(user_data->allocator, user_data);
  1283. }
  1284. static struct aws_proxied_socket_channel_user_data *s_proxied_socket_channel_user_data_new(
  1285. struct aws_allocator *allocator,
  1286. struct aws_socket_channel_bootstrap_options *channel_options) {
  1287. struct aws_proxied_socket_channel_user_data *user_data =
  1288. aws_mem_calloc(allocator, 1, sizeof(struct aws_proxied_socket_channel_user_data));
  1289. if (user_data == NULL) {
  1290. return NULL;
  1291. }
  1292. user_data->allocator = allocator;
  1293. user_data->original_setup_callback = channel_options->setup_callback;
  1294. user_data->original_shutdown_callback = channel_options->shutdown_callback;
  1295. user_data->original_user_data = channel_options->user_data;
  1296. user_data->bootstrap = aws_client_bootstrap_acquire(channel_options->bootstrap);
  1297. return user_data;
  1298. }
  1299. static void s_http_proxied_socket_channel_setup(
  1300. struct aws_client_bootstrap *bootstrap,
  1301. int error_code,
  1302. struct aws_channel *channel,
  1303. void *user_data) {
  1304. (void)bootstrap;
  1305. struct aws_proxied_socket_channel_user_data *proxied_user_data = user_data;
  1306. if (error_code != AWS_ERROR_SUCCESS || channel == NULL) {
  1307. proxied_user_data->original_setup_callback(
  1308. proxied_user_data->bootstrap, error_code, NULL, proxied_user_data->original_user_data);
  1309. s_proxied_socket_channel_user_data_destroy(proxied_user_data);
  1310. return;
  1311. }
  1312. proxied_user_data->channel = channel;
  1313. proxied_user_data->original_setup_callback(
  1314. proxied_user_data->bootstrap,
  1315. AWS_ERROR_SUCCESS,
  1316. proxied_user_data->channel,
  1317. proxied_user_data->original_user_data);
  1318. }
  1319. static void s_http_proxied_socket_channel_shutdown(
  1320. struct aws_client_bootstrap *bootstrap,
  1321. int error_code,
  1322. struct aws_channel *channel,
  1323. void *user_data) {
  1324. (void)bootstrap;
  1325. (void)channel;
  1326. struct aws_proxied_socket_channel_user_data *proxied_user_data = user_data;
  1327. proxied_user_data->original_shutdown_callback(
  1328. proxied_user_data->bootstrap, error_code, proxied_user_data->channel, proxied_user_data->original_user_data);
  1329. s_proxied_socket_channel_user_data_destroy(proxied_user_data);
  1330. }
  1331. int aws_http_proxy_new_socket_channel(
  1332. struct aws_socket_channel_bootstrap_options *channel_options,
  1333. const struct aws_http_proxy_options *proxy_options) {
  1334. AWS_FATAL_ASSERT(channel_options != NULL && channel_options->bootstrap != NULL);
  1335. AWS_FATAL_ASSERT(proxy_options != NULL);
  1336. if (proxy_options->connection_type != AWS_HPCT_HTTP_TUNNEL) {
  1337. AWS_LOGF_ERROR(
  1338. AWS_LS_HTTP_PROXY_NEGOTIATION,
  1339. "Creating a raw protocol channel through an http proxy requires a tunneling proxy "
  1340. "configuration");
  1341. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  1342. }
  1343. if (channel_options->tls_options == NULL) {
  1344. AWS_LOGF_ERROR(
  1345. AWS_LS_HTTP_PROXY_NEGOTIATION,
  1346. "Creating a raw protocol channel through an http proxy requires tls to the endpoint");
  1347. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  1348. }
  1349. struct aws_allocator *allocator = channel_options->bootstrap->allocator;
  1350. struct aws_proxied_socket_channel_user_data *user_data =
  1351. s_proxied_socket_channel_user_data_new(allocator, channel_options);
  1352. struct aws_http_client_connection_options http_connection_options = AWS_HTTP_CLIENT_CONNECTION_OPTIONS_INIT;
  1353. http_connection_options.allocator = allocator;
  1354. http_connection_options.bootstrap = channel_options->bootstrap;
  1355. http_connection_options.host_name = aws_byte_cursor_from_c_str(channel_options->host_name);
  1356. http_connection_options.port = channel_options->port;
  1357. http_connection_options.socket_options = channel_options->socket_options;
  1358. http_connection_options.tls_options = channel_options->tls_options;
  1359. http_connection_options.proxy_options = proxy_options;
  1360. http_connection_options.user_data = user_data;
  1361. http_connection_options.on_setup = NULL; /* use channel callbacks, not http callbacks */
  1362. http_connection_options.on_shutdown = NULL; /* use channel callbacks, not http callbacks */
  1363. http_connection_options.requested_event_loop = channel_options->requested_event_loop;
  1364. if (s_aws_http_client_connect_via_tunneling_proxy(
  1365. &http_connection_options, s_http_proxied_socket_channel_setup, s_http_proxied_socket_channel_shutdown)) {
  1366. goto on_error;
  1367. }
  1368. return AWS_OP_SUCCESS;
  1369. on_error:
  1370. s_proxied_socket_channel_user_data_destroy(user_data);
  1371. return AWS_OP_ERR;
  1372. }