1 /**
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0.
4  */
5 
6 #include <aws/http/private/h2_stream.h>
7 
8 #include <aws/http/private/h2_connection.h>
9 #include <aws/http/private/strutil.h>
10 #include <aws/http/status_code.h>
11 #include <aws/io/channel.h>
12 #include <aws/io/logging.h>
13 
14 /* Apple toolchains such as xcode and swiftpm define the DEBUG symbol. undef it here so we can actually use the token */
15 #undef DEBUG
16 
17 static void s_stream_destroy(struct aws_http_stream *stream_base);
18 static void s_stream_update_window(struct aws_http_stream *stream_base, size_t increment_size);
19 static int s_stream_reset_stream(struct aws_http_stream *stream_base, uint32_t http2_error);
20 static int s_stream_get_received_error_code(struct aws_http_stream *stream_base, uint32_t *out_http2_error);
21 static int s_stream_get_sent_error_code(struct aws_http_stream *stream_base, uint32_t *out_http2_error);
22 
23 static void s_stream_cross_thread_work_task(struct aws_channel_task *task, void *arg, enum aws_task_status status);
24 static struct aws_h2err s_send_rst_and_close_stream(struct aws_h2_stream *stream, struct aws_h2err stream_error);
25 static int s_stream_reset_stream_internal(struct aws_http_stream *stream_base, struct aws_h2err stream_error);
26 
27 struct aws_http_stream_vtable s_h2_stream_vtable = {
28     .destroy = s_stream_destroy,
29     .update_window = s_stream_update_window,
30     .activate = aws_h2_stream_activate,
31     .http1_write_chunk = NULL,
32     .http2_reset_stream = s_stream_reset_stream,
33     .http2_get_received_error_code = s_stream_get_received_error_code,
34     .http2_get_sent_error_code = s_stream_get_sent_error_code,
35 };
36 
aws_h2_stream_state_to_str(enum aws_h2_stream_state state)37 const char *aws_h2_stream_state_to_str(enum aws_h2_stream_state state) {
38     switch (state) {
39         case AWS_H2_STREAM_STATE_IDLE:
40             return "IDLE";
41         case AWS_H2_STREAM_STATE_RESERVED_LOCAL:
42             return "RESERVED_LOCAL";
43         case AWS_H2_STREAM_STATE_RESERVED_REMOTE:
44             return "RESERVED_REMOTE";
45         case AWS_H2_STREAM_STATE_OPEN:
46             return "OPEN";
47         case AWS_H2_STREAM_STATE_HALF_CLOSED_LOCAL:
48             return "HALF_CLOSED_LOCAL";
49         case AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE:
50             return "HALF_CLOSED_REMOTE";
51         case AWS_H2_STREAM_STATE_CLOSED:
52             return "CLOSED";
53         default:
54             /* unreachable */
55             AWS_ASSERT(0);
56             return "*** UNKNOWN ***";
57     }
58 }
59 
s_get_h2_connection(const struct aws_h2_stream * stream)60 static struct aws_h2_connection *s_get_h2_connection(const struct aws_h2_stream *stream) {
61     return AWS_CONTAINER_OF(stream->base.owning_connection, struct aws_h2_connection, base);
62 }
63 
s_lock_synced_data(struct aws_h2_stream * stream)64 static void s_lock_synced_data(struct aws_h2_stream *stream) {
65     int err = aws_mutex_lock(&stream->synced_data.lock);
66     AWS_ASSERT(!err && "lock failed");
67     (void)err;
68 }
69 
s_unlock_synced_data(struct aws_h2_stream * stream)70 static void s_unlock_synced_data(struct aws_h2_stream *stream) {
71     int err = aws_mutex_unlock(&stream->synced_data.lock);
72     AWS_ASSERT(!err && "unlock failed");
73     (void)err;
74 }
75 
76 #define AWS_PRECONDITION_ON_CHANNEL_THREAD(STREAM)                                                                     \
77     AWS_PRECONDITION(aws_channel_thread_is_callers_thread(s_get_h2_connection(STREAM)->base.channel_slot->channel))
78 
79 static bool s_client_state_allows_frame_type[AWS_H2_STREAM_STATE_COUNT][AWS_H2_FRAME_TYPE_COUNT] = {
80     /* State before anything is sent or received */
81     [AWS_H2_STREAM_STATE_IDLE] = {0},
82     /* Client streams are never in reserved (local) state */
83     [AWS_H2_STREAM_STATE_RESERVED_LOCAL] = {0},
84     /* Client received push-request via PUSH_PROMISE on another stream.
85      * Waiting for push-response to start arriving on this server-initiated stream. */
86     [AWS_H2_STREAM_STATE_RESERVED_REMOTE] =
87         {
88             [AWS_H2_FRAME_T_HEADERS] = true,
89             [AWS_H2_FRAME_T_RST_STREAM] = true,
90         },
91     /* Client is sending request and has not received full response yet. */
92     [AWS_H2_STREAM_STATE_OPEN] =
93         {
94             [AWS_H2_FRAME_T_DATA] = true,
95             [AWS_H2_FRAME_T_HEADERS] = true,
96             [AWS_H2_FRAME_T_RST_STREAM] = true,
97             [AWS_H2_FRAME_T_PUSH_PROMISE] = true,
98             [AWS_H2_FRAME_T_WINDOW_UPDATE] = true,
99         },
100     /* Client has sent full request (END_STREAM), but has not received full response yet. */
101     [AWS_H2_STREAM_STATE_HALF_CLOSED_LOCAL] =
102         {
103             [AWS_H2_FRAME_T_DATA] = true,
104             [AWS_H2_FRAME_T_HEADERS] = true,
105             [AWS_H2_FRAME_T_RST_STREAM] = true,
106             [AWS_H2_FRAME_T_PUSH_PROMISE] = true,
107             [AWS_H2_FRAME_T_WINDOW_UPDATE] = true,
108         },
109     /* Client has received full response (END_STREAM), but is still sending request (uncommon). */
110     [AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE] =
111         {
112             [AWS_H2_FRAME_T_RST_STREAM] = true,
113             [AWS_H2_FRAME_T_WINDOW_UPDATE] = true,
114         },
115     /* Full request sent (END_STREAM) and full response received (END_STREAM).
116      * OR sent RST_STREAM. OR received RST_STREAM. */
117     [AWS_H2_STREAM_STATE_CLOSED] = {0},
118 };
119 
120 static bool s_server_state_allows_frame_type[AWS_H2_STREAM_STATE_COUNT][AWS_H2_FRAME_TYPE_COUNT] = {
121     /* State before anything is sent or received, waiting for request headers to arrives and start things off */
122     [AWS_H2_STREAM_STATE_IDLE] =
123         {
124             [AWS_H2_FRAME_T_HEADERS] = true,
125         },
126     /* Server sent push-request via PUSH_PROMISE on a client-initiated stream,
127      * but hasn't started sending the push-response on this server-initiated stream yet. */
128     [AWS_H2_STREAM_STATE_RESERVED_LOCAL] =
129         {
130             [AWS_H2_FRAME_T_RST_STREAM] = true,
131             [AWS_H2_FRAME_T_WINDOW_UPDATE] = true,
132         },
133     /* Server streams are never in reserved (remote) state */
134     [AWS_H2_STREAM_STATE_RESERVED_REMOTE] = {0},
135     /* Server is receiving request, and has sent full response yet. */
136     [AWS_H2_STREAM_STATE_OPEN] =
137         {
138             [AWS_H2_FRAME_T_HEADERS] = true,
139             [AWS_H2_FRAME_T_DATA] = true,
140             [AWS_H2_FRAME_T_RST_STREAM] = true,
141             [AWS_H2_FRAME_T_WINDOW_UPDATE] = true,
142         },
143     /* Server has sent full response (END_STREAM), but has not received full response yet (uncommon). */
144     [AWS_H2_STREAM_STATE_HALF_CLOSED_LOCAL] =
145         {
146             [AWS_H2_FRAME_T_HEADERS] = true,
147             [AWS_H2_FRAME_T_DATA] = true,
148             [AWS_H2_FRAME_T_RST_STREAM] = true,
149             [AWS_H2_FRAME_T_WINDOW_UPDATE] = true,
150         },
151     /* Server has received full request (END_STREAM), and is still sending response. */
152     [AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE] =
153         {
154             [AWS_H2_FRAME_T_RST_STREAM] = true,
155             [AWS_H2_FRAME_T_WINDOW_UPDATE] = true,
156         },
157     /* Full request received (END_STREAM) and full response sent (END_STREAM).
158      * OR sent RST_STREAM. OR received RST_STREAM. */
159     [AWS_H2_STREAM_STATE_CLOSED] = {0},
160 };
161 
162 /* Returns the appropriate Stream Error if given frame not allowed in current state */
s_check_state_allows_frame_type(const struct aws_h2_stream * stream,enum aws_h2_frame_type frame_type)163 static struct aws_h2err s_check_state_allows_frame_type(
164     const struct aws_h2_stream *stream,
165     enum aws_h2_frame_type frame_type) {
166 
167     AWS_PRECONDITION(frame_type < AWS_H2_FRAME_T_UNKNOWN); /* Decoder won't invoke callbacks for unknown frame types */
168     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
169 
170     const enum aws_h2_stream_state state = stream->thread_data.state;
171 
172     bool allowed;
173     if (stream->base.server_data) {
174         allowed = s_server_state_allows_frame_type[state][frame_type];
175     } else {
176         allowed = s_client_state_allows_frame_type[state][frame_type];
177     }
178 
179     if (allowed) {
180         return AWS_H2ERR_SUCCESS;
181     }
182 
183     /* Determine specific error code */
184     enum aws_http2_error_code h2_error_code = AWS_HTTP2_ERR_PROTOCOL_ERROR;
185 
186     /* If peer knows the state is closed, then it's a STREAM_CLOSED error */
187     if (state == AWS_H2_STREAM_STATE_CLOSED || state == AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE) {
188         h2_error_code = AWS_HTTP2_ERR_STREAM_CLOSED;
189     }
190 
191     AWS_H2_STREAM_LOGF(
192         ERROR,
193         stream,
194         "Malformed message, cannot receive %s frame in %s state",
195         aws_h2_frame_type_to_str(frame_type),
196         aws_h2_stream_state_to_str(state));
197 
198     return aws_h2err_from_h2_code(h2_error_code);
199 }
200 
s_stream_send_update_window_frame(struct aws_h2_stream * stream,size_t increment_size)201 static int s_stream_send_update_window_frame(struct aws_h2_stream *stream, size_t increment_size) {
202     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
203     AWS_PRECONDITION(increment_size <= AWS_H2_WINDOW_UPDATE_MAX);
204 
205     struct aws_h2_connection *connection = s_get_h2_connection(stream);
206     struct aws_h2_frame *stream_window_update_frame =
207         aws_h2_frame_new_window_update(stream->base.alloc, stream->base.id, (uint32_t)increment_size);
208 
209     if (!stream_window_update_frame) {
210         AWS_H2_STREAM_LOGF(
211             ERROR,
212             stream,
213             "Failed to create WINDOW_UPDATE frame on connection, error %s",
214             aws_error_name(aws_last_error()));
215         return AWS_OP_ERR;
216     }
217     aws_h2_connection_enqueue_outgoing_frame(connection, stream_window_update_frame);
218 
219     return AWS_OP_SUCCESS;
220 }
221 
aws_h2_stream_new_request(struct aws_http_connection * client_connection,const struct aws_http_make_request_options * options)222 struct aws_h2_stream *aws_h2_stream_new_request(
223     struct aws_http_connection *client_connection,
224     const struct aws_http_make_request_options *options) {
225     AWS_PRECONDITION(client_connection);
226     AWS_PRECONDITION(options);
227 
228     struct aws_h2_stream *stream = aws_mem_calloc(client_connection->alloc, 1, sizeof(struct aws_h2_stream));
229     if (!stream) {
230         return NULL;
231     }
232 
233     /* Initialize base stream */
234     stream->base.vtable = &s_h2_stream_vtable;
235     stream->base.alloc = client_connection->alloc;
236     stream->base.owning_connection = client_connection;
237     stream->base.user_data = options->user_data;
238     stream->base.on_incoming_headers = options->on_response_headers;
239     stream->base.on_incoming_header_block_done = options->on_response_header_block_done;
240     stream->base.on_incoming_body = options->on_response_body;
241     stream->base.on_complete = options->on_complete;
242     stream->base.client_data = &stream->base.client_or_server_data.client;
243     stream->base.client_data->response_status = AWS_HTTP_STATUS_CODE_UNKNOWN;
244 
245     /* Stream refcount starts at 1, and gets incremented again for the connection upon a call to activate() */
246     aws_atomic_init_int(&stream->base.refcount, 1);
247 
248     /* Init H2 specific stuff */
249     stream->thread_data.state = AWS_H2_STREAM_STATE_IDLE;
250     stream->thread_data.outgoing_message = options->request;
251 
252     stream->sent_reset_error_code = -1;
253     stream->received_reset_error_code = -1;
254 
255     stream->synced_data.reset_error.h2_code = AWS_HTTP2_ERR_COUNT;
256     stream->synced_data.api_state = AWS_H2_STREAM_API_STATE_INIT;
257     if (aws_mutex_init(&stream->synced_data.lock)) {
258         AWS_H2_STREAM_LOGF(
259             ERROR, stream, "Mutex init error %d (%s).", aws_last_error(), aws_error_name(aws_last_error()));
260         aws_mem_release(stream->base.alloc, stream);
261         return NULL;
262     }
263     aws_http_message_acquire(stream->thread_data.outgoing_message);
264     aws_channel_task_init(
265         &stream->cross_thread_work_task, s_stream_cross_thread_work_task, stream, "HTTP/2 stream cross-thread work");
266     return stream;
267 }
268 
s_stream_cross_thread_work_task(struct aws_channel_task * task,void * arg,enum aws_task_status status)269 static void s_stream_cross_thread_work_task(struct aws_channel_task *task, void *arg, enum aws_task_status status) {
270     (void)task;
271 
272     struct aws_h2_stream *stream = arg;
273     if (status != AWS_TASK_STATUS_RUN_READY) {
274         goto end;
275     }
276 
277     struct aws_h2_connection *connection = s_get_h2_connection(stream);
278 
279     if (aws_h2_stream_get_state(stream) == AWS_H2_STREAM_STATE_CLOSED) {
280         /* stream is closed, silently ignoring the requests from user */
281         AWS_H2_STREAM_LOG(
282             TRACE, stream, "Stream closed before cross thread work task runs, ignoring everything was sent by user.");
283         goto end;
284     }
285 
286     /* Not sending window update at half closed remote state */
287     bool ignore_window_update = (aws_h2_stream_get_state(stream) == AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE);
288     bool reset_called;
289     size_t window_update_size;
290     struct aws_h2err reset_error;
291 
292     { /* BEGIN CRITICAL SECTION */
293         s_lock_synced_data(stream);
294         stream->synced_data.is_cross_thread_work_task_scheduled = false;
295 
296         /* window_update_size is ensured to be not greater than AWS_H2_WINDOW_UPDATE_MAX */
297         window_update_size = stream->synced_data.window_update_size;
298         stream->synced_data.window_update_size = 0;
299         reset_called = stream->synced_data.reset_called;
300         reset_error = stream->synced_data.reset_error;
301 
302         s_unlock_synced_data(stream);
303     } /* END CRITICAL SECTION */
304 
305     if (window_update_size > 0 && !ignore_window_update) {
306         if (s_stream_send_update_window_frame(stream, window_update_size)) {
307             /* Treat this as a connection error */
308             aws_h2_connection_shutdown_due_to_write_err(connection, aws_last_error());
309         }
310     }
311 
312     /* The largest legal value will be 2 * max window size, which is way less than INT64_MAX, so if the window_size_self
313      * overflows, remote peer will find it out. So just apply the change and ignore the possible overflow.*/
314     stream->thread_data.window_size_self += window_update_size;
315 
316     if (reset_called) {
317         struct aws_h2err returned_h2err = s_send_rst_and_close_stream(stream, reset_error);
318         if (aws_h2err_failed(returned_h2err)) {
319             aws_h2_connection_shutdown_due_to_write_err(connection, returned_h2err.aws_code);
320         }
321     }
322 
323     /* It's likely that frames were queued while processing cross-thread work.
324      * If so, try writing them now */
325     aws_h2_try_write_outgoing_frames(connection);
326 
327 end:
328     aws_http_stream_release(&stream->base);
329 }
330 
s_stream_destroy(struct aws_http_stream * stream_base)331 static void s_stream_destroy(struct aws_http_stream *stream_base) {
332     AWS_PRECONDITION(stream_base);
333     struct aws_h2_stream *stream = AWS_CONTAINER_OF(stream_base, struct aws_h2_stream, base);
334 
335     AWS_H2_STREAM_LOG(DEBUG, stream, "Destroying stream");
336     aws_mutex_clean_up(&stream->synced_data.lock);
337     aws_http_message_release(stream->thread_data.outgoing_message);
338 
339     aws_mem_release(stream->base.alloc, stream);
340 }
341 
s_stream_update_window(struct aws_http_stream * stream_base,size_t increment_size)342 static void s_stream_update_window(struct aws_http_stream *stream_base, size_t increment_size) {
343     AWS_PRECONDITION(stream_base);
344     struct aws_h2_stream *stream = AWS_CONTAINER_OF(stream_base, struct aws_h2_stream, base);
345     struct aws_h2_connection *connection = s_get_h2_connection(stream);
346     if (!increment_size) {
347         return;
348     }
349     if (!connection->base.manual_window_management) {
350         /* auto-mode, manual update window is not supported */
351         AWS_H2_STREAM_LOG(
352             DEBUG, stream, "Manual window management is off, update window operations are not supported.");
353         return;
354     }
355 
356     int err = 0;
357     bool stream_is_init;
358     bool cross_thread_work_should_schedule = false;
359     size_t sum_size;
360     { /* BEGIN CRITICAL SECTION */
361         s_lock_synced_data(stream);
362 
363         err |= aws_add_size_checked(stream->synced_data.window_update_size, increment_size, &sum_size);
364         err |= sum_size > AWS_H2_WINDOW_UPDATE_MAX;
365         stream_is_init = stream->synced_data.api_state == AWS_H2_STREAM_API_STATE_INIT;
366 
367         if (!err && !stream_is_init) {
368             cross_thread_work_should_schedule = !stream->synced_data.is_cross_thread_work_task_scheduled;
369             stream->synced_data.is_cross_thread_work_task_scheduled = true;
370             stream->synced_data.window_update_size = sum_size;
371         }
372         s_unlock_synced_data(stream);
373     } /* END CRITICAL SECTION */
374 
375     if (cross_thread_work_should_schedule) {
376         AWS_H2_STREAM_LOG(TRACE, stream, "Scheduling stream cross-thread work task");
377         /* increment the refcount of stream to keep it alive until the task runs */
378         aws_atomic_fetch_add(&stream->base.refcount, 1);
379         aws_channel_schedule_task_now(connection->base.channel_slot->channel, &stream->cross_thread_work_task);
380         return;
381     }
382 
383     if (stream_is_init) {
384         AWS_H2_STREAM_LOG(
385             ERROR,
386             stream,
387             "Stream update window failed. Stream is in initialized state, please activate the stream first.");
388         aws_raise_error(AWS_ERROR_INVALID_STATE);
389         return;
390     }
391 
392     if (err) {
393         /* The increment_size is still not 100% safe, since we cannot control the incoming data frame. So just
394          * ruled out the value that is obviously wrong values */
395         AWS_H2_STREAM_LOG(
396             ERROR,
397             stream,
398             "The stream's flow-control window has been incremented beyond 2**31 -1, the max for HTTP/2. The stream "
399             "will close.");
400         aws_raise_error(AWS_ERROR_OVERFLOW_DETECTED);
401         struct aws_h2err stream_error = {
402             .aws_code = AWS_ERROR_OVERFLOW_DETECTED,
403             .h2_code = AWS_HTTP2_ERR_INTERNAL_ERROR,
404         };
405         /* Only when stream is not initialized reset will fail. So, we can assert it to be succeed. */
406         AWS_FATAL_ASSERT(s_stream_reset_stream_internal(stream_base, stream_error) == AWS_OP_SUCCESS);
407     }
408     return;
409 }
410 
s_stream_reset_stream_internal(struct aws_http_stream * stream_base,struct aws_h2err stream_error)411 static int s_stream_reset_stream_internal(struct aws_http_stream *stream_base, struct aws_h2err stream_error) {
412 
413     struct aws_h2_stream *stream = AWS_CONTAINER_OF(stream_base, struct aws_h2_stream, base);
414     struct aws_h2_connection *connection = s_get_h2_connection(stream);
415     bool reset_called;
416     bool stream_is_init;
417     bool cross_thread_work_should_schedule = false;
418 
419     { /* BEGIN CRITICAL SECTION */
420         s_lock_synced_data(stream);
421 
422         reset_called = stream->synced_data.reset_called;
423         stream_is_init = stream->synced_data.api_state == AWS_H2_STREAM_API_STATE_INIT;
424         if (!reset_called && !stream_is_init) {
425             cross_thread_work_should_schedule = !stream->synced_data.is_cross_thread_work_task_scheduled;
426             stream->synced_data.reset_called = true;
427             stream->synced_data.reset_error = stream_error;
428         }
429         s_unlock_synced_data(stream);
430     } /* END CRITICAL SECTION */
431 
432     if (stream_is_init) {
433         AWS_H2_STREAM_LOG(
434             ERROR, stream, "Reset stream failed. Stream is in initialized state, please activate the stream first.");
435         return aws_raise_error(AWS_ERROR_INVALID_STATE);
436     }
437     if (cross_thread_work_should_schedule) {
438         AWS_H2_STREAM_LOG(TRACE, stream, "Scheduling stream cross-thread work task");
439         /* increment the refcount of stream to keep it alive until the task runs */
440         aws_atomic_fetch_add(&stream->base.refcount, 1);
441         aws_channel_schedule_task_now(connection->base.channel_slot->channel, &stream->cross_thread_work_task);
442         return AWS_OP_SUCCESS;
443     }
444     if (reset_called) {
445         AWS_H2_STREAM_LOG(DEBUG, stream, "Reset stream ignored. Reset stream has been called already.");
446     }
447 
448     return AWS_OP_SUCCESS;
449 }
450 
s_stream_reset_stream(struct aws_http_stream * stream_base,uint32_t http2_error)451 static int s_stream_reset_stream(struct aws_http_stream *stream_base, uint32_t http2_error) {
452     struct aws_h2err stream_error = {
453         .aws_code = AWS_ERROR_HTTP_RST_STREAM_SENT,
454         .h2_code = http2_error,
455     };
456 
457     return s_stream_reset_stream_internal(stream_base, stream_error);
458 }
459 
s_stream_get_received_error_code(struct aws_http_stream * stream_base,uint32_t * out_http2_error)460 static int s_stream_get_received_error_code(struct aws_http_stream *stream_base, uint32_t *out_http2_error) {
461     struct aws_h2_stream *stream = AWS_CONTAINER_OF(stream_base, struct aws_h2_stream, base);
462     if (stream->received_reset_error_code == -1) {
463         return aws_raise_error(AWS_ERROR_HTTP_DATA_NOT_AVAILABLE);
464     }
465     *out_http2_error = (uint32_t)stream->received_reset_error_code;
466     return AWS_OP_SUCCESS;
467 }
468 
s_stream_get_sent_error_code(struct aws_http_stream * stream_base,uint32_t * out_http2_error)469 static int s_stream_get_sent_error_code(struct aws_http_stream *stream_base, uint32_t *out_http2_error) {
470     struct aws_h2_stream *stream = AWS_CONTAINER_OF(stream_base, struct aws_h2_stream, base);
471     if (stream->sent_reset_error_code == -1) {
472         return aws_raise_error(AWS_ERROR_HTTP_DATA_NOT_AVAILABLE);
473     }
474     *out_http2_error = (uint32_t)stream->sent_reset_error_code;
475     return AWS_OP_SUCCESS;
476 }
477 
aws_h2_stream_get_state(const struct aws_h2_stream * stream)478 enum aws_h2_stream_state aws_h2_stream_get_state(const struct aws_h2_stream *stream) {
479     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
480     return stream->thread_data.state;
481 }
482 
483 /* Given a Stream Error, send RST_STREAM frame and close stream.
484  * A Connection Error is returned if something goes catastrophically wrong */
s_send_rst_and_close_stream(struct aws_h2_stream * stream,struct aws_h2err stream_error)485 static struct aws_h2err s_send_rst_and_close_stream(struct aws_h2_stream *stream, struct aws_h2err stream_error) {
486     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
487     AWS_PRECONDITION(stream->thread_data.state != AWS_H2_STREAM_STATE_CLOSED);
488 
489     struct aws_h2_connection *connection = s_get_h2_connection(stream);
490 
491     stream->thread_data.state = AWS_H2_STREAM_STATE_CLOSED;
492     { /* BEGIN CRITICAL SECTION */
493         s_lock_synced_data(stream);
494         stream->synced_data.api_state = AWS_H2_STREAM_API_STATE_COMPLETE;
495         s_unlock_synced_data(stream);
496     } /* END CRITICAL SECTION */
497     AWS_H2_STREAM_LOGF(
498         DEBUG,
499         stream,
500         "Sending RST_STREAM with error code %s (0x%x). State -> CLOSED",
501         aws_http2_error_code_to_str(stream_error.h2_code),
502         stream_error.h2_code);
503 
504     /* Send RST_STREAM */
505     struct aws_h2_frame *rst_stream_frame =
506         aws_h2_frame_new_rst_stream(stream->base.alloc, stream->base.id, stream_error.h2_code);
507     if (!rst_stream_frame) {
508         AWS_H2_STREAM_LOGF(ERROR, stream, "Error creating RST_STREAM frame, %s", aws_error_name(aws_last_error()));
509         return aws_h2err_from_last_error();
510     }
511     aws_h2_connection_enqueue_outgoing_frame(connection, rst_stream_frame); /* connection takes ownership of frame */
512     stream->sent_reset_error_code = stream_error.h2_code;
513 
514     /* Tell connection that stream is now closed */
515     if (aws_h2_connection_on_stream_closed(
516             connection, stream, AWS_H2_STREAM_CLOSED_WHEN_RST_STREAM_SENT, stream_error.aws_code)) {
517         return aws_h2err_from_last_error();
518     }
519 
520     return AWS_H2ERR_SUCCESS;
521 }
522 
aws_h2_stream_window_size_change(struct aws_h2_stream * stream,int32_t size_changed,bool self)523 struct aws_h2err aws_h2_stream_window_size_change(struct aws_h2_stream *stream, int32_t size_changed, bool self) {
524     if (self) {
525         if (stream->thread_data.window_size_self + size_changed > AWS_H2_WINDOW_UPDATE_MAX) {
526             return aws_h2err_from_h2_code(AWS_HTTP2_ERR_FLOW_CONTROL_ERROR);
527         }
528         stream->thread_data.window_size_self += size_changed;
529     } else {
530         if ((int64_t)stream->thread_data.window_size_peer + size_changed > AWS_H2_WINDOW_UPDATE_MAX) {
531             return aws_h2err_from_h2_code(AWS_HTTP2_ERR_FLOW_CONTROL_ERROR);
532         }
533         stream->thread_data.window_size_peer += size_changed;
534     }
535     return AWS_H2ERR_SUCCESS;
536 }
537 
aws_h2_stream_on_activated(struct aws_h2_stream * stream,bool * out_has_outgoing_data)538 int aws_h2_stream_on_activated(struct aws_h2_stream *stream, bool *out_has_outgoing_data) {
539     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
540 
541     struct aws_h2_connection *connection = s_get_h2_connection(stream);
542 
543     /* Create HEADERS frame */
544     struct aws_http_message *msg = stream->thread_data.outgoing_message;
545     bool has_body_stream = aws_http_message_get_body_stream(msg) != NULL;
546     struct aws_http_headers *h2_headers = aws_h2_create_headers_from_request(msg, stream->base.alloc);
547     if (!h2_headers) {
548         AWS_H2_STREAM_LOGF(
549             ERROR, stream, "Failed to create HTTP/2 style headers from request %s", aws_error_name(aws_last_error()));
550         goto error;
551     }
552     struct aws_h2_frame *headers_frame = aws_h2_frame_new_headers(
553         stream->base.alloc,
554         stream->base.id,
555         h2_headers,
556         !has_body_stream /* end_stream */,
557         0 /* padding - not currently configurable via public API */,
558         NULL /* priority - not currently configurable via public API */);
559 
560     /* Release refcount of h2_headers here, let frame take the full ownership of it */
561     aws_http_headers_release(h2_headers);
562     if (!headers_frame) {
563         AWS_H2_STREAM_LOGF(ERROR, stream, "Failed to create HEADERS frame: %s", aws_error_name(aws_last_error()));
564         goto error;
565     }
566 
567     /* Initialize the flow-control window size */
568     stream->thread_data.window_size_peer =
569         connection->thread_data.settings_peer[AWS_HTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
570     stream->thread_data.window_size_self =
571         connection->thread_data.settings_self[AWS_HTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
572 
573     if (has_body_stream) {
574         /* If stream has DATA to send, put it in the outgoing_streams_list, and we'll send data later */
575         stream->thread_data.state = AWS_H2_STREAM_STATE_OPEN;
576         AWS_H2_STREAM_LOG(TRACE, stream, "Sending HEADERS. State -> OPEN");
577     } else {
578         /* If stream has no body, then HEADERS frame marks the end of outgoing data */
579         stream->thread_data.state = AWS_H2_STREAM_STATE_HALF_CLOSED_LOCAL;
580         AWS_H2_STREAM_LOG(TRACE, stream, "Sending HEADERS with END_STREAM. State -> HALF_CLOSED_LOCAL");
581     }
582 
583     *out_has_outgoing_data = has_body_stream;
584     aws_h2_connection_enqueue_outgoing_frame(connection, headers_frame);
585     return AWS_OP_SUCCESS;
586 
587 error:
588     return AWS_OP_ERR;
589 }
590 
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)591 int aws_h2_stream_encode_data_frame(
592     struct aws_h2_stream *stream,
593     struct aws_h2_frame_encoder *encoder,
594     struct aws_byte_buf *output,
595     int *data_encode_status) {
596 
597     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
598     AWS_PRECONDITION(
599         stream->thread_data.state == AWS_H2_STREAM_STATE_OPEN ||
600         stream->thread_data.state == AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE);
601     struct aws_h2_connection *connection = s_get_h2_connection(stream);
602     AWS_PRECONDITION(connection->thread_data.window_size_peer > AWS_H2_MIN_WINDOW_SIZE);
603 
604     if (stream->thread_data.window_size_peer <= AWS_H2_MIN_WINDOW_SIZE) {
605         /* The stream is stalled now */
606         *data_encode_status = AWS_H2_DATA_ENCODE_ONGOING_WINDOW_STALLED;
607         return AWS_OP_SUCCESS;
608     }
609 
610     *data_encode_status = AWS_H2_DATA_ENCODE_COMPLETE;
611     struct aws_input_stream *body = aws_http_message_get_body_stream(stream->thread_data.outgoing_message);
612     AWS_ASSERT(body);
613 
614     bool body_complete;
615     bool body_stalled;
616     if (aws_h2_encode_data_frame(
617             encoder,
618             stream->base.id,
619             body,
620             true /*body_ends_stream*/,
621             0 /*pad_length*/,
622             &stream->thread_data.window_size_peer,
623             &connection->thread_data.window_size_peer,
624             output,
625             &body_complete,
626             &body_stalled)) {
627 
628         /* Failed to write DATA, treat it as a Stream Error */
629         AWS_H2_STREAM_LOGF(ERROR, stream, "Error encoding stream DATA, %s", aws_error_name(aws_last_error()));
630         struct aws_h2err returned_h2err = s_send_rst_and_close_stream(stream, aws_h2err_from_last_error());
631         if (aws_h2err_failed(returned_h2err)) {
632             aws_h2_connection_shutdown_due_to_write_err(connection, returned_h2err.aws_code);
633         }
634         return AWS_OP_SUCCESS;
635     }
636 
637     if (body_complete) {
638         if (stream->thread_data.state == AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE) {
639             /* Both sides have sent END_STREAM */
640             stream->thread_data.state = AWS_H2_STREAM_STATE_CLOSED;
641             AWS_H2_STREAM_LOG(TRACE, stream, "Sent END_STREAM. State -> CLOSED");
642             { /* BEGIN CRITICAL SECTION */
643                 s_lock_synced_data(stream);
644                 stream->synced_data.api_state = AWS_H2_STREAM_API_STATE_COMPLETE;
645                 s_unlock_synced_data(stream);
646             } /* END CRITICAL SECTION */
647             /* Tell connection that stream is now closed */
648             if (aws_h2_connection_on_stream_closed(
649                     connection, stream, AWS_H2_STREAM_CLOSED_WHEN_BOTH_SIDES_END_STREAM, AWS_ERROR_SUCCESS)) {
650                 return AWS_OP_ERR;
651             }
652         } else {
653             /* Else can't close until we receive END_STREAM */
654             stream->thread_data.state = AWS_H2_STREAM_STATE_HALF_CLOSED_LOCAL;
655             AWS_H2_STREAM_LOG(TRACE, stream, "Sent END_STREAM. State -> HALF_CLOSED_LOCAL");
656         }
657     } else {
658         /* Body not complete */
659         *data_encode_status = AWS_H2_DATA_ENCODE_ONGOING;
660         if (body_stalled) {
661             *data_encode_status = AWS_H2_DATA_ENCODE_ONGOING_BODY_STALLED;
662         }
663         if (stream->thread_data.window_size_peer <= AWS_H2_MIN_WINDOW_SIZE) {
664             /* if body and window both stalled, we take the window stalled status, which will take the stream out from
665              * outgoing list */
666             *data_encode_status = AWS_H2_DATA_ENCODE_ONGOING_WINDOW_STALLED;
667         }
668     }
669 
670     return AWS_OP_SUCCESS;
671 }
672 
aws_h2_stream_on_decoder_headers_begin(struct aws_h2_stream * stream)673 struct aws_h2err aws_h2_stream_on_decoder_headers_begin(struct aws_h2_stream *stream) {
674     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
675 
676     struct aws_h2err stream_err = s_check_state_allows_frame_type(stream, AWS_H2_FRAME_T_HEADERS);
677     if (aws_h2err_failed(stream_err)) {
678         return s_send_rst_and_close_stream(stream, stream_err);
679     }
680 
681     return AWS_H2ERR_SUCCESS;
682 }
683 
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)684 struct aws_h2err aws_h2_stream_on_decoder_headers_i(
685     struct aws_h2_stream *stream,
686     const struct aws_http_header *header,
687     enum aws_http_header_name name_enum,
688     enum aws_http_header_block block_type) {
689 
690     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
691 
692     /* Not calling s_check_state_allows_frame_type() here because we already checked
693      * at start of HEADERS frame in aws_h2_stream_on_decoder_headers_begin() */
694 
695     bool is_server = stream->base.server_data;
696 
697     /* RFC-7540 8.1 - Message consists of:
698      * - 0+ Informational 1xx headers (response-only, decoder validates that this only occurs in responses)
699      * - 1 main headers with normal request or response.
700      * - 0 or 1 trailing headers with no pseudo-headers */
701     switch (block_type) {
702         case AWS_HTTP_HEADER_BLOCK_INFORMATIONAL:
703             if (stream->thread_data.received_main_headers) {
704                 AWS_H2_STREAM_LOG(
705                     ERROR, stream, "Malformed message, received informational (1xx) response after main response");
706                 goto malformed;
707             }
708             break;
709         case AWS_HTTP_HEADER_BLOCK_MAIN:
710             if (stream->thread_data.received_main_headers) {
711                 AWS_H2_STREAM_LOG(ERROR, stream, "Malformed message, received second set of headers");
712                 goto malformed;
713             }
714             break;
715         case AWS_HTTP_HEADER_BLOCK_TRAILING:
716             if (!stream->thread_data.received_main_headers) {
717                 /* A HEADERS frame without any pseudo-headers looks like trailing headers to the decoder */
718                 AWS_H2_STREAM_LOG(ERROR, stream, "Malformed headers lack required pseudo-header fields.");
719                 goto malformed;
720             }
721             break;
722         default:
723             AWS_ASSERT(0);
724     }
725 
726     if (is_server) {
727         return aws_h2err_from_aws_code(AWS_ERROR_UNIMPLEMENTED);
728 
729     } else {
730         /* Client */
731         if (name_enum == AWS_HTTP_HEADER_STATUS) {
732             uint64_t status_code;
733             int err = aws_strutil_read_unsigned_num(header->value, &status_code);
734             AWS_ASSERT(!err && "Invalid :status value. Decoder should have already validated this");
735             (void)err;
736 
737             stream->base.client_data->response_status = (int)status_code;
738         }
739     }
740 
741     if (stream->base.on_incoming_headers) {
742         if (stream->base.on_incoming_headers(&stream->base, block_type, header, 1, stream->base.user_data)) {
743             /* #TODO: callback errors should be Stream Errors, not Connection Errors */
744             AWS_H2_STREAM_LOGF(
745                 ERROR, stream, "Incoming header callback raised error, %s", aws_error_name(aws_last_error()));
746             return aws_h2err_from_last_error();
747         }
748     }
749 
750     return AWS_H2ERR_SUCCESS;
751 
752 malformed:
753     return s_send_rst_and_close_stream(stream, aws_h2err_from_h2_code(AWS_HTTP2_ERR_PROTOCOL_ERROR));
754 }
755 
aws_h2_stream_on_decoder_headers_end(struct aws_h2_stream * stream,bool malformed,enum aws_http_header_block block_type)756 struct aws_h2err aws_h2_stream_on_decoder_headers_end(
757     struct aws_h2_stream *stream,
758     bool malformed,
759     enum aws_http_header_block block_type) {
760 
761     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
762 
763     /* Not calling s_check_state_allows_frame_type() here because we already checked
764      * at start of HEADERS frame in aws_h2_stream_on_decoder_headers_begin() */
765 
766     if (malformed) {
767         AWS_H2_STREAM_LOG(ERROR, stream, "Headers are malformed");
768         return s_send_rst_and_close_stream(stream, aws_h2err_from_h2_code(AWS_HTTP2_ERR_PROTOCOL_ERROR));
769     }
770 
771     switch (block_type) {
772         case AWS_HTTP_HEADER_BLOCK_INFORMATIONAL:
773             AWS_H2_STREAM_LOG(TRACE, stream, "Informational 1xx header-block done.");
774             break;
775         case AWS_HTTP_HEADER_BLOCK_MAIN:
776             AWS_H2_STREAM_LOG(TRACE, stream, "Main header-block done.");
777             stream->thread_data.received_main_headers = true;
778             break;
779         case AWS_HTTP_HEADER_BLOCK_TRAILING:
780             AWS_H2_STREAM_LOG(TRACE, stream, "Trailing 1xx header-block done.");
781             break;
782         default:
783             AWS_ASSERT(0);
784     }
785 
786     if (stream->base.on_incoming_header_block_done) {
787         if (stream->base.on_incoming_header_block_done(&stream->base, block_type, stream->base.user_data)) {
788             AWS_H2_STREAM_LOGF(
789                 ERROR,
790                 stream,
791                 "Incoming-header-block-done callback raised error, %s",
792                 aws_error_name(aws_last_error()));
793             return aws_h2err_from_last_error();
794         }
795     }
796 
797     return AWS_H2ERR_SUCCESS;
798 }
799 
aws_h2_stream_on_decoder_push_promise(struct aws_h2_stream * stream,uint32_t promised_stream_id)800 struct aws_h2err aws_h2_stream_on_decoder_push_promise(struct aws_h2_stream *stream, uint32_t promised_stream_id) {
801     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
802 
803     struct aws_h2err stream_err = s_check_state_allows_frame_type(stream, AWS_H2_FRAME_T_PUSH_PROMISE);
804     if (aws_h2err_failed(stream_err)) {
805         return s_send_rst_and_close_stream(stream, stream_err);
806     }
807 
808     /* Note: Until we have a need for it, PUSH_PROMISE is not a fully supported feature.
809      * Promised streams are automatically rejected in a manner compliant with RFC-7540. */
810     AWS_H2_STREAM_LOG(DEBUG, stream, "Automatically rejecting promised stream, PUSH_PROMISE is not fully supported");
811     if (aws_h2_connection_send_rst_and_close_reserved_stream(
812             s_get_h2_connection(stream), promised_stream_id, AWS_HTTP2_ERR_REFUSED_STREAM)) {
813         return aws_h2err_from_last_error();
814     }
815 
816     return AWS_H2ERR_SUCCESS;
817 }
818 
aws_h2_stream_on_decoder_data_begin(struct aws_h2_stream * stream,uint32_t payload_len,bool end_stream)819 struct aws_h2err aws_h2_stream_on_decoder_data_begin(
820     struct aws_h2_stream *stream,
821     uint32_t payload_len,
822     bool end_stream) {
823 
824     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
825 
826     struct aws_h2err stream_err = s_check_state_allows_frame_type(stream, AWS_H2_FRAME_T_DATA);
827     if (aws_h2err_failed(stream_err)) {
828         return s_send_rst_and_close_stream(stream, stream_err);
829     }
830 
831     if (!stream->thread_data.received_main_headers) {
832         AWS_H2_STREAM_LOG(ERROR, stream, "Malformed message, received DATA before main HEADERS");
833         return s_send_rst_and_close_stream(stream, aws_h2err_from_h2_code(AWS_HTTP2_ERR_PROTOCOL_ERROR));
834     }
835 
836     /* RFC-7540 6.9.1:
837      * The sender MUST NOT send a flow-controlled frame with a length that exceeds
838      * the space available in either of the flow-control windows advertised by the receiver.
839      * Frames with zero length with the END_STREAM flag set (that is, an empty DATA frame)
840      * MAY be sent if there is no available space in either flow-control window. */
841     if ((int32_t)payload_len > stream->thread_data.window_size_self && payload_len != 0) {
842         AWS_H2_STREAM_LOGF(
843             ERROR,
844             stream,
845             "DATA length=%" PRIu32 " exceeds flow-control window=%" PRIi64,
846             payload_len,
847             stream->thread_data.window_size_self);
848         return s_send_rst_and_close_stream(stream, aws_h2err_from_h2_code(AWS_HTTP2_ERR_FLOW_CONTROL_ERROR));
849     }
850     stream->thread_data.window_size_self -= payload_len;
851 
852     /* send a stream window_update frame to automatically maintain the stream self window size, if
853      * manual_window_management is not set */
854     if (payload_len != 0 && !end_stream && !stream->base.owning_connection->manual_window_management) {
855         struct aws_h2_frame *stream_window_update_frame =
856             aws_h2_frame_new_window_update(stream->base.alloc, stream->base.id, payload_len);
857         if (!stream_window_update_frame) {
858             AWS_H2_STREAM_LOGF(
859                 ERROR,
860                 stream,
861                 "WINDOW_UPDATE frame on stream failed to be sent, error %s",
862                 aws_error_name(aws_last_error()));
863             return aws_h2err_from_last_error();
864         }
865 
866         aws_h2_connection_enqueue_outgoing_frame(s_get_h2_connection(stream), stream_window_update_frame);
867         stream->thread_data.window_size_self += payload_len;
868     }
869 
870     return AWS_H2ERR_SUCCESS;
871 }
872 
aws_h2_stream_on_decoder_data_i(struct aws_h2_stream * stream,struct aws_byte_cursor data)873 struct aws_h2err aws_h2_stream_on_decoder_data_i(struct aws_h2_stream *stream, struct aws_byte_cursor data) {
874     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
875 
876     /* Not calling s_check_state_allows_frame_type() here because we already checked at start of DATA frame in
877      * aws_h2_stream_on_decoder_data_begin() */
878 
879     if (stream->base.on_incoming_body) {
880         if (stream->base.on_incoming_body(&stream->base, &data, stream->base.user_data)) {
881             AWS_H2_STREAM_LOGF(
882                 ERROR, stream, "Incoming body callback raised error, %s", aws_error_name(aws_last_error()));
883             return aws_h2err_from_last_error();
884         }
885     }
886 
887     return AWS_H2ERR_SUCCESS;
888 }
889 
aws_h2_stream_on_decoder_window_update(struct aws_h2_stream * stream,uint32_t window_size_increment,bool * window_resume)890 struct aws_h2err aws_h2_stream_on_decoder_window_update(
891     struct aws_h2_stream *stream,
892     uint32_t window_size_increment,
893     bool *window_resume) {
894     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
895 
896     *window_resume = false;
897 
898     struct aws_h2err stream_err = s_check_state_allows_frame_type(stream, AWS_H2_FRAME_T_WINDOW_UPDATE);
899     if (aws_h2err_failed(stream_err)) {
900         return s_send_rst_and_close_stream(stream, stream_err);
901     }
902     if (window_size_increment == 0) {
903         /* flow-control window increment of 0 MUST be treated as error (RFC7540 6.9.1) */
904         AWS_H2_STREAM_LOG(ERROR, stream, "Window update frame with 0 increment size");
905         return s_send_rst_and_close_stream(stream, aws_h2err_from_h2_code(AWS_HTTP2_ERR_PROTOCOL_ERROR));
906     }
907     int32_t old_window_size = stream->thread_data.window_size_peer;
908     stream_err = (aws_h2_stream_window_size_change(stream, window_size_increment, false /*self*/));
909     if (aws_h2err_failed(stream_err)) {
910         /* We MUST NOT allow a flow-control window to exceed the max */
911         AWS_H2_STREAM_LOG(
912             ERROR, stream, "Window update frame causes the stream flow-control window to exceed the maximum size");
913         return s_send_rst_and_close_stream(stream, stream_err);
914     }
915     if (stream->thread_data.window_size_peer > AWS_H2_MIN_WINDOW_SIZE && old_window_size <= AWS_H2_MIN_WINDOW_SIZE) {
916         *window_resume = true;
917     }
918     return AWS_H2ERR_SUCCESS;
919 }
920 
aws_h2_stream_on_decoder_end_stream(struct aws_h2_stream * stream)921 struct aws_h2err aws_h2_stream_on_decoder_end_stream(struct aws_h2_stream *stream) {
922     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
923 
924     /* Not calling s_check_state_allows_frame_type() here because END_STREAM isn't
925      * an actual frame type. It's a flag on DATA or HEADERS frames, and we
926      * already checked the legality of those frames in their respective callbacks. */
927 
928     if (stream->thread_data.state == AWS_H2_STREAM_STATE_HALF_CLOSED_LOCAL) {
929         /* Both sides have sent END_STREAM */
930         stream->thread_data.state = AWS_H2_STREAM_STATE_CLOSED;
931         AWS_H2_STREAM_LOG(TRACE, stream, "Received END_STREAM. State -> CLOSED");
932         { /* BEGIN CRITICAL SECTION */
933             s_lock_synced_data(stream);
934             stream->synced_data.api_state = AWS_H2_STREAM_API_STATE_COMPLETE;
935             s_unlock_synced_data(stream);
936         } /* END CRITICAL SECTION */
937         /* Tell connection that stream is now closed */
938         if (aws_h2_connection_on_stream_closed(
939                 s_get_h2_connection(stream),
940                 stream,
941                 AWS_H2_STREAM_CLOSED_WHEN_BOTH_SIDES_END_STREAM,
942                 AWS_ERROR_SUCCESS)) {
943             return aws_h2err_from_last_error();
944         }
945 
946     } else {
947         /* Else can't close until our side sends END_STREAM */
948         stream->thread_data.state = AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE;
949         AWS_H2_STREAM_LOG(TRACE, stream, "Received END_STREAM. State -> HALF_CLOSED_REMOTE");
950     }
951 
952     return AWS_H2ERR_SUCCESS;
953 }
954 
aws_h2_stream_on_decoder_rst_stream(struct aws_h2_stream * stream,uint32_t h2_error_code)955 struct aws_h2err aws_h2_stream_on_decoder_rst_stream(struct aws_h2_stream *stream, uint32_t h2_error_code) {
956     AWS_PRECONDITION_ON_CHANNEL_THREAD(stream);
957 
958     /* Check that this state allows RST_STREAM. */
959     struct aws_h2err err = s_check_state_allows_frame_type(stream, AWS_H2_FRAME_T_RST_STREAM);
960     if (aws_h2err_failed(err)) {
961         /* Usually we send a RST_STREAM when the state doesn't allow a frame type, but RFC-7540 5.4.2 says:
962          * "To avoid looping, an endpoint MUST NOT send a RST_STREAM in response to a RST_STREAM frame." */
963         return err;
964     }
965 
966     /* RFC-7540 8.1 - a server MAY request that the client abort transmission of a request without error by sending a
967      * RST_STREAM with an error code of NO_ERROR after sending a complete response (i.e., a frame with the END_STREAM
968      * flag). Clients MUST NOT discard responses as a result of receiving such a RST_STREAM */
969     int aws_error_code;
970     if (stream->base.client_data && (h2_error_code == AWS_HTTP2_ERR_NO_ERROR) &&
971         (stream->thread_data.state == AWS_H2_STREAM_STATE_HALF_CLOSED_REMOTE)) {
972 
973         aws_error_code = AWS_ERROR_SUCCESS;
974 
975     } else {
976         aws_error_code = AWS_ERROR_HTTP_RST_STREAM_RECEIVED;
977         AWS_H2_STREAM_LOGF(
978             ERROR,
979             stream,
980             "Peer terminated stream with HTTP/2 RST_STREAM frame, error-code=0x%x(%s)",
981             h2_error_code,
982             aws_http2_error_code_to_str(h2_error_code));
983     }
984 
985     stream->thread_data.state = AWS_H2_STREAM_STATE_CLOSED;
986     { /* BEGIN CRITICAL SECTION */
987         s_lock_synced_data(stream);
988         stream->synced_data.api_state = AWS_H2_STREAM_API_STATE_COMPLETE;
989         s_unlock_synced_data(stream);
990     } /* END CRITICAL SECTION */
991     stream->received_reset_error_code = h2_error_code;
992 
993     AWS_H2_STREAM_LOGF(
994         TRACE,
995         stream,
996         "Received RST_STREAM code=0x%x(%s). State -> CLOSED",
997         h2_error_code,
998         aws_http2_error_code_to_str(h2_error_code));
999 
1000     if (aws_h2_connection_on_stream_closed(
1001             s_get_h2_connection(stream), stream, AWS_H2_STREAM_CLOSED_WHEN_RST_STREAM_RECEIVED, aws_error_code)) {
1002         return aws_h2err_from_last_error();
1003     }
1004 
1005     return AWS_H2ERR_SUCCESS;
1006 }
1007