websocket_encoder.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  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/websocket_encoder.h>
  6. #include <inttypes.h>
  7. typedef int(state_fn)(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf);
  8. /* STATE_INIT: Outputs no data */
  9. static int s_state_init(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf) {
  10. (void)out_buf;
  11. if (!encoder->is_frame_in_progress) {
  12. return aws_raise_error(AWS_ERROR_INVALID_STATE);
  13. }
  14. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_OPCODE_BYTE;
  15. return AWS_OP_SUCCESS;
  16. }
  17. /* STATE_OPCODE_BYTE: Outputs 1st byte of frame, which is packed with goodies. */
  18. static int s_state_opcode_byte(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf) {
  19. AWS_ASSERT((encoder->frame.opcode & 0xF0) == 0); /* Should be impossible, the opcode was checked in start_frame() */
  20. /* Right 4 bits are opcode, left 4 bits are fin|rsv1|rsv2|rsv3 */
  21. uint8_t byte = encoder->frame.opcode;
  22. byte |= (encoder->frame.fin << 7);
  23. byte |= (encoder->frame.rsv[0] << 6);
  24. byte |= (encoder->frame.rsv[1] << 5);
  25. byte |= (encoder->frame.rsv[2] << 4);
  26. /* If buffer has room to write, proceed to next state */
  27. if (aws_byte_buf_write_u8(out_buf, byte)) {
  28. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_LENGTH_BYTE;
  29. }
  30. return AWS_OP_SUCCESS;
  31. }
  32. /* STATE_LENGTH_BYTE: Output 2nd byte of frame, which indicates payload length */
  33. static int s_state_length_byte(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf) {
  34. /* First bit is masking bool */
  35. uint8_t byte = (uint8_t)(encoder->frame.masked << 7);
  36. /* Next 7bits are length, if length is small.
  37. * Otherwise next 7bits are a magic number indicating how many bytes will be required to encode actual length */
  38. bool extended_length_required;
  39. if (encoder->frame.payload_length < AWS_WEBSOCKET_2BYTE_EXTENDED_LENGTH_MIN_VALUE) {
  40. byte |= (uint8_t)encoder->frame.payload_length;
  41. extended_length_required = false;
  42. } else if (encoder->frame.payload_length <= AWS_WEBSOCKET_2BYTE_EXTENDED_LENGTH_MAX_VALUE) {
  43. byte |= AWS_WEBSOCKET_7BIT_VALUE_FOR_2BYTE_EXTENDED_LENGTH;
  44. extended_length_required = true;
  45. } else {
  46. AWS_ASSERT(encoder->frame.payload_length <= AWS_WEBSOCKET_8BYTE_EXTENDED_LENGTH_MAX_VALUE);
  47. byte |= AWS_WEBSOCKET_7BIT_VALUE_FOR_8BYTE_EXTENDED_LENGTH;
  48. extended_length_required = true;
  49. }
  50. /* If buffer has room to write, proceed to next appropriate state */
  51. if (aws_byte_buf_write_u8(out_buf, byte)) {
  52. if (extended_length_required) {
  53. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_EXTENDED_LENGTH;
  54. encoder->state_bytes_processed = 0;
  55. } else {
  56. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_MASKING_KEY_CHECK;
  57. }
  58. }
  59. return AWS_OP_SUCCESS;
  60. }
  61. /* STATE_EXTENDED_LENGTH: Output extended length (state skipped if not using extended length). */
  62. static int s_state_extended_length(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf) {
  63. /* Fill tmp buffer with extended-length in network byte order */
  64. uint8_t network_bytes_array[8] = {0};
  65. struct aws_byte_buf network_bytes_buf =
  66. aws_byte_buf_from_empty_array(network_bytes_array, sizeof(network_bytes_array));
  67. if (encoder->frame.payload_length <= AWS_WEBSOCKET_2BYTE_EXTENDED_LENGTH_MAX_VALUE) {
  68. aws_byte_buf_write_be16(&network_bytes_buf, (uint16_t)encoder->frame.payload_length);
  69. } else {
  70. aws_byte_buf_write_be64(&network_bytes_buf, encoder->frame.payload_length);
  71. }
  72. /* Use cursor to iterate over tmp buffer */
  73. struct aws_byte_cursor network_bytes_cursor = aws_byte_cursor_from_buf(&network_bytes_buf);
  74. /* Advance cursor if some bytes already written */
  75. aws_byte_cursor_advance(&network_bytes_cursor, (size_t)encoder->state_bytes_processed);
  76. /* Shorten cursor if it won't all fit in out_buf */
  77. bool all_data_written = true;
  78. size_t space_available = out_buf->capacity - out_buf->len;
  79. if (network_bytes_cursor.len > space_available) {
  80. network_bytes_cursor.len = space_available;
  81. all_data_written = false;
  82. }
  83. aws_byte_buf_write_from_whole_cursor(out_buf, network_bytes_cursor);
  84. encoder->state_bytes_processed += network_bytes_cursor.len;
  85. /* If all bytes written, advance to next state */
  86. if (all_data_written) {
  87. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_MASKING_KEY_CHECK;
  88. }
  89. return AWS_OP_SUCCESS;
  90. }
  91. /* MASKING_KEY_CHECK: Outputs no data. Gets things ready for (or decides to skip) the STATE_MASKING_KEY */
  92. static int s_state_masking_key_check(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf) {
  93. (void)out_buf;
  94. if (encoder->frame.masked) {
  95. encoder->state_bytes_processed = 0;
  96. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_MASKING_KEY;
  97. } else {
  98. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_PAYLOAD_CHECK;
  99. }
  100. return AWS_OP_SUCCESS;
  101. }
  102. /* MASKING_KEY: Output masking-key (state skipped if no masking key). */
  103. static int s_state_masking_key(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf) {
  104. /* Prepare cursor to iterate over masking-key bytes */
  105. struct aws_byte_cursor cursor =
  106. aws_byte_cursor_from_array(encoder->frame.masking_key, sizeof(encoder->frame.masking_key));
  107. /* Advance cursor if some bytes already written (moves ptr forward but shortens len so end stays in place) */
  108. aws_byte_cursor_advance(&cursor, (size_t)encoder->state_bytes_processed);
  109. /* Shorten cursor if it won't all fit in out_buf */
  110. bool all_data_written = true;
  111. size_t space_available = out_buf->capacity - out_buf->len;
  112. if (cursor.len > space_available) {
  113. cursor.len = space_available;
  114. all_data_written = false;
  115. }
  116. aws_byte_buf_write_from_whole_cursor(out_buf, cursor);
  117. encoder->state_bytes_processed += cursor.len;
  118. /* If all bytes written, advance to next state */
  119. if (all_data_written) {
  120. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_PAYLOAD_CHECK;
  121. }
  122. return AWS_OP_SUCCESS;
  123. }
  124. /* MASKING_KEY_CHECK: Outputs no data. Gets things ready for (or decides to skip) STATE_PAYLOAD */
  125. static int s_state_payload_check(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf) {
  126. (void)out_buf;
  127. if (encoder->frame.payload_length > 0) {
  128. encoder->state_bytes_processed = 0;
  129. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_PAYLOAD;
  130. } else {
  131. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_DONE;
  132. }
  133. return AWS_OP_SUCCESS;
  134. }
  135. /* PAYLOAD: Output payload until we're done (state skipped if no payload). */
  136. static int s_state_payload(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf) {
  137. /* Bail early if out_buf has no space for writing */
  138. if (out_buf->len >= out_buf->capacity) {
  139. return AWS_OP_SUCCESS;
  140. }
  141. const uint64_t prev_bytes_processed = encoder->state_bytes_processed;
  142. const struct aws_byte_buf prev_buf = *out_buf;
  143. /* Invoke callback which will write to buffer */
  144. int err = encoder->stream_outgoing_payload(out_buf, encoder->user_data);
  145. if (err) {
  146. return AWS_OP_ERR;
  147. }
  148. /* Ensure that user did not commit forbidden acts upon the out_buf */
  149. AWS_FATAL_ASSERT(
  150. (out_buf->buffer == prev_buf.buffer) && (out_buf->capacity == prev_buf.capacity) &&
  151. (out_buf->len >= prev_buf.len));
  152. size_t bytes_written = out_buf->len - prev_buf.len;
  153. err = aws_add_u64_checked(encoder->state_bytes_processed, bytes_written, &encoder->state_bytes_processed);
  154. if (err) {
  155. return aws_raise_error(AWS_ERROR_HTTP_OUTGOING_STREAM_LENGTH_INCORRECT);
  156. }
  157. /* Mask data, if necessary.
  158. * RFC-6455 Section 5.3 Client-to-Server Masking
  159. * Each byte of payload is XOR against a byte of the masking-key */
  160. if (encoder->frame.masked) {
  161. uint64_t mask_index = prev_bytes_processed;
  162. /* Optimization idea: don't do this 1 byte at a time */
  163. uint8_t *current_byte = out_buf->buffer + prev_buf.len;
  164. uint8_t *end_byte = out_buf->buffer + out_buf->len;
  165. while (current_byte != end_byte) {
  166. *current_byte++ ^= encoder->frame.masking_key[mask_index++ % 4];
  167. }
  168. }
  169. /* If done writing payload, proceed to next state */
  170. if (encoder->state_bytes_processed == encoder->frame.payload_length) {
  171. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_DONE;
  172. } else {
  173. /* Some more error-checking... */
  174. if (encoder->state_bytes_processed > encoder->frame.payload_length) {
  175. AWS_LOGF_ERROR(
  176. AWS_LS_HTTP_WEBSOCKET,
  177. "id=%p: Outgoing stream has exceeded stated payload length of %" PRIu64,
  178. (void *)encoder->user_data,
  179. encoder->frame.payload_length);
  180. return aws_raise_error(AWS_ERROR_HTTP_OUTGOING_STREAM_LENGTH_INCORRECT);
  181. }
  182. }
  183. return AWS_OP_SUCCESS;
  184. }
  185. static state_fn *s_state_functions[AWS_WEBSOCKET_ENCODER_STATE_DONE] = {
  186. s_state_init,
  187. s_state_opcode_byte,
  188. s_state_length_byte,
  189. s_state_extended_length,
  190. s_state_masking_key_check,
  191. s_state_masking_key,
  192. s_state_payload_check,
  193. s_state_payload,
  194. };
  195. int aws_websocket_encoder_process(struct aws_websocket_encoder *encoder, struct aws_byte_buf *out_buf) {
  196. /* Run state machine until frame is completely decoded, or the state stops changing.
  197. * Note that we don't necessarily stop looping when out_buf is full, because not all states need to output data */
  198. while (encoder->state != AWS_WEBSOCKET_ENCODER_STATE_DONE) {
  199. const enum aws_websocket_encoder_state prev_state = encoder->state;
  200. int err = s_state_functions[encoder->state](encoder, out_buf);
  201. if (err) {
  202. return AWS_OP_ERR;
  203. }
  204. if (prev_state == encoder->state) {
  205. /* dev-assert: Check that each state is doing as much work as it possibly can.
  206. * Except for the PAYLOAD state, where it's up to the user to fill the buffer. */
  207. AWS_ASSERT((out_buf->len == out_buf->capacity) || (encoder->state == AWS_WEBSOCKET_ENCODER_STATE_PAYLOAD));
  208. break;
  209. }
  210. }
  211. if (encoder->state == AWS_WEBSOCKET_ENCODER_STATE_DONE) {
  212. encoder->state = AWS_WEBSOCKET_ENCODER_STATE_INIT;
  213. encoder->is_frame_in_progress = false;
  214. }
  215. return AWS_OP_SUCCESS;
  216. }
  217. int aws_websocket_encoder_start_frame(struct aws_websocket_encoder *encoder, const struct aws_websocket_frame *frame) {
  218. /* Error-check as much as possible before accepting next frame */
  219. if (encoder->is_frame_in_progress) {
  220. return aws_raise_error(AWS_ERROR_INVALID_STATE);
  221. }
  222. /* RFC-6455 Section 5.2 contains all these rules... */
  223. /* Opcode must fit in 4bits */
  224. if (frame->opcode != (frame->opcode & 0x0F)) {
  225. AWS_LOGF_ERROR(
  226. AWS_LS_HTTP_WEBSOCKET,
  227. "id=%p: Outgoing frame has unknown opcode 0x%" PRIx8,
  228. (void *)encoder->user_data,
  229. frame->opcode);
  230. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  231. }
  232. /* High bit of 8byte length must be clear */
  233. if (frame->payload_length > AWS_WEBSOCKET_8BYTE_EXTENDED_LENGTH_MAX_VALUE) {
  234. AWS_LOGF_ERROR(
  235. AWS_LS_HTTP_WEBSOCKET,
  236. "id=%p: Outgoing frame's payload length exceeds the max",
  237. (void *)encoder->user_data);
  238. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  239. }
  240. /* Data frames with the FIN bit clear are considered fragmented and must be followed by
  241. * 1+ CONTINUATION frames, where only the final CONTINUATION frame's FIN bit is set.
  242. *
  243. * Control frames may be injected in the middle of a fragmented message,
  244. * but control frames may not be fragmented themselves. */
  245. bool keep_expecting_continuation_data_frame = encoder->expecting_continuation_data_frame;
  246. if (aws_websocket_is_data_frame(frame->opcode)) {
  247. bool is_continuation_frame = (AWS_WEBSOCKET_OPCODE_CONTINUATION == frame->opcode);
  248. if (encoder->expecting_continuation_data_frame != is_continuation_frame) {
  249. AWS_LOGF_ERROR(
  250. AWS_LS_HTTP_WEBSOCKET,
  251. "id=%p: Fragmentation error. Outgoing frame starts a new message but previous message has not ended",
  252. (void *)encoder->user_data);
  253. return aws_raise_error(AWS_ERROR_INVALID_STATE);
  254. }
  255. keep_expecting_continuation_data_frame = !frame->fin;
  256. } else {
  257. /* Control frames themselves MUST NOT be fragmented. */
  258. if (!frame->fin) {
  259. AWS_LOGF_ERROR(
  260. AWS_LS_HTTP_WEBSOCKET,
  261. "id=%p: It is illegal to send a fragmented control frame",
  262. (void *)encoder->user_data);
  263. return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  264. }
  265. }
  266. /* Frame accepted */
  267. encoder->frame = *frame;
  268. encoder->is_frame_in_progress = true;
  269. encoder->expecting_continuation_data_frame = keep_expecting_continuation_data_frame;
  270. return AWS_OP_SUCCESS;
  271. }
  272. bool aws_websocket_encoder_is_frame_in_progress(const struct aws_websocket_encoder *encoder) {
  273. return encoder->is_frame_in_progress;
  274. }
  275. void aws_websocket_encoder_init(
  276. struct aws_websocket_encoder *encoder,
  277. aws_websocket_encoder_payload_fn *stream_outgoing_payload,
  278. void *user_data) {
  279. AWS_ZERO_STRUCT(*encoder);
  280. encoder->user_data = user_data;
  281. encoder->stream_outgoing_payload = stream_outgoing_payload;
  282. }
  283. uint64_t aws_websocket_frame_encoded_size(const struct aws_websocket_frame *frame) {
  284. /* This is an internal function, so asserts are sufficient error handling */
  285. AWS_ASSERT(frame);
  286. AWS_ASSERT(frame->payload_length <= AWS_WEBSOCKET_8BYTE_EXTENDED_LENGTH_MAX_VALUE);
  287. /* All frames start with at least 2 bytes */
  288. uint64_t total = 2;
  289. /* If masked, add 4 bytes for masking-key */
  290. if (frame->masked) {
  291. total += 4;
  292. }
  293. /* If extended payload length, add 2 or 8 bytes */
  294. if (frame->payload_length >= AWS_WEBSOCKET_8BYTE_EXTENDED_LENGTH_MIN_VALUE) {
  295. total += 8;
  296. } else if (frame->payload_length >= AWS_WEBSOCKET_2BYTE_EXTENDED_LENGTH_MIN_VALUE) {
  297. total += 2;
  298. }
  299. /* Plus payload itself */
  300. total += frame->payload_length;
  301. return total;
  302. }