File: h2_stream.h

package info (click to toggle)
aws-crt-python 0.20.4%2Bdfsg-1~bpo12%2B1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-backports
  • size: 72,656 kB
  • sloc: ansic: 381,805; python: 23,008; makefile: 6,251; sh: 4,536; cpp: 699; ruby: 208; java: 77; perl: 73; javascript: 46; xml: 11
file content (190 lines) | stat: -rw-r--r-- 8,231 bytes parent folder | download | duplicates (3)
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
#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;

    /* Only the event-loop thread may touch this data */
    struct {
        enum aws_h2_stream_state state;
        int32_t window_size_peer;
        /* The local window size.
         * We allow this value exceed the max window size (int64 can hold much more than 0x7FFFFFFF),
         * We leave it up to the remote peer to detect whether the max window size has been exceeded. */
        int64_t window_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;
    } 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 */
        size_t window_update_size;

        /* 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);

struct aws_h2err aws_h2_stream_window_size_change(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 */