-
Notifications
You must be signed in to change notification settings - Fork 50
Expand file tree
/
Copy pathh2_stream.h
More file actions
216 lines (179 loc) · 9.29 KB
/
h2_stream.h
File metadata and controls
216 lines (179 loc) · 9.29 KB
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#ifndef AWS_HTTP_H2_STREAM_H
#define AWS_HTTP_H2_STREAM_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/http/private/h2_frames.h>
#include <aws/http/private/request_response_impl.h>
#include <aws/common/mutex.h>
#include <aws/io/channel.h>
#include <inttypes.h>
#define AWS_H2_STREAM_LOGF(level, stream, text, ...) \
AWS_LOGF_##level( \
AWS_LS_HTTP_STREAM, \
"id=%" PRIu32 " connection=%p state=%s: " text, \
(stream)->base.id, \
(void *)(stream)->base.owning_connection, \
aws_h2_stream_state_to_str((stream)->thread_data.state), \
__VA_ARGS__)
#define AWS_H2_STREAM_LOG(level, stream, text) AWS_H2_STREAM_LOGF(level, (stream), "%s", (text))
enum aws_h2_stream_state {
/* Initial state, before anything sent or received. */
AWS_H2_STREAM_STATE_IDLE,
/* (server-only) stream-id was reserved via PUSH_PROMISE on another stream,
* but HEADERS for this stream have not been sent yet */
AWS_H2_STREAM_STATE_RESERVED_LOCAL,
/* (client-only) stream-id was reserved via PUSH_PROMISE on another stream,
* but HEADERS for this stream have not been received yet */
AWS_H2_STREAM_STATE_RESERVED_REMOTE,
/* Neither side is done sending their message. */
AWS_H2_STREAM_STATE_OPEN,
/* This side is done sending message (END_STREAM), but peer is not done. */
AWS_H2_STREAM_STATE_HALF_CLOSED_LOCAL,
/* Peer is done sending message (END_STREAM), but this side is not done */
AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE,
/* Both sides done sending message (END_STREAM),
* or either side has sent RST_STREAM */
AWS_H2_STREAM_STATE_CLOSED,
AWS_H2_STREAM_STATE_COUNT,
};
/* simplified stream state for API implementation */
enum aws_h2_stream_api_state {
AWS_H2_STREAM_API_STATE_INIT,
AWS_H2_STREAM_API_STATE_ACTIVE,
AWS_H2_STREAM_API_STATE_COMPLETE,
};
/* Indicates the state of the body of the HTTP/2 stream */
enum aws_h2_stream_body_state {
AWS_H2_STREAM_BODY_STATE_NONE, /* Has no body for the HTTP/2 stream */
AWS_H2_STREAM_BODY_STATE_WAITING_WRITES, /* Has no active body, but waiting for more to be
write */
AWS_H2_STREAM_BODY_STATE_ONGOING, /* Has active ongoing body */
};
/* represents a write operation, which will be turned into a data frame */
struct aws_h2_stream_data_write {
struct aws_linked_list_node node;
struct aws_input_stream *data_stream;
aws_http2_stream_write_data_complete_fn *on_complete;
void *user_data;
bool end_stream;
};
struct aws_h2_stream {
struct aws_http_stream base;
struct aws_linked_list_node node;
struct aws_channel_task cross_thread_work_task;
/* The threshold to send out a window update frame.
* When the window_size_self is less than the threshold, client will starts the sending of WINDOW_UPDATE frame
* to keep flow continues.
*/
int32_t window_size_threshold_to_send_update;
aws_http2_on_remote_end_stream_fn *on_h2_remote_end_stream;
/* Only the event-loop thread may touch this data */
struct {
enum aws_h2_stream_state state;
/* The remote window size.
* RFC-9113 6.9.2: The settings can shrink the exiting flow-control windows to negative values.
**/
int32_t window_size_peer;
/* The local window size.
* RFC-9113 6.9.2: The settings can shrink the exiting flow-control windows to negative values.
**/
int32_t window_size_self;
/**
* The size to increment the window_size_self pending to be sent.
* Allow the pending_window_update_size to exceed the max window size.
* The client will send the WINDOW_UPDATE frame to the server only valid.
* If the pending_window_update_size is too large, we will leave the excess to send it out later.
**/
uint64_t pending_window_update_size_self;
struct aws_http_message *outgoing_message;
/* All queued writes. If the message provides a body stream, it will be first in this list
* This list can drain, which results in the stream being put to sleep (moved to waiting_streams_list in
* h2_connection). */
struct aws_linked_list outgoing_writes; /* aws_http2_stream_data_write */
bool received_main_headers;
bool content_length_received;
/* Set if incoming message has content-length header */
uint64_t incoming_content_length;
/* The total length of payload of data frame received */
uint64_t incoming_data_length;
/* Indicates that the stream is currently in the waiting_streams_list and is
* asleep. When stream needs to be awaken, moving the stream back to the outgoing_streams_list and set this bool
* to false */
bool waiting_for_writes;
/* Set when s_stream_complete has been called. Prevents double-completion
* (e.g. GOAWAY completes stream, then pending cancel cross-thread task fires) */
bool is_complete;
} thread_data;
/* Any thread may touch this data, but the lock must be held (unless it's an atomic) */
struct {
struct aws_mutex lock;
bool is_cross_thread_work_task_scheduled;
/* The window_update value for `thread_data.window_size_self` that haven't applied yet */
uint64_t pending_window_update_size_self;
/* The combined aws_http2_error_code user wanted to send to remote peer via rst_stream and internal aws error
* code we want to inform user about. */
struct aws_h2err reset_error;
bool reset_called;
bool manual_write_ended;
/* Simplified stream state. */
enum aws_h2_stream_api_state api_state;
/* any data streams sent manually via aws_http2_stream_write_data */
struct aws_linked_list pending_write_list; /* aws_h2_stream_pending_data */
} synced_data;
bool manual_write;
/* Store the sent reset HTTP/2 error code, set to -1, if none has sent so far */
int64_t sent_reset_error_code;
/* Store the received reset HTTP/2 error code, set to -1, if none has received so far */
int64_t received_reset_error_code;
};
const char *aws_h2_stream_state_to_str(enum aws_h2_stream_state state);
struct aws_h2_stream *aws_h2_stream_new_request(
struct aws_http_connection *client_connection,
const struct aws_http_make_request_options *options);
enum aws_h2_stream_state aws_h2_stream_get_state(const struct aws_h2_stream *stream);
/**
* When the flow control windows changed with SETTING and WINDOW_UPDATE frame receive.
* The SETTINGS and remote WINDOW_UPDATE frame should cause flow control error if window size is illegal.
* But client controls the window to be legal for the user.
**/
struct aws_h2err aws_h2_stream_window_size_change_direct(struct aws_h2_stream *stream, int32_t size_changed, bool self);
/* Connection is ready to send frames from stream now */
int aws_h2_stream_on_activated(struct aws_h2_stream *stream, enum aws_h2_stream_body_state *body_state);
/* Completes stream for one reason or another, clean up any pending writes/resources. */
void aws_h2_stream_complete(struct aws_h2_stream *stream, int error_code);
/* Connection is ready to send data from stream now.
* Stream may complete itself during this call.
* data_encode_status: see `aws_h2_data_encode_status`
*/
int aws_h2_stream_encode_data_frame(
struct aws_h2_stream *stream,
struct aws_h2_frame_encoder *encoder,
struct aws_byte_buf *output,
int *data_encode_status);
struct aws_h2err aws_h2_stream_on_decoder_headers_begin(struct aws_h2_stream *stream);
struct aws_h2err aws_h2_stream_on_decoder_headers_i(
struct aws_h2_stream *stream,
const struct aws_http_header *header,
enum aws_http_header_name name_enum,
enum aws_http_header_block block_type);
struct aws_h2err aws_h2_stream_on_decoder_headers_end(
struct aws_h2_stream *stream,
bool malformed,
enum aws_http_header_block block_type);
struct aws_h2err aws_h2_stream_on_decoder_push_promise(struct aws_h2_stream *stream, uint32_t promised_stream_id);
struct aws_h2err aws_h2_stream_on_decoder_data_begin(
struct aws_h2_stream *stream,
uint32_t payload_len,
uint32_t total_padding_bytes,
bool end_stream);
struct aws_h2err aws_h2_stream_on_decoder_data_i(struct aws_h2_stream *stream, struct aws_byte_cursor data);
struct aws_h2err aws_h2_stream_on_decoder_window_update(
struct aws_h2_stream *stream,
uint32_t window_size_increment,
bool *window_resume);
struct aws_h2err aws_h2_stream_on_decoder_end_stream(struct aws_h2_stream *stream);
struct aws_h2err aws_h2_stream_on_decoder_rst_stream(struct aws_h2_stream *stream, uint32_t h2_error_code);
int aws_h2_stream_activate(struct aws_http_stream *stream);
#endif /* AWS_HTTP_H2_STREAM_H */