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