1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
#ifndef AWS_HTTP_H1_ENCODER_H
#define AWS_HTTP_H1_ENCODER_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/http/private/http_impl.h>
#include <aws/http/private/request_response_impl.h>
struct aws_h1_chunk {
struct aws_allocator *allocator;
struct aws_input_stream *data;
uint64_t data_size;
aws_http1_stream_write_chunk_complete_fn *on_complete;
void *user_data;
struct aws_linked_list_node node;
/* Buffer containing pre-encoded start line: chunk-size [chunk-ext] CRLF */
struct aws_byte_buf chunk_line;
};
struct aws_h1_trailer {
struct aws_allocator *allocator;
struct aws_byte_buf trailer_data;
};
/**
* Message to be submitted to encoder.
* Contains data necessary for encoder to write an outgoing request or response.
*/
struct aws_h1_encoder_message {
/* Upon creation, the "head" (everything preceding body) is buffered here. */
struct aws_byte_buf outgoing_head_buf;
/* Single stream used for unchunked body */
struct aws_input_stream *body;
/* Pointer to list of `struct aws_h1_chunk`, used for chunked encoding.
* List is owned by aws_h1_stream.
* Encoder completes/frees/pops front chunk when it's done sending.
* If list goes empty, encoder waits for more chunks to arrive.
* A chunk with data_size=0 means "final chunk" */
struct aws_linked_list *pending_chunk_list;
/* Pointer to chunked_trailer, used for chunked_trailer. */
struct aws_h1_trailer *trailer;
/* If non-zero, length of unchunked body to send */
uint64_t content_length;
bool has_connection_close_header;
bool has_chunked_encoding_header;
};
enum aws_h1_encoder_state {
AWS_H1_ENCODER_STATE_INIT,
AWS_H1_ENCODER_STATE_HEAD,
AWS_H1_ENCODER_STATE_UNCHUNKED_BODY,
AWS_H1_ENCODER_STATE_CHUNK_NEXT,
AWS_H1_ENCODER_STATE_CHUNK_LINE,
AWS_H1_ENCODER_STATE_CHUNK_BODY,
AWS_H1_ENCODER_STATE_CHUNK_END,
AWS_H1_ENCODER_STATE_CHUNK_TRAILER,
AWS_H1_ENCODER_STATE_DONE,
};
struct aws_h1_encoder {
struct aws_allocator *allocator;
enum aws_h1_encoder_state state;
/* Current message being encoded */
struct aws_h1_encoder_message *message;
/* Used by some states to track progress. Reset to 0 whenever state changes */
uint64_t progress_bytes;
/* Current chunk */
struct aws_h1_chunk *current_chunk;
/* Number of chunks sent, just used for logging */
size_t chunk_count;
/* Encoder logs with this stream ptr as the ID, and passes this ptr to the chunk_complete callback */
struct aws_http_stream *current_stream;
};
struct aws_h1_chunk *aws_h1_chunk_new(struct aws_allocator *allocator, const struct aws_http1_chunk_options *options);
struct aws_h1_trailer *aws_h1_trailer_new(
struct aws_allocator *allocator,
const struct aws_http_headers *trailing_headers);
void aws_h1_trailer_destroy(struct aws_h1_trailer *trailer);
/* Just destroy the chunk (don't fire callback) */
void aws_h1_chunk_destroy(struct aws_h1_chunk *chunk);
/* Destroy chunk and fire its completion callback */
void aws_h1_chunk_complete_and_destroy(struct aws_h1_chunk *chunk, struct aws_http_stream *http_stream, int error_code);
int aws_chunk_line_from_options(struct aws_http1_chunk_options *options, struct aws_byte_buf *chunk_line);
AWS_EXTERN_C_BEGIN
/* Validate request and cache any info the encoder will need later in the "encoder message". */
AWS_HTTP_API
int aws_h1_encoder_message_init_from_request(
struct aws_h1_encoder_message *message,
struct aws_allocator *allocator,
const struct aws_http_message *request,
struct aws_linked_list *pending_chunk_list);
int aws_h1_encoder_message_init_from_response(
struct aws_h1_encoder_message *message,
struct aws_allocator *allocator,
const struct aws_http_message *response,
bool body_headers_ignored,
struct aws_linked_list *pending_chunk_list);
AWS_HTTP_API
void aws_h1_encoder_message_clean_up(struct aws_h1_encoder_message *message);
AWS_HTTP_API
void aws_h1_encoder_init(struct aws_h1_encoder *encoder, struct aws_allocator *allocator);
AWS_HTTP_API
void aws_h1_encoder_clean_up(struct aws_h1_encoder *encoder);
AWS_HTTP_API
int aws_h1_encoder_start_message(
struct aws_h1_encoder *encoder,
struct aws_h1_encoder_message *message,
struct aws_http_stream *stream);
AWS_HTTP_API
int aws_h1_encoder_process(struct aws_h1_encoder *encoder, struct aws_byte_buf *out_buf);
AWS_HTTP_API
bool aws_h1_encoder_is_message_in_progress(const struct aws_h1_encoder *encoder);
/* Return true if the encoder is stuck waiting for more chunks to be added to the current message */
AWS_HTTP_API
bool aws_h1_encoder_is_waiting_for_chunks(const struct aws_h1_encoder *encoder);
AWS_EXTERN_C_END
#endif /* AWS_HTTP_H1_ENCODER_H */
|