h1_encoder.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  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/h1_encoder.h>
  6. #include <aws/http/private/strutil.h>
  7. #include <aws/http/status_code.h>
  8. #include <aws/io/logging.h>
  9. #include <aws/io/stream.h>
  10. #include <inttypes.h>
  11. #define ENCODER_LOGF(level, encoder, text, ...) \
  12. AWS_LOGF_##level(AWS_LS_HTTP_STREAM, "id=%p: " text, (void *)encoder->current_stream, __VA_ARGS__)
  13. #define ENCODER_LOG(level, encoder, text) ENCODER_LOGF(level, encoder, "%s", text)
  14. #define MAX_ASCII_HEX_CHUNK_STR_SIZE (sizeof(uint64_t) * 2 + 1)
  15. #define CRLF_SIZE 2
  16. /**
  17. * Scan headers to detect errors and determine anything we'll need to know later (ex: total length).
  18. */
  19. static int s_scan_outgoing_headers(
  20. struct aws_h1_encoder_message *encoder_message,
  21. const struct aws_http_message *message,
  22. size_t *out_header_lines_len,
  23. bool body_headers_ignored,
  24. bool body_headers_forbidden) {
  25. size_t total = 0;
  26. bool has_body_stream = aws_http_message_get_body_stream(message);
  27. bool has_content_length_header = false;
  28. bool has_transfer_encoding_header = false;
  29. const size_t num_headers = aws_http_message_get_header_count(message);
  30. for (size_t i = 0; i < num_headers; ++i) {
  31. struct aws_http_header header;
  32. aws_http_message_get_header(message, &header, i);
  33. /* Validate header field-name (RFC-7230 3.2): field-name = token */
  34. if (!aws_strutil_is_http_token(header.name)) {
  35. AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=static: Header name is invalid");
  36. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_NAME);
  37. }
  38. /* Validate header field-value.
  39. * The value itself isn't supposed to have whitespace on either side,
  40. * but we'll trim it off before validation so we don't start needlessly
  41. * failing requests that used to work before we added validation.
  42. * This should be OK because field-value can be sent with any amount
  43. * of whitespace around it, which the other side will just ignore (RFC-7230 3.2):
  44. * header-field = field-name ":" OWS field-value OWS */
  45. struct aws_byte_cursor field_value = aws_strutil_trim_http_whitespace(header.value);
  46. if (!aws_strutil_is_http_field_value(field_value)) {
  47. AWS_LOGF_ERROR(
  48. AWS_LS_HTTP_STREAM,
  49. "id=static: Header '" PRInSTR "' has invalid value",
  50. AWS_BYTE_CURSOR_PRI(header.name));
  51. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_VALUE);
  52. }
  53. enum aws_http_header_name name_enum = aws_http_str_to_header_name(header.name);
  54. switch (name_enum) {
  55. case AWS_HTTP_HEADER_CONNECTION: {
  56. if (aws_byte_cursor_eq_c_str(&field_value, "close")) {
  57. encoder_message->has_connection_close_header = true;
  58. }
  59. } break;
  60. case AWS_HTTP_HEADER_CONTENT_LENGTH: {
  61. has_content_length_header = true;
  62. if (aws_byte_cursor_utf8_parse_u64(field_value, &encoder_message->content_length)) {
  63. AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=static: Invalid Content-Length");
  64. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_VALUE);
  65. }
  66. } break;
  67. case AWS_HTTP_HEADER_TRANSFER_ENCODING: {
  68. has_transfer_encoding_header = true;
  69. if (0 == field_value.len) {
  70. AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=static: Transfer-Encoding must include a valid value");
  71. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_VALUE);
  72. }
  73. struct aws_byte_cursor substr;
  74. AWS_ZERO_STRUCT(substr);
  75. while (aws_byte_cursor_next_split(&field_value, ',', &substr)) {
  76. struct aws_byte_cursor trimmed = aws_strutil_trim_http_whitespace(substr);
  77. if (0 == trimmed.len) {
  78. AWS_LOGF_ERROR(
  79. AWS_LS_HTTP_STREAM,
  80. "id=static: Transfer-Encoding header whitespace only "
  81. "comma delimited header value");
  82. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_VALUE);
  83. }
  84. if (encoder_message->has_chunked_encoding_header) {
  85. AWS_LOGF_ERROR(
  86. AWS_LS_HTTP_STREAM, "id=static: Transfer-Encoding header must end with \"chunked\"");
  87. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_VALUE);
  88. }
  89. if (aws_byte_cursor_eq_c_str(&trimmed, "chunked")) {
  90. encoder_message->has_chunked_encoding_header = true;
  91. }
  92. }
  93. } break;
  94. default:
  95. break;
  96. }
  97. /* header-line: "{name}: {value}\r\n" */
  98. int err = 0;
  99. err |= aws_add_size_checked(header.name.len, total, &total);
  100. err |= aws_add_size_checked(header.value.len, total, &total);
  101. err |= aws_add_size_checked(4, total, &total); /* ": " + "\r\n" */
  102. if (err) {
  103. return AWS_OP_ERR;
  104. }
  105. }
  106. if (!encoder_message->has_chunked_encoding_header && has_transfer_encoding_header) {
  107. AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=static: Transfer-Encoding header must include \"chunked\"");
  108. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_VALUE);
  109. }
  110. /* Per RFC 7230: A sender MUST NOT send a Content-Length header field in any message that contains a
  111. * Transfer-Encoding header field. */
  112. if (encoder_message->has_chunked_encoding_header && has_content_length_header) {
  113. AWS_LOGF_ERROR(
  114. AWS_LS_HTTP_STREAM, "id=static: Both Content-Length and Transfer-Encoding are set. Only one may be used");
  115. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_VALUE);
  116. }
  117. if (encoder_message->has_chunked_encoding_header && has_body_stream) {
  118. AWS_LOGF_ERROR(
  119. AWS_LS_HTTP_STREAM,
  120. "id=static: Both Transfer-Encoding chunked header and body stream is set. "
  121. "chunked data must use the chunk API to write the body stream.");
  122. return aws_raise_error(AWS_ERROR_HTTP_INVALID_BODY_STREAM);
  123. }
  124. if (body_headers_forbidden && (encoder_message->content_length > 0 || has_transfer_encoding_header)) {
  125. AWS_LOGF_ERROR(
  126. AWS_LS_HTTP_STREAM,
  127. "id=static: Transfer-Encoding or Content-Length headers may not be present in such a message");
  128. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_FIELD);
  129. }
  130. if (body_headers_ignored) {
  131. /* Don't send body, no matter what the headers are */
  132. encoder_message->content_length = 0;
  133. encoder_message->has_chunked_encoding_header = false;
  134. }
  135. if (encoder_message->content_length > 0 && !has_body_stream) {
  136. return aws_raise_error(AWS_ERROR_HTTP_MISSING_BODY_STREAM);
  137. }
  138. *out_header_lines_len = total;
  139. return AWS_OP_SUCCESS;
  140. }
  141. static int s_scan_outgoing_trailer(const struct aws_http_headers *headers, size_t *out_size) {
  142. const size_t num_headers = aws_http_headers_count(headers);
  143. size_t total = 0;
  144. for (size_t i = 0; i < num_headers; i++) {
  145. struct aws_http_header header;
  146. aws_http_headers_get_index(headers, i, &header);
  147. /* Validate header field-name (RFC-7230 3.2): field-name = token */
  148. if (!aws_strutil_is_http_token(header.name)) {
  149. AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=static: Header name is invalid");
  150. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_NAME);
  151. }
  152. /* Validate header field-value.
  153. * The value itself isn't supposed to have whitespace on either side,
  154. * but we'll trim it off before validation so we don't start needlessly
  155. * failing requests that used to work before we added validation.
  156. * This should be OK because field-value can be sent with any amount
  157. * of whitespace around it, which the other side will just ignore (RFC-7230 3.2):
  158. * header-field = field-name ":" OWS field-value OWS */
  159. struct aws_byte_cursor field_value = aws_strutil_trim_http_whitespace(header.value);
  160. if (!aws_strutil_is_http_field_value(field_value)) {
  161. AWS_LOGF_ERROR(
  162. AWS_LS_HTTP_STREAM,
  163. "id=static: Header '" PRInSTR "' has invalid value",
  164. AWS_BYTE_CURSOR_PRI(header.name));
  165. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_VALUE);
  166. }
  167. enum aws_http_header_name name_enum = aws_http_str_to_header_name(header.name);
  168. if (name_enum == AWS_HTTP_HEADER_TRANSFER_ENCODING || name_enum == AWS_HTTP_HEADER_CONTENT_LENGTH ||
  169. name_enum == AWS_HTTP_HEADER_HOST || name_enum == AWS_HTTP_HEADER_EXPECT ||
  170. name_enum == AWS_HTTP_HEADER_CACHE_CONTROL || name_enum == AWS_HTTP_HEADER_MAX_FORWARDS ||
  171. name_enum == AWS_HTTP_HEADER_PRAGMA || name_enum == AWS_HTTP_HEADER_RANGE ||
  172. name_enum == AWS_HTTP_HEADER_TE || name_enum == AWS_HTTP_HEADER_CONTENT_ENCODING ||
  173. name_enum == AWS_HTTP_HEADER_CONTENT_TYPE || name_enum == AWS_HTTP_HEADER_CONTENT_RANGE ||
  174. name_enum == AWS_HTTP_HEADER_TRAILER || name_enum == AWS_HTTP_HEADER_WWW_AUTHENTICATE ||
  175. name_enum == AWS_HTTP_HEADER_AUTHORIZATION || name_enum == AWS_HTTP_HEADER_PROXY_AUTHENTICATE ||
  176. name_enum == AWS_HTTP_HEADER_PROXY_AUTHORIZATION || name_enum == AWS_HTTP_HEADER_SET_COOKIE ||
  177. name_enum == AWS_HTTP_HEADER_COOKIE || name_enum == AWS_HTTP_HEADER_AGE ||
  178. name_enum == AWS_HTTP_HEADER_EXPIRES || name_enum == AWS_HTTP_HEADER_DATE ||
  179. name_enum == AWS_HTTP_HEADER_LOCATION || name_enum == AWS_HTTP_HEADER_RETRY_AFTER ||
  180. name_enum == AWS_HTTP_HEADER_VARY || name_enum == AWS_HTTP_HEADER_WARNING) {
  181. AWS_LOGF_ERROR(
  182. AWS_LS_HTTP_STREAM,
  183. "id=static: Trailing Header '" PRInSTR "' has invalid value",
  184. AWS_BYTE_CURSOR_PRI(header.name));
  185. return aws_raise_error(AWS_ERROR_HTTP_INVALID_HEADER_FIELD);
  186. }
  187. int err = 0;
  188. err |= aws_add_size_checked(header.name.len, total, &total);
  189. err |= aws_add_size_checked(header.value.len, total, &total);
  190. err |= aws_add_size_checked(4, total, &total); /* ": " + "\r\n" */
  191. if (err) {
  192. return AWS_OP_ERR;
  193. }
  194. }
  195. if (aws_add_size_checked(2, total, &total)) { /* "\r\n" */
  196. return AWS_OP_ERR;
  197. }
  198. *out_size = total;
  199. return AWS_OP_SUCCESS;
  200. }
  201. static bool s_write_crlf(struct aws_byte_buf *dst) {
  202. AWS_PRECONDITION(aws_byte_buf_is_valid(dst));
  203. struct aws_byte_cursor crlf_cursor = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("\r\n");
  204. return aws_byte_buf_write_from_whole_cursor(dst, crlf_cursor);
  205. }
  206. static void s_write_headers(struct aws_byte_buf *dst, const struct aws_http_headers *headers) {
  207. const size_t num_headers = aws_http_headers_count(headers);
  208. bool wrote_all = true;
  209. for (size_t i = 0; i < num_headers; ++i) {
  210. struct aws_http_header header;
  211. aws_http_headers_get_index(headers, i, &header);
  212. /* header-line: "{name}: {value}\r\n" */
  213. wrote_all &= aws_byte_buf_write_from_whole_cursor(dst, header.name);
  214. wrote_all &= aws_byte_buf_write_u8(dst, ':');
  215. wrote_all &= aws_byte_buf_write_u8(dst, ' ');
  216. wrote_all &= aws_byte_buf_write_from_whole_cursor(dst, header.value);
  217. wrote_all &= s_write_crlf(dst);
  218. }
  219. AWS_ASSERT(wrote_all);
  220. (void)wrote_all;
  221. }
  222. int aws_h1_encoder_message_init_from_request(
  223. struct aws_h1_encoder_message *message,
  224. struct aws_allocator *allocator,
  225. const struct aws_http_message *request,
  226. struct aws_linked_list *pending_chunk_list) {
  227. AWS_PRECONDITION(aws_linked_list_is_valid(pending_chunk_list));
  228. AWS_ZERO_STRUCT(*message);
  229. message->body = aws_input_stream_acquire(aws_http_message_get_body_stream(request));
  230. message->pending_chunk_list = pending_chunk_list;
  231. struct aws_byte_cursor method;
  232. int err = aws_http_message_get_request_method(request, &method);
  233. if (err) {
  234. AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=static: Request method not set");
  235. aws_raise_error(AWS_ERROR_HTTP_INVALID_METHOD);
  236. goto error;
  237. }
  238. /* RFC-7230 3.1.1: method = token */
  239. if (!aws_strutil_is_http_token(method)) {
  240. AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=static: Request method is invalid");
  241. aws_raise_error(AWS_ERROR_HTTP_INVALID_METHOD);
  242. goto error;
  243. }
  244. struct aws_byte_cursor uri;
  245. err = aws_http_message_get_request_path(request, &uri);
  246. if (err) {
  247. AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=static: Request path not set");
  248. aws_raise_error(AWS_ERROR_HTTP_INVALID_PATH);
  249. goto error;
  250. }
  251. if (!aws_strutil_is_http_request_target(uri)) {
  252. AWS_LOGF_ERROR(AWS_LS_HTTP_STREAM, "id=static: Request path is invalid");
  253. aws_raise_error(AWS_ERROR_HTTP_INVALID_PATH);
  254. goto error;
  255. }
  256. struct aws_byte_cursor version = aws_http_version_to_str(AWS_HTTP_VERSION_1_1);
  257. /**
  258. * Calculate total size needed for outgoing_head_buffer, then write to buffer.
  259. */
  260. size_t header_lines_len;
  261. err = s_scan_outgoing_headers(
  262. message, request, &header_lines_len, false /*body_headers_ignored*/, false /*body_headers_forbidden*/);
  263. if (err) {
  264. goto error;
  265. }
  266. /* request-line: "{method} {uri} {version}\r\n" */
  267. size_t request_line_len = 4; /* 2 spaces + "\r\n" */
  268. err |= aws_add_size_checked(method.len, request_line_len, &request_line_len);
  269. err |= aws_add_size_checked(uri.len, request_line_len, &request_line_len);
  270. err |= aws_add_size_checked(version.len, request_line_len, &request_line_len);
  271. /* head-end: "\r\n" */
  272. size_t head_end_len = 2;
  273. size_t head_total_len = request_line_len;
  274. err |= aws_add_size_checked(header_lines_len, head_total_len, &head_total_len);
  275. err |= aws_add_size_checked(head_end_len, head_total_len, &head_total_len);
  276. if (err) {
  277. goto error;
  278. }
  279. err = aws_byte_buf_init(&message->outgoing_head_buf, allocator, head_total_len);
  280. if (err) {
  281. goto error;
  282. }
  283. bool wrote_all = true;
  284. wrote_all &= aws_byte_buf_write_from_whole_cursor(&message->outgoing_head_buf, method);
  285. wrote_all &= aws_byte_buf_write_u8(&message->outgoing_head_buf, ' ');
  286. wrote_all &= aws_byte_buf_write_from_whole_cursor(&message->outgoing_head_buf, uri);
  287. wrote_all &= aws_byte_buf_write_u8(&message->outgoing_head_buf, ' ');
  288. wrote_all &= aws_byte_buf_write_from_whole_cursor(&message->outgoing_head_buf, version);
  289. wrote_all &= s_write_crlf(&message->outgoing_head_buf);
  290. s_write_headers(&message->outgoing_head_buf, aws_http_message_get_const_headers(request));
  291. wrote_all &= s_write_crlf(&message->outgoing_head_buf);
  292. (void)wrote_all;
  293. AWS_ASSERT(wrote_all);
  294. return AWS_OP_SUCCESS;
  295. error:
  296. aws_h1_encoder_message_clean_up(message);
  297. return AWS_OP_ERR;
  298. }
  299. int aws_h1_encoder_message_init_from_response(
  300. struct aws_h1_encoder_message *message,
  301. struct aws_allocator *allocator,
  302. const struct aws_http_message *response,
  303. bool body_headers_ignored,
  304. struct aws_linked_list *pending_chunk_list) {
  305. AWS_PRECONDITION(aws_linked_list_is_valid(pending_chunk_list));
  306. AWS_ZERO_STRUCT(*message);
  307. message->body = aws_input_stream_acquire(aws_http_message_get_body_stream(response));
  308. message->pending_chunk_list = pending_chunk_list;
  309. struct aws_byte_cursor version = aws_http_version_to_str(AWS_HTTP_VERSION_1_1);
  310. int status_int;
  311. int err = aws_http_message_get_response_status(response, &status_int);
  312. if (err) {
  313. return aws_raise_error(AWS_ERROR_HTTP_INVALID_STATUS_CODE);
  314. }
  315. /* Status code must fit in 3 digits */
  316. AWS_ASSERT(status_int >= 0 && status_int <= 999); /* aws_http_message should have already checked this */
  317. char status_code_str[4] = "XXX";
  318. snprintf(status_code_str, sizeof(status_code_str), "%03d", status_int);
  319. struct aws_byte_cursor status_code = aws_byte_cursor_from_c_str(status_code_str);
  320. struct aws_byte_cursor status_text = aws_byte_cursor_from_c_str(aws_http_status_text(status_int));
  321. /**
  322. * Calculate total size needed for outgoing_head_buffer, then write to buffer.
  323. */
  324. size_t header_lines_len;
  325. /**
  326. * no body needed in the response
  327. * RFC-7230 section 3.3 Message Body
  328. */
  329. body_headers_ignored |= status_int == AWS_HTTP_STATUS_CODE_304_NOT_MODIFIED;
  330. bool body_headers_forbidden = status_int == AWS_HTTP_STATUS_CODE_204_NO_CONTENT || status_int / 100 == 1;
  331. err = s_scan_outgoing_headers(message, response, &header_lines_len, body_headers_ignored, body_headers_forbidden);
  332. if (err) {
  333. goto error;
  334. }
  335. /* valid status must be three digital code, change it into byte_cursor */
  336. /* response-line: "{version} {status} {status_text}\r\n" */
  337. size_t response_line_len = 4; /* 2 spaces + "\r\n" */
  338. err |= aws_add_size_checked(version.len, response_line_len, &response_line_len);
  339. err |= aws_add_size_checked(status_code.len, response_line_len, &response_line_len);
  340. err |= aws_add_size_checked(status_text.len, response_line_len, &response_line_len);
  341. /* head-end: "\r\n" */
  342. size_t head_end_len = 2;
  343. size_t head_total_len = response_line_len;
  344. err |= aws_add_size_checked(header_lines_len, head_total_len, &head_total_len);
  345. err |= aws_add_size_checked(head_end_len, head_total_len, &head_total_len);
  346. if (err) {
  347. goto error;
  348. }
  349. err = aws_byte_buf_init(&message->outgoing_head_buf, allocator, head_total_len);
  350. if (err) {
  351. return AWS_OP_ERR;
  352. }
  353. bool wrote_all = true;
  354. wrote_all &= aws_byte_buf_write_from_whole_cursor(&message->outgoing_head_buf, version);
  355. wrote_all &= aws_byte_buf_write_u8(&message->outgoing_head_buf, ' ');
  356. wrote_all &= aws_byte_buf_write_from_whole_cursor(&message->outgoing_head_buf, status_code);
  357. wrote_all &= aws_byte_buf_write_u8(&message->outgoing_head_buf, ' ');
  358. wrote_all &= aws_byte_buf_write_from_whole_cursor(&message->outgoing_head_buf, status_text);
  359. wrote_all &= s_write_crlf(&message->outgoing_head_buf);
  360. s_write_headers(&message->outgoing_head_buf, aws_http_message_get_const_headers(response));
  361. wrote_all &= s_write_crlf(&message->outgoing_head_buf);
  362. (void)wrote_all;
  363. AWS_ASSERT(wrote_all);
  364. /* Success! */
  365. return AWS_OP_SUCCESS;
  366. error:
  367. aws_h1_encoder_message_clean_up(message);
  368. return AWS_OP_ERR;
  369. }
  370. void aws_h1_encoder_message_clean_up(struct aws_h1_encoder_message *message) {
  371. aws_input_stream_release(message->body);
  372. aws_byte_buf_clean_up(&message->outgoing_head_buf);
  373. aws_h1_trailer_destroy(message->trailer);
  374. AWS_ZERO_STRUCT(*message);
  375. }
  376. void aws_h1_encoder_init(struct aws_h1_encoder *encoder, struct aws_allocator *allocator) {
  377. AWS_ZERO_STRUCT(*encoder);
  378. encoder->allocator = allocator;
  379. }
  380. void aws_h1_encoder_clean_up(struct aws_h1_encoder *encoder) {
  381. AWS_ZERO_STRUCT(*encoder);
  382. }
  383. int aws_h1_encoder_start_message(
  384. struct aws_h1_encoder *encoder,
  385. struct aws_h1_encoder_message *message,
  386. struct aws_http_stream *stream) {
  387. AWS_PRECONDITION(encoder);
  388. AWS_PRECONDITION(message);
  389. if (encoder->message) {
  390. ENCODER_LOG(ERROR, encoder, "Attempting to start new request while previous request is in progress.");
  391. return aws_raise_error(AWS_ERROR_INVALID_STATE);
  392. }
  393. encoder->current_stream = stream;
  394. encoder->message = message;
  395. return AWS_OP_SUCCESS;
  396. }
  397. static bool s_write_chunk_size(struct aws_byte_buf *dst, uint64_t chunk_size) {
  398. AWS_PRECONDITION(dst);
  399. AWS_PRECONDITION(aws_byte_buf_is_valid(dst));
  400. char ascii_hex_chunk_size_str[MAX_ASCII_HEX_CHUNK_STR_SIZE] = {0};
  401. snprintf(ascii_hex_chunk_size_str, sizeof(ascii_hex_chunk_size_str), "%" PRIX64, chunk_size);
  402. return aws_byte_buf_write_from_whole_cursor(dst, aws_byte_cursor_from_c_str(ascii_hex_chunk_size_str));
  403. }
  404. static bool s_write_chunk_extension(struct aws_byte_buf *dst, struct aws_http1_chunk_extension *chunk_extension) {
  405. AWS_PRECONDITION(chunk_extension);
  406. AWS_PRECONDITION(aws_byte_buf_is_valid(dst));
  407. bool wrote_all = true;
  408. wrote_all &= aws_byte_buf_write_u8(dst, ';');
  409. wrote_all &= aws_byte_buf_write_from_whole_cursor(dst, chunk_extension->key);
  410. wrote_all &= aws_byte_buf_write_u8(dst, '=');
  411. wrote_all &= aws_byte_buf_write_from_whole_cursor(dst, chunk_extension->value);
  412. return wrote_all;
  413. }
  414. static size_t s_calculate_chunk_line_size(const struct aws_http1_chunk_options *options) {
  415. size_t chunk_line_size = MAX_ASCII_HEX_CHUNK_STR_SIZE + CRLF_SIZE;
  416. for (size_t i = 0; i < options->num_extensions; ++i) {
  417. struct aws_http1_chunk_extension *chunk_extension = options->extensions + i;
  418. chunk_line_size += sizeof(';');
  419. chunk_line_size += chunk_extension->key.len;
  420. chunk_line_size += sizeof('=');
  421. chunk_line_size += chunk_extension->value.len;
  422. }
  423. return chunk_line_size;
  424. }
  425. static void s_populate_chunk_line_buffer(
  426. struct aws_byte_buf *chunk_line,
  427. const struct aws_http1_chunk_options *options) {
  428. bool wrote_chunk_line = true;
  429. wrote_chunk_line &= s_write_chunk_size(chunk_line, options->chunk_data_size);
  430. for (size_t i = 0; i < options->num_extensions; ++i) {
  431. wrote_chunk_line &= s_write_chunk_extension(chunk_line, options->extensions + i);
  432. }
  433. wrote_chunk_line &= s_write_crlf(chunk_line);
  434. AWS_ASSERT(wrote_chunk_line);
  435. (void)wrote_chunk_line;
  436. }
  437. struct aws_h1_trailer *aws_h1_trailer_new(
  438. struct aws_allocator *allocator,
  439. const struct aws_http_headers *trailing_headers) {
  440. /* Allocate trailer along with storage for the trailer-line */
  441. size_t trailer_size = 0;
  442. if (s_scan_outgoing_trailer(trailing_headers, &trailer_size)) {
  443. return NULL;
  444. }
  445. struct aws_h1_trailer *trailer = aws_mem_calloc(allocator, 1, sizeof(struct aws_h1_trailer));
  446. trailer->allocator = allocator;
  447. aws_byte_buf_init(&trailer->trailer_data, allocator, trailer_size); /* cannot fail */
  448. s_write_headers(&trailer->trailer_data, trailing_headers);
  449. s_write_crlf(&trailer->trailer_data); /* \r\n */
  450. return trailer;
  451. }
  452. void aws_h1_trailer_destroy(struct aws_h1_trailer *trailer) {
  453. if (trailer == NULL) {
  454. return;
  455. }
  456. aws_byte_buf_clean_up(&trailer->trailer_data);
  457. aws_mem_release(trailer->allocator, trailer);
  458. }
  459. struct aws_h1_chunk *aws_h1_chunk_new(struct aws_allocator *allocator, const struct aws_http1_chunk_options *options) {
  460. /* Allocate chunk along with storage for the chunk-line */
  461. struct aws_h1_chunk *chunk;
  462. size_t chunk_line_size = s_calculate_chunk_line_size(options);
  463. void *chunk_line_storage;
  464. if (!aws_mem_acquire_many(
  465. allocator, 2, &chunk, sizeof(struct aws_h1_chunk), &chunk_line_storage, chunk_line_size)) {
  466. return NULL;
  467. }
  468. chunk->allocator = allocator;
  469. chunk->data = aws_input_stream_acquire(options->chunk_data);
  470. chunk->data_size = options->chunk_data_size;
  471. chunk->on_complete = options->on_complete;
  472. chunk->user_data = options->user_data;
  473. chunk->chunk_line = aws_byte_buf_from_empty_array(chunk_line_storage, chunk_line_size);
  474. s_populate_chunk_line_buffer(&chunk->chunk_line, options);
  475. return chunk;
  476. }
  477. void aws_h1_chunk_destroy(struct aws_h1_chunk *chunk) {
  478. AWS_PRECONDITION(chunk);
  479. aws_input_stream_release(chunk->data);
  480. aws_mem_release(chunk->allocator, chunk);
  481. }
  482. void aws_h1_chunk_complete_and_destroy(
  483. struct aws_h1_chunk *chunk,
  484. struct aws_http_stream *http_stream,
  485. int error_code) {
  486. AWS_PRECONDITION(chunk);
  487. aws_http1_stream_write_chunk_complete_fn *on_complete = chunk->on_complete;
  488. void *user_data = chunk->user_data;
  489. /* Clean up before firing callback */
  490. aws_h1_chunk_destroy(chunk);
  491. if (NULL != on_complete) {
  492. on_complete(http_stream, error_code, user_data);
  493. }
  494. }
  495. static void s_clean_up_current_chunk(struct aws_h1_encoder *encoder, int error_code) {
  496. AWS_PRECONDITION(encoder->current_chunk);
  497. AWS_PRECONDITION(&encoder->current_chunk->node == aws_linked_list_front(encoder->message->pending_chunk_list));
  498. aws_linked_list_remove(&encoder->current_chunk->node);
  499. aws_h1_chunk_complete_and_destroy(encoder->current_chunk, encoder->current_stream, error_code);
  500. encoder->current_chunk = NULL;
  501. }
  502. /* Write as much as possible from src_buf to dst, using encoder->progress_len to track progress.
  503. * Returns true if the entire src_buf has been copied */
  504. static bool s_encode_buf(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst, const struct aws_byte_buf *src) {
  505. /* advance src_cursor to current position in src_buf */
  506. struct aws_byte_cursor src_cursor = aws_byte_cursor_from_buf(src);
  507. aws_byte_cursor_advance(&src_cursor, (size_t)encoder->progress_bytes);
  508. /* write as much as possible to dst, src_cursor is advanced as write occurs */
  509. struct aws_byte_cursor written = aws_byte_buf_write_to_capacity(dst, &src_cursor);
  510. encoder->progress_bytes += written.len;
  511. return src_cursor.len == 0;
  512. }
  513. /* Write as much body stream as possible into dst buffer.
  514. * Increments encoder->progress_bytes to track progress */
  515. static int s_encode_stream(
  516. struct aws_h1_encoder *encoder,
  517. struct aws_byte_buf *dst,
  518. struct aws_input_stream *stream,
  519. uint64_t total_length,
  520. bool *out_done) {
  521. *out_done = false;
  522. if (dst->capacity == dst->len) {
  523. /* Return success because we want to try again later */
  524. return AWS_OP_SUCCESS;
  525. }
  526. /* Read from stream */
  527. ENCODER_LOG(TRACE, encoder, "Reading from body stream.");
  528. const size_t prev_len = dst->len;
  529. int err = aws_input_stream_read(stream, dst);
  530. const size_t amount_read = dst->len - prev_len;
  531. if (err) {
  532. ENCODER_LOGF(
  533. ERROR,
  534. encoder,
  535. "Failed to read body stream, error %d (%s)",
  536. aws_last_error(),
  537. aws_error_name(aws_last_error()));
  538. return AWS_OP_ERR;
  539. }
  540. /* Increment progress_bytes, and make sure we haven't written too much */
  541. int add_err = aws_add_u64_checked(encoder->progress_bytes, amount_read, &encoder->progress_bytes);
  542. if (add_err || encoder->progress_bytes > total_length) {
  543. ENCODER_LOGF(ERROR, encoder, "Body stream has exceeded expected length: %" PRIu64, total_length);
  544. return aws_raise_error(AWS_ERROR_HTTP_OUTGOING_STREAM_LENGTH_INCORRECT);
  545. }
  546. ENCODER_LOGF(
  547. TRACE,
  548. encoder,
  549. "Sending %zu bytes of body, progress: %" PRIu64 "/%" PRIu64,
  550. amount_read,
  551. encoder->progress_bytes,
  552. total_length);
  553. /* Return if we're done sending stream */
  554. if (encoder->progress_bytes == total_length) {
  555. *out_done = true;
  556. return AWS_OP_SUCCESS;
  557. }
  558. /* Return if stream failed to write anything. Maybe the data isn't ready yet. */
  559. if (amount_read == 0) {
  560. /* Ensure we're not at end-of-stream too early */
  561. struct aws_stream_status status;
  562. err = aws_input_stream_get_status(stream, &status);
  563. if (err) {
  564. ENCODER_LOGF(
  565. TRACE,
  566. encoder,
  567. "Failed to query body stream status, error %d (%s)",
  568. aws_last_error(),
  569. aws_error_name(aws_last_error()));
  570. return AWS_OP_ERR;
  571. }
  572. if (status.is_end_of_stream) {
  573. ENCODER_LOGF(
  574. ERROR,
  575. encoder,
  576. "Reached end of body stream but sent less than declared length %" PRIu64 "/%" PRIu64,
  577. encoder->progress_bytes,
  578. total_length);
  579. return aws_raise_error(AWS_ERROR_HTTP_OUTGOING_STREAM_LENGTH_INCORRECT);
  580. }
  581. }
  582. /* Not done streaming data out yet */
  583. return AWS_OP_SUCCESS;
  584. }
  585. /* A state function should:
  586. * - Raise an error only if unrecoverable error occurs.
  587. * - `return s_switch_state(...)` to switch states.
  588. * - `return AWS_OP_SUCCESS` if it can't progress any further (waiting for more
  589. * space to write into, waiting for more chunks, etc). */
  590. typedef int encoder_state_fn(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst);
  591. /* Switch state.
  592. * The only reason this returns a value is so it can be called with `return` to conclude a state function */
  593. static int s_switch_state(struct aws_h1_encoder *encoder, enum aws_h1_encoder_state state) {
  594. encoder->state = state;
  595. encoder->progress_bytes = 0;
  596. return AWS_OP_SUCCESS;
  597. }
  598. /* Initial state. Waits until a new message is set */
  599. static int s_state_fn_init(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst) {
  600. (void)dst;
  601. if (!encoder->message) {
  602. /* Remain in this state. */
  603. return AWS_OP_SUCCESS;
  604. }
  605. /* Start encoding message */
  606. ENCODER_LOG(TRACE, encoder, "Starting to send data.");
  607. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_HEAD);
  608. }
  609. /* Write out first line of request/response, plus all the headers.
  610. * These have been pre-encoded in aws_h1_encoder_message->outgoing_head_buf. */
  611. static int s_state_fn_head(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst) {
  612. bool done = s_encode_buf(encoder, dst, &encoder->message->outgoing_head_buf);
  613. if (!done) {
  614. /* Remain in this state */
  615. return AWS_OP_SUCCESS;
  616. }
  617. /* Don't NEED to free this buffer now, but we don't need it anymore, so why not */
  618. aws_byte_buf_clean_up(&encoder->message->outgoing_head_buf);
  619. /* Pick next state */
  620. if (encoder->message->body && encoder->message->content_length) {
  621. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_UNCHUNKED_BODY);
  622. } else if (encoder->message->has_chunked_encoding_header) {
  623. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_CHUNK_NEXT);
  624. } else {
  625. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_DONE);
  626. }
  627. }
  628. /* Write out body (not using chunked encoding). */
  629. static int s_state_fn_unchunked_body(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst) {
  630. bool done;
  631. if (s_encode_stream(encoder, dst, encoder->message->body, encoder->message->content_length, &done)) {
  632. return AWS_OP_ERR;
  633. }
  634. if (!done) {
  635. /* Remain in this state until we're done writing out body */
  636. return AWS_OP_SUCCESS;
  637. }
  638. /* Message is done */
  639. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_DONE);
  640. }
  641. /* Select next chunk to work on.
  642. * Encoder is essentially "paused" here if no chunks are available. */
  643. static int s_state_fn_chunk_next(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst) {
  644. (void)dst;
  645. if (aws_linked_list_empty(encoder->message->pending_chunk_list)) {
  646. /* Remain in this state until more chunks arrive */
  647. ENCODER_LOG(TRACE, encoder, "No chunks ready to send, waiting for more...");
  648. return AWS_OP_SUCCESS;
  649. }
  650. /* Set next chunk and go to next state */
  651. struct aws_linked_list_node *node = aws_linked_list_front(encoder->message->pending_chunk_list);
  652. encoder->current_chunk = AWS_CONTAINER_OF(node, struct aws_h1_chunk, node);
  653. encoder->chunk_count++;
  654. ENCODER_LOGF(
  655. TRACE,
  656. encoder,
  657. "Begin sending chunk %zu with size %" PRIu64,
  658. encoder->chunk_count,
  659. encoder->current_chunk->data_size);
  660. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_CHUNK_LINE);
  661. }
  662. /* Write out "chunk-size [chunk-ext] CRLF".
  663. * This data is pre-encoded in the chunk's chunk_line buffer */
  664. static int s_state_fn_chunk_line(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst) {
  665. bool done = s_encode_buf(encoder, dst, &encoder->current_chunk->chunk_line);
  666. if (!done) {
  667. /* Remain in state until done writing line */
  668. return AWS_OP_SUCCESS;
  669. }
  670. /* Pick next state */
  671. if (encoder->current_chunk->data_size == 0) {
  672. /* If data_size is 0, then this was the last chunk, which has no body.
  673. * Mark it complete and move on to trailer. */
  674. ENCODER_LOG(TRACE, encoder, "Final chunk complete");
  675. s_clean_up_current_chunk(encoder, AWS_ERROR_SUCCESS);
  676. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_CHUNK_TRAILER);
  677. }
  678. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_CHUNK_BODY);
  679. }
  680. /* Write out data for current chunk */
  681. static int s_state_fn_chunk_body(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst) {
  682. bool done;
  683. if (s_encode_stream(encoder, dst, encoder->current_chunk->data, encoder->current_chunk->data_size, &done)) {
  684. int error_code = aws_last_error();
  685. /* The error was caused by the chunk itself, report that specific error in its completion callback */
  686. s_clean_up_current_chunk(encoder, error_code);
  687. /* Re-raise error, in case it got cleared during user callback */
  688. return aws_raise_error(error_code);
  689. }
  690. if (!done) {
  691. /* Remain in this state until we're done writing out body */
  692. return AWS_OP_SUCCESS;
  693. }
  694. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_CHUNK_END);
  695. }
  696. /* Write CRLF and mark chunk as complete */
  697. static int s_state_fn_chunk_end(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst) {
  698. bool done = s_write_crlf(dst);
  699. if (!done) {
  700. /* Remain in this state until done writing out CRLF */
  701. return AWS_OP_SUCCESS;
  702. }
  703. ENCODER_LOG(TRACE, encoder, "Chunk complete");
  704. s_clean_up_current_chunk(encoder, AWS_ERROR_SUCCESS);
  705. /* Pick next chunk to work on */
  706. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_CHUNK_NEXT);
  707. }
  708. /* Write out trailer after last chunk */
  709. static int s_state_fn_chunk_trailer(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst) {
  710. bool done;
  711. /* if a chunked trailer was set */
  712. if (encoder->message->trailer) {
  713. done = s_encode_buf(encoder, dst, &encoder->message->trailer->trailer_data);
  714. } else {
  715. done = s_write_crlf(dst);
  716. }
  717. if (!done) {
  718. /* Remain in this state until we're done writing out trailer */
  719. return AWS_OP_SUCCESS;
  720. }
  721. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_DONE);
  722. }
  723. /* Message is done, loop back to start of state machine */
  724. static int s_state_fn_done(struct aws_h1_encoder *encoder, struct aws_byte_buf *dst) {
  725. (void)dst;
  726. ENCODER_LOG(TRACE, encoder, "Done sending data.");
  727. encoder->message = NULL;
  728. return s_switch_state(encoder, AWS_H1_ENCODER_STATE_INIT);
  729. }
  730. struct encoder_state_def {
  731. encoder_state_fn *fn;
  732. const char *name;
  733. };
  734. static struct encoder_state_def s_encoder_states[] = {
  735. [AWS_H1_ENCODER_STATE_INIT] = {.fn = s_state_fn_init, .name = "INIT"},
  736. [AWS_H1_ENCODER_STATE_HEAD] = {.fn = s_state_fn_head, .name = "HEAD"},
  737. [AWS_H1_ENCODER_STATE_UNCHUNKED_BODY] = {.fn = s_state_fn_unchunked_body, .name = "BODY"},
  738. [AWS_H1_ENCODER_STATE_CHUNK_NEXT] = {.fn = s_state_fn_chunk_next, .name = "CHUNK_NEXT"},
  739. [AWS_H1_ENCODER_STATE_CHUNK_LINE] = {.fn = s_state_fn_chunk_line, .name = "CHUNK_LINE"},
  740. [AWS_H1_ENCODER_STATE_CHUNK_BODY] = {.fn = s_state_fn_chunk_body, .name = "CHUNK_BODY"},
  741. [AWS_H1_ENCODER_STATE_CHUNK_END] = {.fn = s_state_fn_chunk_end, .name = "CHUNK_END"},
  742. [AWS_H1_ENCODER_STATE_CHUNK_TRAILER] = {.fn = s_state_fn_chunk_trailer, .name = "CHUNK_TRAILER"},
  743. [AWS_H1_ENCODER_STATE_DONE] = {.fn = s_state_fn_done, .name = "DONE"},
  744. };
  745. int aws_h1_encoder_process(struct aws_h1_encoder *encoder, struct aws_byte_buf *out_buf) {
  746. AWS_PRECONDITION(encoder);
  747. AWS_PRECONDITION(out_buf);
  748. if (!encoder->message) {
  749. ENCODER_LOG(ERROR, encoder, "No message is currently set for encoding.");
  750. return aws_raise_error(AWS_ERROR_INVALID_STATE);
  751. }
  752. /* Run state machine until states stop changing. (due to out_buf running
  753. * out of space, input_stream stalling, waiting for more chunks, etc) */
  754. enum aws_h1_encoder_state prev_state;
  755. do {
  756. prev_state = encoder->state;
  757. if (s_encoder_states[encoder->state].fn(encoder, out_buf)) {
  758. return AWS_OP_ERR;
  759. }
  760. } while (prev_state != encoder->state);
  761. return AWS_OP_SUCCESS;
  762. }
  763. bool aws_h1_encoder_is_message_in_progress(const struct aws_h1_encoder *encoder) {
  764. return encoder->message;
  765. }
  766. bool aws_h1_encoder_is_waiting_for_chunks(const struct aws_h1_encoder *encoder) {
  767. return encoder->state == AWS_H1_ENCODER_STATE_CHUNK_NEXT &&
  768. aws_linked_list_empty(encoder->message->pending_chunk_list);
  769. }